diff --git a/Bunkers/.gradle/6.8/executionHistory/executionHistory.bin b/Bunkers/.gradle/6.8/executionHistory/executionHistory.bin
new file mode 100644
index 0000000..cbd758c
Binary files /dev/null and b/Bunkers/.gradle/6.8/executionHistory/executionHistory.bin differ
diff --git a/Bunkers/.gradle/6.8/executionHistory/executionHistory.lock b/Bunkers/.gradle/6.8/executionHistory/executionHistory.lock
new file mode 100644
index 0000000..599e431
Binary files /dev/null and b/Bunkers/.gradle/6.8/executionHistory/executionHistory.lock differ
diff --git a/Bunkers/.gradle/6.8/fileChanges/last-build.bin b/Bunkers/.gradle/6.8/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/Bunkers/.gradle/6.8/fileChanges/last-build.bin differ
diff --git a/Bunkers/.gradle/6.8/fileHashes/fileHashes.bin b/Bunkers/.gradle/6.8/fileHashes/fileHashes.bin
new file mode 100644
index 0000000..19af660
Binary files /dev/null and b/Bunkers/.gradle/6.8/fileHashes/fileHashes.bin differ
diff --git a/Bunkers/.gradle/6.8/fileHashes/fileHashes.lock b/Bunkers/.gradle/6.8/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..85082a6
Binary files /dev/null and b/Bunkers/.gradle/6.8/fileHashes/fileHashes.lock differ
diff --git a/Bunkers/.gradle/6.8/fileHashes/resourceHashesCache.bin b/Bunkers/.gradle/6.8/fileHashes/resourceHashesCache.bin
new file mode 100644
index 0000000..afdd41f
Binary files /dev/null and b/Bunkers/.gradle/6.8/fileHashes/resourceHashesCache.bin differ
diff --git a/Bunkers/.gradle/6.8/gc.properties b/Bunkers/.gradle/6.8/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/Bunkers/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Bunkers/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..b1d611b
Binary files /dev/null and b/Bunkers/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/Bunkers/.gradle/buildOutputCleanup/cache.properties b/Bunkers/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..4549f70
--- /dev/null
+++ b/Bunkers/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Sat Jul 24 19:59:25 CEST 2021
+gradle.version=6.8
diff --git a/Bunkers/.gradle/buildOutputCleanup/outputFiles.bin b/Bunkers/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 0000000..24fdeeb
Binary files /dev/null and b/Bunkers/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/Bunkers/.gradle/checksums/checksums.lock b/Bunkers/.gradle/checksums/checksums.lock
new file mode 100644
index 0000000..906b66a
Binary files /dev/null and b/Bunkers/.gradle/checksums/checksums.lock differ
diff --git a/Bunkers/.gradle/checksums/md5-checksums.bin b/Bunkers/.gradle/checksums/md5-checksums.bin
new file mode 100644
index 0000000..78590fa
Binary files /dev/null and b/Bunkers/.gradle/checksums/md5-checksums.bin differ
diff --git a/Bunkers/.gradle/checksums/sha1-checksums.bin b/Bunkers/.gradle/checksums/sha1-checksums.bin
new file mode 100644
index 0000000..33ead88
Binary files /dev/null and b/Bunkers/.gradle/checksums/sha1-checksums.bin differ
diff --git a/Bunkers/.gradle/configuration-cache/gc.properties b/Bunkers/.gradle/configuration-cache/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/Bunkers/.gradle/vcs-1/gc.properties b/Bunkers/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/Bunkers/.idea/.gitignore b/Bunkers/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/Bunkers/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/Bunkers/.idea/compiler.xml b/Bunkers/.idea/compiler.xml
new file mode 100644
index 0000000..61a9130
--- /dev/null
+++ b/Bunkers/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bunkers/.idea/gradle.xml b/Bunkers/.idea/gradle.xml
new file mode 100644
index 0000000..611e7c8
--- /dev/null
+++ b/Bunkers/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bunkers/.idea/jarRepositories.xml b/Bunkers/.idea/jarRepositories.xml
new file mode 100644
index 0000000..55f1d4b
--- /dev/null
+++ b/Bunkers/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bunkers/.idea/libraries-with-intellij-classes.xml b/Bunkers/.idea/libraries-with-intellij-classes.xml
new file mode 100644
index 0000000..9fa3156
--- /dev/null
+++ b/Bunkers/.idea/libraries-with-intellij-classes.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bunkers/.idea/misc.xml b/Bunkers/.idea/misc.xml
new file mode 100644
index 0000000..b0051c8
--- /dev/null
+++ b/Bunkers/.idea/misc.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Bunkers/build.gradle b/Bunkers/build.gradle
new file mode 100644
index 0000000..d58be1c
--- /dev/null
+++ b/Bunkers/build.gradle
@@ -0,0 +1,62 @@
+plugins {
+ id "org.jetbrains.kotlin.jvm" version "1.5.0"
+ id "com.github.johnrengelman.shadow" version "5.2.0"
+}
+
+group = 'cc.fyre.carnage'
+version = '1.0-SNAPSHOT'
+description = 'carnage'
+
+targetCompatibility = '1.8'
+sourceCompatibility = '1.8'
+
+shadowJar {
+ classifier = null
+ minimize()
+}
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+
+ flatDir {
+ dirs 'libs'
+ }
+
+}
+
+dependencies {
+
+ compile "com.google.code.gson:gson:2.8.5"
+
+ compileOnly "net.frozenorb:qLib:LATEST"
+ compileOnly 'cc.fyre.engine:game:1.0-SNAPSHOT'
+ compileOnly 'com.comphenix.protocol:ProtocolLib:4.4.0'
+ compileOnly 'net.hylist:spigot-server:1.7.10-R0.1-SNAPSHOT'
+ compileOnly 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.0'
+
+ compileOnly fileTree(dir: 'libs', include: ['*.jar'])
+}
+
+apply plugin: "kotlin"
+apply plugin: 'maven-publish'
+
+compileKotlin {
+ kotlinOptions.jvmTarget = '1.8'
+}
+
+sourceSets {
+ main.java.srcDirs += 'src/main/kotlin/'
+}
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
+
+publishing {
+ publications {
+ shadow(MavenPublication) { publication ->
+ project.shadow.component(publication)
+ }
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/build/classes/kotlin/main/META-INF/bunkers.kotlin_module b/Bunkers/build/classes/kotlin/main/META-INF/bunkers.kotlin_module
new file mode 100644
index 0000000..70f0f69
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/META-INF/bunkers.kotlin_module differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/Bunkers$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/Bunkers$Companion.class
new file mode 100644
index 0000000..6993789
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/Bunkers$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/Bunkers.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/Bunkers.class
new file mode 100644
index 0000000..576447f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/Bunkers.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/ClaimHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/ClaimHandler.class
new file mode 100644
index 0000000..88f8765
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/ClaimHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim$BorderIterator$BorderDirection.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim$BorderIterator$BorderDirection.class
new file mode 100644
index 0000000..94ec069
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim$BorderIterator$BorderDirection.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim$BorderIterator.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim$BorderIterator.class
new file mode 100644
index 0000000..8268dea
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim$BorderIterator.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim.class
new file mode 100644
index 0000000..a1a119d
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/Claim.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/ClaimSelection$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/ClaimSelection$Companion.class
new file mode 100644
index 0000000..6f56a4c
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/ClaimSelection$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/ClaimSelection.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/ClaimSelection.class
new file mode 100644
index 0000000..8a55377
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/data/ClaimSelection.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/listener/ClaimListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/listener/ClaimListener.class
new file mode 100644
index 0000000..9d8b443
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/listener/ClaimListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/listener/ClaimPositionListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/listener/ClaimPositionListener.class
new file mode 100644
index 0000000..a87be6c
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/listener/ClaimPositionListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/movement/ClaimMovementAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/movement/ClaimMovementAdapter.class
new file mode 100644
index 0000000..ef87cfd
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/claim/movement/ClaimMovementAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/EventHandler$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/EventHandler$Companion.class
new file mode 100644
index 0000000..c26ef08
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/EventHandler$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/EventHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/EventHandler.class
new file mode 100644
index 0000000..1b694ac
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/EventHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/command/KOTHSetTimeCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/command/KOTHSetTimeCommand.class
new file mode 100644
index 0000000..3a68147
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/command/KOTHSetTimeCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/command/KOTHStartCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/command/KOTHStartCommand.class
new file mode 100644
index 0000000..7d97c77
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/command/KOTHStartCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/listener/EventListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/listener/EventListener.class
new file mode 100644
index 0000000..e2cc050
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/listener/EventListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/service/EventService.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/service/EventService.class
new file mode 100644
index 0000000..6e6928c
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/event/service/EventService.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$Companion.class
new file mode 100644
index 0000000..9c63cd8
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$onGameFinish$$inlined$sortedByDescending$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$onGameFinish$$inlined$sortedByDescending$1.class
new file mode 100644
index 0000000..ad3c646
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$onGameFinish$$inlined$sortedByDescending$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$onPlayersSent$$inlined$sortedByDescending$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$onPlayersSent$$inlined$sortedByDescending$1.class
new file mode 100644
index 0000000..bd83578
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter$onPlayersSent$$inlined$sortedByDescending$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter.class
new file mode 100644
index 0000000..89bbf43
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/BunkersGameAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/deathmessage/BunkersDeathMessageConfiguration.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/deathmessage/BunkersDeathMessageConfiguration.class
new file mode 100644
index 0000000..e4a603f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/deathmessage/BunkersDeathMessageConfiguration.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener$onChunkLoad$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener$onChunkLoad$1.class
new file mode 100644
index 0000000..3c4cb2f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener$onChunkLoad$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener$onMapLoad$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener$onMapLoad$1.class
new file mode 100644
index 0000000..283a9e4
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener$onMapLoad$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener.class
new file mode 100644
index 0000000..658998b
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/ChunkListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$Companion.class
new file mode 100644
index 0000000..c7ffcdf
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$onGameStateChangeEnding$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$onGameStateChangeEnding$1.class
new file mode 100644
index 0000000..e9fdfdf
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$onGameStateChangeEnding$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$onItemConsume$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$onItemConsume$1.class
new file mode 100644
index 0000000..1f402de
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener$onItemConsume$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener.class
new file mode 100644
index 0000000..1c598b5
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/GameListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/LunarClientListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/LunarClientListener.class
new file mode 100644
index 0000000..8455169
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/LunarClientListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/VotingListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/VotingListener.class
new file mode 100644
index 0000000..f76cfdb
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/listener/VotingListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/CountdownScoreboardAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/CountdownScoreboardAdapter.class
new file mode 100644
index 0000000..6b27e29
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/CountdownScoreboardAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/InProgressScoreboardAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/InProgressScoreboardAdapter.class
new file mode 100644
index 0000000..ee06bc7
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/InProgressScoreboardAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter$getScoreGetter$lambda-2$$inlined$sortedBy$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter$getScoreGetter$lambda-2$$inlined$sortedBy$1.class
new file mode 100644
index 0000000..a47a922
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter$getScoreGetter$lambda-2$$inlined$sortedBy$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter.class
new file mode 100644
index 0000000..bb6e5a4
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/WaitingScoreboardAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/WaitingScoreboardAdapter.class
new file mode 100644
index 0000000..31b0498
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/scoreboard/WaitingScoreboardAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter$Direction.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter$Direction.class
new file mode 100644
index 0000000..9112440
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter$Direction.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter$provide$$inlined$sortedByDescending$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter$provide$$inlined$sortedByDescending$1.class
new file mode 100644
index 0000000..07ba0d2
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter$provide$$inlined$sortedByDescending$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter.class
new file mode 100644
index 0000000..a455128
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/game/tab/BunkersTabAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/PillarHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/PillarHandler.class
new file mode 100644
index 0000000..35287b6
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/PillarHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/Pillar$Type.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/Pillar$Type.class
new file mode 100644
index 0000000..d4434b5
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/Pillar$Type.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/Pillar.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/Pillar.class
new file mode 100644
index 0000000..1398018
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/Pillar.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/adapter/WallAdapter.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/adapter/WallAdapter.class
new file mode 100644
index 0000000..2190806
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/data/adapter/WallAdapter.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarListener.class
new file mode 100644
index 0000000..38346c2
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarPacketListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarPacketListener.class
new file mode 100644
index 0000000..0bd2e9b
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarPacketListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarWallListener$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarWallListener$Companion.class
new file mode 100644
index 0000000..41b34b3
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarWallListener$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarWallListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarWallListener.class
new file mode 100644
index 0000000..c44ad19
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pillar/listener/PillarWallListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/PvPClassHandler$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/PvPClassHandler$Companion.class
new file mode 100644
index 0000000..7cd822f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/PvPClassHandler$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/PvPClassHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/PvPClassHandler.class
new file mode 100644
index 0000000..c923157
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/PvPClassHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/PvPClass$Type.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/PvPClass$Type.class
new file mode 100644
index 0000000..0e30bc5
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/PvPClass$Type.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/PvPClass.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/PvPClass.class
new file mode 100644
index 0000000..1c2650b
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/PvPClass.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem$EffectConsumableItem.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem$EffectConsumableItem.class
new file mode 100644
index 0000000..307ef5d
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem$EffectConsumableItem.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem.class
new file mode 100644
index 0000000..e1834f5
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect$BardEffect$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect$BardEffect$Companion.class
new file mode 100644
index 0000000..61510ea
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect$BardEffect$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect$BardEffect.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect$BardEffect.class
new file mode 100644
index 0000000..a7abad0
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect$BardEffect.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect.class
new file mode 100644
index 0000000..eb2778d
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/service/BardService.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/service/BardService.class
new file mode 100644
index 0000000..e7e9358
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/service/BardService.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/type/BardClass.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/type/BardClass.class
new file mode 100644
index 0000000..fb67860
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/data/type/BardClass.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent$Companion.class
new file mode 100644
index 0000000..f765357
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent.class
new file mode 100644
index 0000000..29f45d5
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent$Companion.class
new file mode 100644
index 0000000..5a99b76
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent.class
new file mode 100644
index 0000000..2bc5162
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent$Companion.class
new file mode 100644
index 0000000..1bbe2e3
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent.class
new file mode 100644
index 0000000..bc10cc3
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/listener/PvPClassListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/listener/PvPClassListener.class
new file mode 100644
index 0000000..ebe3a1e
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/pvpclass/listener/PvPClassListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/RepairHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/RepairHandler.class
new file mode 100644
index 0000000..5a0e7c6
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/RepairHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/listener/RepairListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/listener/RepairListener.class
new file mode 100644
index 0000000..7564b75
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/listener/RepairListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/menu/RepairMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/menu/RepairMenu.class
new file mode 100644
index 0000000..a51ea61
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/menu/RepairMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/menu/element/RepairButton.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/menu/element/RepairButton.class
new file mode 100644
index 0000000..732a303
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/repair/menu/element/RepairButton.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/ShopHandler$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/ShopHandler$Companion.class
new file mode 100644
index 0000000..edeb601
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/ShopHandler$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/ShopHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/ShopHandler.class
new file mode 100644
index 0000000..3fb5e90
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/ShopHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/data/ShopType$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/data/ShopType$Companion.class
new file mode 100644
index 0000000..0aabb53
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/data/ShopType$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/data/ShopType.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/data/ShopType.class
new file mode 100644
index 0000000..b830793
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/data/ShopType.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/listener/ShopListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/listener/ShopListener.class
new file mode 100644
index 0000000..0b88326
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/listener/ShopListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/BuildMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/BuildMenu.class
new file mode 100644
index 0000000..891173b
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/BuildMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/ClassMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/ClassMenu.class
new file mode 100644
index 0000000..136ad23
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/ClassMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/CombatMenu$getButtons$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/CombatMenu$getButtons$1.class
new file mode 100644
index 0000000..80e4269
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/CombatMenu$getButtons$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/CombatMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/CombatMenu.class
new file mode 100644
index 0000000..65cb59d
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/CombatMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/EnchantMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/EnchantMenu.class
new file mode 100644
index 0000000..9ab237e
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/EnchantMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/SellMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/SellMenu.class
new file mode 100644
index 0000000..b3d13ff
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/SellMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/BuyElement.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/BuyElement.class
new file mode 100644
index 0000000..c471476
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/BuyElement.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/EnchantElement.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/EnchantElement.class
new file mode 100644
index 0000000..7954628
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/EnchantElement.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/SellElement.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/SellElement.class
new file mode 100644
index 0000000..7abacca
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/menu/element/SellElement.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/parameter/ShopTypeParameterProvider.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/parameter/ShopTypeParameterProvider.class
new file mode 100644
index 0000000..1c14c8c
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/parameter/ShopTypeParameterProvider.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/service/ShopService.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/service/ShopService.class
new file mode 100644
index 0000000..b58d2eb
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/shop/service/ShopService.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler$Companion.class
new file mode 100644
index 0000000..ce37442
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler$WhenMappings.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler$WhenMappings.class
new file mode 100644
index 0000000..180cebc
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler$WhenMappings.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler.class
new file mode 100644
index 0000000..f91b014
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/StatisticHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/command/BalanceCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/command/BalanceCommand.class
new file mode 100644
index 0000000..1614558
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/command/BalanceCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/command/PayCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/command/PayCommand.class
new file mode 100644
index 0000000..1ee5c9f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/command/PayCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/listener/StatisticListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/listener/StatisticListener.class
new file mode 100644
index 0000000..b3f3a2a
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/listener/StatisticListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/service/BalanceService.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/service/BalanceService.class
new file mode 100644
index 0000000..5bae544
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/statistic/service/BalanceService.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/SupplyHandler$addSupplyToService$task$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/SupplyHandler$addSupplyToService$task$1.class
new file mode 100644
index 0000000..d531195
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/SupplyHandler$addSupplyToService$task$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/SupplyHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/SupplyHandler.class
new file mode 100644
index 0000000..996cb06
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/SupplyHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/data/Supply.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/data/Supply.class
new file mode 100644
index 0000000..8f6a095
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/data/Supply.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/listener/SupplyListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/listener/SupplyListener.class
new file mode 100644
index 0000000..a9de65d
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/supply/listener/SupplyListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/TeamHandler$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/TeamHandler$Companion.class
new file mode 100644
index 0000000..514d393
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/TeamHandler$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/TeamHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/TeamHandler.class
new file mode 100644
index 0000000..ae35f85
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/TeamHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamChatCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamChatCommand.class
new file mode 100644
index 0000000..23418d7
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamChatCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamClaimCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamClaimCommand.class
new file mode 100644
index 0000000..55b27c9
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamClaimCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamFocusCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamFocusCommand.class
new file mode 100644
index 0000000..e5859e1
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamFocusCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamHQCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamHQCommand.class
new file mode 100644
index 0000000..59dba4f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamHQCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamInfoCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamInfoCommand.class
new file mode 100644
index 0000000..6f2dfbf
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamInfoCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamLocationCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamLocationCommand.class
new file mode 100644
index 0000000..582a882
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamLocationCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamRallyCommand$execute$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamRallyCommand$execute$1.class
new file mode 100644
index 0000000..4d67517
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamRallyCommand$execute$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamRallyCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamRallyCommand.class
new file mode 100644
index 0000000..c5c8fd3
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamRallyCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetDTRCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetDTRCommand.class
new file mode 100644
index 0000000..a7f9ac4
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetDTRCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetHQCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetHQCommand.class
new file mode 100644
index 0000000..b1f6050
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetHQCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetHologramCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetHologramCommand.class
new file mode 100644
index 0000000..033ed28
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetHologramCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetShopCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetShopCommand.class
new file mode 100644
index 0000000..9c89190
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamSetShopCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamVoteKickCommand.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamVoteKickCommand.class
new file mode 100644
index 0000000..2e74ee0
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/TeamVoteKickCommand.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/parameter/TeamParameterProvider.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/parameter/TeamParameterProvider.class
new file mode 100644
index 0000000..9d96b34
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/command/parameter/TeamParameterProvider.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Companion.class
new file mode 100644
index 0000000..b7ef5b9
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Type$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Type$Companion.class
new file mode 100644
index 0000000..e9d6cc5
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Type$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Type.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Type.class
new file mode 100644
index 0000000..b14654a
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team$Type.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team.class
new file mode 100644
index 0000000..6ae731e
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/Team.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/TeamChest.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/TeamChest.class
new file mode 100644
index 0000000..284c0e3
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/data/TeamChest.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamChatListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamChatListener.class
new file mode 100644
index 0000000..d72f60f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamChatListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamChestListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamChestListener.class
new file mode 100644
index 0000000..fae9751
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamChestListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamListener$onPlayerJoin$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamListener$onPlayerJoin$1.class
new file mode 100644
index 0000000..921af44
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamListener$onPlayerJoin$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamListener.class
new file mode 100644
index 0000000..ebff409
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamProtectionListener$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamProtectionListener$Companion.class
new file mode 100644
index 0000000..45ef75f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamProtectionListener$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamProtectionListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamProtectionListener.class
new file mode 100644
index 0000000..ea73612
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamProtectionListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamRallyListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamRallyListener.class
new file mode 100644
index 0000000..86ed498
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/listener/TeamRallyListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/TeamChestModifyMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/TeamChestModifyMenu.class
new file mode 100644
index 0000000..9e43928
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/TeamChestModifyMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/TeamChestPurchaseMenu.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/TeamChestPurchaseMenu.class
new file mode 100644
index 0000000..8d6a961
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/TeamChestPurchaseMenu.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/button/TeamChestMemberButton.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/button/TeamChestMemberButton.class
new file mode 100644
index 0000000..023580a
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/button/TeamChestMemberButton.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/button/TeamChestPurchaseButton.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/button/TeamChestPurchaseButton.class
new file mode 100644
index 0000000..39d53f1
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/team/menu/button/TeamChestPurchaseButton.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/TimerHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/TimerHandler.class
new file mode 100644
index 0000000..80f0294
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/TimerHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/Timer$createTask$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/Timer$createTask$1.class
new file mode 100644
index 0000000..5d0173a
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/Timer$createTask$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/Timer.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/Timer.class
new file mode 100644
index 0000000..1f0254f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/Timer.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/TimerType$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/TimerType$Companion.class
new file mode 100644
index 0000000..ed9b5bd
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/TimerType$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/TimerType.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/TimerType.class
new file mode 100644
index 0000000..37cf8e6
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/data/TimerType.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerCreateEvent$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerCreateEvent$Companion.class
new file mode 100644
index 0000000..aa821ad
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerCreateEvent$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerCreateEvent.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerCreateEvent.class
new file mode 100644
index 0000000..d6b1123
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerCreateEvent.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExpireEvent$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExpireEvent$Companion.class
new file mode 100644
index 0000000..c06c745
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExpireEvent$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExpireEvent.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExpireEvent.class
new file mode 100644
index 0000000..4ce3dcf
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExpireEvent.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExtendEvent$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExtendEvent$Companion.class
new file mode 100644
index 0000000..dc89b49
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExtendEvent$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExtendEvent.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExtendEvent.class
new file mode 100644
index 0000000..4f1cb43
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerExtendEvent.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerRemoveEvent$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerRemoveEvent$Companion.class
new file mode 100644
index 0000000..ab4ff37
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerRemoveEvent$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerRemoveEvent.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerRemoveEvent.class
new file mode 100644
index 0000000..f02c279
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/event/TimerRemoveEvent.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/AntidoteListener$onTimerCreate$1.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/AntidoteListener$onTimerCreate$1.class
new file mode 100644
index 0000000..8e8e409
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/AntidoteListener$onTimerCreate$1.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/AntidoteListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/AntidoteListener.class
new file mode 100644
index 0000000..8d1e864
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/AntidoteListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/EnderpearlListener$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/EnderpearlListener$Companion.class
new file mode 100644
index 0000000..19c9ec3
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/EnderpearlListener$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/EnderpearlListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/EnderpearlListener.class
new file mode 100644
index 0000000..c78d055
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/EnderpearlListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/HomeListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/HomeListener.class
new file mode 100644
index 0000000..277c2a8
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/HomeListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/RespawnListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/RespawnListener.class
new file mode 100644
index 0000000..84cae57
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/RespawnListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/TimerListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/TimerListener.class
new file mode 100644
index 0000000..ab9599c
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/timer/listener/TimerListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/VillagerHandler$Companion.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/VillagerHandler$Companion.class
new file mode 100644
index 0000000..2cfb9aa
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/VillagerHandler$Companion.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/VillagerHandler.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/VillagerHandler.class
new file mode 100644
index 0000000..ca8678c
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/VillagerHandler.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/data/VillagerEntity.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/data/VillagerEntity.class
new file mode 100644
index 0000000..61e0c7f
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/data/VillagerEntity.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/data/kb/ZeroKBProfile.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/data/kb/ZeroKBProfile.class
new file mode 100644
index 0000000..b667a69
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/data/kb/ZeroKBProfile.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerListener.class
new file mode 100644
index 0000000..49cc692
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerLoggerListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerLoggerListener.class
new file mode 100644
index 0000000..8c419cd
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerLoggerListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerPacketListener.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerPacketListener.class
new file mode 100644
index 0000000..0eca874
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/listener/VillagerPacketListener.class differ
diff --git a/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/service/VillagerLoggerService.class b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/service/VillagerLoggerService.class
new file mode 100644
index 0000000..2a74075
Binary files /dev/null and b/Bunkers/build/classes/kotlin/main/cc/fyre/bunkers/villager/service/VillagerLoggerService.class differ
diff --git a/Bunkers/build/kotlin/compileKotlin/build-history.bin b/Bunkers/build/kotlin/compileKotlin/build-history.bin
new file mode 100644
index 0000000..211cfea
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/build-history.bin differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab
new file mode 100644
index 0000000..4a132c5
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream
new file mode 100644
index 0000000..31db614
--- /dev/null
+++ b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream
@@ -0,0 +1 @@
+Q$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\command\KOTHSetTimeCommand.ktF$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\EnchantMenu.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\data\TimerType.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\BuildMenu.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\service\BardService.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerExtendEvent.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamInfoCommand.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetDTRCommand.kt\$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\InProgressScoreboardAdapter.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\data\Supply.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\TimerHandler.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamChestListener.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\movement\ClaimMovementAdapter.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamClaimCommand.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\data\Claim.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\PvPClassEquipEvent.kt[$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\CountdownScoreboardAdapter.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\parameter\ShopTypeParameterProvider.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\listener\RepairListener.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\PvPClassUnEquipEvent.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\listener\ShopListener.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\service\ShopService.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\CombatMenu.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\menu\element\RepairButton.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\LunarClientListener.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\command\KOTHStartCommand.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\service\VillagerLoggerService.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\listener\SupplyListener.ktG$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\PvPClass.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarWallListener.ktX$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\VotingScoreboardAdapter.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\type\BardEffectEvent.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarPacketListener.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\listener\EventListener.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\ClassMenu.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\EnderpearlListener.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamChatListener.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\ShopHandler.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\TeamHandler.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\service\EventService.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\service\BalanceService.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\data\kb\ZeroKBProfile.ktG$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\menu\RepairMenu.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\AntidoteListener.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamLocationCommand.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\listener\PvPClassListener.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\data\Pillar.kt]$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\parameter\TeamParameterProvider.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\TimerListener.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\data\Timer.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\command\BalanceCommand.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\data\TeamChest.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\data\ShopType.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\VotingListener.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetHologramCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerRemoveEvent.ktH$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\BunkersGameAdapter.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\SellElement.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\TeamChestModifyMenu.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\SellMenu.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\button\TeamChestPurchaseButton.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\data\adapter\WallAdapter.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\command\PayCommand.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\tab\BunkersTabAdapter.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\button\TeamChestMemberButton.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamChatCommand.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamRallyListener.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamVoteKickCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\data\VillagerEntity.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\EnchantElement.ktc$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\deathmessage\BunkersDeathMessageConfiguration.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\PillarHandler.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetShopCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetHQCommand.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamHQCommand.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\TeamChestPurchaseMenu.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\VillagerHandler.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\WaitingScoreboardAdapter.kt?$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\data\Team.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\SupplyHandler.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerExpireEvent.kt8$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\Bunkers.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\BuyElement.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\type\BardClass.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\RespawnListener.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\PvPClassHandler.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamListener.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamFocusCommand.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\RepairHandler.ktL$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\HomeListener.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerListener.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\item\energy\EnergyEffect.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\GameListener.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\listener\ClaimPositionListener.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerLoggerListener.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamRallyCommand.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerPacketListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\listener\StatisticListener.ktL$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\ChunkListener.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\EventHandler.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\item\ConsumableItem.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\listener\ClaimListener.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerCreateEvent.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\StatisticHandler.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamProtectionListener.ktJ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\data\ClaimSelection.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\ClaimHandler.kt
\ No newline at end of file
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len
new file mode 100644
index 0000000..4ee2ced
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len
new file mode 100644
index 0000000..a5fbec6
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at
new file mode 100644
index 0000000..ba08800
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i
new file mode 100644
index 0000000..4b1d575
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab
new file mode 100644
index 0000000..0a3f5f3
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream
new file mode 100644
index 0000000..aa71739
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len
new file mode 100644
index 0000000..8aa3e07
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len
new file mode 100644
index 0000000..c8fcfd5
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at
new file mode 100644
index 0000000..3a69b8c
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i
new file mode 100644
index 0000000..2270724
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab
new file mode 100644
index 0000000..b2011f2
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream
new file mode 100644
index 0000000..aa71739
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len
new file mode 100644
index 0000000..8aa3e07
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len
new file mode 100644
index 0000000..c8fcfd5
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at
new file mode 100644
index 0000000..e74b63c
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i
new file mode 100644
index 0000000..2270724
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab
new file mode 100644
index 0000000..14dadaa
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream
new file mode 100644
index 0000000..f8d2c20
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len
new file mode 100644
index 0000000..c74a057
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len
new file mode 100644
index 0000000..ec8f944
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at
new file mode 100644
index 0000000..ca60b73
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i
new file mode 100644
index 0000000..eda4a5c
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab
new file mode 100644
index 0000000..9dca8c7
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream
new file mode 100644
index 0000000..b8e7ca0
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len
new file mode 100644
index 0000000..396b400
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len
new file mode 100644
index 0000000..73f3a40
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at
new file mode 100644
index 0000000..906b9aa
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i
new file mode 100644
index 0000000..f98dde9
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab
new file mode 100644
index 0000000..cf0a9b4
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream
new file mode 100644
index 0000000..49dd08b
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len
new file mode 100644
index 0000000..bb7002d
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len
new file mode 100644
index 0000000..90f446f
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values
new file mode 100644
index 0000000..c25a598
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at
new file mode 100644
index 0000000..4c3e8fc
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.s b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.s
new file mode 100644
index 0000000..3af0aac
--- /dev/null
+++ b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.s
@@ -0,0 +1 @@
+âµø²
\ No newline at end of file
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i
new file mode 100644
index 0000000..f723b6e
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab
new file mode 100644
index 0000000..5faf1e8
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream
new file mode 100644
index 0000000..726fd8c
--- /dev/null
+++ b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream
@@ -0,0 +1 @@
+8$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\Bunkers.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\ClaimHandler.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\data\Claim.ktJ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\data\ClaimSelection.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\listener\ClaimListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\listener\ClaimPositionListener.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\movement\ClaimMovementAdapter.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\EventHandler.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\command\KOTHSetTimeCommand.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\command\KOTHStartCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\listener\EventListener.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\service\EventService.ktH$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\BunkersGameAdapter.ktc$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\deathmessage\BunkersDeathMessageConfiguration.ktL$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\ChunkListener.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\GameListener.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\LunarClientListener.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\VotingListener.kt[$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\CountdownScoreboardAdapter.kt\$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\InProgressScoreboardAdapter.ktX$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\VotingScoreboardAdapter.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\WaitingScoreboardAdapter.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\tab\BunkersTabAdapter.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\PillarHandler.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\data\Pillar.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\data\adapter\WallAdapter.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarPacketListener.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarWallListener.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\PvPClassHandler.ktG$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\PvPClass.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\item\ConsumableItem.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\item\energy\EnergyEffect.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\service\BardService.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\type\BardClass.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\PvPClassEquipEvent.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\PvPClassUnEquipEvent.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\type\BardEffectEvent.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\listener\PvPClassListener.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\RepairHandler.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\listener\RepairListener.ktG$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\menu\RepairMenu.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\menu\element\RepairButton.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\ShopHandler.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\data\ShopType.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\listener\ShopListener.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\BuildMenu.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\ClassMenu.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\CombatMenu.ktF$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\EnchantMenu.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\SellMenu.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\BuyElement.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\EnchantElement.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\SellElement.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\parameter\ShopTypeParameterProvider.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\service\ShopService.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\StatisticHandler.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\command\BalanceCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\command\PayCommand.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\listener\StatisticListener.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\service\BalanceService.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\SupplyHandler.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\data\Supply.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\listener\SupplyListener.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\TeamHandler.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamChatCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamClaimCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamFocusCommand.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamHQCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamInfoCommand.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamLocationCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamRallyCommand.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetDTRCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetHQCommand.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetHologramCommand.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetShopCommand.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamVoteKickCommand.kt]$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\parameter\TeamParameterProvider.kt?$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\data\Team.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\data\TeamChest.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamChatListener.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamChestListener.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamProtectionListener.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamRallyListener.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\TeamChestModifyMenu.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\TeamChestPurchaseMenu.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\button\TeamChestMemberButton.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\button\TeamChestPurchaseButton.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\TimerHandler.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\data\Timer.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\data\TimerType.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerCreateEvent.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerExpireEvent.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerExtendEvent.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerRemoveEvent.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\AntidoteListener.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\EnderpearlListener.ktL$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\HomeListener.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\RespawnListener.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\TimerListener.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\VillagerHandler.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\data\VillagerEntity.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\data\kb\ZeroKBProfile.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerListener.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerLoggerListener.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerPacketListener.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\service\VillagerLoggerService.kt
\ No newline at end of file
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len
new file mode 100644
index 0000000..4ee2ced
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len
new file mode 100644
index 0000000..a5fbec6
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at
new file mode 100644
index 0000000..3ce9024
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i
new file mode 100644
index 0000000..9299d12
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab
new file mode 100644
index 0000000..d4da447
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream
new file mode 100644
index 0000000..319fc62
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len
new file mode 100644
index 0000000..d73a735
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len
new file mode 100644
index 0000000..b31f54b
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at
new file mode 100644
index 0000000..0682e54
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i
new file mode 100644
index 0000000..ed93c06
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab
new file mode 100644
index 0000000..95137dd
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream
new file mode 100644
index 0000000..8dd30df
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len
new file mode 100644
index 0000000..e5ebdc5
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len
new file mode 100644
index 0000000..bba171d
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at
new file mode 100644
index 0000000..a81966d
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i
new file mode 100644
index 0000000..6ae275f
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab
new file mode 100644
index 0000000..2bef6ae
--- /dev/null
+++ b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab
@@ -0,0 +1,2 @@
+114
+6
\ No newline at end of file
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab
new file mode 100644
index 0000000..6ac1e4c
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream
new file mode 100644
index 0000000..726fd8c
--- /dev/null
+++ b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream
@@ -0,0 +1 @@
+8$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\Bunkers.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\ClaimHandler.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\data\Claim.ktJ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\data\ClaimSelection.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\listener\ClaimListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\listener\ClaimPositionListener.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\claim\movement\ClaimMovementAdapter.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\EventHandler.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\command\KOTHSetTimeCommand.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\command\KOTHStartCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\listener\EventListener.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\event\service\EventService.ktH$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\BunkersGameAdapter.ktc$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\deathmessage\BunkersDeathMessageConfiguration.ktL$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\ChunkListener.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\GameListener.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\LunarClientListener.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\listener\VotingListener.kt[$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\CountdownScoreboardAdapter.kt\$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\InProgressScoreboardAdapter.ktX$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\VotingScoreboardAdapter.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\scoreboard\WaitingScoreboardAdapter.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\game\tab\BunkersTabAdapter.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\PillarHandler.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\data\Pillar.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\data\adapter\WallAdapter.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarPacketListener.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pillar\listener\PillarWallListener.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\PvPClassHandler.ktG$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\PvPClass.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\item\ConsumableItem.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\item\energy\EnergyEffect.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\service\BardService.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\data\type\BardClass.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\PvPClassEquipEvent.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\PvPClassUnEquipEvent.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\event\type\BardEffectEvent.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\pvpclass\listener\PvPClassListener.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\RepairHandler.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\listener\RepairListener.ktG$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\menu\RepairMenu.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\repair\menu\element\RepairButton.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\ShopHandler.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\data\ShopType.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\listener\ShopListener.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\BuildMenu.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\ClassMenu.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\CombatMenu.ktF$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\EnchantMenu.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\SellMenu.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\BuyElement.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\EnchantElement.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\menu\element\SellElement.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\parameter\ShopTypeParameterProvider.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\shop\service\ShopService.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\StatisticHandler.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\command\BalanceCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\command\PayCommand.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\listener\StatisticListener.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\statistic\service\BalanceService.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\SupplyHandler.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\data\Supply.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\supply\listener\SupplyListener.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\TeamHandler.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamChatCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamClaimCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamFocusCommand.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamHQCommand.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamInfoCommand.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamLocationCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamRallyCommand.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetDTRCommand.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetHQCommand.ktT$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetHologramCommand.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamSetShopCommand.ktQ$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\TeamVoteKickCommand.kt]$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\command\parameter\TeamParameterProvider.kt?$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\data\Team.ktD$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\data\TeamChest.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamChatListener.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamChestListener.ktK$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamListener.ktU$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamProtectionListener.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\listener\TeamRallyListener.ktN$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\TeamChestModifyMenu.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\TeamChestPurchaseMenu.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\button\TeamChestMemberButton.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\team\menu\button\TeamChestPurchaseButton.ktC$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\TimerHandler.ktA$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\data\Timer.ktE$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\data\TimerType.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerCreateEvent.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerExpireEvent.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerExtendEvent.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\event\TimerRemoveEvent.ktP$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\AntidoteListener.ktR$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\EnderpearlListener.ktL$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\HomeListener.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\RespawnListener.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\timer\listener\TimerListener.ktI$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\VillagerHandler.ktM$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\data\VillagerEntity.ktO$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\data\kb\ZeroKBProfile.ktS$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerListener.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerLoggerListener.ktY$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\listener\VillagerPacketListener.ktW$PROJECT_DIR$\src\main\kotlin\cc\fyre\bunkers\villager\service\VillagerLoggerService.kt
\ No newline at end of file
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len
new file mode 100644
index 0000000..4ee2ced
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len
new file mode 100644
index 0000000..a5fbec6
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at
new file mode 100644
index 0000000..5f07d47
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i
new file mode 100644
index 0000000..25e690c
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab
new file mode 100644
index 0000000..36afa02
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream
new file mode 100644
index 0000000..3f77128
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len
new file mode 100644
index 0000000..cfeb6a8
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len
new file mode 100644
index 0000000..5672451
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at
new file mode 100644
index 0000000..8b24c41
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i
new file mode 100644
index 0000000..1401fd5
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab
new file mode 100644
index 0000000..ba569a6
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream
new file mode 100644
index 0000000..6d1fc79
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len
new file mode 100644
index 0000000..ee7366c
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len
new file mode 100644
index 0000000..a4bec2c
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values
new file mode 100644
index 0000000..83e39c2
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at
new file mode 100644
index 0000000..7ffdf31
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.s b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.s
new file mode 100644
index 0000000..6631c3d
--- /dev/null
+++ b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.s
@@ -0,0 +1 @@
+ísÛ}ârÊ–ðbÅX
\ No newline at end of file
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i
new file mode 100644
index 0000000..01f3248
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i differ
diff --git a/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len
new file mode 100644
index 0000000..5315f7a
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len differ
diff --git a/Bunkers/build/kotlin/compileKotlin/last-build.bin b/Bunkers/build/kotlin/compileKotlin/last-build.bin
new file mode 100644
index 0000000..9e10ea4
Binary files /dev/null and b/Bunkers/build/kotlin/compileKotlin/last-build.bin differ
diff --git a/Bunkers/build/libs/bunkers-1.0-SNAPSHOT.jar b/Bunkers/build/libs/bunkers-1.0-SNAPSHOT.jar
new file mode 100644
index 0000000..5fe82d4
Binary files /dev/null and b/Bunkers/build/libs/bunkers-1.0-SNAPSHOT.jar differ
diff --git a/Bunkers/build/publications/shadow/pom-default.xml b/Bunkers/build/publications/shadow/pom-default.xml
new file mode 100644
index 0000000..59d084f
--- /dev/null
+++ b/Bunkers/build/publications/shadow/pom-default.xml
@@ -0,0 +1,8 @@
+
+
+ 4.0.0
+ cc.fyre.carnage
+ bunkers
+ 1.0-SNAPSHOT
+
+
diff --git a/Bunkers/build/resources/main/plugin.yml b/Bunkers/build/resources/main/plugin.yml
new file mode 100644
index 0000000..8009c4e
--- /dev/null
+++ b/Bunkers/build/resources/main/plugin.yml
@@ -0,0 +1,4 @@
+name: Bunkers
+main: cc.fyre.bunkers.Bunkers
+version: 1.0-SNAPSHOT
+depend: [qLib,GameEngine]
diff --git a/Bunkers/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml b/Bunkers/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml
new file mode 100644
index 0000000..9f9159d
--- /dev/null
+++ b/Bunkers/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml
@@ -0,0 +1,12 @@
+
+
+ cc.fyre.carnage
+ bunkers
+
+ 1.0-SNAPSHOT
+
+ 1.0-SNAPSHOT
+
+ 20210829081348
+
+
diff --git a/Bunkers/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml b/Bunkers/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml
new file mode 100644
index 0000000..a2d5d9d
--- /dev/null
+++ b/Bunkers/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml
@@ -0,0 +1,24 @@
+
+
+ cc.fyre.carnage
+ bunkers
+ 1.0-SNAPSHOT
+
+
+ true
+
+ 20210829081348
+
+
+ jar
+ 1.0-SNAPSHOT
+ 20210829081348
+
+
+ pom
+ 1.0-SNAPSHOT
+ 20210829081348
+
+
+
+
diff --git a/Bunkers/build/tmp/shadowJar/MANIFEST.MF b/Bunkers/build/tmp/shadowJar/MANIFEST.MF
new file mode 100644
index 0000000..59499bc
--- /dev/null
+++ b/Bunkers/build/tmp/shadowJar/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/Bunkers/gradle/wrapper/gradle-wrapper.jar b/Bunkers/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/Bunkers/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Bunkers/gradle/wrapper/gradle-wrapper.properties b/Bunkers/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..da9702f
--- /dev/null
+++ b/Bunkers/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/Bunkers/gradlew b/Bunkers/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/Bunkers/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/Bunkers/gradlew.bat b/Bunkers/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/Bunkers/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/Bunkers/settings.gradle b/Bunkers/settings.gradle
new file mode 100644
index 0000000..9d19b66
--- /dev/null
+++ b/Bunkers/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'bunkers'
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/Bunkers.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/Bunkers.kt
new file mode 100644
index 0000000..ad3e1a2
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/Bunkers.kt
@@ -0,0 +1,78 @@
+package cc.fyre.bunkers
+
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.claim.ClaimHandler
+import cc.fyre.bunkers.event.EventHandler
+import cc.fyre.bunkers.game.BunkersGameAdapter
+import cc.fyre.bunkers.game.tab.BunkersTabAdapter
+import cc.fyre.bunkers.pvpclass.PvPClassHandler
+import cc.fyre.bunkers.repair.RepairHandler
+import cc.fyre.bunkers.shop.ShopHandler
+import cc.fyre.bunkers.villager.VillagerHandler
+import cc.fyre.bunkers.statistic.StatisticHandler
+import cc.fyre.bunkers.supply.SupplyHandler
+import cc.fyre.bunkers.pillar.PillarHandler
+
+import cc.fyre.bunkers.timer.TimerHandler
+import cc.fyre.engine.GameEngine
+import net.frozenorb.qlib.tab.FrozenTabHandler
+
+import org.bukkit.plugin.java.JavaPlugin
+
+/**
+ * @project bunkers
+ *
+ * @date 30/07/2020
+ * @author xanderume@gmail.com
+ */
+class Bunkers : JavaPlugin() {
+
+ lateinit var adapter: BunkersGameAdapter
+
+ lateinit var shopHandler: ShopHandler
+ lateinit var teamHandler: TeamHandler
+ lateinit var claimHandler: ClaimHandler
+ lateinit var timerHandler: TimerHandler
+ lateinit var eventHandler: EventHandler
+ lateinit var supplyHandler: SupplyHandler
+ lateinit var repairHandler: RepairHandler
+ lateinit var pillarHandler: PillarHandler
+ lateinit var villagerHandler: VillagerHandler
+ lateinit var pvpClassHandler: PvPClassHandler
+ lateinit var statisticHandler: StatisticHandler
+
+ override fun onEnable() {
+ instance = this
+
+ this.adapter = BunkersGameAdapter(this)
+
+ GameEngine.instance.gameHandler.adapter = this.adapter
+
+ this.shopHandler = ShopHandler(this)
+ this.teamHandler = TeamHandler(this)
+ this.claimHandler = ClaimHandler(this)
+ this.eventHandler = EventHandler(this)
+ this.timerHandler = TimerHandler(this)
+ this.supplyHandler = SupplyHandler(this)
+ this.repairHandler = RepairHandler(this)
+ this.pillarHandler = PillarHandler(this)
+ this.villagerHandler = VillagerHandler(this)
+ this.pvpClassHandler = PvPClassHandler(this)
+ this.statisticHandler = StatisticHandler(this)
+
+ FrozenTabHandler.setLayoutProvider(BunkersTabAdapter)
+ }
+
+
+ override fun onDisable() {
+ this.claimHandler.dispose()
+ this.supplyHandler.dispose()
+ this.pvpClassHandler.dispose()
+ }
+
+ companion object {
+
+ lateinit var instance: Bunkers
+
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/ClaimHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/ClaimHandler.kt
new file mode 100644
index 0000000..d05dfbe
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/ClaimHandler.kt
@@ -0,0 +1,57 @@
+package cc.fyre.bunkers.claim
+
+import net.hylist.HylistSpigot
+import cc.fyre.bunkers.Bunkers
+
+import cc.fyre.bunkers.claim.data.ClaimSelection
+import cc.fyre.bunkers.claim.listener.ClaimListener
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.bunkers.claim.listener.ClaimPositionListener
+import cc.fyre.bunkers.claim.movement.ClaimMovementAdapter
+import cc.fyre.engine.map.data.Map
+
+import org.bukkit.ChatColor
+
+import org.bukkit.entity.Player
+import java.util.*
+
+
+/**
+ * @project hcf
+ *
+ * @date 04/04/2020
+ * @author xanderume@gmail.com
+ */
+class ClaimHandler(private val instance: Bunkers) {
+
+ val selections = HashMap()
+
+ init {
+ HylistSpigot.INSTANCE.addMovementHandler(ClaimMovementAdapter(this.instance))
+
+ this.instance.server.pluginManager.registerEvents(ClaimListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(ClaimMovementAdapter(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(ClaimPositionListener(this.instance),this.instance)
+ }
+
+ fun findSelection(uuid: UUID):Optional {
+ return Optional.ofNullable(this.selections[uuid])
+ }
+
+ fun startSelection(player: Player,team: Team,map: Map,slot: Int) {
+
+ if (this.selections.remove(player.uniqueId) != null) {
+ player.inventory.removeItem(ClaimSelection.ITEM)
+ }
+
+ player.inventory.setItem(slot,ClaimSelection.ITEM)
+ player.sendMessage("${ChatColor.GREEN}You have been given a claiming wand.")
+
+ this.selections[player.uniqueId] = ClaimSelection(map,team)
+ }
+
+ fun dispose() {
+ this.selections.keys.map{this.instance.server.getPlayer(it)}.filter{it != null}.forEach{it.inventory.removeItem(ClaimSelection.ITEM)}
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/data/Claim.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/data/Claim.kt
new file mode 100644
index 0000000..c46b835
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/data/Claim.kt
@@ -0,0 +1,104 @@
+package cc.fyre.bunkers.claim.data
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+import org.bukkit.Location
+import org.bukkit.World
+import org.bukkit.block.Block
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * @project hcf
+ *
+ * @date 04/04/2020
+ * @author xanderume@gmail.com
+ */
+class Claim(world: World,x1: Int,x2: Int,z1: Int,z2: Int) {
+
+ constructor(first: Location,second: Location):this(first.world,first.blockX,second.blockX,first.blockZ,second.blockZ)
+
+ private val x1 = min(x1,x2)
+ private val x2 = max(x1,x2)
+ private val z1 = min(z1,z2)
+ private val z2 = max(z1,z2)
+
+ private val world = world.name
+
+ fun findWorld():World? = Bunkers.instance.server.getWorld(this.world)
+
+ fun contains(x: Int,z: Int,world: World):Boolean {
+ return x >= this.x1 && x <= this.x2 && z >= this.z1 && z <= this.z2 && this.world == world.name
+ }
+
+ fun contains(location: Location):Boolean {
+
+ val world = this.findWorld() ?: return false
+
+ return this.contains(location.blockX,location.blockZ,world)
+ }
+
+ fun getLower():Location {
+ return Location(this.findWorld(),this.x1.toDouble(),0.0,this.z1.toDouble())
+ }
+
+ fun getUpper():Location {
+ return Location(this.findWorld(),this.x2.toDouble(),256.0,this.z2.toDouble())
+ }
+
+ fun borderIterator():Iterator> {
+ return BorderIterator(this,this.x1,this.z1,this.x2,this.z2)
+ }
+
+ // HCTeams can suck my dick nigga
+ class BorderIterator(val claim: Claim,x1: Int, z1: Int, x2: Int, z2: Int) : MutableIterator> {
+
+ private var x: Int = min(x1,x2)
+ private var z: Int = min(z1,z2)
+
+ private var next = true
+ private var direction = BorderDirection.POS_Z
+
+ private var minX: Int = this.claim.getLower().blockX
+ private var minZ: Int = this.claim.getLower().blockZ
+ private var maxX: Int = this.claim.getUpper().blockX
+ private var maxZ: Int = this.claim.getUpper().blockZ
+
+ override fun hasNext(): Boolean {
+ return this.next
+ }
+
+ override fun next():Pair {
+ if (this.direction == BorderDirection.POS_Z) {
+ if (++this.z == this.maxZ) {
+ this.direction = BorderDirection.POS_X
+ }
+ } else if (this.direction == BorderDirection.POS_X) {
+ if (++this.x == this.maxX) {
+ this.direction = BorderDirection.NEG_Z
+ }
+ } else if (this.direction == BorderDirection.NEG_Z) {
+ if (--this.z == this.minZ) {
+ this.direction = BorderDirection.NEG_X
+ }
+ } else if (this.direction == BorderDirection.NEG_X) {
+ if (--this.x == this.minX) {
+ this.next = false
+ }
+ }
+ return Pair(this.x,this.z)
+ }
+
+ override fun remove() {}
+
+ enum class BorderDirection {
+
+ POS_X,
+ POS_Z,
+ NEG_X,
+ NEG_Z
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/data/ClaimSelection.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/data/ClaimSelection.kt
new file mode 100644
index 0000000..0692edb
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/data/ClaimSelection.kt
@@ -0,0 +1,49 @@
+package cc.fyre.bunkers.claim.data
+
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.engine.map.data.Map
+import net.frozenorb.qlib.util.ItemBuilder
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.Material
+
+import org.bukkit.event.block.Action
+
+/**
+ * @project hcf
+ *
+ * @date 04/04/2020
+ * @author xanderume@gmail.com
+ */
+class ClaimSelection(val map: Map,val team: Team) {
+
+ var first: Location? = null
+ var second: Location? = null
+
+ fun getFormattedMessage(action: Action,location: Location):Array {
+
+ val toReturn = arrayOfNulls(1)
+
+ toReturn[0] = "${ChatColor.YELLOW}Set claim's location ${ChatColor.LIGHT_PURPLE}${if (action == Action.LEFT_CLICK_BLOCK) 1 else 2}${ChatColor.YELLOW} to ${ChatColor.GREEN}(${ChatColor.WHITE}${location.blockX}, ${location.blockY}, ${location.blockZ}${ChatColor.GREEN})${ChatColor.YELLOW}."
+
+ return toReturn
+ }
+
+ companion object {
+
+ val ITEM = ItemBuilder.of(Material.WOOD_HOE)
+ .name("${ChatColor.GREEN}${ChatColor.ITALIC}Claiming Wand")
+ .addToLore(
+ "",
+ "${ChatColor.YELLOW}Right Click ${ChatColor.GOLD}Air",
+ "${ChatColor.AQUA}- ${ChatColor.WHITE}Cancel current claim",
+ "",
+ "${ChatColor.YELLOW}Right/Left Click ${ChatColor.GOLD}Block",
+ "${ChatColor.AQUA}- ${ChatColor.WHITE}Select claim's corners",
+ "",
+ "${ChatColor.BLUE}Crouch ${ChatColor.YELLOW}Left Click ${ChatColor.GOLD}Block/Air",
+ "${ChatColor.AQUA}- ${ChatColor.WHITE}Purchase current claim"
+ ).build()
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/listener/ClaimListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/listener/ClaimListener.kt
new file mode 100644
index 0000000..3634dcf
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/listener/ClaimListener.kt
@@ -0,0 +1,59 @@
+package cc.fyre.bunkers.claim.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.claim.data.ClaimSelection
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+
+import org.bukkit.event.player.PlayerDropItemEvent
+import org.bukkit.event.player.PlayerItemDamageEvent
+import org.bukkit.event.player.PlayerQuitEvent
+
+/**
+ * @project hcf
+ *
+ * @date 01/05/2020
+ * @author xanderume@gmail.com
+ */
+class ClaimListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+
+ if (!this.instance.claimHandler.findSelection(event.player.uniqueId).isPresent) {
+ return
+ }
+
+ event.player.inventory.remove(ClaimSelection.ITEM)
+
+ this.instance.claimHandler.selections.remove(event.player.uniqueId)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerDropItem(event: PlayerDropItemEvent) {
+
+ if (!event.itemDrop.itemStack.isSimilar(ClaimSelection.ITEM)) {
+ return
+ }
+
+ event.itemDrop.remove()
+
+ this.instance.claimHandler.selections.remove(event.player.uniqueId)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerDamageItem(event: PlayerItemDamageEvent) {
+
+ if (!event.item.isSimilar(ClaimSelection.ITEM)) {
+ return
+ }
+
+ if (!this.instance.claimHandler.findSelection(event.player.uniqueId).isPresent) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/listener/ClaimPositionListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/listener/ClaimPositionListener.kt
new file mode 100644
index 0000000..2904add
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/listener/ClaimPositionListener.kt
@@ -0,0 +1,96 @@
+package cc.fyre.bunkers.claim.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.claim.data.Claim
+import cc.fyre.bunkers.claim.data.ClaimSelection
+import org.bukkit.Bukkit
+
+import org.bukkit.ChatColor
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.Action
+import org.bukkit.event.player.PlayerInteractEvent
+
+
+/**
+ * @project hcf
+ *
+ * @date 03/06/2020
+ * @author xanderume@gmail.com
+ */
+class ClaimPositionListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerInteract(event: PlayerInteractEvent) {
+
+ if (event.item == null) {
+ return
+ }
+
+ if (!event.item.isSimilar(ClaimSelection.ITEM)) {
+ return
+ }
+
+ val optionalSelection = this.instance.claimHandler.findSelection(event.player.uniqueId)
+
+ if (!optionalSelection.isPresent) {
+ return
+ }
+
+ val selection = optionalSelection.get()
+
+ event.isCancelled = true
+
+ if (event.action == Action.RIGHT_CLICK_AIR) {
+ event.player.itemInHand = null
+ event.player.sendMessage("${ChatColor.RED}You have cancelled the claiming process.")
+
+ this.instance.claimHandler.selections.remove(event.player.uniqueId)
+ return
+ }
+
+ if (event.action == Action.LEFT_CLICK_AIR) {
+
+ if (!event.player.isSneaking) {
+ return
+ }
+
+ if (selection.first == null || selection.second == null) {
+ event.player.sendMessage("${ChatColor.RED}You have not selected both corners of your claim yet!")
+ return
+ }
+
+ event.player.itemInHand = null
+
+ this.instance.claimHandler.selections.remove(event.player.uniqueId)
+
+ selection.team.claim = Claim(selection.first!!,selection.second!!)
+
+ Bukkit.getServer().scheduler.runTaskAsynchronously(this.instance) {
+
+ if (!Bunkers.instance.teamHandler.saveTeamData(selection.team,selection.map).wasAcknowledged()) {
+ event.player.sendMessage("${ChatColor.RED}Failed to update team data..")
+ return@runTaskAsynchronously
+ }
+
+ event.player.sendMessage("${ChatColor.YELLOW}Updated ${selection.team.type.getDisplayName()}${ChatColor.YELLOW}'s claim on map ${ChatColor.LIGHT_PURPLE}${selection.map.id}${ChatColor.YELLOW}.")
+ }
+ return
+ }
+
+ if (event.clickedBlock == null) {
+ return
+ }
+
+ if (event.action == Action.LEFT_CLICK_BLOCK) {
+ selection.first = event.clickedBlock.location
+ } else {
+ selection.second = event.clickedBlock.location
+ }
+
+ selection.getFormattedMessage(event.action,event.clickedBlock.location).filterNotNull().forEach{event.player.sendMessage(it)}
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/movement/ClaimMovementAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/movement/ClaimMovementAdapter.kt
new file mode 100644
index 0000000..1586fa0
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/claim/movement/ClaimMovementAdapter.kt
@@ -0,0 +1,60 @@
+package cc.fyre.bunkers.claim.movement
+
+import cc.fyre.bunkers.Bunkers
+import net.hylist.handler.MovementHandler
+
+import mkremins.fanciful.FancyMessage
+import net.minecraft.server.v1_7_R4.PacketPlayInFlying
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerTeleportEvent
+
+/**
+ * @project hcf
+ *
+ * @date 03/06/2020
+ * @author xanderume@gmail.com
+ */
+class ClaimMovementAdapter(private val instance: Bunkers) : MovementHandler,Listener {
+
+ override fun handleUpdateRotation(player: Player,to: Location,from: Location,packet: PacketPlayInFlying?) {}
+
+ override fun handleUpdateLocation(player: Player,to: Location,from: Location,packet: PacketPlayInFlying?) {
+
+ if (from.blockX == to.blockX && from.blockZ == to.blockZ) {
+ return
+ }
+
+ val toTeam = this.instance.teamHandler.findByLocation(to)
+ val fromTeam = this.instance.teamHandler.findByLocation(from)
+
+ if (fromTeam.type == toTeam.type) {
+ return
+ }
+
+ FancyMessage("${ChatColor.YELLOW}Now leaving: ")
+ .then(fromTeam.getDisplayName())
+ .tooltip("${ChatColor.GREEN}Click to view team info.")
+ .command("/team info ${fromTeam.type.name}")
+ .then("${ChatColor.YELLOW} (${ChatColor.RED}Dangerous${ChatColor.YELLOW})")
+ .send(player)
+
+ FancyMessage("${ChatColor.YELLOW}Now entering: ")
+ .then(toTeam.getDisplayName())
+ .tooltip("${ChatColor.GREEN}Click to view team info.")
+ .command("/team info ${toTeam.type.name}")
+ .then("${ChatColor.YELLOW} (${ChatColor.RED}Dangerous${ChatColor.YELLOW})")
+ .send(player)
+
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+ this.handleUpdateLocation(event.player,event.to,event.from,null)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/EventHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/EventHandler.kt
new file mode 100644
index 0000000..2fdecf7
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/EventHandler.kt
@@ -0,0 +1,143 @@
+package cc.fyre.bunkers.event
+
+import net.hylist.HylistSpigot
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.event.command.KOTHSetTimeCommand
+import cc.fyre.bunkers.event.command.KOTHStartCommand
+import cc.fyre.bunkers.event.listener.EventListener
+import cc.fyre.bunkers.event.service.EventService
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.bunkers.team.listener.TeamProtectionListener
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.engine.GameEngine
+import net.frozenorb.qlib.command.FrozenCommandHandler
+import net.frozenorb.qlib.util.TimeUtils
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.entity.Player
+import java.util.*
+import java.util.concurrent.TimeUnit
+import kotlin.math.abs
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class EventHandler(private val instance: Bunkers) {
+
+ private var active = false
+
+ var controller: UUID? = null
+ var maxControlTime = 480
+
+ var controlledBy: UUID? = null
+ var controlledByTeam: Team? = null
+
+ val service = EventService(this.instance)
+
+ init {
+ HylistSpigot.INSTANCE.addMovementHandler(EventListener(this.instance))
+
+ FrozenCommandHandler.registerClass(KOTHStartCommand::class.java)
+ FrozenCommandHandler.registerClass(KOTHSetTimeCommand::class.java)
+
+ this.instance.server.pluginManager.registerEvents(EventListener(this.instance),this.instance)
+ }
+
+ fun isActive():Boolean {
+ return this.active
+ }
+
+ fun setActive(value: Boolean) {
+
+ if (value) {
+ this.service.runTaskTimer(this.instance,20L,20L)
+ this.instance.server.broadcastMessage("$PREFIX ${ChatColor.BLUE}${GameEngine.instance.gameHandler.map.id}${ChatColor.YELLOW} can now be contested.")
+ }
+
+ this.active = value
+ }
+
+ fun setMaxCaptureTime(seconds: Int) {
+
+ if (this.service.remaining.get() > seconds) {
+ this.service.remaining.set(seconds)
+ }
+
+ this.maxControlTime = seconds
+ this.instance.server.broadcastMessage("$PREFIX ${ChatColor.BLUE}${GameEngine.instance.gameHandler.map.id}${ChatColor.YELLOW} has been reduced to ${ChatColor.RED}${TimeUtils.formatIntoDetailedString(seconds)}${ChatColor.YELLOW}.")
+ }
+
+ fun getCaptureZone():Location {
+ return this.instance.teamHandler.cache[Team.Type.KOTH]?.hq ?: this.instance.server.getWorld(GameEngine.instance.gameHandler.map.id).spawnLocation.clone().add(0.5,0.0,0.5)
+ }
+
+ fun setController(player: Player?) {
+
+ if ((this.maxControlTime - this.service.remaining.get() > 30)) {
+ this.instance.server.broadcastMessage("$PREFIX ${ChatColor.YELLOW}Control of ${ChatColor.BLUE}${GameEngine.instance.gameHandler.map.id}${ChatColor.YELLOW} lost.")
+ }
+
+ this.service.remaining.set(this.maxControlTime)
+
+ this.controller = player?.uniqueId
+
+ if (player == null) {
+ this.service.remaining.set(this.maxControlTime)
+ return
+ }
+
+ player.sendMessage("$PREFIX ${ChatColor.YELLOW}Attempting to control ${ChatColor.BLUE}${GameEngine.instance.gameHandler.map.id}${ChatColor.YELLOW}.")
+ }
+
+ fun isInsideCaptureZone(location: Location, player: Player):Boolean {
+
+ val zone = this.getCaptureZone()
+
+ if (!location.world.name.equals(zone.world.name,true)) {
+ return false
+ }
+
+ if (TeamProtectionListener.protection.containsKey(player.uniqueId)) {
+ return false
+ }
+
+ if (GameEngine.instance.spectateHandler.isSpectating(player.uniqueId)) {
+ return false
+ }
+
+ if (GameEngine.instance.disqualifieHandler.isDisqualified(player.uniqueId)) {
+ return false
+ }
+
+ val respawn = this.instance.timerHandler.findRemaining(player.uniqueId, TimerType.RESPAWN)
+
+ if (respawn > 0L) {
+ return false
+ }
+
+ var radius = 3
+
+ if (location.world.name.equals("Classic",true)) {
+ radius = 5
+ }
+
+ return abs(location.blockX - zone.blockX) <= radius && abs(location.blockY - zone.blockY) <= 5 && abs(location.blockZ - zone.blockZ) <= radius
+ }
+
+ companion object {
+
+ val PREFIX = "${ChatColor.GOLD}[KingOfTheHill]"
+ val KOTH_START_TIME = TimeUnit.MINUTES.toSeconds(10).toInt()
+ val CAPTURE_TIME_DECREASE = mutableMapOf(
+ TimeUnit.MINUTES.toSeconds(20).toInt() to 420,
+ TimeUnit.MINUTES.toSeconds(30).toInt() to 360,
+ TimeUnit.MINUTES.toSeconds(40).toInt() to 300,
+ TimeUnit.MINUTES.toSeconds(50).toInt() to 240,
+ TimeUnit.MINUTES.toSeconds(60).toInt() to 180
+ )
+
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/command/KOTHSetTimeCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/command/KOTHSetTimeCommand.kt
new file mode 100644
index 0000000..c371d1f
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/command/KOTHSetTimeCommand.kt
@@ -0,0 +1,17 @@
+package cc.fyre.bunkers.event.command
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import org.bukkit.command.CommandSender
+
+object KOTHSetTimeCommand {
+
+ @JvmStatic
+ @Command(names = ["koth settime","event settime"],permission = "op")
+ fun execute(sender: CommandSender, @Param(name = "seconds")seconds: Int) {
+ Bunkers.instance.eventHandler.service.remaining.set(seconds)
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/command/KOTHStartCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/command/KOTHStartCommand.kt
new file mode 100644
index 0000000..63f18bb
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/command/KOTHStartCommand.kt
@@ -0,0 +1,15 @@
+package cc.fyre.bunkers.event.command
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.command.Command
+import org.bukkit.command.CommandSender
+
+object KOTHStartCommand {
+
+ @JvmStatic
+ @Command(names = ["koth start","event start"],permission = "op")
+ fun execute(sender: CommandSender) {
+ Bunkers.instance.eventHandler.setActive(!Bunkers.instance.eventHandler.isActive())
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/listener/EventListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/listener/EventListener.kt
new file mode 100644
index 0000000..1bbf89f
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/listener/EventListener.kt
@@ -0,0 +1,109 @@
+package cc.fyre.bunkers.event.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.engine.GameEngine
+import net.hylist.handler.MovementHandler
+import net.minecraft.server.v1_7_R4.PacketPlayInFlying
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.PlayerDeathEvent
+import org.bukkit.event.player.PlayerQuitEvent
+import org.bukkit.event.player.PlayerTeleportEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class EventListener(private val instance: Bunkers):Listener,MovementHandler {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+
+ if (!this.instance.eventHandler.isActive()) {
+ return
+ }
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.player)) {
+ return
+ }
+
+ if (this.instance.eventHandler.controller == null || this.instance.eventHandler.controller != event.player.uniqueId) {
+ return
+ }
+
+ this.instance.eventHandler.setController(GameEngine.instance.gameHandler.getPlayers().filter{it.uniqueId != event.player.uniqueId}.firstOrNull{this.instance.eventHandler.isInsideCaptureZone(it.location, it)})
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerDeath(event: PlayerDeathEvent) {
+
+ if (!this.instance.eventHandler.isActive()) {
+ return
+ }
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.entity)) {
+ return
+ }
+
+ if (this.instance.eventHandler.controller == null || this.instance.eventHandler.controller != event.entity.uniqueId) {
+ return
+ }
+
+ this.instance.eventHandler.setController(GameEngine.instance.gameHandler.getPlayers().filter{it.uniqueId != event.entity.uniqueId}.firstOrNull{this.instance.eventHandler.isInsideCaptureZone(it.location, it)})
+ return
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+ this.handleUpdateLocation(event.player,event.to,event.from,null)
+ }
+
+ override fun handleUpdateRotation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {}
+
+ override fun handleUpdateLocation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {
+
+ if (from.blockX == to.blockX && from.blockZ == to.blockZ) {
+ return
+ }
+
+ if (!this.instance.eventHandler.isActive()) {
+ return
+ }
+
+ if (!GameEngine.instance.gameHandler.isPlaying(player)) {
+ return
+ }
+
+ if (GameEngine.instance.spectateHandler.isSpectating(player)) {
+ return
+ }
+
+ if (this.instance.eventHandler.controller != null) {
+
+ if (player.uniqueId != this.instance.eventHandler.controller) {
+ return
+ }
+
+ if (this.instance.eventHandler.isInsideCaptureZone(to, player)) {
+ return
+ }
+
+ this.instance.eventHandler.setController(GameEngine.instance.gameHandler.getPlayers().filter{it.uniqueId != player.uniqueId}.firstOrNull{this.instance.eventHandler.isInsideCaptureZone(it.location, it)})
+ return
+ }
+
+ if (!this.instance.eventHandler.isInsideCaptureZone(to, player)) {
+ return
+ }
+
+ this.instance.eventHandler.setController(player)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/service/EventService.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/service/EventService.kt
new file mode 100644
index 0000000..1e83201
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/event/service/EventService.kt
@@ -0,0 +1,68 @@
+package cc.fyre.bunkers.event.service
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.event.EventHandler
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.util.TimeUtils
+import org.bukkit.ChatColor
+import org.bukkit.scheduler.BukkitRunnable
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class EventService(private val instance: Bunkers) : BukkitRunnable() {
+
+ val remaining = AtomicInteger(480)
+
+ override fun run() {
+
+ if (this.instance.eventHandler.controller == null) {
+ return
+ }
+
+ if (GameEngine.instance.gameHandler.getState() != GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(this.instance.eventHandler.controller)
+
+ if (player == null || !this.instance.eventHandler.isInsideCaptureZone(player.location, player) || player.isDead) {
+ this.instance.eventHandler.setController(GameEngine.instance.gameHandler.getPlayers().filter{it.uniqueId != this.instance.eventHandler.controller}.firstOrNull{this.instance.eventHandler.isInsideCaptureZone(it.location, it)})
+ return
+ }
+
+ if (this.remaining.get() <= 0) {
+ this.cancel()
+ this.instance.eventHandler.controlledBy = this.instance.eventHandler.controller!!
+ this.instance.eventHandler.controlledByTeam = this.instance.teamHandler.findById(this.instance.eventHandler.controller!!)
+ this.instance.eventHandler.setActive(false)
+ GameEngine.instance.gameHandler.setState(GameServer.State.ENDING)
+ return
+ }
+
+ if (this.remaining.get() != this.instance.eventHandler.maxControlTime && this.remaining.get() % 30 == 0) {
+
+ val team = this.instance.teamHandler.findById(this.instance.eventHandler.controller!!)!!
+
+ team.sendMessage("${EventHandler.PREFIX}${ChatColor.YELLOW} Your team is controlling ${ChatColor.BLUE}${GameEngine.instance.gameHandler.map.id}${ChatColor.YELLOW}.",this.instance.eventHandler.controller!!)
+
+ this.instance.server.getPlayer(this.instance.eventHandler.controller).sendMessage("${EventHandler.PREFIX}${ChatColor.YELLOW} Attempting to control ${ChatColor.BLUE}${GameEngine.instance.gameHandler.map.id}${ChatColor.YELLOW}.")
+
+ val ignore = team.members.plus(this.instance.eventHandler.controller)
+
+ this.instance.server.onlinePlayers.filter{!ignore.contains(it.uniqueId)}.forEach{
+ it.sendMessage(ChatColor.GOLD.toString() + "${EventHandler.PREFIX} ${ChatColor.BLUE}${GameEngine.instance.gameHandler.map.id}${ChatColor.YELLOW} is trying to be controlled. ${ChatColor.RED}(${TimeUtils.formatIntoHHMMSS(this.remaining.get())})")
+ }
+
+ }
+
+ this.remaining.decrementAndGet()
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/BunkersGameAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/BunkersGameAdapter.kt
new file mode 100644
index 0000000..a913c0a
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/BunkersGameAdapter.kt
@@ -0,0 +1,392 @@
+package cc.fyre.bunkers.game
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.event.EventHandler
+import cc.fyre.bunkers.game.deathmessage.BunkersDeathMessageConfiguration
+import cc.fyre.bunkers.game.listener.*
+import cc.fyre.bunkers.game.scoreboard.*
+
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.team.data.Team
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.game.adapter.GameAdapter
+import cc.fyre.engine.game.adapter.scoreboard.ScoreboardAdapter
+import cc.fyre.engine.game.data.Game
+import cc.fyre.engine.game.data.type.BunkersGame
+import cc.fyre.engine.profile.data.type.BunkersProfile
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.util.ItemBuilder
+import com.google.common.collect.ImmutableSet
+import com.google.gson.JsonObject
+import net.frozenorb.qlib.deathmessage.FrozenDeathMessageHandler
+import net.frozenorb.qlib.nametag.NametagInfo
+import net.frozenorb.qlib.nametag.NametagProvider
+import net.frozenorb.qlib.util.TimeUtils
+import net.frozenorb.qlib.util.UUIDUtils
+import org.apache.commons.lang.StringUtils
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.inventory.meta.PotionMeta
+import org.bukkit.potion.PotionEffect
+import org.bukkit.potion.PotionEffectType
+import java.util.*
+import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
+
+/**
+ * @project bunkers
+ *
+ * @date 13/08/2020
+ * @author xanderume@gmail.com
+ */
+class BunkersGameAdapter(private val instance: Bunkers) : GameAdapter {
+
+ init {
+
+ FrozenDeathMessageHandler.setConfiguration(BunkersDeathMessageConfiguration)
+
+ this.instance.server.pluginManager.registerEvents(GameListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(ChunkListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(VotingListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(LunarClientListener(this.instance),this.instance)
+ }
+
+ override fun onTick(seconds: Int) {
+
+ if (seconds >= EventHandler.KOTH_START_TIME && !this.instance.eventHandler.isActive()) {
+ this.instance.eventHandler.setActive(true)
+ }
+
+ if (EventHandler.CAPTURE_TIME_DECREASE.containsKey(seconds)) {
+ this.instance.eventHandler.setMaxCaptureTime(EventHandler.CAPTURE_TIME_DECREASE[seconds]!!)
+ }
+
+ if (TeamHandler.RAIDABLE_BROADCASTS.contains(seconds) || (TeamHandler.RAIDABLE_TIME - seconds <= 5 && seconds <= TeamHandler.RAIDABLE_TIME)) {
+ this.instance.server.broadcastMessage("${ChatColor.RED}${ChatColor.BOLD}All teams will go raidable in ${TimeUtils.formatIntoDetailedString((TeamHandler.RAIDABLE_TIME - seconds))}.")
+ }
+
+ if (seconds == TeamHandler.RAIDABLE_TIME) {
+ this.instance.server.broadcastMessage("${ChatColor.RED}${ChatColor.BOLD}All teams are now raidable.")
+ this.instance.teamHandler.findPlayerTeams().filter{!it.isRaidable()}.forEach{it.dtr = 0.0}
+ return
+ }
+
+ val payload = JsonObject()
+
+ payload.addProperty("GAME_TIME",seconds * 1000L)
+
+ if (this.instance.eventHandler.isActive()) {
+
+ val zoneData = JsonObject()
+
+ zoneData.addProperty("CAP_ZONE_NAME",this.instance.teamHandler.cache[Team.Type.KOTH]?.getDisplayName() ?: "")
+ zoneData.addProperty("CAP_ZONE_TIME",this.instance.eventHandler.service.remaining.get())
+
+ payload.add("CAP_ZONE_DATA",zoneData)
+ }
+
+ this.instance.teamHandler.findPlayerTeams().forEach{payload.addProperty("${it.type.name}_DTR",it.getDTRDisplay())}
+
+ GameEngine.instance.gameHandler.addMetadata(payload)
+ }
+
+ override fun onGameFinish() {
+
+ val team = this.instance.eventHandler.controlledByTeam
+
+ val messages = ArrayList()
+
+ messages.add(Team.LINE)
+ messages.add(" ")
+ messages.add(StringUtils.center("${ChatColor.GOLD}Winner: ${team?.getDisplayName() ?: "${ChatColor.WHITE}Unknown"}",Team.LINE.length))
+
+ if (team != null) {
+ messages.add(StringUtils.center(StringUtils.join(team.members.map{UUIDUtils.name(it)}.toTypedArray(),"${ChatColor.GRAY}, "),Team.LINE.length))
+ }
+
+ messages.add(" ")
+
+ val kills = this.instance.statisticHandler.kills.entries.sortedByDescending{it.value}.take(3)
+
+ messages.add(StringUtils.center("${ChatColor.GOLD}Top Kills:",Team.LINE.length))
+
+ val colors = arrayOf(ChatColor.DARK_GREEN,ChatColor.GREEN,ChatColor.GOLD)
+
+ kills.withIndex().forEach{messages.add(StringUtils.center("${colors[it.index]}#${it.index + 1} ${UUIDUtils.name(it.value.key)}${ChatColor.GRAY}: ${it.value.value}",Team.LINE.length))}
+
+ messages.add(" ")
+ messages.add(Team.LINE)
+
+ messages.forEach{this.instance.server.broadcastMessage(it)}
+ }
+
+ override fun onPlayersSent(players: ArrayList) {
+ GameEngine.instance.gameHandler.parties.sortedByDescending{it.size}.forEach{this.instance.teamHandler.addToTeam(it)}
+ //this.loadParties(ArrayList(GameEngine.instance.gameHandler.parties.sortedBy{it.size}))
+ }
+
+ override fun onGameAddPlayer(player: Player) {
+
+ val team = this.instance.teamHandler.findById(player.uniqueId)
+
+ if (team != null) {
+ return
+ }
+
+ if (this.instance.teamHandler.addToTeam(player.uniqueId) != null) {
+ return
+ }
+
+ GameEngine.instance.spectateHandler.addSpectator(player)
+ }
+
+ override fun onGameAddSpectator(player: Player) {
+
+ val team = this.instance.teamHandler.cache[Team.Type.KOTH] ?: return
+
+ player.teleport(team.hq)
+ }
+
+ override fun onGameDisqualifiePlayer(uuid: UUID) {
+
+ val name = "${this.instance.teamHandler.findById(uuid)?.type?.color ?: ChatColor.WHITE}${UUIDUtils.name(uuid)}"
+
+ this.instance.server.broadcastMessage("$name${ChatColor.GOLD}[${this.instance.statisticHandler.getKills(uuid)}]${ChatColor.RED} has been disqualified.")
+ }
+
+ override fun onGameRemovePlayer(player: Player) {}
+
+ override fun getNameTag(player: Player,target: Player):NametagInfo? {
+
+ val targetTeam = this.instance.teamHandler.findById(target.uniqueId)
+
+ if (targetTeam != null && targetTeam.isFocused(player)) {
+ return NametagProvider.createNametag(ChatColor.LIGHT_PURPLE.toString(),"")
+ }
+
+ val team = this.instance.teamHandler.findById(player.uniqueId)
+
+ if (team != null) {
+ val nameTagEntry = NametagProvider.createNametag(team.type.color.toString(),"")
+
+ if (targetTeam == null || !targetTeam.getName().equals(team.getName(), true)) {
+ //TODO nameTagEntry.allowFriendlyVisibility = false
+ }
+
+ if (targetTeam != null && targetTeam.getName().equals(team.getName(), true)) {
+ //TODO nameTagEntry.allowFriendlyVisibility = true
+ }
+
+ return NametagProvider.createNametag(team.type.color.toString(),"")
+ }
+
+ return null
+ }
+
+ override fun getScoreboardAdapters(): HashMap {
+
+ val toReturn = hashMapOf()
+
+ toReturn[GameServer.State.WAITING] = WaitingScoreboardAdapter()
+ toReturn[GameServer.State.VOTING] = VotingScoreboardAdapter()
+ toReturn[GameServer.State.COUNTDOWN] = CountdownScoreboardAdapter()
+ toReturn[GameServer.State.IN_PROGRESS] = InProgressScoreboardAdapter()
+
+ return toReturn
+ }
+ override fun getEndGameData():Game {
+
+ var team: Team? = null
+
+ if (this.instance.eventHandler.controlledBy != null) {
+ team = this.instance.teamHandler.findById(this.instance.eventHandler.controlledBy!!)
+ }
+
+ val teams = ArrayList()
+
+ this.instance.teamHandler.findPlayerTeams().forEach{teams.add(BunkersGame.Team(it.getName(),it.getColor().toString(),it.dtr,it.members.toCollection(ArrayList())))}
+
+ return BunkersGame(
+ GameEngine.instance.gameHandler.getGameTime(),
+ GameEngine.instance.gameHandler.map.id,
+ teams,
+ this.instance.statisticHandler.kills,
+ this.instance.statisticHandler.deaths,
+ this.instance.statisticHandler.playTime,
+ this.instance.statisticHandler.oresMined.entries.associate{it.key to it.value.entries.sumBy{entry -> entry.value}}.toMap(HashMap()),
+ this.instance.statisticHandler.playTimeClass.entries.associate{it.key to it.value.entries.maxByOrNull{entry -> entry.value}?.key}.toMap(HashMap()),
+ team?.getName(),
+ this.instance.eventHandler.controlledBy
+ )
+ }
+
+ override fun onGameFinishUpdateProfiles() {
+
+ val controller = this.instance.eventHandler.controlledBy
+ val winningTeam = if (controller == null) null else this.instance.teamHandler.findById(controller)
+
+ this.instance.teamHandler.findPlayerTeams().forEach{team ->
+
+ for (member in team.members) {
+
+ var profile = GameEngine.instance.api.profileHandler.findById(member,GameEngineAPI.GameMode.BUNKERS) as BunkersProfile?
+
+ if (profile == null) {
+ profile = BunkersProfile(member)
+ }
+
+ val player = this.instance.server.getPlayer(profile.id)
+
+ if (player != null) {
+
+ val pvpClass = this.instance.pvpClassHandler.findById(player.uniqueId)
+
+ if (pvpClass != null) {
+ this.instance.statisticHandler.recalculatePlayTime(player.uniqueId,pvpClass.type.backendType)
+ }
+
+ this.instance.statisticHandler.recalculatePlayTime(player.uniqueId)
+ }
+
+ if (winningTeam != null && winningTeam.isMember(profile.id) && player != null) {
+
+ if (GameEngine.instance.gameHandler.ranked) {
+ profile.rankedWins++
+ } else {
+ profile.normalWins++
+ }
+
+ profile.totalWins++
+ } else {
+ if (GameEngine.instance.gameHandler.ranked) {
+ profile.rankedLosses++
+ } else {
+ profile.normalLosses++
+ }
+
+ profile.totalLosses++
+ }
+
+ profile.gamesPlayed++
+ profile.kills += this.instance.statisticHandler.getKills(member)
+ profile.deaths += this.instance.statisticHandler.getDeaths(member)
+ profile.playTime += this.instance.statisticHandler.getPlayTime(member)
+ profile.oresMined += this.instance.statisticHandler.getOresMined(member)
+
+ BunkersProfile.Ore.values().forEach{
+ profile.oresTypeMined[it] = (profile.oresTypeMined[it] ?: 0) + this.instance.statisticHandler.getOresMined(member,it)
+ }
+
+ BunkersProfile.PvPClass.values().forEach{
+ profile.classPlayTime[it] = (profile.classPlayTime[it] ?: 0L) + this.instance.statisticHandler.getPlayTime(member,it)
+ }
+
+ GameEngine.instance.api.profileHandler.update(profile)
+ }
+
+ }
+ }
+
+ companion object {
+
+ val ANTIDOTE = ItemBuilder.of(Material.POTION).name("${ChatColor.RED}${ChatColor.BOLD}Antidote").data(8228).build()
+ val LESSER_INVISIBILITY = ItemBuilder.of(Material.POTION).name("${ChatColor.WHITE}Lesser Invisibility").data(8270).build()
+
+ val STARTER_ITEMS = ImmutableSet.of(
+ ItemBuilder.of(Material.STONE_AXE).addToLore("${ChatColor.GOLD}Soulbound").build(),
+ ItemBuilder.of(Material.STONE_PICKAXE).addToLore("${ChatColor.GOLD}Soulbound").build()
+ )
+
+ init {
+
+ val itemMeta = LESSER_INVISIBILITY.itemMeta as PotionMeta
+
+ itemMeta.addCustomEffect(PotionEffect(PotionEffectType.INVISIBILITY,(6*60) * 20,2),true)
+
+ LESSER_INVISIBILITY.itemMeta = itemMeta
+ }
+
+ }
+
+ // Old method use this one if current isn't good
+
+ /*
+ fun loadParties(parties: ArrayList>) {
+
+ Bunkers.instance.server.logger.info("--- Party Sets ---")
+ parties.forEach{Bunkers.instance.server.logger.info(StringUtils.join(arrayListOf(it).flatMap{ members -> members.map{ member -> UUIDUtils.name(member)}},", "))}
+ Bunkers.instance.server.logger.info("------------------")
+ Bunkers.instance.server.logger.info(" ")
+ Bunkers.instance.server.logger.info("--- Full Sets ---")
+ parties.forEach{Bunkers.instance.server.logger.info(StringUtils.join(arrayListOf(parties.filter{it.size >= TeamHandler.PLAYERS_PER_TEAM}).flatMap{ members -> members.flatten().map{ member -> UUIDUtils.name(member)}},", "))}
+ Bunkers.instance.server.logger.info("------------------")
+
+ val oddParties = ArrayList>()
+
+ parties.removeIf{
+
+ if (it.size < TeamHandler.PLAYERS_PER_TEAM) {
+ return@removeIf false
+ }
+
+ val team = Bunkers.instance.teamHandler.cache.values.first{team -> !team.type.isSystem() && team.members.size == 0}
+ val oddMembers = ArrayList()
+
+ for (uuid in it) {
+
+ if (team.members.size >= TeamHandler.PLAYERS_PER_TEAM) {
+
+ Bunkers.instance.server.logger.info("--- Odd Man Out ---")
+ Bunkers.instance.server.logger.info("${UUIDUtils.name(uuid)} -> ${team.type}")
+ Bunkers.instance.server.logger.info("-----------------------")
+
+ oddMembers.add(uuid)
+ continue
+ }
+
+ Bunkers.instance.server.logger.info("--- Add Member ---")
+ Bunkers.instance.server.logger.info("${UUIDUtils.name(uuid)} -> ${team.type}")
+ Bunkers.instance.server.logger.info("-----------------------")
+
+ team.members.add(uuid)
+ }
+
+ oddParties.add(oddMembers)
+ return@removeIf true
+ }
+
+ for (party in parties) {
+
+ val foundPlayers = ArrayList()
+
+ for (possibleParty in parties.filter{it != party}) {
+
+ if (foundPlayers.size + possibleParty.size > TeamHandler.PLAYERS_PER_TEAM) {
+ continue
+ }
+
+ foundPlayers.addAll(possibleParty)
+ }
+
+ if (foundPlayers.size == TeamHandler.PLAYERS_PER_TEAM) {
+ parties.forEach{nigger -> nigger.removeIf{foundPlayers.contains(it)}}
+ Bunkers.instance.teamHandler.cache.values.first{team -> !team.type.isSystem() && team.members.size == 0}.members.addAll(foundPlayers)
+ }
+
+ }
+
+ if (oddParties.isNotEmpty()) {
+ oddParties.sortedBy{it.size}.forEach{members -> members.forEach{Bunkers.instance.teamHandler.cache.values.first{team -> !team.type.isSystem() && team.members.size < TeamHandler.PLAYERS_PER_TEAM}.members.add(it)}}
+ }
+
+ if (parties.isNotEmpty()) {
+ parties.sortedBy{it.size}.forEach{members -> members.forEach{Bunkers.instance.teamHandler.cache.values.first{team -> !team.type.isSystem() && team.members.size < TeamHandler.PLAYERS_PER_TEAM}.members.add(it)}}
+ }
+
+ Bunkers.instance.teamHandler.cache.values.forEach{Bunkers.instance.server.logger.info("${it.type} -> ${StringUtil.join(it.members.map{ member -> UUIDUtils.name(member)}.toTypedArray(),", ")}")}
+ }*/
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/deathmessage/BunkersDeathMessageConfiguration.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/deathmessage/BunkersDeathMessageConfiguration.kt
new file mode 100644
index 0000000..fbcd678
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/deathmessage/BunkersDeathMessageConfiguration.kt
@@ -0,0 +1,25 @@
+package cc.fyre.bunkers.game.deathmessage
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.deathmessage.DeathMessageConfiguration
+import net.frozenorb.qlib.util.UUIDUtils
+import org.bukkit.ChatColor
+import java.util.*
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+object BunkersDeathMessageConfiguration : DeathMessageConfiguration {
+
+ override fun shouldShowDeathMessage(p0: UUID?, p1: UUID?, p2: UUID?): Boolean {
+ return true
+ }
+
+ override fun formatPlayerName(uuid: UUID): String {
+ return "${Bunkers.instance.teamHandler.findById(uuid)?.getColor() ?: ChatColor.WHITE}${UUIDUtils.name(uuid)}${ChatColor.DARK_RED}[${Bunkers.instance.statisticHandler.getKills(uuid)}]"
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/ChunkListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/ChunkListener.kt
new file mode 100644
index 0000000..49ee3ad
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/ChunkListener.kt
@@ -0,0 +1,88 @@
+package cc.fyre.bunkers.game.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.engine.map.event.MapLoadEvent
+import org.bukkit.Chunk
+import org.bukkit.entity.Monster
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.world.ChunkLoadEvent
+import org.bukkit.event.world.ChunkUnloadEvent
+import org.bukkit.scheduler.BukkitRunnable
+
+
+/**
+ * @project bunkers
+ *
+ * @date 19/01/2021
+ * @author xanderume@gmail.com
+ */
+class ChunkListener(private val instance: Bunkers) : Listener {
+
+ private val cache = ArrayList()
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onChunkLoad(event: ChunkLoadEvent) {
+
+ object : BukkitRunnable() {
+
+ override fun run() {
+ event.chunk.entities.filterIsInstance().forEach{it.remove()}
+ }
+
+ }.runTaskLater(this.instance,20L)
+
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onChunkUnLoad(event: ChunkUnloadEvent) {
+
+ if (!this.cache.contains(event.chunk)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onMapLoad(event: MapLoadEvent) {
+
+ object : BukkitRunnable() {
+
+ override fun run() {
+
+ for (team in this@ChunkListener.instance.teamHandler.findPlayerTeams()) {
+
+ val location = team.hq
+
+ if (location == null) {
+ this@ChunkListener.instance.server.logger.info("Failed to load chunks for ${team.getName()}, no hq set.")
+ return
+ }
+
+ for (x in -4 until 4) {
+
+ for (z in -4 until 4) {
+
+ location.world.getChunkAtAsync(location.blockX + (x shr 4),location.blockZ + (z shr 4)) {
+
+ if (this@ChunkListener.cache.contains(it)) {
+ return@getChunkAtAsync
+ }
+
+ it.load()
+
+ this@ChunkListener.cache.add(it)
+ this@ChunkListener.instance.logger.info("Loaded chunk at ${it.x}, ${it.z} for ${team.getName()}.")
+ }
+ }
+ }
+
+ }
+ }
+
+ }.runTaskLater(this.instance,5L)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/GameListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/GameListener.kt
new file mode 100644
index 0000000..3deaf7b
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/GameListener.kt
@@ -0,0 +1,267 @@
+package cc.fyre.bunkers.game.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.game.BunkersGameAdapter
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.event.GameStateChangeEvent
+import cc.fyre.engine.map.event.MapLoadEvent
+import cc.fyre.engine.server.data.GameServer
+import org.apache.commons.lang.StringUtils
+import org.bukkit.Bukkit
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.craftbukkit.v1_7_R4.CraftWorld
+import org.bukkit.entity.*
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.Action
+import org.bukkit.event.block.BlockFadeEvent
+import org.bukkit.event.block.BlockPhysicsEvent
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.inventory.InventoryOpenEvent
+import org.bukkit.event.inventory.InventoryType
+import org.bukkit.event.player.PlayerDropItemEvent
+import org.bukkit.event.player.PlayerInteractEvent
+import org.bukkit.event.player.PlayerItemConsumeEvent
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.potion.PotionEffectType
+import org.bukkit.scheduler.BukkitRunnable
+import org.bukkit.util.StringUtil
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onMapLoad(event: MapLoadEvent) {
+ event.world.setGameRuleValue("doMobSpawning","false")
+ event.world.entities.filterIsInstance().forEach{it.remove()}
+
+ val handle = (event.world as CraftWorld).handle
+
+ handle.spigotConfig.walkExhaustion = 0.0F
+ handle.spigotConfig.regenExhaustion = 0.0F
+ handle.spigotConfig.sprintExhaustion = 0.0F
+ handle.spigotConfig.combatExhaustion = 0.0F
+ }
+
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onFarmDecay(event: BlockFadeEvent) {
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onPlayerDropItem(event: PlayerDropItemEvent) {
+
+ val stack = event.itemDrop.itemStack
+
+ if (!stack.hasItemMeta() || !stack.itemMeta.hasLore() || !ChatColor.stripColor(stack.itemMeta.lore[0]).equals("Soulbound",true)) {
+ return
+ }
+
+ event.itemDrop.remove()
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.entity !is Player) {
+ return
+ }
+
+ val player = event.entity as Player
+
+ if (player.activePotionEffects.none{it.type == PotionEffectType.INVISIBILITY && it.amplifier == 2}) {
+ return
+ }
+
+ var attacker: Player? = null
+
+ if (event.damager is Player) {
+ attacker = event.damager as Player
+ } else if (event.damager is Projectile && (event.damager as Projectile).shooter is Player) {
+ attacker = (event.damager as Projectile).shooter as Player
+ }
+
+ if (attacker == null) {
+ return
+ }
+
+ player.removePotionEffect(PotionEffectType.INVISIBILITY)
+ player.sendMessage("${ChatColor.RED}${ChatColor.RED}Your lesser invisibility has been removed!")
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+ //TODO LunarClientAPI.getInstance().sendPacket(event.player, LCPacketServerRule(ServerRule.LEGACY_COMBAT, true))
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.player)) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+
+ if (!team.isRaidable()) {
+ return
+ }
+
+ GameEngine.instance.gameHandler.removePlayer(event.player)
+ GameEngine.instance.spectateHandler.addSpectator(event.player)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerInteract(event: PlayerInteractEvent) {
+
+ if (event.action != Action.PHYSICAL) {
+ return
+ }
+
+ if (event.clickedBlock.type != Material.SOIL) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onInventoryOpen(event: InventoryOpenEvent) {
+
+ if (!DISABLED_INVENTORIES.any{it == event.inventory.type}) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onItemConsume(event: PlayerItemConsumeEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.item.type != Material.POTION) {
+ return
+ }
+
+ object : BukkitRunnable() {
+
+ override fun run() {
+
+ if (!event.player.isOnline) {
+ return
+ }
+
+ event.player.itemInHand = null
+ }
+
+ }.runTaskLater(this.instance,2L)
+
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onGameStateChange(event: GameStateChangeEvent) {
+
+ if (event.new != GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ val koth = this.instance.teamHandler.cache[Team.Type.KOTH]!!
+
+ if (koth.hq != null) {
+ koth.hq!!.chunk.load()
+ }
+
+ this.instance.server.onlinePlayers.forEach{
+
+ val team = this.instance.teamHandler.findById(it.uniqueId)
+
+ if (team?.hq != null && !team.hq!!.chunk.isLoaded) {
+ team.hq!!.chunk.load()
+ }
+
+ if (team == null) {
+ it.teleport(koth.hq)
+ } else {
+
+ val hq = team.hq
+
+ if (hq == null) {
+ it.sendMessage("${ChatColor.RED}Your team's HQ seems to be missing, please contact an administrator..")
+ } else {
+ it.teleport(hq)
+ //TODO sendPacket(it,WayPointAddPacket("HQ",hq.world,hq.blockX,hq.blockY,hq.blockZ,team.type.getRGBColor(),forced = true,visible = true))
+
+ val teams = StringUtils.join(this.instance.teamHandler.findPlayerTeams().filter{ filtered -> filtered.type != team.type && filtered.members.isNotEmpty()}.map{ filtered -> filtered.getDisplayName()}.toTypedArray())
+
+ arrayListOf(
+ "",
+ " ${ChatColor.GOLD}You are apart of the ${team.getDisplayName()}${ChatColor.GOLD} team.",
+ " ${ChatColor.GOLD}Make $teams${ChatColor.GOLD} raidable",
+ " ${ChatColor.GOLD}and/or capture ${koth.getDisplayName()}${ChatColor.GOLD} to win.",
+ " ${ChatColor.GOLD}Make sure to block up all ${ChatColor.RED}${ChatColor.BOLD}${team.holograms.size} ${ChatColor.GOLD}entrances!",
+ " ${ChatColor.GOLD}Food can be found outside your base.",
+ ""
+ ).forEach{message -> it.sendMessage(message)}
+ }
+
+ }
+
+ if (koth.hq != null) {
+ //TODO sendPacket(it,WayPointAddPacket("${koth.getDisplayName()}${ChatColor.WHITE}",koth.hq!!.world,koth.hq!!.blockX,koth.hq!!.blockY,koth.hq!!.blockZ,koth.type.getRGBColor(),forced = true,visible = true))
+ }
+
+ BunkersGameAdapter.STARTER_ITEMS.forEach{item -> it.inventory.addItem(item)}
+ }
+
+ this.instance.teamHandler.findPlayerTeams().forEach{team -> team.shops.entries.forEach{this.instance.villagerHandler.cache.add(this.instance.shopHandler.spawnVillager(it.value,it.key,team.type))}}
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onBlockPhysics(event: BlockPhysicsEvent) {
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onGameStateChangeEnding(event: GameStateChangeEvent) {
+
+ if (event.new != GameServer.State.ENDING) {
+ return
+ }
+
+ val team = this.instance.eventHandler.controlledByTeam ?: return
+
+ object : BukkitRunnable() {
+
+ override fun run() {
+
+ val koth = this@GameListener.instance.teamHandler.cache[Team.Type.KOTH]
+
+ if (koth?.hq != null) {
+ koth.hq!!.world.spawnEntity(koth.hq,EntityType.FIREWORK) as Firework
+ }
+
+ Bukkit.broadcastMessage("${team.getDisplayName()}${ChatColor.YELLOW} wins!")
+ }
+
+ }.runTaskTimer(this.instance,30L,30L)
+ }
+
+ companion object {
+
+ val DISABLED_INVENTORIES = InventoryType.values().filter{it != InventoryType.CHEST && it != InventoryType.CREATIVE && it != InventoryType.PLAYER}.toMutableSet()
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/LunarClientListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/LunarClientListener.kt
new file mode 100644
index 0000000..ca55430
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/LunarClientListener.kt
@@ -0,0 +1,70 @@
+package cc.fyre.bunkers.game.listener
+
+import net.hylist.HylistSpigot
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+import net.hylist.handler.MovementHandler
+import net.minecraft.server.v1_7_R4.PacketPlayInFlying
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerTeleportEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 17/12/2020
+ * @author xanderume@gmail.com
+ */
+class LunarClientListener(private val instance: Bunkers) : Listener,MovementHandler {
+
+ init {
+ HylistSpigot.INSTANCE.addMovementHandler(this)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ this.instance.server.scheduler.runTaskLater(this.instance,{
+
+ if (event.player == null || !event.player.isOnline) {
+ return@runTaskLater
+ }
+
+ val koth = this.instance.teamHandler.cache[Team.Type.KOTH]
+
+ if (koth?.hq != null) {
+ //TODO LunarClientAPI.instance.packetHandler.sendPacket(event.player,WayPointAddPacket("${koth.getDisplayName()}${ChatColor.WHITE}",koth.hq!!.world,koth.hq!!.blockX,koth.hq!!.blockY,koth.hq!!.blockZ,koth.type.getRGBColor(),forced = true,visible = true))
+ }
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return@runTaskLater
+
+ if (team.hq == null) {
+ return@runTaskLater
+ }
+
+ //TODO LunarClientAPI.instance.packetHandler.sendPacket(event.player,WayPointAddPacket("HQ",team.hq!!.world,team.hq!!.blockX,team.hq!!.blockY,team.hq!!.blockZ,team.type.getRGBColor(),forced = true,visible = true))
+ },20L)
+
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+ this.handleUpdateLocation(event.player,event.to,event.from,null)
+ }
+
+ override fun handleUpdateLocation(player: Player,to: Location,from: Location,packet: PacketPlayInFlying?) {
+
+ if (from.blockX == to.blockX && from.blockZ == to.blockZ) {
+ return
+ }
+
+ }
+
+ override fun handleUpdateRotation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {}
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/VotingListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/VotingListener.kt
new file mode 100644
index 0000000..1b00512
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/listener/VotingListener.kt
@@ -0,0 +1,65 @@
+package cc.fyre.bunkers.game.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import org.apache.commons.lang.StringUtils
+import org.bukkit.Bukkit
+import org.bukkit.ChatColor
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 20/01/2021
+ * @author xanderume@gmail.com
+ */
+class VotingListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ if (event.player.world != GameEngine.instance.voteHandler.world) {
+ return
+ }
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.player)) {
+ return
+ }
+
+ if (!GameEngine.instance.gameHandler.getState().isPastOrCurrently(GameServer.State.IN_PROGRESS)) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+
+ if (team.hq == null) {
+ event.player.sendMessage("${ChatColor.RED}Your team's HQ seems to be missing, please contact an administrator..")
+ return
+ }
+
+ Bukkit.getScheduler().runTaskLater(this.instance,{
+
+ val koth = this.instance.teamHandler.cache[Team.Type.KOTH]!!
+
+ event.player.teleport(team.hq)
+
+ val teams = StringUtils.join(this.instance.teamHandler.findPlayerTeams().filter{ filtered -> filtered.type != team.type && filtered.members.isNotEmpty()}.map{ filtered -> filtered.getDisplayName()}.toTypedArray())
+
+ arrayListOf(
+ "",
+ " ${ChatColor.GOLD}You are apart of the ${team.getDisplayName()}${ChatColor.GOLD} team.",
+ " ${ChatColor.GOLD}Make $teams${ChatColor.GOLD} raidable",
+ " ${ChatColor.GOLD}and/or capture ${koth.getDisplayName()}${ChatColor.GOLD} to win.",
+ " ${ChatColor.GOLD}Make sure to block up all ${ChatColor.RED}${ChatColor.BOLD}${team.holograms.size} ${ChatColor.GOLD}entrances!",
+ " ${ChatColor.GOLD}Food can be found outside your base.",
+ ""
+ ).forEach{message -> event.player.sendMessage(message)}
+
+ },10L)
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/CountdownScoreboardAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/CountdownScoreboardAdapter.kt
new file mode 100644
index 0000000..6b214a5
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/CountdownScoreboardAdapter.kt
@@ -0,0 +1,40 @@
+package cc.fyre.bunkers.game.scoreboard
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.adapter.GameAdapter
+import cc.fyre.engine.game.adapter.scoreboard.ScoreboardAdapter
+import net.frozenorb.qlib.scoreboard.ScoreGetter
+import net.frozenorb.qlib.scoreboard.TitleGetter
+import org.bukkit.ChatColor
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class CountdownScoreboardAdapter : ScoreboardAdapter {
+
+ override fun getTitleGetter(): TitleGetter {
+ return TitleGetter.forStaticString(
+ "${ChatColor.GOLD}${ChatColor.BOLD} MC-Market ${ChatColor.GRAY}┃${ChatColor.WHITE} Bunkers"
+ )
+ }
+
+ override fun getScoreGetter(): ScoreGetter {
+ return ScoreGetter{toReturn,player ->
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId) ?: return@ScoreGetter
+
+ toReturn.add(GameAdapter.SCOREBOARD_LINE)
+ toReturn.add("${ChatColor.GREEN}${ChatColor.BOLD}Map${ChatColor.GRAY}: ${ChatColor.WHITE}${GameEngine.instance.gameHandler.map.id}")
+ toReturn.add("${ChatColor.GOLD}${ChatColor.BOLD}Team${ChatColor.GRAY}: ${team.getDisplayName()}")
+ toReturn.add("${ChatColor.DARK_BLUE}${GameAdapter.SCOREBOARD_LINE}")
+
+ toReturn.toTypedArray()
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/InProgressScoreboardAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/InProgressScoreboardAdapter.kt
new file mode 100644
index 0000000..e3742f2
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/InProgressScoreboardAdapter.kt
@@ -0,0 +1,87 @@
+package cc.fyre.bunkers.game.scoreboard
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.adapter.GameAdapter
+import cc.fyre.engine.game.adapter.scoreboard.ScoreboardAdapter
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.engine.util.FormatUtil
+import net.frozenorb.qlib.scoreboard.ScoreGetter
+import net.frozenorb.qlib.scoreboard.TitleGetter
+import org.bukkit.ChatColor
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class InProgressScoreboardAdapter : ScoreboardAdapter {
+
+ override fun getTitleGetter(): TitleGetter {
+ return TitleGetter.forStaticString(
+ "${ChatColor.GOLD}${ChatColor.BOLD} MC-Market ${ChatColor.GRAY}┃${ChatColor.WHITE} Bunkers"
+ )
+ }
+
+ override fun getScoreGetter(): ScoreGetter {
+ return ScoreGetter{toReturn,player ->
+
+ if (GameEngine.instance.gameHandler.getState() == GameServer.State.VOTING) {
+ GameEngine.instance.voteHandler.cache.entries.forEach{toReturn.add("${ChatColor.DARK_AQUA}${ChatColor.BOLD}${it.key.id}${ChatColor.GRAY}: ${ChatColor.WHITE}${it.value.size}")}
+ }
+
+ if (GameEngine.instance.gameHandler.getState() == GameServer.State.IN_PROGRESS) {
+ toReturn.add("${ChatColor.GOLD}${ChatColor.BOLD}Game Time${ChatColor.GRAY}: ${ChatColor.RED}${FormatUtil.formatIntoMMSS(GameEngine.instance.gameHandler.getGameTime())}")
+ }
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team != null) {
+ toReturn.add("${ChatColor.GOLD}${ChatColor.BOLD}DTR${ChatColor.GRAY}: ${team.getDTRDisplay()}")
+ }
+
+ if (!GameEngine.instance.spectateHandler.isSpectating(player)) {
+ toReturn.add("${ChatColor.GREEN}${ChatColor.BOLD}Balance${ChatColor.GRAY}:${ChatColor.RED} $${Bunkers.instance.statisticHandler.getBalance(player.uniqueId)}")
+ }
+
+ if (Bunkers.instance.eventHandler.isActive()) {
+ toReturn.add("${ChatColor.BLUE}${ChatColor.BOLD}${GameEngine.instance.gameHandler.map.id}${ChatColor.GRAY}: ${ChatColor.RED}${FormatUtil.formatIntoMMSS(Bunkers.instance.eventHandler.service.remaining.get() * 1000L)}")
+ }
+
+ Bunkers.instance.timerHandler.findTimers(player.uniqueId).filter{it.type.displays}.forEach{toReturn.add("${it.type.scoreboard}${ChatColor.GRAY}:${ChatColor.RED} ${FormatUtil.formatIntoFancy(it.getRemaining())}")}
+
+
+ val pvpClass = Bunkers.instance.pvpClassHandler.findById(player.uniqueId)
+
+ if (pvpClass != null) {
+
+ if (pvpClass.isEnergyBased()) {
+
+ val cooldown = Bunkers.instance.timerHandler.findRemaining(player.uniqueId,TimerType.ENERGY_COOLDOWN)
+
+ if (cooldown > 0L) {
+ toReturn.add("${ChatColor.GREEN}${ChatColor.BOLD}${pvpClass.getName()} Effect${ChatColor.GRAY}: ${ChatColor.RED}${FormatUtil.formatIntoMMSS(cooldown)}")
+ }
+
+ val energy = Bunkers.instance.pvpClassHandler.getEnergy(player)
+
+ if (energy > 0) {
+ toReturn.add("${ChatColor.AQUA}${ChatColor.BOLD}${pvpClass.getName()} Energy${ChatColor.GRAY}: ${ChatColor.RED}$energy.0")
+ }
+
+ }
+
+ }
+
+ if (toReturn.isNotEmpty()) {
+ toReturn.add(0,GameAdapter.SCOREBOARD_LINE)
+ toReturn.add("${ChatColor.DARK_BLUE}${GameAdapter.SCOREBOARD_LINE}")
+ }
+
+ toReturn.toTypedArray()
+ }
+ }
+
+}
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter.kt
new file mode 100644
index 0000000..114807e
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/VotingScoreboardAdapter.kt
@@ -0,0 +1,38 @@
+package cc.fyre.bunkers.game.scoreboard
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.adapter.GameAdapter
+import cc.fyre.engine.game.adapter.scoreboard.ScoreboardAdapter
+import net.frozenorb.qlib.scoreboard.ScoreGetter
+import net.frozenorb.qlib.scoreboard.TitleGetter
+import org.bukkit.ChatColor
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class VotingScoreboardAdapter : ScoreboardAdapter {
+
+ override fun getTitleGetter(): TitleGetter {
+ return TitleGetter.forStaticString(
+ "${ChatColor.GOLD}${ChatColor.BOLD} MC-Market ${ChatColor.GRAY}┃${ChatColor.WHITE} Bunkers"
+ )
+ }
+
+ override fun getScoreGetter(): ScoreGetter {
+ return ScoreGetter{toReturn,_ ->
+
+
+ toReturn.add(GameAdapter.SCOREBOARD_LINE)
+
+ GameEngine.instance.voteHandler.cache.entries.sortedBy{it.key.id.length}.forEach{toReturn.add("${it.key.id}: ${ChatColor.GOLD}${it.value.size}")}
+
+ toReturn.add("${ChatColor.DARK_BLUE}${GameAdapter.SCOREBOARD_LINE}")
+ toReturn.toTypedArray()
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/WaitingScoreboardAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/WaitingScoreboardAdapter.kt
new file mode 100644
index 0000000..7380221
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/scoreboard/WaitingScoreboardAdapter.kt
@@ -0,0 +1,32 @@
+package cc.fyre.bunkers.game.scoreboard
+
+import cc.fyre.engine.game.adapter.GameAdapter
+import cc.fyre.engine.game.adapter.scoreboard.ScoreboardAdapter
+import net.frozenorb.qlib.scoreboard.ScoreGetter
+import net.frozenorb.qlib.scoreboard.TitleGetter
+import org.bukkit.ChatColor
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class WaitingScoreboardAdapter : ScoreboardAdapter {
+
+ override fun getTitleGetter(): TitleGetter {
+ return TitleGetter.forStaticString(
+ "${ChatColor.GOLD}${ChatColor.BOLD} MC-Market ${ChatColor.GRAY}┃${ChatColor.WHITE} Bunkers"
+ ) }
+
+ override fun getScoreGetter(): ScoreGetter {
+ return ScoreGetter{ toReturn, _ ->
+ toReturn.add(GameAdapter.SCOREBOARD_LINE)
+ toReturn.add("Waiting...")
+ toReturn.add("${ChatColor.DARK_BLUE}${GameAdapter.SCOREBOARD_LINE}")
+
+ toReturn.toTypedArray()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/tab/BunkersTabAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/tab/BunkersTabAdapter.kt
new file mode 100644
index 0000000..e75520e
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/game/tab/BunkersTabAdapter.kt
@@ -0,0 +1,216 @@
+package cc.fyre.bunkers.game.tab
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.event.EventHandler
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.bunkers.timer.data.TimerType
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.engine.util.FormatUtil
+import com.google.common.collect.HashBasedTable
+import net.frozenorb.qlib.tab.construct.TabLayout
+import net.frozenorb.qlib.tab.provider.LayoutProvider
+import net.frozenorb.qlib.util.UUIDUtils
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import java.util.*
+
+/**
+ * @project bunkers
+ *
+ * @date 21/08/2020
+ * @author xanderume@gmail.com
+ */
+object BunkersTabAdapter : LayoutProvider {
+
+ override fun provide(player: Player): TabLayout {
+
+ val layout = TabLayout.create(player)
+
+ var y = 3
+
+ layout.set(0,y++,"${ChatColor.GOLD}Player Info:")
+ layout.set(0,y++,"${ChatColor.GRAY}Kills: ${ChatColor.WHITE}${Bunkers.instance.statisticHandler.getKills(player.uniqueId)}")
+ layout.set(0,y++,"${ChatColor.GRAY}Deaths: ${ChatColor.WHITE}${Bunkers.instance.statisticHandler.getDeaths(player.uniqueId)}")
+
+ y++
+
+ if (player.location.world != null) {
+ layout.set(0,y++,"${ChatColor.GOLD}Location:")
+ layout.set(0,y++,"${ChatColor.RED}${Bunkers.instance.teamHandler.findByLocation(player.location).getDisplayName()}")
+ layout.set(0,y++,"${ChatColor.GRAY}${player.location.blockX}, ${player.location.blockZ} [${this.getCardinalDirection(player)}${ChatColor.GRAY}]")
+ }
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team != null) {
+ y = 3
+
+ layout.set(1,y++,"${ChatColor.GOLD}Team Info:")
+ layout.set(1,y++,"${ChatColor.GRAY}DTR: ${team.getDTRDisplay()}")
+ layout.set(1,y++,"${ChatColor.GRAY}Online: ${ChatColor.WHITE}${team.findOnlineMembers().size}/${team.members.size}")
+ }
+
+ y = 3
+
+ layout.set(2,y++,"${ChatColor.GOLD}Game Info:")
+
+ if (GameEngine.instance.gameHandler.getState().isPastOrCurrently(GameServer.State.IN_PROGRESS)) {
+ layout.set(2,y++,"${ChatColor.GRAY}Time: ${ChatColor.WHITE}${FormatUtil.formatIntoMMSS(GameEngine.instance.gameHandler.getGameTime())}")
+ } else {
+
+ var map = "Voting"
+
+ if (GameEngine.instance.gameHandler.getState().isPastOrCurrently(GameServer.State.COUNTDOWN)) {
+ map = GameEngine.instance.gameHandler.map.id
+ }
+
+ layout.set(2,y++,"${ChatColor.GRAY}Map: ${ChatColor.WHITE}$map")
+ }
+
+ layout.set(2,y++,"${ChatColor.GRAY}Players: ${ChatColor.WHITE}${GameEngine.instance.gameHandler.getPlayers().size}")
+
+ y++
+
+ if (GameEngine.instance.gameHandler.getState().isPastOrCurrently(GameServer.State.COUNTDOWN)) {
+ val captureZone = Bunkers.instance.eventHandler.getCaptureZone()
+
+ layout.set(2,y++,"${ChatColor.GOLD}${GameEngine.instance.gameHandler.map.id}:")
+ layout.set(2,y++,"${ChatColor.GRAY}${captureZone.blockX}, ${captureZone.blockZ}")
+
+ val time = if (Bunkers.instance.eventHandler.isActive()) {
+ Bunkers.instance.eventHandler.service.remaining.get() * 1000L
+ } else {
+ (EventHandler.KOTH_START_TIME * 1000L) - (GameEngine.instance.gameHandler.getGameTime())
+ }
+
+ layout.set(2,y++,"${ChatColor.GRAY}${FormatUtil.formatIntoMMSS(time)}")
+ }
+
+ y = 7
+
+ var x = 1
+
+ Bunkers.instance.teamHandler.findPlayerTeams().sortedByDescending{it.isMember(player)}.forEach{
+
+ val next: Int = if (y == 7) {
+ 0
+ } else {
+ if (x >= 2) {
+ 0
+ } else {
+ x + 1
+ }
+ }
+
+ layout.set(x,y++,"${it.getDisplayName()} Team ${ChatColor.GRAY}[${it.getDTRDisplay()}${ChatColor.GRAY}]")
+
+ it.members.forEach{member -> layout.set(x,y++,this.getDisplayName(player,member,it))}
+
+ y = 14
+ x = next
+ }
+
+ return layout
+ }
+
+ private fun getCardinalDirection(player: Player):String {
+
+ var rot = (player.location.yaw - 90) % 360.toDouble()
+
+ if (rot < 0) {
+ rot += 360.0
+ }
+
+ return this.getDirection(rot)
+ }
+
+ private fun getDirection(rot: Double): String {
+
+ return when {
+ 0 <= rot && rot < 22.5 -> Direction.WEST.getDisplay()
+ 22.5 <= rot && rot < 67.5 -> "${Direction.NORTH.getDisplay()}${Direction.WEST.getDisplay()}"
+ 67.5 <= rot && rot < 112.5 -> Direction.NORTH.getDisplay()
+ 112.5 <= rot && rot < 157.5 -> "${Direction.NORTH.getDisplay()}${Direction.EAST.getDisplay()}"
+ 157.5 <= rot && rot < 202.5 -> Direction.EAST.getDisplay()
+ 202.5 <= rot && rot < 247.5 -> "${Direction.SOUTH.getDisplay()}${Direction.EAST.getDisplay()}"
+ 247.5 <= rot && rot < 292.5 -> Direction.SOUTH.getDisplay()
+ 292.5 <= rot && rot < 337.5 -> "${Direction.SOUTH.getDisplay()}${Direction.WEST.getDisplay()}"
+ 337.5 <= rot && rot < 360.0 -> Direction.WEST.getDisplay()
+ else -> ""
+ }
+
+ }
+ private fun getDisplayName(viewer: Player,uuid: UUID,team: Team): String {
+
+ val player = Bunkers.instance.server.getPlayer(uuid)
+
+ if (player != null) {
+
+ if (GameEngine.instance.spectateHandler.isSpectating(player)) {
+ return "${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${player.name}"
+ }
+
+ val respawn = Bunkers.instance.timerHandler.findRemaining(uuid,TimerType.RESPAWN)
+
+ if (team.isMember(viewer.uniqueId) && respawn > 0L) {
+ return "${ChatColor.GRAY}${player.name}${ChatColor.RED} ${respawn / 1000L}s"
+ }
+
+ return "${team.getColor()}${player.name}"
+ }
+
+ val name = UUIDUtils.name(uuid)
+
+ if (GameEngine.instance.disqualifieHandler.isDisqualified(uuid)) {
+ return "${ChatColor.DARK_GRAY}${ChatColor.STRIKETHROUGH}${name}"
+ }
+
+ return "${ChatColor.GRAY}$name"
+ }
+
+ enum class Direction(private val display: String) {
+
+ EAST("E"),
+ WEST("W"),
+ SOUTH("S"),
+ NORTH("N");
+
+ fun getDisplay():String {
+
+ if (GameEngine.instance.gameHandler.getState().isBeforeOrCurrently(GameServer.State.COUNTDOWN)) {
+ return "${ChatColor.WHITE}${this.display}"
+ }
+
+ return "${DIRECTIONS.get(GameEngine.instance.gameHandler.map.id.toLowerCase(),this) ?: ChatColor.WHITE}${this.display}"
+ }
+
+ }
+
+ val DIRECTIONS = HashBasedTable.create()
+
+ init {
+ //TODO LOL
+ DIRECTIONS.put("western",Direction.WEST,ChatColor.BLUE)
+ DIRECTIONS.put("western",Direction.EAST,ChatColor.YELLOW)
+ DIRECTIONS.put("western",Direction.SOUTH,ChatColor.RED)
+ DIRECTIONS.put("western",Direction.NORTH,ChatColor.GREEN)
+
+ DIRECTIONS.put("classic",Direction.WEST,ChatColor.YELLOW)
+ DIRECTIONS.put("classic",Direction.EAST,ChatColor.GREEN)
+ DIRECTIONS.put("classic",Direction.SOUTH,ChatColor.RED)
+ DIRECTIONS.put("classic",Direction.NORTH,ChatColor.BLUE)
+
+ DIRECTIONS.put("medieval",Direction.WEST,ChatColor.GREEN)
+ DIRECTIONS.put("medieval",Direction.EAST,ChatColor.YELLOW)
+ DIRECTIONS.put("medieval",Direction.NORTH,ChatColor.RED)
+ DIRECTIONS.put("medieval",Direction.SOUTH,ChatColor.BLUE)
+
+ DIRECTIONS.put("colosseum",Direction.WEST,ChatColor.YELLOW)
+ DIRECTIONS.put("colosseum",Direction.EAST,ChatColor.GREEN)
+ DIRECTIONS.put("colosseum",Direction.NORTH,ChatColor.RED)
+ DIRECTIONS.put("colosseum",Direction.SOUTH,ChatColor.BLUE)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/PillarHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/PillarHandler.kt
new file mode 100644
index 0000000..8c69469
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/PillarHandler.kt
@@ -0,0 +1,181 @@
+package cc.fyre.bunkers.pillar
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.pillar.data.Pillar
+
+import cc.fyre.bunkers.pillar.data.adapter.WallAdapter
+
+import cc.fyre.bunkers.pillar.listener.PillarListener
+import cc.fyre.bunkers.pillar.listener.PillarPacketListener
+import cc.fyre.bunkers.pillar.listener.PillarWallListener
+import com.comphenix.protocol.ProtocolLibrary
+import com.google.common.collect.HashBasedTable
+import org.bukkit.Location
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import java.util.*
+import java.util.function.Predicate
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+
+
+/**
+ * @project hcf
+ *
+ * @date 27/08/2020
+ * @author xanderume@gmail.com
+ */
+
+// Rewrite & cleanup of https://github.com/iPvP-MC/iHCF/master/com/doctordark/hcf/visualise/VisualiseHandler.java
+
+class PillarHandler(private val instance: Bunkers) {
+
+ val cache: HashBasedTable = HashBasedTable.create()
+ val adapters = ArrayList()
+
+ init {
+ this.instance.server.pluginManager.registerEvents(PillarWallListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(PillarListener(this.instance),this.instance)
+
+ ProtocolLibrary.getProtocolManager().addPacketListener(PillarPacketListener(this.instance))
+ }
+
+ fun findPillar(uuid: UUID,location: Location):Pillar? {
+ return this.cache.get(uuid,location)
+ }
+
+ fun findPillars(uuid: UUID):MutableSet {
+ return this.cache.row(uuid).values.toMutableSet()
+ }
+
+ fun findPillars(uuid: UUID,type: Pillar.Type):MutableSet {
+ return this.cache.row(uuid).filter{it.value.type == type}.values.toMutableSet()
+ }
+
+ fun findPillarAmountByType(uuid: UUID,type: Pillar.Type):Int {
+
+ val toReturn = HashSet()
+
+ for (pillar in this.cache.row(uuid).filter{it.value.type == type}.values) {
+
+ if (toReturn.any{it.location.blockX == pillar.location.blockX && it.location.blockZ == pillar.location.blockZ}) {
+ continue
+ }
+
+ toReturn.add(pillar)
+ }
+
+ return toReturn.size
+ }
+
+ fun sendPillars(player: Player,type: Pillar.Type,locations: Collection,material: Material,overwrite: Boolean) {
+ this.sendPillars(player,type,locations,material,0,overwrite)
+ }
+
+ fun sendPillars(player: Player,type: Pillar.Type,locations: Collection,material: Material,data: Int,overwrite: Boolean) {
+ this.sendPillars(player,type,locations,Material.GLASS,material,data,overwrite)
+ }
+
+ fun sendPillars(player: Player,type: Pillar.Type,locations: Collection,origin: Material,material: Material,data: Int,overwrite: Boolean) {
+
+ val pillars = HashMap()
+
+ for (location in locations) {
+
+ if (this.cache.contains(player.uniqueId,location) && !overwrite) {
+ continue
+ }
+
+ if (location.block.type.isSolid || location.block.type != Material.AIR) {
+ continue
+ }
+
+ var blockType = origin
+
+ if (type != Pillar.Type.CLAIM_BORDER) {
+
+ if (location.blockY == 0 || location.blockY % 3 == 0) {
+ blockType = material
+ }
+
+ }
+
+ val pillar = Pillar(type,location,blockType,data.toShort())
+
+ pillars[location] = pillar
+
+ player.sendBlockChange(location,pillar.material,pillar.data.toByte())
+
+ this.cache.put(player.uniqueId,location,pillar)
+ }
+
+ }
+
+ fun sendPillarsAsync(player: Player,type: Pillar.Type,locations: Collection,material: Material,overwrite: Boolean) {
+
+ val pillars = HashMap()
+
+ for (location in locations) {
+
+ if (this.cache.contains(player.uniqueId,location) && !overwrite) {
+ continue
+ }
+
+ location.world.getChunkAtAsync(location) {
+
+ if (location.block.type.isSolid || location.block.type != Material.AIR) {
+ return@getChunkAtAsync
+ }
+
+ var blockType = Material.GLASS
+
+ if (type != Pillar.Type.CLAIM_BORDER) {
+
+ if (location.blockY == 0 || location.blockY % 3 == 0) {
+ blockType = material
+ }
+
+ }
+
+ val pillar = Pillar(type,location,blockType)
+
+ pillars[location] = pillar
+
+ player.sendBlockChange(location,pillar.material,pillar.data.toByte())
+
+ this.cache.put(player.uniqueId,location,pillar)
+ }
+
+ }
+
+ }
+
+ fun removePillar(player: Player,location: Location) {
+
+ val pillar = this.cache.remove(player.uniqueId,location) ?: return
+
+ if (pillar.material == location.block.type && pillar.data == location.block.data.toShort()) {
+ return
+ }
+
+ player.sendBlockChange(location,location.block.type,location.block.data)
+ }
+
+ fun removePillars(player: Player,type: Pillar.Type) {
+ this.removePillars(player,type,Predicate{true})
+ }
+
+ fun removePillars(player: Player,locations: Collection) {
+ locations.forEach{this.removePillar(player,it)}
+ }
+
+ fun removePillars(player: Player,type: Pillar.Type,predicate: Predicate) {
+
+ if (!this.cache.containsRow(player.uniqueId)) {
+ return
+ }
+
+ HashMap(this.cache.row(player.uniqueId)).filter{predicate.test(it.value) && (it.value == null || it.value.type == type)}.forEach{this.removePillar(player,it.key)}
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/data/Pillar.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/data/Pillar.kt
new file mode 100644
index 0000000..ddebb66
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/data/Pillar.kt
@@ -0,0 +1,22 @@
+package cc.fyre.bunkers.pillar.data
+
+import org.bukkit.Location
+import org.bukkit.Material
+
+/**
+ * @project hcf
+ *
+ * @date 27/08/2020
+ * @author xanderume@gmail.com
+ */
+class Pillar(val type: Type,val location: Location,val material: Material,val data: Short) {
+
+ constructor(type: Type,location: Location,material: Material):this(type,location,material,0)
+
+ enum class Type(val materials: Array) {
+
+ CLAIM_BORDER(arrayOf(Material.STAINED_GLASS));
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/data/adapter/WallAdapter.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/data/adapter/WallAdapter.kt
new file mode 100644
index 0000000..6acf916
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/data/adapter/WallAdapter.kt
@@ -0,0 +1,20 @@
+package cc.fyre.bunkers.pillar.data.adapter
+
+import cc.fyre.bunkers.team.data.Team
+import org.bukkit.entity.Player
+
+import org.bukkit.Material
+
+/**
+ * @project hcf
+ *
+ * @date 02/01/2021
+ * @author xanderume@gmail.com
+ */
+interface WallAdapter {
+
+ fun getMaterial(player: Player):Pair
+ fun shouldCheck(player: Player,team: Team?):Boolean
+ fun shouldApply(player: Player,team: Team,playerTeam: Team?):Boolean
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarListener.kt
new file mode 100644
index 0000000..c9300dd
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarListener.kt
@@ -0,0 +1,28 @@
+package cc.fyre.bunkers.pillar.listener
+
+import cc.fyre.bunkers.Bunkers
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.PlayerDeathEvent
+import org.bukkit.event.player.PlayerQuitEvent
+
+/**
+ * @project hcf
+ *
+ * @date 28/08/2020
+ * @author xanderume@gmail.com
+ */
+class PillarListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+ this.instance.pillarHandler.findPillars(event.player.uniqueId).forEach{this.instance.pillarHandler.cache.remove(event.player.uniqueId,it.type)}
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerDeath(event: PlayerDeathEvent) {
+ this.instance.pillarHandler.findPillars(event.entity.uniqueId).forEach{this.instance.pillarHandler.cache.remove(event.entity.uniqueId,it.type)}
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarPacketListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarPacketListener.kt
new file mode 100644
index 0000000..b2c7b2e
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarPacketListener.kt
@@ -0,0 +1,61 @@
+package cc.fyre.bunkers.pillar.listener
+
+import cc.fyre.bunkers.Bunkers
+import com.comphenix.protocol.PacketType
+import com.comphenix.protocol.events.PacketAdapter
+import com.comphenix.protocol.events.PacketEvent
+
+import org.bukkit.GameMode
+import org.bukkit.Location
+
+/**
+ * @project hcf
+ *
+ * @date 28/08/2020
+ * @author xanderume@gmail.com
+ */
+class PillarPacketListener(private val instance: Bunkers) : PacketAdapter(instance,listOf(PacketType.Play.Client.BLOCK_DIG,PacketType.Play.Client.BLOCK_PLACE)) {
+
+ override fun onPacketReceiving(event: PacketEvent) {
+
+ if (event.packet.type == PacketType.Play.Client.BLOCK_PLACE) {
+
+ val pillar = this.instance.pillarHandler.findPillar(event.player.uniqueId,Location(event.player.world,event.packet.integers.read(0).toDouble(),event.packet.integers.read(1).toDouble(),event.packet.integers.read(2).toDouble()))
+
+ if (pillar == null || event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ event.isCancelled = true
+ return
+ }
+
+ val action = event.packet.integers.read(4)
+
+ if (!(action == 0 || action == 2)) {
+ return
+ }
+
+ val x = event.packet.integers.read(0)
+ val y = event.packet.integers.read(1)
+ val z = event.packet.integers.read(2)
+
+ val location = Location(event.player.world,x.toDouble(),y.toDouble(),z.toDouble())
+
+ val pillar = this.instance.pillarHandler.findPillar(event.player.uniqueId,location) ?: return
+
+ event.isCancelled = true
+
+ if (action == 2) {
+ event.player.sendBlockChange(location,pillar.material,pillar.data.toByte())
+ return
+ }
+
+ if (event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ event.player.sendBlockChange(location,pillar.material,pillar.data.toByte())
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarWallListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarWallListener.kt
new file mode 100644
index 0000000..e0745c2
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pillar/listener/PillarWallListener.kt
@@ -0,0 +1,146 @@
+package cc.fyre.bunkers.pillar.listener
+
+import net.hylist.HylistSpigot
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.pillar.data.Pillar
+import net.hylist.handler.MovementHandler
+
+import cc.fyre.bunkers.pillar.data.adapter.WallAdapter
+import cc.fyre.bunkers.team.data.Team
+
+import net.minecraft.server.v1_7_R4.PacketPlayInFlying
+import org.bukkit.GameMode
+import org.bukkit.Location
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerTeleportEvent
+import java.util.*
+import java.util.function.Predicate
+import kotlin.collections.HashMap
+import kotlin.math.abs
+
+
+/**
+ * @project hcf
+ *
+ * @date 16/09/2020
+ * @author xanderume@gmail.com
+ */
+class PillarWallListener(private val instance: Bunkers) : Listener,MovementHandler {
+
+ init {
+ HylistSpigot.INSTANCE.addMovementHandler(this)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+ this.handleUpdateLocation(event.player,event.to,event.from,null)
+ }
+
+ override fun handleUpdateRotation(player: Player,to: Location,from: Location,packet: PacketPlayInFlying?) {}
+
+ override fun handleUpdateLocation(player: Player,to: Location,from: Location,packet: PacketPlayInFlying?) {
+
+ if (player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ if (from.blockX == to.blockX && from.blockY == to.blockY && from.blockZ == to.blockZ) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(player.uniqueId) ?: return
+
+ val adapters = this.instance.pillarHandler.adapters.filter{it.shouldCheck(player,team)}
+
+ if (adapters.isEmpty()) {
+ return
+ }
+
+ this.instance.pillarHandler.removePillars(player,Pillar.Type.CLAIM_BORDER,Predicate{
+ return@Predicate it.location.world == to.world &&
+ abs(to.blockX - it.location.blockX) > WALL_BORDER_HORIZONTAL_DISTANCE ||
+ abs(to.blockY - it.location.blockY) > WALL_BORDER_HEIGHT_ABOVE_DIFF ||
+ abs(to.blockZ - it.location.blockZ) > WALL_BORDER_HORIZONTAL_DISTANCE
+ })
+
+ val minX = to.blockX - WALL_BORDER_HORIZONTAL_DISTANCE
+ val maxX = to.blockX + WALL_BORDER_HORIZONTAL_DISTANCE
+ val minZ = to.blockZ - WALL_BORDER_HORIZONTAL_DISTANCE
+ val maxZ = to.blockZ + WALL_BORDER_HORIZONTAL_DISTANCE
+
+ val minHeight: Int = to.blockY - WALL_BORDER_HEIGHT_BELOW_DIFF
+ val maxHeight: Int = to.blockY + WALL_BORDER_HEIGHT_ABOVE_DIFF
+
+ val entries = HashMap()
+
+ for (x in minX until maxX) {
+
+ for (z in minZ until maxZ) {
+
+ val enemy = this.instance.teamHandler.findByLocation(Location(to.world,x.toDouble(),0.0,z.toDouble()))
+
+ for (adapter in adapters) {
+
+ if (!adapter.shouldApply(player,enemy,team)) {
+ continue
+ }
+
+ if (entries.containsKey(enemy)) {
+ // prevent flicker
+ continue
+ }
+
+ entries[enemy] = adapter
+ }
+
+ }
+
+ }
+
+ for (entry in entries) {
+
+ if (entry.key.claim == null) {
+ continue
+ }
+
+ val material = entry.value.getMaterial(player)
+
+ if (entry.key.claim!!.contains(player.location)) {
+ continue
+ }
+
+ val locations = ArrayList()
+
+ entry.key.claim!!.borderIterator().forEachRemaining{
+
+ if (abs(it.first - to.blockX) > WALL_BORDER_HORIZONTAL_DISTANCE) {
+ return@forEachRemaining
+ }
+
+ if (abs(it.second - to.blockZ) > WALL_BORDER_HORIZONTAL_DISTANCE) {
+ return@forEachRemaining
+ }
+
+ for (i in minHeight until maxHeight) {
+ locations.add(Location(to.world,it.first.toDouble(),i.toDouble(),it.second.toDouble()))
+ }
+
+ }
+
+ this.instance.pillarHandler.sendPillars(player,Pillar.Type.CLAIM_BORDER,locations,material.first,material.first,material.second,true)
+ }
+
+ }
+
+ companion object {
+
+ private const val WALL_BORDER_HEIGHT_BELOW_DIFF = 3
+ private const val WALL_BORDER_HEIGHT_ABOVE_DIFF = 4
+ private const val WALL_BORDER_HORIZONTAL_DISTANCE = 7
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/PvPClassHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/PvPClassHandler.kt
new file mode 100644
index 0000000..10eccfb
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/PvPClassHandler.kt
@@ -0,0 +1,138 @@
+package cc.fyre.bunkers.pvpclass
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.pvpclass.data.PvPClass
+import cc.fyre.bunkers.pvpclass.data.type.BardClass
+import cc.fyre.bunkers.pvpclass.event.PvPClassEquipEvent
+import cc.fyre.bunkers.pvpclass.event.PvPClassUnEquipEvent
+import cc.fyre.bunkers.pvpclass.listener.PvPClassListener
+import cc.fyre.engine.profile.data.type.BunkersProfile
+import com.google.common.collect.HashBasedTable
+import org.bukkit.entity.Player
+import org.bukkit.potion.PotionEffect
+import org.bukkit.potion.PotionEffectType
+import java.util.*
+import java.util.concurrent.TimeUnit
+import kotlin.collections.HashMap
+import kotlin.math.min
+
+
+/**
+ * @project hcf
+ *
+ * @date 10/09/2020
+ * @author xanderume@gmail.com
+ */
+class PvPClassHandler(private val instance: Bunkers) {
+
+ val cache = HashMap()
+ val typeToClass = HashMap()
+
+ val effects = HashBasedTable.create()
+
+ private val energy = HashMap()
+
+ init {
+ this.typeToClass[PvPClass.Type.BARD] = BardClass
+
+ this.instance.server.pluginManager.registerEvents(PvPClassListener(this.instance),this.instance)
+ }
+
+ fun dispose() {
+ this.instance.server.onlinePlayers.filter{this.cache.containsKey(it.uniqueId)}.forEach{this.setPvPClass(it,null)}
+ }
+
+ fun findById(uuid: UUID):PvPClass? {
+
+ if (!this.cache.containsKey(uuid)) {
+ return null
+ }
+
+ return this.typeToClass[this.cache[uuid]!!]
+ }
+
+ fun findByType(type: PvPClass.Type):PvPClass? {
+ return this.typeToClass[type]
+ }
+
+ fun setPvPClass(player: Player,type: PvPClass.Type?) {
+
+ if (this.cache.containsKey(player.uniqueId)) {
+
+ if (this.cache[player.uniqueId] == type) {
+ return
+ }
+
+ val previous = this.cache.remove(player.uniqueId)!!
+
+ this.instance.server.pluginManager.callEvent(PvPClassUnEquipEvent(player,this.typeToClass[previous]!!))
+
+ this.energy.remove(player.uniqueId)
+ this.typeToClass[previous]!!.onDisable(player)
+
+ this.instance.statisticHandler.recalculatePlayTime(player.uniqueId,previous.backendType)
+ this.instance.statisticHandler.playTimeClassEquipped[player.uniqueId]?.remove(previous.backendType)
+
+ previous.effects.filter{player.activePotionEffects.any{effect -> it.type == effect.type && it.duration > (TimeUnit.MINUTES.toMillis(8L)) && it.amplifier == effect.amplifier}}.forEach{player.removePotionEffect(it.type)}
+ }
+
+ if (type == null || !this.typeToClass.containsKey(type)) {
+ return
+ }
+
+ val event = PvPClassEquipEvent(player,this.typeToClass[type]!!)
+
+ this.instance.server.pluginManager.callEvent(event)
+
+ if (event.isCancelled) {
+ return
+ }
+
+ this.cache[player.uniqueId] = type
+ this.energy[player.uniqueId] = System.currentTimeMillis()
+ this.typeToClass[type]!!.onEnable(player)
+
+
+ this.instance.statisticHandler.playTimeClassEquipped.putIfAbsent(player.uniqueId,EnumMap(BunkersProfile.PvPClass::class.java))
+ this.instance.statisticHandler.playTimeClassEquipped[player.uniqueId]!![type.backendType] = System.currentTimeMillis()
+
+ type.effects.forEach{player.addPotionEffect(it,true)}
+ }
+
+ fun getEnergy(player: Player):Int {
+
+ if (!this.energy.containsKey(player.uniqueId)) {
+ return 0
+ }
+
+ val energy = this.energy[player.uniqueId]!!
+
+ if (energy == 0L) {
+ return 0
+ }
+
+ return min(100,(1.0 * (System.currentTimeMillis()) - energy).toInt() / 1000)
+ }
+
+ fun setEnergy(player: Player,energy: Int) {
+ this.energy[player.uniqueId] = (System.currentTimeMillis() - (1000L * energy))
+ }
+
+ fun addPotionEffect(player: Player,effect: PotionEffect) {
+
+ if (player.activePotionEffects.any{it.type == effect.type && (it.amplifier > effect.amplifier || (it.amplifier == effect.amplifier && it.duration > effect.duration))}) {
+ return
+ }
+
+ // only cache the ones are lower then infinite & normal bard speed duration
+ player.activePotionEffects.stream().filter{it.type == effect.type && it.duration > 120 && it.duration <= 1_000_000}.findFirst().ifPresent{this.effects.put(player.uniqueId,it.type,it)}
+
+ player.addPotionEffect(effect,true)
+ }
+
+ companion object {
+
+ const val BARD_RANGE = 25.0
+
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/PvPClass.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/PvPClass.kt
new file mode 100644
index 0000000..920c7c4
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/PvPClass.kt
@@ -0,0 +1,67 @@
+package cc.fyre.bunkers.pvpclass.data
+
+import cc.fyre.bunkers.pvpclass.data.item.energy.EnergyEffect
+import cc.fyre.bunkers.pvpclass.data.item.ConsumableItem
+import cc.fyre.engine.profile.data.type.BunkersProfile
+import com.google.common.collect.HashBasedTable
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.potion.PotionEffect
+import org.bukkit.potion.PotionEffectType
+import java.util.*
+import kotlin.collections.ArrayList
+
+/**
+ * @project hcf
+ *
+ * @date 10/09/2020
+ * @author xanderume@gmail.com
+ */
+abstract class PvPClass(val type: Type) {
+
+ protected val effects = ArrayList()
+
+ private val cooldowns = HashBasedTable.create()
+ private val consumables = this.getConsumableItems()
+
+ fun getName():String {
+ return this.type.displayName
+ }
+
+ abstract fun onEnable(player: Player)
+ abstract fun onDisable(player: Player)
+
+ abstract fun isEnergyBased():Boolean
+ abstract fun getConsumableItems():List
+
+ open fun isEquipped(player: Player):Boolean {
+ return player.inventory.armorContents.all{it != null && it.type.name.startsWith(this.type.armor)}
+ }
+
+ fun getCooldown(player: Player,consumable: ConsumableItem):Long {
+
+ if (!this.cooldowns.contains(player.uniqueId,consumable.material)) {
+ return 0L
+ }
+
+ return (this.cooldowns.get(player.uniqueId,consumable.material) + consumable.cooldown) - System.currentTimeMillis()
+ }
+
+ fun setCooldown(player: Player,consumable: ConsumableItem) {
+ this.cooldowns.put(player.uniqueId,consumable.material,System.currentTimeMillis())
+ }
+
+ fun findEffectByItem(material: Material):EnergyEffect? {
+ return this.effects.firstOrNull{it.material == material}
+ }
+
+ fun findConsumableByItem(material: Material):ConsumableItem? {
+ return this.consumables.firstOrNull{it.material == material}
+ }
+
+ enum class Type(val displayName: String,val armor: String,val effects: Array,val backendType: BunkersProfile.PvPClass) {
+ DIAMOND("Diamond","DIAMOND",arrayOf(),BunkersProfile.PvPClass.DIAMOND),
+ BARD("Bard","GOLD",arrayOf(PotionEffect(PotionEffectType.SPEED,Integer.MAX_VALUE,1),PotionEffect(PotionEffectType.REGENERATION,Integer.MAX_VALUE,0),PotionEffect(PotionEffectType.DAMAGE_RESISTANCE,Integer.MAX_VALUE,1)),BunkersProfile.PvPClass.BARD);
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem.kt
new file mode 100644
index 0000000..78def2a
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/item/ConsumableItem.kt
@@ -0,0 +1,28 @@
+package cc.fyre.bunkers.pvpclass.data.item
+
+import cc.fyre.bunkers.Bunkers
+
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.potion.PotionEffect
+
+/**
+ * @project hcf
+ *
+ * @date 10/09/2020
+ * @author xanderume@gmail.com
+ */
+abstract class ConsumableItem(val material: Material,val cooldown: Long) {
+
+ abstract fun onConsume(player: Player): Boolean
+
+ class EffectConsumableItem(material: Material,cooldown: Long,private val effect: PotionEffect) : ConsumableItem(material,cooldown) {
+
+ override fun onConsume(player: Player):Boolean {
+ Bunkers.instance.pvpClassHandler.addPotionEffect(player,this.effect)
+ return true
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect.kt
new file mode 100644
index 0000000..ff21418
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/item/energy/EnergyEffect.kt
@@ -0,0 +1,102 @@
+package cc.fyre.bunkers.pvpclass.data.item.energy
+
+import cc.fyre.bunkers.Bunkers
+
+import cc.fyre.bunkers.pvpclass.PvPClassHandler
+import cc.fyre.bunkers.pvpclass.data.PvPClass
+import cc.fyre.bunkers.pvpclass.data.item.ConsumableItem
+import cc.fyre.bunkers.pvpclass.data.type.BardClass
+import cc.fyre.bunkers.pvpclass.event.type.BardEffectEvent
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.engine.util.PotionUtil
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.potion.PotionEffect
+import org.bukkit.potion.PotionEffectType
+import java.util.concurrent.TimeUnit
+import java.util.function.Predicate
+
+/**
+ * @project hcf
+ *
+ * @date 11/09/2020
+ * @author xanderume@gmail.com
+ */
+open class EnergyEffect(val energy: Int,material: Material,val effect: PotionEffect?) : ConsumableItem(material,TimeUnit.SECONDS.toMillis(10L)) {
+
+ override fun onConsume(player: Player): Boolean {
+
+ if (this.effect == null) {
+ return false
+ }
+
+ player.addPotionEffect(this.effect,true)
+ return true
+ }
+
+ class BardEffect(energy: Int,material: Material,val passive: PotionEffect?,effect: PotionEffect?) : EnergyEffect(energy,material,effect) {
+
+ var predicate: Predicate? = null
+
+ constructor(energy: Int,material: Material,passive: PotionEffect?,effect: PotionEffect?,predicate: Predicate):this(energy,material,passive,effect) {
+ this.predicate = predicate
+ }
+
+ override fun onConsume(player: Player): Boolean {
+
+ val debuff = if (this.effect == null) false else isDebuff(this.effect.type)
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId) ?: return false
+
+ val receivers = findReceivers(player,team,PvPClassHandler.BARD_RANGE,debuff,this.effect)
+
+ Bunkers.instance.server.pluginManager.callEvent(BardEffectEvent(player,receivers.filter{it.uniqueId != player.uniqueId},this))
+
+ receivers.forEach{
+
+ if (this.effect == null && this.predicate != null) {
+ this.predicate!!.test(it)
+ } else if (this.effect != null) {
+ Bunkers.instance.pvpClassHandler.addPotionEffect(it,this.effect)
+ }
+
+ }
+ return true
+ }
+
+ companion object {
+
+ fun isDebuff(effect: PotionEffectType):Boolean {
+ return PotionUtil.isDebuff(effect)
+ }
+
+ fun findReceivers(player: Player,team: Team,range: Double,debuff: Boolean,effect: PotionEffect?):Collection {
+
+ val toReturn = ArrayList()
+
+ player.getNearbyEntities(range,range / 2,range).filter{it.uniqueId != player.uniqueId}.filterIsInstance().filter{
+
+ val pvpClass = Bunkers.instance.pvpClassHandler.findById(it.uniqueId)
+
+ if (effect != null && pvpClass?.type == PvPClass.Type.BARD && BardClass.BARD_ILLEGAL_EFFECTS.contains(effect.type)) {
+ return@filter false
+ }
+
+ if (debuff) {
+ return@filter !team.isMember(it.uniqueId)
+ }
+
+ return@filter team.isMember(it.uniqueId)
+ }.forEach{toReturn.add(it)}
+
+ if (effect == null || !BardClass.BARD_ILLEGAL_EFFECTS.contains(effect.type)) {
+ toReturn.add(player)
+ }
+
+ return toReturn
+ }
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/service/BardService.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/service/BardService.kt
new file mode 100644
index 0000000..8c51b73
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/service/BardService.kt
@@ -0,0 +1,48 @@
+package cc.fyre.bunkers.pvpclass.data.service
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.pvpclass.PvPClassHandler
+import cc.fyre.bunkers.pvpclass.data.PvPClass
+import cc.fyre.bunkers.pvpclass.data.item.energy.EnergyEffect
+import org.bukkit.scheduler.BukkitRunnable
+
+/**
+ * @project hcf
+ *
+ * @date 12/09/2020
+ * @author xanderume@gmail.com
+ */
+class BardService(private val instance: Bunkers) : BukkitRunnable() {
+
+ override fun run() {
+
+ for (entry in this.instance.pvpClassHandler.cache.filterValues{it == PvPClass.Type.BARD}.mapKeys{this.instance.server.getPlayer(it.key)}.mapValues{this.instance.pvpClassHandler.findByType(it.value)}) {
+
+ if (entry.key == null || !entry.key.isOnline) {
+ continue
+ }
+
+ if (entry.value == null) {
+ continue
+ }
+
+ if (entry.key.itemInHand == null) {
+ continue
+ }
+
+ val effect = entry.value!!.findEffectByItem(entry.key.itemInHand.type)
+
+ if (effect == null || effect !is EnergyEffect.BardEffect || effect.passive == null) {
+ continue
+ }
+
+ val team = this.instance.teamHandler.findById(entry.key.uniqueId) ?: return
+
+ val receivers = EnergyEffect.BardEffect.findReceivers(entry.key,team,PvPClassHandler.BARD_RANGE,EnergyEffect.BardEffect.isDebuff(effect.passive.type),effect.passive)
+
+ receivers.forEach{this.instance.pvpClassHandler.addPotionEffect(it,effect.passive)}
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/type/BardClass.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/type/BardClass.kt
new file mode 100644
index 0000000..d550776
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/data/type/BardClass.kt
@@ -0,0 +1,97 @@
+package cc.fyre.bunkers.pvpclass.data.type
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.pvpclass.data.PvPClass
+import cc.fyre.bunkers.pvpclass.data.item.energy.EnergyEffect
+import cc.fyre.bunkers.pvpclass.data.item.ConsumableItem
+import cc.fyre.bunkers.pvpclass.data.service.BardService
+import cc.fyre.bunkers.pvpclass.event.type.BardEffectEvent
+import cc.fyre.engine.util.FormatUtil
+import cc.fyre.engine.util.PotionUtil
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.PotionEffectAddEvent
+import org.bukkit.potion.PotionEffect
+import org.bukkit.potion.PotionEffectType
+import java.util.function.Predicate
+
+/**
+ * @project hcf
+ *
+ * @date 12/09/2020
+ * @author xanderume@gmail.com
+ */
+object BardClass : PvPClass(Type.BARD),Listener {
+
+ val BARD_ILLEGAL_EFFECTS = arrayOf(PotionEffectType.INCREASE_DAMAGE)
+ private val service = BardService(Bunkers.instance)
+
+ init {
+ this.effects.add(EnergyEffect.BardEffect(20,Material.SUGAR,PotionEffect(PotionEffectType.SPEED,6*20,1),PotionEffect(PotionEffectType.SPEED,6*20,2)))
+ this.effects.add(EnergyEffect.BardEffect(45,Material.BLAZE_POWDER,PotionEffect(PotionEffectType.INCREASE_DAMAGE,6*20,0),PotionEffect(PotionEffectType.INCREASE_DAMAGE,5*20,1)))
+ this.effects.add(EnergyEffect.BardEffect(40,Material.GHAST_TEAR,PotionEffect(PotionEffectType.REGENERATION,6*20,0),PotionEffect(PotionEffectType.REGENERATION,5*20,2)))
+ this.effects.add(EnergyEffect.BardEffect(40,Material.IRON_INGOT,PotionEffect(PotionEffectType.DAMAGE_RESISTANCE,6*20,0),PotionEffect(PotionEffectType.DAMAGE_RESISTANCE,5*20,2)))
+ this.effects.add(EnergyEffect.BardEffect(25,Material.FEATHER,PotionEffect(PotionEffectType.JUMP,6*20,1),PotionEffect(PotionEffectType.JUMP,5*20,6)))
+ this.effects.add(EnergyEffect.BardEffect(25,Material.MAGMA_CREAM,PotionEffect(PotionEffectType.FIRE_RESISTANCE,6*20,0),PotionEffect(PotionEffectType.FIRE_RESISTANCE,46*20,0)))
+ this.effects.add(EnergyEffect.BardEffect(35,Material.SPIDER_EYE,null,PotionEffect(PotionEffectType.WITHER,5*20,1)))
+
+ this.effects.add(EnergyEffect.BardEffect(25,Material.WHEAT,null,null,Predicate{
+ it.foodLevel = 20
+ it.saturation = 10.0F
+ return@Predicate true
+ }))
+
+ //this.effects.add(EnergyEffect.BardEffect(25,Material.FERMENTED_SPIDER_EYE,PotionEffect(PotionEffectType.INVISIBILITY,6*20,0),PotionEffect(PotionEffectType.INVISIBILITY,46*20,0)))
+
+ this.service.runTaskTimer(Bunkers.instance,4L,4L)
+
+ Bunkers.instance.server.pluginManager.registerEvents(this,Bunkers.instance)
+ }
+
+ override fun onEnable(player: Player) {}
+
+ override fun onDisable(player: Player) {}
+
+ override fun isEnergyBased(): Boolean {
+ return true
+ }
+
+ override fun getConsumableItems(): List {
+ return ArrayList()
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPotionEffectAdd(event: PotionEffectAddEvent) {
+
+ if (Bunkers.instance.pvpClassHandler.findById(event.entity.uniqueId)?.type != this.type) {
+ return
+ }
+
+ if (BARD_ILLEGAL_EFFECTS.none{it == event.effect.type}) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onBardEffect(event: BardEffectEvent) {
+
+ if (event.effect.effect == null) {
+ return
+ }
+
+ val name = PotionUtil.getDisplayName(event.effect.effect.type)
+ val level = FormatUtil.toRoman(event.effect.effect.amplifier + 1)
+ val debuff = PotionUtil.isDebuff(event.effect.effect.type)
+
+ val total = event.receivers.size
+
+ event.player.sendMessage("${ChatColor.YELLOW}You have given $name $level ${ChatColor.YELLOW}to ${if (debuff) "${ChatColor.RED}${total}${ChatColor.YELLOW} enem${if (total == 1) "y" else "ies"}" else if (total == 0 && !BARD_ILLEGAL_EFFECTS.contains(event.effect.effect.type)) "yourself" else "${ChatColor.GREEN}$total ${ChatColor.YELLOW}teammate${if (total == 1) "" else "s"}"}.")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent.kt
new file mode 100644
index 0000000..4c9e2ec
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/PvPClassEquipEvent.kt
@@ -0,0 +1,35 @@
+package cc.fyre.bunkers.pvpclass.event
+
+import cc.fyre.bunkers.pvpclass.data.PvPClass
+import org.bukkit.entity.Player
+import org.bukkit.event.Cancellable
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+
+/**
+ * @project hcf
+ *
+ * @date 11/09/2020
+ * @author xanderume@gmail.com
+ */
+class PvPClassEquipEvent(val player: Player,val pvpClass: PvPClass) : Event(), Cancellable {
+
+ private var cancelled = false
+
+ override fun isCancelled(): Boolean {
+ return this.cancelled
+ }
+
+ override fun setCancelled(cancelled: Boolean) {
+ this.cancelled = cancelled
+ }
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+ @JvmStatic val handlerList = HandlerList()
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent.kt
new file mode 100644
index 0000000..5f0b751
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/PvPClassUnEquipEvent.kt
@@ -0,0 +1,25 @@
+package cc.fyre.bunkers.pvpclass.event
+
+import cc.fyre.bunkers.pvpclass.data.PvPClass
+import org.bukkit.entity.Player
+
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+
+/**
+ * @project hcf
+ *
+ * @date 11/09/2020
+ * @author xanderume@gmail.com
+ */
+class PvPClassUnEquipEvent(val player: Player,val pvpClass: PvPClass) : Event() {
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+ @JvmStatic val handlerList = HandlerList()
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent.kt
new file mode 100644
index 0000000..af74c51
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/event/type/BardEffectEvent.kt
@@ -0,0 +1,25 @@
+package cc.fyre.bunkers.pvpclass.event.type
+
+import cc.fyre.bunkers.pvpclass.data.item.energy.EnergyEffect
+import org.bukkit.entity.Player
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+
+/**
+ * @project hcf
+ *
+ * @date 11/09/2020
+ * @author xanderume@gmail.com
+ */
+class BardEffectEvent(val player: Player,val receivers: Collection,val effect: EnergyEffect.BardEffect) : Event() {
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+ @JvmStatic val handlerList = HandlerList()
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/listener/PvPClassListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/listener/PvPClassListener.kt
new file mode 100644
index 0000000..b84c74f
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/pvpclass/listener/PvPClassListener.kt
@@ -0,0 +1,158 @@
+package cc.fyre.bunkers.pvpclass.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.engine.util.FormatUtil
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.Action
+import org.bukkit.event.entity.PotionEffectExpireEvent
+import org.bukkit.event.inventory.EquipmentSetEvent
+import org.bukkit.event.player.PlayerInteractEvent
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerQuitEvent
+
+/**
+ * @project hcf
+ *
+ * @date 10/09/2020
+ * @author xanderume@gmail.com
+ */
+class PvPClassListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+ this.instance.pvpClassHandler.typeToClass.values.stream().filter{it.isEquipped(event.player)}.findFirst().ifPresent{this.instance.pvpClassHandler.setPvPClass(event.player,it.type)}
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+ this.instance.pvpClassHandler.setPvPClass(event.player,null)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEquipmentSet(event: EquipmentSetEvent) {
+
+ if (event.humanEntity !is Player) {
+ return
+ }
+
+ val current = this.instance.pvpClassHandler.findById(event.humanEntity.uniqueId)
+
+ // current one is equipped no need to check for other one
+ if (current != null && current.isEquipped(event.humanEntity as Player)) {
+ return
+ }
+
+ val new = this.instance.pvpClassHandler.typeToClass.values.firstOrNull{it.isEquipped(event.humanEntity as Player)}
+
+ if (new != null) {
+ this.instance.pvpClassHandler.setPvPClass(event.humanEntity as Player,new.type)
+ return
+ }
+
+ this.instance.pvpClassHandler.setPvPClass(event.humanEntity as Player,null)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerInteract(event: PlayerInteractEvent) {
+
+ if (event.action == Action.PHYSICAL) {
+ return
+ }
+
+ if (event.item == null) {
+ return
+ }
+
+ val pvpClass = this.instance.pvpClassHandler.findById(event.player.uniqueId) ?: return
+
+ val consumable = pvpClass.findConsumableByItem(event.item.type) ?: return
+
+ val cooldown = pvpClass.getCooldown(event.player,consumable)
+
+ if (cooldown > 0L) {
+ event.player.sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${FormatUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
+ return
+ }
+
+ if (!consumable.onConsume(event.player)) {
+ return
+ }
+
+ pvpClass.setCooldown(event.player,consumable)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onEnergyInteract(event: PlayerInteractEvent) {
+
+ if (!event.action.name.contains("RIGHT")) {
+ return
+ }
+
+ if (event.player.itemInHand == null) {
+ return
+ }
+
+ val pvpClass = this.instance.pvpClassHandler.findById(event.player.uniqueId) ?: return
+
+ if (!pvpClass.isEnergyBased()) {
+ return
+ }
+
+ val effect = pvpClass.findEffectByItem(event.player.itemInHand.type) ?: return
+
+ val cooldown = this.instance.timerHandler.findRemaining(event.player.uniqueId,TimerType.ENERGY_COOLDOWN)
+
+ if (cooldown > 0L) {
+ event.player.sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${FormatUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
+ return
+ }
+
+ val energy = this.instance.pvpClassHandler.getEnergy(event.player)
+
+ if (energy < effect.energy) {
+ event.player.sendMessage("${ChatColor.RED}You do not have enough energy for this! You need ${effect.energy} energy, but you only have ${energy.toInt()}.")
+ return
+ }
+
+ if (!effect.onConsume(event.player)) {
+ return
+ }
+
+ if (event.player.itemInHand.amount == 1) {
+ event.player.itemInHand = null
+ } else {
+ event.player.itemInHand.amount = event.player.itemInHand.amount - 1
+ }
+
+ this.instance.timerHandler.addTimer(event.player.uniqueId,TimerType.ENERGY_COOLDOWN)
+ this.instance.pvpClassHandler.setEnergy(event.player,energy - effect.energy)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPotionExpire(event: PotionEffectExpireEvent) {
+
+ if (event.entity !is Player) {
+ return
+ }
+
+ val previous = this.instance.pvpClassHandler.effects.remove(event.entity.uniqueId,event.effect.type)
+
+ //restore all effects that are missing for example infinite speed 2
+ if (previous == null || previous.duration >= 1_000_000) {
+
+ val pvpClass = this.instance.pvpClassHandler.findById(event.entity.uniqueId) ?: return
+
+ this.instance.server.scheduler.runTaskLater(this.instance,{pvpClass.type.effects.filter{!event.entity.hasPotionEffect(it.type)}.forEach{event.entity.addPotionEffect(it)}},1L)
+ return
+ }
+
+ event.isCancelled = true
+ event.entity.addPotionEffect(previous,true)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/RepairHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/RepairHandler.kt
new file mode 100644
index 0000000..7a4af69
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/RepairHandler.kt
@@ -0,0 +1,26 @@
+package cc.fyre.bunkers.repair
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.repair.listener.RepairListener
+import org.bukkit.inventory.ItemStack
+import org.spigotmc.SpigotConfig
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class RepairHandler(private val instance: Bunkers) {
+
+ init {
+ SpigotConfig.reduceArmorDamage = true
+
+ this.instance.server.pluginManager.registerEvents(RepairListener(this.instance),this.instance)
+ }
+
+ fun calculatePrice(item: ItemStack):Int {
+ return ((100.0 - (((item.type.maxDurability.toDouble() - item.durability.toDouble()) / item.type.maxDurability.toDouble()) * 100.0)) * 3.0).toInt()
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/listener/RepairListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/listener/RepairListener.kt
new file mode 100644
index 0000000..cd19342
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/listener/RepairListener.kt
@@ -0,0 +1,42 @@
+package cc.fyre.bunkers.repair.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.repair.menu.RepairMenu
+import org.bukkit.Material
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.Action
+import org.bukkit.event.player.PlayerInteractEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class RepairListener(private val instance: Bunkers):Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerInteract(event: PlayerInteractEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.clickedBlock == null) {
+ return
+ }
+
+ if (event.action == Action.PHYSICAL || event.action.name.contains("AIR",true)) {
+ return
+ }
+
+ if (event.clickedBlock.type != Material.ANVIL) {
+ return
+ }
+
+ this.instance.server.scheduler.runTaskLater(this.instance,{RepairMenu().openMenu(event.player)},1L)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/menu/RepairMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/menu/RepairMenu.kt
new file mode 100644
index 0000000..4dcc3bc
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/menu/RepairMenu.kt
@@ -0,0 +1,43 @@
+package cc.fyre.bunkers.repair.menu
+
+import cc.fyre.bunkers.repair.menu.element.RepairButton
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class RepairMenu : Menu() {
+
+ override fun size(buttons: Map): Int {
+ return 6*9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "${ChatColor.LIGHT_PURPLE}${ChatColor.BOLD}Repair"
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ val toReturn = HashMap()
+
+ toReturn[11] = RepairButton(player.inventory.helmet)
+ toReturn[20] = RepairButton(player.inventory.chestplate)
+ toReturn[29] = RepairButton(player.inventory.leggings)
+ toReturn[38] = RepairButton(player.inventory.boots)
+ toReturn[42] = RepairButton(player.inventory.itemInHand)
+
+ return toReturn
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/menu/element/RepairButton.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/menu/element/RepairButton.kt
new file mode 100644
index 0000000..7d240b9
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/repair/menu/element/RepairButton.kt
@@ -0,0 +1,80 @@
+package cc.fyre.bunkers.repair.menu.element
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.util.ItemBuilder
+import net.frozenorb.qlib.util.ItemUtils
+import org.apache.commons.lang.StringUtils
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.inventory.ClickType
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class RepairButton(private val itemStack: ItemStack?) : Button() {
+
+ private val name = if (this.itemStack == null || this.itemStack.type == Material.AIR) "Air" else ItemUtils.getName(ItemStack(this.itemStack.type))
+
+ override fun getName(p0: Player?): String ?{
+ return null
+ }
+
+ override fun getMaterial(p0: Player?): Material? {
+ return null
+ }
+
+ override fun getDescription(p0: Player?): MutableList? {
+ return null
+ }
+
+ override fun getButtonItem(player: Player?): ItemStack {
+
+ if (this.itemStack == null || this.itemStack.type == Material.AIR || this.itemStack.type.maxDurability == 0.toShort()) {
+ return ItemBuilder.of(Material.STAINED_GLASS_PANE)
+ .name(" ")
+ .data(15)
+ .build()
+ }
+
+ if (this.itemStack.durability == 0.toShort()) {
+ return ItemBuilder.of(Material.STAINED_GLASS_PANE).name(" ").data(13).build()
+ }
+
+ val price = Bunkers.instance.repairHandler.calculatePrice(this.itemStack)
+
+ return ItemBuilder.copyOf(this.itemStack.clone()).name("${ChatColor.GOLD}${this.name}").addToLore(
+ "${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}",
+ "${ChatColor.GREEN}Repair ${ChatColor.YELLOW}${this.name}${ChatColor.GREEN} for ${ChatColor.RED}$${price}${ChatColor.GREEN}.",
+ "${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}"
+ ).build()
+ }
+
+ override fun clicked(player: Player, slot: Int, clickType: ClickType?) {
+
+ if (this.itemStack == null || this.itemStack.type == Material.AIR) {
+ return
+ }
+
+ if (this.itemStack.durability == 0.toShort()) {
+ return
+ }
+
+ val price = Bunkers.instance.repairHandler.calculatePrice(this.itemStack)
+
+ if (price > Bunkers.instance.statisticHandler.getBalance(player.uniqueId)) {
+ player.sendMessage("${ChatColor.RED}You cannot afford to repair this item.")
+ return
+ }
+
+ this.itemStack.durability = 0
+
+ Bunkers.instance.statisticHandler.addBalance(player.uniqueId,-price)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/ShopHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/ShopHandler.kt
new file mode 100644
index 0000000..aa75189
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/ShopHandler.kt
@@ -0,0 +1,63 @@
+package cc.fyre.bunkers.shop
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.shop.data.ShopType
+import cc.fyre.bunkers.shop.listener.ShopListener
+import cc.fyre.bunkers.shop.parameter.ShopTypeParameterProvider
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.bunkers.villager.data.VillagerEntity
+import net.frozenorb.qlib.command.FrozenCommandHandler
+import org.bukkit.Location
+import org.bukkit.Material
+import org.bukkit.inventory.Inventory
+import org.bukkit.inventory.ItemStack
+import org.bukkit.metadata.FixedMetadataValue
+
+/**
+ * @project bunkers
+ *
+ * @date 18/08/2020
+ * @author xanderume@gmail.com
+ */
+class ShopHandler(private val instance: Bunkers) {
+
+ init {
+ this.instance.server.pluginManager.registerEvents(ShopListener(this.instance),this.instance)
+
+ FrozenCommandHandler.registerParameterType(ShopType::class.java,ShopTypeParameterProvider())
+ }
+
+ fun spawnVillager(location: Location,shop: ShopType,team: Team.Type):VillagerEntity {
+
+ val villager = this.instance.villagerHandler.spawnVillager(location)
+
+ villager.bukkitEntity.setMetadata(TYPE_METADATA,FixedMetadataValue(this.instance,shop.name))
+ villager.bukkitEntity.setMetadata(TEAM_METADATA,FixedMetadataValue(this.instance,team.name))
+
+ villager.customName = "${team.color}${shop.getDisplayName()}"
+ villager.customNameVisible = true
+
+ return villager
+ }
+
+ companion object {
+
+ const val TYPE_METADATA = "SHOP_TYPE"
+ const val TEAM_METADATA = "TEAM_TYPE"
+
+ const val RESPAWN_SECONDS = 300
+
+ fun isArmor(item: ItemStack):Boolean {
+ return item.type.name.endsWith("HELMET",true)
+ || item.type.name.endsWith("CHESTPLATE",true)
+ || item.type.name.endsWith("LEGGINGS",true)
+ || item.type.name.endsWith("BOOTS",true)
+ }
+
+ fun findAvailableSlots(inventory: Inventory):Int {
+ return inventory.contents.filter{it == null || it.type == Material.AIR}.count()
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/data/ShopType.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/data/ShopType.kt
new file mode 100644
index 0000000..9802bf3
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/data/ShopType.kt
@@ -0,0 +1,35 @@
+package cc.fyre.bunkers.shop.data
+
+import cc.fyre.bunkers.shop.menu.BuildMenu
+import cc.fyre.bunkers.shop.menu.CombatMenu
+import cc.fyre.bunkers.shop.menu.EnchantMenu
+import cc.fyre.bunkers.shop.menu.SellMenu
+import net.frozenorb.qlib.menu.Menu
+import org.apache.commons.lang.StringUtils
+
+/**
+ * @project bunkers
+ *
+ * @date 18/08/2020
+ * @author xanderume@gmail.com
+ */
+enum class ShopType(val menu: Menu) {
+
+ SELL(SellMenu()),
+ BUILD(BuildMenu()),
+ COMBAT(CombatMenu()),
+ ENCHANT(EnchantMenu());
+
+ fun getDisplayName():String {
+ return "${StringUtils.capitalize(this.name.toLowerCase())} Shop"
+ }
+
+ companion object {
+
+ fun findByName(name: String): ShopType? {
+ return values().firstOrNull{it.name.equals(name,true)}
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/listener/ShopListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/listener/ShopListener.kt
new file mode 100644
index 0000000..64855db
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/listener/ShopListener.kt
@@ -0,0 +1,121 @@
+package cc.fyre.bunkers.shop.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.shop.ShopHandler
+import cc.fyre.bunkers.shop.data.ShopType
+import cc.fyre.bunkers.shop.service.ShopService
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.bunkers.villager.VillagerHandler
+import cc.fyre.bunkers.villager.data.kb.ZeroKBProfile
+import cc.fyre.engine.GameEngine
+import org.bukkit.craftbukkit.v1_7_R4.entity.CraftVillager
+import org.bukkit.entity.Player
+import org.bukkit.entity.Villager
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.entity.EntityDamageEvent
+import org.bukkit.event.entity.EntityDeathEvent
+import org.bukkit.event.player.PlayerInteractEntityEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 18/08/2020
+ * @author xanderume@gmail.com
+ */
+class ShopListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDeath(event: EntityDeathEvent) {
+
+ if (event.entity !is Villager) {
+ return
+ }
+
+ if (!event.entity.hasMetadata(ShopHandler.TYPE_METADATA) || !event.entity.hasMetadata(ShopHandler.TEAM_METADATA)) {
+ return
+ }
+
+ val shop = ShopType.findByName(event.entity.getMetadata(ShopHandler.TYPE_METADATA)[0].asString()) ?: return
+ val type = Team.Type.findByName(event.entity.getMetadata(ShopHandler.TEAM_METADATA)[0].asString()) ?: return
+
+ ShopService(event.entity.location.clone(),shop,type).runTaskTimer(this.instance,20L,20L)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityInteract(event: PlayerInteractEntityEvent) {
+
+ if (event.rightClicked !is Villager) {
+ return
+ }
+
+ if (!event.rightClicked.hasMetadata(ShopHandler.TYPE_METADATA) || !event.rightClicked.hasMetadata(ShopHandler.TEAM_METADATA)) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+ val type = Team.Type.findByName(event.rightClicked.getMetadata(ShopHandler.TEAM_METADATA)[0].asString()) ?: return
+
+ if (team.type != type) {
+ return
+ }
+
+ if (this.instance.timerHandler.hasTimer(event.player.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.player)) {
+ return
+ }
+
+ this.instance.server.scheduler.runTask(this.instance) {
+ ShopType.findByName(event.rightClicked.getMetadata(ShopHandler.TYPE_METADATA)[0].asString())?.menu?.openMenu(event.player)
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDamage(event: EntityDamageEvent) {
+
+ if (event.entity !is Villager) {
+ return
+ }
+
+ if ((event.entity as Villager).kbProfile != VillagerHandler.KB_PROFILE) {
+ (event.entity as CraftVillager).kbProfile = VillagerHandler.KB_PROFILE
+ }
+
+ if (!event.entity.hasMetadata(ShopHandler.TYPE_METADATA) || !event.entity.hasMetadata(ShopHandler.TEAM_METADATA)) {
+ return
+ }
+
+ if (event !is EntityDamageByEntityEvent) {
+ event.isCancelled = true
+ return
+ }
+
+ if (event.damager !is Player) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.damager.uniqueId)
+
+ if (team == null) {
+ event.isCancelled = true
+ return
+ }
+
+ val type = Team.Type.findByName(event.entity.getMetadata(ShopHandler.TEAM_METADATA)[0].asString()) ?: return
+
+ if (team.type != type) {
+ event.damage = event.damage / 1.5F
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/BuildMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/BuildMenu.kt
new file mode 100644
index 0000000..6130c33
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/BuildMenu.kt
@@ -0,0 +1,51 @@
+package cc.fyre.bunkers.shop.menu
+
+import cc.fyre.bunkers.shop.menu.element.BuyElement
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project bunkers
+ *
+ * @date 05/08/2020
+ * @author xanderume@gmail.com
+ */
+class BuildMenu : Menu() {
+
+ override fun size(buttons: Map): Int {
+ return 5*9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "${ChatColor.BLUE}${ChatColor.BOLD}Build"
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ val toReturn = HashMap()
+
+ toReturn[10] = BuyElement(ItemStack(Material.FENCE_GATE),3,true)
+ toReturn[11] = BuyElement(ItemStack(Material.LADDER),3,true)
+ toReturn[12] = BuyElement(ItemStack(Material.CHEST),3,true)
+
+ toReturn[14] = BuyElement(ItemStack(Material.COBBLESTONE),1,true)
+ toReturn[15] = BuyElement(ItemStack(Material.STONE),1,true)
+ toReturn[16] = BuyElement(ItemStack(Material.SMOOTH_BRICK),1,true)
+
+ toReturn[30] = BuyElement(ItemStack(Material.DIAMOND_PICKAXE),50,false)
+ toReturn[31] = BuyElement(ItemStack(Material.DIAMOND_AXE),50,false)
+ toReturn[32] = BuyElement(ItemStack(Material.DIAMOND_SPADE),50,false)
+
+ return toReturn
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/ClassMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/ClassMenu.kt
new file mode 100644
index 0000000..6b5106d
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/ClassMenu.kt
@@ -0,0 +1,52 @@
+package cc.fyre.bunkers.shop.menu
+
+import cc.fyre.bunkers.shop.menu.element.BuyElement
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+import net.frozenorb.qlib.menu.buttons.BackButton
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project bunkers
+ *
+ * @date 26/12/2020
+ * @author xanderume@gmail.com
+ */
+class ClassMenu : Menu() {
+
+ override fun size(buttons: Map): Int {
+ return 5*9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "${ChatColor.RED}${ChatColor.BOLD}Class"
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ val toReturn = HashMap()
+
+ toReturn[10] = BuyElement(ItemStack(Material.SUGAR),10,true)
+ toReturn[11] = BuyElement(ItemStack(Material.WHEAT),10,true)
+
+ toReturn[15] = BuyElement(ItemStack(Material.BLAZE_POWDER),20,true)
+ toReturn[16] = BuyElement(ItemStack(Material.GHAST_TEAR),20,true)
+
+ toReturn[19] = BuyElement(ItemStack(Material.FEATHER),10,true)
+ toReturn[20] = BuyElement(ItemStack(Material.MAGMA_CREAM),10,true)
+
+ toReturn[24] = BuyElement(ItemStack(Material.SPIDER_EYE),20,true)
+ toReturn[25] = BuyElement(ItemStack(Material.IRON_INGOT),20,true)
+
+ toReturn[31] = BackButton(CombatMenu())
+
+ return toReturn
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/CombatMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/CombatMenu.kt
new file mode 100644
index 0000000..52d8a93
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/CombatMenu.kt
@@ -0,0 +1,84 @@
+package cc.fyre.bunkers.shop.menu
+
+import cc.fyre.bunkers.game.BunkersGameAdapter
+import cc.fyre.bunkers.shop.menu.element.BuyElement
+
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+
+import net.frozenorb.qlib.util.ItemBuilder
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.inventory.ClickType
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project bunkers
+ *
+ * @date 05/08/2020
+ * @author xanderume@gmail.com
+ */
+class CombatMenu : Menu() {
+
+ override fun size(buttons: Map): Int {
+ return 6*9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "${ChatColor.RED}${ChatColor.BOLD}Combat"
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ val toReturn = HashMap()
+
+ toReturn[9] = BuyElement(ItemStack(Material.DIAMOND_HELMET),75,false)
+ toReturn[18] = BuyElement(ItemStack(Material.DIAMOND_CHESTPLATE),200,false)
+ toReturn[27] = BuyElement(ItemStack(Material.DIAMOND_LEGGINGS),150,false)
+ toReturn[36] = BuyElement(ItemStack(Material.DIAMOND_BOOTS),75,false)
+
+ toReturn[19] = BuyElement(ItemStack(Material.DIAMOND_SWORD),100,false)
+ toReturn[28] = BuyElement(ItemStack(Material.ENDER_PEARL),25,true)
+
+ toReturn[13] = object : Button() {
+
+ override fun getName(p0: Player?): String {
+ return "${ChatColor.RED}${ChatColor.BOLD}Class Shop"
+ }
+
+ override fun getDescription(p0: Player?): MutableList {
+ return arrayListOf()
+ }
+
+ override fun getMaterial(p0: Player?): Material {
+ return Material.GOLD_INGOT
+ }
+
+ override fun clicked(player: Player?, slot: Int, clickType: ClickType?) {
+ ClassMenu().openMenu(player)
+ }
+
+ }
+
+ toReturn[21] = BuyElement(ItemBuilder.of(Material.POTION).data(8226).build(),"Speed Potion",10,false)
+ toReturn[22] = BuyElement(BunkersGameAdapter.ANTIDOTE,"Antidote",150,false)
+ toReturn[23] = BuyElement(BunkersGameAdapter.LESSER_INVISIBILITY,"Lesser Invisibility",300,false)
+ toReturn[30] = BuyElement(ItemBuilder.of(Material.POTION).data(16421).build(),"Healing Potion",5,true)
+ toReturn[31] = BuyElement(ItemBuilder.of(Material.POTION).data(16388).build(),"Poison Potion",50,false)
+ toReturn[32] = BuyElement(ItemBuilder.of(Material.POTION).data(16426).build(),"Slowness Potion",50,false)
+ toReturn[40] = BuyElement(ItemBuilder.of(Material.POTION).data(16430).build(),"Invisibility Potion",1250,false)
+
+ toReturn[17] = BuyElement(ItemStack(Material.GOLD_HELMET),75,false)
+ toReturn[26] = BuyElement(ItemStack(Material.GOLD_CHESTPLATE),200,false)
+ toReturn[35] = BuyElement(ItemStack(Material.GOLD_LEGGINGS),150,false)
+ toReturn[44] = BuyElement(ItemStack(Material.GOLD_BOOTS),75,false)
+
+ return toReturn
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+
+}
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/EnchantMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/EnchantMenu.kt
new file mode 100644
index 0000000..4456ead
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/EnchantMenu.kt
@@ -0,0 +1,48 @@
+package cc.fyre.bunkers.shop.menu
+
+import cc.fyre.bunkers.shop.menu.element.EnchantElement
+
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.enchantments.Enchantment
+import org.bukkit.entity.Player
+import org.bukkit.inventory.ItemStack
+
+class EnchantMenu : Menu() {
+
+ override fun size(buttons: Map): Int {
+ return 6*9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "${ChatColor.BLUE}${ChatColor.BOLD}Enchant"
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ val toReturn = HashMap()
+
+ toReturn[10] = EnchantElement(ItemStack(Material.DIAMOND_HELMET),Enchantment.PROTECTION_ENVIRONMENTAL,1,300)
+ toReturn[19] = EnchantElement(ItemStack(Material.DIAMOND_CHESTPLATE),Enchantment.PROTECTION_ENVIRONMENTAL,1,300)
+ toReturn[28] = EnchantElement(ItemStack(Material.DIAMOND_LEGGINGS),Enchantment.PROTECTION_ENVIRONMENTAL,1,300)
+ toReturn[37] = EnchantElement(ItemStack(Material.DIAMOND_BOOTS),Enchantment.PROTECTION_ENVIRONMENTAL,1,300)
+
+ toReturn[12] = EnchantElement(ItemStack(Material.DIAMOND_SWORD),Enchantment.DAMAGE_ALL,1,125)
+ toReturn[13] = EnchantElement(ItemStack(Material.FEATHER),Enchantment.PROTECTION_FALL,4,125)
+ toReturn[14] = EnchantElement(ItemStack(Material.DIAMOND_PICKAXE),Enchantment.DIG_SPEED,3,500)
+
+ toReturn[16] = EnchantElement(ItemStack(Material.GOLD_HELMET),Enchantment.DURABILITY,3,350)
+ toReturn[25] = EnchantElement(ItemStack(Material.GOLD_CHESTPLATE),Enchantment.DURABILITY,3,350)
+ toReturn[34] = EnchantElement(ItemStack(Material.GOLD_LEGGINGS),Enchantment.DURABILITY,3,350)
+ toReturn[43] = EnchantElement(ItemStack(Material.GOLD_BOOTS),Enchantment.DURABILITY,3,350)
+
+ return toReturn
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/SellMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/SellMenu.kt
new file mode 100644
index 0000000..444e971
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/SellMenu.kt
@@ -0,0 +1,46 @@
+package cc.fyre.bunkers.shop.menu
+
+import cc.fyre.bunkers.shop.menu.element.SellElement
+
+
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 04/08/2020
+ * @author xanderume@gmail.com
+ */
+class SellMenu : Menu() {
+
+ override fun size(buttons: Map): Int {
+ return 9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "${ChatColor.GREEN}${ChatColor.BOLD}Sell"
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ val toReturn = HashMap()
+
+ toReturn[2] = SellElement(Material.EMERALD,40,true)
+ toReturn[3] = SellElement(Material.DIAMOND,30,true)
+ toReturn[4] = SellElement(Material.GOLD_INGOT,25,true)
+ toReturn[5] = SellElement(Material.IRON_INGOT,20,true)
+ toReturn[6] = SellElement(Material.COAL,10,true)
+
+ return toReturn
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/BuyElement.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/BuyElement.kt
new file mode 100644
index 0000000..427da3e
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/BuyElement.kt
@@ -0,0 +1,153 @@
+package cc.fyre.bunkers.shop.menu.element
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.shop.ShopHandler
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.util.ItemUtils
+import org.apache.commons.lang.StringUtils
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.inventory.ClickType
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project bunkers
+ *
+ * @date 05/08/2020
+ * @author xanderume@gmail.com
+ */
+class BuyElement(private val item: ItemStack,private val price: Int,private val fill: Boolean) : Button() {
+
+ private var name: String? = null
+ private var displayName: String? = null
+
+ constructor(item: ItemStack,displayName: String,price: Int,fill: Boolean):this(item,price,fill) {
+ this.name = displayName
+ this.displayName = displayName
+ }
+
+ override fun getName(player: Player): String {
+
+ val balance = Bunkers.instance.statisticHandler.getBalance(player.uniqueId)
+
+ if (this.name == null) {
+ this.name = ItemUtils.getName(ItemStack(this.item.type))
+ }
+
+ return "${if (balance < this.price) ChatColor.RED else ChatColor.GREEN}Buy ${this.name}"
+ }
+
+ override fun getMaterial(p0: Player?): Material? {
+ return this.item.type
+ }
+
+ override fun getDamageValue(player: Player?): Byte {
+ return this.item.data.data
+ }
+
+ override fun getDescription(player: Player): MutableList {
+
+ val lore = ArrayList()
+ val balance = Bunkers.instance.statisticHandler.getBalance(player.uniqueId)
+
+ lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
+ lore.add("${ChatColor.GREEN}Buy ${ChatColor.YELLOW}1x ${this.name}${ChatColor.GREEN} for ${ChatColor.RED}$${this.price}${ChatColor.GREEN}.")
+
+ if (this.fill) {
+
+ var amount = if (this.item.maxStackSize != 1) this.item.maxStackSize else ShopHandler.findAvailableSlots(player.inventory)
+
+ if (amount * this.price > balance) {
+ amount = (balance / this.price)
+ }
+
+ if (amount != 0) {
+ lore.add("${ChatColor.GREEN}Buy ${ChatColor.YELLOW}${amount}x ${this.name}${ChatColor.GREEN} for ${ChatColor.RED}$${amount * this.price}${ChatColor.GREEN}.")
+ }
+
+ }
+
+ lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
+
+ return lore
+ }
+
+ //TODO: cleanup armor part
+
+ override fun clicked(player: Player,slot: Int,clickType: ClickType) {
+
+ if (this.name == null) {
+ this.name = ItemUtils.getName(ItemStack(this.item.type))
+ }
+
+ val balance = Bunkers.instance.statisticHandler.getBalance(player.uniqueId)
+
+ if (!this.fill || clickType.isLeftClick) {
+
+ if (balance < this.price) {
+ player.sendMessage("${ChatColor.RED}You cannot afford this item.")
+ return
+ }
+
+ if (ShopHandler.isArmor(this.item)) {
+
+ val part = this.item.type.name.toUpperCase().split("_")[1]
+
+ when {
+ part == "HELMET" && (player.inventory.helmet == null || player.inventory.helmet.type == Material.AIR) -> player.inventory.helmet = this.item
+ part == "CHESTPLATE" && (player.inventory.chestplate == null || player.inventory.chestplate.type == Material.AIR) -> player.inventory.chestplate = this.item
+ part == "LEGGINGS" && (player.inventory.leggings == null || player.inventory.leggings.type == Material.AIR) -> player.inventory.leggings = this.item
+ part == "BOOTS" && (player.inventory.boots == null || player.inventory.boots.type == Material.AIR) -> player.inventory.boots = this.item
+ else -> player.inventory.addItem(this.item)
+ }
+
+ player.updateInventory()
+ } else {
+ player.inventory.addItem(this.item)
+ }
+
+ player.sendMessage("${ChatColor.GREEN}Purchased ${ChatColor.YELLOW}1${ChatColor.GREEN} ${this.name} for ${ChatColor.WHITE}$${this.price}${ChatColor.GREEN}.")
+
+ Bunkers.instance.statisticHandler.addBalance(player.uniqueId,-this.price)
+ return
+ }
+
+ if (!clickType.isRightClick) {
+ return
+ }
+
+ var amount = if (this.item.maxStackSize != 1) this.item.maxStackSize else ShopHandler.findAvailableSlots(player.inventory)
+
+ if (amount * this.price > balance) {
+ amount = (balance / this.price)
+ }
+
+ if (amount == 0) {
+ return
+ }
+
+ val item = this.item.clone()
+
+ item.amount = amount
+
+ if (this.item.maxStackSize > 1) {
+ player.inventory.addItem(item)
+ } else {
+ repeat(amount) {
+
+ val new = item.clone()
+
+ new.amount = 1
+
+ player.inventory.addItem(new)
+ }
+
+ }
+
+ player.sendMessage("${ChatColor.GREEN}Purchased ${ChatColor.YELLOW}${amount}${ChatColor.GREEN} ${"${this.name}${if (amount > 1) "" else "s"}"} for ${ChatColor.WHITE}$${amount * this.price}${ChatColor.GREEN}.")
+
+ Bunkers.instance.statisticHandler.addBalance(player.uniqueId,-(amount*this.price))
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/EnchantElement.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/EnchantElement.kt
new file mode 100644
index 0000000..8c762c5
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/EnchantElement.kt
@@ -0,0 +1,109 @@
+package cc.fyre.bunkers.shop.menu.element
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.shop.ShopHandler
+import cc.fyre.engine.util.EnchantUtil
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.util.ItemUtils
+import org.apache.commons.lang.StringUtils
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.enchantments.Enchantment
+import org.bukkit.entity.Player
+import org.bukkit.event.inventory.ClickType
+import org.bukkit.inventory.ItemStack
+
+class EnchantElement(private val item: ItemStack,private val enchant: Enchantment,private val level: Int,private val price: Int) : Button() {
+
+ private var displayName: String? = null
+
+ constructor(item: ItemStack,enchant: Enchantment,level: Int,price: Int,displayName: String):this(item,enchant,level,price) {
+ this.displayName = displayName
+ }
+
+ private val name = this.displayName ?: ItemUtils.getName(this.item)
+
+ override fun getName(player: Player): String {
+
+ val balance = Bunkers.instance.statisticHandler.getBalance(player.uniqueId)
+
+ return "${if (balance < this.price) ChatColor.RED else ChatColor.GREEN}Buy ${EnchantUtil.getName(this.enchant)} ${this.level}"
+ }
+
+ override fun getMaterial(p0: Player?): Material? {
+ return this.item.type
+ }
+
+ override fun getDamageValue(player: Player?): Byte {
+ return this.item.data.data
+ }
+
+ override fun getDescription(p0: Player?): MutableList {
+
+ val lore = arrayListOf()
+
+ lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
+ lore.add("${ChatColor.GREEN}Buy ${ChatColor.YELLOW}${EnchantUtil.getName(this.enchant)} ${this.level} ${ChatColor.GREEN}for ${ChatColor.RED}$${this.price}${ChatColor.GREEN}.")
+ lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
+
+ return lore
+ }
+
+ override fun clicked(player: Player,slot: Int,clickType: ClickType) {
+
+ val balance = Bunkers.instance.statisticHandler.getBalance(player.uniqueId)
+
+ if (balance < this.price) {
+ player.sendMessage("${ChatColor.RED}You cannot afford this enchant.")
+ return
+ }
+
+ val item = player.inventory.armorContents.plus(player.inventory.contents).filterNotNull().filter{
+
+ if (it.type == Material.AIR) {
+ return@filter false
+ }
+
+ if (it.containsEnchantment(this.enchant)) {
+ return@filter false
+ }
+
+ if (this.enchant == Enchantment.DURABILITY && this.item.type.name.contains("DIAMOND")) {
+ return@filter false
+ }
+
+ if (this.enchant == Enchantment.DURABILITY) {
+ return@filter ShopHandler.isArmor(it) && this.item.type.name.split("_")[1].equals(it.type.name.split("_")[1],true)
+ }
+
+ if (this.enchant == Enchantment.PROTECTION_FALL) {
+ return@filter it.type.name.endsWith("BOOTS")
+ }
+
+ if (this.enchant == Enchantment.PROTECTION_ENVIRONMENTAL) {
+ return@filter ShopHandler.isArmor(it) && this.item.type.name.split("_")[1].equals(it.type.name.split("_")[1],true)
+ }
+
+ // for some reason canEnchantItem returns false?
+ if (this.enchant == Enchantment.ARROW_INFINITE) {
+ return@filter it.type == Material.BOW
+ }
+
+ return@filter this.enchant.canEnchantItem(it)
+ }.firstOrNull{ if (this.item.type == Material.FEATHER && this.enchant == Enchantment.PROTECTION_FALL) it.type.name.endsWith("BOOTS") else if (this.enchant == Enchantment.PROTECTION_ENVIRONMENTAL || this.enchant == Enchantment.DURABILITY) ShopHandler.isArmor(it) else if (this.enchant == Enchantment.ARROW_INFINITE) it.type == Material.BOW else it.type == this.item.type}
+
+ if (item == null) {
+ player.sendMessage("${ChatColor.RED}You have no item to enchant ${ChatColor.WHITE}${EnchantUtil.getName(this.enchant)}${ChatColor.RED} on.")
+ return
+ }
+
+ item.addEnchantment(this.enchant,this.level)
+ player.updateInventory()
+ Bunkers.instance.statisticHandler.addBalance(player.uniqueId,-this.price)
+
+ player.sendMessage("${ChatColor.GREEN}Enchanted${ChatColor.YELLOW} ${EnchantUtil.getName(this.enchant)} ${this.level} ${ChatColor.GREEN}on your ${ChatColor.WHITE}${ItemUtils.getName(ItemStack(item.type))} ${ChatColor.GREEN}for ${ChatColor.WHITE}$${this.price}${ChatColor.GREEN}.")
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/SellElement.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/SellElement.kt
new file mode 100644
index 0000000..a33f5c8
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/menu/element/SellElement.kt
@@ -0,0 +1,85 @@
+package cc.fyre.bunkers.shop.menu.element
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.util.ItemUtils
+import org.apache.commons.lang.StringUtils
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.inventory.ClickType
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project bunkers
+ *
+ * @date 05/08/2020
+ * @author xanderume@gmail.com
+ */
+class SellElement(private val item: Material,private val price: Int,private val all: Boolean) : Button() {
+
+ private val name = ItemUtils.getName(ItemStack(this.item)).replace(" Ingot","")
+
+ override fun getName(player: Player): String {
+ return "${if (player.inventory.contents.any{it != null && it.type == this.item}) ChatColor.RED else ChatColor.GREEN}Sell ${this.name}"
+ }
+
+ override fun getMaterial(p0: Player?): Material {
+ return this.item
+ }
+
+ override fun getDescription(p0: Player?): MutableList {
+ val lore = ArrayList()
+
+ lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
+ lore.add("${ChatColor.GREEN}Sell ${ChatColor.YELLOW}1x ${this.name}${ChatColor.GREEN} for ${ChatColor.RED}$${this.price}${ChatColor.GREEN}.")
+ lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
+
+ return lore
+ }
+
+ override fun clicked(player: Player, slot: Int, clickType: ClickType) {
+
+ val collections = player.inventory.contents.filter{it != null && it.type == this.item}.toCollection(ArrayList())
+
+ if (collections.isEmpty()) {
+ player.sendMessage("${ChatColor.RED}You do not have any ${this.name.toLowerCase()} to sell.")
+ return
+ }
+
+ if (!this.all || clickType.isLeftClick) {
+ val item = player.inventory.contents.firstOrNull{it != null && it.type == this.item}
+
+ if (item == null) {
+ player.sendMessage("${ChatColor.RED}You do not have any ${this.name.toLowerCase()} to sell.")
+ return
+ }
+
+ if (item.amount == 1) {
+ player.inventory.removeItem(item)
+ } else {
+ item.amount = item.amount - 1
+ }
+
+ player.updateInventory()
+ player.sendMessage("${ChatColor.GREEN}Sold ${ChatColor.YELLOW}1 ${ChatColor.GREEN}${this.name} for ${ChatColor.WHITE}$${this.price}${ChatColor.YELLOW}.")
+
+ Bunkers.instance.statisticHandler.addBalance(player.uniqueId,this.price)
+ return
+ }
+
+ val amount = collections.filter{it != null && it.type == this.item}.map{it.amount}.sum()
+
+ collections.forEach{player.inventory.removeItem(it)}
+
+ player.updateInventory()
+ player.sendMessage("${ChatColor.GREEN}Sold ${ChatColor.YELLOW}${amount} ${ChatColor.GREEN}${"${this.name}${if (this.isPlural()) "s" else ""}"} for ${ChatColor.WHITE}$${amount * this.price}${ChatColor.YELLOW}.")
+
+ Bunkers.instance.statisticHandler.addBalance(player.uniqueId,this.price * amount)
+ }
+
+ private fun isPlural():Boolean {
+ return this.item != Material.IRON_INGOT && this.item != Material.GOLD_INGOT && this.item != Material.COAL
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/parameter/ShopTypeParameterProvider.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/parameter/ShopTypeParameterProvider.kt
new file mode 100644
index 0000000..100931e
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/parameter/ShopTypeParameterProvider.kt
@@ -0,0 +1,33 @@
+package cc.fyre.bunkers.shop.parameter
+
+import cc.fyre.bunkers.shop.data.ShopType
+import net.frozenorb.qlib.command.ParameterType
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 04/08/2020
+ * @author xanderume@gmail.com
+ */
+class ShopTypeParameterProvider : ParameterType {
+
+ override fun transform(sender: CommandSender, source: String): ShopType? {
+
+ val toReturn = ShopType.values().firstOrNull{it.name.equals(source,true)}
+
+ if (toReturn == null) {
+ sender.sendMessage("${ChatColor.RED}Shop type ${ChatColor.YELLOW}$source${ChatColor.RED} not found.")
+ return null
+ }
+
+ return toReturn
+ }
+
+ override fun tabComplete(player: Player, flags: Set, source: String): List {
+ return emptyList()
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/service/ShopService.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/service/ShopService.kt
new file mode 100644
index 0000000..bacc36d
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/shop/service/ShopService.kt
@@ -0,0 +1,48 @@
+package cc.fyre.bunkers.shop.service
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.shop.ShopHandler
+import cc.fyre.bunkers.shop.data.ShopType
+import cc.fyre.bunkers.team.data.Team
+import net.frozenorb.qlib.hologram.FrozenHologramHandler
+import net.frozenorb.qlib.util.TimeUtils
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.scheduler.BukkitRunnable
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * @project bunkers
+ *
+ * @date 18/08/2020
+ * @author xanderume@gmail.com
+ */
+class ShopService(private val location: Location,private val shop: ShopType,private val team: Team.Type):BukkitRunnable() {
+
+ private val hologram = FrozenHologramHandler.createHologram()
+ .at(this.location.clone().add(0.0,1.6,0.0))
+ .build()
+
+ private val remaining = AtomicInteger(ShopHandler.RESPAWN_SECONDS)
+
+ init {
+ this.hologram.addLines("${this.team.color}${this.shop.getDisplayName()}","${ChatColor.GRAY}Respawns in ${ChatColor.YELLOW}${TimeUtils.formatIntoHHMMSS(this.remaining.get())}")
+ FrozenHologramHandler.getCache().add(this.hologram)
+ }
+
+ override fun run() {
+
+ if (this.remaining.get() <= 0) {
+ this.hologram.destroy()
+
+ FrozenHologramHandler.getCache().remove(this.hologram)
+ Bunkers.instance.shopHandler.spawnVillager(this.location,this.shop,this.team)
+
+ this.cancel()
+ return
+ }
+
+ this.hologram.setLine(1,"${ChatColor.GRAY}Respawns in ${ChatColor.YELLOW}${TimeUtils.formatIntoHHMMSS(this.remaining.decrementAndGet())}")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/StatisticHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/StatisticHandler.kt
new file mode 100644
index 0000000..a46ab87
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/StatisticHandler.kt
@@ -0,0 +1,155 @@
+package cc.fyre.bunkers.statistic
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.statistic.command.BalanceCommand
+import cc.fyre.bunkers.statistic.command.PayCommand
+import cc.fyre.bunkers.statistic.listener.StatisticListener
+import cc.fyre.bunkers.statistic.service.BalanceService
+import cc.fyre.engine.profile.data.type.BunkersProfile
+import net.frozenorb.qlib.command.FrozenCommandHandler
+import org.bukkit.Material
+import java.util.*
+import java.util.concurrent.TimeUnit
+import kotlin.collections.HashMap
+
+/**
+ * @project bunkers
+ *
+ * @date 03/08/2020
+ * @author xanderume@gmail.com
+ */
+class StatisticHandler(private val instance: Bunkers) {
+
+ val kills = HashMap()
+ val deaths = HashMap()
+ val balance = HashMap()
+ val killStreak = HashMap()
+
+ val oresMined = HashMap>()
+
+ val playTime = HashMap()
+ val playTimeJoined = HashMap()
+
+ val playTimeClass = HashMap>()
+ val playTimeClassEquipped = HashMap>()
+
+ init {
+ FrozenCommandHandler.registerClass(PayCommand::class.java)
+ FrozenCommandHandler.registerClass(BalanceCommand::class.java)
+
+ this.instance.server.pluginManager.registerEvents(StatisticListener(this.instance),this.instance)
+
+ this.instance.server.scheduler.runTaskTimer(this.instance,BalanceService(this.instance),60L,60L)
+ }
+
+ fun getKills(uuid: UUID):Int {
+ return this.kills[uuid] ?: 0
+ }
+
+ fun addKills(uuid: UUID,amount: Int) {
+ this.kills.putIfAbsent(uuid,0)
+ this.kills[uuid] = this.kills[uuid]!! + amount
+ }
+
+ fun getDeaths(uuid: UUID):Int {
+ return this.deaths[uuid] ?: 0
+ }
+
+ fun addDeaths(uuid: UUID,amount: Int) {
+ this.deaths.putIfAbsent(uuid,0)
+ this.deaths[uuid] = this.deaths[uuid]!! + amount
+ }
+
+ fun getBalance(uuid: UUID):Int {
+ return this.balance[uuid] ?: STARTER_BALANCE
+ }
+
+ fun addBalance(uuid: UUID,amount: Int) {
+ this.balance.putIfAbsent(uuid,STARTER_BALANCE)
+ this.balance[uuid] = this.balance[uuid]!! + amount
+ }
+
+ fun getOresMined(uuid: UUID):Int {
+
+ if (!this.oresMined.containsKey(uuid)) {
+ return 0
+ }
+
+ return this.oresMined[uuid]!!.entries.sumBy{it.value}
+ }
+
+ fun getOresMined(uuid: UUID,ore: BunkersProfile.Ore):Int {
+
+ if (!this.oresMined.containsKey(uuid)) {
+ return 0
+ }
+
+ return this.oresMined[uuid]!![ore] ?: 0
+ }
+
+ fun addOresMined(uuid: UUID,material: Material) {
+ this.oresMined.putIfAbsent(uuid,EnumMap(BunkersProfile.Ore::class.java))
+
+ val ore = when(material) {
+ Material.COAL_ORE -> BunkersProfile.Ore.COAL
+ Material.IRON_ORE -> BunkersProfile.Ore.IRON
+ Material.GOLD_ORE -> BunkersProfile.Ore.GOLD
+ Material.DIAMOND_ORE -> BunkersProfile.Ore.DIAMOND
+ Material.EMERALD_ORE -> BunkersProfile.Ore.EMERALD
+ else -> null
+ } ?: return
+
+ this.oresMined[uuid]!![ore] = (this.oresMined[uuid]!![ore] ?: 0) + 1
+ }
+
+ fun getPlayTime(uuid: UUID):Long {
+ return this.playTime[uuid] ?: 0L
+ }
+
+ fun getPlayTime(uuid: UUID,type: BunkersProfile.PvPClass):Long {
+
+ if (!this.playTimeClass.containsKey(uuid)) {
+ return 0L
+ }
+
+ return this.playTimeClass[uuid]!![type] ?: 0L
+ }
+
+ fun recalculatePlayTime(uuid: UUID) {
+
+ if (!this.playTimeJoined.containsKey(uuid)) {
+ return
+ }
+
+ this.playTime[uuid] = (this.playTime[uuid] ?: 0) + (System.currentTimeMillis() - this.playTimeJoined[uuid]!!)
+ }
+
+ fun recalculatePlayTime(uuid: UUID,pvpClass: BunkersProfile.PvPClass) {
+
+ if (!this.playTimeClassEquipped.containsKey(uuid)) {
+ return
+ }
+
+ this.playTimeClass.putIfAbsent(uuid,EnumMap(BunkersProfile.PvPClass::class.java))
+ this.playTimeClass[uuid]!![pvpClass] = (this.playTimeClass[uuid]!![pvpClass] ?: 0) + (System.currentTimeMillis() - (this.playTimeClassEquipped[uuid]!![pvpClass] ?: 0L))
+ }
+
+ fun getKillStreak(uuid: UUID):Int {
+ this.killStreak.putIfAbsent(uuid,0)
+ return this.killStreak[uuid]!!
+ }
+
+ fun addKillStreak(uuid: UUID,amount: Int) {
+ this.killStreak.putIfAbsent(uuid,0)
+ this.killStreak[uuid] = this.killStreak[uuid]!! + amount
+ }
+
+ companion object {
+
+ const val STARTER_BALANCE = 150
+ const val BALANCE_PER_KILL = 200
+
+ val PAY_TIME = TimeUnit.MINUTES.toMillis(2L)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/command/BalanceCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/command/BalanceCommand.kt
new file mode 100644
index 0000000..461af2e
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/command/BalanceCommand.kt
@@ -0,0 +1,50 @@
+package cc.fyre.bunkers.statistic.command
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import net.frozenorb.qlib.util.UUIDUtils
+import org.bukkit.Bukkit
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import java.util.*
+
+/**
+ * @project bunkers
+ *
+ * @date 03/02/2021
+ * @author xanderume@gmail.com
+ */
+object BalanceCommand {
+
+ @JvmStatic
+ @Command(names = ["balance","bal","money"],permission = "")
+ fun execute(player: Player,@Param(name = "player",defaultValue = "self")uuid: UUID) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ Bukkit.getServer().scheduler.runTaskAsynchronously(Bunkers.instance) {
+
+ if (!team.isMember(uuid)) {
+ player.sendMessage("${ChatColor.RED}${UUIDUtils.name(uuid)} is not on your team.")
+ return@runTaskAsynchronously
+ }
+
+ val balance = Bunkers.instance.statisticHandler.getBalance(uuid)
+
+ if (player.uniqueId == uuid) {
+ player.sendMessage("${ChatColor.GREEN}Balance: ${ChatColor.RED}$$balance")
+ return@runTaskAsynchronously
+ }
+
+ player.sendMessage("${ChatColor.GREEN}${UUIDUtils.name(uuid)} Balance: ${ChatColor.RED}$$balance")
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/command/PayCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/command/PayCommand.kt
new file mode 100644
index 0000000..451f298
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/command/PayCommand.kt
@@ -0,0 +1,75 @@
+package cc.fyre.bunkers.statistic.command
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.statistic.StatisticHandler
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.engine.util.FormatUtil
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import net.frozenorb.qlib.util.UUIDUtils
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import java.util.*
+import java.util.concurrent.TimeUnit
+
+/**
+ * @project bunkers
+ *
+ * @date 19/08/2020
+ * @author xanderume@gmail.com
+ */
+object PayCommand {
+
+ @JvmStatic
+ @Command(names = ["pay"],permission = "")
+ fun execute(player: Player,@Param(name = "player")uuid: UUID,@Param(name = "amount")amount: Int) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ if (amount <= 0) {
+ player.sendMessage("${ChatColor.RED}Amount must be positive.")
+ return
+ }
+
+ if (amount > Bunkers.instance.statisticHandler.getBalance(player.uniqueId)) {
+ player.sendMessage("${ChatColor.RED}You only have $${Bunkers.instance.statisticHandler.getBalance(player.uniqueId)}.")
+ return
+ }
+
+ if (player.uniqueId == uuid) {
+ player.sendMessage("${ChatColor.RED}You cannot pay yourself!")
+ return
+ }
+
+ if (!team.isMember(uuid)) {
+ player.sendMessage("${ChatColor.RED}${UUIDUtils.name(uuid)} is not on your team.")
+ return
+ }
+
+ if (GameEngine.instance.gameHandler.getState() != GameServer.State.IN_PROGRESS) {
+ player.sendMessage("${ChatColor.RED}Please wait for the game to start.")
+ return
+ }
+
+ val time = GameEngine.instance.gameHandler.getGameTime()
+
+ if (time <= StatisticHandler.PAY_TIME) {
+ player.sendMessage("${ChatColor.RED}You can only pay teammates ${ChatColor.WHITE}${FormatUtil.formatIntoDetailedString(StatisticHandler.PAY_TIME)}${ChatColor.RED} into the game, please wait another ${ChatColor.RED}${ChatColor.BOLD}${FormatUtil.formatIntoDetailedString(TimeUnit.MINUTES.toMillis(2L) - time)}${ChatColor.RED}!")
+ return
+ }
+
+ Bunkers.instance.statisticHandler.addBalance(uuid,amount)
+ Bunkers.instance.statisticHandler.addBalance(player.uniqueId,-amount)
+
+ player.sendMessage("${ChatColor.YELLOW}You have sent ${ChatColor.LIGHT_PURPLE}$${amount}${ChatColor.YELLOW} to ${ChatColor.LIGHT_PURPLE}${UUIDUtils.name(uuid)}${ChatColor.YELLOW}.")
+
+ Bunkers.instance.server.getPlayer(uuid)?.sendMessage("${ChatColor.LIGHT_PURPLE}${player.name}${ChatColor.YELLOW} has sent you $${ChatColor.LIGHT_PURPLE}${amount}${ChatColor.YELLOW}.")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/listener/StatisticListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/listener/StatisticListener.kt
new file mode 100644
index 0000000..e2d89b0
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/listener/StatisticListener.kt
@@ -0,0 +1,40 @@
+package cc.fyre.bunkers.statistic.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.engine.GameEngine
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerQuitEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 25/12/2020
+ * @author xanderume@gmail.com
+ */
+class StatisticListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.player)) {
+ return
+ }
+
+ this.instance.statisticHandler.playTimeJoined[event.player.uniqueId] = System.currentTimeMillis()
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.player)) {
+ return
+ }
+
+ this.instance.statisticHandler.recalculatePlayTime(event.player.uniqueId)
+ this.instance.statisticHandler.playTimeJoined.remove(event.player.uniqueId)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/service/BalanceService.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/service/BalanceService.kt
new file mode 100644
index 0000000..569109d
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/statistic/service/BalanceService.kt
@@ -0,0 +1,25 @@
+package cc.fyre.bunkers.statistic.service
+
+import cc.fyre.bunkers.Bunkers
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+
+/**
+ * @project bunkers
+ *
+ * @date 05/08/2020
+ * @author xanderume@gmail.com
+ */
+class BalanceService(private val instance: Bunkers) : Runnable {
+
+ override fun run() {
+
+ if (GameEngine.instance.gameHandler.getState() != GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ GameEngine.instance.gameHandler.getPlayers().forEach{this.instance.statisticHandler.addBalance(it.uniqueId,3)}
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/SupplyHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/SupplyHandler.kt
new file mode 100644
index 0000000..df1a2c4
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/SupplyHandler.kt
@@ -0,0 +1,69 @@
+package cc.fyre.bunkers.supply
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.supply.data.Supply
+
+import cc.fyre.bunkers.supply.listener.SupplyListener
+import com.google.common.collect.HashBasedTable
+import org.bukkit.Location
+import org.bukkit.Material
+import org.bukkit.block.Block
+import org.bukkit.inventory.ItemStack
+import org.bukkit.scheduler.BukkitRunnable
+import org.bukkit.scheduler.BukkitTask
+import java.util.*
+import kotlin.collections.HashSet
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class SupplyHandler(private val instance: Bunkers) {
+
+ val cache = HashBasedTable.create()
+
+ private val supplies = HashSet()
+
+ init {
+ this.supplies.add(Supply(Material.CROPS,ItemStack(Material.COOKIE),Material.AIR,2500L))
+ this.supplies.add(Supply(Material.POTATO,ItemStack(Material.BAKED_POTATO),Material.AIR,2500L))
+ this.supplies.add(Supply(Material.CARROT,ItemStack(Material.GOLDEN_CARROT),Material.AIR,2500L))
+
+ this.supplies.add(Supply(Material.COAL_ORE,ItemStack(Material.COAL),Material.COBBLESTONE,10_000L))
+ this.supplies.add(Supply(Material.IRON_ORE,ItemStack(Material.IRON_INGOT),Material.COBBLESTONE,10_000L))
+ this.supplies.add(Supply(Material.GOLD_ORE,ItemStack(Material.GOLD_INGOT),Material.COBBLESTONE,20_000L))
+ this.supplies.add(Supply(Material.DIAMOND_ORE,ItemStack(Material.DIAMOND),Material.COBBLESTONE,20_000L))
+ this.supplies.add(Supply(Material.EMERALD_ORE,ItemStack(Material.EMERALD),Material.COBBLESTONE,30_000L))
+
+ this.instance.server.pluginManager.registerEvents(SupplyListener(this.instance),this.instance)
+ }
+
+ fun dispose() {
+ this.cache.values().forEach{it.cancel()}
+ }
+
+ fun isBeingSupplied(location: Location):Boolean {
+ return this.cache.containsRow(location)
+ }
+
+ fun getSupplyByOrigin(origin: Material):Supply? {
+ return this.supplies.firstOrNull{it.origin == origin}
+ }
+
+ fun addSupplyToService(block: Block,entry: Supply) {
+
+ val task = object : BukkitRunnable() {
+
+ override fun run() {
+ this@SupplyHandler.cache.remove(block.location,entry)
+ block.type = entry.origin
+ }
+
+ }.runTaskLater(this.instance,entry.duration / 50)
+
+ this.cache.put(block.location,entry,task)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/data/Supply.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/data/Supply.kt
new file mode 100644
index 0000000..d03f1c9
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/data/Supply.kt
@@ -0,0 +1,16 @@
+package cc.fyre.bunkers.supply.data
+
+import org.bukkit.Material
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class Supply(val origin: Material,val reward: ItemStack,val replace: Material,val duration: Long) {
+
+ fun isFarm() = false
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/listener/SupplyListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/listener/SupplyListener.kt
new file mode 100644
index 0000000..1b2f4aa
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/supply/listener/SupplyListener.kt
@@ -0,0 +1,41 @@
+package cc.fyre.bunkers.supply.listener
+
+import cc.fyre.bunkers.Bunkers
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.BlockBreakEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class SupplyListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onBlockBreak(event: BlockBreakEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (this.instance.supplyHandler.isBeingSupplied(event.block.location)) {
+ event.isCancelled = true
+ return
+ }
+
+ val supply = this.instance.supplyHandler.getSupplyByOrigin(event.block.type) ?: return
+
+ this.instance.statisticHandler.addOresMined(event.player.uniqueId,event.block.type)
+
+ event.block.type = supply.replace
+
+ event.isCancelled = true
+ event.player.inventory.addItem(supply.reward)
+
+ this.instance.supplyHandler.addSupplyToService(event.block,supply)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/TeamHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/TeamHandler.kt
new file mode 100644
index 0000000..aebedff
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/TeamHandler.kt
@@ -0,0 +1,158 @@
+package cc.fyre.bunkers.team
+/**
+ * @project bunkers
+ *
+ * @date 30/07/2020
+ * @author xanderume@gmail.com
+ */
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.command.*
+import cc.fyre.bunkers.team.command.parameter.TeamParameterProvider
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.bunkers.team.listener.*
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.map.data.Map
+import com.mongodb.client.model.Filters
+import com.mongodb.client.model.UpdateOptions
+import com.mongodb.client.result.UpdateResult
+import net.frozenorb.qlib.command.FrozenCommandHandler
+import net.frozenorb.qlib.qLib
+import net.frozenorb.qlib.util.UUIDUtils
+import org.apache.commons.lang.StringUtils
+import org.bson.Document
+import org.bukkit.ChatColor
+import org.bukkit.Location
+
+import java.util.*
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+import kotlin.collections.HashMap
+
+//TODO: team loading & saving is kinda ass
+class TeamHandler(private val instance: Bunkers) {
+
+ val cache = HashMap()
+ val collection = GameEngine.instance.api.databaseHandler.mongoDB.getCollection("teams")
+
+ init {
+ Team.Type.values().forEach{this.cache[it] = Team(it)}
+
+ this.instance.server.pluginManager.registerEvents(TeamListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(TeamChatListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(TeamChestListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(TeamRallyListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(TeamProtectionListener(this.instance),this.instance)
+
+ FrozenCommandHandler.registerClass(TeamHQCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamInfoCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamChatCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamSetHQCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamSetShopCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamClaimCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamFocusCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamRallyCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamLocationCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamVoteKickCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamSetDTRCommand::class.java)
+ FrozenCommandHandler.registerClass(TeamSetHologramCommand::class.java)
+ FrozenCommandHandler.registerParameterType(Team::class.java,TeamParameterProvider())
+ }
+
+ fun findById(uuid: UUID):Team? {
+ return this.cache.values.firstOrNull{it.members.contains(uuid)}
+ }
+
+ fun findByLocation(location: Location):Team {
+ return this.cache.values.firstOrNull{it.claim != null && it.claim!!.contains(location)} ?: (this.cache[Team.Type.WAR_ZONE] ?: Team(Team.Type.WAR_ZONE))
+ }
+
+ fun findSystemTeams():MutableSet {
+ return this.cache.values.filter{it.type.isSystem()}.toMutableSet()
+ }
+
+ fun findPlayerTeams():MutableSet {
+ return this.cache.values.filter{!it.type.isSystem()}.toMutableSet()
+ }
+
+ fun loadTeamDataSync(map: Map) {
+
+ val document = this.collection.find(Filters.eq("_id",map.id)).firstOrNull() ?: return
+
+ Team.Type.values().filter{document.containsKey(it.name)}.forEach{
+ val team = qLib.GSON.fromJson(Document.parse(document.getString(it.name)).toJson(GameEngineAPI.JSON_WRITER_SETTINGS),Team::class.java)
+
+ val cachedTeam = this.cache[it]!!
+
+ cachedTeam.hq = team.hq
+ cachedTeam.claim = team.claim
+ cachedTeam.shops.putAll(team.shops)
+ cachedTeam.holograms.addAll(team.holograms)
+ }
+
+ }
+
+ fun saveTeamData(team: Team,map: Map):UpdateResult {
+
+ val document = this.collection.find(Filters.eq("_id",map.id)).firstOrNull() ?: Document("_id",map.id)
+
+ document.append(team.type.name,qLib.GSON.toJson(team))
+
+ return this.collection.updateOne(Document("_id",map.id),Document("\$set",document), UpdateOptions().upsert(true))
+ }
+
+ fun addToTeam(uuid: UUID):Team? {
+
+ val team = Bunkers.instance.teamHandler.findPlayerTeams().filter{!it.isFull()}.maxByOrNull{it.getAvailableSlots()}
+
+ if (team == null) {
+
+ val player = this.instance.server.getPlayer(uuid)
+
+ GameEngine.instance.gameHandler.removePlayer(player)
+ player.kickPlayer("${ChatColor.RED}We we're unable find you a team!")
+ return null
+ }
+
+ this.instance.logger.info("Added ${UUIDUtils.name(uuid)} to ${team.getDisplayName()} team.")
+
+ team.members.add(uuid)
+ return team
+ }
+
+ fun addToTeam(players: ArrayList) {
+
+ val team = this.findPlayerTeams().find{it.getAvailableSlots() >= players.size} ?: this.findPlayerTeams().maxByOrNull{it.getAvailableSlots()}
+
+ if (team == null) {
+ players.forEach{this.addToTeam(it)}
+ return
+ }
+
+ players.filter{Bunkers.instance.teamHandler.findById(it) == null}.forEach{
+
+ if (team.isFull()) {
+ this.addToTeam(it)
+ this.instance.logger.info("Team ${team.getDisplayName()} was full, moved ${UUIDUtils.name(it)} to another team.")
+ } else {
+ team.members.add(it)
+ }
+
+ }
+
+ this.instance.logger.info("Added ${StringUtils.join(team.members.map{UUIDUtils.name(it)}.toTypedArray(),", ")} to ${team.getDisplayName()} team.")
+ }
+
+ companion object {
+
+ const val CHEST_PRICE = 500
+ const val PLAYERS_PER_TEAM = 5
+
+ val RALLY_TIME = TimeUnit.MINUTES.toSeconds(5L).toInt()
+ val RAIDABLE_TIME = TimeUnit.HOURS.toSeconds(1L).toInt()
+ val RAIDABLE_BROADCASTS = mutableListOf(TimeUnit.MINUTES.toSeconds(30L).toInt(),TimeUnit.MINUTES.toSeconds(40L).toInt(),TimeUnit.MINUTES.toSeconds(50L).toInt(),TimeUnit.MINUTES.toSeconds(55L).toInt())
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamChatCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamChatCommand.kt
new file mode 100644
index 0000000..5db19ee
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamChatCommand.kt
@@ -0,0 +1,65 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.command.Command
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 19/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamChatCommand {
+
+ @JvmStatic
+ @Command(names = ["team chat","t chat","team c","t c"],permission = "")
+ fun execute(player: Player) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ team.chat[player.uniqueId] = !(team.chat[player.uniqueId] ?: false)
+
+ player.sendMessage("${ChatColor.YELLOW}You are now talking in ${if (team.chat[player.uniqueId]!!) "${ChatColor.BLUE}team" else "${ChatColor.RED}public"}${ChatColor.YELLOW} chat.")
+ }
+
+ @JvmStatic
+ @Command(names = ["publicchat","pc"], permission = "")
+ fun publicChat(player: Player) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ team.chat[player.uniqueId] = false
+
+ player.sendMessage("${ChatColor.YELLOW}You are now talking in ${ChatColor.RED}public${ChatColor.YELLOW} chat.")
+ }
+
+ @JvmStatic
+ @Command(names = ["teamchat","tc"], permission = "")
+ fun teamChat(player: Player) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ team.chat[player.uniqueId] = true
+
+ player.sendMessage("${ChatColor.YELLOW}You are now talking in ${ChatColor.BLUE}team${ChatColor.YELLOW} chat.")
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamClaimCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamClaimCommand.kt
new file mode 100644
index 0000000..434e59b
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamClaimCommand.kt
@@ -0,0 +1,27 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.engine.map.data.Map
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 03/08/2020
+ * @author xanderume@gmail.com
+ */
+object
+TeamClaimCommand {
+
+ @JvmStatic
+ @Command(names = ["team claim","t claim","faction claim","fac claim","f claim"],hidden = true,permission = "bunkers.command.team.claim")
+ fun execute(player: Player, @Param(name = "team")team: Team, @Param(name = "map")map: Map) {
+ Bunkers.instance.claimHandler.startSelection(player,team,map,0)
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamFocusCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamFocusCommand.kt
new file mode 100644
index 0000000..78f74cb
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamFocusCommand.kt
@@ -0,0 +1,57 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import net.frozenorb.qlib.nametag.FrozenNametagHandler
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 20/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamFocusCommand {
+
+ @JvmStatic
+ @Command(names = ["team focus","t focus","faction focus","fac focus","f focus","focus"], permission = "")
+ fun execute(player: Player,@Param(name = "player")target: Player) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ if (team.isMember(target)) {
+ player.sendMessage("${ChatColor.RED}${target.name} is on your team.")
+ return
+ }
+
+ if (team.focus != null && team.focus == target.uniqueId) {
+ team.focus = null
+ team.sendMessage("${ChatColor.LIGHT_PURPLE}${player.name}${ChatColor.YELLOW} has un-focused ${ChatColor.LIGHT_PURPLE}${target.name}${ChatColor.YELLOW}.")
+ team.findOnlineMembers().forEach{FrozenNametagHandler.reloadPlayer(it,target)}
+ return
+ }
+
+ val members = team.findOnlineMembers()
+
+ if (team.focus != null) {
+
+ Bunkers.instance.server.getPlayer(team.focus)?.also{
+ members.forEach{member -> FrozenNametagHandler.reloadPlayer(it,member)}
+ }
+
+ }
+
+ team.focus = target.uniqueId
+ team.sendMessage("${ChatColor.LIGHT_PURPLE}${player.name}${ChatColor.YELLOW} has focused ${ChatColor.LIGHT_PURPLE}${target.name}${ChatColor.YELLOW}.")
+
+ members.forEach{FrozenNametagHandler.reloadPlayer(it,target)}
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamHQCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamHQCommand.kt
new file mode 100644
index 0000000..79ddfb9
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamHQCommand.kt
@@ -0,0 +1,61 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.command.Command
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 03/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamHQCommand {
+
+ @JvmStatic
+ @Command(names = [
+ "faction hq","fac hq","f hq","team hq","t hq","hq","faction home","fac home","f home","team home","t home","home",
+ "faction stuck","fac stuck","f stuck","team stuck","t stuck","stuck","faction stuck","fac stuck","f stuck","team stuck","t stuck","stuck"
+ ],permission = "")
+ fun execute(player: Player) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ if (team.hq == null) {
+ player.sendMessage("${ChatColor.RED}Your team's HQ has not been setup, please contact an administrator.")
+ return
+ }
+
+ if (GameEngine.instance.gameHandler.getState() != GameServer.State.IN_PROGRESS) {
+ player.sendMessage("${ChatColor.RED}You cannot warp to your team's HQ right now.")
+ return
+ }
+
+ if (Bunkers.instance.timerHandler.hasTimer(player.uniqueId,TimerType.HOME)) {
+ player.sendMessage("${ChatColor.RED}You are already warping to your team's HQ!")
+ return
+ }
+
+ if (Bunkers.instance.timerHandler.hasTimer(player.uniqueId,TimerType.RESPAWN)) {
+ player.sendMessage("${ChatColor.RED}You cannot warp to your team's HQ whilst respawning!")
+ return
+ }
+
+ val teamByLocation = Bunkers.instance.teamHandler.findByLocation(player.location)
+
+ val duration = if (teamByLocation.type == team.type || teamByLocation.type == Team.Type.WAR_ZONE || teamByLocation.type == Team.Type.KOTH || team.isRaidable()) 10_000L else 30_000L
+
+ Bunkers.instance.timerHandler.addTimer(player.uniqueId,TimerType.HOME,duration)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamInfoCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamInfoCommand.kt
new file mode 100644
index 0000000..1553996
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamInfoCommand.kt
@@ -0,0 +1,22 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.team.data.Team
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import org.bukkit.command.CommandSender
+
+/**
+ * @project bunkers
+ *
+ * @date 08/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamInfoCommand {
+
+ @JvmStatic
+ @Command(names = ["faction info","fac info","f info","team info","t info","faction who","fac who","f who","team who","t who","faction show","fac show","f show","team show","t show","faction i","fac i","f i","team i","t i"], permission = "")
+ fun execute(sender: CommandSender,@Param(name = "team",defaultValue = "self")team: Team) {
+ team.sendInfo(sender)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamLocationCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamLocationCommand.kt
new file mode 100644
index 0000000..20b05b0
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamLocationCommand.kt
@@ -0,0 +1,31 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 20/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamLocationCommand {
+
+ @JvmStatic
+ @Command(names = ["tl"], permission = "")
+ fun execute(player: Player,@Param(name = "player",defaultValue = "self")target: Player) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ team.sendMessage("${ChatColor.DARK_AQUA}(Team) ${target.name}: ${ChatColor.YELLOW}[${target.location.blockX}, ${target.location.blockY}, ${target.location.blockZ}] ${ChatColor.DARK_AQUA}- ${Bunkers.instance.teamHandler.findByLocation(target.location).getDisplayName()}")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamRallyCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamRallyCommand.kt
new file mode 100644
index 0000000..1b5749d
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamRallyCommand.kt
@@ -0,0 +1,63 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.team.data.Team
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.util.FormatUtil
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import org.bukkit.scheduler.BukkitRunnable
+
+/**
+ * @project bunkers
+ *
+ * @date 22/12/2020
+ * @author xanderume@gmail.com
+ */
+object TeamRallyCommand {
+
+
+ @JvmStatic
+ @Command(names = ["faction rally","fac rally","f rally","team rally","t rally","rally"], permission = "")
+ fun execute(player: Player,@Param(name = "team",defaultValue = "self")team: Team) {
+
+ if (!GameEngine.instance.gameHandler.isPlaying(player)) {
+ player.sendMessage("${ChatColor.RED}You cannot do this as a spectator!")
+ return
+ }
+
+ if (team.rally != null) {
+ //TODO team.findOnlineMembers().forEach{LunarClientAPI.instance.packetHandler.sendPacket(it,WayPointRemovePacket("Rally",team.rally!!.world))}
+ }
+
+ if (team.rallyTask != null) {
+ team.rallyTask!!.cancel()
+ }
+
+ team.rally = player.location.clone().add(0.5,0.0,0.5)
+ team.rallyTask = object : BukkitRunnable() {
+
+ override fun run() {
+
+ if (team.rally == null) {
+ return
+ }
+
+ //TODO team.findOnlineMembers().forEach{LunarClientAPI.instance.packetHandler.sendPacket(it,WayPointRemovePacket("Rally",team.rally!!.world))}
+ team.rally = null
+ team.rallyTask = null
+ team.sendMessage("${ChatColor.DARK_AQUA}The team rally has expired!")
+ }
+
+ }.runTaskLater(Bunkers.instance,TeamHandler.RALLY_TIME * 20L)
+
+ //TODO val packet = WayPointAddPacket("Rally",team.rally!!.world,team.rally!!.blockX,team.rally!!.blockY,team.rally!!.blockZ,Color.ORANGE,forced = true,visible = true)
+
+ team.sendMessage("${ChatColor.DARK_AQUA}${player.name} has updated the team's rally point, this will last for ${FormatUtil.formatIntoDetailedString(TeamHandler.RALLY_TIME * 1000L)}!")
+ //TODO team.findOnlineMembers().forEach{LunarClientAPI.instance.packetHandler.sendPacket(it,packet)}
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetDTRCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetDTRCommand.kt
new file mode 100644
index 0000000..36d893a
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetDTRCommand.kt
@@ -0,0 +1,29 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.team.data.Team
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import kotlin.math.min
+
+/**
+ * @project bunkers
+ *
+ * @date 23/12/2020
+ * @author xanderume@gmail.com
+ */
+object
+TeamSetDTRCommand {
+
+ @JvmStatic
+ @Command(names = ["team setdtr","t setdtr","faction setdtr","fac setdtr","f setdtr","setdtr"],hidden = true,permission = "bunkers.command.team.setdtr")
+ fun execute(sender: CommandSender, @Param(name = "team")team: Team, @Param(name = "dtr")dtr: Double) {
+ team.dtr = min(dtr,TeamHandler.PLAYERS_PER_TEAM + 1.0)
+
+ sender.sendMessage("${ChatColor.YELLOW}You have set ${team.getDisplayName()}${ChatColor.YELLOW}'s DTR to: ${ChatColor.LIGHT_PURPLE}${team.getDTR()}")
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetHQCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetHQCommand.kt
new file mode 100644
index 0000000..b920fab
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetHQCommand.kt
@@ -0,0 +1,33 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import cc.fyre.engine.map.data.Map
+import org.bukkit.ChatColor
+
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 03/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamSetHQCommand {
+
+ @JvmStatic
+ @Command(names = ["team sethq","t sethq","faction sethq","fac sethq","f sethq"],async = true,permission = "bunkers.command.team.sethq")
+ fun execute(player: Player,@Param(name = "team")team: Team,@Param(name = "map",defaultValue = "current")map: Map) {
+ team.hq = player.location
+
+ if (!Bunkers.instance.teamHandler.saveTeamData(team,map).wasAcknowledged()) {
+ player.sendMessage("${ChatColor.RED}Failed to update team data..")
+ return
+ }
+
+ player.sendMessage("${ChatColor.YELLOW}Updated ${team.getDisplayName()}${ChatColor.YELLOW}'s HQ on map ${ChatColor.LIGHT_PURPLE}${map.id}${ChatColor.YELLOW}.")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetHologramCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetHologramCommand.kt
new file mode 100644
index 0000000..6a618c0
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetHologramCommand.kt
@@ -0,0 +1,33 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+
+import cc.fyre.engine.map.data.Map
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamSetHologramCommand {
+
+ @JvmStatic
+ @Command(names = ["team sethologram","t sethologram","faction sethologram","fac sethologram","f sethologram"],async = true,permission = "bunkers.command.team.sethologram")
+ fun execute(player: Player, @Param(name = "team")team: Team, @Param(name = "map",defaultValue = "current")map: Map) {
+ team.holograms.add(player.location.clone())
+
+ if (!Bunkers.instance.teamHandler.saveTeamData(team,map).wasAcknowledged()) {
+ player.sendMessage("${ChatColor.RED}Failed to update team data..")
+ return
+ }
+
+ player.sendMessage("${ChatColor.YELLOW}Added Hologram for ${team.getDisplayName()}${ChatColor.YELLOW}'s team on map ${ChatColor.LIGHT_PURPLE}${map.id}${ChatColor.YELLOW}.")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetShopCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetShopCommand.kt
new file mode 100644
index 0000000..b111221
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamSetShopCommand.kt
@@ -0,0 +1,34 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.shop.data.ShopType
+import cc.fyre.bunkers.team.data.Team
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import cc.fyre.engine.map.data.Map
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.entity.Player
+
+/**
+ * @project bunkers
+ *
+ * @date 04/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamSetShopCommand {
+
+ @JvmStatic
+ @Command(names = ["team setshop","t setshop","faction setshop","fac setshop","f setshop"],async = true,permission = "bunkers.command.team.setshop")
+ fun execute(player: Player, @Param(name = "shop")type: ShopType, @Param(name = "team")team: Team, @Param(name = "map",defaultValue = "current")map: Map) {
+ team.shops[type] = Location(Bunkers.instance.server.getWorld(map.id),player.location.x,player.location.y,player.location.z,player.location.yaw,player.location.pitch)
+
+ if (!Bunkers.instance.teamHandler.saveTeamData(team,map).wasAcknowledged()) {
+ player.sendMessage("${ChatColor.RED}Failed to update team data..")
+ return
+ }
+
+ player.sendMessage("${ChatColor.YELLOW}Updated ${team.getDisplayName()}${ChatColor.YELLOW}'s ${type.name} shop on map ${ChatColor.LIGHT_PURPLE}${map.id}${ChatColor.YELLOW}.")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamVoteKickCommand.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamVoteKickCommand.kt
new file mode 100644
index 0000000..5d14a72
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/TeamVoteKickCommand.kt
@@ -0,0 +1,103 @@
+package cc.fyre.bunkers.team.command
+
+import cc.fyre.bunkers.Bunkers
+import net.frozenorb.qlib.command.Command
+import net.frozenorb.qlib.command.Param
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import mkremins.fanciful.FancyMessage
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import kotlin.collections.ArrayList
+
+/**
+ * @project bunkers
+ *
+ * @date 24/08/2020
+ * @author xanderume@gmail.com
+ */
+object TeamVoteKickCommand {
+
+ @JvmStatic
+ @Command(names = ["faction votekick","fac votekick","f votekick","team votekick","t votekick","votekick","faction votekick","fac votekick","f votekick","team votekick","t votekick","votekick"], permission = "")
+ fun execute(player: Player,@Param(name = "player")target: Player) {
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+ if (GameEngine.instance.gameHandler.getState().isBeforeOrCurrently(GameServer.State.COUNTDOWN)) {
+ player.sendMessage("${ChatColor.RED}You cannot votekick players as the game has not started yet!")
+ return
+ }
+
+ if (team.members.size <= 2) {
+ player.sendMessage("${ChatColor.RED}Members can no longer be vote kicked.")
+ return
+ }
+
+ if (!team.isMember(target)) {
+ player.sendMessage("${ChatColor.WHITE}${target.name} ${ChatColor.RED}is not on your team.")
+ return
+ }
+
+ if (GameEngine.instance.spectateHandler.isSpectating(player) || GameEngine.instance.disqualifieHandler.isDisqualified(player.uniqueId)) {
+ player.sendMessage("${ChatColor.RED}You can no longer vote kick a member.")
+ return
+ }
+
+ if (player.uniqueId == target.uniqueId) {
+ player.sendMessage("${ChatColor.RED}You cannot vote kick yourself.")
+ return
+ }
+
+ if (GameEngine.instance.spectateHandler.isSpectating(target) || GameEngine.instance.disqualifieHandler.isDisqualified(target.uniqueId)) {
+ player.sendMessage("${ChatColor.RED}You can no longer vote kick ${ChatColor.WHITE}${target.name}${ChatColor.RED}.")
+ return
+ }
+
+ team.votes.putIfAbsent(target.uniqueId,ArrayList())
+
+ if (team.votes[target.uniqueId]!!.contains(player.uniqueId)) {
+ player.sendMessage("${ChatColor.RED}You have already voted to kick ${target.name})}${ChatColor.RED}.")
+ return
+ }
+
+ val required = team.findAliveMembers().size - 1
+
+ team.votes[target.uniqueId]!!.add(player.uniqueId)
+
+ if (team.votes[target.uniqueId]!!.size >= required) {
+ team.dtr -= 1.0
+ team.votes[target.uniqueId]?.clear()
+
+ team.sendMessage("${ChatColor.RED}${target.name} has been voted off the team!",target.uniqueId)
+ target.sendMessage("${ChatColor.RED}You have been voted off the team.")
+
+ GameEngine.instance.gameHandler.removePlayer(target)
+ GameEngine.instance.spectateHandler.addSpectator(target)
+
+ Bunkers.instance.statisticHandler.recalculatePlayTime(target.uniqueId)
+ Bunkers.instance.statisticHandler.playTimeJoined.remove(target.uniqueId)
+
+ Bunkers.instance.server.onlinePlayers.filterNot{team.isMember(it)}.forEach{it.sendMessage("${team.getColor()}${target.name}${ChatColor.RED} has been voted off ${team.getDisplayName()}${ChatColor.RED}'s team!")}
+ return
+ }
+
+ team.members.mapNotNull{Bunkers.instance.server.getPlayer(it)}.forEach{
+
+ val message = FancyMessage("${team.getColor()}[Team] ${ChatColor.RED}${player.name}${ChatColor.YELLOW} has voted to kick ${ChatColor.RED}${target.name}${ChatColor.YELLOW}.")
+
+ if (it.uniqueId != target.uniqueId) {
+ message.tooltip("${ChatColor.GREEN}Click to vote kick ${player.name}.")
+ }
+
+ message.send(it)
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/parameter/TeamParameterProvider.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/parameter/TeamParameterProvider.kt
new file mode 100644
index 0000000..33681f0
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/command/parameter/TeamParameterProvider.kt
@@ -0,0 +1,70 @@
+package cc.fyre.bunkers.team.command.parameter
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+import net.frozenorb.qlib.command.ParameterType
+import net.frozenorb.qlib.util.UUIDUtils
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import org.bukkit.entity.Player
+import java.lang.Exception
+import java.util.*
+import kotlin.collections.ArrayList
+
+/**
+ * @project bunkers
+ *
+ * @date 03/08/2020
+ * @author xanderume@gmail.com
+ */
+class TeamParameterProvider : ParameterType {
+
+ override fun transform(sender: CommandSender,source: String): Team? {
+
+ if (sender is Player && source.equals("self",true)) {
+
+ val team = Bunkers.instance.teamHandler.findById(sender.uniqueId)
+
+ if (team == null) {
+ sender.sendMessage("${ChatColor.RED}You are not on a team!")
+ return null
+ }
+
+ return team
+ }
+
+ var type: Team.Type? = null
+
+ try {
+ type = Team.Type.valueOf(source.toUpperCase())
+ } catch (ex: Exception) {}
+
+ if (type != null) {
+ return Bunkers.instance.teamHandler.cache[type]!!
+ }
+
+ var id: UUID?
+
+ val player = Bunkers.instance.server.getPlayer(source)
+
+ if (player != null) {
+ id = player.uniqueId
+ }
+
+ id = UUIDUtils.uuid(source)
+
+ val team: Team? = if (id == null) null else Bunkers.instance.teamHandler.findById(id)
+
+ if (team == null) {
+ sender.sendMessage("${ChatColor.RED}No team or member with the name $source found.")
+ return null
+ }
+
+ return team
+ }
+
+ override fun tabComplete(player: Player, flags: Set, source: String): List {
+ return ArrayList()
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/data/Team.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/data/Team.kt
new file mode 100644
index 0000000..1454c69
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/data/Team.kt
@@ -0,0 +1,237 @@
+package cc.fyre.bunkers.team.data
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.claim.data.Claim
+import cc.fyre.bunkers.shop.data.ShopType
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.timer.data.TimerType
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import com.google.gson.annotations.Expose
+import mkremins.fanciful.FancyMessage
+import net.frozenorb.qlib.util.UUIDUtils
+import org.apache.commons.lang.StringUtils
+import org.apache.commons.lang.WordUtils
+import org.bukkit.ChatColor
+import org.bukkit.Color
+import org.bukkit.DyeColor
+import org.bukkit.Location
+import org.bukkit.block.Block
+import org.bukkit.block.Chest
+import org.bukkit.block.DoubleChest
+import org.bukkit.command.CommandSender
+import org.bukkit.entity.Player
+import org.bukkit.scheduler.BukkitTask
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+
+/**
+ * @project bunkers
+ *
+ * @date 30/07/2020
+ * @author xanderume@gmail.com
+ */
+class Team(val type: Type) {
+
+ var hq: Location? = null
+ var claim: Claim? = null
+ val shops = HashMap()
+ val holograms = HashSet()
+
+ var focus: UUID? = null
+
+ @Transient var dtr = TeamHandler.PLAYERS_PER_TEAM + 1.0
+ @Transient val chat = mutableMapOf()
+ @Transient var votes = mutableMapOf>()
+ @Transient val members = hashSetOf()
+
+ @Transient var chests = mutableMapOf()
+
+ @Transient var rally: Location? = null
+ @Transient var rallyTask: BukkitTask? = null
+
+ fun isFull():Boolean {
+ return this.members.size >= TeamHandler.PLAYERS_PER_TEAM
+ }
+
+ fun getAvailableSlots():Int {
+ return TeamHandler.PLAYERS_PER_TEAM - this.members.size
+ }
+
+ fun isMember(uuid: UUID):Boolean {
+ return this.members.contains(uuid)
+ }
+
+ fun isMember(player: Player):Boolean {
+ return this.members.contains(player.uniqueId)
+ }
+
+ fun isRaidable():Boolean {
+ return this.dtr <= 0.0
+ }
+
+ fun getDTR():String {
+ return DTR_FORMAT.format(this.dtr)
+ }
+
+ fun isFocused(player: Player):Boolean {
+ return this.focus != null && this.focus == player.uniqueId
+ }
+
+
+ fun getDTRDisplay():String {
+
+ var color = ChatColor.GREEN
+
+ when {
+ this.dtr <= 0.0 -> color = ChatColor.GOLD
+ this.dtr > 1.0 && this.dtr <= 2.0 -> color = ChatColor.YELLOW
+ this.dtr > 0.0 && this.dtr <= 1.0 -> color = ChatColor.RED
+ this.dtr <= (TeamHandler.PLAYERS_PER_TEAM + 1.0) / 2 -> color = ChatColor.DARK_RED
+ }
+
+ return "$color${this.getDTR()}"
+ }
+
+ fun getColor():ChatColor {
+ return this.type.color
+ }
+
+ fun getDisplayName():String {
+ return this.type.getDisplayName()
+ }
+
+ fun sendMessage(message: FancyMessage) {
+ this.members.mapNotNull{Bunkers.instance.server.getPlayer(it)}.forEach{message.send(it)}
+ }
+
+ fun sendMessage(message: String) {
+ this.sendMessage(*arrayOf(message))
+ }
+
+ fun sendMessage(vararg message: String) {
+ this.members.mapNotNull{Bunkers.instance.server.getPlayer(it)}.forEach{it.sendMessage(message)}
+ }
+
+ fun sendMessage(message: String,vararg ignore: UUID) {
+ this.members.filter{!ignore.contains(it)}.mapNotNull{Bunkers.instance.server.getPlayer(it)}.forEach{it.sendMessage(message)}
+ }
+
+ fun sendInfo(sender: CommandSender) {
+ sender.sendMessage(LINE)
+
+ if (this.type.isSystem()) {
+ sender.sendMessage(this.getDisplayName())
+ sender.sendMessage("${ChatColor.YELLOW}Location: ${ChatColor.WHITE}${if (this.hq == null) "None" else "${this.hq!!.blockX}, ${this.hq!!.blockZ}"}")
+ } else {
+ sender.sendMessage("${this.getDisplayName()} ${ChatColor.GRAY}[${this.findOnlineMembers().size}/${this.members.size}]${ChatColor.DARK_AQUA} - ${ChatColor.YELLOW}HQ: ${ChatColor.WHITE}${if (this.hq == null) "None" else "${this.hq!!.blockX}, ${this.hq!!.blockZ}"}")
+
+ if (this.members.isNotEmpty()) {
+ sender.sendMessage("${ChatColor.YELLOW}Members: ${StringUtils.join(this.members.map{"${this.getDisplayName(it)}${ChatColor.YELLOW}[${ChatColor.GREEN}${Bunkers.instance.statisticHandler.getKills(it)}${ChatColor.YELLOW}]"}.toTypedArray(),"${ChatColor.GRAY}, ")}")
+ }
+
+ sender.sendMessage("${ChatColor.YELLOW}Deaths Until Raidable: ${this.getDTRDisplay()}")
+ }
+
+ sender.sendMessage(LINE)
+ }
+
+ fun getDisplayName(uuid: UUID): String {
+
+ val player = Bunkers.instance.server.getPlayer(uuid)
+
+ if (player != null) {
+
+ if (GameEngine.instance.spectateHandler.isSpectating(player)) {
+ return "${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${player.name}"
+ }
+
+ val respawn = Bunkers.instance.timerHandler.findRemaining(uuid,TimerType.RESPAWN)
+
+ if (respawn > 0L) {
+ return "${ChatColor.RED}${player.name}"
+ }
+
+ return "${ChatColor.GREEN}${player.name}"
+ }
+
+ val name = UUIDUtils.name(uuid)
+
+ if (GameEngine.instance.disqualifieHandler.isDisqualified(uuid)) {
+ return "${ChatColor.DARK_GRAY}${ChatColor.STRIKETHROUGH}${name}"
+ }
+
+ return "${ChatColor.GRAY}$name"
+ }
+
+ fun findChestByBlock(block: Block):TeamChest? {
+
+ val state = block.state
+
+ if (state !is Chest) {
+ return null
+ }
+
+ val holder = state.inventory.holder
+
+ return if (holder is DoubleChest) {
+ this.chests[holder.location]
+ } else {
+ this.chests[block.location]
+ }
+ }
+
+ fun findAliveMembers():MutableSet {
+ return this.members.filter{!(GameEngine.instance.spectateHandler.isSpectating(it) || GameEngine.instance.disqualifieHandler.isDisqualified(it))}.toMutableSet()
+ }
+
+ fun findOnlineMembers():MutableList {
+ return this.members.mapNotNull{Bunkers.instance.server.getPlayer(it)}.toMutableList()
+ }
+
+ fun getName(): String {
+ return WordUtils.capitalizeFully(this.type.name.replace("_"," ")).replace(" ","")
+ }
+
+ enum class Type(val color: ChatColor) {
+
+ RED(ChatColor.RED),
+ BLUE(ChatColor.BLUE),
+ GREEN(ChatColor.GREEN),
+ YELLOW(ChatColor.YELLOW),
+ KOTH(ChatColor.AQUA),
+ WAR_ZONE(ChatColor.DARK_RED);
+
+ fun isSystem():Boolean {
+ return this == WAR_ZONE || this == KOTH
+ }
+
+ fun getDisplayName():String {
+
+ if (this == KOTH && (GameEngine.instance.gameHandler.getState().isPastOrCurrently(GameServer.State.COUNTDOWN))) {
+ return "${this.color}${GameEngine.instance.gameHandler.map.id} ${ChatColor.GOLD}KOTH"
+ }
+
+ return "${this.color}${WordUtils.capitalizeFully(this.name.replace("_"," ")).replace(" ","")}"
+ }
+
+ companion object {
+
+ fun findByName(name: String):Type? {
+ return values().firstOrNull{it.name.equals(name,true)}
+ }
+
+ }
+
+ }
+
+ companion object {
+
+ val DTR_FORMAT = DecimalFormat("0.0")
+
+ val LINE = "${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",53)}"
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/data/TeamChest.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/data/TeamChest.kt
new file mode 100644
index 0000000..1a86a00
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/data/TeamChest.kt
@@ -0,0 +1,11 @@
+package cc.fyre.bunkers.team.data
+
+import java.util.*
+
+data class TeamChest(val owner: UUID,val double: Boolean,val members: MutableSet = mutableSetOf()) {
+
+ fun isMember(uuid: UUID):Boolean {
+ return uuid == this.owner || this.members.contains(uuid)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamChatListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamChatListener.kt
new file mode 100644
index 0000000..ef7327b
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamChatListener.kt
@@ -0,0 +1,58 @@
+package cc.fyre.bunkers.team.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.engine.GameEngine
+import org.bukkit.ChatColor
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.AsyncPlayerChatEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 19/08/2020
+ * @author xanderume@gmail.com
+ */
+class TeamChatListener(private val instance: Bunkers):Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onAsyncChat(event: AsyncPlayerChatEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+
+ if (GameEngine.instance.spectateHandler.isSpectating(event.player)) {
+ return
+ }
+
+ val teamPrefix = event.message[0] == '@'
+ val globalPrefix = event.message[0] == '!'
+
+ if ((teamPrefix || globalPrefix)) {
+
+ if (event.message.length == 1) {
+ event.player.sendMessage("${ChatColor.RED}You must supply a message.")
+ event.isCancelled = true
+ return
+ }
+
+ event.message = event.message.substring(1).trim()
+ }
+
+ if (teamPrefix || (team.chat[event.player.uniqueId] == true && !globalPrefix)) {
+ event.recipients.clear()
+ event.recipients.addAll(team.findOnlineMembers())
+
+ event.format = "${ChatColor.DARK_AQUA}(Team) ${event.player.name}:${ChatColor.YELLOW} ${event.message}"
+ return
+ }
+
+ event.format = "${ChatColor.GOLD}[${team.getDisplayName()}${ChatColor.GOLD}]${ChatColor.WHITE}${event.player.name}: ${event.message}"
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamChestListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamChestListener.kt
new file mode 100644
index 0000000..4312a56
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamChestListener.kt
@@ -0,0 +1,120 @@
+package cc.fyre.bunkers.team.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.team.menu.TeamChestPurchaseMenu
+import cc.fyre.bunkers.team.menu.TeamChestModifyMenu
+import org.bukkit.Bukkit
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.block.Chest
+import org.bukkit.block.DoubleChest
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.Action
+import org.bukkit.event.block.BlockBreakEvent
+import org.bukkit.event.block.BlockPlaceEvent
+import org.bukkit.event.player.PlayerInteractEvent
+
+class TeamChestListener(private val instance: Bunkers) : Listener {
+
+ private val placed = hashSetOf()
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onBlockPlace(event: BlockPlaceEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.block.state !is Chest) {
+ return
+ }
+
+ this.placed.add(event.block.location)
+
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onBlockBreak(event: BlockBreakEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.block.state !is Chest) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.block.location)
+
+ if (team.findChestByBlock(event.block) != null) {
+ event.isCancelled = true
+ return
+ }
+
+ if (this.placed.remove(event.block.location)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ private fun onPlayerInteract(event: PlayerInteractEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ val state = event.clickedBlock.state
+
+ if (state !is Chest) {
+ return
+ }
+
+ if (this.placed.contains(event.clickedBlock.location)) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.clickedBlock.location)
+
+ if (!team.isMember(event.player.uniqueId)) {
+ return
+ }
+
+ val chest = team.findChestByBlock(event.clickedBlock)
+
+ if (chest == null) {
+
+ if (state.inventory.holder is DoubleChest) {
+ TeamChestPurchaseMenu(true,(state.inventory.holder as DoubleChest).location).openMenu(event.player)
+ } else {
+ TeamChestPurchaseMenu(false,state.location).openMenu(event.player)
+ }
+
+ event.isCancelled = true
+ return
+ }
+
+ if (!chest.isMember(event.player.uniqueId)) {
+ event.player.sendMessage("${ChatColor.RED}You cannot access this chest.")
+ event.isCancelled = true
+ return
+ }
+
+ if (event.action != Action.LEFT_CLICK_BLOCK) {
+ return
+ }
+
+ if (chest.owner != event.player.uniqueId) {
+ return
+ }
+
+ event.isCancelled = true
+
+ TeamChestModifyMenu(chest).openMenu(event.player)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamListener.kt
new file mode 100644
index 0000000..ebed5c3
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamListener.kt
@@ -0,0 +1,221 @@
+package cc.fyre.bunkers.team.listener
+
+import net.hylist.HylistSpigot
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.statistic.StatisticHandler
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.map.event.MapLoadEvent
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.hologram.FrozenHologramHandler
+import net.frozenorb.qlib.hologram.construct.Hologram
+import net.hylist.handler.MovementHandler
+import net.minecraft.server.v1_7_R4.PacketPlayInFlying
+import org.bukkit.Bukkit
+
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.entity.Player
+import org.bukkit.entity.Projectile
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.entity.PlayerDeathEvent
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerPearlRefundEvent
+import org.bukkit.event.player.PlayerRespawnEvent
+import org.bukkit.event.player.PlayerTeleportEvent
+import org.bukkit.scheduler.BukkitRunnable
+
+/**
+ * @project bunkers
+ *
+ * @date 06/08/2020
+ * @author xanderume@gmail.com
+ */
+class TeamListener(private val instance: Bunkers) : Listener,MovementHandler {
+
+ val cache = HashSet()
+
+ init {
+ HylistSpigot.INSTANCE.addMovementHandler(this)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onMapLoad(event: MapLoadEvent) {
+ Bukkit.getServer().scheduler.runTaskAsynchronously(this.instance) {
+ this.instance.teamHandler.loadTeamDataSync(event.map)
+ this.instance.teamHandler.findPlayerTeams().flatMap{it.holograms}.withIndex().forEach{
+
+ val hologram = FrozenHologramHandler.createHologram()
+ .at(it.value.clone().add(0.0,1.5,0.0))
+ .build()
+
+ hologram.addLines("${ChatColor.RED}${ChatColor.BOLD}WARNING!","${ChatColor.YELLOW}Blockup this entrance!")
+
+ FrozenHologramHandler.getCache().add(hologram)
+
+ this.cache.add(hologram)
+ }
+ }
+
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerDeath(event: PlayerDeathEvent) {
+
+ val team = this.instance.teamHandler.findById(event.entity.uniqueId) ?: return
+
+ if (event.entity.killer != null) {
+
+ val balance = this.instance.statisticHandler.getBalance(event.entity.uniqueId)
+
+ this.instance.statisticHandler.addKills(event.entity.killer.uniqueId,1)
+ this.instance.statisticHandler.addBalance(event.entity.killer.uniqueId,if (balance >= StatisticHandler.BALANCE_PER_KILL) StatisticHandler.BALANCE_PER_KILL else balance)
+
+ event.entity.killer.sendMessage("${ChatColor.GOLD}You earned ${ChatColor.WHITE}$${if (balance >= StatisticHandler.BALANCE_PER_KILL) StatisticHandler.BALANCE_PER_KILL else balance}.0${ChatColor.GOLD} for killing ${team.type.color}${event.entity.name}${ChatColor.GOLD}!")
+ }
+
+ team.dtr -= 1.0
+ team.sendMessage(
+ "${ChatColor.RED}Member Death: ${ChatColor.WHITE}${event.entity.name}",
+ "${ChatColor.RED}DTR: ${ChatColor.WHITE}${team.getDTR()}"
+ )
+
+ if (team.dtr <= 0) {
+ team.findOnlineMembers().forEach{TeamProtectionListener.protection.remove(it.uniqueId)}
+ }
+
+ event.entity.world.strikeLightningEffect(event.entity.location)
+ event.drops.removeIf{it.hasItemMeta() && it.itemMeta.hasLore() && ChatColor.stripColor(it.itemMeta.lore[0]).equals("Soulbound",true)}
+
+ if (team.isRaidable()) {
+ GameEngine.instance.gameHandler.removePlayer(event.entity)
+ }
+
+ this.instance.statisticHandler.addDeaths(event.entity.uniqueId,1)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerRespawn(event: PlayerRespawnEvent) {
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+
+ if (!team.isRaidable()) {
+ return
+ }
+
+ GameEngine.instance.spectateHandler.addSpectator(event.player)
+
+ this.instance.statisticHandler.recalculatePlayTime(event.player.uniqueId)
+ this.instance.statisticHandler.playTimeJoined.remove(event.player.uniqueId)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+
+ if (event.cause != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.to)
+
+ if (team.type.isSystem()) {
+ return
+ }
+
+ if (team.isRaidable()) {
+ return
+ }
+
+ if (team.isMember(event.player)) {
+ return
+ }
+
+ if ((team.hq?.distance(event.to) ?: 8.0) > 7.0 || (team.hq?.distance(event.from) ?: 8.0) <= 7.0) {
+ return
+ }
+
+ event.player.sendMessage("${ChatColor.RED}You cannot enderpearl this close to ${team.getDisplayName()}${ChatColor.RED}'s HQ!")
+ event.isCancelled = true
+
+ this.instance.server.pluginManager.callEvent(PlayerPearlRefundEvent(event.player))
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ if (GameEngine.instance.gameHandler.getState().isBeforeOrCurrently(GameServer.State.COUNTDOWN)) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+
+ object : BukkitRunnable() {
+
+ override fun run() {
+
+ if (!event.player.isOnline) {
+ return
+ }
+
+ team.sendInfo(event.player)
+ }
+
+ }.runTaskLater(this.instance,20L)
+
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
+
+ if (event.entity !is Player) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.entity.uniqueId)
+
+ if (team == null) {
+ event.isCancelled = true
+ return
+ }
+
+ val attacker = if (event.damager is Player) event.damager as Player else if (event.damager is Projectile && (event.damager as Projectile).shooter is Player) (event.damager as Projectile).shooter as Player else null ?: return
+
+ if (attacker.uniqueId == event.entity.uniqueId) {
+ return
+ }
+
+ if (!team.isMember(attacker.uniqueId)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ override fun handleUpdateRotation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {}
+
+ override fun handleUpdateLocation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {
+
+ if (from.blockX == to.blockX && from.blockZ == to.blockZ) {
+ return
+ }
+
+ if (!GameEngine.instance.gameHandler.isPlaying(player)) {
+ return
+ }
+
+ this.cache.removeIf{
+
+ if (player.world.uid != it.location.world.uid || it.location.distance(player.location) > 5.0) {
+ return@removeIf false
+ }
+
+ it.destroy()
+ FrozenHologramHandler.getCache().remove(it)
+ return@removeIf true
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamProtectionListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamProtectionListener.kt
new file mode 100644
index 0000000..e39877f
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamProtectionListener.kt
@@ -0,0 +1,391 @@
+package cc.fyre.bunkers.team.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.Team
+import com.google.common.collect.ImmutableSet
+import org.bukkit.ChatColor
+import org.bukkit.GameMode
+import org.bukkit.Location
+import org.bukkit.Material
+import org.bukkit.entity.ItemFrame
+import org.bukkit.entity.Player
+import org.bukkit.entity.Projectile
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.Action
+import org.bukkit.event.block.BlockBreakEvent
+import org.bukkit.event.block.BlockIgniteEvent
+import org.bukkit.event.block.BlockPlaceEvent
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.entity.EntityDamageEvent
+import org.bukkit.event.entity.PotionSplashEvent
+import org.bukkit.event.hanging.HangingBreakByEntityEvent
+import org.bukkit.event.hanging.HangingPlaceEvent
+import org.bukkit.event.player.*
+import java.util.*
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+
+/**
+ * @project bunkers
+ *
+ * @date 03/08/2020
+ * @author xanderume@gmail.com
+ */
+class TeamProtectionListener(private val instance: Bunkers) : Listener {
+
+ private val blocks = HashSet()
+ private val restricted = HashMap()
+
+ @EventHandler(priority = EventPriority.HIGH,ignoreCancelled = true)
+ private fun onBlockPlace(event: BlockPlaceEvent) {
+
+ if (event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.block.location)
+
+ if (team.isRaidable()) {
+ return
+ }
+
+ if (team.isMember(event.player)) {
+
+ if ((team.hq?.distance(event.block.location) ?: 10.0) <= 5.0) {
+ event.player.sendMessage("${ChatColor.RED}You cannot place this close to your team's HQ!")
+ event.isCancelled = true
+ return
+ }
+
+ this.blocks.add(event.block.location)
+ return
+ }
+
+ event.isCancelled = true
+ event.player.sendMessage("${ChatColor.YELLOW}You cannot build in ${team.getDisplayName()}${ChatColor.YELLOW}'s territory!")
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL,ignoreCancelled = true)
+ private fun onBlockBreak(event: BlockBreakEvent) {
+
+ if (event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ if (this.instance.supplyHandler.getSupplyByOrigin(event.block.type) != null) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.block.location)
+
+ if (team.isRaidable()) {
+ return
+ }
+
+ if (team.isMember(event.player.uniqueId)) {
+
+ if (this.blocks.remove(event.block.location)) {
+ return
+ }
+
+ event.isCancelled = true
+ return
+ }
+
+ event.isCancelled = true
+ event.player.sendMessage("${ChatColor.YELLOW}You cannot build in ${team.getDisplayName()}${ChatColor.YELLOW}'s territory!")
+
+ if (team.type == Team.Type.WAR_ZONE) {
+ return
+ }
+
+ if (!event.block.type.isBlock) {
+ return
+ }
+
+ this.restricted[event.player.uniqueId] = System.currentTimeMillis() + 1000L
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerInteract(event: PlayerInteractEvent) {
+
+ if (event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ if (event.action == Action.LEFT_CLICK_AIR || event.action == Action.RIGHT_CLICK_AIR) {
+ return
+ }
+
+ if (event.action == Action.PHYSICAL) {
+ event.isCancelled = true
+ return
+ }
+
+ if (event.clickedBlock == null) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.clickedBlock.location)
+
+ if (team.isRaidable() || team.isMember(event.player)) {
+ return
+ }
+
+ if (NO_INTERACT.none{it == event.clickedBlock.type}) {
+ return
+ }
+
+ event.isCancelled = true
+ event.player.sendMessage("${ChatColor.YELLOW}You cannot do this in ${team.getDisplayName()}${ChatColor.YELLOW}'s territory!")
+ }
+
+ @EventHandler(priority = EventPriority.HIGH)
+ private fun onHangingPlace(event: HangingPlaceEvent) {
+
+ if (event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.block.location)
+
+ if (team.isRaidable() || team.isMember(event.player)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.HIGH)
+ private fun onHangingBreakByEntity(event: HangingBreakByEntityEvent) {
+
+ if (event.remover !is Player) {
+ return
+ }
+
+ val player = event.remover as Player
+
+ if (player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.entity.location)
+
+ if (team.isRaidable() || team.isMember(player)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST,ignoreCancelled = true)
+ private fun onInteractEntity(event: PlayerInteractEntityEvent) {
+
+ if (event.rightClicked !is ItemFrame) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.rightClicked.location)
+
+ if (team.isRaidable() || team.isMember(event.player)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.HIGH,ignoreCancelled = true)
+ private fun onEntityDamageItemFrame(event: EntityDamageByEntityEvent) {
+
+ if (event.entity !is ItemFrame) {
+ return
+ }
+
+ if (event.damager !is Player && !(event.damager is Projectile && (event.damager as Projectile).shooter is Player)) {
+ return
+ }
+
+ val player = if (event.damager is Player) event.damager as Player else (event.damager as Projectile).shooter as Player
+
+ if (player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.entity.location)
+
+ if (team.isRaidable() || team.isMember(player)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ private fun onBlockIgnite(event: BlockIgniteEvent) {
+
+ if (event.player == null || event.player.gameMode != GameMode.CREATIVE) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(event.block.location)
+
+ if (team.isRaidable() || team.isMember(event.player)) {
+ return
+ }
+
+ if (event.cause == BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL && (team.isMember(event.player))) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onBucketFill(event: PlayerBucketFillEvent) {
+
+ val location = event.blockClicked.getRelative(event.blockFace).location
+
+ if (event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(location)
+
+ if (team.isRaidable() || team.isMember(event.player)) {
+ return
+ }
+
+ event.isCancelled = true
+ event.player.sendMessage("${ChatColor.BLUE}You cannot build in ${team.getDisplayName()}${ChatColor.YELLOW}'s territory.")
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onBucketEmpty(event: PlayerBucketEmptyEvent) {
+
+ val location = event.blockClicked.getRelative(event.blockFace).location
+
+ if (event.player.gameMode == GameMode.CREATIVE) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findByLocation(location)
+
+ if (team.isRaidable() || team.isMember(event.player)) {
+ return
+ }
+
+ event.isCancelled = true
+ event.player.sendMessage("${ChatColor.BLUE}You cannot build in ${team.getDisplayName()}${ChatColor.YELLOW}'s territory.")
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+ this.restricted.remove(event.player.uniqueId)
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL,ignoreCancelled = true)
+ private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
+
+ if (!this.restricted.containsKey(event.damager.uniqueId)) {
+ return
+ }
+
+ if (System.currentTimeMillis() >= this.restricted[event.damager.uniqueId]!!) {
+ this.restricted.remove(event.damager.uniqueId)
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+
+ if (event.to != team.hq) {
+ return
+ }
+
+ protection[event.player.uniqueId] = false
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ private fun onEntityDamage(event: EntityDamageEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.entity !is Player) {
+ return
+ }
+
+ if (protection.containsKey(event.entity.uniqueId) && event.cause == EntityDamageEvent.DamageCause.POISON) {
+ event.isCancelled = true
+ return
+ }
+
+ if (protection.remove(event.entity.uniqueId) == null) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onPotionSplash(event: PotionSplashEvent) {
+ event.affectedEntities.removeIf{it is Player && protection.containsKey(it.uniqueId)}
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onEntityDamageByEntityProtection(event: EntityDamageByEntityEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ var attacker: Player? = null
+
+ if (event.damager is Player) {
+ attacker = event.damager as Player
+ } else if (event.damager is Projectile && (event.damager as Projectile).shooter is Player) {
+ attacker = (event.damager as Projectile).shooter as Player
+ }
+
+ if (event.entity !is Player || attacker == null) {
+ return
+ }
+
+ if (protection.containsKey(event.entity.uniqueId)) {
+ event.isCancelled = true
+ attacker.sendMessage("${ChatColor.RED}${(event.entity as Player).name} is currently PvP Protected!")
+ return
+ }
+
+ if (!protection.containsKey(event.damager.uniqueId)) {
+ return
+ }
+
+ if (protection[event.damager.uniqueId] == true) {
+ protection.remove(event.damager.uniqueId)
+ return
+ }
+
+ event.isCancelled = true
+ (event.damager as Player).sendMessage("${ChatColor.RED}Your PvP Protection will be removed upon attacking.")
+ protection[event.damager.uniqueId] = true
+ }
+
+ companion object {
+
+ val protection: HashMap = HashMap()
+ val NO_INTERACT: ImmutableSet = ImmutableSet.of(Material.FENCE_GATE,Material.FURNACE,Material.BURNING_FURNACE,Material.BREWING_STAND,Material.CHEST,Material.HOPPER,Material.DISPENSER,Material.WOODEN_DOOR,Material.STONE_BUTTON,Material.WOOD_BUTTON,Material.TRAPPED_CHEST,Material.TRAP_DOOR,Material.LEVER,Material.DROPPER,Material.ENCHANTMENT_TABLE,Material.BED_BLOCK,Material.ANVIL,Material.BEACON)
+ val ATTACK_DISABLING_BLOCKS: ImmutableSet = ImmutableSet.of(Material.GLASS, Material.WOOD_DOOR, Material.IRON_DOOR, Material.FENCE_GATE)
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamRallyListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamRallyListener.kt
new file mode 100644
index 0000000..d0bb5d2
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/listener/TeamRallyListener.kt
@@ -0,0 +1,29 @@
+package cc.fyre.bunkers.team.listener
+
+import cc.fyre.bunkers.Bunkers
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 22/12/2020
+ * @author xanderume@gmail.com
+ */
+class TeamRallyListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ val team = this.instance.teamHandler.findById(event.player.uniqueId) ?: return
+
+ if (team.rally == null) {
+ return
+ }
+
+ //TODO LunarClientAPI.instance.packetHandler.sendPacket(event.player,WayPointAddPacket("Rally",team.rally!!.world,team.rally!!.blockX,team.rally!!.blockY,team.rally!!.blockZ,Color.ORANGE,forced = true,visible = true))
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/TeamChestModifyMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/TeamChestModifyMenu.kt
new file mode 100644
index 0000000..f1c0493
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/TeamChestModifyMenu.kt
@@ -0,0 +1,37 @@
+package cc.fyre.bunkers.team.menu
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.data.TeamChest
+import cc.fyre.bunkers.team.menu.button.TeamChestMemberButton
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+import org.bukkit.entity.Player
+
+class TeamChestModifyMenu(private val chest: TeamChest) : Menu() {
+
+ override fun size(buttons: MutableMap?): Int {
+ return 3*9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "${if (this.chest.double) "Large " else ""}Chest"
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ var index = 12
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)!!
+ val toReturn = mutableMapOf()
+
+ for (member in team.members.filter{it != player.uniqueId}) {
+ toReturn[index++] = TeamChestMemberButton(this.chest,member)
+ }
+
+ return toReturn
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/TeamChestPurchaseMenu.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/TeamChestPurchaseMenu.kt
new file mode 100644
index 0000000..e7a0c37
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/TeamChestPurchaseMenu.kt
@@ -0,0 +1,33 @@
+package cc.fyre.bunkers.team.menu
+
+import cc.fyre.bunkers.team.menu.button.TeamChestPurchaseButton
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.menu.Menu
+import org.bukkit.Location
+import org.bukkit.entity.Player
+
+class TeamChestPurchaseMenu(private val double: Boolean, private val location: Location) : Menu() {
+
+ override fun size(buttons: MutableMap?): Int {
+ return 3*9
+ }
+
+ override fun getTitle(player: Player): String {
+ return "Buy Chest"
+ }
+
+ override fun isPlaceholder(): Boolean {
+ return true
+ }
+
+ override fun getButtons(player: Player): MutableMap {
+
+ val toReturn = mutableMapOf()
+
+ toReturn[11] = TeamChestPurchaseButton(this.double,this.location,true)
+ toReturn[15] = TeamChestPurchaseButton(this.double,this.location,false)
+
+ return toReturn
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/button/TeamChestMemberButton.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/button/TeamChestMemberButton.kt
new file mode 100644
index 0000000..08bdfc0
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/button/TeamChestMemberButton.kt
@@ -0,0 +1,47 @@
+package cc.fyre.bunkers.team.menu.button
+
+import cc.fyre.bunkers.team.data.TeamChest
+import cc.fyre.engine.GameEngine
+import net.frozenorb.qlib.menu.Button
+import net.frozenorb.qlib.util.UUIDUtils
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.inventory.ClickType
+import java.util.*
+
+class TeamChestMemberButton(private val chest: TeamChest,private val member: UUID) : Button() {
+
+ private val disqualified = GameEngine.instance.disqualifieHandler.isDisqualified(this.member)
+
+ override fun getName(p0: Player?): String {
+
+ val color = if (this.disqualified) ChatColor.GRAY else if (this.chest.isMember(this.member)) ChatColor.GREEN else ChatColor.RED
+
+ return "$color${ChatColor.BOLD}${if (this.disqualified) ChatColor.STRIKETHROUGH else ""}${UUIDUtils.name(this.member)}"
+ }
+
+
+ override fun getDescription(p0: Player?): MutableList {
+ return mutableListOf()
+ }
+
+ override fun getMaterial(p0: Player?): Material {
+ return Material.SKULL_ITEM
+ }
+
+ override fun clicked(player: Player?, slot: Int, clickType: ClickType?) {
+
+ if (this.disqualified) {
+ return
+ }
+
+ if (this.chest.isMember(this.member)) {
+ this.chest.members.remove(this.member)
+ } else {
+ this.chest.members.add(this.member)
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/button/TeamChestPurchaseButton.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/button/TeamChestPurchaseButton.kt
new file mode 100644
index 0000000..e5a5ecd
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/team/menu/button/TeamChestPurchaseButton.kt
@@ -0,0 +1,70 @@
+package cc.fyre.bunkers.team.menu.button
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.team.TeamHandler
+import cc.fyre.bunkers.team.data.TeamChest
+import cc.fyre.bunkers.team.menu.TeamChestModifyMenu
+import net.frozenorb.qlib.menu.Button
+import org.bukkit.ChatColor
+import org.bukkit.DyeColor
+import org.bukkit.Location
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.inventory.ClickType
+
+class TeamChestPurchaseButton(private val double: Boolean, private val location: Location, private val value: Boolean) : Button() {
+
+ override fun getName(p0: Player?): String {
+
+ if (this.value) {
+ return "${ChatColor.GREEN}${ChatColor.BOLD}Purchase Chest"
+ }
+
+ return "${ChatColor.RED}${ChatColor.BOLD}Cancel Purchase"
+ }
+
+ override fun getMaterial(p0: Player?): Material {
+ return Material.WOOL
+ }
+
+ override fun getDescription(p0: Player?): MutableList {
+ return mutableListOf()
+ }
+
+ override fun getDamageValue(player: Player?): Byte {
+ return if (this.value) DyeColor.LIME.woolData else DyeColor.RED.woolData
+ }
+
+ override fun clicked(player: Player, slot: Int, clickType: ClickType?) {
+
+ if (!this.value) {
+ player.sendMessage("${ChatColor.RED}Purchase cancelled.")
+ return
+ }
+
+ val team = Bunkers.instance.teamHandler.findById(player.uniqueId)
+
+ if (team == null) {
+ player.sendMessage("${ChatColor.RED}You are not on a team!")
+ return
+ }
+
+
+ val balance = Bunkers.instance.statisticHandler.getBalance(player.uniqueId)
+
+ if (balance <= TeamHandler.CHEST_PRICE) {
+ player.closeInventory()
+ player.sendMessage("${ChatColor.RED}You need ${ChatColor.BOLD}$${TeamHandler.CHEST_PRICE}${ChatColor.RED} to purchase this chest.")
+ return
+ }
+
+ val chest = TeamChest(player.uniqueId,this.double)
+
+ team.chests[this.location] = chest
+
+ player.sendMessage("${ChatColor.GREEN}You have purchased this chest for ${ChatColor.BOLD}${TeamHandler.CHEST_PRICE}${ChatColor.GREEN}!")
+
+ TeamChestModifyMenu(chest).openMenu(player)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/TimerHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/TimerHandler.kt
new file mode 100644
index 0000000..dbb7224
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/TimerHandler.kt
@@ -0,0 +1,117 @@
+package cc.fyre.bunkers.timer
+
+import net.hylist.HylistSpigot
+import cc.fyre.bunkers.Bunkers
+
+import cc.fyre.bunkers.timer.data.Timer
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.bunkers.timer.event.TimerCreateEvent
+import cc.fyre.bunkers.timer.event.TimerExtendEvent
+import cc.fyre.bunkers.timer.event.TimerRemoveEvent
+import cc.fyre.bunkers.timer.listener.*
+
+import java.util.*
+import java.util.concurrent.ConcurrentHashMap
+import kotlin.collections.HashSet
+
+/**
+ * @project hcf
+ *
+ * @date 06/07/2020
+ * @author xanderume@gmail.com
+ */
+class TimerHandler(private val instance: Bunkers) {
+
+ val cache = ConcurrentHashMap>()
+
+ init {
+ HylistSpigot.INSTANCE.addMovementHandler(HomeListener(this.instance))
+ HylistSpigot.INSTANCE.addMovementHandler(RespawnListener(this.instance))
+
+ this.instance.server.pluginManager.registerEvents(HomeListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(TimerListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(RespawnListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(AntidoteListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(EnderpearlListener(this.instance),this.instance)
+ }
+
+ fun findTimers(uuid: UUID):HashSet {
+ return this.cache[uuid] ?: HashSet()
+ }
+
+ fun addTimer(uuid: UUID,type: TimerType) {
+ this.addTimer(uuid,type,type.duration)
+ }
+
+ fun addTimer(uuid: UUID,type: TimerType,duration: Long) {
+
+ this.cache.putIfAbsent(uuid,HashSet())
+
+ var timer = this.cache[uuid]!!.firstOrNull{it.type == type}
+
+ if (timer != null) {
+ timer.setRemaining(duration)
+ this.instance.server.pluginManager.callEvent(TimerExtendEvent(timer,uuid,duration))
+ return
+ }
+
+ timer = Timer(type,duration,uuid)
+
+ val event = TimerCreateEvent(timer,uuid,duration)
+
+ this.instance.server.pluginManager.callEvent(event)
+
+ if (event.isCancelled) {
+ return
+ }
+
+ this.cache[uuid]!!.add(timer)
+ }
+
+ fun removeTimer(uuid: UUID,type: TimerType):Boolean {
+
+ if (!this.cache.containsKey(uuid)) {
+ return false
+ }
+
+ val timer = this.cache[uuid]!!.firstOrNull{it.type == type} ?: return false
+
+ timer.task?.cancel()
+
+ this.instance.server.pluginManager.callEvent(TimerRemoveEvent(timer,uuid))
+
+ return this.cache[uuid]!!.remove(timer)
+ }
+
+ fun hasTimer(uuid: UUID,type: TimerType):Boolean {
+
+ if (!this.cache.containsKey(uuid)) {
+ return false
+ }
+
+ return this.cache[uuid]!!.any{it.type == type && it.getRemaining() > 0}
+ }
+
+ fun setPaused(uuid: UUID,type: TimerType,value: Boolean):Boolean {
+
+ if (!this.cache.containsKey(uuid)) {
+ return false
+ }
+
+ val timer = this.cache[uuid]!!.firstOrNull{it.type == type} ?: return false
+
+ timer.setPaused(value)
+ return true
+ }
+
+ fun findRemaining(uuid: UUID,type: TimerType):Long {
+
+ if (!this.cache.containsKey(uuid)) {
+ return 0L
+ }
+
+ return this.cache[uuid]!!.firstOrNull{it.type == type}?.getRemaining() ?: 0L
+ }
+
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/data/Timer.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/data/Timer.kt
new file mode 100644
index 0000000..2b92082
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/data/Timer.kt
@@ -0,0 +1,107 @@
+package cc.fyre.bunkers.timer.data
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.event.TimerExpireEvent
+import org.bukkit.scheduler.BukkitRunnable
+import org.bukkit.scheduler.BukkitTask
+import java.util.*
+
+/**
+ * @project hcf
+ *
+ * @date 06/07/2020
+ * @author xanderume@gmail.com
+ */
+open class Timer(val type: TimerType,private val duration: Long,var owner: UUID?) {
+
+ constructor(type: TimerType,owner: UUID?):this(type,type.duration,owner)
+
+ var task: BukkitTask? = null
+
+ private var paused = 0L
+ private var started = System.currentTimeMillis()
+ private var expires = System.currentTimeMillis() + this.duration
+
+ init {
+
+ if (this.owner != null) {
+ this.task = this.createTask(this.duration)
+ }
+
+ }
+
+ fun getDuration(): Long {
+ return this.duration
+ }
+
+ fun isPaused():Boolean {
+ return this.paused != 0L
+ }
+
+ fun setPaused(value: Boolean) {
+
+ if (value == this.isPaused()) {
+ return
+ }
+
+ if (value) {
+
+ if (this.task != null) {
+ this.task!!.cancel()
+ }
+
+ this.paused = this.getRemaining()
+ return
+ }
+
+ this.setRemaining(this.paused)
+ this.paused = 0L
+ }
+
+ fun getRemaining():Long {
+
+ if (this.paused != 0L) {
+ return this.paused
+ }
+
+ return this.expires - System.currentTimeMillis()
+ }
+
+ fun setRemaining(duration: Long) {
+
+ if (duration <= 0L) {
+ return
+ }
+
+ this.expires = System.currentTimeMillis() + duration
+
+ if (this.owner == null) {
+ return
+ }
+
+ if (this.task != null) {
+ this.task!!.cancel()
+ }
+
+ this.task = this.createTask(duration)
+ }
+
+ private fun createTask(duration: Long): BukkitTask {
+ return object : BukkitRunnable() {
+
+ override fun run() {
+
+ if (this@Timer.owner == null) {
+ return
+ }
+
+ if (Bunkers.instance.timerHandler.cache.containsKey(this@Timer.owner!!)) {
+ Bunkers.instance.timerHandler.cache[this@Timer.owner!!]!!.remove(this@Timer)
+ }
+
+ Bunkers.instance.server.pluginManager.callEvent(TimerExpireEvent(this@Timer,this@Timer.owner!!))
+ }
+
+ }.runTaskLater(Bunkers.instance,duration / 50L)
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/data/TimerType.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/data/TimerType.kt
new file mode 100644
index 0000000..3f691fd
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/data/TimerType.kt
@@ -0,0 +1,29 @@
+package cc.fyre.bunkers.timer.data
+
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import java.util.concurrent.TimeUnit
+
+/**
+ * @project hcf
+ *
+ * @date 06/07/2020
+ * @author xanderume@gmail.com
+ */
+enum class TimerType(val duration: Long,val scoreboard: String,val displays: Boolean,val icon: Material?) {
+
+ HOME(TimeUnit.SECONDS.toMillis(10L),"${ChatColor.BLUE}${ChatColor.BOLD}HQ",true,Material.WOOD_DOOR),
+ RESPAWN(TimeUnit.SECONDS.toMillis(15L),"${ChatColor.GOLD}${ChatColor.BOLD}Respawn",true,Material.LEASH),
+ ANTIDOTE(TimeUnit.SECONDS.toMillis(5L),"${ChatColor.RED}${ChatColor.BOLD}Antidote",true,Material.SPIDER_EYE),
+ ENDER_PEARL(TimeUnit.SECONDS.toMillis(16L),"${ChatColor.YELLOW}${ChatColor.BOLD}Enderpearl",true,Material.ENDER_PEARL),
+ ENERGY_COOLDOWN(TimeUnit.SECONDS.toMillis(10L),"${ChatColor.GREEN}${ChatColor.BOLD}Energy Effect",false,Material.GOLD_HELMET);
+
+ companion object {
+
+ fun findByName(name: String): TimerType? {
+ return values().firstOrNull{it.name.equals(name,true) || it.name.replace("_", "").equals(name,true) || ChatColor.stripColor(it.scoreboard.replace(" ", "")).equals(name,true)}
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerCreateEvent.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerCreateEvent.kt
new file mode 100644
index 0000000..5962eb4
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerCreateEvent.kt
@@ -0,0 +1,41 @@
+package cc.fyre.bunkers.timer.event
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.data.Timer
+import org.bukkit.event.Cancellable
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+import java.util.*
+
+/**
+ * @project hcf
+ *
+ * @date 06/07/2020
+ * @author xanderume@gmail.com
+ */
+class TimerCreateEvent(val timer: Timer,val uuid: UUID,val duration: Long) : Event(),Cancellable {
+
+ private var cancelled = false
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+ @JvmStatic val handlerList = HandlerList()
+ }
+
+ override fun isCancelled(): Boolean {
+ return this.cancelled
+ }
+
+ override fun setCancelled(cancelled: Boolean) {
+ this.cancelled = cancelled
+ }
+
+ fun call(): TimerCreateEvent {
+ Bunkers.instance.server.pluginManager.callEvent(this)
+ return this
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerExpireEvent.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerExpireEvent.kt
new file mode 100644
index 0000000..ccc47aa
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerExpireEvent.kt
@@ -0,0 +1,30 @@
+package cc.fyre.bunkers.timer.event
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.data.Timer
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+import java.util.*
+
+/**
+ * @project hcf
+ *
+ * @date 06/07/2020
+ * @author xanderume@gmail.com
+ */
+class TimerExpireEvent(val timer: Timer, val uuid: UUID) : Event() {
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+ @JvmStatic val handlerList = HandlerList()
+ }
+
+ fun call(): TimerExpireEvent {
+ Bunkers.instance.server.pluginManager.callEvent(this)
+ return this
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerExtendEvent.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerExtendEvent.kt
new file mode 100644
index 0000000..bb446b7
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerExtendEvent.kt
@@ -0,0 +1,26 @@
+package cc.fyre.bunkers.timer.event
+
+import cc.fyre.bunkers.timer.data.Timer
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+import java.util.*
+
+/**
+ * @project hcf
+ *
+ * @date 01/11/2020
+ * @author xanderume@gmail.com
+ */
+class TimerExtendEvent(val timer: Timer,val uuid: UUID,val newDuration: Long) : Event() {
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+
+ @JvmStatic val handlerList = HandlerList()
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerRemoveEvent.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerRemoveEvent.kt
new file mode 100644
index 0000000..0dc9f7b
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/event/TimerRemoveEvent.kt
@@ -0,0 +1,30 @@
+package cc.fyre.bunkers.timer.event
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.data.Timer
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+import java.util.*
+
+/**
+ * @project hcf
+ *
+ * @date 19/07/2020
+ * @author xanderume@gmail.com
+ */
+class TimerRemoveEvent(val timer: Timer, val uuid: UUID) : Event() {
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+ @JvmStatic val handlerList = HandlerList()
+ }
+
+ fun call(): TimerRemoveEvent {
+ Bunkers.instance.server.pluginManager.callEvent(this)
+ return this
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/AntidoteListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/AntidoteListener.kt
new file mode 100644
index 0000000..435fc7a
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/AntidoteListener.kt
@@ -0,0 +1,115 @@
+package cc.fyre.bunkers.timer.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.game.BunkersGameAdapter
+import cc.fyre.bunkers.pvpclass.data.item.energy.EnergyEffect
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.bunkers.timer.event.TimerCreateEvent
+import cc.fyre.engine.util.FormatUtil
+import net.frozenorb.qlib.util.TimeUtils
+import net.md_5.bungee.api.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.PotionEffectAddEvent
+import org.bukkit.event.player.PlayerItemConsumeEvent
+import org.bukkit.scheduler.BukkitRunnable
+
+/**
+ * @project bunkers
+ *
+ * @date 03/02/2021
+ * @author xanderume@gmail.com
+ */
+class AntidoteListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onTimerCreate(event: TimerCreateEvent) {
+
+ if (event.timer.type != TimerType.ANTIDOTE) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(event.uuid) ?: return
+
+ player.sendMessage("${ChatColor.RED}You are now immune to debuffs for ${TimeUtils.formatIntoDetailedString((event.timer.getDuration() / 1000L).toInt())}.")
+
+ object : BukkitRunnable() {
+
+ override fun run() {
+
+ for (effect in player.activePotionEffects) {
+
+ if (EnergyEffect.BardEffect.isDebuff(effect.type)) {
+ player.removePotionEffect(effect.type)
+ }
+
+ }
+
+ }
+
+ }.runTaskLater(this.instance,2L)
+
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPreConsume(event: PlayerItemConsumeEvent) {
+
+ if (event.item.type != Material.POTION) {
+ return
+ }
+
+ if (!BunkersGameAdapter.ANTIDOTE.isSimilar(event.item)) {
+ return
+ }
+
+ val cooldown = this.instance.timerHandler.findRemaining(event.player.uniqueId,TimerType.ANTIDOTE)
+
+ if (cooldown <= 0L) {
+ return
+ }
+
+ event.isCancelled = true
+ event.player.sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${FormatUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
+ event.player.updateInventory()
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onItemConsume(event: PlayerItemConsumeEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.item.type != Material.POTION) {
+ return
+ }
+
+ if (!BunkersGameAdapter.ANTIDOTE.isSimilar(event.item)) {
+ return
+ }
+
+ this.instance.timerHandler.addTimer(event.player.uniqueId,TimerType.ANTIDOTE)
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onPotionEffectAdd(event: PotionEffectAddEvent) {
+
+ if (event.entity !is Player) {
+ return
+ }
+
+ if (!this.instance.timerHandler.hasTimer(event.entity.uniqueId,TimerType.ANTIDOTE)) {
+ return
+ }
+
+ if (!EnergyEffect.BardEffect.isDebuff(event.effect.type)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/EnderpearlListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/EnderpearlListener.kt
new file mode 100644
index 0000000..22bcb87
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/EnderpearlListener.kt
@@ -0,0 +1,146 @@
+package cc.fyre.bunkers.timer.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.engine.util.FormatUtil
+import org.bukkit.ChatColor
+import org.bukkit.Material
+import org.bukkit.entity.EnderPearl
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.ProjectileLaunchEvent
+import org.bukkit.event.player.PlayerPearlRefundEvent
+import org.bukkit.inventory.ItemStack
+
+/**
+ * @project hcf
+ *
+ * @date 20/07/2020
+ * @author xanderume@gmail.com
+ */
+class EnderpearlListener(private val instance: Bunkers):Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR,ignoreCancelled = true)
+ private fun onProjectileLaunched(event: ProjectileLaunchEvent) {
+
+ if (event.entity !is EnderPearl || event.entity.shooter !is Player) {
+ return
+ }
+
+ this.instance.timerHandler.addTimer((event.entity.shooter as Player).uniqueId,TimerType.ENDER_PEARL)
+ }
+
+ @EventHandler(priority = EventPriority.HIGH,ignoreCancelled = true)
+ private fun onProjectileLaunch(event: ProjectileLaunchEvent) {
+
+ if (event.entity !is EnderPearl || event.entity.shooter !is Player) {
+ return
+ }
+
+ val cooldown = this.instance.timerHandler.findRemaining((event.entity.shooter as Player).uniqueId,TimerType.ENDER_PEARL)
+
+ if (cooldown <= 0) {
+ return
+ }
+
+ event.isCancelled = true
+
+ (event.entity.shooter as Player).sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${FormatUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
+ (event.entity.shooter as Player).updateInventory()
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPearlRefund(event: PlayerPearlRefundEvent) {
+ event.player.inventory.addItem(ItemStack(Material.ENDER_PEARL))
+ this.instance.timerHandler.removeTimer(event.player.uniqueId,TimerType.ENDER_PEARL)
+ }
+
+// @EventHandler(priority = EventPriority.LOW)
+// private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+//
+// if (event.isCancelled || event.cause != PlayerTeleportEvent.TeleportCause.ENDER_PEARL || event.to.world.environment != World.Environment.NORMAL) {
+// return
+// }
+//
+// val face = this.getDirection(event.player)
+// val block = this.getDirectionalBlock(event.to.block,face)
+//
+// if ((block == null || block.type != Material.FENCE_GATE || block.getRelative(BlockFace.UP).type != Material.TRAP_DOOR) && event.to.block.type != Material.FENCE_GATE && EntityEnderPearl.pearlAbleType.stream().noneMatch { it: String? -> event.to.block.type.name.contains(it!!) } && !event.to.block.getRelative(BlockFace.UP).type.name.contains("STEP") || event.to.block.type == null || block == null && EntityEnderPearl.pearlAbleType.none{event.to.block.type.name.contains(it)}) {
+// return
+// }
+//
+// if (this.isPearlGlitching(block) && event.to.block.type != Material.AIR) {
+// event.isCancelled = true
+// this.instance.server.pluginManager.callEvent(PlayerPearlRefundEvent(event.player))
+// return
+// }
+//
+// event.to = this.findSuitableLocation(event.to,face)
+// }
+
+// private fun getDirectionalBlock(block: Block,face: BlockFace): Block? {
+//
+// val relative = block.getRelative(face)
+//
+// if (relative == null || relative.type == Material.AIR) {
+// return null
+// }
+//
+// return relative
+// }
+
+// private fun isPearlGlitching(block: Block?): Boolean {
+// return block != null && block.type != Material.AIR && block.type.isSolid && !RETURN_TYPES.contains(block.type) || block is Openable && !(block as Openable).isOpen
+// }
+
+// private fun findSuitableLocation(location: Location,face: BlockFace): Location {
+//
+// val toReturn = location.clone()
+//
+// if (face.ordinal <= 3) {
+// toReturn.x += face.modX
+// toReturn.y += face.modY
+// toReturn.z += face.modZ
+// }
+//
+// if (toReturn.block.getRelative(BlockFace.DOWN) == null || !toReturn.block.getRelative(BlockFace.DOWN).type.isSolid) {
+// toReturn.y += BlockFace.DOWN.modY
+// }
+//
+// return toReturn
+// }
+
+// private fun getDirection(player: Player): BlockFace {
+//
+// var toReturn = player.location.yaw
+//
+// if (toReturn < 0) {
+// toReturn += 360.0F
+// }
+//
+// if (toReturn >= 315 || toReturn < 45) {
+// return BlockFace.SOUTH
+// } else if (toReturn < 135) {
+// return BlockFace.WEST
+// } else if (toReturn < 225) {
+// return BlockFace.NORTH
+// } else if (toReturn < 315) {
+// return BlockFace.EAST
+// }
+//
+// return BlockFace.NORTH
+// }
+
+ companion object {
+
+ val RETURN_TYPES = arrayListOf(
+ Material.LADDER,Material.BRICK_STAIRS,Material.SMOOTH_STAIRS,Material.WOOD_STAIRS,Material.SPRUCE_WOOD_STAIRS,Material.TORCH,Material.NETHER_BRICK_STAIRS,
+ Material.QUARTZ_STAIRS,Material.BEDROCK,Material.CAKE,Material.STEP,Material.WOOD_STEP,Material.LEVER,Material.DAYLIGHT_DETECTOR,Material.COBBLE_WALL,
+ Material.FENCE_GATE,Material.SIGN,Material.SIGN_POST,Material.WALL_SIGN,Material.STATIONARY_WATER,Material.WATER,Material.LAVA,Material.STATIONARY_LAVA,
+ Material.STONE_PLATE,Material.WOOD_PLATE,Material.IRON_PLATE,Material.GOLD_PLATE
+ )
+
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/HomeListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/HomeListener.kt
new file mode 100644
index 0000000..5308920
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/HomeListener.kt
@@ -0,0 +1,123 @@
+package cc.fyre.bunkers.timer.listener
+
+import cc.fyre.bunkers.Bunkers
+import net.hylist.handler.MovementHandler
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.bunkers.timer.event.TimerCreateEvent
+import cc.fyre.bunkers.timer.event.TimerExpireEvent
+import cc.fyre.engine.util.FormatUtil
+import net.minecraft.server.v1_7_R4.PacketPlayInFlying
+import org.bukkit.ChatColor
+import org.bukkit.Location
+import org.bukkit.entity.EnderPearl
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityDamageEvent
+import org.bukkit.event.player.PlayerQuitEvent
+import org.bukkit.event.player.PlayerTeleportEvent
+
+/**
+ * @project hcf
+ *
+ * @date 06/07/2020
+ * @author xanderume@gmail.com
+ */
+class HomeListener(private val instance: Bunkers) : Listener,MovementHandler {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onTimerCreate(event: TimerCreateEvent) {
+
+ if (event.timer.type != TimerType.HOME) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(event.uuid) ?: return
+
+ player.sendMessage("${ChatColor.YELLOW}Teleporting in ${ChatColor.LIGHT_PURPLE}${FormatUtil.formatIntoDetailedString(event.timer.getDuration())}${ChatColor.YELLOW}... Stay still and do not take damage.")
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onTimerExpire(event: TimerExpireEvent) {
+
+ if (event.timer.type != TimerType.HOME) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(event.uuid) ?: return
+
+ val team = this.instance.teamHandler.findById(player.uniqueId) ?: return
+
+ if (team.hq == null) {
+ player.sendMessage("${ChatColor.RED}Your team's HQ has not been setup, please contact an administrator.")
+ return
+ }
+
+ player.world.getEntitiesByClass(EnderPearl::class.java).filter{pearl -> pearl.shooter != null && pearl.shooter is Player && (pearl.shooter as Player).uniqueId == player.uniqueId}.forEach{pearl -> pearl.remove()}
+
+ this.instance.server.scheduler.runTask(this.instance) {
+
+ if (team.hq!!.chunk.isLoaded) {
+ team.hq!!.chunk.load()
+ }
+
+ player.teleport(team.hq)
+ }
+
+ player.sendMessage("${ChatColor.YELLOW}Warping to ${ChatColor.LIGHT_PURPLE}${team.getDisplayName()}${ChatColor.YELLOW}${ChatColor.YELLOW}'s HQ.")
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+ this.instance.timerHandler.removeTimer(event.player.uniqueId, TimerType.HOME)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onEntityDamage(event: EntityDamageEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ if (event.damage <= 0) {
+ return
+ }
+
+ if (event.entity !is Player) {
+ return
+ }
+
+ if (!this.instance.timerHandler.removeTimer(event.entity.uniqueId,TimerType.HOME)) {
+ return
+ }
+
+ (event.entity as Player).sendMessage("${ChatColor.RED}Teleport cancelled.")
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ this.handleUpdateLocation(event.player,event.to,event.from,null)
+ }
+
+ override fun handleUpdateRotation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {}
+
+ override fun handleUpdateLocation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {
+
+ if (from.blockX == to.blockX && from.blockZ == to.blockZ) {
+ return
+ }
+
+ if (!this.instance.timerHandler.removeTimer(player.uniqueId,TimerType.HOME)) {
+ return
+ }
+
+ player.sendMessage("${ChatColor.RED}Teleport cancelled.")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/RespawnListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/RespawnListener.kt
new file mode 100644
index 0000000..b5c71a1
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/RespawnListener.kt
@@ -0,0 +1,247 @@
+package cc.fyre.bunkers.timer.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.game.BunkersGameAdapter
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.bunkers.timer.event.TimerExpireEvent
+import cc.fyre.engine.GameEngine
+import net.hylist.handler.MovementHandler
+import net.minecraft.server.v1_7_R4.PacketPlayInFlying
+import org.bukkit.ChatColor
+import org.bukkit.GameMode
+import org.bukkit.Location
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.BlockBreakEvent
+import org.bukkit.event.block.BlockPlaceEvent
+import org.bukkit.event.entity.*
+import org.bukkit.event.inventory.InventoryClickEvent
+import org.bukkit.event.player.*
+import org.spigotmc.SpigotConfig
+import java.util.*
+import kotlin.collections.HashMap
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class RespawnListener(private val instance: Bunkers) : Listener, MovementHandler {
+
+ private val cache = HashMap()
+
+ init {
+ SpigotConfig.instantRespawn = true
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerDeath(event: PlayerDeathEvent) {
+
+ this.cache[event.entity.uniqueId] = event.entity.location
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.entity)) {
+ return
+ }
+
+ event.entity.gameMode = GameMode.CREATIVE
+ event.entity.isFlying = true
+
+ this.instance.timerHandler.addTimer(event.entity.uniqueId,TimerType.RESPAWN)
+ this.instance.server.onlinePlayers.forEach{it.hidePlayer(event.entity)}
+
+ GameEngine.instance.gameHandler.removePlayer(event.entity)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerRespawn(event: PlayerRespawnEvent) {
+
+ if (!this.cache.containsKey(event.player.uniqueId)) {
+ return
+ }
+
+ event.respawnLocation = this.cache[event.player.uniqueId]!!.clone().add(0.0,5.0,0.0)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onTimerExpire(event: TimerExpireEvent) {
+
+ if (event.timer.type != TimerType.RESPAWN) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(event.uuid) ?: return
+
+ val team = this.instance.teamHandler.findById(player.uniqueId) ?: return
+
+ if (team.hq == null) {
+ player.sendMessage("${ChatColor.RED}Your team's HQ has not been setup, please contact an administrator.")
+ return
+ }
+
+ player.gameMode = GameMode.SURVIVAL
+ player.isFlying = false
+ player.inventory.clear()
+
+ this.cache.remove(player.uniqueId)
+
+ BunkersGameAdapter.STARTER_ITEMS.forEach{player.inventory.addItem(it)}
+
+ //need to go on main thread
+ this.instance.server.scheduler.runTask(this.instance) {
+
+ if (team.hq!!.chunk.isLoaded) {
+ team.hq!!.chunk.load()
+ }
+
+ player.teleport(team.hq)
+ }
+
+ this.instance.server.onlinePlayers.forEach{it.showPlayer(player)}
+
+ GameEngine.instance.gameHandler.addPlayer(player)
+
+ player.sendMessage("${ChatColor.YELLOW}Warping to ${ChatColor.LIGHT_PURPLE}${team.getDisplayName()}${ChatColor.YELLOW}${ChatColor.YELLOW}'s HQ.")
+ }
+
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ if (!this.instance.timerHandler.hasTimer(event.player.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.player.gameMode = GameMode.CREATIVE
+ event.player.isFlying = true
+ event.player.inventory.clear()
+ event.player.inventory.armorContents = null
+ event.player.activePotionEffects.forEach{event.player.removePotionEffect(it.type)}
+
+ this.instance.server.onlinePlayers.forEach{it.hidePlayer(event.player)}
+
+ this.instance.timerHandler.setPaused(event.player.uniqueId,TimerType.RESPAWN,false)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+ this.instance.timerHandler.setPaused(event.player.uniqueId,TimerType.RESPAWN,true)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerTeleport(event: PlayerTeleportEvent) {
+
+ if (event.isCancelled) {
+ return
+ }
+
+ this.handleUpdateLocation(event.player,event.to,event.from,null)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onBlockBreak(event: BlockBreakEvent) {
+
+ if (!this.instance.timerHandler.hasTimer(event.player.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onBlockPlace(event: BlockPlaceEvent) {
+
+ if (!this.instance.timerHandler.hasTimer(event.player.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDamage(event: EntityDamageEvent) {
+
+ if (event.entity !is Player) {
+ return
+ }
+
+ if (!this.instance.timerHandler.hasTimer((event.entity as Player).uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerInteract(event: PlayerInteractEvent) {
+
+ if (!this.instance.timerHandler.hasTimer(event.player.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
+
+ if (event.damager !is Player) {
+ return
+ }
+
+ if (!this.instance.timerHandler.hasTimer(event.damager.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onInventoryClick(event: InventoryClickEvent) {
+
+ if (event.whoClicked !is Player) {
+ return
+ }
+
+ if (!this.instance.timerHandler.hasTimer((event.whoClicked as Player).uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPickupItem(event: PlayerPickupItemEvent) {
+
+ if (!this.instance.timerHandler.hasTimer(event.player.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ override fun handleUpdateRotation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {}
+
+ override fun handleUpdateLocation(player: Player, to: Location, from: Location, packet: PacketPlayInFlying?) {
+
+ if (from.blockX == to.blockX && from.blockZ == to.blockZ) {
+ return
+ }
+
+ if (!this.instance.timerHandler.hasTimer(player.uniqueId,TimerType.RESPAWN)) {
+ return
+ }
+
+ val location = this.cache[player.uniqueId] ?: this.cache.putIfAbsent(player.uniqueId,from) ?: return
+
+ if (location.distance(to) < 25) {
+ return
+ }
+
+ player.teleport(from)
+ player.sendMessage("${ChatColor.RED}You cannot move more than 25 blocks from where you died.")
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/TimerListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/TimerListener.kt
new file mode 100644
index 0000000..3eafef9
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/timer/listener/TimerListener.kt
@@ -0,0 +1,64 @@
+package cc.fyre.bunkers.timer.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.timer.event.TimerCreateEvent
+import cc.fyre.bunkers.timer.event.TimerExtendEvent
+import cc.fyre.bunkers.timer.event.TimerRemoveEvent
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerQuitEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 23/12/2020
+ * @author xanderume@gmail.com
+ */
+class TimerListener(private val instance: Bunkers) :Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+
+ val timers = this.instance.timerHandler.cache[event.player.uniqueId] ?: return
+
+ //TODO timers.filter{it.type.icon != null}.forEach{LunarClientAPI.instance.packetHandler.sendPacket(event.player,CooldownPacket(it.type.icon!!,it.type.name,1L))}
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onTimerCreate(event: TimerCreateEvent) {
+
+ if (event.timer.type.icon == null) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(event.uuid) ?: return
+
+ //TODO LunarClientAPI.instance.packetHandler.sendPacket(player,CooldownPacket(event.timer.type.icon,event.timer.type.name,event.duration))
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onTimerRemove(event: TimerRemoveEvent) {
+
+ if (event.timer.type.icon == null) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(event.uuid) ?: return
+
+ //TODO LunarClientAPI.instance.packetHandler.sendPacket(player,CooldownPacket(event.timer.type.icon,event.timer.type.name,1L))
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onTimerExtend(event: TimerExtendEvent) {
+
+ if (event.timer.type.icon == null) {
+ return
+ }
+
+ val player = this.instance.server.getPlayer(event.uuid) ?: return
+
+ //TODO LunarClientAPI.instance.packetHandler.sendPacket(player,CooldownPacket(event.timer.type.icon,event.timer.type.name,event.newDuration))
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/VillagerHandler.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/VillagerHandler.kt
new file mode 100644
index 0000000..d974a79
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/VillagerHandler.kt
@@ -0,0 +1,136 @@
+package cc.fyre.bunkers.villager
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.villager.data.VillagerEntity
+import cc.fyre.bunkers.villager.listener.VillagerPacketListener
+import cc.fyre.bunkers.villager.data.kb.ZeroKBProfile
+import cc.fyre.bunkers.villager.listener.VillagerListener
+import cc.fyre.bunkers.villager.listener.VillagerLoggerListener
+import cc.fyre.bunkers.villager.service.VillagerLoggerService
+import com.comphenix.protocol.ProtocolLibrary
+import net.frozenorb.qlib.qLib
+import net.frozenorb.qlib.serialization.ItemStackAdapter
+import net.minecraft.server.v1_7_R4.EntityTypes
+import org.bukkit.ChatColor
+
+import org.bukkit.Location
+import org.bukkit.Material
+import org.bukkit.entity.Player
+import org.bukkit.inventory.ItemStack
+import org.bukkit.metadata.FixedMetadataValue
+import java.util.*
+
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+
+
+/**
+ * @project bunkers
+ *
+ * @date 03/08/2020
+ * @author xanderume@gmail.com
+ */
+class VillagerHandler(private val instance: Bunkers) {
+
+ val cache = HashSet()
+ val items = HashMap>()
+ val loggers = HashMap()
+ val services = HashMap()
+
+ init {
+ this.registerEntity(VillagerEntity::class.java,"Villager",120)
+
+ this.instance.server.pluginManager.registerEvents(VillagerListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(VillagerLoggerListener(this.instance),this.instance)
+
+ ProtocolLibrary.getProtocolManager().addPacketListener(VillagerPacketListener(this.instance))
+ }
+
+ fun spawnVillager(location: Location):VillagerEntity {
+
+ if (!location.chunk.isLoaded) {
+ location.chunk.load()
+ }
+
+ val villager = VillagerEntity(location)
+
+ villager.setLocation(location.x,location.y,location.z,(location.yaw * 256.0f / 360.0f),(location.pitch * 256.0f / 360.0f))
+ villager.setPosition(location.x,location.y,location.z)
+
+ val result = villager.world.addEntity(villager)
+
+ if (!result) {
+ this.instance.server.logger.info("Failed to spawn villager.")
+ }
+
+ villager.k = false
+ villager.fromMobSpawner = true
+
+ villager.health = villager.maxHealth
+ villager.kbProfile = KB_PROFILE
+
+ this.cache.add(villager)
+
+ return villager
+ }
+
+ fun spawnCombatLogger(location: Location,player: Player) {
+
+ val villager = this.spawnVillager(location)
+
+ villager.customName = "${ChatColor.GRAY}(Combat-Logger)${this.instance.teamHandler.findById(player.uniqueId)?.getColor() ?: ChatColor.WHITE} ${player.name}"
+ villager.customNameVisible = true
+
+ val items = ArrayList()
+
+ items.addAll(player.inventory.contents.filterNotNull().filter{it.type != Material.AIR})
+ items.addAll(player.inventory.armorContents.filterNotNull().filter{it.type != Material.AIR})
+
+ villager.bukkitEntity.setMetadata(LOGGER_OWNER_METADATA,FixedMetadataValue(this.instance,player.uniqueId.toString()))
+ villager.bukkitEntity.setMetadata(LOGGER_ITEMS_METADATA,FixedMetadataValue(this.instance,qLib.GSON.toJson(items,ItemStackAdapter::class.java)))
+
+ this.items[player.uniqueId] = player.inventory.contents.plus(player.inventory.armorContents).filterNotNull().filter{it.type != Material.AIR}.toTypedArray()
+ this.loggers[player.uniqueId] = villager
+
+ val service = VillagerLoggerService(player.uniqueId,villager)
+
+ service.runTaskTimer(this.instance,20L,20L)
+
+ this.services[player.uniqueId] = service
+ }
+
+ private fun registerEntity(entityClass: Class<*>, name: String, id: Int) {
+ this.setFieldPrivateStaticMap("d",entityClass,name)
+ this.setFieldPrivateStaticMap("f",entityClass,Integer.valueOf(id))
+ }
+
+ private fun setFieldPrivateStaticMap(fieldName: String, key: Any, value: Any) {
+
+ try {
+ val field = EntityTypes::class.java.getDeclaredField(fieldName)
+ field.isAccessible = true
+ val map = field.get(null) as HashMap
+ map[key] = value
+ field.set(null, map)
+ } catch (ex: SecurityException) {
+ ex.printStackTrace()
+ } catch (ex: IllegalArgumentException) {
+ ex.printStackTrace()
+ } catch (ex: IllegalAccessException) {
+ ex.printStackTrace()
+ } catch (ex: NoSuchFieldException) {
+ ex.printStackTrace()
+ }
+
+ }
+
+ companion object {
+
+ val KB_PROFILE = ZeroKBProfile()
+
+ const val LOGGER_OWNER_METADATA = "LOGGER_OWNER"
+ const val LOGGER_ITEMS_METADATA = "LOGGER_ITEMS"
+
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/data/VillagerEntity.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/data/VillagerEntity.kt
new file mode 100644
index 0000000..ed2d1c0
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/data/VillagerEntity.kt
@@ -0,0 +1,29 @@
+package cc.fyre.bunkers.villager.data
+
+import net.minecraft.server.v1_7_R4.DamageSource
+import net.minecraft.server.v1_7_R4.Entity
+import net.minecraft.server.v1_7_R4.EntityAgeable
+import net.minecraft.server.v1_7_R4.EntityVillager
+import org.bukkit.Location
+import org.bukkit.craftbukkit.v1_7_R4.CraftWorld
+
+/**
+ * @project bunkers
+ *
+ * @date 16/08/2020
+ * @author xanderume@gmail.com
+ */
+class VillagerEntity(location: Location):EntityVillager((location.world as CraftWorld).handle) {
+
+ override fun move(x: Double,y: Double,z: Double) {}
+ override fun collide(entity: Entity?) {}
+ override fun g(d0: Double, d1: Double, d2: Double) {}
+
+ override fun dropDeathLoot(flag: Boolean, i: Int) {}
+ override fun createChild(entity: EntityAgeable?): EntityAgeable? = null
+
+ override fun damageEntity(damagesource: DamageSource,float: Float): Boolean {
+ return super.damageEntity(damagesource,float / 2.5F)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/data/kb/ZeroKBProfile.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/data/kb/ZeroKBProfile.kt
new file mode 100644
index 0000000..88a32a5
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/data/kb/ZeroKBProfile.kt
@@ -0,0 +1,72 @@
+package cc.fyre.bunkers.villager.data.kb
+
+import net.hylist.knockback.KnockbackProfile
+
+/**
+ * @project bunkers
+ *
+ * @date 17/08/2020
+ * @author xanderume@gmail.com
+ */
+class ZeroKBProfile : KnockbackProfile {
+
+ private val name = "Zero"
+ private var friction = 2.0
+ private var vertical = 0.0
+ private var horizontal = 0.0
+ private var verticalLimit = 0.0
+ private var extraVertical = 0.0
+ private var extraHorizontal = 0.0
+
+ override fun getName():String {
+ return name
+ }
+
+ override fun getFriction(): Double {
+ return friction
+ }
+
+ override fun setFriction(friction: Double) {
+ this.friction = friction
+ }
+
+ override fun getHorizontal(): Double {
+ return horizontal
+ }
+
+ override fun setHorizontal(horizontal: Double) {
+ this.horizontal = horizontal
+ }
+
+ override fun getVertical(): Double {
+ return vertical
+ }
+
+ override fun setVertical(vertical: Double) {
+ this.vertical = vertical
+ }
+
+ override fun getVerticalLimit(): Double {
+ return verticalLimit
+ }
+
+ override fun setVerticalLimit(verticalLimit: Double) {
+ this.verticalLimit = verticalLimit
+ }
+
+ override fun getExtraHorizontal(): Double {
+ return extraHorizontal
+ }
+
+ override fun setExtraHorizontal(extraHorizontal: Double) {
+ this.extraHorizontal = extraHorizontal
+ }
+
+ override fun getExtraVertical(): Double {
+ return extraVertical
+ }
+
+ override fun setExtraVertical(extraVertical: Double) {
+ this.extraVertical = extraVertical
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerListener.kt
new file mode 100644
index 0000000..dd51758
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerListener.kt
@@ -0,0 +1,39 @@
+package cc.fyre.bunkers.villager.listener
+
+import cc.fyre.bunkers.Bunkers
+import org.bukkit.entity.Villager
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.PotionEffectAddEvent
+import org.bukkit.event.world.ChunkUnloadEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 18/08/2020
+ * @author xanderume@gmail.com
+ */
+class VillagerListener(private val instance: Bunkers):Listener {
+
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onChunkUnLoad(event: ChunkUnloadEvent) {
+
+ if (this.instance.villagerHandler.cache.none{event.chunk.entities.firstOrNull{entity -> entity.uniqueId == it.uniqueID} != null}) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPotionEffectAdd(event: PotionEffectAddEvent) {
+
+ if (event.entity !is Villager) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerLoggerListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerLoggerListener.kt
new file mode 100644
index 0000000..a3ca61c
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerLoggerListener.kt
@@ -0,0 +1,134 @@
+package cc.fyre.bunkers.villager.listener
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.statistic.StatisticHandler
+import cc.fyre.bunkers.timer.data.TimerType
+import cc.fyre.bunkers.villager.VillagerHandler
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.util.UUIDUtils
+
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import org.bukkit.entity.Villager
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.entity.EntityDeathEvent
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerQuitEvent
+import java.util.*
+
+/**
+ * @project bunkers
+ *
+ * @date 18/08/2020
+ * @author xanderume@gmail.com
+ */
+class VillagerLoggerListener(private val instance: Bunkers) : Listener {
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+
+ if (!GameEngine.instance.gameHandler.isPlaying(event.player)) {
+ return
+ }
+
+ if (GameEngine.instance.gameHandler.getState() != GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ this.instance.villagerHandler.spawnCombatLogger(event.player.location,event.player)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDeath(event: EntityDeathEvent) {
+
+ if (event.entity !is Villager) {
+ return
+ }
+
+ if (!event.entity.hasMetadata(VillagerHandler.LOGGER_OWNER_METADATA) || !event.entity.hasMetadata(VillagerHandler.LOGGER_ITEMS_METADATA)) {
+ return
+ }
+
+ val uuid = UUID.fromString(event.entity.getMetadata(VillagerHandler.LOGGER_OWNER_METADATA)[0].asString()) ?: return
+
+
+ val items = this.instance.villagerHandler.items.remove(uuid)
+
+ if (items != null) {
+ event.drops.clear()
+ event.drops.addAll(items)
+ }
+
+ this.instance.villagerHandler.loggers.remove(uuid)
+
+ val team = this.instance.teamHandler.findById(uuid) ?: return
+ val name = UUIDUtils.name(uuid)
+
+ if (event.entity.killer != null) {
+
+ val balance = this.instance.statisticHandler.getBalance(event.entity.uniqueId)
+
+ this.instance.statisticHandler.addKills(event.entity.killer.uniqueId,1)
+ this.instance.statisticHandler.addBalance(event.entity.killer.uniqueId,if (balance >= StatisticHandler.BALANCE_PER_KILL) StatisticHandler.BALANCE_PER_KILL else balance)
+
+ event.entity.killer.sendMessage("${ChatColor.GOLD}You earned ${ChatColor.WHITE}$${if (balance >= StatisticHandler.BALANCE_PER_KILL) StatisticHandler.BALANCE_PER_KILL else balance}.0${ChatColor.GOLD} for killing ${team.type.color}$name${ChatColor.GOLD}!")
+ }
+
+ team.dtr -= 1.0
+ team.sendMessage("${ChatColor.RED}Member Death: ${ChatColor.WHITE}$name","${ChatColor.RED}DTR: ${ChatColor.WHITE}${team.getDTR()}")
+
+ event.entity.world.strikeLightningEffect(event.entity.location)
+ event.drops.removeIf{it.hasItemMeta() && it.itemMeta.hasLore() && ChatColor.stripColor(it.itemMeta.lore[0]).equals("Soulbound",true)}
+
+ if (!team.isRaidable()) {
+ this.instance.timerHandler.addTimer(uuid,TimerType.RESPAWN)
+ this.instance.timerHandler.setPaused(uuid,TimerType.RESPAWN,true)
+ }
+
+ this.instance.server.broadcastMessage("${team.getColor()}$name${ChatColor.GOLD}[${this.instance.statisticHandler.getKills(uuid)}] ${ChatColor.YELLOW}${if (event.entity.killer == null) "died" else "was slain by ${this.instance.teamHandler.findById(event.entity.killer.uniqueId)?.getColor() ?: ChatColor.WHITE}${event.entity.killer.name}${ChatColor.GOLD}[${this.instance.statisticHandler.getKills(event.entity.killer.uniqueId)}]"}${ChatColor.YELLOW}.")
+
+ this.instance.statisticHandler.addDeaths(uuid,1)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDamage(event: EntityDamageByEntityEvent) {
+
+ if (event.entity !is Villager) {
+ return
+ }
+
+ if (!event.entity.hasMetadata(VillagerHandler.LOGGER_OWNER_METADATA)) {
+ return
+ }
+
+ val uuid = UUID.fromString(event.entity.getMetadata(VillagerHandler.LOGGER_OWNER_METADATA)[0].asString()) ?: return
+
+ if (event.damager !is Player) {
+ return
+ }
+
+ val team = this.instance.teamHandler.findById(event.damager.uniqueId) ?: return
+
+ if (!team.isMember(uuid)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ val villager = this.instance.villagerHandler.loggers.remove(event.player.uniqueId) ?: return
+
+ villager.bukkitEntity.remove()
+
+ this.instance.villagerHandler.services.remove(event.player.uniqueId)
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerPacketListener.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerPacketListener.kt
new file mode 100644
index 0000000..eb0d6eb
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/listener/VillagerPacketListener.kt
@@ -0,0 +1,31 @@
+package cc.fyre.bunkers.villager.listener
+
+import cc.fyre.bunkers.Bunkers
+import com.comphenix.protocol.PacketType
+import com.comphenix.protocol.events.PacketAdapter
+import com.comphenix.protocol.events.PacketEvent
+
+/**
+ * @project bunkers
+ *
+ * @date 08/08/2020
+ * @author xanderume@gmail.com
+ */
+class VillagerPacketListener(instance: Bunkers) : PacketAdapter(instance,PacketType.Play.Server.NAMED_SOUND_EFFECT) {
+
+ override fun onPacketSending(event: PacketEvent) {
+
+ val name = event.packet.strings.read(0)
+
+ if (!name.startsWith("MOB.VILLAGER",true)) {
+ return
+ }
+
+ if (name.endsWith("DEATH",true) || name.endsWith("HIT",true)) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/service/VillagerLoggerService.kt b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/service/VillagerLoggerService.kt
new file mode 100644
index 0000000..e9f7d90
--- /dev/null
+++ b/Bunkers/src/main/kotlin/cc/fyre/bunkers/villager/service/VillagerLoggerService.kt
@@ -0,0 +1,38 @@
+package cc.fyre.bunkers.villager.service
+
+import cc.fyre.bunkers.Bunkers
+import cc.fyre.bunkers.villager.data.VillagerEntity
+import org.bukkit.ChatColor
+import org.bukkit.scheduler.BukkitRunnable
+import java.util.*
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * @project bunkers
+ *
+ * @date 19/08/2020
+ * @author xanderume@gmail.com
+ */
+class VillagerLoggerService(private val uuid: UUID,private val villager: VillagerEntity):BukkitRunnable() {
+
+ private val name = this.villager.customName
+ private val remaining = AtomicInteger(25)
+
+ override fun run() {
+
+ if (this.remaining.get() == 0 || this.villager.bukkitEntity.isDead) {
+ this.cancel()
+
+ if (!this.villager.bukkitEntity.isDead) {
+ this.villager.bukkitEntity.remove()
+ }
+
+ Bunkers.instance.villagerHandler.loggers.remove(this.uuid)
+ Bunkers.instance.villagerHandler.services.remove(this.uuid)
+ return
+ }
+
+ this.villager.customName = "${this.name}${ChatColor.YELLOW} (${this.remaining.decrementAndGet()}s)"
+ }
+
+}
\ No newline at end of file
diff --git a/Bunkers/src/main/resources/plugin.yml b/Bunkers/src/main/resources/plugin.yml
new file mode 100644
index 0000000..8009c4e
--- /dev/null
+++ b/Bunkers/src/main/resources/plugin.yml
@@ -0,0 +1,4 @@
+name: Bunkers
+main: cc.fyre.bunkers.Bunkers
+version: 1.0-SNAPSHOT
+depend: [qLib,GameEngine]
diff --git a/Engine/.gradle/6.8/executionHistory/executionHistory.bin b/Engine/.gradle/6.8/executionHistory/executionHistory.bin
new file mode 100644
index 0000000..2a7f4a9
Binary files /dev/null and b/Engine/.gradle/6.8/executionHistory/executionHistory.bin differ
diff --git a/Engine/.gradle/6.8/executionHistory/executionHistory.lock b/Engine/.gradle/6.8/executionHistory/executionHistory.lock
new file mode 100644
index 0000000..0f66333
Binary files /dev/null and b/Engine/.gradle/6.8/executionHistory/executionHistory.lock differ
diff --git a/Engine/.gradle/6.8/fileChanges/last-build.bin b/Engine/.gradle/6.8/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/Engine/.gradle/6.8/fileChanges/last-build.bin differ
diff --git a/Engine/.gradle/6.8/fileHashes/fileHashes.bin b/Engine/.gradle/6.8/fileHashes/fileHashes.bin
new file mode 100644
index 0000000..852db5c
Binary files /dev/null and b/Engine/.gradle/6.8/fileHashes/fileHashes.bin differ
diff --git a/Engine/.gradle/6.8/fileHashes/fileHashes.lock b/Engine/.gradle/6.8/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..12cd5ba
Binary files /dev/null and b/Engine/.gradle/6.8/fileHashes/fileHashes.lock differ
diff --git a/Engine/.gradle/6.8/fileHashes/resourceHashesCache.bin b/Engine/.gradle/6.8/fileHashes/resourceHashesCache.bin
new file mode 100644
index 0000000..1de7ada
Binary files /dev/null and b/Engine/.gradle/6.8/fileHashes/resourceHashesCache.bin differ
diff --git a/Engine/.gradle/6.8/gc.properties b/Engine/.gradle/6.8/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/Engine/.gradle/6.8/javaCompile/classAnalysis.bin b/Engine/.gradle/6.8/javaCompile/classAnalysis.bin
new file mode 100644
index 0000000..44acf1c
Binary files /dev/null and b/Engine/.gradle/6.8/javaCompile/classAnalysis.bin differ
diff --git a/Engine/.gradle/6.8/javaCompile/jarAnalysis.bin b/Engine/.gradle/6.8/javaCompile/jarAnalysis.bin
new file mode 100644
index 0000000..eadaf17
Binary files /dev/null and b/Engine/.gradle/6.8/javaCompile/jarAnalysis.bin differ
diff --git a/Engine/.gradle/6.8/javaCompile/javaCompile.lock b/Engine/.gradle/6.8/javaCompile/javaCompile.lock
new file mode 100644
index 0000000..a0e2e52
Binary files /dev/null and b/Engine/.gradle/6.8/javaCompile/javaCompile.lock differ
diff --git a/Engine/.gradle/6.8/javaCompile/taskHistory.bin b/Engine/.gradle/6.8/javaCompile/taskHistory.bin
new file mode 100644
index 0000000..a0c8d58
Binary files /dev/null and b/Engine/.gradle/6.8/javaCompile/taskHistory.bin differ
diff --git a/Engine/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Engine/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..7a0a825
Binary files /dev/null and b/Engine/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/Engine/.gradle/buildOutputCleanup/cache.properties b/Engine/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..6ac1877
--- /dev/null
+++ b/Engine/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Sat Jul 24 19:59:35 CEST 2021
+gradle.version=6.8
diff --git a/Engine/.gradle/buildOutputCleanup/outputFiles.bin b/Engine/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 0000000..587526c
Binary files /dev/null and b/Engine/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/Engine/.gradle/checksums/checksums.lock b/Engine/.gradle/checksums/checksums.lock
new file mode 100644
index 0000000..116a215
Binary files /dev/null and b/Engine/.gradle/checksums/checksums.lock differ
diff --git a/Engine/.gradle/checksums/md5-checksums.bin b/Engine/.gradle/checksums/md5-checksums.bin
new file mode 100644
index 0000000..6fbe53d
Binary files /dev/null and b/Engine/.gradle/checksums/md5-checksums.bin differ
diff --git a/Engine/.gradle/checksums/sha1-checksums.bin b/Engine/.gradle/checksums/sha1-checksums.bin
new file mode 100644
index 0000000..5875ba7
Binary files /dev/null and b/Engine/.gradle/checksums/sha1-checksums.bin differ
diff --git a/Engine/.gradle/configuration-cache/gc.properties b/Engine/.gradle/configuration-cache/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/Engine/.gradle/vcs-1/gc.properties b/Engine/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/Engine/.idea/.gitignore b/Engine/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/Engine/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/Engine/.idea/compiler.xml b/Engine/.idea/compiler.xml
new file mode 100644
index 0000000..61a9130
--- /dev/null
+++ b/Engine/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Engine/.idea/gradle.xml b/Engine/.idea/gradle.xml
new file mode 100644
index 0000000..9c628f0
--- /dev/null
+++ b/Engine/.idea/gradle.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Engine/.idea/jarRepositories.xml b/Engine/.idea/jarRepositories.xml
new file mode 100644
index 0000000..55f1d4b
--- /dev/null
+++ b/Engine/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Engine/.idea/libraries-with-intellij-classes.xml b/Engine/.idea/libraries-with-intellij-classes.xml
new file mode 100644
index 0000000..9fa3156
--- /dev/null
+++ b/Engine/.idea/libraries-with-intellij-classes.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Engine/.idea/misc.xml b/Engine/.idea/misc.xml
new file mode 100644
index 0000000..b0051c8
--- /dev/null
+++ b/Engine/.idea/misc.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Engine/api/build.gradle b/Engine/api/build.gradle
new file mode 100644
index 0000000..deec761
--- /dev/null
+++ b/Engine/api/build.gradle
@@ -0,0 +1,50 @@
+plugins {
+ id "org.jetbrains.kotlin.jvm" version "1.5.0"
+ id "com.github.johnrengelman.shadow" version "5.2.0"
+ id "com.gorylenko.gradle-git-properties" version "2.2.2"
+}
+
+targetCompatibility = '1.8'
+sourceCompatibility = '1.8'
+
+shadowJar {
+ classifier = null
+ minimize()
+ archiveName = "engine-" + this.name + "-" + this.version + ".jar"
+}
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+}
+
+dependencies {
+ compile "com.google.code.gson:gson:2.8.5"
+ compile "cc.fyre.symbiote:symbiote:1.0-SNAPSHOT"
+ compile "org.mongodb:mongo-java-driver:3.10.2"
+
+ compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.0"
+}
+
+apply plugin: "kotlin"
+apply plugin: 'maven-publish'
+
+compileKotlin {
+ kotlinOptions.jvmTarget = '1.8'
+}
+
+sourceSets {
+ main.java.srcDirs += 'src/main/kotlin/'
+}
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
+
+publishing {
+ publications {
+ shadow(MavenPublication) { publication ->
+ project.shadow.component(publication)
+ }
+ }
+}
diff --git a/Engine/api/build/classes/kotlin/main/META-INF/api.kotlin_module b/Engine/api/build/classes/kotlin/main/META-INF/api.kotlin_module
new file mode 100644
index 0000000..70f0f69
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/META-INF/api.kotlin_module differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI$Companion.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI$Companion.class
new file mode 100644
index 0000000..53080cf
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI$Companion.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI$GameMode.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI$GameMode.class
new file mode 100644
index 0000000..01ace4e
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI$GameMode.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI.class
new file mode 100644
index 0000000..56b1350
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/GameEngineAPI.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/database/DatabaseHandler.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/database/DatabaseHandler.class
new file mode 100644
index 0000000..e9dd2a8
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/database/DatabaseHandler.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/GameDataHandler.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/GameDataHandler.class
new file mode 100644
index 0000000..f3c87dc
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/GameDataHandler.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/Game.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/Game.class
new file mode 100644
index 0000000..2c8e2bb
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/Game.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/type/BunkersGame$Team.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/type/BunkersGame$Team.class
new file mode 100644
index 0000000..47c40e0
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/type/BunkersGame$Team.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/type/BunkersGame.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/type/BunkersGame.class
new file mode 100644
index 0000000..64c3c0f
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/game/data/type/BunkersGame.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/ProfileHandler.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/ProfileHandler.class
new file mode 100644
index 0000000..eeadece
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/ProfileHandler.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/Profile.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/Profile.class
new file mode 100644
index 0000000..233f772
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/Profile.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$Ore.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$Ore.class
new file mode 100644
index 0000000..5e31b6c
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$Ore.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$PvPClass.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$PvPClass.class
new file mode 100644
index 0000000..c12599f
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$PvPClass.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$getPrimaryClass$$inlined$sortedByDescending$1.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$getPrimaryClass$$inlined$sortedByDescending$1.class
new file mode 100644
index 0000000..b511ae2
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile$getPrimaryClass$$inlined$sortedByDescending$1.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile.class
new file mode 100644
index 0000000..2d3fc06
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/profile/data/type/BunkersProfile.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/GameServerHandler.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/GameServerHandler.class
new file mode 100644
index 0000000..7b62550
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/GameServerHandler.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer$Companion.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer$Companion.class
new file mode 100644
index 0000000..c56fd16
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer$Companion.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer$State.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer$State.class
new file mode 100644
index 0000000..bc01de3
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer$State.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer.class
new file mode 100644
index 0000000..c7dc8ef
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/data/GameServer.class differ
diff --git a/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/listener/GameServerListener.class b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/listener/GameServerListener.class
new file mode 100644
index 0000000..fd8f0ee
Binary files /dev/null and b/Engine/api/build/classes/kotlin/main/cc/fyre/engine/server/listener/GameServerListener.class differ
diff --git a/Engine/api/build/kotlin/api10SNAPSHOTjar-classes.txt b/Engine/api/build/kotlin/api10SNAPSHOTjar-classes.txt
new file mode 100644
index 0000000..c8147cc
--- /dev/null
+++ b/Engine/api/build/kotlin/api10SNAPSHOTjar-classes.txt
@@ -0,0 +1 @@
+C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\GameEngineAPI$Companion.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\GameEngineAPI$GameMode.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\GameEngineAPI.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\database\DatabaseHandler.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\game\GameDataHandler.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\game\data\Game.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\game\data\type\BunkersGame$Team.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\game\data\type\BunkersGame.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\profile\ProfileHandler.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\profile\data\Profile.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\profile\data\type\BunkersProfile$Ore.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\profile\data\type\BunkersProfile$PvPClass.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\profile\data\type\BunkersProfile$getPrimaryClass$$inlined$sortedByDescending$1.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\profile\data\type\BunkersProfile.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\server\GameServerHandler.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\server\data\GameServer$Companion.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\server\data\GameServer$State.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\server\data\GameServer.class;C:\Users\xande\Documents\fyre\$$$\engine\api\build\classes\kotlin\main\cc\fyre\engine\server\listener\GameServerListener.class
\ No newline at end of file
diff --git a/Engine/api/build/kotlin/compileKotlin/build-history.bin b/Engine/api/build/kotlin/compileKotlin/build-history.bin
new file mode 100644
index 0000000..97a0c2a
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/build-history.bin differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab
new file mode 100644
index 0000000..6d19f40
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream
new file mode 100644
index 0000000..6e6c7ae
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len
new file mode 100644
index 0000000..e4e877d
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len
new file mode 100644
index 0000000..a541356
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at
new file mode 100644
index 0000000..89ee2b2
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i
new file mode 100644
index 0000000..c2815c5
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab
new file mode 100644
index 0000000..d7c064c
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream
new file mode 100644
index 0000000..3bcecf0
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len
new file mode 100644
index 0000000..0cfcfa1
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len
new file mode 100644
index 0000000..09407ef
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at
new file mode 100644
index 0000000..10e3b98
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i
new file mode 100644
index 0000000..e041941
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab
new file mode 100644
index 0000000..15f271d
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream
new file mode 100644
index 0000000..3bcecf0
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len
new file mode 100644
index 0000000..0cfcfa1
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len
new file mode 100644
index 0000000..09407ef
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at
new file mode 100644
index 0000000..336cce7
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i
new file mode 100644
index 0000000..e041941
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab
new file mode 100644
index 0000000..4b73c71
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream
new file mode 100644
index 0000000..0128bd2
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len
new file mode 100644
index 0000000..a57f5a0
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len
new file mode 100644
index 0000000..01bdaa1
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at
new file mode 100644
index 0000000..a4566aa
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i
new file mode 100644
index 0000000..c72edd8
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab
new file mode 100644
index 0000000..57aac3b
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream
new file mode 100644
index 0000000..01e4cca
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len
new file mode 100644
index 0000000..7b79156
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len
new file mode 100644
index 0000000..14f7c06
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at
new file mode 100644
index 0000000..ef6c15f
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i
new file mode 100644
index 0000000..70f1223
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab
new file mode 100644
index 0000000..4c4c4d1
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream
new file mode 100644
index 0000000..ddb6974
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len
new file mode 100644
index 0000000..f6ed631
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len
new file mode 100644
index 0000000..14f7c06
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at
new file mode 100644
index 0000000..7f83a18
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i
new file mode 100644
index 0000000..fc8bd6e
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab
new file mode 100644
index 0000000..5ba5a2c
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream
new file mode 100644
index 0000000..150935c
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len
new file mode 100644
index 0000000..e4e877d
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len
new file mode 100644
index 0000000..a541356
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at
new file mode 100644
index 0000000..380dcb9
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i
new file mode 100644
index 0000000..dcf34ac
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab
new file mode 100644
index 0000000..8a5cd75
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream
new file mode 100644
index 0000000..f078d91
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len
new file mode 100644
index 0000000..a196eeb
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len
new file mode 100644
index 0000000..93a595b
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at
new file mode 100644
index 0000000..d8e4d80
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i
new file mode 100644
index 0000000..55ac800
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab
new file mode 100644
index 0000000..34ab339
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream
new file mode 100644
index 0000000..1ce991a
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len
new file mode 100644
index 0000000..1b6e45b
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len
new file mode 100644
index 0000000..817b326
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at
new file mode 100644
index 0000000..f86de80
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i
new file mode 100644
index 0000000..0ff8a94
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab
new file mode 100644
index 0000000..feef2d8
--- /dev/null
+++ b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab
@@ -0,0 +1,2 @@
+18
+7
\ No newline at end of file
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab
new file mode 100644
index 0000000..0f127d8
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream
new file mode 100644
index 0000000..150935c
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len
new file mode 100644
index 0000000..e4e877d
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len
new file mode 100644
index 0000000..a541356
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at
new file mode 100644
index 0000000..5b7bdc3
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i
new file mode 100644
index 0000000..b857bf8
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab
new file mode 100644
index 0000000..fa0732c
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream
new file mode 100644
index 0000000..99cb6e9
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len
new file mode 100644
index 0000000..c54fd0d
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len
new file mode 100644
index 0000000..09407ef
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at
new file mode 100644
index 0000000..3d17800
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i
new file mode 100644
index 0000000..504f86b
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab
new file mode 100644
index 0000000..06489b4
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream
new file mode 100644
index 0000000..b36b9ce
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len
new file mode 100644
index 0000000..2a793c1
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len
new file mode 100644
index 0000000..af35e75
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at
new file mode 100644
index 0000000..e9849ac
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i
new file mode 100644
index 0000000..46d05b3
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i differ
diff --git a/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len differ
diff --git a/Engine/api/build/kotlin/compileKotlin/last-build.bin b/Engine/api/build/kotlin/compileKotlin/last-build.bin
new file mode 100644
index 0000000..0d0a325
Binary files /dev/null and b/Engine/api/build/kotlin/compileKotlin/last-build.bin differ
diff --git a/Engine/api/build/libs/api-1.0-SNAPSHOT.jar b/Engine/api/build/libs/api-1.0-SNAPSHOT.jar
new file mode 100644
index 0000000..07289f9
Binary files /dev/null and b/Engine/api/build/libs/api-1.0-SNAPSHOT.jar differ
diff --git a/Engine/api/build/libs/engine-api-1.0-SNAPSHOT.jar b/Engine/api/build/libs/engine-api-1.0-SNAPSHOT.jar
new file mode 100644
index 0000000..be33b51
Binary files /dev/null and b/Engine/api/build/libs/engine-api-1.0-SNAPSHOT.jar differ
diff --git a/Engine/api/build/publications/shadow/pom-default.xml b/Engine/api/build/publications/shadow/pom-default.xml
new file mode 100644
index 0000000..67a1f01
--- /dev/null
+++ b/Engine/api/build/publications/shadow/pom-default.xml
@@ -0,0 +1,8 @@
+
+
+ 4.0.0
+ cc.fyre.engine
+ api
+ 1.0-SNAPSHOT
+
+
diff --git a/Engine/api/build/resources/main/git.properties b/Engine/api/build/resources/main/git.properties
new file mode 100644
index 0000000..966753a
--- /dev/null
+++ b/Engine/api/build/resources/main/git.properties
@@ -0,0 +1,19 @@
+git.branch=
+git.build.host=IMAGESE-432HNTP
+git.build.user.email=xanderume@gmail.com
+git.build.user.name=xander
+git.build.version=1.0-SNAPSHOT
+git.closest.tag.commit.count=
+git.closest.tag.name=
+git.commit.id=
+git.commit.id.abbrev=
+git.commit.id.describe=
+git.commit.message.full=
+git.commit.message.short=
+git.commit.time=
+git.commit.user.email=
+git.commit.user.name=
+git.dirty=true
+git.remote.origin.url=
+git.tags=
+git.total.commit.count=0
diff --git a/Engine/api/build/tmp/jar/MANIFEST.MF b/Engine/api/build/tmp/jar/MANIFEST.MF
new file mode 100644
index 0000000..59499bc
--- /dev/null
+++ b/Engine/api/build/tmp/jar/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/Engine/api/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml b/Engine/api/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml
new file mode 100644
index 0000000..5b12c54
--- /dev/null
+++ b/Engine/api/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml
@@ -0,0 +1,12 @@
+
+
+ cc.fyre.engine
+ api
+
+ 1.0-SNAPSHOT
+
+ 1.0-SNAPSHOT
+
+ 20210725122141
+
+
diff --git a/Engine/api/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml b/Engine/api/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml
new file mode 100644
index 0000000..6869382
--- /dev/null
+++ b/Engine/api/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml
@@ -0,0 +1,24 @@
+
+
+ cc.fyre.engine
+ api
+ 1.0-SNAPSHOT
+
+
+ true
+
+ 20210725122141
+
+
+ pom
+ 1.0-SNAPSHOT
+ 20210725122141
+
+
+ jar
+ 1.0-SNAPSHOT
+ 20210725122141
+
+
+
+
diff --git a/Engine/api/build/tmp/shadowJar/MANIFEST.MF b/Engine/api/build/tmp/shadowJar/MANIFEST.MF
new file mode 100644
index 0000000..59499bc
--- /dev/null
+++ b/Engine/api/build/tmp/shadowJar/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/GameEngineAPI.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/GameEngineAPI.kt
new file mode 100644
index 0000000..161399f
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/GameEngineAPI.kt
@@ -0,0 +1,76 @@
+package cc.fyre.engine
+
+import cc.fyre.engine.database.DatabaseHandler
+import cc.fyre.engine.game.GameDataHandler
+import cc.fyre.engine.game.data.type.BunkersGame
+import cc.fyre.engine.profile.ProfileHandler
+import cc.fyre.engine.profile.data.type.BunkersProfile
+import cc.fyre.engine.server.GameServerHandler
+
+import com.google.gson.GsonBuilder
+import com.google.gson.LongSerializationPolicy
+import org.bson.json.JsonMode
+import org.bson.json.JsonWriterSettings
+import java.io.File
+
+/**
+ * @project engine
+ *
+ * @date 10/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameEngineAPI(val mode: GameMode) {
+
+ val gson = GsonBuilder().create()
+
+ val databaseHandler = DatabaseHandler(this)
+
+ val gameDataHandler = GameDataHandler(this)
+ val gameServerHandler = GameServerHandler(this)
+
+ val profileHandler = this.loadProfileHandler()
+
+ fun dispose() {
+ this.databaseHandler.dispose()
+ }
+
+ private fun loadProfileHandler():ProfileHandler<*> {
+
+ if (this.mode == GameMode.BUNKERS) {
+ return ProfileHandler(this)
+ }
+
+ return ProfileHandler(this)
+ }
+
+ enum class GameMode(val season: Int,
+ val displayName: String,
+ val mongoDB: String,
+ val redisDB: String,
+ val lobbyServer: String,
+ val prefix: String,
+ val requiredQueueSize: Int,
+ val requiredDuelSize: Int,
+ val mapBased: Boolean,
+ val spectatable: Boolean,
+ val disqualifies: Boolean,
+ val clazz: Class<*>,
+ val profileClazz: Class<*>,
+ val idPath: String) {
+
+ BUNKERS(3,"Bunkers","bunkers","bunkers","Bunkers-Lobby","§7[§c§lBunkers§7]",20,3,true,true,true,BunkersGame::class.java,BunkersProfile::class.java,"teams.players")
+
+ }
+
+ companion object {
+
+ val PARENT_DIRECTORY = File("/home/engine/")
+
+ const val GAME_DATA_PACKET = "GAME_DATA"
+ const val GAME_SEND_PACKET = "GAME_SEND"
+ const val GAME_SENT_PACKET = "GAME_SENT"
+
+ val JSON_WRITER_SETTINGS: JsonWriterSettings = JsonWriterSettings.builder().outputMode(JsonMode.RELAXED).build()
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/database/DatabaseHandler.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/database/DatabaseHandler.kt
new file mode 100644
index 0000000..253e009
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/database/DatabaseHandler.kt
@@ -0,0 +1,35 @@
+package cc.fyre.engine.database
+
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.symbiote.SymbioteAPI
+import cc.fyre.symbiote.type.RedisSymbioteAPI
+import com.mongodb.MongoClient
+import com.mongodb.ServerAddress
+import com.mongodb.client.MongoDatabase
+
+import redis.clients.jedis.JedisPool
+
+/**
+ * @project bunkers
+ *
+ * @date 30/07/2020
+ * @author xanderume@gmail.com
+ */
+class DatabaseHandler(private val instance: GameEngineAPI) {
+
+ val symbiote: SymbioteAPI
+
+ val mongoDB: MongoDatabase
+ val mongoPool = MongoClient(ServerAddress("localhost",27017))
+ val redisPool = JedisPool("localhost",6379)
+
+ init {
+ this.mongoDB = this.mongoPool.getDatabase(this.instance.mode.mongoDB)
+ this.symbiote = RedisSymbioteAPI(this.instance.gson,this.redisPool,this.instance.mode.redisDB)
+ }
+
+ fun dispose() {
+ this.redisPool.close()
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/game/GameDataHandler.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/game/GameDataHandler.kt
new file mode 100644
index 0000000..fb2d861
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/game/GameDataHandler.kt
@@ -0,0 +1,85 @@
+package cc.fyre.engine.game
+
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.game.data.Game
+import com.mongodb.client.MongoCollection
+import com.mongodb.client.model.Filters
+import com.mongodb.client.model.UpdateOptions
+import com.mongodb.client.result.UpdateResult
+import org.bson.Document
+import java.util.*
+import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
+
+/**
+ * @project engine
+ *
+ * @date 17/12/2020
+ * @author xanderume@gmail.com
+ */
+class GameDataHandler(private val instance: GameEngineAPI) {
+
+ val collection: MongoCollection
+ val collections = hashMapOf>()
+
+ init {
+
+ for (i in 1..this.instance.mode.season) {
+ this.collections[i] = this.instance.databaseHandler.mongoDB.getCollection("games${if (i == 1) "" else "$i"}")
+ }
+
+ this.collection = this.collections[this.instance.mode.season]!!
+ }
+
+ private fun getCollection(season: Int):MongoCollection {
+ return this.collections.getOrPut(season) { this.instance.databaseHandler.mongoDB.getCollection("games$season") }
+ }
+
+ fun update(game: Game):UpdateResult {
+ return this.collection.updateOne(Document("_id",game.id.toString()),Document("\$set",Document.parse(this.instance.gson.toJson(game,game.mode.clazz))),UpdateOptions().upsert(true))
+ }
+
+ fun findById(id: UUID,mode: GameEngineAPI.GameMode,season: Int):Collection {
+ return this.getCollection(season).find(Filters.and(Filters.eq(this.instance.mode.idPath,id.toString()),Filters.eq("mode",mode.name))).map{this.instance.gson.fromJson(it.toJson(GameEngineAPI.JSON_WRITER_SETTINGS),mode.clazz) as T}.toList()
+ }
+
+
+ fun findById(id: UUID,mode: GameEngineAPI.GameMode):HashMap> {
+
+ val toReturn = HashMap>()
+
+ for (entry in this.collections.entries) {
+
+ toReturn[entry.key] = ArrayList()
+
+ for (document in entry.value.find(Filters.and(Filters.eq(this.instance.mode.idPath,id.toString()),Filters.eq("mode",mode.name)))) {
+ toReturn[entry.key]!!.add(this.instance.gson.fromJson(document.toJson(GameEngineAPI.JSON_WRITER_SETTINGS),mode.clazz) as T)
+ }
+
+ }
+
+ return toReturn
+ }
+
+ fun findByMode(mode: GameEngineAPI.GameMode,season: Int):Collection {
+ return this.getCollection(season).find(Filters.eq("mode",mode.name)).map{this.instance.gson.fromJson(it.toJson(GameEngineAPI.JSON_WRITER_SETTINGS),mode.clazz) as T}.toList()
+ }
+
+ fun findByMode(mode: GameEngineAPI.GameMode):HashMap> {
+
+ val toReturn = HashMap>()
+
+ for (entry in this.collections.entries) {
+
+ toReturn[entry.key] = ArrayList()
+
+ for (document in entry.value.find(Filters.eq("mode",mode.name))) {
+ toReturn[entry.key]!!.add(this.instance.gson.fromJson(document.toJson(GameEngineAPI.JSON_WRITER_SETTINGS),mode.clazz) as T)
+ }
+
+ }
+
+ return toReturn
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/game/data/Game.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/game/data/Game.kt
new file mode 100644
index 0000000..5bd6d53
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/game/data/Game.kt
@@ -0,0 +1,18 @@
+package cc.fyre.engine.game.data
+
+import cc.fyre.engine.GameEngineAPI
+import com.google.gson.annotations.SerializedName
+import java.util.*
+
+/**
+ * @project engine
+ *
+ * @date 17/12/2020
+ * @author xanderume@gmail.com
+ */
+open class Game(@SerializedName("_id")val id: UUID,val mode: GameEngineAPI.GameMode,val time: Long) {
+
+ var ranked = false
+ val created = System.currentTimeMillis()
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/game/data/type/BunkersGame.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/game/data/type/BunkersGame.kt
new file mode 100644
index 0000000..b9805c3
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/game/data/type/BunkersGame.kt
@@ -0,0 +1,65 @@
+package cc.fyre.engine.game.data.type
+
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.game.data.Game
+import cc.fyre.engine.profile.data.type.BunkersProfile
+import com.google.gson.annotations.SerializedName
+import java.util.*
+import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
+
+/**
+ * @project engine
+ *
+ * @date 17/12/2020
+ * @author xanderume@gmail.com
+ */
+class BunkersGame(
+ time: Long,
+ val map: String,
+ val teams: ArrayList,
+ val kills: HashMap,
+ val deaths: HashMap,
+ val playTime: HashMap,
+ val oresMined: HashMap,
+ val primaryClass: HashMap,
+ val winner: String?,
+ val kothControlledBy: UUID?
+) : Game(UUID.randomUUID(),GameEngineAPI.GameMode.BUNKERS,time) {
+
+ fun getKills(player: UUID):Int {
+ return this.kills[player] ?: 0
+ }
+
+ fun getDeaths(player: UUID):Int {
+ return this.deaths[player] ?: 0
+ }
+
+ fun getWinningTeam():Team? {
+
+ if (this.winner == null) {
+ return null
+ }
+
+ return this.teams.firstOrNull{it.name.equals(this.winner,true)}
+ }
+
+ fun getOresMined(uuid: UUID):Int {
+ return this.oresMined[uuid] ?: 0
+ }
+
+ fun getPrimaryClass(uuid: UUID):String {
+ return this.primaryClass[uuid]?.displayName ?: "N/A"
+ }
+
+ fun getPlayers():MutableList {
+ return this.teams.flatMap{it.players}.toMutableList()
+ }
+
+ fun getWinners():MutableList {
+ return this.getWinningTeam()?.players?.toMutableList() ?: ArrayList()
+ }
+
+ class Team(val name: String,val color: String,val dtr: Double,val players: ArrayList)
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/profile/ProfileHandler.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/profile/ProfileHandler.kt
new file mode 100644
index 0000000..14a49c8
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/profile/ProfileHandler.kt
@@ -0,0 +1,44 @@
+package cc.fyre.engine.profile
+
+import cc.fyre.engine.GameEngineAPI
+
+import cc.fyre.engine.profile.data.Profile
+import com.mongodb.client.MongoCollection
+import com.mongodb.client.model.Filters
+import com.mongodb.client.model.UpdateOptions
+import com.mongodb.client.result.UpdateResult
+import org.bson.Document
+import java.util.*
+
+/**
+ * @project engine
+ *
+ * @date 17/12/2020
+ * @author xanderume@gmail.com
+ */
+class ProfileHandler(private val instance: GameEngineAPI) {
+
+ val collection: MongoCollection
+ val collections = hashMapOf>()
+
+ init {
+
+ for (i in 1..this.instance.mode.season) {
+ this.collections[i] = this.instance.databaseHandler.mongoDB.getCollection("profiles${if (i == 1) "" else "$i"}")
+ }
+
+ this.collection = this.collections[this.instance.mode.season]!!
+ }
+
+ fun update(profile: Profile):UpdateResult {
+ return this.collection.updateOne(Document("_id",profile.id.toString()),Document("\$set",Document.parse(this.instance.gson.toJson(profile,profile.mode.profileClazz))),UpdateOptions().upsert(true))
+ }
+
+ fun findById(id: UUID,mode: GameEngineAPI.GameMode):T? {
+
+ val query = this.collection.find(Filters.eq("_id",id.toString())).first() ?: return null
+
+ return this.instance.gson.fromJson(query.toJson(GameEngineAPI.JSON_WRITER_SETTINGS),mode.profileClazz) as T
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/profile/data/Profile.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/profile/data/Profile.kt
new file mode 100644
index 0000000..a251589
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/profile/data/Profile.kt
@@ -0,0 +1,15 @@
+package cc.fyre.engine.profile.data
+
+import cc.fyre.engine.GameEngineAPI
+import com.google.gson.annotations.SerializedName
+import java.util.*
+
+/**
+ * @project engine
+ *
+ * @date 17/12/2020
+ * @author xanderume@gmail.com
+ */
+open class Profile(@SerializedName("_id")val id: UUID,val mode: GameEngineAPI.GameMode) {
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/profile/data/type/BunkersProfile.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/profile/data/type/BunkersProfile.kt
new file mode 100644
index 0000000..68db5a7
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/profile/data/type/BunkersProfile.kt
@@ -0,0 +1,67 @@
+package cc.fyre.engine.profile.data.type
+
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.profile.data.Profile
+import java.util.*
+import kotlin.collections.HashMap
+
+/**
+ * @project engine
+ *
+ * @date 17/12/2020
+ * @author xanderume@gmail.com
+ */
+class BunkersProfile(uuid: UUID) : Profile(uuid,GameEngineAPI.GameMode.BUNKERS) {
+
+ var normalWins = 0
+ var normalLosses = 0
+
+ var rankedWins = 0
+ var rankedLosses = 0
+
+ var totalWins = 0
+ var totalLosses = 0
+
+ var kills = 0
+ var deaths = 0
+
+ var playTime = 0L
+ var oresMined = 0
+
+ var gamesPlayed = 0
+
+ var oresTypeMined = HashMap()
+ var classPlayTime = HashMap()
+
+ fun getOresMined(ore: Ore):Int {
+ return this.oresTypeMined[ore] ?: 0
+ }
+
+ fun getPrimaryClass():String {
+
+ if (this.classPlayTime.isEmpty()) {
+ return "N/A"
+ }
+
+ return PvPClass.values().associate{it to (this.classPlayTime[it] ?: 0L)}.entries.sortedByDescending{it.value}.firstOrNull()?.key?.displayName ?: "N/A"
+ }
+
+ enum class Ore(val displayName: String) {
+
+ COAL("COAL"),
+ IRON("Iron"),
+ GOLD("Gold"),
+ DIAMOND("Diamond"),
+ EMERALD("Emerald"),
+
+ }
+
+ enum class PvPClass(val displayName: String) {
+
+ BARD("Bard"),
+ //ARCHER("Archer"),
+ DIAMOND("Diamond"),
+
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/server/GameServerHandler.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/server/GameServerHandler.kt
new file mode 100644
index 0000000..e20a863
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/server/GameServerHandler.kt
@@ -0,0 +1,47 @@
+package cc.fyre.engine.server
+
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.engine.server.listener.GameServerListener
+import cc.fyre.symbiote.Symbiote
+import java.util.*
+
+/**
+ * @project engine
+ *
+ * @date 10/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameServerHandler(private val instance: GameEngineAPI) {
+
+ val cache = hashMapOf()
+
+ init {
+ this.instance.databaseHandler.symbiote.addListener(GameServerListener(this.instance))
+ }
+
+ fun findById(id: String):GameServer? {
+ return this.cache[id.toLowerCase()]
+ }
+
+ fun findLastGame(player: UUID):GameServer? {
+ return this.findLastGame(player,this.instance.mode)
+ }
+
+ fun findLastGame(player: UUID,mode: GameEngineAPI.GameMode):GameServer? {
+ return this.cache.values.firstOrNull{it.mode == mode && it.players.contains(player) && !it.spectators.contains(player)}
+ }
+
+ fun update(server: GameServer) {
+ this.instance.databaseHandler.symbiote.sendPacket(Symbiote(GameServer.UPDATE_ID,server))
+ }
+
+ fun findAvailableGames():MutableSet {
+ return this.cache.values.filter{it.isAvailable() && it.mode == this.instance.mode}.toMutableSet()
+ }
+
+ fun findSpectatableGames():MutableSet {
+ return this.cache.values.filter{it.isInProgress() && it.mode == this.instance.mode && it.mode.spectatable}.toMutableSet()
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/server/data/GameServer.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/server/data/GameServer.kt
new file mode 100644
index 0000000..e9dae46
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/server/data/GameServer.kt
@@ -0,0 +1,67 @@
+package cc.fyre.engine.server.data
+
+import cc.fyre.engine.GameEngineAPI
+import com.google.gson.JsonObject
+import com.google.gson.annotations.SerializedName
+import java.util.*
+import kotlin.collections.HashSet
+
+/**
+ * @project engine
+ *
+ * @date 10/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameServer(@SerializedName("_id")val id: String,val port: Int,val mode: GameEngineAPI.GameMode) {
+
+ var state = State.VOTING
+ var ranked = false
+ var players = hashSetOf()
+ var spectators = hashSetOf()
+ var disqualified = hashSetOf()
+ var lastHeartbeat = 0L
+
+ val metadata = JsonObject()
+
+ fun isOnline():Boolean {
+ return this.lastHeartbeat != 0L && (System.currentTimeMillis() - this.lastHeartbeat) < ONLINE_FAIL_SAFE
+ }
+
+ fun isAvailable():Boolean {
+ return this.state == State.WAITING && this.isOnline()
+ }
+
+ fun isInProgress():Boolean {
+ return this.state == State.IN_PROGRESS
+ }
+
+ enum class State {
+
+ // keep them in order
+
+ WAITING,
+ VOTING,
+ COUNTDOWN,
+ IN_PROGRESS,
+ ENDING;
+
+ fun isPastOrCurrently(state: State):Boolean {
+ return this.ordinal >= state.ordinal
+ }
+
+ fun isBeforeOrCurrently(state: State):Boolean {
+ return this.ordinal <= state.ordinal
+ }
+
+ }
+
+ companion object {
+
+ const val UPDATE_ID = "GAME_DATA_UPDATE"
+ const val DELETE_ID = "GAME_DATA_DELETE"
+ const val ONLINE_FAIL_SAFE = 5000L
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Engine/api/src/main/kotlin/cc/fyre/engine/server/listener/GameServerListener.kt b/Engine/api/src/main/kotlin/cc/fyre/engine/server/listener/GameServerListener.kt
new file mode 100644
index 0000000..616e8bb
--- /dev/null
+++ b/Engine/api/src/main/kotlin/cc/fyre/engine/server/listener/GameServerListener.kt
@@ -0,0 +1,35 @@
+package cc.fyre.engine.server.listener
+
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.symbiote.parasite.Parasite
+import cc.fyre.symbiote.parasite.ParasiteListener
+import com.google.gson.JsonObject
+
+/**
+ * @project engine
+ *
+ * @date 10/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameServerListener(private val api: GameEngineAPI) : ParasiteListener {
+
+ @Parasite(GameServer.UPDATE_ID)
+ fun onServerUpdate(data: JsonObject) {
+
+ val server = this.api.gson.fromJson(data,GameServer::class.java)
+
+ if (!this.api.gameServerHandler.cache.containsKey(server.id.toLowerCase())) {
+ this.api.gameServerHandler.cache[server.id.toLowerCase()] = server
+ return
+ }
+
+ this.api.gameServerHandler.cache.replace(server.id.toLowerCase(),server)
+ }
+
+ @Parasite(GameServer.DELETE_ID)
+ fun onServerDelete(data: JsonObject) {
+ this.api.gameServerHandler.cache.remove(data["_id"].asString.toLowerCase())
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/build.gradle b/Engine/build.gradle
new file mode 100644
index 0000000..f8ec8dc
--- /dev/null
+++ b/Engine/build.gradle
@@ -0,0 +1,31 @@
+allprojects {
+ group = 'cc.fyre.engine'
+ version = '1.0-SNAPSHOT'
+}
+
+subprojects {
+
+ repositories {
+
+ flatDir {
+ dirs 'libs'
+ }
+
+ mavenLocal()
+ mavenCentral()
+ }
+
+ afterEvaluate {
+
+ dependencies {
+ compileOnly fileTree(dir: 'libs', include: ['*.jar'])
+ }
+
+ }
+
+ tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+ }
+
+
+}
diff --git a/Engine/game/build.gradle b/Engine/game/build.gradle
new file mode 100644
index 0000000..0cc8914
--- /dev/null
+++ b/Engine/game/build.gradle
@@ -0,0 +1,50 @@
+plugins {
+ id "org.jetbrains.kotlin.jvm" version "1.5.0"
+ id "com.github.johnrengelman.shadow" version "5.2.0"
+}
+
+targetCompatibility = '1.8'
+sourceCompatibility = '1.8'
+
+shadowJar {
+ classifier = null
+ minimize()
+ archiveName = "engine-" + this.name + "-" + this.version + ".jar"
+}
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+}
+
+dependencies {
+ compile project(":api")
+
+ compileOnly 'com.comphenix.protocol:ProtocolLib:4.4.0'
+ compileOnly "net.frozenorb:qLib:LATEST"
+ compileOnly 'cc.fyre:spigot-server:1.7.10-R0.1-SNAPSHOT'
+ compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.0"
+}
+
+apply plugin: "kotlin"
+apply plugin: 'maven-publish'
+
+compileKotlin {
+ kotlinOptions.jvmTarget = '1.8'
+}
+
+sourceSets {
+ main.java.srcDirs += 'src/main/kotlin/'
+}
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
+
+publishing {
+ publications {
+ shadow(MavenPublication) { publication ->
+ project.shadow.component(publication)
+ }
+ }
+}
diff --git a/Engine/game/build/classes/kotlin/main/META-INF/game.kotlin_module b/Engine/game/build/classes/kotlin/main/META-INF/game.kotlin_module
new file mode 100644
index 0000000..70f0f69
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/META-INF/game.kotlin_module differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/GameEngine$Companion.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/GameEngine$Companion.class
new file mode 100644
index 0000000..46287e8
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/GameEngine$Companion.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/GameEngine.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/GameEngine.class
new file mode 100644
index 0000000..5b0bc4a
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/GameEngine.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/DisqualifieHandler$Companion.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/DisqualifieHandler$Companion.class
new file mode 100644
index 0000000..2b8a70c
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/DisqualifieHandler$Companion.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/DisqualifieHandler.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/DisqualifieHandler.class
new file mode 100644
index 0000000..1efd2d4
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/DisqualifieHandler.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/listener/DisqualifieListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/listener/DisqualifieListener.class
new file mode 100644
index 0000000..526be6f
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/listener/DisqualifieListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/service/DisqualifieService.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/service/DisqualifieService.class
new file mode 100644
index 0000000..2a9b418
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/disqualifie/service/DisqualifieService.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/GameHandler$Companion.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/GameHandler$Companion.class
new file mode 100644
index 0000000..17160b1
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/GameHandler$Companion.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/GameHandler.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/GameHandler.class
new file mode 100644
index 0000000..73ec8f3
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/GameHandler.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter$Companion.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter$Companion.class
new file mode 100644
index 0000000..f1858db
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter$Companion.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter$DefaultGameAdapter.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter$DefaultGameAdapter.class
new file mode 100644
index 0000000..e71f980
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter$DefaultGameAdapter.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter.class
new file mode 100644
index 0000000..1b33c7a
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/GameAdapter.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/scoreboard/ScoreboardAdapter.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/scoreboard/ScoreboardAdapter.class
new file mode 100644
index 0000000..86689dc
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/adapter/scoreboard/ScoreboardAdapter.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/command/ForceStartCommand.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/command/ForceStartCommand.class
new file mode 100644
index 0000000..96a5bc5
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/command/ForceStartCommand.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/event/GameStateChangeEvent$Companion.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/event/GameStateChangeEvent$Companion.class
new file mode 100644
index 0000000..62f04f3
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/event/GameStateChangeEvent$Companion.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/event/GameStateChangeEvent.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/event/GameStateChangeEvent.class
new file mode 100644
index 0000000..529ca66
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/event/GameStateChangeEvent.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GameListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GameListener.class
new file mode 100644
index 0000000..e9b1fc8
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GameListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GamePacketListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GamePacketListener.class
new file mode 100644
index 0000000..d73cb85
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GamePacketListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GameStateListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GameStateListener.class
new file mode 100644
index 0000000..99b0db1
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/listener/GameStateListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/nametag/GameNameTagAdapter.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/nametag/GameNameTagAdapter.class
new file mode 100644
index 0000000..9c99e8d
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/nametag/GameNameTagAdapter.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/service/CountdownService.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/service/CountdownService.class
new file mode 100644
index 0000000..83b5571
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/service/CountdownService.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/service/GameTimerService.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/service/GameTimerService.class
new file mode 100644
index 0000000..3f2b95a
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/game/service/GameTimerService.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/listener/GeneralListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/listener/GeneralListener.class
new file mode 100644
index 0000000..d4c8077
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/listener/GeneralListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/MapHandler$special$$inlined$sortedBy$1.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/MapHandler$special$$inlined$sortedBy$1.class
new file mode 100644
index 0000000..2b8e19e
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/MapHandler$special$$inlined$sortedBy$1.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/MapHandler.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/MapHandler.class
new file mode 100644
index 0000000..e51cdb1
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/MapHandler.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapIconCommand.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapIconCommand.class
new file mode 100644
index 0000000..57db40f
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapIconCommand.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapLoadCommand.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapLoadCommand.class
new file mode 100644
index 0000000..4be5258
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapLoadCommand.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapTPCommand.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapTPCommand.class
new file mode 100644
index 0000000..f73a7f0
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/MapTPCommand.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/parameter/MapParameterProvider.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/parameter/MapParameterProvider.class
new file mode 100644
index 0000000..1a050d9
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/command/parameter/MapParameterProvider.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/data/Map.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/data/Map.class
new file mode 100644
index 0000000..e7bcdf5
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/data/Map.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/event/MapLoadEvent$Companion.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/event/MapLoadEvent$Companion.class
new file mode 100644
index 0000000..4b85d1e
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/event/MapLoadEvent$Companion.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/event/MapLoadEvent.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/event/MapLoadEvent.class
new file mode 100644
index 0000000..ed04c52
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/event/MapLoadEvent.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/listener/MapListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/listener/MapListener.class
new file mode 100644
index 0000000..19fcd21
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/map/listener/MapListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/SpectateHandler.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/SpectateHandler.class
new file mode 100644
index 0000000..276c91f
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/SpectateHandler.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/Item.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/Item.class
new file mode 100644
index 0000000..7d5c73f
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/Item.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/SpectateMenu.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/SpectateMenu.class
new file mode 100644
index 0000000..bad2cb3
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/SpectateMenu.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/TeleportMenu.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/TeleportMenu.class
new file mode 100644
index 0000000..de13355
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/TeleportMenu.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/element/SpectateButton.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/element/SpectateButton.class
new file mode 100644
index 0000000..9ec3057
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/element/SpectateButton.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/element/TeleportButton.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/element/TeleportButton.class
new file mode 100644
index 0000000..669d3a6
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/menu/element/TeleportButton.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/LobbyItem.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/LobbyItem.class
new file mode 100644
index 0000000..9492df5
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/LobbyItem.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/SpectateItem.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/SpectateItem.class
new file mode 100644
index 0000000..c18497e
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/SpectateItem.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/TeleportItem.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/TeleportItem.class
new file mode 100644
index 0000000..8e1c013
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/data/type/TeleportItem.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/listener/SpectateListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/listener/SpectateListener.class
new file mode 100644
index 0000000..b9d1ac5
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/spectate/listener/SpectateListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/BungeeUtil.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/BungeeUtil.class
new file mode 100644
index 0000000..2b4d30b
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/BungeeUtil.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/EnchantUtil.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/EnchantUtil.class
new file mode 100644
index 0000000..dfc0827
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/EnchantUtil.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/FormatUtil.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/FormatUtil.class
new file mode 100644
index 0000000..0ee625a
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/FormatUtil.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/PotionUtil.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/PotionUtil.class
new file mode 100644
index 0000000..ef3ab4d
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/util/PotionUtil.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/VoteHandler$Companion.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/VoteHandler$Companion.class
new file mode 100644
index 0000000..935ed87
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/VoteHandler$Companion.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/VoteHandler.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/VoteHandler.class
new file mode 100644
index 0000000..220bf0f
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/VoteHandler.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/command/VoteCommand.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/command/VoteCommand.class
new file mode 100644
index 0000000..6a3e46c
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/command/VoteCommand.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/listener/VoteListener.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/listener/VoteListener.class
new file mode 100644
index 0000000..e00616f
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/listener/VoteListener.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/service/VoteService$run$$inlined$sortedByDescending$1.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/service/VoteService$run$$inlined$sortedByDescending$1.class
new file mode 100644
index 0000000..78eae38
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/service/VoteService$run$$inlined$sortedByDescending$1.class differ
diff --git a/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/service/VoteService.class b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/service/VoteService.class
new file mode 100644
index 0000000..9c230cb
Binary files /dev/null and b/Engine/game/build/classes/kotlin/main/cc/fyre/engine/voting/service/VoteService.class differ
diff --git a/Engine/game/build/kotlin/compileKotlin/build-history.bin b/Engine/game/build/kotlin/compileKotlin/build-history.bin
new file mode 100644
index 0000000..aa7b6c9
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/build-history.bin differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab
new file mode 100644
index 0000000..e8997af
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream
new file mode 100644
index 0000000..631cd4c
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len
new file mode 100644
index 0000000..3878c14
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len
new file mode 100644
index 0000000..709f734
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at
new file mode 100644
index 0000000..101cd74
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i
new file mode 100644
index 0000000..48fd9ec
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab
new file mode 100644
index 0000000..be10dbb
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream
new file mode 100644
index 0000000..d6f3d17
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len
new file mode 100644
index 0000000..b3482a8
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len
new file mode 100644
index 0000000..62cf1e5
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at
new file mode 100644
index 0000000..b9b5f4b
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i
new file mode 100644
index 0000000..46f8922
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab
new file mode 100644
index 0000000..f5266c3
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream
new file mode 100644
index 0000000..d6f3d17
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len
new file mode 100644
index 0000000..b3482a8
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len
new file mode 100644
index 0000000..62cf1e5
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at
new file mode 100644
index 0000000..5bbad5e
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i
new file mode 100644
index 0000000..46f8922
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab
new file mode 100644
index 0000000..761e0a6
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream
new file mode 100644
index 0000000..2f8137b
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len
new file mode 100644
index 0000000..7911e33
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len
new file mode 100644
index 0000000..a9f80ae
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at
new file mode 100644
index 0000000..2af40fb
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i
new file mode 100644
index 0000000..8002d0a
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab
new file mode 100644
index 0000000..be23c22
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream
new file mode 100644
index 0000000..3739bb5
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len
new file mode 100644
index 0000000..9d5b257
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len
new file mode 100644
index 0000000..bff9925
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at
new file mode 100644
index 0000000..8a52d33
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i
new file mode 100644
index 0000000..2617f42
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab
new file mode 100644
index 0000000..d6554b9
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream
new file mode 100644
index 0000000..8281594
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len
new file mode 100644
index 0000000..1dab4ab
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len
new file mode 100644
index 0000000..6f80c14
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at
new file mode 100644
index 0000000..31584e4
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i
new file mode 100644
index 0000000..0544ef5
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab
new file mode 100644
index 0000000..23ccb76
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream
new file mode 100644
index 0000000..dd0e594
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len
new file mode 100644
index 0000000..3878c14
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len
new file mode 100644
index 0000000..709f734
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at
new file mode 100644
index 0000000..51071c6
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i
new file mode 100644
index 0000000..239e79b
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab
new file mode 100644
index 0000000..1dbc6d7
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream
new file mode 100644
index 0000000..8379808
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len
new file mode 100644
index 0000000..78e8f3b
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len
new file mode 100644
index 0000000..6f677df
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at
new file mode 100644
index 0000000..b13067a
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i
new file mode 100644
index 0000000..c5f98e9
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/subtypes.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab
new file mode 100644
index 0000000..b5cb182
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream
new file mode 100644
index 0000000..37b0cc4
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len
new file mode 100644
index 0000000..9196559
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len
new file mode 100644
index 0000000..42df8b9
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at
new file mode 100644
index 0000000..96e9115
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i
new file mode 100644
index 0000000..fab913b
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/supertypes.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab
new file mode 100644
index 0000000..fcb34dd
--- /dev/null
+++ b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab
@@ -0,0 +1,2 @@
+43
+1
\ No newline at end of file
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab
new file mode 100644
index 0000000..3680791
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream
new file mode 100644
index 0000000..dd0e594
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len
new file mode 100644
index 0000000..3878c14
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len
new file mode 100644
index 0000000..709f734
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at
new file mode 100644
index 0000000..956b516
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i
new file mode 100644
index 0000000..818435c
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab
new file mode 100644
index 0000000..921dcf9
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream
new file mode 100644
index 0000000..c86230b
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len
new file mode 100644
index 0000000..5b8e1ac
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len
new file mode 100644
index 0000000..a123325
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at
new file mode 100644
index 0000000..006f666
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i
new file mode 100644
index 0000000..a243e51
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab
new file mode 100644
index 0000000..4ca521f
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream
new file mode 100644
index 0000000..e764b95
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len
new file mode 100644
index 0000000..222e4f4
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len
new file mode 100644
index 0000000..3eaf7c6
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values
new file mode 100644
index 0000000..d4d4987
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at
new file mode 100644
index 0000000..32d062e
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.s b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.s
new file mode 100644
index 0000000..e9d182f
--- /dev/null
+++ b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.s
@@ -0,0 +1 @@
+îq
\ No newline at end of file
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i
new file mode 100644
index 0000000..72b181f
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i differ
diff --git a/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len
new file mode 100644
index 0000000..131e265
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len differ
diff --git a/Engine/game/build/kotlin/compileKotlin/last-build.bin b/Engine/game/build/kotlin/compileKotlin/last-build.bin
new file mode 100644
index 0000000..882a783
Binary files /dev/null and b/Engine/game/build/kotlin/compileKotlin/last-build.bin differ
diff --git a/Engine/game/build/libs/engine-game-1.0-SNAPSHOT.jar b/Engine/game/build/libs/engine-game-1.0-SNAPSHOT.jar
new file mode 100644
index 0000000..e95b4c9
Binary files /dev/null and b/Engine/game/build/libs/engine-game-1.0-SNAPSHOT.jar differ
diff --git a/Engine/game/build/publications/shadow/pom-default.xml b/Engine/game/build/publications/shadow/pom-default.xml
new file mode 100644
index 0000000..797da9b
--- /dev/null
+++ b/Engine/game/build/publications/shadow/pom-default.xml
@@ -0,0 +1,8 @@
+
+
+ 4.0.0
+ cc.fyre.engine
+ game
+ 1.0-SNAPSHOT
+
+
diff --git a/Engine/game/build/resources/main/config.yml b/Engine/game/build/resources/main/config.yml
new file mode 100644
index 0000000..53b0af5
--- /dev/null
+++ b/Engine/game/build/resources/main/config.yml
@@ -0,0 +1 @@
+server-id: "Bunkers-01"
\ No newline at end of file
diff --git a/Engine/game/build/resources/main/plugin.yml b/Engine/game/build/resources/main/plugin.yml
new file mode 100644
index 0000000..84a2e87
--- /dev/null
+++ b/Engine/game/build/resources/main/plugin.yml
@@ -0,0 +1,4 @@
+name: GameEngine
+main: cc.fyre.engine.GameEngine
+version: 1.0-SNAPSHOT
+depend: [qLib,Kotlin]
diff --git a/Engine/game/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml b/Engine/game/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml
new file mode 100644
index 0000000..a7ace9b
--- /dev/null
+++ b/Engine/game/build/tmp/publishShadowPublicationToMavenLocal/module-maven-metadata.xml
@@ -0,0 +1,12 @@
+
+
+ cc.fyre.engine
+ game
+
+ 1.0-SNAPSHOT
+
+ 1.0-SNAPSHOT
+
+ 20210829082618
+
+
diff --git a/Engine/game/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml b/Engine/game/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml
new file mode 100644
index 0000000..2b7d803
--- /dev/null
+++ b/Engine/game/build/tmp/publishShadowPublicationToMavenLocal/snapshot-maven-metadata.xml
@@ -0,0 +1,24 @@
+
+
+ cc.fyre.engine
+ game
+ 1.0-SNAPSHOT
+
+
+ true
+
+ 20210829082618
+
+
+ pom
+ 1.0-SNAPSHOT
+ 20210829082618
+
+
+ jar
+ 1.0-SNAPSHOT
+ 20210829082618
+
+
+
+
diff --git a/Engine/game/build/tmp/shadowJar/MANIFEST.MF b/Engine/game/build/tmp/shadowJar/MANIFEST.MF
new file mode 100644
index 0000000..59499bc
--- /dev/null
+++ b/Engine/game/build/tmp/shadowJar/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/GameEngine.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/GameEngine.kt
new file mode 100644
index 0000000..a1ff969
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/GameEngine.kt
@@ -0,0 +1,64 @@
+package cc.fyre.engine
+
+import cc.fyre.engine.disqualifie.DisqualifieHandler
+import cc.fyre.engine.game.GameHandler
+import cc.fyre.engine.listener.GeneralListener
+import cc.fyre.engine.map.MapHandler
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.engine.spectate.SpectateHandler
+import cc.fyre.engine.util.BungeeUtil
+import cc.fyre.engine.voting.VoteHandler
+import cc.fyre.symbiote.Symbiote
+import org.bukkit.plugin.java.JavaPlugin
+
+/**
+ * @project engine
+ *
+ * @date 10/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameEngine : JavaPlugin() {
+
+ lateinit var api: GameEngineAPI
+ lateinit var mapHandler: MapHandler
+ lateinit var gameHandler: GameHandler
+ lateinit var voteHandler: VoteHandler
+ lateinit var spectateHandler: SpectateHandler
+ lateinit var disqualifieHandler: DisqualifieHandler
+
+ override fun onEnable() {
+ instance = this
+
+ this.api = GameEngineAPI(this.findGameMode())
+
+ this.mapHandler = MapHandler(this)
+ this.gameHandler = GameHandler(this)
+ this.voteHandler = VoteHandler(this)
+ this.spectateHandler = SpectateHandler(this)
+ this.disqualifieHandler = DisqualifieHandler(this)
+
+ this.server.logger.info("[GameEngine] Loaded Game Engine on ${this.api.mode.displayName}.")
+
+ this.server.messenger.registerOutgoingPluginChannel(this,BungeeUtil.PROXY_CHANNEL)
+ this.server.pluginManager.registerEvents(GeneralListener(this),this)
+ }
+
+ override fun onDisable() {
+ this.mapHandler.dispose()
+ this.voteHandler.dispose()
+
+ this.api.databaseHandler.symbiote.sendPacket(Symbiote(GameServer.DELETE_ID,this.gameHandler.server))
+ this.api.dispose()
+ }
+
+ private fun findGameMode():GameEngineAPI.GameMode {
+ return GameEngineAPI.GameMode.BUNKERS
+ }
+
+ companion object {
+
+ lateinit var instance: GameEngine
+
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/DisqualifieHandler.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/DisqualifieHandler.kt
new file mode 100644
index 0000000..243e785
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/DisqualifieHandler.kt
@@ -0,0 +1,42 @@
+package cc.fyre.engine.disqualifie
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.disqualifie.listener.DisqualifieListener
+import cc.fyre.engine.disqualifie.service.DisqualifieService
+import java.util.*
+import java.util.concurrent.TimeUnit
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+
+/**
+ * @project engine
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class DisqualifieHandler(private val instance: GameEngine) {
+
+ val cache = HashMap()
+ val service = DisqualifieService(this.instance)
+
+ private val disqualified = HashSet()
+
+ init {
+ this.instance.server.pluginManager.registerEvents(DisqualifieListener(this.instance),this.instance)
+ }
+
+ fun disqualifie(uuid: UUID) {
+ this.disqualified.add(uuid)
+ this.instance.gameHandler.adapter.onGameDisqualifiePlayer(uuid)
+ }
+
+ fun isDisqualified(uuid: UUID):Boolean {
+ return this.disqualified.contains(uuid)
+ }
+
+ companion object {
+
+ val DURATION = TimeUnit.MINUTES.toMillis(5L)
+
+ }
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/listener/DisqualifieListener.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/listener/DisqualifieListener.kt
new file mode 100644
index 0000000..064c3c2
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/listener/DisqualifieListener.kt
@@ -0,0 +1,58 @@
+package cc.fyre.engine.disqualifie.listener
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.event.GameStateChangeEvent
+import cc.fyre.engine.server.data.GameServer
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerQuitEvent
+
+/**
+ * @project engine
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class DisqualifieListener(private val instance: GameEngine):Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ if (this.instance.disqualifieHandler.cache.remove(event.player.uniqueId) != null) {
+ return
+ }
+
+ if (!this.instance.disqualifieHandler.isDisqualified(event.player.uniqueId)) {
+ return
+ }
+
+ this.instance.spectateHandler.addSpectator(event.player)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+
+ if (this.instance.spectateHandler.isSpectating(event.player) || this.instance.disqualifieHandler.isDisqualified(event.player.uniqueId)) {
+ return
+ }
+
+ this.instance.disqualifieHandler.cache[event.player.uniqueId] = System.currentTimeMillis()
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onGameStateChange(event: GameStateChangeEvent) {
+
+ if (!this.instance.api.mode.disqualifies) {
+ return
+ }
+
+ if (event.new != GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ this.instance.disqualifieHandler.service.runTaskTimer(this.instance,20L,20L)
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/service/DisqualifieService.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/service/DisqualifieService.kt
new file mode 100644
index 0000000..addc06c
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/disqualifie/service/DisqualifieService.kt
@@ -0,0 +1,31 @@
+package cc.fyre.engine.disqualifie.service
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.disqualifie.DisqualifieHandler
+import org.bukkit.ChatColor
+import org.bukkit.scheduler.BukkitRunnable
+
+/**
+ * @project engine
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class DisqualifieService(private val instance: GameEngine) : BukkitRunnable() {
+
+ override fun run() {
+
+ this.instance.disqualifieHandler.cache.entries.removeIf{
+
+ if (((it.value + DisqualifieHandler.DURATION) - System.currentTimeMillis()) > 0) {
+ return@removeIf false
+ }
+
+ this.instance.gameHandler.players.remove(it.key)
+ this.instance.disqualifieHandler.disqualifie(it.key)
+ return@removeIf true
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/GameHandler.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/GameHandler.kt
new file mode 100644
index 0000000..54cbdde
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/GameHandler.kt
@@ -0,0 +1,150 @@
+package cc.fyre.engine.game
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.adapter.GameAdapter
+import cc.fyre.engine.game.command.ForceStartCommand
+import cc.fyre.engine.game.event.GameStateChangeEvent
+import cc.fyre.engine.game.listener.GameListener
+import cc.fyre.engine.game.listener.GamePacketListener
+import cc.fyre.engine.game.listener.GameStateListener
+import cc.fyre.engine.game.nametag.GameNameTagAdapter
+import cc.fyre.engine.game.service.CountdownService
+import cc.fyre.engine.game.service.GameTimerService
+import cc.fyre.engine.map.data.Map
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.engine.voting.VoteHandler
+import com.google.gson.JsonObject
+import net.frozenorb.qlib.command.FrozenCommandHandler
+import net.frozenorb.qlib.nametag.FrozenNametagHandler
+import org.bukkit.Bukkit
+import org.bukkit.entity.Player
+import java.util.*
+import java.util.concurrent.TimeUnit
+import kotlin.collections.HashSet
+
+/**
+ * @project engine
+ *
+ * @date 11/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameHandler(private val instance: GameEngine) {
+
+ val server = GameServer(
+ this.instance.config.getString("server-id"),
+ Bukkit.getServer().port,
+ this.instance.api.mode
+ )
+
+ val players = HashSet()
+
+ val service = GameTimerService(this.instance)
+ val countdownService = CountdownService(this.instance)
+
+ var ranked = false
+ var lastLogout = 0L
+
+ var adapter: GameAdapter = GameAdapter.DefaultGameAdapter()
+
+ private var state = GameServer.State.WAITING
+
+ lateinit var map: Map
+ lateinit var parties: ArrayList>
+
+ init {
+ FrozenCommandHandler.registerClass(ForceStartCommand::class.java)
+ FrozenNametagHandler.registerProvider(GameNameTagAdapter(this.instance))
+
+ this.instance.server.scheduler.runTaskTimerAsynchronously(this.instance,{this.update()},40L,40L)
+ this.instance.server.pluginManager.registerEvents(GameListener(this.instance),this.instance)
+ this.instance.server.pluginManager.registerEvents(GameStateListener(this.instance),this.instance)
+
+ this.instance.api.databaseHandler.symbiote.addListener(GamePacketListener(this.instance))
+ }
+
+ fun getState():GameServer.State {
+ return this.state
+ }
+
+ fun setState(state: GameServer.State) {
+
+ if (this.state == state) {
+ return
+ }
+
+ this.instance.server.pluginManager.callEvent(GameStateChangeEvent(this.state,state))
+ this.state = state
+ return
+ }
+
+ private fun update() {
+ this.server.state = this.state
+ this.server.ranked = this.ranked
+ this.server.players = this.players
+ this.server.spectators = this.instance.spectateHandler.cache
+ this.server.disqualified = this.players.filter{this.instance.disqualifieHandler.isDisqualified(it)}.toHashSet()
+ this.server.lastHeartbeat = System.currentTimeMillis()
+
+ if (this.instance.api.mode.mapBased && this.state.isPastOrCurrently(GameServer.State.COUNTDOWN)) {
+ this.server.metadata.addProperty("map",this.map.id)
+ }
+
+ this.instance.api.gameServerHandler.update(this.server)
+ }
+
+ fun addMetadata(jsonObject: JsonObject) {
+ jsonObject.entrySet().forEach{this.server.metadata.add(it.key,it.value)}
+ }
+
+ fun addPlayer(player: Player) {
+ this.players.add(player.uniqueId)
+ this.adapter.onGameAddPlayer(player)
+ }
+
+ fun removePlayer(player: Player) {
+ this.players.remove(player.uniqueId)
+ this.adapter.onGameRemovePlayer(player)
+ }
+
+ fun getGameTime():Long {
+
+ if (this.service.started == 0L) {
+ return 0L
+ }
+
+ return System.currentTimeMillis() - this.service.started
+ }
+
+ fun getVotingTime():Long {
+
+ if (this.instance.voteHandler.service.started == 0L) {
+ return VoteHandler.VOTING_SECONDS * 1000L
+ }
+
+ return (this.instance.voteHandler.service.started + VoteHandler.VOTING_SECONDS * 1000L) - System.currentTimeMillis()
+ }
+
+ fun getCountdownTime():Long {
+
+ if (this.countdownService.started == 0L) {
+ return VoteHandler.VOTING_SECONDS * 1000L
+ }
+
+ return (this.countdownService.started + COUNTDOWN_SECONDS * 1000L) - System.currentTimeMillis()
+ }
+
+ fun isPlaying(player: Player):Boolean {
+ return this.players.contains(player.uniqueId)
+ }
+
+ fun getPlayers():MutableSet {
+ return this.players.mapNotNull{this.instance.server.getPlayer(it)}.toMutableSet()
+ }
+
+ companion object {
+
+ const val COUNTDOWN_SECONDS = 15
+
+ val AUTO_END_GAME_TIME = TimeUnit.MINUTES.toMillis(5L)
+ }
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/adapter/GameAdapter.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/adapter/GameAdapter.kt
new file mode 100644
index 0000000..2a5512e
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/adapter/GameAdapter.kt
@@ -0,0 +1,62 @@
+package cc.fyre.engine.game.adapter
+
+import cc.fyre.engine.game.adapter.scoreboard.ScoreboardAdapter
+import cc.fyre.engine.game.data.Game
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.nametag.NametagInfo
+import net.minecraft.util.org.apache.commons.lang3.StringUtils
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+import java.util.*
+import kotlin.collections.HashMap
+
+/**
+ * @project engine
+ *
+ * @date 12/08/2020
+ * @author xanderume@gmail.com
+ */
+interface GameAdapter {
+
+ fun onTick(seconds: Int)
+ fun onGameFinish()
+ fun onGameFinishUpdateProfiles()
+
+ fun onPlayersSent(players: ArrayList)
+
+ fun onGameAddPlayer(player: Player)
+ fun onGameRemovePlayer(player: Player)
+ fun onGameAddSpectator(player: Player)
+ fun onGameDisqualifiePlayer(uuid: UUID)
+
+ fun getNameTag(player: Player,target: Player): NametagInfo?
+ fun getScoreboardAdapters():HashMap
+
+ fun getEndGameData():Game?
+
+ class DefaultGameAdapter : GameAdapter {
+
+ override fun onTick(seconds: Int) {}
+ override fun onGameFinish() {}
+ override fun onGameFinishUpdateProfiles() {}
+
+ override fun onPlayersSent(players: ArrayList) {}
+
+ override fun onGameAddPlayer(player: Player) {}
+ override fun onGameRemovePlayer(player: Player) {}
+ override fun onGameAddSpectator(player: Player) {}
+ override fun onGameDisqualifiePlayer(uuid: UUID) {}
+
+ override fun getNameTag(player: Player, target: Player):NametagInfo? = null
+ override fun getScoreboardAdapters(): HashMap = hashMapOf()
+
+ override fun getEndGameData(): Game? = null
+ }
+
+ companion object {
+
+ val SCOREBOARD_LINE = "${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",20)}"
+
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/adapter/scoreboard/ScoreboardAdapter.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/adapter/scoreboard/ScoreboardAdapter.kt
new file mode 100644
index 0000000..8e6c90f
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/adapter/scoreboard/ScoreboardAdapter.kt
@@ -0,0 +1,11 @@
+package cc.fyre.engine.game.adapter.scoreboard
+
+import net.frozenorb.qlib.scoreboard.ScoreGetter
+import net.frozenorb.qlib.scoreboard.TitleGetter
+
+interface ScoreboardAdapter {
+
+ fun getTitleGetter(): TitleGetter
+ fun getScoreGetter(): ScoreGetter
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/command/ForceStartCommand.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/command/ForceStartCommand.kt
new file mode 100644
index 0000000..5eee50c
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/command/ForceStartCommand.kt
@@ -0,0 +1,30 @@
+package cc.fyre.engine.game.command
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.command.Command
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+
+/**
+ * @project engine
+ *
+ * @date 16/08/2020
+ * @author xanderume@gmail.com
+ */
+object ForceStartCommand {
+
+ @JvmStatic
+ @Command(names = ["forcestart"],hidden = true,permission = "bunkers.command.forcestart")
+ fun execute(sender: CommandSender) {
+
+ if (GameEngine.instance.gameHandler.getState().isPastOrCurrently(GameServer.State.IN_PROGRESS)) {
+ sender.sendMessage("${ChatColor.RED}The game has already started!")
+ return
+ }
+
+ GameEngine.instance.gameHandler.setState(GameServer.State.COUNTDOWN)
+ GameEngine.instance.gameHandler.setState(GameServer.State.IN_PROGRESS)
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/event/GameStateChangeEvent.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/event/GameStateChangeEvent.kt
new file mode 100644
index 0000000..71bb4d0
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/event/GameStateChangeEvent.kt
@@ -0,0 +1,33 @@
+package cc.fyre.engine.game.event
+
+import cc.fyre.engine.server.data.GameServer
+import org.bukkit.event.Cancellable
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+/**
+ * @project bunkers
+ *
+ * @date 09/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameStateChangeEvent(val previous: GameServer.State,val new: GameServer.State):Event(),Cancellable {
+
+ private var cancelled = false
+
+ override fun isCancelled(): Boolean {
+ return this.cancelled
+ }
+
+ override fun setCancelled(cancelled: Boolean) {
+ this.cancelled = cancelled
+ }
+
+ override fun getHandlers(): HandlerList {
+ return handlerList
+ }
+
+ companion object {
+ @JvmStatic val handlerList = HandlerList()
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GameListener.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GameListener.kt
new file mode 100644
index 0000000..a8b8d90
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GameListener.kt
@@ -0,0 +1,61 @@
+package cc.fyre.engine.game.listener
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import net.frozenorb.qlib.scoreboard.FrozenScoreboardHandler
+import net.frozenorb.qlib.scoreboard.ScoreboardConfiguration
+
+import org.bukkit.GameMode
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerQuitEvent
+
+/**
+ * @project engine
+ *
+ * @date 12/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameListener(private val instance: GameEngine) : Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerJoin(event: PlayerJoinEvent) {
+
+ if (FrozenScoreboardHandler.getConfiguration() == null && this.instance.gameHandler.adapter.getScoreboardAdapters()[this.instance.gameHandler.getState()] != null) {
+
+ val configuration = ScoreboardConfiguration()
+
+ configuration.titleGetter = this.instance.gameHandler.adapter.getScoreboardAdapters()[this.instance.gameHandler.getState()]!!.getTitleGetter()
+ configuration.scoreGetter = this.instance.gameHandler.adapter.getScoreboardAdapters()[this.instance.gameHandler.getState()]!!.getScoreGetter()
+
+ FrozenScoreboardHandler.setConfiguration(configuration)
+ }
+
+ if (!this.instance.gameHandler.getState().isBeforeOrCurrently(GameServer.State.COUNTDOWN)) {
+ return
+ }
+
+ if (GameEngine.instance.api.mode.mapBased && this.instance.gameHandler.getState() == GameServer.State.WAITING) {
+ this.instance.gameHandler.setState(GameServer.State.VOTING)
+ }
+
+ event.player.health = event.player.maxHealth
+ event.player.foodLevel = 20
+ event.player.gameMode = GameMode.ADVENTURE
+ event.player.inventory.clear()
+ event.player.inventory.armorContents = null
+ event.player.activePotionEffects.forEach{event.player.removePotionEffect(it.type)}
+
+ event.player.teleport(this.instance.voteHandler.world.spawnLocation.add(0.5,0.0,0.5))
+
+ this.instance.gameHandler.addPlayer(event.player)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onPlayerQuit(event: PlayerQuitEvent) {
+ this.instance.gameHandler.lastLogout = System.currentTimeMillis()
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GamePacketListener.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GamePacketListener.kt
new file mode 100644
index 0000000..246dcf0
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GamePacketListener.kt
@@ -0,0 +1,64 @@
+package cc.fyre.engine.game.listener
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.symbiote.Symbiote
+import cc.fyre.symbiote.parasite.Parasite
+import cc.fyre.symbiote.parasite.ParasiteListener
+import com.google.gson.JsonObject
+import org.bukkit.Bukkit
+import java.util.*
+import kotlin.collections.ArrayList
+
+/**
+ * @project engine
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class GamePacketListener(private val instance: GameEngine):ParasiteListener {
+
+ @Parasite(GameEngineAPI.GAME_DATA_PACKET)
+ fun onPartyData(data: JsonObject) {
+
+ if (GameEngine.instance.gameHandler.server.id != data["_id"].asString) {
+ return
+ }
+
+ if (GameEngineAPI.GameMode.valueOf(data["mode"].asString) != this.instance.api.mode) {
+ return
+ }
+
+
+ this.instance.gameHandler.ranked = data["ranked"].asBoolean
+ this.instance.gameHandler.parties = this.instance.api.gson.fromJson>>(data["parties"].asString,List::class.java).map{list -> list.map{value -> UUID.fromString(value)}.toCollection(ArrayList())}.toCollection(ArrayList())
+
+ // We received the data, now send a packet back to the lobby informing to send the players to the game.
+
+ val payload = JsonObject()
+
+ payload.addProperty("_id",GameEngine.instance.gameHandler.server.id)
+ payload.addProperty("mode",this.instance.api.mode.name)
+ payload.addProperty("players",this.instance.api.gson.toJson(this.instance.gameHandler.parties.flatten()))
+
+ Bukkit.getServer().scheduler.runTaskAsynchronously(this.instance) {
+ GameEngine.instance.api.databaseHandler.symbiote.sendPacket(Symbiote(GameEngineAPI.GAME_SEND_PACKET,payload))
+ }
+
+ }
+
+ @Parasite(GameEngineAPI.GAME_SENT_PACKET)
+ fun onPartySent(data: JsonObject) {
+
+ if (GameEngine.instance.gameHandler.server.id != data["_id"].asString) {
+ return
+ }
+
+ if (GameEngineAPI.GameMode.valueOf(data["mode"].asString) != this.instance.api.mode) {
+ return
+ }
+
+ this.instance.gameHandler.adapter.onPlayersSent(this.instance.api.gson.fromJson>(data["players"].asString,List::class.java).map{UUID.fromString(it)}.toCollection(ArrayList()))
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GameStateListener.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GameStateListener.kt
new file mode 100644
index 0000000..ad28c06
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/listener/GameStateListener.kt
@@ -0,0 +1,127 @@
+package cc.fyre.engine.game.listener
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.game.event.GameStateChangeEvent
+import cc.fyre.engine.server.data.GameServer
+import cc.fyre.engine.util.BungeeUtil
+import cc.fyre.symbiote.parasite.ParasiteListener
+import net.frozenorb.qlib.command.FrozenCommandHandler
+import net.frozenorb.qlib.scoreboard.FrozenScoreboardHandler
+import net.frozenorb.qlib.scoreboard.ScoreboardConfiguration
+import org.bukkit.Bukkit
+import org.bukkit.ChatColor
+import org.bukkit.GameMode
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import java.util.*
+
+/**
+ * @project engine
+ *
+ * @date 12/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameStateListener(private val instance: GameEngine) : Listener,ParasiteListener {
+
+ init {
+ this.instance.api.databaseHandler.symbiote.addListener(this)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onStateVoting(event: GameStateChangeEvent) {
+
+ if (event.new != GameServer.State.VOTING) {
+ return
+ }
+
+ this.instance.voteHandler.service.runTaskTimer(this.instance,20L,20L)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onStateCountdown(event: GameStateChangeEvent) {
+
+ if (event.new != GameServer.State.COUNTDOWN) {
+ return
+ }
+
+ if (event.previous == GameServer.State.VOTING) {
+
+ val map = this.instance.gameHandler.map
+ val votes = this.instance.voteHandler.getVotes(map)
+
+ this.instance.mapHandler.copyAndLoadMap(map)
+ this.instance.gameHandler.getPlayers().forEach{it.inventory.clear()}
+ this.instance.server.broadcastMessage(" ")
+ this.instance.server.broadcastMessage("${this.instance.api.mode.prefix}${ChatColor.WHITE} Map ${ChatColor.GOLD}${map.id}${ChatColor.WHITE} has won with ${ChatColor.GOLD}${this.instance.voteHandler.getVotes(map)} vote${if (votes == 1) "" else "s"}${ChatColor.WHITE}.")
+ this.instance.server.broadcastMessage(" ")
+ }
+
+ this.instance.gameHandler.countdownService.runTaskTimer(this.instance,20L,20L)
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onStateInProgress(event: GameStateChangeEvent) {
+
+ if (event.new != GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ this.instance.gameHandler.service.runTaskTimer(this.instance,20L,20L)
+ this.instance.gameHandler.getPlayers().forEach{it.gameMode = GameMode.SURVIVAL}
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onGameStateChange(event: GameStateChangeEvent) {
+
+ if (event.previous == event.new) {
+ return
+ }
+
+ val adapter = this.instance.gameHandler.adapter.getScoreboardAdapters()[event.new] ?: return
+ val configuration = ScoreboardConfiguration()
+
+ configuration.titleGetter = adapter.getTitleGetter()
+ configuration.scoreGetter = adapter.getScoreGetter()
+
+ FrozenScoreboardHandler.setConfiguration(configuration)
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onGameStateEnding(event: GameStateChangeEvent) {
+
+ if (event.new != GameServer.State.ENDING) {
+ return
+ }
+
+ this.instance.gameHandler.adapter.onGameFinish()
+
+ this.instance.server.scheduler.runTaskLaterAsynchronously(this.instance,{
+ this.instance.gameHandler.adapter.onGameFinishUpdateProfiles()
+ },20L)
+
+ val data = this.instance.gameHandler.adapter.getEndGameData()
+
+ if (data != null) {
+ data.ranked = this.instance.gameHandler.ranked
+
+ Bukkit.getServer().scheduler.runTaskAsynchronously(this.instance) {
+ this.instance.api.gameDataHandler.update(data)
+ }
+
+ }
+
+ this.instance.server.scheduler.runTaskLater(this.instance,{
+
+ Bukkit.getServer().onlinePlayers.forEach{
+ // We have to teleport all the players to a different world before we can delete the world
+ it.teleport(Bukkit.getServer().worlds[0].spawnLocation)
+ BungeeUtil.sendToServer(it,GameEngine.instance.api.mode.lobbyServer)
+ }
+
+ this.instance.server.shutdown()
+ },10*20L)
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/nametag/GameNameTagAdapter.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/nametag/GameNameTagAdapter.kt
new file mode 100644
index 0000000..20d0aa1
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/nametag/GameNameTagAdapter.kt
@@ -0,0 +1,27 @@
+package cc.fyre.engine.game.nametag
+
+import cc.fyre.engine.GameEngine
+import net.frozenorb.qlib.nametag.NametagInfo
+import net.frozenorb.qlib.nametag.NametagProvider
+import org.bukkit.ChatColor
+import org.bukkit.entity.Player
+
+/**
+ * @project engine
+ *
+ * @date 14/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameNameTagAdapter(private val instance: GameEngine) : NametagProvider("Bunkers Nametags",1) {
+
+
+ override fun fetchNametag(player: Player,target: Player):NametagInfo {
+
+ if (this.instance.spectateHandler.isSpectating(player)) {
+ return createNametag(ChatColor.GRAY.toString(),"")
+ }
+
+ return this.instance.gameHandler.adapter.getNameTag(player,target) ?: createNametag(ChatColor.RED.toString(),"")
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/service/CountdownService.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/service/CountdownService.kt
new file mode 100644
index 0000000..8ee047f
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/service/CountdownService.kt
@@ -0,0 +1,40 @@
+package cc.fyre.engine.game.service
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.GameHandler
+import cc.fyre.engine.server.data.GameServer
+import org.bukkit.ChatColor
+import org.bukkit.scheduler.BukkitRunnable
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * @project engine
+ *
+ * @date 11/08/2020
+ * @author xanderume@gmail.com
+ */
+class CountdownService(private val instance: GameEngine) : BukkitRunnable() {
+
+ var started = 0L
+ var remaining = AtomicInteger(GameHandler.COUNTDOWN_SECONDS)
+
+ override fun run() {
+
+ if (this.started == 0L) {
+ this.started = System.currentTimeMillis()
+ }
+
+ if (this.remaining.get() == 15 || this.remaining.get() == 10 || this.remaining.get() in 1..5) {
+ this.instance.server.broadcastMessage("${this.instance.api.mode.prefix} ${ChatColor.WHITE}Game starts in ${ChatColor.GOLD}${this.remaining.get()} second${if (this.remaining.get() == 1) "" else "s"}${ChatColor.WHITE}.")
+ }
+
+ if (this.remaining.get() <= 0) {
+ this.cancel()
+ this.instance.gameHandler.setState(GameServer.State.IN_PROGRESS)
+ return
+ }
+
+ this.remaining.decrementAndGet()
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/game/service/GameTimerService.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/game/service/GameTimerService.kt
new file mode 100644
index 0000000..3d94590
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/game/service/GameTimerService.kt
@@ -0,0 +1,33 @@
+package cc.fyre.engine.game.service
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.game.GameHandler
+import org.bukkit.scheduler.BukkitRunnable
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * @project engine
+ *
+ * @date 12/08/2020
+ * @author xanderume@gmail.com
+ */
+class GameTimerService(private val instance: GameEngine) : BukkitRunnable() {
+
+ var time = AtomicInteger()
+ var started = 0L
+
+ override fun run() {
+
+ if (this.started == 0L) {
+ this.started = System.currentTimeMillis()
+ }
+
+ if ((this.instance.gameHandler.lastLogout != 0L && (((this.instance.gameHandler.lastLogout + GameHandler.AUTO_END_GAME_TIME) - System.currentTimeMillis()) <= 0)) && this.instance.gameHandler.getPlayers().isEmpty()) {
+ this.instance.server.shutdown()
+ return
+ }
+
+ this.instance.gameHandler.adapter.onTick(this.time.incrementAndGet())
+ }
+
+}
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/listener/GeneralListener.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/listener/GeneralListener.kt
new file mode 100644
index 0000000..1a7172c
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/listener/GeneralListener.kt
@@ -0,0 +1,92 @@
+package cc.fyre.engine.listener
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.server.data.GameServer
+import org.bukkit.entity.EnderPearl
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.BlockIgniteEvent
+import org.bukkit.event.block.LeavesDecayEvent
+import org.bukkit.event.entity.*
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerQuitEvent
+import org.bukkit.event.weather.WeatherChangeEvent
+
+/**
+ * @project engine
+ *
+ * @date 12/08/2020
+ * @author xanderume@gmail.com
+ */
+class GeneralListener(private val instance: GameEngine):Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onBlockIgnite(event: BlockIgniteEvent) {
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onLeavesDecay(event: LeavesDecayEvent) {
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onCreeperPower(event: CreeperPowerEvent) {
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityExplode(event: EntityExplodeEvent) {
+ event.blockList().clear()
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onExplosionPrime(event: ExplosionPrimeEvent) {
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onWeatherChange(event: WeatherChangeEvent) {
+ event.world.time = 6000
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onEntityDamage(event: EntityDamageEvent) {
+
+ if (this.instance.gameHandler.getState() == GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ private fun onFoodLevelChange(event: FoodLevelChangeEvent) {
+
+ if (this.instance.gameHandler.getState() == GameServer.State.IN_PROGRESS) {
+ return
+ }
+
+ event.isCancelled = true
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ private fun onPlayerDeath(event: PlayerDeathEvent) {
+ event.entity.world.getEntitiesByClass(EnderPearl::class.java).filter{it.shooter != null && it.shooter is Player && (it.shooter as Player).uniqueId == event.entity.uniqueId}.forEach{it.remove()}
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ private fun onJoin(event: PlayerJoinEvent) {
+ event.joinMessage = null
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ private fun onQuit(event: PlayerQuitEvent) {
+ event.quitMessage = null
+ }
+
+}
\ No newline at end of file
diff --git a/Engine/game/src/main/kotlin/cc/fyre/engine/map/MapHandler.kt b/Engine/game/src/main/kotlin/cc/fyre/engine/map/MapHandler.kt
new file mode 100644
index 0000000..3891253
--- /dev/null
+++ b/Engine/game/src/main/kotlin/cc/fyre/engine/map/MapHandler.kt
@@ -0,0 +1,109 @@
+package cc.fyre.engine.map
+
+import cc.fyre.engine.GameEngine
+import cc.fyre.engine.GameEngineAPI
+import cc.fyre.engine.map.command.MapIconCommand
+import cc.fyre.engine.map.command.MapLoadCommand
+import cc.fyre.engine.map.command.MapTPCommand
+import cc.fyre.engine.map.command.parameter.MapParameterProvider
+import cc.fyre.engine.map.data.Map
+import cc.fyre.engine.map.event.MapLoadEvent
+import cc.fyre.engine.map.listener.MapListener
+
+import com.google.gson.JsonSyntaxException
+import com.mongodb.client.model.Filters
+import com.mongodb.client.model.UpdateOptions
+import com.mongodb.client.result.UpdateResult
+import net.frozenorb.qlib.command.FrozenCommandHandler
+import net.frozenorb.qlib.qLib
+import net.minecraft.util.org.apache.commons.io.FileUtils
+import org.bson.Document
+import org.bukkit.World
+import org.bukkit.WorldCreator
+import java.io.File
+import kotlin.collections.HashSet
+
+/**
+ * @project engine
+ *
+ * @date 10/08/2020
+ * @author xanderume@gmail.com
+ */
+class MapHandler(private val instance: GameEngine) {
+
+ val cache = HashSet