├── .gitattributes
├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── dictionaries
│ └── Simon.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── jarRepositories.xml
├── kotlinc.xml
├── misc.xml
├── modules
│ ├── WynnLab.main.iml
│ ├── WynnLab.test.iml
│ └── WynnLab_main.iml
├── uiDesigner.xml
└── vcs.xml
├── LICENSE
├── README.md
├── build.gradle
├── crowdin.yml
├── desktop.ini
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── libs
├── WynnScript2-1.0-all.jar
└── craftbukkit-1.16.5.jar
├── settings.gradle
└── src
├── main
├── java
│ └── com
│ │ └── wynnlab
│ │ └── java
│ │ └── AddItemFlags.java
├── kotlin
│ └── com
│ │ └── wynnlab
│ │ ├── Main.kt
│ │ ├── MainThread.kt
│ │ ├── Players.kt
│ │ ├── WynnClass.kt
│ │ ├── api
│ │ ├── item api.kt
│ │ ├── nms api.kt
│ │ ├── persistent data api.kt
│ │ └── player api.kt
│ │ ├── commands
│ │ ├── BaseCommand.kt
│ │ ├── BuildCommand.kt
│ │ ├── CastCommand.kt
│ │ ├── ClassCommand.kt
│ │ ├── DevCommands.kt
│ │ ├── DummyCommand.kt
│ │ ├── EssentialsCommands.kt
│ │ ├── GMCommands.kt
│ │ ├── ItemCommand.kt
│ │ ├── MobCommand.kt
│ │ ├── PVPCommands.kt
│ │ ├── RankCommand.kt
│ │ └── tab_completers
│ │ │ ├── BaseTabCompleter.kt
│ │ │ ├── BuildTabCompleter.kt
│ │ │ ├── CastTabCompleter.kt
│ │ │ ├── ClassTabCompleter.kt
│ │ │ ├── EssentialsTabCompleters.kt
│ │ │ ├── GMTabCompleters.kt
│ │ │ ├── ItemTabCompleter.kt
│ │ │ ├── MobTabCompleter.kt
│ │ │ ├── NoTabCompleter.kt
│ │ │ └── RankTabCompleter.kt
│ │ ├── entities
│ │ ├── CustomEntity.kt
│ │ ├── Dummy.kt
│ │ ├── Hologram.kt
│ │ ├── WynnMob.kt
│ │ ├── class stubs.txt
│ │ └── pathfinder
│ │ │ ├── PathfinderGoalCastSpell.kt
│ │ │ ├── PathfinderGoalMeleeAttack.kt
│ │ │ └── PathfinderGoalRangedAttack.kt
│ │ ├── essentials
│ │ ├── Party.kt
│ │ └── Rank.kt
│ │ ├── events
│ │ ├── SpellCastEvent.kt
│ │ └── WorldInstanceEvents.kt
│ │ ├── gui
│ │ ├── ClassGUI.kt
│ │ ├── CompassGUI.kt
│ │ ├── GUI.kt
│ │ └── PVPGUI.kt
│ │ ├── guilds
│ │ └── Guild.kt
│ │ ├── items
│ │ ├── Build.kt
│ │ ├── Identifications.kt
│ │ ├── SpecialItems.kt
│ │ ├── WynnItem.kt
│ │ └── api access.kt
│ │ ├── listeners
│ │ ├── BaseListener.kt
│ │ ├── CastListener.kt
│ │ ├── CommandListener.kt
│ │ ├── DamageListener.kt
│ │ ├── FallingBlockListener.kt
│ │ ├── GUIListener.kt
│ │ ├── PlayerClickListener.kt
│ │ ├── PlayerEventsListener.kt
│ │ ├── ProjectileHitListener.kt
│ │ └── ScriptAPIListeners.kt
│ │ ├── localization
│ │ └── Language.kt
│ │ ├── locations
│ │ ├── Location.kt
│ │ └── locations.kt
│ │ ├── pvp
│ │ ├── Duels.kt
│ │ └── FFA.kt
│ │ ├── scoreboard
│ │ ├── ConfiguredSidebar.kt
│ │ ├── PartySidebar.kt
│ │ ├── Sidebar.kt
│ │ ├── StandardSidebar.kt
│ │ └── elements.kt
│ │ ├── spells
│ │ ├── MobSpell.kt
│ │ ├── PlayerSpell.kt
│ │ ├── PySpell.kt
│ │ ├── Spell.kt
│ │ ├── SpellPlayer.kt
│ │ └── spell utils.kt
│ │ └── util
│ │ ├── BaseSerializable.kt
│ │ ├── Deferred.kt
│ │ ├── LocationIterator.kt
│ │ ├── OnlyAsync.kt
│ │ ├── Optional.kt
│ │ ├── RefreshRunnable.kt
│ │ ├── TickRunnable.kt
│ │ ├── WynnScript utils.kt
│ │ ├── adventure utils.kt
│ │ ├── bukkit utils.kt
│ │ ├── operators.kt
│ │ ├── resources.kt
│ │ ├── task utils.kt
│ │ ├── worlds.kt
│ │ └── wynncraft api.kt
└── resources
│ ├── classes
│ ├── assassin
│ │ ├── assassin.yml
│ │ ├── assassin_main.py
│ │ ├── multihit.py
│ │ ├── smoke_bomb.py
│ │ ├── smoke_bomb_tick.py
│ │ ├── spin_attack.py
│ │ ├── vanish.py
│ │ └── vanish_end.py
│ ├── monk
│ │ ├── control.py
│ │ ├── monk.yml
│ │ ├── monk_main.py
│ │ ├── shield.py
│ │ ├── silence.py
│ │ └── step.py
│ ├── shaman
│ │ ├── aura.py
│ │ ├── haul.py
│ │ ├── shaman.yml
│ │ ├── shaman_main.py
│ │ ├── totem.py
│ │ ├── totem_tick.py
│ │ └── uproot.py
│ └── warrior
│ │ ├── bash.py
│ │ ├── charge.py
│ │ ├── uppercut.py
│ │ ├── uppercut_throw.py
│ │ ├── war_scream.py
│ │ ├── warrior.yml
│ │ └── warrior_main.py
│ ├── lang
│ ├── ar_SA.yml
│ ├── de_DE.yml
│ └── en_us.yml
│ ├── locations.yml
│ ├── mobs
│ ├── dummy.yml
│ └── scripts
│ │ └── pull.ws2
│ └── plugin.yml
└── test
└── kotlin
├── Optional performance.kt
├── Optional test.kt
├── api test.kt
├── jstest.kt
├── p
└── IC.kt
└── scripting.kt
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.ws2 linguist-language=WynnScript
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project exclude paths
2 | /.gradle/
3 | /build/
4 | /bin/
5 | /old_builds/
6 | /libs/
7 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/dictionaries/Simon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | multihit
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/modules/WynnLab.main.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | PAPER
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/modules/WynnLab.test.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | PAPER
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/WynnLab_main.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | PAPER
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Siinus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## This Repository is archived! You can compile it and try it out anywanys though.
2 | [New Repository](https://github.com/wynnlab/wynnlab-minestom)
3 |
4 | # WynnLab
5 | [](https://discord.gg/7ktHKn2nZG)
6 | [](https://www.wynnlab.tk)
7 | 
8 | [](https://crowdin.com/project/wynnlab)
9 |
10 | Wynncraft Recreation as Minecraft 1.17 plugin
11 |
12 | This is my recreation of the popular MMORPG in Minecraft: Wynncraft.
13 |
14 | ### Join our Minecraft server: play.wynnlab.tk
15 |
16 | ---
17 | ### Usage
18 |
19 | Clone the project in IntelliJ and execute the task ShadowJar (terminal >> gradlew shadowJar).
20 |
21 | ---
22 | Credits to Wynncraft for the combat system. I'm not part of the Wynncraft team.
23 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'org.jetbrains.kotlin.jvm' version '1.5.10'
4 | }
5 |
6 | group = 'com.wynnlab'
7 | version = '1.1.0' // "git describe --tags".execute().text
8 |
9 | ext {
10 | kotlinVersion = '1.5.10'
11 | apiVersion = '1.17'
12 | paperRelease = '0.1-SNAPSHOT'
13 | }
14 |
15 | repositories {
16 | mavenCentral()
17 | maven { url 'https://papermc.io/repo/repository/maven-public/' }
18 |
19 | flatDir { dirs './libs/' }
20 | flatDir { dirs 'D:/Libraries/Java/' }
21 | flatDir { dirs 'D:/IdeaProjects/WynnLabScriptAPI/build/libs/' }
22 | flatDir { dirs 'D:/IdeaProjects/WynnLabAPI/build/libs/' }
23 | }
24 |
25 | dependencies {
26 | // Paper (Spigot) API
27 | compileOnly "io.papermc.paper:paper-api:$apiVersion-R$paperRelease"
28 |
29 | // Craftbukkit & NMS
30 | compileOnly name: "craftbukkit-$apiVersion"
31 |
32 | // WynnScript (deprecated)
33 | compileOnly name: 'WynnScript2-1.0-all'
34 |
35 | // API
36 | compileOnly name: "WynnLabAPI-$version"
37 |
38 | // Kotlin
39 | compileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
40 |
41 | // Jython
42 | compileOnly "org.python:jython-standalone:2.7.1"
43 | testImplementation "org.python:jython-standalone:2.7.1"
44 |
45 | //testCompile group: 'junit', name: 'junit', version: '4.12'
46 | }
47 |
48 | //sourceCompatibility = 16
49 | //targetCompatibility = 16
50 |
51 | compileKotlin {
52 | kotlinOptions.jvmTarget = '16'
53 | kotlinOptions.freeCompilerArgs = [ '-Xopt-in=kotlin.RequiresOptIn' ]
54 | }
55 |
56 | compileTestKotlin {
57 | kotlinOptions.jvmTarget = '16'
58 | }
59 |
60 | processResources {
61 | duplicatesStrategy = 'include'
62 | from(sourceSets.main.resources.srcDirs) {
63 | filter org.apache.tools.ant.filters.ReplaceTokens, tokens: [VERSION: version, API: apiVersion]
64 | }
65 | }
66 |
67 | java {
68 | toolchain {
69 | languageVersion = JavaLanguageVersion.of(16)
70 | }
71 | }
72 |
73 | /*task buildAndCopy {
74 | dependsOn 'shadowJar'
75 | doLast {
76 | copy {
77 | from file("D:\\IdeaProjects\\WynnLab\\build\\libs\\WynnLab-$version-all.jar")
78 | into file("M:\\plugins")
79 | }
80 | }
81 | }*/
--------------------------------------------------------------------------------
/crowdin.yml:
--------------------------------------------------------------------------------
1 | files:
2 | - source: /src/main/resources/lang
3 | ignore:
4 | - ar_sa.yml
5 | - de_de.yml
6 | - en_us.yml
7 | translation: /src/main/resources/lang/%locale_with_underscore%.yml
8 |
--------------------------------------------------------------------------------
/desktop.ini:
--------------------------------------------------------------------------------
1 | [.ShellClassInfo]
2 | IconResource=D:\Pictures\WynnLab.ico,0
3 | [ViewState]
4 | Mode=
5 | Vid=
6 | FolderType=Generic
7 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WynnLab/WynnLab-Core/9950bc1485fa187394c1b1326fa0b5c6b6a1ac96/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/libs/WynnScript2-1.0-all.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WynnLab/WynnLab-Core/9950bc1485fa187394c1b1326fa0b5c6b6a1ac96/libs/WynnScript2-1.0-all.jar
--------------------------------------------------------------------------------
/libs/craftbukkit-1.16.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WynnLab/WynnLab-Core/9950bc1485fa187394c1b1326fa0b5c6b6a1ac96/libs/craftbukkit-1.16.5.jar
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 |
2 | rootProject.name = 'WynnLab'
3 |
4 |
--------------------------------------------------------------------------------
/src/main/java/com/wynnlab/java/AddItemFlags.java:
--------------------------------------------------------------------------------
1 | package com.wynnlab.java;
2 |
3 | import org.bukkit.inventory.ItemFlag;
4 | import org.bukkit.inventory.meta.ItemMeta;
5 |
6 | public class AddItemFlags {
7 | public static void addAllItemFlags(ItemMeta meta) {
8 | meta.addItemFlags(ItemFlag.values());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/Main.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab
2 |
3 | import com.wynnlab.api.sidebars
4 | import com.wynnlab.commands.registerCommands
5 | import com.wynnlab.commands.tab_completers.registerTabCompleters
6 | import com.wynnlab.listeners.registerListeners
7 | import com.wynnlab.localization.loadLanguages
8 | import com.wynnlab.locations.loadLocations
9 | import com.wynnlab.util.DEG2RAD
10 | import com.wynnlab.util.RAD2DEG
11 | import com.wynnlab.util.registerSerializers
12 | import com.wynnlab.util.saveAllResources
13 | import net.kyori.adventure.text.Component
14 | import net.kyori.adventure.text.format.NamedTextColor
15 | import net.kyori.adventure.text.format.TextColor
16 | import org.bukkit.Bukkit
17 | import org.bukkit.GameRule
18 | import org.bukkit.World
19 | import org.bukkit.plugin.java.JavaPlugin
20 | import org.bukkit.util.Vector
21 | import org.python.util.PythonInterpreter
22 |
23 | class Main : JavaPlugin() {
24 | override fun onLoad() {
25 | instance = this
26 |
27 | python.set("plugin", this)
28 | python.set("random", random)
29 | python.set("RAD2DEG", RAD2DEG)
30 | python.set("DEG2RAD", DEG2RAD)
31 | python.set("VectorUP", Vector(0, 1, 0))
32 |
33 | saveAllResources()
34 | }
35 |
36 | override fun onEnable() {
37 | registerCommands()
38 | registerTabCompleters()
39 | registerCommands()
40 | registerListeners()
41 | registerSerializers()
42 |
43 | setGameRules()
44 | Players.initPlayers()
45 |
46 | MainThread.schedule()
47 |
48 | loadClasses()
49 |
50 | loadLanguages()
51 |
52 | loadLocations()
53 |
54 | Bukkit.getServer().spigot().spigotConfig.set("settings.attribute.maxHealth.max", 1000000)
55 | }
56 |
57 | override fun onDisable() {
58 | Bukkit.getOnlinePlayers().forEach(Players::removePlayerFromActivities)
59 |
60 | sidebars.clear()
61 |
62 | python.close()
63 | }
64 |
65 | private fun setGameRules() {
66 | Bukkit.getWorlds().forEach {
67 | setGameRules(it)
68 | }
69 | }
70 |
71 | fun setGameRules(world: World) {
72 | world.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false)
73 | world.setGameRule(GameRule.DISABLE_RAIDS, false)
74 | world.setGameRule(GameRule.DO_FIRE_TICK, false)
75 | world.setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true)
76 | world.setGameRule(GameRule.DO_LIMITED_CRAFTING, false)
77 | world.setGameRule(GameRule.DO_MOB_SPAWNING, false)
78 | world.setGameRule(GameRule.DO_PATROL_SPAWNING, false)
79 | world.setGameRule(GameRule.FALL_DAMAGE, false)
80 | world.setGameRule(GameRule.MOB_GRIEFING, false)
81 | world.setGameRule(GameRule.NATURAL_REGENERATION, false)
82 | //world.setGameRule(GameRule.REDUCED_DEBUG_INFO, true)
83 | world.setGameRule(GameRule.SPAWN_RADIUS, 0)
84 | world.setGameRule(GameRule.SPECTATORS_GENERATE_CHUNKS, false)
85 | }
86 | }
87 |
88 | private lateinit var instance: Main
89 | val wynnlab get() = instance
90 |
91 | val WL_COLOR = TextColor.color(0x82e617)
92 | val PREFIX = Component.text("[", NamedTextColor.DARK_GRAY)
93 | .append(Component.text("WynnLab", WL_COLOR))
94 | .append(Component.text("] ", NamedTextColor.DARK_GRAY))
95 | //"§8[§bWynnLab§8] §r"
96 | val PLAY_WYNNLAB_TK = Component.text("play.", TextColor.color(0x666666))
97 | .append(Component.text("WYNNLAB", WL_COLOR))
98 | .append(Component.text(".tk", TextColor.color(0x666666)))
99 |
100 | val random = java.util.Random()
101 |
102 | val python by lazy { PythonInterpreter() }
103 |
104 | val NL_REGEX = Regex("\\n")
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/MainThread.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab
2 |
3 | import com.wynnlab.api.*
4 | import com.wynnlab.essentials.Party
5 | import com.wynnlab.localization.Language
6 | import com.wynnlab.locations.updateLocations
7 | import com.wynnlab.spells.PySpell
8 | import net.kyori.adventure.text.Component
9 | import net.kyori.adventure.text.event.ClickEvent
10 | import net.kyori.adventure.text.event.HoverEvent
11 | import net.kyori.adventure.text.format.NamedTextColor
12 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
13 | import org.bukkit.Bukkit
14 | import org.bukkit.attribute.Attribute
15 | import org.bukkit.entity.Player
16 | import org.bukkit.event.Listener
17 | import org.bukkit.potion.PotionEffect
18 | import org.bukkit.potion.PotionEffectType
19 |
20 | object MainThread : Listener {
21 | fun schedule() {
22 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> onTick() }, 1L, 1L)
23 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> onSecond() }, 20L, 20L)
24 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> on4Seconds() }, 80L, 80L)
25 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> on10Seconds() }, 200L, 200L)
26 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> on5Minutes() }, 100L, 6000L)
27 | }
28 |
29 | private fun onTick() {
30 | for (player in Bukkit.getOnlinePlayers()) {
31 | val pvp = player.hasScoreboardTag("pvp")
32 |
33 | // Send action bar
34 | player.standardActionBar()
35 |
36 | // Reset exhaustion to not lose mana except in spell casts
37 | player.exhaustion = 0f
38 |
39 | // Store max health and set attribute
40 | val maxHealth = (505 + player.getId("health_bonus") + player.getArmorHealth()).coerceIn(1, 1000000).toDouble()
41 | player.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.baseValue = maxHealth
42 |
43 | if (!player.hasPotionEffect(PotionEffectType.INVISIBILITY) && "invis" in player.scoreboardTags)
44 | PySpell.castSpell(player, "ASSASSIN", 5)
45 |
46 | // Walk speed
47 | val speed = player.getId("speed")
48 | player.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED)!!.baseValue = .1 + (if (pvp) speed.coerceAtMost(100) else speed) * .001
49 | }
50 | }
51 |
52 | private fun onSecond() {
53 | Party.parties.forEach(Party::update)
54 |
55 | for (player in Bukkit.getOnlinePlayers()) {
56 | val pvp = player.hasScoreboardTag("pvp")
57 |
58 | // Natural mana regen
59 | player.foodLevel = (player.foodLevel + if (player.hasPotionEffect(PotionEffectType.INVISIBILITY)) -1 else if (pvp) 2 else 1).coerceIn(0, 20)
60 |
61 | val jumpHeight = player.getId("jump_height") - 1
62 | if (jumpHeight != 0) player.addPotionEffect(PotionEffect(PotionEffectType.JUMP, 21,
63 | if (pvp) jumpHeight.coerceAtMost(3) else jumpHeight,
64 | true, false, false))
65 |
66 | player.testInventory()
67 | player.updateLocations()
68 | player.updateSidebar()
69 | }
70 | }
71 |
72 | private fun on4Seconds() {
73 | for (player in Bukkit.getOnlinePlayers()) {
74 | if (!player.hasPotionEffect(PotionEffectType.INVISIBILITY)) player.foodLevel = (player.foodLevel + player.getId("mana_regen")).coerceIn(0, 20)
75 |
76 | if (player.hasScoreboardTag("pvp"))
77 | continue
78 | healthRegen(player, false)
79 | }
80 | }
81 |
82 | private fun on10Seconds() {
83 | for (player in Bukkit.getOnlinePlayers()) {
84 | if (!player.hasScoreboardTag("pvp"))
85 | continue
86 | healthRegen(player, true)
87 | }
88 | }
89 |
90 | private fun on5Minutes() {
91 | for (player in Bukkit.getOnlinePlayers()) {
92 | val msg = Language[player.locale()].getRandomMessageAsString("tips")
93 | var c = LegacyComponentSerializer.legacy('&').deserialize(msg)
94 | if (msg.startsWith("ᛩf2"))
95 | c = c.append(Component.text("https://discord.gg/7ktHKn2nZG", COLOR_DISCORD)
96 | .hoverEvent(HoverEvent.showText(Component.text("Click to join!", NamedTextColor.GRAY)))
97 | .clickEvent(ClickEvent.openUrl("https://discord.gg/7ktHKn2nZG")))
98 | player.sendMessage(c)
99 | }
100 | }
101 |
102 | private fun healthRegen(player: Player, pvp: Boolean) {
103 | val maxHealth = (505 + player.getId("health_bonus") + player.getArmorHealth()).coerceIn(1, 1000000).toDouble()
104 | val healthBonus = player.getId("health_regen_raw") * (1 + player.getId("health_regen") / 100f)
105 | player.health = (player.health + if (pvp && healthBonus > 2500) (healthBonus - 2500) * .15f + 2500 else healthBonus).coerceIn(1.0, maxHealth)
106 | }
107 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/WynnClass.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("Classes")
2 |
3 | package com.wynnlab
4 |
5 | import com.wynnlab.registry.ClassRegistry
6 | import com.wynnlab.spells.Spell
7 | import com.wynnlab.util.BaseSerializable
8 | import com.wynnlab.util.ConfigurationDeserializable
9 | import org.bukkit.Material
10 | import org.bukkit.configuration.file.YamlConfiguration
11 | import java.io.File
12 | import java.util.logging.Level
13 |
14 | data class WynnClass(
15 | val id: String,
16 | val item: Material,
17 | val itemDamage: Int,
18 | val metaStats: Tuple4,
19 | val invertedControls: Boolean,
20 | val spells: List
21 | ) : BaseSerializable() {
22 |
23 | override fun serialize(): Map {
24 | val out = LinkedHashMap()
25 |
26 | out["id"] = id
27 | out["item"] = item.name
28 | if (itemDamage != 0) out["item_damage"] = itemDamage
29 | out["metaStats"] = mapOf("damage" to metaStats.v1, "defence" to metaStats.v2, "range" to metaStats.v3, "spells" to metaStats.v4)
30 | out["invertedControls"] = invertedControls
31 | out["spells"] = spells
32 |
33 | return out
34 | }
35 |
36 | override val deserializer = Companion
37 |
38 | companion object : ConfigurationDeserializable {
39 | @JvmStatic
40 | @Suppress("unused", "unchecked_cast")
41 | override fun deserialize(map: Map): WynnClass {
42 | val id = map["id"] as String
43 | val item = Material.valueOf(map["item"] as String)
44 | val itemDamage = (map["item_damage"] as Number??: 0).toInt()
45 | val metaStats = map["metaStats"] as Map
46 | val invertedControls = map["invertedControls"] as Boolean
47 | val spells = map["spells"] as List
48 |
49 | spellOrdinal = 0
50 |
51 | return WynnClass(id, item, itemDamage,
52 | Tuple4(metaStats["damage"]!!.toInt(), metaStats["defence"]!!.toInt(), metaStats["range"]!!.toInt(), metaStats["spells"]!!.toInt()),
53 | invertedControls, spells)
54 | }
55 |
56 | operator fun get(string: String) = classes[string]
57 | }
58 | }
59 |
60 | val classes = linkedMapOf()
61 |
62 | internal var spellOrdinal = 0
63 |
64 | fun loadClasses() {
65 | val classFolder = File(wynnlab.dataFolder, "classes")
66 |
67 | if (!classFolder.exists()) {
68 | wynnlab.logger.log(Level.WARNING, "No classes loaded")
69 | return
70 | }
71 |
72 | for (f in classFolder.listFiles { f, _ -> f.isDirectory } ?: return) {
73 | currentClassLoadFolder = f
74 |
75 | wynnlab.logger.log(Level.INFO, "Loading class ${f.name} ...")
76 |
77 | val configFile = File(f, "${f.name}.yml")
78 | val config = YamlConfiguration()
79 | config.load(configFile)
80 | val wynnClass = config.getSerializable("class", WynnClass::class.java) ?: continue
81 | classes[wynnClass.id] = wynnClass
82 | }
83 |
84 | classes.remove("MONK")?.let { classes["MONK"] = it }
85 |
86 | ClassRegistry.entries().forEach {
87 | classes[it.id] = it
88 | }
89 |
90 | //plugin.logger.log(Level.INFO, "Classes: $classes")
91 | //plugin.logger.log(Level.INFO, "Listeners: ${plugin.projectileHitListener.tags}")
92 | }
93 |
94 | data class Tuple4(val v1: T, val v2: T, val v3: T, val v4: T)
95 |
96 | internal lateinit var currentClassLoadFolder: File
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/api/item api.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("ItemAPI")
2 |
3 | package com.wynnlab.api
4 |
5 | import com.wynnlab.items.WynnItem
6 | import org.bukkit.inventory.ItemStack
7 | import org.bukkit.inventory.meta.Damageable
8 | import org.bukkit.inventory.meta.ItemMeta
9 | import kotlin.contracts.ExperimentalContracts
10 | import kotlin.contracts.InvocationKind
11 | import kotlin.contracts.contract
12 |
13 | @OptIn(ExperimentalContracts::class)
14 | inline fun ItemStack.meta(edit: ItemMeta.() -> Unit): ItemStack {
15 | contract { callsInPlace(edit, InvocationKind.EXACTLY_ONCE) }
16 | val meta = itemMeta
17 | meta.edit()
18 | itemMeta = meta
19 | return this
20 | }
21 |
22 | //BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER
23 | @OptIn(ExperimentalContracts::class)
24 | inline fun ItemStack.metaAs(edit: T.() -> Unit): ItemStack {
25 | contract { callsInPlace(edit, InvocationKind.EXACTLY_ONCE) }
26 | val meta = itemMeta as? T ?: return this
27 | meta.edit()
28 | itemMeta = meta as ItemMeta
29 | return this
30 | }
31 |
32 | fun ItemStack.setAppearance(damage: Int): ItemStack {
33 | val meta = itemMeta
34 | (meta as Damageable).damage = damage
35 | meta.isUnbreakable = true
36 | itemMeta = meta
37 | return this
38 | }
39 |
40 | fun ItemStack.getWynnType() = itemMeta?.data?.getString("type")?.let { WynnItem.Type.valueOf(it) }
41 | fun ItemStack.takeIfType(type: WynnItem.Type) = takeIf { it.getWynnType() == type }
42 |
43 | fun ItemStack.getClassReq() = itemMeta?.data?.getString("class_req")
44 |
45 | fun ItemStack.getAttackSpeed() = itemMeta?.data?.getString("attack_speed")?.let { WynnItem.AttackSpeed.valueOf(it) }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/api/nms api.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.api
2 |
3 | //val World.nms get() = (this as CraftWorld).handle
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/api/persistent data api.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("PersistentDataAPI")
2 |
3 | package com.wynnlab.api
4 |
5 | import com.wynnlab.wynnlab
6 | import org.bukkit.NamespacedKey
7 | import org.bukkit.persistence.PersistentDataContainer
8 | import org.bukkit.persistence.PersistentDataHolder
9 | import org.bukkit.persistence.PersistentDataType
10 |
11 | inline val PersistentDataHolder.data get() = persistentDataContainer
12 |
13 | operator fun PersistentDataContainer.get(key: String, type: PersistentDataType) =
14 | try { this[NamespacedKey(wynnlab, key), type] } catch (e: IllegalArgumentException) { null }
15 |
16 | fun PersistentDataContainer.getString(key: String, default: String? = null) = this[key, PersistentDataType.STRING] ?: default
17 |
18 | fun PersistentDataContainer.getInt(key: String, default: Int? = null) = this[key, PersistentDataType.INTEGER] ?: default
19 |
20 | fun PersistentDataContainer.getIntArray(key: String, default: IntArray? = null) = this[key, PersistentDataType.INTEGER_ARRAY] ?: default
21 |
22 | fun PersistentDataContainer.getContainer(key: String, default: PersistentDataContainer? = null) = this[key, PersistentDataType.TAG_CONTAINER] ?: default
23 |
24 | fun PersistentDataContainer.getContainerArray(key: String, default: Array? = null): Array? = this[key, PersistentDataType.TAG_CONTAINER_ARRAY] ?: default
25 |
26 | fun PersistentDataContainer.getBoolean(key: String, default: Boolean = false): Boolean { return (this[key, PersistentDataType.BYTE] ?: return default) != 0.toByte() }
27 |
28 | fun PersistentDataContainer.getDouble(key: String, default: Double? = null) = this[key, PersistentDataType.DOUBLE] ?: default
29 |
30 |
31 | operator fun PersistentDataContainer.set(key: String, type: PersistentDataType, value: Z) =
32 | set(NamespacedKey(wynnlab, key), type, value!!)
33 |
34 | fun PersistentDataContainer.setString(key: String, value: String) = set(key, PersistentDataType.STRING, value)
35 |
36 | fun PersistentDataContainer.setInt(key: String, value: Int) = set(key, PersistentDataType.INTEGER, value)
37 |
38 | fun PersistentDataContainer.setIntArray(key: String, value: IntArray) = set(key, PersistentDataType.INTEGER_ARRAY, value)
39 |
40 | fun PersistentDataContainer.setContainer(key: String, value: PersistentDataContainer.() -> Unit) {
41 | val container = adapterContext.newPersistentDataContainer()
42 | container.value()
43 | set(key, PersistentDataType.TAG_CONTAINER, container)
44 | }
45 |
46 | fun PersistentDataContainer.setBoolean(key: String, value: Boolean) = set(key, PersistentDataType.BYTE, if (value) 1.toByte() else 0.toByte())
47 |
48 | fun PersistentDataContainer.setDouble(key: String, value: Double) = set(key, PersistentDataType.DOUBLE, value)
49 |
50 |
51 | fun PersistentDataContainer.remove(key: String) = remove(NamespacedKey(wynnlab, key))
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/BaseCommand.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.command.CommandExecutor
5 |
6 | abstract class BaseCommand(vararg val names: String) : CommandExecutor
7 |
8 | fun registerCommands() {
9 | registerCommand(BuildCommand)
10 | registerCommand(CastCommand)
11 | registerCommand(ClassCommand)
12 | registerCommand(DevCommands)
13 | registerCommand(DummyCommand)
14 | registerCommand(EssentialsCommands)
15 | registerCommand(GMCommands)
16 | registerCommand(ItemCommand)
17 | registerCommand(MobCommand)
18 | registerCommand(PVPCommands)
19 | registerCommand(RankCommand)
20 | }
21 |
22 | private fun registerCommand(command: BaseCommand) {
23 | for (name in command.names)
24 | wynnlab.getCommand(name)?.setExecutor(command)
25 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/BuildCommand.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.items.Build
4 | import org.bukkit.command.Command
5 | import org.bukkit.command.CommandSender
6 | import org.bukkit.entity.Player
7 |
8 | object BuildCommand : BaseCommand("build") {
9 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
10 | val player = (sender as? Player) ?: return true
11 | if (args.isEmpty()) return false
12 |
13 | return when (args[0]) {
14 | "save" -> save(player, args)
15 | "equip" -> equip(player, args)
16 | "delete" -> delete(player, args)
17 | "publish" -> publish(player, args)
18 | "show" -> show(player, args)
19 | else -> false
20 | }
21 | }
22 |
23 | private fun save(player: Player, args: Array): Boolean {
24 | if (args.size != 2) return false
25 | val eq = player.equipment
26 | Build[player.uniqueId, args[1]] = Build(eq?.helmet, eq?.chestplate, eq?.leggings, eq?.boots, eq?.itemInMainHand)
27 | return true
28 | }
29 |
30 | private fun equip(player: Player, args: Array): Boolean {
31 | if (args.size != 2) return false
32 | (Build[player.uniqueId, args[1]] ?: run {
33 | player.sendMessage("§cThe build §f${args[1]}§c doesn't exist")
34 | return true
35 | }).equip(player)
36 | return true
37 | }
38 |
39 | private fun delete(player: Player, args: Array): Boolean {
40 | if (args.size != 2) return false
41 | Build.remove(player.uniqueId, args[1]) ?: player.sendMessage("§cThe build §f${args[1]}§c doesn't exist")
42 | return true
43 | }
44 |
45 | private fun publish(player: Player, args: Array): Boolean {
46 | if (args.size == 2) player.sendMessage("§cSpecify a name for the build (e.g. §fVery cool build§c)")
47 | if (args.size < 3) return false
48 | (Build[player.uniqueId, args[1]] ?: run {
49 | player.sendMessage("§cThe build §f${args[1]}§c doesn't exist")
50 | return true
51 | }).publish(args.slice(2 until args.size).joinToString(" "))
52 | return true
53 | }
54 |
55 | private fun show(player: Player, args: Array): Boolean {
56 | if (args.size != 1) return false
57 | Build.GUI(player).show()
58 | return true
59 | }
60 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/CastCommand.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.api.getWynnClass
4 | import com.wynnlab.events.SpellCastEvent
5 | import org.bukkit.Bukkit
6 | import org.bukkit.command.Command
7 | import org.bukkit.command.CommandSender
8 | import org.bukkit.entity.Player
9 |
10 | object CastCommand : BaseCommand("cast") {
11 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
12 | if (sender !is Player) {
13 | sender.sendMessage("§cThis command can only be executed by players")
14 | return true
15 | }
16 | if (args.size != 1) {
17 | sender.sendMessage("§cPlease specify a spell id")
18 | return false
19 | }
20 | val wynnClass = sender.getWynnClass()
21 | if (wynnClass == null) {
22 | sender.sendMessage("§cPLease select a class first")
23 | return true
24 | }
25 | val spell = args[0].toIntOrNull()
26 | if (spell == null || spell < 0 || spell > 4) {
27 | sender.sendMessage("§c'${args[0]}' is not a valid spell id")
28 | return false
29 | }
30 | Bukkit.getPluginManager().callEvent(SpellCastEvent(sender, spell))
31 | return true
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/ClassCommand.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.api.hasScoreboardTag
4 | import com.wynnlab.api.setWynnClass
5 | import com.wynnlab.gui.ClassGUI
6 | import org.bukkit.command.Command
7 | import org.bukkit.command.CommandSender
8 | import org.bukkit.entity.Player
9 |
10 | object ClassCommand : BaseCommand("class") {
11 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
12 | if (sender !is Player) {
13 | sender.sendMessage("§cThis command can only be executed by players")
14 | return true
15 | }
16 |
17 | if (sender.hasScoreboardTag("pvp")) {
18 | sender.sendMessage("§cYou can't change your class in PVP")
19 | return true
20 | }
21 |
22 | if (args.size != 1) {
23 | return if (args.isEmpty()) {
24 | ClassGUI(sender).show()
25 | true
26 | } else false
27 | }
28 | sender.setWynnClass(args[0].toUpperCase())
29 | return true
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/DevCommands.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.api.getId
4 | import com.wynnlab.api.sendWynnMessage
5 | import com.wynnlab.localization.Language
6 | import org.bukkit.command.Command
7 | import org.bukkit.command.CommandSender
8 | import org.bukkit.entity.Player
9 |
10 | /**
11 | * Commands:
12 | * - itemdata
13 | * - getid
14 | * - script //TODO
15 | */
16 | object DevCommands : BaseCommand("itemdata", "getid") {
17 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
18 | if (!sender.isOp) {
19 | sender.sendMessage("§4You need to be an operator to execute this command")
20 | return true
21 | }
22 | return when (label) {
23 | "itemdata" -> itemdata(sender, args)
24 | "getid" -> getid(sender, args)
25 | else -> false
26 | }
27 | }
28 |
29 | private fun itemdata(sender: CommandSender, args: Array): Boolean {
30 | if (sender !is Player) {
31 | sender.sendMessage("§cThis command can only be performed by players")
32 | return true
33 | }
34 | if (args.isEmpty()) {
35 | sender.sendMessage("§cPlease specify an item index")
36 | return false
37 | }
38 | sender.performCommand("data get entity @s Inventory[${args[0]}].tag.PublicBukkitValues${
39 | if (args.size == 1) "" else args.slice(1 until args.size).joinToString(".", ".") { "wynnlab:$it" }
40 | }")
41 | return true
42 | }
43 |
44 | private fun getid(sender: CommandSender, args: Array): Boolean {
45 | if (!sender.isOp) {
46 | if (sender is Player)
47 | sender.sendWynnMessage("commands.no_op")
48 | else
49 | sender.sendMessage(Language.en_us.getMessage("commands.no_op"))
50 | return true
51 | }
52 | if (args.isEmpty()) {
53 | sender.sendMessage("§cPlease specify an id name")
54 | return false
55 | }
56 |
57 | val id = args[0]
58 |
59 | val target: Player = if (args.size == 1) {
60 | if (sender is Player) sender else null
61 | } else {
62 | if (args.size == 2) sender.server.selectEntities(sender, args[1]).filterIsInstance().let {
63 | if (it.size != 1) null
64 | else it[0]
65 | } else null
66 | } ?: run {
67 | sender.sendMessage("§cPlease specify one valid target")
68 | return false
69 | }
70 |
71 | sender.sendMessage("§b${target.name}§7's id '§e$id§7' is: ${target.getId(id).let { if (it > 0) "§a+$it" else "§c$it" }}")
72 |
73 | return true
74 | }
75 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/DummyCommand.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.api.hasScoreboardTag
4 | import com.wynnlab.entities.Dummy
5 | import org.bukkit.command.Command
6 | import org.bukkit.command.CommandSender
7 | import org.bukkit.entity.Player
8 |
9 | object DummyCommand : BaseCommand("dummy") {
10 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
11 | if (sender !is Player) {
12 | sender.sendMessage("§cThis command can only be executed by players")
13 | return true
14 | }
15 |
16 | if (sender.hasScoreboardTag("pvp")) {
17 | sender.sendMessage("§cYou can't spawn a dummy during pvp")
18 | return true
19 | }
20 |
21 | if (args.isNotEmpty())
22 | return false
23 |
24 | Dummy(sender.location).spawn(sender.world)
25 | /*val wynnMob = WynnMob("Dummy", EntityTypes.VINDICATOR, WynnMob.AI.values()[random.nextInt(4)], 0, 100000, 0, 0..0,
26 | 1.0, null, .1, .0, false, false, false, .0,
27 | null, null, SoundEffects.ENTITY_DONKEY_DEATH, SoundEffects.BLOCK_GLASS_BREAK, SoundEffects.ENTITY_ENDER_DRAGON_DEATH, .0,
28 | WynnMob.Equipment(null), listOf())*/
29 |
30 | //wynnMob.spawn(sender.location)
31 |
32 | return true
33 | }
34 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/GMCommands.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.WynnClass
4 | import com.wynnlab.classes
5 | import com.wynnlab.loadClasses
6 | import com.wynnlab.wynnlab
7 | import org.bukkit.Bukkit
8 | import org.bukkit.command.Command
9 | import org.bukkit.command.CommandSender
10 | import org.bukkit.configuration.file.YamlConfiguration
11 | import java.io.File
12 | import java.io.FileWriter
13 | import java.io.IOException
14 | import java.net.MalformedURLException
15 | import java.net.URL
16 |
17 | object GMCommands : BaseCommand("upload", "wlrl") {
18 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean =
19 | when (label) {
20 | "upload" -> upload(sender, args)
21 | "wlrl" -> wlrl(sender, args)
22 | else -> false
23 | }
24 |
25 | private fun upload(sender: CommandSender, args: Array): Boolean {
26 | if (!/*sender.hasPermission("gm")*/sender.isOp) {
27 | sender.sendMessage("§cYou don't have permission to perform this command")
28 | return true
29 | }
30 |
31 | if (args.size < 3)
32 | return false
33 |
34 | val newFileLoc = when (args[0]) {
35 | "item" -> File(wynnlab.dataFolder, "custom_items")
36 | "mob" -> File(wynnlab.dataFolder, "mobs")
37 | "mob_spell" -> File(File(wynnlab.dataFolder, "mobs"), "scripts")
38 | "music" -> File(Bukkit.getPluginManager().getPlugin("JukeBox")?.dataFolder, "songs")
39 | else -> return false
40 | }
41 |
42 | if (!newFileLoc.exists()) newFileLoc.mkdirs()
43 |
44 | val downloadFile = File(newFileLoc, args[1])
45 | if (!downloadFile.createNewFile()) {
46 | sender.sendMessage("The file ${args[1]} already exists")
47 | return true
48 | }
49 |
50 | val url = try {
51 | URL(args.slice(2 until args.size).joinToString("%20"))
52 | } catch (e: MalformedURLException) {
53 | sender.sendMessage("§cMalformed URL")
54 | return false
55 | }
56 |
57 | val text = try {
58 | url.openStream().reader().readText()
59 | } catch (e: IOException) {
60 | sender.sendMessage("§cIO Exception")
61 | return true
62 | }
63 |
64 | FileWriter(downloadFile).use { writer ->
65 | writer.write(text)
66 | }
67 |
68 | sender.sendMessage("§aSuccessfully uploaded your ${args[0]} to ${args[1]}")
69 |
70 | return true
71 | }
72 |
73 | private fun wlrl(sender: CommandSender, args: Array): Boolean {
74 | if (!/*sender.hasPermission("gm")*/sender.isOp) {
75 | sender.sendMessage("§cYou don't have permission to perform this command")
76 | return true
77 | }
78 |
79 | if (args.isEmpty())
80 | return false
81 |
82 | when (args[0]) {
83 | "mobs" -> {
84 | MobCommand.mobs.clear()
85 | }
86 | "mob" -> {
87 | if (args.size < 2) {
88 | sender.sendMessage("§cPlease specify a mob to reload")
89 | return false
90 | }
91 | MobCommand.mobs.remove(args[1]) ?: run {
92 | sender.sendMessage("§cThe mob ${args[1]} doesn't exist")
93 | return false
94 | }
95 | }
96 | "classes" -> {
97 | classes.clear()
98 | loadClasses()
99 | }
100 | "class" -> {
101 | if (args.size < 2) {
102 | sender.sendMessage("§cPlease specify a class to reload")
103 | return false
104 | }
105 | classes[args[1]] ?: run {
106 | sender.sendMessage("§cThe class ${args[1]} doesn't exist")
107 | return true
108 | }
109 | val configFile = (File(wynnlab.dataFolder, "classes").listFiles { _, name -> name.equals(args[1]) })?.let { files ->
110 | if (files.isEmpty()) null
111 | else files[0]
112 | } ?: run {
113 | sender.sendMessage("§cThe class ${args[1]} doesn't exist")
114 | return true
115 | }
116 | val config = YamlConfiguration()
117 | config.load(configFile)
118 | config.getSerializable("class", WynnClass::class.java)?.let { classes.replace(args[1], it) } ?: run {
119 | sender.sendMessage("§cMalformed config")
120 | return true
121 | }
122 | }
123 | }
124 |
125 | sender.sendMessage("§aReloaded ${args.joinToString(" ")}")
126 |
127 | return true
128 | }
129 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/ItemCommand.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.api.hasScoreboardTag
4 | import com.wynnlab.items.SpecialItems
5 | import com.wynnlab.items.WynnItem
6 | import com.wynnlab.items.getAPIResults
7 | import com.wynnlab.wynnlab
8 | import net.kyori.adventure.text.Component
9 | import org.bukkit.Bukkit
10 | import org.bukkit.command.Command
11 | import org.bukkit.command.CommandSender
12 | import org.bukkit.entity.Player
13 |
14 | object ItemCommand : BaseCommand("item") {
15 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
16 | if (sender !is Player) {
17 | sender.sendMessage("§cThis command can only be executed by players")
18 | return true
19 | }
20 |
21 | if (sender.hasScoreboardTag("pvp")) {
22 | sender.sendMessage("§cYou can't give yourself items during pvp")
23 | return true
24 | }
25 |
26 | if (args.isEmpty()) {
27 | sender.sendMessage("§cPlease specify an item name")
28 | return false
29 | }
30 |
31 | val itemName = args.joinToString(" ")
32 |
33 | try {
34 | sender.inventory.addItem(SpecialItems.valueOf(itemName).itemStack(sender))
35 | } catch (ignored: IllegalArgumentException) { }
36 |
37 | getAPIResults(itemName).execute { jsonObjects ->
38 | if (jsonObjects.isEmpty()) {
39 | sender.sendMessage("§c\"$itemName\" was not found")
40 | return@execute
41 | }
42 | if (jsonObjects.size == 1) {
43 | val wynnItem = WynnItem.parse(jsonObjects[0])
44 | sender.inventory.addItem(wynnItem.generateNewItem(sender))
45 | } else {
46 | val inv = Bukkit.createInventory(sender, (jsonObjects.size / 9 + 1) * 9, Component.text("Your Items"))
47 | val wynnItems = jsonObjects.mapNotNull { WynnItem.parse(it).takeUnless { we -> we.isNormal() } }
48 | inv.addItem(*Array(wynnItems.size) { i ->
49 | wynnItems[i].generateNewItem(sender)
50 | })
51 | Bukkit.getScheduler().scheduleSyncDelayedTask(wynnlab) {
52 | sender.openInventory(inv)
53 | }
54 | }
55 | }
56 |
57 | return true
58 | }
59 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/PVPCommands.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.api.hasScoreboardTag
4 | import com.wynnlab.api.sendWynnMessage
5 | import com.wynnlab.gui.PVPGUI
6 | import org.bukkit.Bukkit
7 | import org.bukkit.command.Command
8 | import org.bukkit.command.CommandSender
9 | import org.bukkit.entity.Player
10 |
11 | object PVPCommands : BaseCommand("pvp", "hub", "leave", "stats") {
12 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
13 | return when (label) {
14 | "pvp" -> pvp(sender, args)
15 | "hub" -> hub(sender, args)
16 | "leave", "l" -> leave(sender, args)
17 | "stats" -> stats(sender, args)
18 | else -> false
19 | }
20 | }
21 |
22 | fun pvp(sender: CommandSender, args: Array): Boolean {
23 | if (args.isNotEmpty())
24 | return false
25 |
26 | if (sender !is Player) {
27 | sender.sendMessage("§cThis command can only be executed by players!")
28 | return true
29 | }
30 |
31 | if (sender.hasScoreboardTag("pvp")) {
32 | sender.sendMessage("§cYou can't use that command during pvp")
33 | return true
34 | }
35 |
36 | PVPGUI(sender).show()
37 |
38 | return true
39 | }
40 |
41 | private fun hub(sender: CommandSender, args: Array): Boolean {
42 | if (args.isNotEmpty())
43 | return false
44 |
45 | if (sender !is Player) {
46 | sender.sendMessage("§cThis command can only be executed by players!")
47 | return true
48 | }
49 |
50 | sender.teleport(Bukkit.getWorld("neww")!!.spawnLocation)
51 |
52 | return true
53 | }
54 |
55 | private fun leave(sender: CommandSender, args: Array): Boolean {
56 | if (args.isNotEmpty())
57 | return false
58 |
59 | if (sender !is Player) {
60 | sender.sendMessage("§cThis command can only be executed by players!")
61 | return true
62 | }
63 |
64 | if (!sender.hasScoreboardTag("pvp")) {
65 | sender.sendMessage("§cThere's nothing to leave")
66 | return true
67 | }
68 |
69 | sender.teleport(Bukkit.getWorld("neww")!!.spawnLocation)
70 |
71 | return true
72 | }
73 |
74 | private fun stats(sender: CommandSender, args: Array): Boolean {
75 | if (args.size > 1)
76 | return false
77 |
78 | if (sender !is Player) {
79 | sender.sendMessage("§cThis command can only be executed by players!")
80 | return true
81 | }
82 |
83 | if (!sender.hasScoreboardTag("ffa")) {
84 | sender.sendMessage("§cYou don't have stats here")
85 | return true
86 | }
87 |
88 | val target = if (args.isEmpty()) sender else Bukkit.getPlayer(args[0]) ?: run {
89 | sender.sendWynnMessage("messages.player_not_exist")
90 | return true
91 | }
92 |
93 | sender.sendWynnMessage("messages.stats.stats_of", target.name)
94 | sender.sendWynnMessage("messages.stats.kills", 0)
95 | sender.sendWynnMessage("messages.stats.deaths", 0)
96 | sender.sendWynnMessage("messages.stats.kd", 0)
97 | sender.sendWynnMessage("messages.stats.damage_dealt", 0)
98 | sender.sendWynnMessage("messages.stats.damage_taken", 0)
99 |
100 | return true
101 | }
102 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/RankCommand.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands
2 |
3 | import com.wynnlab.essentials.Rank
4 | import org.bukkit.command.Command
5 | import org.bukkit.command.CommandSender
6 | import org.bukkit.entity.Player
7 |
8 | object RankCommand : BaseCommand("rank") {
9 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
10 | if (!sender.isOp) {
11 | sender.sendMessage("§cYou need to be an operator to execute this command")
12 | return true
13 | }
14 | if (args.isEmpty()) {
15 | sender.sendMessage("§cPlease specify a rank")
16 | return false
17 | }
18 |
19 | val rank: Rank = try {
20 | Rank.valueOf(args[0].toUpperCase())
21 | } catch (e: IllegalArgumentException) {
22 | sender.sendMessage("§cPlease specify a valid rank")
23 | return false
24 | }
25 |
26 | val targets: List = if (args.size == 1) {
27 | if (sender is Player) listOf(sender) else null
28 | } else {
29 | if (args.size == 2) sender.server.selectEntities(sender, args[1]).filterIsInstance() else null
30 | } ?: run {
31 | sender.sendMessage("§cPlease specify a valid target")
32 | return false
33 | }
34 |
35 | targets.forEach {
36 | rank.apply(it)
37 | }
38 |
39 | return true
40 | }
41 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/BaseTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.command.TabCompleter
5 |
6 | abstract class BaseTabCompleter(vararg val names: String) : TabCompleter {
7 | fun completeWord(words: List, input: String) = words.filter { it.startsWith(input) }
8 | }
9 |
10 | fun registerTabCompleters() {
11 | registerTabCompleter(BuildTabCompleter)
12 | registerTabCompleter(CastTabCompleter)
13 | registerTabCompleter(ClassTabCompleter)
14 | registerTabCompleter(EssentialsTabCompleters)
15 | registerTabCompleter(GMTabCompleters)
16 | registerTabCompleter(ItemTabCompleter)
17 | registerTabCompleter(MobTabCompleter)
18 | registerTabCompleter(RankTabCompleter)
19 | registerTabCompleter(NoTabCompleter)
20 | }
21 |
22 | private fun registerTabCompleter(tabCompleter: BaseTabCompleter) {
23 | for (name in tabCompleter.names)
24 | wynnlab.getCommand(name)?.tabCompleter = tabCompleter
25 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/BuildTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import com.wynnlab.items.Build
4 | import org.bukkit.command.Command
5 | import org.bukkit.command.CommandSender
6 | import org.bukkit.entity.Player
7 |
8 | object BuildTabCompleter : BaseTabCompleter("build") {
9 | override fun onTabComplete(
10 | sender: CommandSender,
11 | command: Command,
12 | alias: String,
13 | args: Array
14 | ): List? = if (sender is Player && args.size == 2) when (args[0]) {
15 | "save" -> emptyList()
16 | "equip", "delete", "publish" -> completeWord(Build.buildNamesOf(sender).toList(), args[1])
17 | else -> null
18 | } else if (args.size == 1) completeWord(subcommands, args[0]) else emptyList()
19 |
20 | private val subcommands = listOf("save", "equip", "delete", "publish", "show")
21 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/CastTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import org.bukkit.command.Command
4 | import org.bukkit.command.CommandSender
5 |
6 | object CastTabCompleter : BaseTabCompleter("cast") {
7 | override fun onTabComplete(
8 | sender: CommandSender,
9 | command: Command,
10 | alias: String,
11 | args: Array
12 | ): List? = if (args.size == 1)
13 | castIds
14 | else null
15 |
16 | private val castIds = listOf("1", "2", "3", "4")
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/ClassTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import org.bukkit.command.Command
4 | import org.bukkit.command.CommandSender
5 |
6 | object ClassTabCompleter : BaseTabCompleter("class") {
7 | override fun onTabComplete(
8 | sender: CommandSender,
9 | command: Command,
10 | alias: String,
11 | args: Array
12 | ): List? = if (args.size == 1)
13 | completeWord(classes, args[0])
14 | else null
15 |
16 | private val classes = listOf("archer", "assassin", "mage", "shaman", "warrior")
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/EssentialsTabCompleters.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import org.bukkit.command.Command
4 | import org.bukkit.command.CommandSender
5 | import org.bukkit.entity.Player
6 |
7 | object EssentialsTabCompleters : BaseTabCompleter("msg", "party") {
8 | override fun onTabComplete(
9 | sender: CommandSender,
10 | command: Command,
11 | alias: String,
12 | args: Array
13 | ): List? =
14 | when (alias) {
15 | "msg" -> {
16 | if (args.size == 1)
17 | (sender as? Player)?.world?.players?.map { it.name }
18 | else null
19 | }
20 | "party" -> {
21 | when {
22 | args.size == 1 -> completeWord(partyArgs, args[0])
23 | args.size > 1 -> when (args[0]) {
24 | "invite" -> (sender as? Player)?.world?.players?.map { it.name }
25 | else -> null
26 | }
27 | else -> null
28 | }
29 | }
30 | else -> null
31 | }
32 |
33 | private val partyArgs = listOf("create", "invite", "join", "leave")
34 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/GMTabCompleters.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("IntroduceWhenSubject")
2 |
3 | package com.wynnlab.commands.tab_completers
4 |
5 | import org.bukkit.command.Command
6 | import org.bukkit.command.CommandSender
7 |
8 | object GMTabCompleters : BaseTabCompleter("upload", "wlrl") {
9 | override fun onTabComplete(
10 | sender: CommandSender,
11 | command: Command,
12 | alias: String,
13 | args: Array
14 | ): List? =
15 | when (alias) {
16 | "upload" -> if (args.size == 1)
17 | completeWord(uploadArgs, args[0])
18 | else null
19 | "wlrl" -> when {
20 | args.size == 1 -> completeWord(wlrlArgs, args[0])
21 | else -> null
22 | }
23 | else -> null
24 | }
25 |
26 | private val uploadArgs = listOf("item", "mob", "mob_spell", "music")
27 |
28 | private val wlrlArgs = listOf("mob", "mobs", "class", "classes")
29 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/ItemTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import com.wynnlab.items.getAPIResults
4 | import org.bukkit.command.Command
5 | import org.bukkit.command.CommandSender
6 |
7 | object ItemTabCompleter : BaseTabCompleter("item") {
8 | override fun onTabComplete(
9 | sender: CommandSender,
10 | command: Command,
11 | alias: String,
12 | args: Array
13 | ): List? {
14 | if (args.isEmpty())
15 | return null
16 |
17 | val itemName = args.joinToString(" ")
18 |
19 | if (itemName.length < 3)
20 | return listOf(args.last())
21 |
22 | val apiResults = getAPIResults(itemName).task()
23 |
24 | val list = apiResults.mapNotNull {
25 | it["name"] as String?
26 | }
27 |
28 | return if (args.size == 1)
29 | list
30 | else
31 | list.filter { it.startsWith(itemName, ignoreCase = true) }
32 | .map { it.substring(itemName.length - args.last().length) }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/MobTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.command.Command
5 | import org.bukkit.command.CommandSender
6 | import java.io.File
7 |
8 | object MobTabCompleter : BaseTabCompleter("mob") {
9 | override fun onTabComplete(
10 | sender: CommandSender,
11 | command: Command,
12 | alias: String,
13 | args: Array
14 | ): List? {
15 | if (args.isEmpty())
16 | return null
17 |
18 | return completeWord(
19 | (File(wynnlab.dataFolder, "mobs").list() ?: return emptyList()).asList()
20 | .filter { it.endsWith(".yml") }.map { it.substring(0, it.length - 4) },
21 | args[0])
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/NoTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import org.bukkit.command.Command
4 | import org.bukkit.command.CommandSender
5 |
6 | object NoTabCompleter : BaseTabCompleter("pvp", "hub", "leave") {
7 | override fun onTabComplete(
8 | _0: CommandSender,
9 | _1: Command,
10 | _2: String,
11 | _3: Array
12 | ): List? = null
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/commands/tab_completers/RankTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.commands.tab_completers
2 |
3 | import org.bukkit.command.Command
4 | import org.bukkit.command.CommandSender
5 |
6 | object RankTabCompleter : BaseTabCompleter("rank") {
7 | override fun onTabComplete(
8 | sender: CommandSender,
9 | command: Command,
10 | alias: String,
11 | args: Array
12 | ): List? = if (args.size == 1)
13 | completeWord(ranks, args[0])
14 | else null
15 |
16 | private val ranks = listOf("player", "vip", "vip+", "hero", "champion", "ct", "mod", "admin")
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/entities/CustomEntity.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.entities
2 |
3 | import net.minecraft.world.entity.Entity
4 | import org.bukkit.World
5 | import org.bukkit.craftbukkit.v1_17_R1.CraftWorld
6 | import org.bukkit.event.entity.CreatureSpawnEvent
7 |
8 | interface CustomEntity {
9 | fun spawn(world: World) {
10 | (world as CraftWorld).addEntity(this as Entity, CreatureSpawnEvent.SpawnReason.CUSTOM)
11 | }
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/entities/Dummy.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.entities
2 |
3 | import net.minecraft.network.chat.ChatComponentText
4 | import net.minecraft.world.entity.EntityTypes
5 | import net.minecraft.world.entity.ai.attributes.GenericAttributes
6 | import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat
7 | import net.minecraft.world.entity.monster.EntityVindicator
8 | import org.bukkit.Location
9 | import org.bukkit.craftbukkit.v1_17_R1.CraftWorld
10 | import org.bukkit.entity.Vindicator
11 |
12 | class Dummy(location: Location) : EntityVindicator(EntityTypes.aW, (location.world as CraftWorld).handle), CustomEntity {
13 | init {
14 | setLocation(location.x, location.y, location.z, location.yaw, location.pitch)
15 |
16 | //collides = false
17 |
18 | customName = ChatComponentText("Dummy")
19 | customNameVisible = true
20 |
21 | getAttributeInstance(GenericAttributes.a)!!.value = 100000.0
22 | health = 100000f
23 | }
24 |
25 | override fun initPathfinder() {
26 | bO.a(0, PathfinderGoalFloat(this))
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/entities/Hologram.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.entities
2 |
3 | import com.wynnlab.wynnlab
4 | import net.minecraft.network.chat.ChatComponentText
5 | import net.minecraft.world.entity.EntityTypes
6 | import net.minecraft.world.entity.decoration.EntityArmorStand
7 | import org.bukkit.Bukkit
8 | import org.bukkit.Location
9 | import org.bukkit.craftbukkit.v1_17_R1.CraftWorld
10 | import org.bukkit.entity.ArmorStand
11 |
12 | class Hologram(location: Location, text: String) : EntityArmorStand(EntityTypes.c, (location.world as CraftWorld).handle), CustomEntity {
13 | init {
14 | isInvisible = true
15 | isInvulnerable = true
16 | collides = false
17 | isNoGravity = true
18 | isSmall = true
19 |
20 | setLocation(location.x, location.y, location.z, location.yaw, location.pitch)
21 |
22 | customName = ChatComponentText(text)
23 | customNameVisible = true
24 | }
25 |
26 | fun removeAfter(time: Long) = Bukkit.getScheduler().runTaskLater(wynnlab, ::remove, time)
27 |
28 | fun remove() {
29 | die()
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/entities/class stubs.txt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.entities
2 |
3 | import com.wynnlab.spells.MobSpell
4 | import net.minecraft.server.v1_16_R3.Entity
5 | import net.minecraft.server.v1_16_R3.EntityTypes
6 | import net.minecraft.server.v1_16_R3.EntityVindicator
7 | import org.bukkit.Location
8 | import org.bukkit.Sound
9 | import org.bukkit.craftbukkit.v1_16_R3.CraftWorld
10 | import org.bukkit.entity.Projectile
11 | import org.bukkit.entity.Vindicator
12 |
13 | class WEntityImpl(
14 | val location: Location,
15 | val name: String,
16 | val level: Int,
17 | val ai: WynnMob.AI,
18 | val health: Int,
19 | val regen: Int,
20 | val damage: IntRange,
21 | val attackSpeed: Double,
22 | val projectile: Class?,
23 | val speed: Double,
24 | val vision: Double,
25 | val invisible: Boolean = false,
26 | val burning: Boolean = false,
27 | val baby: Boolean = false,
28 | val defense: Double,
29 | val elementalDamage: WynnMob.Elemental?,
30 | val elementalDefense: WynnMob.Elemental?,
31 | val ambientSound: Sound,
32 | val hurtSound: Sound,
33 | val deathSound: Sound,
34 | val kbResistance: Double,
35 | val spells: List
36 | ) : WEntity {
37 | override fun init(entity: Entity) {
38 | entity.setLocation(location.x, location.y, location.z, location.yaw, location.pitch)
39 | }
40 | }
41 |
42 | interface WEntity : CustomEntity {
43 | fun init(entity: Entity)
44 | }
45 |
46 | class WVindicator(
47 | location: Location,
48 | name: String,
49 | level: Int,
50 | ai: WynnMob.AI,
51 | health: Int,
52 | regen: Int,
53 | damage: IntRange,
54 | attackSpeed: Double,
55 | projectile: Class?,
56 | speed: Double,
57 | vision: Double,
58 | invisible: Boolean = false,
59 | burning: Boolean = false,
60 | baby: Boolean = false,
61 | defense: Double,
62 | elementalDamage: WynnMob.Elemental?,
63 | elementalDefense: WynnMob.Elemental?,
64 | ambientSound: Sound,
65 | hurtSound: Sound,
66 | deathSound: Sound,
67 | kbResistance: Double,
68 | spells: List
69 | ) : EntityVindicator(EntityTypes.VINDICATOR, (location.world as CraftWorld).handle),
70 | WEntity by WEntityImpl(location, name, level, ai, health, regen, damage, attackSpeed, projectile, speed, vision, invisible, burning, baby, defense, elementalDamage, elementalDefense, ambientSound, hurtSound, deathSound, kbResistance, spells) {
71 | init {
72 | init(this)
73 | }
74 | }
75 | fun createWVindicator(
76 | location: Location,
77 | name: String,
78 | level: Int,
79 | ai: WynnMob.AI,
80 | health: Int,
81 | regen: Int,
82 | damage: IntRange,
83 | attackSpeed: Double,
84 | projectile: Class?,
85 | speed: Double,
86 | vision: Double,
87 | invisible: Boolean = false,
88 | burning: Boolean = false,
89 | baby: Boolean = false,
90 | defense: Double,
91 | elementalDamage: WynnMob.Elemental?,
92 | elementalDefense: WynnMob.Elemental?,
93 | ambientSound: Sound,
94 | hurtSound: Sound,
95 | deathSound: Sound,
96 | kbResistance: Double,
97 | spells: List
98 | ) = WVindicator(location, name, level, ai, health, regen, damage, attackSpeed, projectile, speed, vision, invisible, burning, baby, defense, elementalDamage, elementalDefense, ambientSound, hurtSound, deathSound, kbResistance, spells)
99 |
100 | val entityTypeToClass: Map, (Location, String, Int, WynnMob.AI, Int, Int, IntRange, Double, Class?, Double, Double, Boolean, Boolean, Boolean, Double, WynnMob.Elemental?, WynnMob.Elemental?, Sound, Sound, Sound, Double, List) -> Entity> =
101 | hashMapOf(EntityTypes.VINDICATOR to ::createWVindicator)
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/entities/pathfinder/PathfinderGoalCastSpell.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.entities.pathfinder
2 |
3 | import com.wynnlab.base.BaseSpell
4 | import com.wynnlab.mobs.spells.BaseMobSpell
5 | import com.wynnlab.spells.MobSpell
6 | import com.wynnlab.wynnlab
7 | import net.minecraft.server.level.EntityPlayer
8 | import net.minecraft.world.entity.EntityCreature
9 | import net.minecraft.world.entity.EntityLiving
10 | import net.minecraft.world.entity.ai.goal.PathfinderGoal
11 | import org.bukkit.Bukkit
12 | import org.bukkit.NamespacedKey
13 | import org.bukkit.entity.Entity
14 | import org.bukkit.entity.Player
15 | import java.util.*
16 |
17 | class PathfinderGoalCastSpell(private val creature: EntityCreature, range: Double, private val spells: List) : PathfinderGoal() {
18 | private val range = range * range
19 |
20 | private var cooldown = 20
21 | private var prepare = 0
22 |
23 | private var target: EntityLiving? = null
24 |
25 | private var mobSpell: MobSpell? = null
26 | private var baseMobSpell: BaseMobSpell? = null
27 | private var runnable: MobSpell.Ticks? = null
28 |
29 | init {
30 | a(EnumSet.of(Type.b))
31 | }
32 |
33 | override fun a(): Boolean {
34 | if (cooldown > 0) {
35 | --cooldown
36 | return false
37 | }
38 |
39 | target = (creature.goalTarget as? EntityPlayer) ?: return false
40 |
41 | if (target == null)
42 | return false
43 |
44 | if (target!!.f(creature) > range)
45 | return false
46 |
47 | return true
48 | }
49 |
50 | override fun c() {
51 | val spell = try { spells.random() } catch (e: NoSuchElementException) { return }
52 | if (spell is MobSpell) mobSpell = spell else baseMobSpell = (spell as (Entity, Player) -> BaseMobSpell)(creature.bukkitEntity, target!!.bukkitEntity as Player)
53 |
54 | cooldown = mobSpell?.cooldown ?: baseMobSpell!!.cooldown
55 | prepare = mobSpell?.prepareTime ?: 20
56 |
57 | //spell!!.spellEffects(creature.bukkitEntity)
58 | mobSpell?.spellEffects(creature.bukkitEntity) ?: MobSpell.spellEffects(creature.bukkitEntity)
59 |
60 | if (mobSpell?.hasBossBar == true)
61 | creature.bukkitEntity.world.getNearbyEntities(creature.bukkitEntity.location, 10.0, 10.0, 10.0) { it is Player }
62 | .forEach { mobSpell!!.bossBar!!.addPlayer(it as Player) }
63 | }
64 |
65 | override fun b(): Boolean {
66 | if (mobSpell == null && baseMobSpell == null)
67 | return false
68 |
69 | if (prepare > 0) {
70 | --prepare
71 |
72 | if (mobSpell?.hasBossBar == true)
73 | mobSpell!!.bossBar!!.progress = 1.0 - prepare / mobSpell!!.prepareTime.toDouble()
74 |
75 | return true
76 | } else if (prepare == 0) {
77 | if (mobSpell?.hasBossBar == true) {
78 | mobSpell!!.bossBar!!.removeAll()
79 | Bukkit.removeBossBar(NamespacedKey(wynnlab, "prepare_${creature.id}"))
80 | }
81 |
82 | runnable = mobSpell?.newInstance(creature.bukkitEntity, target!!.bukkitEntity as Player)
83 | baseMobSpell?.onCast()
84 | --prepare
85 | }
86 |
87 | if (!(runnable?.tick() ?: true.also { baseMobSpell!!.onTick() }))
88 | return false
89 |
90 | //++runnable!!.t
91 | runnable?.t?.inc() ?: baseMobSpell!!.t.inc()
92 |
93 | val cancel = (runnable?.t ?: baseMobSpell!!.t) > (mobSpell?.maxTick ?: BaseSpell::class.java.getDeclaredField("maxTick").getInt(runnable))
94 |
95 | if (cancel && baseMobSpell != null)
96 | baseMobSpell!!.onCancel()
97 |
98 | return !cancel
99 | }
100 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/entities/pathfinder/PathfinderGoalMeleeAttack.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.entities.pathfinder
2 |
3 | class PathfinderGoalMeleeAttack
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/entities/pathfinder/PathfinderGoalRangedAttack.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.entities.pathfinder
2 |
3 | import net.minecraft.world.entity.EntityCreature
4 | import net.minecraft.world.entity.EntityLiving
5 | import net.minecraft.world.entity.ai.goal.PathfinderGoal
6 | import org.bukkit.Material
7 | import org.bukkit.entity.Projectile
8 | import org.bukkit.entity.Snowball
9 | import org.bukkit.inventory.ItemStack
10 | import org.bukkit.projectiles.ProjectileSource
11 | import java.util.*
12 |
13 | class PathfinderGoalRangedAttack(private val creature: EntityCreature, range: Double, private val cooldown: Int, private val projectile: Class, private val projectileMaterial: Material?) : PathfinderGoal() {
14 | private val range = range * range
15 |
16 | private var c = cooldown
17 |
18 | private var target: EntityLiving? = null
19 |
20 | init {
21 | a(EnumSet.of(Type.b))
22 | }
23 |
24 | override fun a(): Boolean {
25 | if (c > 0) {
26 | --c
27 | return false
28 | }
29 |
30 | c = cooldown
31 |
32 | target = creature.goalTarget
33 |
34 | if (target == null)
35 | return false
36 |
37 | if (target!!.f(creature) > range)
38 | return false
39 |
40 | return true
41 | }
42 |
43 | override fun c() {
44 | val p = ((creature.bukkitEntity as? ProjectileSource) ?: return).launchProjectile(projectile, target!!.bukkitEntity.location.toVector().subtract(creature.bukkitEntity.location.toVector()).normalize().multiply(3))
45 |
46 | if (p is Snowball && projectileMaterial != null)
47 | p.item = ItemStack(projectileMaterial)
48 |
49 | p.addScoreboardTag("mob_projectile")
50 | }
51 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/essentials/Party.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.essentials
2 |
3 | import com.wynnlab.COLOR_HEALTH_HEART
4 | import com.wynnlab.COLOR_HEALTH_VALUE
5 | import com.wynnlab.COLOR_PARTY
6 | import com.wynnlab.PREFIX
7 | import com.wynnlab.api.sendWynnMessage
8 | import com.wynnlab.localization.Language
9 | import net.kyori.adventure.text.Component
10 | import net.kyori.adventure.text.event.ClickEvent
11 | import net.kyori.adventure.text.event.HoverEvent
12 | import net.kyori.adventure.text.format.NamedTextColor
13 | import net.kyori.adventure.text.format.Style
14 | import net.kyori.adventure.text.format.TextDecoration
15 | import org.bukkit.entity.Player
16 |
17 | data class Party(
18 | var owner: Player,
19 | val members: MutableList = mutableListOf()
20 | ) {
21 | var healthTexts = listOf()
22 |
23 | fun addMember(player: Player) {
24 | this.members.forEach {
25 | it.sendWynnMessage("messages.party.joined", player.name)
26 | }
27 |
28 | this.members.add(player)
29 | Party.members[player] = this
30 |
31 | player.sendWynnMessage("messages.party.joined_you")
32 | }
33 |
34 | fun removeMember(player: Player) {
35 | player.sendWynnMessage("messages.party.left_you")
36 |
37 | this.members.remove(player)
38 | Party.members.remove(player)
39 |
40 | this.members.forEach {
41 | it.sendWynnMessage("messages.party.left", player.name)
42 | }
43 |
44 | if (members.isEmpty()) {
45 | parties.remove(this)
46 | return
47 | }
48 |
49 | if (player == owner) {
50 | promote(this.members[0])
51 | }
52 | }
53 |
54 | private fun promote(player: Player) {
55 | player.sendWynnMessage("messages.party.promote")
56 |
57 | owner = player
58 | }
59 |
60 | @Suppress("unchecked_cast")
61 | fun invite(player: Player) {
62 | invites[player] = this
63 |
64 | val language = Language[player.locale()]
65 |
66 | player.sendMessage("$PREFIX${language.getMessage("messages.party.invite.get", owner.name)}")
67 |
68 | player.sendMessage(
69 | Component.text("$PREFIX${language.getMessage("messages.party.join.left")}")
70 | .append(language.getMessage("messages.party.join.link")
71 | .hoverEvent { HoverEvent.showText(
72 | language.getMessage("messages.party.join.hover")
73 | ) as HoverEvent }
74 | .clickEvent(ClickEvent.runCommand("/party join")))
75 | .append(language.getMessage("messages.party.join.right"))
76 | )
77 |
78 | owner.sendWynnMessage("messages.party.invite.send", player.name)
79 | }
80 |
81 | internal fun update() {
82 | healthTexts = members.sortedBy { it.health }.map {
83 | Component.text("- ", COLOR_PARTY)
84 | .append(Component.text(it.health.toInt(), COLOR_HEALTH_VALUE))
85 | .append(Component.text("❤ ", COLOR_HEALTH_HEART))
86 | .append(Component.text(it.name, if (it.isDead) Style.style(NamedTextColor.DARK_GRAY, TextDecoration.STRIKETHROUGH) else Style.style(NamedTextColor.WHITE)))
87 | }
88 | }
89 |
90 | fun getSbTexts(): List {
91 | return healthTexts
92 | }
93 |
94 | companion object {
95 | val parties = mutableListOf()
96 |
97 | val members = mutableMapOf()
98 |
99 | val invites = mutableMapOf()
100 | }
101 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/essentials/Rank.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.essentials
2 |
3 | import com.wynnlab.api.data
4 | import com.wynnlab.api.prefix
5 | import com.wynnlab.api.setString
6 | import org.bukkit.ChatColor
7 | import org.bukkit.entity.Player
8 |
9 | enum class Rank(
10 | val donation: Boolean,
11 | val tag: String,
12 | private val color: ChatColor
13 | ) {
14 | PLAYER(false, "", ChatColor.WHITE),
15 |
16 | VIP(true, "§a[VIP] ", ChatColor.GREEN),
17 | @Suppress("EnumEntryName") `VIP+`(true, "§b[§3VIP+§b] ", ChatColor.AQUA),
18 | HERO(true, "§5[§dHERO§5] ", ChatColor.DARK_PURPLE),
19 | CHAMPION(true, "§e[§6CHAMPION§e] ", ChatColor.YELLOW),
20 |
21 | CT(false, "§3[CT] ", ChatColor.DARK_AQUA),
22 | MOD(false, "§6[§eMOD§6] ", ChatColor.GOLD),
23 | ADMIN(false, "§4[§cADMIN§4] ", ChatColor.DARK_RED);
24 |
25 | /*private val team: Team = registerMainTeam("WynnLab.${name}")
26 |
27 | init {
28 | team.color = color
29 | team.prefix = tag
30 | team.displayName = name
31 | }*/
32 |
33 | fun apply(player: Player) {
34 | //team.addEntry(player.name)
35 | player.prefix = tag+color
36 | player.data.setString("rank", name)
37 | }
38 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/events/SpellCastEvent.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.events
2 |
3 | import org.bukkit.entity.Player
4 | import org.bukkit.event.Event
5 | import org.bukkit.event.HandlerList
6 |
7 | class SpellCastEvent(val player: Player, val spellId: Int) : Event() {
8 | override fun getHandlers(): HandlerList = handlerList
9 |
10 | companion object {
11 | @JvmStatic
12 | val handlerList = HandlerList()
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/events/WorldInstanceEvents.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.events
2 |
3 | class DeleteWorldInstanceEvent()
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/gui/ClassGUI.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.gui
2 |
3 | import com.wynnlab.Tuple4
4 | import com.wynnlab.WynnClass
5 | import com.wynnlab.api.*
6 | import com.wynnlab.classes
7 | import com.wynnlab.classes.BaseClass
8 | import com.wynnlab.util.emptyComponent
9 | import org.bukkit.Sound
10 | import org.bukkit.entity.Player
11 | import org.bukkit.event.inventory.ClickType
12 | import org.bukkit.inventory.ItemFlag
13 | import org.bukkit.inventory.ItemStack
14 | import org.bukkit.inventory.meta.Damageable
15 |
16 | class ClassGUI(player: Player) : GUI(player, player.getLocalizedText("gui.class.title"), 1) {
17 | private val classCount = classes.size
18 | private val itemPositions = (5 - (classCount + .5f) / 2f).toInt()..(4 + classCount / 2)
19 |
20 | init {
21 | registerListener { e ->
22 | e.isCancelled = true
23 |
24 | val classIndex = itemPositions.indexOf(e.slot)
25 | if (classIndex == -1) return@registerListener
26 | val clazz = classes.values.toList()[classIndex]
27 |
28 | if (when (e.click) {
29 | ClickType.LEFT, ClickType.SHIFT_LEFT -> false
30 | ClickType.RIGHT, ClickType.SHIFT_RIGHT -> true
31 | else -> return@registerListener
32 | }) {
33 | player.sendWynnMessage("gui.class.select", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.cloneName"))
34 | player.addScoreboardTag("clone")
35 | } else {
36 | player.sendWynnMessage("gui.class.select", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.className"))
37 | player.removeScoreboardTag("clone")
38 | }
39 |
40 | player.playSound(player.location, Sound.ENTITY_PLAYER_LEVELUP, 1f, 1f)
41 |
42 | player.setWynnClass((clazz as? WynnClass)?.id ?: (clazz as BaseClass).id)
43 |
44 | player.closeInventory()
45 | }
46 | }
47 |
48 | override fun update() {
49 | val iterator = itemPositions.iterator()
50 |
51 | for (clazz in classes.values) {
52 | /*if (clazz is BaseClass) {
53 | inventory.setItem(iterator.nextInt(), ItemStack(Material.BARRIER))
54 | continue
55 | }
56 | if (clazz !is WynnClass && clazz !is BaseClass)
57 | continue*/
58 |
59 | val item = (clazz as? WynnClass)?.item?.let { ItemStack(it) } ?: (clazz as BaseClass).item
60 | val meta = item.itemMeta
61 |
62 | meta.isUnbreakable = true
63 | meta.addItemFlags(*ItemFlag.values())
64 |
65 | if (clazz is WynnClass && clazz.itemDamage != 0 && meta is Damageable)
66 | meta.damage = clazz.itemDamage
67 |
68 | meta.displayName(player.getLocalizedText("gui.class.item.title", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.className")))
69 | val lore = mutableListOf(emptyComponent)
70 |
71 | val (damage, defence, range, spells) = (clazz as? WynnClass)?.metaStats ?: (clazz as BaseClass).metaStats.let { (a, b, c, d) -> Tuple4(a, b, c, d) }
72 | lore.add(player.getLocalizedText("gui.class.item.damage", damage.squares()))
73 | lore.add(player.getLocalizedText("gui.class.item.defence", defence.squares()))
74 | lore.add(player.getLocalizedText("gui.class.item.range", range.squares()))
75 | lore.add(player.getLocalizedText("gui.class.item.spells", spells.squares()))
76 |
77 | lore.add(emptyComponent)
78 | lore.addAll(player.getLocalizedTextMultiline("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.lore"))
79 |
80 | lore.add(player.getLocalizedText("gui.class.item.clone", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.cloneName")))
81 |
82 | meta.lore(lore)
83 | item.itemMeta = meta
84 |
85 | inventory.setItem(iterator.nextInt(), item)
86 | }
87 | }
88 |
89 | private fun Int.squares() = when (this) {
90 | 0 -> "§7■■■■■"
91 | 1 -> "§a■§7■■■■"
92 | 2 -> "§a■■§7■■■"
93 | 3 -> "§a■■■§7■■"
94 | 4 -> "§a■■■■§7■"
95 | else -> "§a■■■■■"
96 | }
97 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/gui/GUI.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.gui
2 |
3 | import com.wynnlab.api.meta
4 | import com.wynnlab.listeners.GUIListener
5 | import com.wynnlab.localization.Language
6 | import com.wynnlab.wynnlab
7 | import net.kyori.adventure.text.Component
8 | import net.kyori.adventure.text.TextComponent
9 | import org.bukkit.Bukkit
10 | import org.bukkit.Material
11 | import org.bukkit.entity.Player
12 | import org.bukkit.event.inventory.InventoryClickEvent
13 | import org.bukkit.inventory.ItemStack
14 |
15 | abstract class GUI(
16 | val player: Player,
17 | val title: TextComponent,
18 | private val rows: Int
19 | ) {
20 | val inventory = Bukkit.createInventory(player, rows * 9, title)
21 |
22 | protected val language = Language[player.locale()]
23 |
24 | private val decorator get() = com.wynnlab.gui.decorator
25 |
26 | fun decorate() {
27 | var i = 0
28 | while (i < rows * 9) {
29 | if (i / 9 == 0 || i / 9 == rows - 1)
30 | inventory.setItem(i, decorator)
31 | else if (i % 9 == 0 || i % 9 == 8)
32 | inventory.setItem(i, decorator)
33 | ++i
34 | }
35 | }
36 |
37 | abstract fun update()
38 |
39 | fun show() {
40 | Bukkit.getScheduler().runTaskAsynchronously(
41 | wynnlab, Runnable {
42 | showSync()
43 | })
44 | }
45 |
46 | fun showSync() {
47 | update()
48 | Bukkit.getScheduler().scheduleSyncDelayedTask(wynnlab) {
49 | player.openInventory(inventory)
50 | }
51 | }
52 |
53 | @GuiListener
54 | inline fun registerListener(crossinline action: (InventoryClickEvent) -> Unit) {
55 | GUIListener.inventories[title.content()] = {
56 | action(it)
57 | update()
58 | }
59 | }
60 | }
61 |
62 | @DslMarker
63 | annotation class GuiListener
64 |
65 | private val decorator = ItemStack(Material.BLACK_STAINED_GLASS_PANE).meta {
66 | displayName(Component.empty())
67 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/gui/PVPGUI.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.gui
2 |
3 | import com.wynnlab.api.getLocalizedString
4 | import com.wynnlab.api.getLocalizedText
5 | import com.wynnlab.api.getLocalizedTextMultiline
6 | import com.wynnlab.api.meta
7 | import com.wynnlab.java.AddItemFlags
8 | import com.wynnlab.pvp.Duels
9 | import com.wynnlab.pvp.FFA
10 | import com.wynnlab.util.emptyComponent
11 | import org.bukkit.Material
12 | import org.bukkit.entity.Player
13 | import org.bukkit.inventory.ItemStack
14 | import org.bukkit.inventory.meta.Damageable
15 |
16 | class PVPGUI(player: Player) : GUI(player, player.getLocalizedText("gui.pvp.title"), 3) {
17 | init {
18 | registerListener { e ->
19 | e.isCancelled = true
20 | when (val slot = e.slot) {
21 | 10 -> FFA.join(player)
22 | else -> {
23 | val index = slot - 11
24 | val currentDuels = Duels.duels.size
25 | if (index == currentDuels) {
26 | // Start duel
27 | Duels.startDuel(player, 0)
28 | player.closeInventory()
29 | } else if (index < currentDuels) {
30 | // Join / leave duel
31 | val duel = Duels.duels[index]
32 | if (duel.player1?.name != player.name && duel.player2?.name != player.name) {
33 | duel.join(player)
34 | } else if (e.isRightClick) {
35 | duel.leave(player)
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
43 | override fun update() {
44 | decorate()
45 |
46 | inventory.setItem(10, ItemStack(if (FFA.players.size < 100) Material.GREEN_CONCRETE else Material.RED_CONCRETE).meta {
47 | //(this as Damageable).damage = 20
48 | //isUnbreakable = true
49 | //addItemFlags(*ItemFlag.values())
50 |
51 | displayName(player.getLocalizedText("gui.pvp.ffa.title"))
52 | val l = mutableListOf(emptyComponent)
53 | l.addAll(player.getLocalizedTextMultiline("gui.pvp.ffa.lore"))
54 | l.add(emptyComponent)
55 | l.add(player.getLocalizedText("gui.pvp.ffa.online", FFA.players.size, 100))
56 | lore(l)
57 | })
58 |
59 | var i = 10
60 | for (duel in Duels.duels) {
61 | ++i
62 |
63 | val full = duel.player1 != null && duel.player2 != null
64 | inventory.setItem(i, ItemStack(Material.GOLDEN_SHOVEL).meta {
65 | (this as Damageable).damage = if (full) 18 else if (duel.ready) 20 else 19
66 | isUnbreakable = true
67 | AddItemFlags.addAllItemFlags(this)
68 |
69 | displayName(player.getLocalizedText("gui.pvp.duel.title"))
70 | lore(listOf(
71 | player.getLocalizedText("gui.pvp.duel.map", player.getLocalizedString("gui.pvp.duel.maps.${Duels.maps[duel.map]}")),
72 | emptyComponent,
73 | player.getLocalizedText("gui.pvp.duel.player1", duel.player1?.name ?: "-"),
74 | player.getLocalizedText("gui.pvp.duel.player2", duel.player2?.name ?: "-"),
75 | emptyComponent,
76 | player.getLocalizedText(if (full) "gui.pvp.duel.spectate" else if (duel.player1?.name != player.name && duel.player2?.name != player.name) "gui.pvp.duel.join" else "gui.pvp.duel.leave")
77 | ))
78 | })
79 | }
80 |
81 | ++i
82 | inventory.setItem(i, ItemStack(Material.GOLDEN_SHOVEL).meta {
83 | (this as Damageable).damage = 22
84 | isUnbreakable = true
85 | AddItemFlags.addAllItemFlags(this)
86 |
87 | displayName(player.getLocalizedText("gui.pvp.duel.create.title"))
88 | })
89 | }
90 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/guilds/Guild.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.guilds
2 |
3 | import com.wynnlab.api.metaAs
4 | import com.wynnlab.util.OnlyAsync
5 | import com.wynnlab.util.getWynncraftAPIResult
6 | import org.bukkit.DyeColor
7 | import org.bukkit.Material
8 | import org.bukkit.block.banner.Pattern
9 | import org.bukkit.block.banner.PatternType
10 | import org.bukkit.inventory.ItemFlag
11 | import org.bukkit.inventory.ItemStack
12 | import org.bukkit.inventory.meta.BannerMeta
13 | import org.json.simple.JSONArray
14 | import org.json.simple.JSONObject
15 |
16 | @OnlyAsync
17 | class Guild(val name: String) {
18 | private val guildObject = getWynncraftAPIResult("https://api.wynncraft.com/public_api.php?action=guildStats&command=${name.replace(" ", "%20")}").task()
19 | val tag = guildObject["prefix"] as String
20 |
21 | val members = (guildObject["members"] as JSONArray).associate { data -> data as JSONObject
22 | (data["name"] as String) to Member(
23 | Member.Rank.valueOf(data["rank"] as String),
24 | data["joinedFriendly"] as String
25 | )
26 | }
27 |
28 | val banner: ItemStack = try {
29 | val bannerData = guildObject["banner"] as JSONObject
30 | ItemStack(Material.valueOf("${bannerData["base"]}_BANNER")).metaAs {
31 | addItemFlags(*ItemFlag.values())
32 | for (layer in bannerData["layers"] as JSONArray) { layer as JSONObject
33 | addPattern(Pattern(DyeColor.valueOf(layer["colour"] as String), PatternType.valueOf(layer["pattern"] as String)))
34 | }
35 | }
36 | } catch (e: Exception) {
37 | ItemStack(Material.WHITE_BANNER)
38 | }
39 |
40 | data class Member(
41 | val rank: Rank,
42 | val joined: String
43 | ) {
44 | enum class Rank {
45 | OWNER, CHIEF, STRATEGIST, CAPTAIN, RECRUITER, RECRUIT;
46 |
47 | val friendlyName = name.toLowerCase().capitalize()
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/items/SpecialItems.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.items
2 |
3 | import com.wynnlab.api.*
4 | import com.wynnlab.listeners.PlayerClickListener
5 | import com.wynnlab.spells.PySpell
6 | import com.wynnlab.util.emptyComponent
7 | import org.bukkit.Color
8 | import org.bukkit.Material
9 | import org.bukkit.entity.Player
10 | import org.bukkit.inventory.ItemFlag
11 | import org.bukkit.inventory.ItemStack
12 | import org.bukkit.inventory.meta.PotionMeta
13 |
14 | enum class SpecialItems(val itemStack: (Player) -> ItemStack, private val rightClick: ((Player, ItemStack) -> Unit)?) {
15 | HealPotion ({ p ->
16 | ItemStack(Material.POTION).metaAs {
17 | addItemFlags(*ItemFlag.values())
18 |
19 | color = Color.FUCHSIA
20 |
21 | displayName(p.getLocalizedText("items.heal_potion.title", 3))
22 |
23 | val lore = mutableListOf(emptyComponent,
24 | p.getLocalizedText("items.heal_potion.effects"),
25 | p.getLocalizedText("items.heal_potion.heal", 24),
26 | p.getLocalizedText("items.heal_potion.duration"),
27 | emptyComponent,
28 | p.getLocalizedText("items.items.combat_lv_min", "§a✔", 5),
29 | emptyComponent
30 | )
31 |
32 | lore.addAll(p.getLocalizedTextMultiline("items.heal_potion.lore"))
33 |
34 | lore(lore)
35 |
36 | data.setString("type", "HealPotion")
37 | data.setInt("healing", 24)
38 |
39 | }}, { p, i ->
40 | i.itemMeta.data.getInt("healing")?.toDouble()?.let { PySpell.heal(p, it) }
41 | });
42 |
43 | init {
44 | if (rightClick != null)
45 | PlayerClickListener.rcEvents[name] = { e -> e.item?.let { rightClick.invoke(e.player, it) } }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/items/api access.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.items
2 |
3 | import com.wynnlab.wynnlab
4 | import com.wynnlab.util.Deferred
5 | import com.wynnlab.util.getWynncraftAPIResult
6 | import com.wynnlab.util.jsonParser
7 | import org.json.simple.JSONObject
8 | import java.io.File
9 | import java.io.FileNotFoundException
10 |
11 | @Suppress("unchecked_cast")
12 | @Throws(APIException::class)
13 | fun getAPIResults(search: String): Deferred> = Deferred {
14 | val root = getWynncraftAPIResult("https://api.wynncraft.com/public_api.php?action=itemDB&search=${search.replace(" ", "%20")}").task()
15 | val items = (root["items"] as List).toMutableList()
16 |
17 | val customItems = customItemFolder?.listFiles { file -> search in file.name } ?: arrayOf()
18 | customItems.forEach { item ->
19 | items.add(jsonParser.parse(item.readText()) as JSONObject)
20 | }
21 |
22 | items
23 | }
24 |
25 | val customItemFolder by lazy { try { File(wynnlab.dataFolder, "custom_items") } catch (e: FileNotFoundException) { null } }
26 |
27 | class APIException(message: String) : Exception("Could not access the API ($message)")
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/listeners/BaseListener.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.listeners
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.Bukkit
5 | import org.bukkit.event.Listener
6 |
7 | abstract class BaseListener : Listener
8 |
9 | fun registerListeners() {
10 | registerListener(CastListener())
11 | registerListener(CommandListener())
12 | registerListener(DamageListener())
13 | registerListener(FallingBlockListener())
14 | registerListener(GUIListener())
15 | registerListener(PlayerClickListener())
16 | registerListener(PlayerEventsListener())
17 | registerListener(ProjectileHitListener())
18 | registerListener(ScriptAPIListeners())
19 | }
20 |
21 | private fun registerListener(listener: BaseListener) {
22 | Bukkit.getPluginManager().registerEvents(listener, wynnlab)
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/listeners/CastListener.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.listeners
2 |
3 | import com.wynnlab.WynnClass
4 | import com.wynnlab.api.*
5 | import com.wynnlab.classes
6 | import com.wynnlab.classes.BaseClass
7 | import com.wynnlab.classes.BasePlayerSpell
8 | import com.wynnlab.events.SpellCastEvent
9 | import com.wynnlab.spells.Spell
10 | import com.wynnlab.spells.lifeSteal
11 | import com.wynnlab.spells.manaSteal
12 | import com.wynnlab.util.RefreshRunnable
13 | import net.kyori.adventure.text.Component
14 | import net.kyori.adventure.text.format.NamedTextColor
15 | import net.kyori.adventure.text.format.TextColor
16 | import org.bukkit.Sound
17 | import org.bukkit.entity.Player
18 | import org.bukkit.event.EventHandler
19 | import org.bukkit.event.EventPriority
20 | import kotlin.math.ceil
21 | import kotlin.math.floor
22 |
23 | class CastListener : BaseListener() {
24 | @EventHandler(priority = EventPriority.HIGHEST)
25 | fun onSpellCast(e: SpellCastEvent) {
26 | val player = e.player
27 | val spellClass = player.getWynnClass()?.let { classes[it] } ?: return
28 | val spellId = e.spellId
29 | val spell = ((spellClass as? WynnClass)?.spells?.get(spellId) ?: (spellClass as BaseClass).spells[spellId](player))
30 |
31 | val cost = cost(player, spellId, (spell as? Spell)?.cost ?: (spell as BasePlayerSpell).cost)
32 |
33 | if (spellId > 0) {
34 | player.data.setInt("spell_cost_extra", if (player.data.getInt("last_spell") == spellId) (player.data.getInt("spell_cost_extra") ?: 0) + 1 else 0)
35 | player.data.setInt("last_spell", spellId)
36 |
37 | RefreshRunnable(player.data, "spell_cost_extra") {
38 | player.data.setInt("spell_cost_extra", 0)
39 | player.data.setInt("last_spell", 0)
40 | }.schedule(100L)
41 | }
42 |
43 | if (spellId > 0) {
44 | if (player.foodLevel > cost) {
45 | player.playSound(player.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, .5f)
46 | player.updateActionBar(
47 | player.getLocalizedText("classes.${player.getWynnClass()}.spells.${if (player.isCloneClass) "${spellId}c" else spellId.toString()}")
48 | .color(TextColor.color(0x75ebf0))
49 | .append(Component.text(" Cast ", TextColor.color(0x9feaed)))
50 | .append(Component.text("[",TextColor.color(0x23abb0)))
51 | .append(Component.text(-cost, TextColor.color(0x23e1e8)))
52 | .append(Component.text("✺ ", TextColor.color(0x2bd3d9)))
53 | .append(Component.text("]",TextColor.color(0x23abb0)))
54 | //"${} Cast " +
55 | // "§3[§b-${cost}✺§3]"
56 | )
57 | player.foodLevel -= cost
58 | } else {
59 | player.playSound(player.location, Sound.BLOCK_ANVIL_PLACE, 1f, 1f)
60 | player.updateActionBar(Component.text("Not enough mana!", NamedTextColor.DARK_RED))
61 | return
62 | }
63 | } else {
64 | if (player.cooldown()) return
65 | }
66 |
67 | if (player.removeScoreboardTag("life_steal"))
68 | lifeSteal(player.getId("life_steal"), player)
69 | if (player.removeScoreboardTag("mana_steal"))
70 | manaSteal(player.getId("mana_steal"), player)
71 | player.removeScoreboardTag("no_life_steal")
72 | player.removeScoreboardTag("no_mana_steal")
73 | player.removeScoreboardTag("no_exploding")
74 |
75 | (spell as? Spell)?.cast(player) ?: (spell as BasePlayerSpell).schedule()
76 | }
77 |
78 | private fun cost(player: Player, spellIndex: Int, cost: Int) =
79 | floor(ceil(cost * (1.0 - skillPercentage(player.getSkill(2)).let { if (player.hasScoreboardTag("pvp")) it.coerceAtMost(.55) else it }) + player.getId("spell_cost_raw_$spellIndex")) *
80 | (1.0 + player.getId("spell_cost_pct_$spellIndex") / 100.0) + (player.data.getInt("spell_cost_extra") ?: 0)).coerceAtLeast(1.0).toInt()
81 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/listeners/CommandListener.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.listeners
2 |
3 | import org.bukkit.event.EventHandler
4 | import org.bukkit.event.player.PlayerCommandPreprocessEvent
5 |
6 | class CommandListener : BaseListener() {
7 | @EventHandler
8 | fun onCommandPreprocess(e: PlayerCommandPreprocessEvent) {
9 | if (e.message == "/kill") {
10 | e.player.health = .0
11 | e.message = "/wynnlab:class"
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/listeners/FallingBlockListener.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.listeners
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.Bukkit
5 | import org.bukkit.Particle
6 | import org.bukkit.entity.FallingBlock
7 | import org.bukkit.event.EventHandler
8 | import org.bukkit.event.EventPriority
9 | import org.bukkit.event.entity.EntityChangeBlockEvent
10 |
11 | class FallingBlockListener : BaseListener() {
12 | @EventHandler(priority = EventPriority.HIGHEST)
13 | fun onTouchGround(e: EntityChangeBlockEvent) {
14 | if (e.entity is FallingBlock) {
15 | if (!e.to.hasGravity()) {
16 | e.entity.world.spawnParticle(Particle.BLOCK_CRACK, e.entity.location, 16, 1.0, 0.25, 1.0, 1.0, e.to.createBlockData())
17 | val from = e.block.type
18 | Bukkit.getScheduler().runTaskLater(wynnlab, Runnable { e.block.type = from }, 2L)
19 | e.entity.remove()
20 | e.isCancelled = true
21 | }
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/listeners/PlayerClickListener.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.listeners
2 |
3 | import com.wynnlab.api.*
4 | import com.wynnlab.gui.CompassGUI
5 | import org.bukkit.GameMode
6 | import org.bukkit.event.EventHandler
7 | import org.bukkit.event.EventPriority
8 | import org.bukkit.event.block.Action
9 | import org.bukkit.event.player.PlayerAnimationEvent
10 | import org.bukkit.event.player.PlayerAnimationType
11 | import org.bukkit.event.player.PlayerInteractEvent
12 | import org.bukkit.inventory.EquipmentSlot
13 |
14 | class PlayerClickListener : BaseListener() {
15 | @EventHandler(priority = EventPriority.HIGHEST)
16 | fun onLeftClick(e: PlayerAnimationEvent) {
17 | if (e.player.gameMode != GameMode.ADVENTURE)
18 | return
19 | if (e.animationType != PlayerAnimationType.ARM_SWING)
20 | return
21 |
22 | e.player.inventory.itemInMainHand.itemMeta?.data?.getString("type")?.let {
23 | lcEvents[it]?.invoke(e)
24 | }
25 |
26 | if (!e.player.checkWeapon())
27 | return
28 |
29 | e.player.addLeftClick()
30 |
31 | e.isCancelled = true
32 | }
33 |
34 | @EventHandler(priority = EventPriority.HIGHEST)
35 | fun onRightClick(e: PlayerInteractEvent) {
36 | if (e.player.gameMode != GameMode.ADVENTURE)
37 | return
38 | if (e.action != Action.RIGHT_CLICK_BLOCK && e.action != Action.RIGHT_CLICK_AIR)
39 | return
40 | if (e.hand != EquipmentSlot.HAND)
41 | return
42 |
43 | when (e.player.inventory.heldItemSlot) {
44 | 6 -> {
45 | CompassGUI(e.player).show()
46 | e.isCancelled = true
47 | }
48 | 7 -> {
49 | e.isCancelled = true
50 | }
51 | 8 -> {
52 | e.isCancelled = true
53 | }
54 | else -> {
55 | e.player.inventory.itemInMainHand.itemMeta?.data?.getString("type")?.let {
56 | rcEvents[it]?.invoke(e)
57 | }
58 |
59 | if (!e.player.checkWeapon())
60 | return
61 |
62 | e.player.addRightClick()
63 | e.isCancelled = true
64 | }
65 | }
66 | }
67 |
68 | companion object {
69 | val rcEvents = hashMapOf Unit>(
70 | "HELMET" to { e ->
71 | val l = e.player.inventory.helmet
72 | e.player.inventory.helmet = e.player.inventory.itemInMainHand
73 | e.player.inventory.setItemInMainHand(l)
74 | },
75 | "CHESTPLATE" to { e ->
76 | val l = e.player.inventory.chestplate
77 | e.player.inventory.chestplate = e.player.inventory.itemInMainHand
78 | e.player.inventory.setItemInMainHand(l)
79 | },
80 | "LEGGINGS" to { e ->
81 | val l = e.player.inventory.leggings
82 | e.player.inventory.leggings = e.player.inventory.itemInMainHand
83 | e.player.inventory.setItemInMainHand(l)
84 | },
85 | "BOOTS" to { e ->
86 | val l = e.player.inventory.boots
87 | e.player.inventory.boots = e.player.inventory.itemInMainHand
88 | e.player.inventory.setItemInMainHand(l)
89 | },
90 | "RING" to { e ->
91 | val l = e.player.inventory.getItem(9)
92 | e.player.inventory.setItem(9, e.player.inventory.itemInMainHand)
93 | e.player.inventory.setItemInMainHand(l)
94 | },
95 | "BRACELET" to { e ->
96 | val l = e.player.inventory.getItem(11)
97 | e.player.inventory.setItem(11, e.player.inventory.itemInMainHand)
98 | e.player.inventory.setItemInMainHand(l)
99 | },
100 | "NECKLACE" to { e ->
101 | val l = e.player.inventory.getItem(12)
102 | e.player.inventory.setItem(12, e.player.inventory.itemInMainHand)
103 | e.player.inventory.setItemInMainHand(l)
104 | }
105 | )
106 |
107 | val lcEvents = hashMapOf Unit>()
108 | }
109 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/listeners/ProjectileHitListener.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.listeners
2 |
3 | import org.bukkit.entity.Arrow
4 | import org.bukkit.entity.Mob
5 | import org.bukkit.entity.Player
6 | import org.bukkit.event.EventHandler
7 | import org.bukkit.event.EventPriority
8 | import org.bukkit.event.entity.ProjectileHitEvent
9 |
10 | class ProjectileHitListener : BaseListener() {
11 | @EventHandler(priority = EventPriority.HIGHEST)
12 | fun onProjectileHit(e: ProjectileHitEvent) {
13 | val proj = e.entity
14 |
15 | if ("mob_projectile" in proj.scoreboardTags)
16 | proj.remove()
17 |
18 | if (proj.shooter !is Player)
19 | return
20 |
21 | for (tag in proj.scoreboardTags) {
22 | tags[tag]?.let {
23 | if (e.hitEntity is Mob) (e.hitEntity as Mob).noDamageTicks = 0
24 | if (proj is Arrow) proj.damage = 0.0
25 | it(e)
26 | }
27 | }
28 | }
29 |
30 | companion object {
31 | val tags = hashMapOf Unit>()
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/listeners/ScriptAPIListeners.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.listeners
2 |
3 | import com.wynnlab.events.DamageEvent
4 | import com.wynnlab.events.HealEvent
5 | import com.wynnlab.spells.damage
6 | import com.wynnlab.spells.heal
7 | import org.bukkit.entity.Player
8 | import org.bukkit.event.EventHandler
9 |
10 | class ScriptAPIListeners : BaseListener() {
11 | @EventHandler
12 | fun onDamage(e: DamageEvent) {
13 | if (e.source !is Player)
14 | return
15 |
16 | damage(e.source as Player, e.target, e.melee, e.multiplier, *e.conversion)
17 | }
18 |
19 | @EventHandler
20 | fun onHeal(e: HealEvent) {
21 | heal(e.target, e.amount)
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/localization/Language.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.localization
2 |
3 | import com.wynnlab.NL_REGEX
4 | import com.wynnlab.wynnlab
5 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
6 | import org.bukkit.configuration.file.YamlConfiguration
7 | import java.io.File
8 | import java.util.*
9 | import java.util.logging.Level
10 |
11 | class Language(private val locale: Locale) {
12 | private val config = YamlConfiguration()
13 |
14 | init {
15 | val file = File(languageFolder, "${locale.toLanguageTag().replace('-', '_')}.yml")
16 | config.load(file)
17 | }
18 |
19 | init {
20 | languages[locale] = this
21 | if (language_fallbacks[locale.language] == null) language_fallbacks[locale.language] = locale
22 | }
23 |
24 | fun getMessage(key: String, vararg format_args: Any?) = LegacyComponentSerializer.legacy('&').deserialize(getMessageAsString(key, *format_args))
25 |
26 | fun getMessageMultiline(key: String, vararg format_args: Any?) = getMessageAsString(key, *format_args).split(NL_REGEX).map {
27 | LegacyComponentSerializer.legacy('&').deserialize(it)
28 | }
29 |
30 | fun getMessageAsString(key: String, vararg format_args: Any?) = getMessageOrNull(key, format_args) ?:
31 | Language[language_fallbacks[locale.language]!!].getMessageOrNull(key, format_args) ?:
32 | en_us.getMessageOrNull(key, format_args) ?: "&4Nls: &r$key"
33 |
34 |
35 | fun getRandomMessage(key: String, vararg format_args: Any?) = LegacyComponentSerializer.legacy('&').deserialize(getRandomMessageAsString(key, *format_args))
36 |
37 | fun getRandomMessageAsString(key: String, vararg format_args: Any?): String = getRandomMessageOrNull(key, format_args) ?:
38 | Language[language_fallbacks[locale.language]!!].getMessageOrNull(key, format_args) ?:
39 | en_us.getRandomMessageOrNull(key, format_args) ?: "&4Nls: &r$key"
40 |
41 |
42 | private fun getRandomMessageOrNull(key: String, format_args: Array) = config.getList(key)?.let {
43 | it.randomOrNull()?.let { r -> String.format(r as String, *format_args) }
44 | }
45 |
46 | private fun getMessageOrNull(key: String, format_args: Array): String? = config.getString(key)?.let {
47 | String.format(it, *format_args)
48 | }
49 |
50 | companion object {
51 | private val languages = hashMapOf()
52 | private val language_fallbacks = hashMapOf()
53 |
54 | val en_us = Language(Locale.US)
55 | operator fun get(locale: Locale) = languages[locale] ?:
56 | languages[language_fallbacks[locale.language]] ?:
57 | en_us
58 | }
59 | }
60 |
61 | private val languageFolder by lazy { File(wynnlab.dataFolder, "lang") }
62 |
63 | fun loadLanguages() {
64 | for (f in languageFolder.list() ?: return) {
65 | val name = f.substring(0, f.length - 4)
66 | wynnlab.logger.log(Level.INFO, "Loading language $name ...")
67 | try {
68 | if (name == "en_US") Language[Locale.US]
69 | else Language(Locale.US)
70 | } catch (e: Exception) {
71 | e.printStackTrace()
72 | continue
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/locations/Location.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.locations
2 |
3 | import com.wynnlab.WL_COLOR
4 | import com.wynnlab.api.getLocalizedText
5 | import com.wynnlab.api.getLocalizedTextMultiline
6 | import com.wynnlab.util.BaseSerializable
7 | import com.wynnlab.util.ConfigurationDeserializable
8 | import net.kyori.adventure.text.Component
9 | import net.kyori.adventure.text.format.NamedTextColor
10 | import net.kyori.adventure.text.format.TextDecoration
11 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
12 | import org.bukkit.Sound
13 | import org.bukkit.SoundCategory
14 | import org.bukkit.entity.Player
15 | import org.bukkit.util.BoundingBox
16 | import java.util.*
17 | import org.bukkit.Location as _Location
18 |
19 | class Location(
20 | val name: String,
21 | private val pos1: _Location,
22 | private val pos2: _Location,
23 | private val announce: Boolean,
24 | private val subtitle: String?,
25 | private val lore: String?,
26 | ) : BaseSerializable() {
27 |
28 | override val deserializer = Companion
29 |
30 | private val discovered = mutableListOf()
31 |
32 | val bossBarTitle = "§3$name"
33 |
34 | fun announce(player: Player, entering: Boolean = true): Boolean {
35 | if (!announce) return false
36 |
37 | player.sendTitle(LegacyComponentSerializer.legacy('§').serialize(player.getLocalizedText(when {
38 | player.uniqueId !in discovered -> "titles.location.discover"
39 | entering -> "titles.location.enter"
40 | else -> "titles.location.leave"
41 | }, name)),
42 | subtitle?.let { LegacyComponentSerializer.legacy('§').serialize(player.getLocalizedText(it)) },
43 | 10, 30, 10)
44 |
45 | return true
46 | }
47 |
48 | fun discover(player: Player) {
49 | if (player.uniqueId !in discovered) {
50 | discovered.add(player.uniqueId)
51 |
52 | player.playSound(player.location, Sound.ENTITY_PLAYER_LEVELUP, SoundCategory.MASTER, 1f, 1f)
53 |
54 | player.sendMessage("§0")
55 |
56 | //player.sendMessage(" ${player.getLocalizedText("titles.location.discover", name)}")
57 | player.sendMessage(Component.text(" ")
58 | .append(player.getLocalizedText("titles.location.discover", name)))
59 | //subtitle?.let { player.sendMessage(" §2§o${player.getLocalizedText(it)}") }
60 | subtitle?.let {
61 | player.sendMessage(Component.text(" ")
62 | .append(player.getLocalizedText(it)
63 | .color(NamedTextColor.DARK_GREEN)
64 | .decorate(TextDecoration.ITALIC)))
65 | }
66 |
67 | lore?.let { l ->
68 | player.sendMessage("§0")
69 |
70 | player.getLocalizedTextMultiline(l).forEach {
71 | player.sendMessage(Component.text(" ")
72 | .append(it.color(WL_COLOR)))
73 | }
74 | }
75 |
76 | player.sendMessage("§0")
77 | }
78 | }
79 |
80 | operator fun contains(l: _Location) = bb.contains(l.x, l.y, l.z)
81 |
82 | private val bb: BoundingBox = BoundingBox(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z)
83 |
84 | override fun serialize(): Map {
85 | val map = mutableMapOf()
86 |
87 | map["name"] = name
88 | map["pos1"] = pos1
89 | map["pos2"] = pos2
90 | map["announce"] = announce
91 | subtitle?.let { map["subtitle"] = it }
92 |
93 | return map
94 | }
95 |
96 | companion object : ConfigurationDeserializable {
97 | @JvmStatic
98 | override fun deserialize(map: Map): Location {
99 | val name = map["name"] as String
100 | val pos1 = map["pos1"] as _Location
101 | val pos2 = map["pos2"] as _Location
102 | val announce = (map["announce"] ?: false) as Boolean
103 | val subtitle = map["subtitle"] as String?
104 | val lore = map["lore"] as String?
105 |
106 | return Location(name, pos1, pos2, announce, subtitle, lore)
107 | }
108 | }
109 |
110 | override fun toString(): String {
111 | return "Location(name='$name', pos1=$pos1, pos2=$pos2, announce=$announce, subtitle=$subtitle)"
112 | }
113 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/locations/locations.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.locations
2 |
3 | import com.wynnlab.api.hasScoreboardTag
4 | import com.wynnlab.wynnlab
5 | import org.bukkit.Bukkit
6 | import org.bukkit.NamespacedKey
7 | import org.bukkit.boss.BarColor
8 | import org.bukkit.boss.BarStyle
9 | import org.bukkit.boss.KeyedBossBar
10 | import org.bukkit.configuration.file.YamlConfiguration
11 | import org.bukkit.entity.Player
12 | import java.io.File
13 |
14 | @Suppress("unchecked_cast")
15 | fun loadLocations() {
16 | val file = File(wynnlab.dataFolder, "locations.yml")
17 | if (!file.exists()) return
18 |
19 | val config = YamlConfiguration()
20 | config.load(file)
21 |
22 | val ls = try {
23 | config.getList("locations") as? List ?: return
24 | } catch (e: IllegalArgumentException) { return }
25 |
26 | ls.forEach { if (it != null) locations.add(it) }
27 |
28 | Bukkit.broadcastMessage(locations.toString())
29 | }
30 |
31 | fun testLocations(player: Player): List = locations.filter { player.location in it }
32 |
33 | fun Player.updateLocations() {
34 | if (locations.isEmpty()) return
35 |
36 | val labb = playerLocations[this]
37 | val before = labb?.locations
38 | val now = testLocations(this)
39 | val bb = labb?.bb ?: createLBB(this)
40 | val entered = before?.let { b -> now.filter { it !in b } } ?: now
41 |
42 | var announced = false
43 | for (l in entered) {
44 | if (!announced && l.announce(this))
45 | announced = true
46 |
47 | l.discover(this)
48 |
49 | bb.setTitle(l.bossBarTitle)
50 | }
51 |
52 | if (!announced) {
53 | val left = before?.let { b -> b.filter { it !in now } } ?: emptyList()
54 |
55 | for (l in left) {
56 | if (!announced && l.announce(this, false))
57 | announced = true
58 | }
59 | }
60 |
61 | if (now.isEmpty()) {
62 | if (hasScoreboardTag("ffa")) {
63 | bb.setTitle("§cFFA §8- §6Kills: §b0 §6Deaths: §b0 §6K/D: §b0")
64 | } else {
65 | bb.setTitle("§c")
66 | }
67 | }
68 |
69 | playerLocations[this] = LocationsAndBB(now, bb)
70 | }
71 |
72 | private fun createLBB(player: Player): KeyedBossBar =
73 | Bukkit.createBossBar(NamespacedKey(wynnlab, "locations_${player.name}"), "Title", BarColor.BLUE, BarStyle.SOLID).apply {
74 | isVisible = true
75 | progress = 1.0
76 |
77 | addPlayer(player)
78 | }
79 |
80 | val locations: MutableList = mutableListOf()
81 |
82 | class LocationsAndBB(
83 | val locations: List,
84 | val bb: KeyedBossBar,
85 | )
86 |
87 | val playerLocations: MutableMap = mutableMapOf()
88 |
89 | fun removePlayerLocations(player: Player) {
90 | val labb = playerLocations.remove(player) ?: return
91 | labb.bb.run {
92 | removeAll()
93 | Bukkit.removeBossBar(key)
94 | }
95 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/pvp/FFA.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.pvp
2 |
3 | import com.wynnlab.api.sendWynnMessage
4 | import org.bukkit.Bukkit
5 | import org.bukkit.entity.Player
6 |
7 |
8 | object FFA {
9 | val players = mutableListOf()
10 |
11 | fun join(player: Player) {
12 | val w = Bukkit.getWorld("FFA") ?: run {
13 | player.sendMessage("§cFFA is currently unavailable")
14 | return
15 | }
16 |
17 | player.teleport(w.spawnLocation)
18 |
19 | val console = Bukkit.getServer().consoleSender
20 | val command = "execute as ${player.name} at @s run spreadplayers 0 0 25 50 false @s"
21 | Bukkit.dispatchCommand(console, command)
22 | }
23 |
24 | fun onJoinWorld(player: Player) {
25 | player.addScoreboardTag("pvp")
26 | player.addScoreboardTag("ffa")
27 |
28 | players.add(player)
29 |
30 | player.sendWynnMessage("messages.ffa.welcome")
31 | player.sendWynnMessage("messages.ffa.stats")
32 | player.sendWynnMessage("messages.ffa.leave")
33 |
34 | players.forEach {
35 | it.sendMessage("§8[§cFFA§8] §a>> §r${player.playerListName}")
36 | }
37 | }
38 |
39 | fun onLeaveWorld(player: Player) {
40 | player.removeScoreboardTag("pvp")
41 | player.removeScoreboardTag("ffa")
42 |
43 | players.remove(player)
44 |
45 | players.forEach {
46 | it.sendMessage("§8[§cFFA§8] §4<< §r${player.playerListName}")
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/scoreboard/ConfiguredSidebar.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.scoreboard
2 |
3 | import org.bukkit.entity.Player
4 |
5 | interface ConfiguredSidebar {
6 | fun apply(player: Player, sidebar: Sidebar)
7 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/scoreboard/PartySidebar.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.scoreboard
2 |
3 | import com.wynnlab.COLOR_DARKER_GRAY
4 | import com.wynnlab.COLOR_PARTY
5 | import com.wynnlab.essentials.Party
6 | import net.kyori.adventure.text.Component
7 | import org.bukkit.entity.Player
8 |
9 | object PartySidebar : ConfiguredSidebar {
10 | override fun apply(player: Player, sidebar: Sidebar) {
11 | val party = Party.members[player]!!
12 |
13 | sidebar.setForUpdate(1, pos(player))
14 |
15 | sidebar.setForUpdate(3, Component.text("Party: ", COLOR_PARTY)
16 | .append(Component.text("(${party.members.size})", COLOR_DARKER_GRAY)))
17 |
18 | var i = 4
19 | party.getSbTexts().forEach {
20 | sidebar.setForUpdate(i++, it)
21 | }
22 |
23 | sidebar.displayLines = i - 1
24 |
25 | while (i < 16)
26 | sidebar.clearForUpdate(i++)
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/scoreboard/Sidebar.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.scoreboard
2 |
3 | import net.kyori.adventure.text.Component
4 | import org.bukkit.Bukkit
5 | import org.bukkit.entity.Player
6 | import org.bukkit.scoreboard.DisplaySlot
7 | import org.bukkit.scoreboard.Team
8 |
9 | class Sidebar(title: Component) {
10 | private val sb = Bukkit.getScoreboardManager().newScoreboard
11 | private val o = sb.registerNewObjective("o", "dummy", title)
12 | init {
13 | o.displaySlot = DisplaySlot.SIDEBAR
14 | }
15 |
16 | var title = title
17 | set(value) {
18 | o.displayName(value)
19 | field = value
20 | }
21 |
22 | private val lines = Array(16) { null }
23 | private val setLines = BooleanArray(16)
24 |
25 | var displayLines = 0
26 |
27 | fun show(player: Player) {
28 | player.scoreboard = sb
29 | }
30 |
31 | /**
32 | * line is top down 0-16
33 | */
34 | @Throws(ArrayIndexOutOfBoundsException::class)
35 | fun set(line: Int, text: Component) {
36 | setForUpdate(line, text)
37 |
38 | fillEmptyLines()
39 | }
40 |
41 | /**
42 | * line is top down 0-16
43 | */
44 | @Throws(ArrayIndexOutOfBoundsException::class)
45 | fun setForUpdate(line: Int, text: Component) {
46 | if (displayLines <= line) displayLines = line + 1
47 | lines[line] = text
48 | setLines[line] = true
49 |
50 | setScore(16 - line, text)
51 | }
52 |
53 | /**
54 | * line is top down 0-16
55 | */
56 | @Throws(ArrayIndexOutOfBoundsException::class)
57 | fun get(line: Int) = lines[line]
58 |
59 | /**
60 | * line is top down 0-16
61 | */
62 | @Throws(ArrayIndexOutOfBoundsException::class)
63 | fun clear(line: Int) {
64 | clearForUpdate(line)
65 |
66 | setDisplayLines()
67 | fillEmptyLines()
68 | }
69 |
70 | fun clearForUpdate(line: Int) {
71 | lines[line] = null
72 | setLines[line] = false
73 | }
74 |
75 | fun clear() {
76 | for (i in 0..15) {
77 | lines[i] = null
78 | setLines[i] = false
79 | removeScore(i)
80 | }
81 | displayLines = 0
82 | }
83 |
84 | fun update() = fillEmptyLines()
85 |
86 | private fun setScore(score: Int, text: Component) {
87 | val t = getTeam(score)
88 | t.prefix(text)
89 | o.getScore(colorInt(score)).score = score
90 | }
91 |
92 | private fun removeScore(score: Int) {
93 | val name = colorInt(score)
94 | if (o.getScore(name).isScoreSet)
95 | return
96 | sb.resetScores(name)
97 | }
98 |
99 | private fun getTeam(score: Int): Team {
100 | val name = colorInt(score)
101 | return sb.getEntryTeam(name) ?: sb.registerNewTeam(score.toString()).apply {
102 | addEntry(name)
103 | }
104 | }
105 |
106 | private fun setDisplayLines() {
107 | var i = -1
108 | var last = i
109 | for (b in setLines) {
110 | if (!b)
111 | last = i
112 |
113 | ++i
114 | }
115 | displayLines = last + 1
116 | }
117 |
118 | private fun fillEmptyLines() {
119 | var i = -1
120 | for (b in setLines) {
121 | ++i
122 | if (i >= displayLines)
123 | removeScore(16 - i)
124 | else if (!b)
125 | setScore(16 - i, Component.empty())
126 | }
127 | }
128 |
129 | private fun colorInt(int: Int) = "§${(int-1).toString(0x10)}"
130 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/scoreboard/StandardSidebar.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.scoreboard
2 |
3 | import com.wynnlab.COLOR_GOLD
4 | import net.kyori.adventure.text.Component
5 | import org.bukkit.entity.Player
6 |
7 | object StandardSidebar : ConfiguredSidebar {
8 | override fun apply(player: Player, sidebar: Sidebar) {
9 | sidebar.setForUpdate(1, quests(player))
10 |
11 | sidebar.setForUpdate(3, pos(player))
12 |
13 | sidebar.setForUpdate(5, Component.text("5 ✯✯✯✯✯", COLOR_GOLD))
14 |
15 | sidebar.clearForUpdate(4)
16 | var i = 6
17 | while (i < 16)
18 | sidebar.clearForUpdate(i++)
19 | sidebar.displayLines = 5
20 | }
21 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/scoreboard/elements.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.scoreboard
2 |
3 | import com.wynnlab.*
4 | import com.wynnlab.util.yawToDir
5 | import net.kyori.adventure.text.Component
6 | import org.bukkit.entity.Player
7 |
8 | fun quests(@Suppress("unused") player: Player) = Component.text("Quests: ", COLOR_QUESTS)
9 | .append(Component.text("0/0", COLOR_QUESTS_COUNT))
10 | .append(Component.text(" [", COLOR_QUESTS_BRACKET))
11 | .append(Component.text("100%", COLOR_QUESTS_COUNT))
12 | .append(Component.text("]", COLOR_QUESTS_BRACKET))
13 |
14 | fun pos(player: Player) = Component.text("Pos: ", COLOR_ORANGE)
15 | .append(Component.text("${player.location.x.toInt()} ", COLOR_DES_RED))
16 | .append(Component.text("${player.location.y.toInt()} ", COLOR_DES_GREEN))
17 | .append(Component.text("${player.location.z.toInt()} ", COLOR_DES_BLUE))
18 | .append(Component.text("[", COLOR_DARKER_GRAY))
19 | .append(Component.text(yawToDir(player.eyeLocation.yaw), COLOR_ORANGE))
20 | .append(Component.text("]", COLOR_DARKER_GRAY))
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/spells/PlayerSpell.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.spells
2 |
3 | import com.wynnlab.api.isCloneClass
4 | import com.wynnlab.currentClassLoadFolder
5 | import com.wynnlab.spellOrdinal
6 | import com.wynnlab.util.BaseSerializable
7 | import com.wynnlab.util.ConfigurationDeserializable
8 | import com.wynnlab.util.TickRunnable
9 | import com.wynnlab.util.prepareScript
10 | import com.wynnlab.wynnscript.CompiledWynnScript
11 | import com.wynnlab.wynnscript.NoSuchFunctionException
12 | import com.wynnlab.wynnscript.WynnScript
13 | import org.bukkit.entity.Player
14 | import java.io.File
15 | import java.io.FileReader
16 |
17 | data class PlayerSpell(
18 | override val cost: Int,
19 | override val maxTick: Int,
20 | val script: CompiledWynnScript,
21 | override val ordinal: Int
22 | ) : Spell, BaseSerializable() {
23 | init {
24 | prepareScript(script)
25 | }
26 |
27 | override fun invoke(player: Player, vararg args: Any?) {
28 | script.resetData()
29 |
30 | val spellPlayer = SpellPlayer(player)
31 | val clone = player.isCloneClass
32 |
33 | val runnable = object : TickRunnable() {
34 | override fun init() {
35 | script.setData("task", this)
36 | try {
37 | script("init", spellPlayer, clone, *args)
38 | } catch (_: NoSuchFunctionException) {
39 | } catch (e: Throwable) {
40 | reportError(e, "§cError at initializing script", player)
41 | }
42 | }
43 |
44 | override fun tick() {
45 | try {
46 | script("tick", t, spellPlayer, clone)
47 | } catch (e: Throwable) {
48 | reportError(e, "§cError at executing script (tick $t)", player)
49 | }
50 | }
51 | }
52 |
53 | runnable.schedule()
54 | }
55 |
56 | override fun serialize(): MutableMap {
57 | val out = LinkedHashMap()
58 |
59 | out["cost"] = cost
60 | out["maxTick"] = maxTick
61 |
62 | return out
63 | }
64 |
65 | override val deserializer = Companion
66 |
67 | companion object : ConfigurationDeserializable {
68 | @JvmStatic
69 | @Suppress("unused")
70 | override fun deserialize(map: Map): PlayerSpell {
71 | val cost = (map["cost"] as Number? ?: 0).toInt()
72 | val maxTick = (map["maxTick"] as Number).toInt()
73 |
74 | val scriptFile = File(currentClassLoadFolder, map["script"] as String)
75 |
76 | val script = FileReader(scriptFile).use { reader ->
77 | WynnScript(reader)
78 | }.compile()
79 |
80 | return PlayerSpell(cost, maxTick, script, spellOrdinal++)
81 | }
82 | }
83 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/spells/Spell.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.spells
2 |
3 | import com.wynnlab.api.getId
4 | import com.wynnlab.api.isCloneClass
5 | import com.wynnlab.currentClassLoadFolder
6 | import com.wynnlab.python
7 | import com.wynnlab.spellOrdinal
8 | import com.wynnlab.util.BaseSerializable
9 | import com.wynnlab.util.ConfigurationDeserializable
10 | import net.kyori.adventure.text.Component
11 | import net.kyori.adventure.text.event.ClickEvent
12 | import net.kyori.adventure.text.event.HoverEvent
13 | import net.kyori.adventure.text.format.NamedTextColor
14 | import org.bukkit.configuration.serialization.ConfigurationSerializable
15 | import org.bukkit.entity.Player
16 | import org.python.core.Py
17 | import org.python.core.PyBoolean
18 | import org.python.core.PyInteger
19 | import org.python.core.PyType
20 | import java.io.File
21 | import java.io.FileReader
22 |
23 | interface Spell : ConfigurationSerializable {
24 | val cost: Int
25 | val maxTick: Int
26 | val ordinal: Int
27 |
28 | fun cast(player: Player, vararg args: Any?) {
29 | invoke(player, args)
30 | }
31 |
32 | fun invoke(player: Player, args: Array)
33 | }
34 |
35 | @Suppress("unchecked_cast")
36 | fun reportError(e: Throwable, msg: String, player: Player) {
37 | player.sendMessage("§4=====================")
38 | player.sendMessage(msg)
39 | player.sendMessage("§bPlease immediately submit a bug report on GitHub!")
40 | val stackTrace = e.stackTraceToString()
41 | player.sendMessage(
42 | Component.text("Error: (${e::class.qualifiedName}) $e ")
43 | .color(NamedTextColor.DARK_RED)
44 | .append(
45 | Component.text("[Stack trace]")
46 | .color(NamedTextColor.YELLOW)
47 | .hoverEvent { HoverEvent.showText(Component.text("Copy")) as HoverEvent }
48 | .clickEvent(ClickEvent.copyToClipboard(e.stackTraceToString()))
49 | )
50 | )
51 | player.sendMessage("§4=====================")
52 | }
53 |
54 | @Deprecated("Use WynnScript")
55 | data class PythonSpell (
56 | override val cost: Int,
57 | override val maxTick: Int,
58 | val pythonClass: PyType,
59 | override val ordinal: Int
60 | ) : Spell, BaseSerializable() {
61 |
62 | override fun invoke(player: Player, vararg args: Any?) {
63 | val instance = try {
64 | pythonClass.__call__(Array(args.size) { i -> Py.java2py(args[i]) })
65 | } catch (e: Throwable) {
66 | reportError(e, "§cError instantiating §nPython §cSpell ($ordinal)", player)
67 | return
68 | }
69 | try {
70 | instance.__setattr__("player", Py.java2py(player))
71 | instance.__setattr__("clone", PyBoolean(player.isCloneClass))
72 | instance.__setattr__("maxTick", PyInteger(maxTick))
73 | } catch (e: Throwable) {
74 | reportError(e, "§cError setting attributes for §nPython §cSpell ($ordinal)", player)
75 | return
76 | }
77 |
78 | try {
79 | instance("schedule")
80 | } catch (e: Throwable) {
81 | reportError(e, "§cError executing §nPython §cSpell ($ordinal)", player)
82 | try {
83 | instance("cancel")
84 | } catch (e: Throwable) {
85 | reportError(e, "§c§lVery critical§c error instantiating §nPython §cSpell ($ordinal)", player)
86 | }
87 | }
88 | }
89 |
90 | override fun serialize(): MutableMap {
91 | val out = LinkedHashMap()
92 |
93 | out["cost"] = cost
94 | out["maxTick"] = maxTick
95 |
96 | return out
97 | }
98 |
99 | override val deserializer = Companion
100 |
101 | companion object : ConfigurationDeserializable {
102 | @JvmStatic
103 | @Suppress("unused")
104 | override fun deserialize(map: Map): PythonSpell {
105 | val cost = (map["cost"] as Number? ?: 0).toInt()
106 | val maxTick = (map["maxTick"] as Number).toInt()
107 |
108 | val scriptFile = File(currentClassLoadFolder, map["script"] as String)
109 |
110 | val script = FileReader(scriptFile).use { reader ->
111 | python.compile(reader)
112 | }
113 | python.exec(script)
114 | val pythonClass: PyType = python.get("Spell") as PyType //TODO: name
115 |
116 | return PythonSpell(cost, maxTick, pythonClass, spellOrdinal++)
117 | }
118 | }
119 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/spells/SpellPlayer.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.spells
2 |
3 | import org.bukkit.Location
4 | import org.bukkit.Particle
5 | import org.bukkit.Sound
6 | import org.bukkit.entity.Entity
7 | import org.bukkit.entity.LivingEntity
8 | import org.bukkit.entity.Mob
9 | import org.bukkit.entity.Player
10 | import org.bukkit.util.Vector
11 |
12 | class SpellPlayer(
13 | val player: Player
14 | ) {
15 | fun getLocation() = player.location.clone()
16 | fun getEyeLocation() = player.eyeLocation.clone()
17 | fun getDirection() = player.eyeLocation.direction.clone()
18 |
19 | fun damage(e: LivingEntity, melee: Boolean, multiplier: Double) =
20 | this.damage(e, melee, multiplier, *doubleArrayOf())
21 |
22 | fun damage(e: LivingEntity, melee: Boolean, multiplier: Double, vararg conversion: Double) =
23 | damage(player, e, melee, multiplier, *conversion)
24 |
25 | @Suppress("unused")
26 | fun damageBy(e: LivingEntity, melee: Boolean, multiplier: Double) =
27 | this.damageBy(e, melee, multiplier, *doubleArrayOf())
28 |
29 | @Suppress("unused")
30 | fun damageBy(e: LivingEntity, melee: Boolean, multiplier: Double, vararg conversion: Double) =
31 | damageBy(player, e, melee, multiplier, *conversion)
32 |
33 | fun heal(amount: Double) =
34 | heal(player, amount)
35 |
36 | fun knockback(target: Entity, direction: Vector, amount: Double) =
37 | com.wynnlab.spells.knockback(target, direction, amount)
38 |
39 | @Suppress("unused")
40 | fun knockback(target: Entity, amount: Double) =
41 | knockbackFromPlayer(target, player, amount)
42 |
43 | fun particle(location: Location, particle: Particle, count: Int, offX: Double, offY: Double, offZ: Double, speed: Double) =
44 | particle(player, location, particle, count, offX, offY, offZ, speed)
45 |
46 | fun particle(location: Location, particle: Particle, count: Int, offX: Double, offY: Double, offZ: Double, speed: Double, data: T?) =
47 | particle(player, location, particle, count, offX, offY, offZ, speed, data)
48 |
49 | fun sound(sound: Sound, volume: Float, pitch: Float) =
50 | sound(player, sound, volume, pitch)
51 |
52 | fun sound(location: Location, sound: Sound, volume: Float, pitch: Float) =
53 | sound(player, location, sound, volume, pitch)
54 |
55 | fun nearbyMobs(x: Double, y: Double, z: Double) =
56 | nearbyMobs(player, x, y, z)
57 |
58 | @Suppress("unchecked_cast")
59 | fun nearbyMobs(location: Location, x: Double, y: Double, z: Double): Collection =
60 | nearbyMobs(player, location, x, y, z)
61 |
62 | @Suppress("unused")
63 | fun nearbyMobsAndTag(location: Location, x: Double, y: Double, z: Double, tag: String): Collection =
64 | nearbyMobsAndTag(player, location, x, y, z, tag)
65 |
66 | fun castSpell(clazz: String, index: Int, vararg args: Any?) =
67 | castSpell(player, clazz, index, *args)
68 |
69 | @Suppress("unused")
70 | fun message(message: List) = player.sendMessage(message.joinToString(""))
71 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/BaseSerializable.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.WynnClass
4 | import com.wynnlab.entities.WynnMob
5 | import com.wynnlab.locations.Location
6 | import com.wynnlab.spells.MobSpell
7 | import com.wynnlab.spells.PlayerSpell
8 | import com.wynnlab.spells.PythonSpell
9 | import com.wynnlab.spells.Spell
10 | import org.bukkit.configuration.serialization.ConfigurationSerializable
11 | import org.bukkit.configuration.serialization.ConfigurationSerialization
12 |
13 | abstract class BaseSerializable> : ConfigurationSerializable {
14 |
15 | abstract val deserializer: ConfigurationDeserializable
16 |
17 | abstract override fun serialize(): Map
18 | }
19 |
20 | interface ConfigurationDeserializable {
21 | fun deserialize(map: Map): T
22 | }
23 |
24 | fun registerSerializers() {
25 | registerSerializer()
26 | registerSerializer()
27 | registerSerializer()
28 | registerSerializer()
29 | registerSerializer()
30 | registerSerializer()
31 | registerSerializer()
32 | registerSerializer()
33 | }
34 |
35 | private inline fun registerSerializer() =
36 | ConfigurationSerialization.registerClass(T::class.java)
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/Deferred.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.Bukkit
5 |
6 | class Deferred(
7 | val task: () -> T
8 | ) {
9 | inline fun execute(crossinline then: (T) -> Unit) {
10 | Bukkit.getScheduler().runTaskAsynchronously(wynnlab, Runnable {
11 | then(task())
12 | })
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/LocationIterator.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import org.bukkit.Location
4 |
5 | class LocationIterator(
6 | val start: Location,
7 | val end: Location,
8 | val step: Double
9 | ) : Iterable {
10 | private val d = end.clone().subtract(start).toVector().normalize().multiply(step)
11 |
12 | override operator fun iterator(): Iterator =
13 | object : Iterator {
14 | private var l = start
15 |
16 | private var iStep = 0.0
17 | private val dist: Double = end.distance(start)
18 |
19 | override operator fun hasNext(): Boolean {
20 | return iStep <= dist
21 | }
22 |
23 | override operator fun next(): Location {
24 | val r = l
25 | l.add(d)
26 | iStep += step
27 | return r
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/OnlyAsync.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | /**
4 | * A function/class that should only be executed in async environment
5 | */
6 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
7 | @Retention(AnnotationRetention.SOURCE)
8 | annotation class OnlyAsync
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/Optional.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | sealed class Optional {
4 | class Some(val value: T) : Optional() {
5 | override fun toString(): String = value.toString()
6 | }
7 |
8 | object None : Optional() {
9 | override fun toString(): String = "NONE"
10 | }
11 |
12 | @Suppress("unchecked_cast")
13 | inline fun ifSome(block: (T) -> R): Optional = when (this) {
14 | is Some -> Some(block(value))
15 | is None -> None as Optional
16 | }
17 |
18 | inline fun ifSomeRun(block: (T) -> Unit) {
19 | if (this is None)
20 | return
21 | block((this as Some).value)
22 | }
23 |
24 | inline fun either(ifSome: (T) -> R, ifNone: () -> R): R = when (this) {
25 | is Some -> ifSome(value)
26 | is None -> ifNone()
27 | }
28 |
29 | inline infix fun or(block: () -> T): T = when (this) {
30 | is Some -> value
31 | is None -> block()
32 | }
33 |
34 | companion object {
35 | @Suppress("unchecked_cast")
36 | operator fun invoke(nullable: T?): Optional = nullable?.let { Some(it) } ?: None as Optional
37 | }
38 | }
39 |
40 | fun T?.optional() = Optional(this)
41 |
42 | @Suppress("unchecked_cast")
43 | fun Any?.optionalAs() = Optional(this as T?)
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/RefreshRunnable.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.api.getInt
4 | import com.wynnlab.api.remove
5 | import com.wynnlab.api.setInt
6 | import com.wynnlab.wynnlab
7 | import org.bukkit.Bukkit
8 | import org.bukkit.persistence.PersistentDataContainer
9 |
10 | /**
11 | * A delayed runnable which delay can be refreshed to delay it further
12 | */
13 | abstract class RefreshRunnable(private val data: PersistentDataContainer, private val id: String) : Runnable {
14 | final override fun run() {
15 | val delay = data.getInt("RR_$id")!!
16 | if (delay > 0)
17 | data.setInt("RR_$id", delay - 1)
18 | if (delay <= 1) {
19 | task()
20 | data.remove("RR_$id")
21 | }
22 | }
23 |
24 | abstract fun task()
25 |
26 | fun schedule(delay: Long) {
27 | Bukkit.getScheduler().runTaskLater(wynnlab, this, delay)
28 | data.setInt("RR_$id", (data.getInt("RR_$id") ?: 0) + 1)
29 | }
30 |
31 | companion object {
32 | inline operator fun invoke(data: PersistentDataContainer, id: String, crossinline task: () -> Unit) =
33 | object : RefreshRunnable(data, id) {
34 | override fun task() {
35 | task()
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/TickRunnable.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.Bukkit
5 |
6 | abstract class TickRunnable : Runnable {
7 | var t = 0
8 |
9 | private var _taskId = -1
10 | val taskId get() = _taskId
11 |
12 | private var scheduled = false
13 | var maxTick = 0
14 |
15 | open fun init() {}
16 |
17 | abstract fun tick()
18 |
19 | fun delay() {
20 | --t
21 | }
22 |
23 | fun cancel() {
24 | Bukkit.getScheduler().cancelTask(_taskId)
25 | }
26 |
27 | final override fun run() {
28 | if (scheduled) {
29 | if (t <= maxTick) {
30 | try {
31 | tick()
32 | } catch (e: Throwable) {
33 | cancel()
34 | throw e
35 | }
36 | ++t
37 | } else {
38 | cancel()
39 | }
40 | }
41 | }
42 |
43 | fun schedule() {
44 | init()
45 | _taskId = Bukkit.getScheduler().runTaskTimer(wynnlab, this, 0L, 1L).taskId
46 | scheduled = true
47 | }
48 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/WynnScript utils.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.spells.SpellUtils
4 | import com.wynnlab.wynnscript.CompiledWynnScript
5 | import com.wynnlab.wynnscript.Invocable
6 | import org.bukkit.Location
7 | import org.bukkit.Material
8 | import org.bukkit.Particle
9 | import org.bukkit.Sound
10 |
11 | fun prepareScript(script: CompiledWynnScript) {
12 | script["print"] = Invocable { _, args -> if (args.size != 1) throw IllegalArgumentException() else
13 | println(args[0])
14 | }
15 |
16 | script["array"] = Invocable { _, args -> args }
17 | script["list"] = Invocable { _, args -> mutableListOf(*args) }
18 | script["set"] = Invocable { _, args -> mutableSetOf(*args) }
19 | script["map"] = Invocable { _, args -> if (args.isNotEmpty()) throw IllegalArgumentException() else
20 | mutableMapOf()
21 | }
22 |
23 | script["SpellUtils"] = SpellUtils
24 |
25 | script["locations"] = Invocable { _, args -> if (args.size != 3) throw IllegalArgumentException() else
26 | LocationIterator(args[0] as Location, args[1] as Location, (args[2] as Number).toDouble())
27 | }
28 |
29 | script["Material"] = Material::class.java
30 | script["Particle"] = Particle::class.java
31 | script["Sound"] = Sound::class.java
32 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/adventure utils.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import net.kyori.adventure.text.Component
4 | import net.kyori.adventure.text.format.Style
5 | import net.kyori.adventure.text.format.TextColor
6 | import net.kyori.adventure.text.format.TextDecoration
7 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
8 |
9 | val emptyComponent: Component get() = Component.text("")
10 |
11 | fun Component.serialize(char: Char = '§') = LegacyComponentSerializer.legacy(char).serialize(this)
12 |
13 | fun colorNonItalic(color: Int): Style = Style.style { sb: Style.Builder ->
14 | sb.decoration(TextDecoration.ITALIC, false)
15 | sb.color(TextColor.color(color))
16 | }
17 | fun colorNonItalic(color: TextColor): Style = Style.style { sb: Style.Builder ->
18 | sb.decoration(TextDecoration.ITALIC, false)
19 | sb.color(color)
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/bukkit utils.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("BukkitUtils")
2 |
3 | package com.wynnlab.util
4 |
5 | import org.bukkit.Bukkit
6 | import org.bukkit.scoreboard.Team
7 | import org.bukkit.util.Vector
8 |
9 | fun Vector.normalizeOnXZ() = if (x == 0.0 && z == 0.0) {
10 | y = 0.0; this
11 | } else {
12 | y = 0.0; normalize()
13 | }
14 |
15 | fun registerMainTeam(name: String): Team = try {
16 | Bukkit.getScoreboardManager().mainScoreboard.registerNewTeam(name)
17 | } catch (e: IllegalArgumentException) {
18 | Bukkit.getScoreboardManager().mainScoreboard.getTeam(name)?.unregister()
19 | Bukkit.getScoreboardManager().mainScoreboard.registerNewTeam(name)
20 | }
21 |
22 | fun yawToDir(yaw: Float) = when {
23 | yaw < -157.5f -> "N"
24 | yaw < -112.5f -> "NE"
25 | yaw < -67.5f -> "E"
26 | yaw < -22.5f -> "SE"
27 | yaw < 22.5f -> "S"
28 | yaw < 67.5f -> "SW"
29 | yaw < 112.5f -> "W"
30 | yaw < 157.5f -> "NW"
31 | else -> "N"
32 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/operators.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import org.bukkit.Location
4 | import org.bukkit.util.Vector
5 | import kotlin.math.PI
6 |
7 | const val RAD2DEG = 180.0 / PI
8 | const val DEG2RAD = PI / 180.0
9 |
10 | operator fun Location.plus(l: Location) = clone().add(l)
11 | operator fun Location.plus(l: Vector) = clone().add(l)
12 | fun Location.plus(x: Double, y: Double, z: Double) = clone().add(x, y, z)
13 |
14 | fun Location.minus(x: Double, y: Double, z: Double) = clone().subtract(x, y, z)
15 |
16 |
17 | operator fun Vector.plus(v: Vector) = clone().add(v)
18 | operator fun Vector.plusAssign(v: Vector) { add(v) }
19 |
20 | operator fun Vector.minus(v: Vector) = clone().subtract(v)
21 |
22 | operator fun Vector.times(x: Double) = clone().multiply(x)
23 | operator fun Vector.times(v: Vector) = clone().multiply(v)
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/resources.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.wynnlab
4 | import java.util.logging.Level
5 |
6 | fun saveAllResources() {
7 | wynnlab.logger.log(Level.INFO, "Saving resources...")
8 | resources.forEach {
9 | wynnlab.saveResource(it, true)
10 | }
11 | wynnlab.logger.log(Level.INFO, "... Done")
12 | }
13 |
14 | val resources = arrayOf(
15 | /////////////////////////////////////
16 | // Top Level
17 | /////////////////////////////////////
18 | "locations.yml",
19 |
20 | // Temp
21 | "mobs/dummy.yml",
22 | "mobs/scripts/pull.ws2",
23 |
24 |
25 | /////////////////////////////////////
26 | // Classes
27 | /////////////////////////////////////
28 |
29 | /*"classes/archer/archer.yml",
30 | "classes/archer/archer_main.py",
31 | "classes/archer/arrow_storm.py",
32 | "classes/archer/escape.py",
33 | "classes/archer/bomb_arrow.py",
34 | "classes/archer/arrow_shield.py",
35 | "classes/archer/arrow_rain.py",*/
36 |
37 | "classes/assassin/assassin.yml",
38 | "classes/assassin/assassin_main.py",
39 | "classes/assassin/spin_attack.py",
40 | "classes/assassin/vanish.py",
41 | "classes/assassin/multihit.py",
42 | "classes/assassin/smoke_bomb.py",
43 | "classes/assassin/vanish_end.py",
44 | "classes/assassin/smoke_bomb_tick.py",
45 |
46 | /*"classes/mage/mage.yml",
47 | "classes/mage/mage_main.py",
48 | "classes/mage/mage_main.ws2",
49 | "classes/mage/heal.py",
50 | "classes/mage/teleport.py",
51 | "classes/mage/meteor.py",
52 | "classes/mage/ice_snake.py",*/
53 |
54 | "classes/shaman/shaman.yml",
55 | "classes/shaman/shaman_main.py",
56 | "classes/shaman/totem.py",
57 | "classes/shaman/haul.py",
58 | "classes/shaman/aura.py",
59 | "classes/shaman/uproot.py",
60 | "classes/shaman/totem_tick.py",
61 |
62 | "classes/warrior/warrior.yml",
63 | "classes/warrior/warrior_main.py",
64 | "classes/warrior/bash.py",
65 | "classes/warrior/charge.py",
66 | "classes/warrior/uppercut.py",
67 | "classes/warrior/war_scream.py",
68 | "classes/warrior/uppercut_throw.py",
69 |
70 | "classes/monk/monk.yml",
71 | "classes/monk/monk_main.py",
72 | "classes/monk/shield.py",
73 | "classes/monk/step.py",
74 | "classes/monk/silence.py",
75 | "classes/monk/control.py",
76 |
77 | /////////////////////////////////////
78 | // Languages
79 | /////////////////////////////////////
80 |
81 | "lang/en_US.yml",
82 | "lang/de_DE.yml",
83 | "lang/ar_SA.yml"
84 | )
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/task utils.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import org.bukkit.scheduler.BukkitRunnable
4 |
5 | inline fun bukkitRunnable(crossinline task: (BukkitRunnable) -> Unit) = object : BukkitRunnable() {
6 | override fun run() {
7 | task(this)
8 | }
9 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/worlds.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.wynnlab
4 | import org.bukkit.*
5 | import org.bukkit.entity.Player
6 | import java.io.File
7 | import java.nio.file.DirectoryNotEmptyException
8 | import java.nio.file.Files
9 | import java.nio.file.LinkOption
10 | import java.nio.file.StandardCopyOption
11 |
12 | fun createInstancedWorld(worldName: String, instanceWorldName: String) = Deferred {
13 | //player.sendMessage("Copying $worldName ...")
14 | try {
15 | Files.copy(
16 | File("./$worldName/").toPath(), File("./$instanceWorldName/").toPath(),
17 | StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS)
18 | } catch (_: DirectoryNotEmptyException) {
19 | deleteDir(File("./$instanceWorldName/"))
20 | Files.copy(
21 | File("./$worldName/").toPath(), File("./$instanceWorldName/").toPath(),
22 | StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS)
23 | }
24 | copyDir(File("./$worldName"), File("./$instanceWorldName"))
25 | File("./$instanceWorldName/uid.dat").delete()
26 | loadWorld(instanceWorldName)
27 | }
28 |
29 | @OnlyAsync
30 | private fun loadWorld(name: String): InstancedWorld? {
31 | //player.sendMessage("Starting wc")
32 |
33 | val wc = WorldCreator.ofNameAndKey(name,
34 | NamespacedKey(wynnlab, name)
35 | )
36 | //player.sendMessage("Initialized wc")
37 |
38 | wc.type(WorldType.FLAT)
39 | wc.generateStructures(false)
40 | wc.environment(World.Environment.NORMAL)
41 | wc.generatorSettings("""{"layers":[{"height":0,"block":"minecraft:air"}],"biome":"minecraft:the_void","structures":{"stronghold":{"distance":0,"count":0,"spread":0},"structures":{}}}""")
42 | wc.hardcore(true)
43 | //player.sendMessage("Set wc options")
44 |
45 | //player.sendMessage("Set world border")
46 |
47 | Bukkit.getScheduler().runTaskLaterAsynchronously(wynnlab, { ->
48 | deleteDir(File("./$name"))
49 | }, 20L)
50 |
51 | return InstancedWorld(name, wc)
52 | }
53 |
54 | class InstancedWorld(val name: String, wc: WorldCreator) {
55 | lateinit var world: World
56 | init {
57 | Bukkit.getScheduler().scheduleSyncDelayedTask(wynnlab) {
58 | world = wc.createWorld()!!
59 | world.worldBorder.apply {
60 | center = Location(world, .0, .0, .0)
61 | size = 64.0
62 | }
63 | }
64 | }
65 |
66 | fun sendPlayer(player: Player, x: Double, y: Double, z: Double, yaw: Float = 0f, pitch: Float = 0f) {
67 | player.teleport(Location(world, x, y, z, yaw, pitch))
68 | }
69 |
70 | fun unload() {
71 | Bukkit.getServer().unloadWorld(world, false)
72 | Bukkit.getScheduler().runTaskAsynchronously(wynnlab) { -> deleteDir(File("./$name")) }
73 | }
74 |
75 | fun unloadOnZeroPlayers() {
76 | Bukkit.getScheduler().runTaskTimer(wynnlab, { task ->
77 | if (world.playerCount < 1) {
78 | unload()
79 | task.cancel()
80 | }
81 | }, 20L, 20L)
82 | }
83 | }
84 |
85 | private fun copyDir(from: File, to: File) {
86 | from.list()!!.forEach { n ->
87 | val f = File(from, n)
88 | val t = File(to, n)
89 | Files.copy(f.toPath(), t.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS)
90 | if (f.isDirectory)
91 | copyDir(f, t)
92 | }
93 | }
94 |
95 | private fun deleteDir(dir: File) {
96 | fun deleteDir(dir: File) {
97 | dir.listFiles()!!.forEach { f ->
98 | if (f.isDirectory)
99 | deleteDir(f)
100 | f.delete()
101 | //println("deleted file: $f")
102 | }
103 | }
104 | deleteDir(dir)
105 | dir.delete()
106 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/wynnlab/util/wynncraft api.kt:
--------------------------------------------------------------------------------
1 | package com.wynnlab.util
2 |
3 | import com.wynnlab.items.APIException
4 | import org.json.simple.JSONObject
5 | import org.json.simple.parser.JSONParser
6 | import java.net.HttpURLConnection
7 | import java.net.MalformedURLException
8 | import java.net.URL
9 | import java.util.*
10 |
11 | fun getWynncraftAPIResult(address: String): Deferred {
12 | val task = {
13 | val url = try {
14 | URL(address)
15 | } catch (e: MalformedURLException) {
16 | throw APIException("Malformed URL")
17 | }
18 |
19 | val connection = url.openConnection() as HttpURLConnection
20 | connection.requestMethod = "GET"
21 | connection.connect()
22 | val responseCode = connection.responseCode
23 |
24 | if (responseCode != 200)
25 | throw APIException("Response code: $responseCode")
26 |
27 | val scanner = Scanner(url.openStream())
28 | val inline = buildString {
29 | while (scanner.hasNext())
30 | append(scanner.nextLine())
31 | }
32 | scanner.close()
33 |
34 | jsonParser.parse(inline) as JSONObject
35 | }
36 |
37 | return Deferred(task)
38 | }
39 |
40 | val jsonParser = JSONParser()
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/assassin.yml:
--------------------------------------------------------------------------------
1 | class:
2 | ==: com.wynnlab.WynnClass
3 | id: ASSASSIN
4 | item: SHEARS
5 | metaStats:
6 | damage: 5
7 | defence: 4
8 | range: 1
9 | spells: 3
10 | invertedControls: false
11 | spells:
12 | - ==: com.wynnlab.spells.PythonSpell
13 | maxTick: 0
14 | script: assassin_main.py
15 | - ==: com.wynnlab.spells.PythonSpell
16 | cost: 6
17 | maxTick: 16
18 | script: spin_attack.py
19 | - ==: com.wynnlab.spells.PythonSpell
20 | cost: 1
21 | maxTick: 0
22 | script: vanish.py
23 | - ==: com.wynnlab.spells.PythonSpell
24 | cost: 8
25 | maxTick: 22
26 | script: multihit.py
27 | - ==: com.wynnlab.spells.PythonSpell
28 | cost: 8
29 | maxTick: 0
30 | script: smoke_bomb.py
31 | - ==: com.wynnlab.spells.PythonSpell
32 | maxTick: 0
33 | script: vanish_end.py
34 | - ==: com.wynnlab.spells.PythonSpell
35 | maxTick: 180
36 | script: smoke_bomb_tick.py
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/assassin_main.py:
--------------------------------------------------------------------------------
1 | #function tick() {
2 | # this.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .8);
3 | # var l = this.player.getEyeLocation().clone().add(this.player.getEyeLocation().getDirection());
4 | # this.particle(l, Particle.SWEEP_ATTACK, 1, 0, 0, 0, 0);
5 | #
6 | # this.nearbyMobs(l, 2, 2, 2).forEach(function (e) {
7 | # this.damage(e, 2);
8 | # });
9 | #}
10 | from org.bukkit import Particle, Sound
11 | from org.bukkit.potion import PotionEffectType
12 |
13 | from com.wynnlab.spells import PySpell
14 |
15 | class Spell(PySpell):
16 | def tick(self):
17 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY):
18 | self.castSpell('ASSASSIN', 5)
19 |
20 | self.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .8)
21 | l = self.player.getEyeLocation().clone().add(self.player.getEyeLocation().getDirection())
22 | self.particle(l, Particle.SWEEP_ATTACK, 1, 0, 0, 0, 0)
23 |
24 | for e in self.nearbyMobs(l, 2, 2, 2):
25 | self.damage(e, True, 1)
26 | self.knockback(e, .5)
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/multihit.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.potion import PotionEffectType
3 |
4 | from com.wynnlab.spells import PySpell
5 | from com.wynnlab.util import BukkitUtils
6 |
7 | class Spell(PySpell):
8 | def __init__(self):
9 | self.l = None
10 | self.entities = None
11 | self.shift = False
12 |
13 | def init(self):
14 | self.shift = self.player.isSneaking()
15 |
16 | def tick(self):
17 | if self.t % 2 != 0:
18 | return
19 |
20 | if self.t == 0:
21 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY):
22 | self.castSpell('ASSASSIN', 5)
23 |
24 | self.sound(Sound.ENTITY_PLAYER_ATTACK_STRONG, .5, 1)
25 | self.sound(Sound.ENTITY_IRON_GOLEM_HURT, 1, 1.5)
26 | if self.clone:
27 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .3, 1.5)
28 |
29 | v = BukkitUtils.normalizeOnXZ(self.player.getEyeLocation().getDirection())
30 | self.l = self.player.getLocation().clone().add(v).add(0, .5, 0)
31 |
32 | self.particle(self.l, Particle.SWEEP_ATTACK, 5, .5, .5, .5, .1)
33 |
34 | self.entities = self.nearbyMobs(self.l, 3, 3, 3)
35 |
36 | self.particle(self.l.add(v), Particle.SWEEP_ATTACK, 5, .5, .5, .5, .1)
37 | self.particle(self.l.add(v), Particle.SWEEP_ATTACK, 5, .5, .5, .5, .1)
38 |
39 | elif self.t <= 20:
40 | for e in self.entities:
41 | e.setVelocity(self.player.getEyeLocation().getDirection().multiply(.05 if self.shift else .3).setY(.2).rotateAroundY((.1 * self.t) if self.t % 2 == 0 else (-.1 * self.t)))
42 |
43 | self.particle(e.getLocation(), Particle.SWEEP_ATTACK, 5, .5, .5, .5, .5)
44 | if self.clone:
45 | self.particle(e.getLocation(), Particle.SPELL_WITCH, 7, .5, .5, .5, .2)
46 | self.particle(e.getLocation(), Particle.SQUID_INK, 6, .5, .5, .5, .1)
47 | self.particle(e.getLocation(), Particle.CRIT, 7 if self.clone else 10, .5, .5, .5, .1)
48 |
49 | self.sound(e.getLocation(), Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, 1.3)
50 | self.sound(e.getLocation(), Sound.ENTITY_PLAYER_ATTACK_CRIT, .8, 1.6)
51 |
52 | self.damage(e, False, .27)
53 |
54 | else:
55 | for e in self.entities:
56 | if not self.shift:
57 | e.setVelocity(self.player.getEyeLocation().getDirection().setY(.5))
58 |
59 | self.sound(e.getLocation(), Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, 1, 1.3)
60 |
61 | self.damage(e, False, 1.2, .2, 0, .3, .5, 0, 0)
62 | if self.clone:
63 | self.sound(e.getLocation(), Sound.ENTITY_BLAZE_DEATH, 1, 1.2)
64 | self.sound(e.getLocation(), Sound.ENTITY_BLAZE_AMBIENT, 1, 1.6)
65 | self.sound(e.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, .5, 1)
66 |
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/smoke_bomb.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Material, Sound
2 | from org.bukkit.entity import Snowball
3 | from org.bukkit.inventory import ItemStack
4 | from org.bukkit.potion import PotionEffectType
5 |
6 | from com.wynnlab.spells import PySpell
7 |
8 | class Spell(PySpell):
9 | def tick(self):
10 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY):
11 | self.castSpell('ASSASSIN', 5)
12 |
13 | self.sound(Sound.ENTITY_ENDER_PEARL_THROW if self.clone else Sound.ENTITY_SNOWBALL_THROW, .8, 1.3)
14 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, .8, 1.3)
15 | self.sound(Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 1, 1.6)
16 |
17 | v = self.player.getEyeLocation().getDirection().multiply(3)
18 | snowballs = (
19 | self.player.launchProjectile(Snowball, v),
20 | self.player.launchProjectile(Snowball, v.rotateAroundY(.4)),
21 | self.player.launchProjectile(Snowball, v.rotateAroundY(-.8))
22 | )
23 |
24 | for snowball in snowballs:
25 | if self.clone:
26 | snowball.setItem(ItemStack(Material.ENDER_PEARL))
27 | snowball.addScoreboardTag('smoke_bomb')
28 |
29 | self.player.addScoreboardTag('smoke_bomb')
30 |
31 | def bomb_hit(event):
32 | event.getEntity().remove()
33 | PySpell.castSpell(event.getEntity().getShooter(), 'ASSASSIN', 6, event.getHitEntity().getLocation() if not event.getHitEntity() is None else event.getHitBlock().getLocation())
34 |
35 | PySpell.registerProjectileHit('smoke_bomb', bomb_hit)
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/smoke_bomb_tick.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.potion import PotionEffect, PotionEffectType
3 |
4 | from com.wynnlab.spells import PySpell
5 |
6 | class Spell(PySpell):
7 | def __init__(self, l):
8 | self.l = l
9 |
10 | def tick(self):
11 | if self.t > 0 and self.player.getScoreboardTags().contains('smoke_bomb'):
12 | self.cancel()
13 |
14 | if self.t % 4 == 0:
15 | self.particle(self.l, Particle.CLOUD, 16, 3, 3, 3, 0.1)
16 | self.particle(self.l, Particle.SPELL_WITCH if self.clone else Particle.SQUID_INK, 16, 3, 3, 3, .2 if self.clone else .1)
17 |
18 | if self.t % 20 == 0:
19 | self.sound(self.l,Sound.BLOCK_FIRE_EXTINGUISH, .3 , 1)
20 |
21 | for e in self.nearbyMobs(self.l, 3, 3, 3):
22 | self.damage(e, False, .6, .45, .25, 0, 0, 0, .3)
23 | PySpell.knockback(e, VectorUP, .5)
24 | e.addPotionEffect(PotionEffect(PotionEffectType.SLOW, 101, 2))
25 |
26 | if self.t == 0:
27 | self.player.removeScoreboardTag('smoke_bomb')
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/spin_attack.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.potion import PotionEffect, PotionEffectType
3 |
4 | from com.wynnlab.spells import PySpell
5 |
6 | from java.lang import Math
7 |
8 | class Spell(PySpell):
9 | def __init__(self):
10 | self.hit = set()
11 |
12 | def tick(self):
13 | if self.t == 0:
14 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY):
15 | self.castSpell('ASSASSIN', 5)
16 |
17 | if self.clone:
18 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, .5, 1.6)
19 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .2, 1.5)
20 |
21 | l = self.player.getEyeLocation().clone().add(Math.sin(self.t * -22.5 * DEG2RAD) * 5, 0, Math.cos(self.t * -22.5 * DEG2RAD) * 5)
22 |
23 | for e in self.nearbyMobs(l, 3, 3, 3):
24 | if e in self.hit:
25 | continue
26 | self.hit.add(e)
27 |
28 | self.damage(e, False, 1.5, .7, 0, .3, 0, 0, 0)
29 | PySpell.knockback(e, VectorUP, .5)
30 | e.addPotionEffect(PotionEffect(PotionEffectType.BLINDNESS, 100, 1))
31 | e.addPotionEffect(PotionEffect(PotionEffectType.SLOW, 20, 8))
32 |
33 | self.particle(l.clone().subtract(0, .5, 0), Particle.SWEEP_ATTACK, 4, .5, .5, .5, 0)
34 | self.particle(l, Particle.CLOUD if self.clone else Particle.SQUID_INK, 5, .5, .5, .5, .1)
35 | self.particle(l, Particle.SPELL_WITCH if self.clone else Particle.CRIT_MAGIC, 10, .5, .5, .5, .2)
36 |
37 | self.sound(l, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, 1.2)
38 | self.sound(l, Sound.ITEM_FLINTANDSTEEL_USE, 1, 1.3)
39 |
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/vanish.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Bukkit, Particle, Sound
2 | from org.bukkit.potion import PotionEffect, PotionEffectType
3 | from org.bukkit.util import Vector
4 |
5 | from com.wynnlab.spells import PySpell
6 |
7 | class Spell(PySpell):
8 | def tick(self):
9 | v = self.player.getEyeLocation().getDirection()
10 | self.player.setVelocity(v.clone().setY(v.getY() * (.6 if v.getY() >= 0 else .2)).multiply(1.3).add(Vector(0, .5, 0)))
11 |
12 | self.player.addPotionEffect(PotionEffect(PotionEffectType.SPEED, 100, 4, True, False, True))
13 | self.player.addPotionEffect(PotionEffect(PotionEffectType.INCREASE_DAMAGE, 100, 4, True, False, True))
14 | self.player.addPotionEffect(PotionEffect(PotionEffectType.INVISIBILITY, 100, 0, True, False, True))
15 |
16 | self.particle(self.player.getEyeLocation(), Particle.SQUID_INK, 30, .5, 1, .5, .2)
17 | self.particle(self.player.getEyeLocation(), Particle.SPELL_WITCH, 40, .5, 1, .5, .5)
18 |
19 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, 1, 1.6)
20 | self.sound(Sound.ENTITY_GHAST_SHOOT, .6, 1)
21 |
22 | self.player.addScoreboardTag('invis')
23 |
24 | for p in Bukkit.getOnlinePlayers():
25 | p.hidePlayer(plugin, self.player)
26 | #TODO: Remove Vanish, Shadow Clone (?)
--------------------------------------------------------------------------------
/src/main/resources/classes/assassin/vanish_end.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Bukkit, Particle, Sound
2 | from org.bukkit.potion import PotionEffectType
3 |
4 | from com.wynnlab.spells import PySpell
5 |
6 | class Spell(PySpell):
7 | def tick(self):
8 | self.player.removeScoreboardTag('invis')
9 |
10 | self.player.removePotionEffect(PotionEffectType.SPEED)
11 | self.player.removePotionEffect(PotionEffectType.INCREASE_DAMAGE)
12 | self.player.removePotionEffect(PotionEffectType.INVISIBILITY)
13 |
14 | self.particle(self.player.getEyeLocation(), Particle.SQUID_INK, 30, .5, 1, .5, .2)
15 | self.particle(self.player.getEyeLocation(), Particle.SPELL_WITCH, 40, .5, 1, .5, .5)
16 |
17 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, 1, 1.6)
18 | self.sound(Sound.ENTITY_GHAST_SHOOT, .6, 1)
19 |
20 | for p in Bukkit.getOnlinePlayers():
21 | p.showPlayer(plugin, self.player)
--------------------------------------------------------------------------------
/src/main/resources/classes/monk/control.py:
--------------------------------------------------------------------------------
1 | from com.wynnlab.spells import PySpell
2 |
3 | class Spell(PySpell):
4 | def tick(self):
5 | pass
--------------------------------------------------------------------------------
/src/main/resources/classes/monk/monk.yml:
--------------------------------------------------------------------------------
1 | class:
2 | ==: com.wynnlab.WynnClass
3 | id: MONK
4 | item: BARRIER #WOODEN_SHOVEL
5 | #item_damage: 1
6 | metaStats:
7 | damage: 0
8 | defence: 0
9 | range: 0
10 | spells: 0
11 | invertedControls: false
12 | spells:
13 | - ==: com.wynnlab.spells.PythonSpell
14 | maxTick: 0
15 | script: monk_main.py
16 | - ==: com.wynnlab.spells.PythonSpell
17 | cost: 0
18 | maxTick: 0
19 | script: shield.py
20 | - ==: com.wynnlab.spells.PythonSpell
21 | cost: 0
22 | maxTick: 0
23 | script: step.py
24 | - ==: com.wynnlab.spells.PythonSpell
25 | cost: 0
26 | maxTick: 0
27 | script: silence.py
28 | - ==: com.wynnlab.spells.PythonSpell
29 | cost: 0
30 | maxTick: 0
31 | script: control.py
--------------------------------------------------------------------------------
/src/main/resources/classes/monk/monk_main.py:
--------------------------------------------------------------------------------
1 | from com.wynnlab.spells import PySpell
2 |
3 | class Spell(PySpell):
4 | def tick(self):
5 | pass
--------------------------------------------------------------------------------
/src/main/resources/classes/monk/shield.py:
--------------------------------------------------------------------------------
1 | from com.wynnlab.spells import PySpell
2 |
3 | class Spell(PySpell):
4 | def tick(self):
5 | pass
--------------------------------------------------------------------------------
/src/main/resources/classes/monk/silence.py:
--------------------------------------------------------------------------------
1 | from com.wynnlab.spells import PySpell
2 |
3 | class Spell(PySpell):
4 | def tick(self):
5 | pass
--------------------------------------------------------------------------------
/src/main/resources/classes/monk/step.py:
--------------------------------------------------------------------------------
1 | from com.wynnlab.spells import PySpell
2 |
3 | class Spell(PySpell):
4 | def tick(self):
5 | pass
--------------------------------------------------------------------------------
/src/main/resources/classes/shaman/aura.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.potion import PotionEffect, PotionEffectType
3 | from org.bukkit.util import Vector
4 |
5 | from com.wynnlab.api import PersistentDataAPI, PlayerAPI
6 | from com.wynnlab.spells import PySpell
7 |
8 | from java.lang import Math
9 |
10 | class Spell(PySpell):
11 | def __init__(self):
12 | self.totem = None
13 | self.hit = set()
14 |
15 | def tick(self):
16 | if self.t == 0:
17 | # Find totem
18 | totem_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem', None)
19 | for e in self.player.getNearbyEntities(16, 16, 16):
20 | if e.getEntityId() == totem_id:
21 | self.totem = e
22 |
23 | if self.totem is None:
24 | PlayerAPI.sendWynnMessage(self.player, 'messages.totem_out')
25 | self.cancel()
26 | return
27 |
28 | self.sound(self.totem.getLocation(), Sound.ENTITY_PLAYER_ATTACK_STRONG, .4, 1)
29 | self.sound(self.totem.getLocation(), Sound.ENTITY_SHULKER_SHOOT, .9, .7)
30 | self.sound(self.totem.getLocation(), Sound.ENTITY_EVOKER_CAST_SPELL, 1, 1.3)
31 | self.sound(self.totem.getLocation(), Sound.ENTITY_EVOKER_PREPARE_SUMMON, .7, .5)
32 |
33 | if self.clone:
34 | self.sound(self.totem.getLocation(), Sound.ENTITY_BLAZE_SHOOT, .7, .7)
35 | self.sound(self.totem.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, .4, .6)
36 |
37 | elif self.t <= 10:
38 | i = 0
39 | while i < 360:
40 | l = self.totem.getLocation().clone().add(Math.sin(i * DEG2RAD) * (self.t + 1), .4, Math.cos(i * DEG2RAD) * (self.t + 1))
41 |
42 | self.particle(l, Particle.SPELL_MOB if self.clone else Particle.CRIT_MAGIC, 0 if self.clone else 1, self.clone, self.clone, self.clone, self.clone)
43 | self.damageAndPull(l)
44 |
45 | i += 15 - self.t
46 |
47 | elif 15 < self.t <= 25:
48 | i = 0
49 | while i < 360:
50 | l = self.totem.getLocation().clone().add(Math.sin(i * DEG2RAD) * (26 - self.t), .4, Math.cos(i * DEG2RAD) * (26 - self.t))
51 |
52 | self.particle(l, Particle.SPELL_MOB if self.clone else Particle.CRIT_MAGIC, 0 if self.clone else 1, self.clone, self.clone, self.clone, self.clone)
53 | self.damageAndPull(l)
54 |
55 | i += self.t - 14
56 |
57 | if self.t % 10 == 0:
58 | for i in range(0, 360, 20):
59 | self.particle(self.totem.getLocation().clone().add(Math.sin(i * DEG2RAD) * 2, 1.6, Math.cos(i * DEG2RAD) * 2), Particle.FIREWORKS_SPARK, 1, 0, 0, 0, 0)
60 |
61 | for e in self.nearbyMobs(self.totem.getLocation(), 1, 1, 1):
62 | e.addPotionEffect(PotionEffect(PotionEffectType.SLOW, 20, 9, True, False))
63 |
64 | if self.t == 10 or self.t == 25:
65 | self.hit = set()
66 |
67 | def damageAndPull(self, l):
68 | for e in self.nearbyMobs(l, .5, 2, .5):
69 | pull_dir = self.totem.getLocation().clone().subtract(e.getLocation()).toVector()
70 | pull_dir = Vector(Math.max(Math.min(pull_dir.getX() / 5, 1), -1), 0.2, Math.max(Math.min(pull_dir.getZ() / 5, 1), -1))
71 |
72 | e.setVelocity(pull_dir)
73 |
74 | if e in self.hit:
75 | continue
76 | self.hit.add(e)
77 |
78 | self.damage(e, False, 2, .7, 0, 0, .3, 0, 0)
--------------------------------------------------------------------------------
/src/main/resources/classes/shaman/haul.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.potion import PotionEffect, PotionEffectType
3 | from org.bukkit.util import Vector
4 |
5 | from com.wynnlab.api import PersistentDataAPI, PlayerAPI
6 | from com.wynnlab.spells import PySpell
7 |
8 | from java.lang import Math
9 |
10 | class Spell(PySpell):
11 | def __init__(self):
12 | self.hit = set()
13 |
14 | def tick(self):
15 | if self.t == 0:
16 | # Find totem
17 | totem = None
18 | totem_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem', None)
19 | for e in self.player.getWorld().getEntities():
20 | if e.getEntityId() == totem_id:
21 | totem = e
22 |
23 | if totem is None:
24 | PlayerAPI.sendWynnMessage(self.player, 'messages.totem_out')
25 | self.cancel()
26 | return
27 |
28 | vector = totem.getLocation().clone().subtract(self.player.getLocation()).add(0, 2, 0).toVector()
29 | vector = Vector(Math.max(Math.min(vector.getX(), 6), -6), Math.max(Math.min(vector.getY(), 2), -2), Math.max(Math.min(vector.getZ(), 6), -6))
30 | self.player.setVelocity(vector.clone().multiply(0.5).setY(vector.getY()).multiply(0.5));
31 |
32 | self.particle(self.player.getLocation(), Particle.CLOUD, 6, 1, 1, 1, 0.1)
33 | self.particle(self.player.getLocation(), Particle.SQUID_INK, 6, 1, 1, 1, 0.1)
34 |
35 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, .4, .8)
36 | self.sound(Sound.ENTITY_BLAZE_SHOOT, 1, 1)
37 | self.sound(Sound.ENTITY_IRON_GOLEM_HURT, .8, .8)
38 | if self.clone:
39 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .1, .9)
40 |
41 | elif self.t > 10:
42 | if self.player.isOnGround():
43 | self.particle(self.player.getLocation().clone().add(0, 1, 0), Particle.FIREWORKS_SPARK if self.clone else Particle.TOTEM, 5, 1, 2, 1, .2)
44 | self.particle(self.player.getLocation(), Particle.CLOUD, 6, 1, .2, 1, .1)
45 | self.particle(self.player.getLocation(), Particle.SQUID_INK, 6, 1, .2, 1, .1)
46 | if self.clone:
47 | self.particle(self.player.getLocation(), Particle.SPELL_MOB, 0, 1, 1, 1, 1)
48 |
49 | self.sound(Sound.BLOCK_STONE_STEP, 1, .9)
50 | self.sound(Sound.BLOCK_STONE_FALL, 1, .9)
51 |
52 | self.player.setVelocity(Vector(0, .5, 0))
53 |
54 | self.cancel()
55 |
56 | else:
57 | for e in self.nearbyMobs(1, 1, 1):
58 | if e in self.hit:
59 | continue
60 | self.hit.add(e)
61 |
62 | self.damage(e, False, 1, .8, 0, .2, 0, 0, 0)
63 | PySpell.knockback(e, VectorUP, 2)
64 | e.addPotionEffect(PotionEffect(PotionEffectType.BLINDNESS, 100, 0, True, False))
--------------------------------------------------------------------------------
/src/main/resources/classes/shaman/shaman.yml:
--------------------------------------------------------------------------------
1 | class:
2 | ==: com.wynnlab.WynnClass
3 | id: SHAMAN
4 | item: STONE_SHOVEL
5 | item_damage: 7
6 | metaStats:
7 | damage: 2
8 | defence: 3
9 | range: 3
10 | spells: 5
11 | invertedControls: false
12 | spells:
13 | - ==: com.wynnlab.spells.PythonSpell
14 | maxTick: 15
15 | script: shaman_main.py
16 | - ==: com.wynnlab.spells.PythonSpell
17 | cost: 4
18 | maxTick: 0
19 | script: totem.py
20 | - ==: com.wynnlab.spells.PythonSpell
21 | cost: 1
22 | maxTick: 300
23 | script: haul.py
24 | - ==: com.wynnlab.spells.PythonSpell
25 | cost: 8
26 | maxTick: 30
27 | script: aura.py
28 | - ==: com.wynnlab.spells.PythonSpell
29 | cost: 6
30 | maxTick: 20
31 | script: uproot.py
32 | - ==: com.wynnlab.spells.PythonSpell
33 | maxTick: 400
34 | script: totem_tick.py
--------------------------------------------------------------------------------
/src/main/resources/classes/shaman/shaman_main.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 |
3 | from com.wynnlab.spells import PySpell
4 |
5 | class Spell(PySpell):
6 | def __init__(self):
7 | self.p_left = None
8 | self.p_center = None
9 | self.p_right = None
10 |
11 | self.dir_left = None
12 | self.dir_center = None
13 | self.dir_right = None
14 |
15 | self.hit = set()
16 |
17 | def init(self):
18 | self.p_left = self.player.getEyeLocation().clone()
19 | self.p_center = self.p_left.clone()
20 | self.p_right = self.p_center.clone()
21 |
22 | self.dir_center = self.player.getEyeLocation().getDirection().clone()
23 | self.dir_left = self.dir_center.clone().rotateAroundY(-.3)
24 | self.dir_right = self.dir_center.clone().rotateAroundY(.3)
25 |
26 | def tick(self):
27 | self.p_left.add(self.dir_left)
28 | self.p_center.add(self.dir_center)
29 | self.p_right.add(self.dir_right)
30 |
31 | if self.t == 0:
32 | self.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .6)
33 | self.sound(Sound.ENTITY_ZOMBIE_INFECT, .5, 1.8)
34 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, 1, 1.4)
35 | if self.clone:
36 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, .5, .2)
37 |
38 | else:
39 | self.particles(self.p_left)
40 | self.particles(self.p_center)
41 | self.particles(self.p_right)
42 |
43 | for e in self.nearbyMobs(self.p_left, 1, 2, 1):
44 | if e in self.hit:
45 | continue
46 | self.hit.add(e)
47 | self.damage(e, True, .333)
48 | self.knockback(e, .1)
49 | for e in self.nearbyMobs(self.p_center, 1, 2, 1):
50 | if e in self.hit:
51 | continue
52 | self.hit.add(e)
53 | self.damage(e, True, .333)
54 | self.knockback(e, .1)
55 | for e in self.nearbyMobs(self.p_right, 1, 2, 1):
56 | if e in self.hit:
57 | continue
58 | self.hit.add(e)
59 | self.damage(e, True, .333)
60 | self.knockback(e, .1)
61 |
62 | def particles(self, l):
63 | if self.clone:
64 | self.particle(l, Particle.SPELL_MOB, 0, 1, 1, 1, 1)
65 | else:
66 | self.particle(l, Particle.CRIT_MAGIC, 3, 0, 0, 0, 0)
67 | #self.particle(l, Particle.CRIT, 2, 0, 0, 0, 0)
--------------------------------------------------------------------------------
/src/main/resources/classes/shaman/totem.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Bukkit, Material, Sound
2 | from org.bukkit.entity import EntityType
3 | from org.bukkit.inventory import ItemStack
4 |
5 | from com.wynnlab.api import PersistentDataAPI
6 | from com.wynnlab.spells import PySpell
7 |
8 | class Spell(PySpell):
9 | def tick(self):
10 | if self.player.getScoreboardTags().contains('totem'):
11 | totem_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem', None)
12 | if not totem_id is None:
13 | for e in self.player.getWorld().getEntities():
14 | if e.getEntityId() == totem_id:
15 | e.remove()
16 |
17 | holo_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem_holo', None)
18 | if not holo_id is None:
19 | for e in self.player.getWorld().getEntities():
20 | if e.getEntityId() == holo_id:
21 | e.remove()
22 |
23 | totem_task = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem_task', None)
24 | if not totem_task is None:
25 | Bukkit.getScheduler().cancelTask(totem_task)
26 |
27 | self.player.addScoreboardTag('totem')
28 |
29 | self.sound(Sound.ENTITY_PLAYER_ATTACK_WEAK, .8, .3)
30 | self.sound(Sound.ENTITY_IRON_GOLEM_HURT, 1, .8)
31 | if self.clone:
32 | self.sound(Sound.ENTITY_BLAZE_SHOOT, 1, .9)
33 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .1, .7)
34 |
35 | dir = self.player.getEyeLocation().getDirection().clone().setY(self.player.getEyeLocation().getDirection().getY())
36 |
37 | totem = self.player.getWorld().spawnEntity(self.player.getLocation().clone().add(0, 1, 0).add(dir), EntityType.ARMOR_STAND)
38 |
39 | totem.addScoreboardTag('totem')
40 | totem.setGravity(True)
41 | totem.setInvulnerable(True)
42 | totem.setVisible(True)
43 |
44 | totem_item = ItemStack(Material.STONE_SHOVEL)
45 | totem_meta = totem_item.getItemMeta()
46 | totem_meta.setUnbreakable(True)
47 | totem_meta.setDamage(29 if self.clone else 28)
48 | totem_item.setItemMeta(totem_meta)
49 |
50 | totem.getEquipment().setHelmet(totem_item)
51 |
52 | totem.setVelocity(dir.setY(1))
53 |
54 | PersistentDataAPI.setInt(PersistentDataAPI.getData(self.player), 'totem', totem.getEntityId())
55 |
56 | self.castSpell('SHAMAN', 5, totem, None, False)
--------------------------------------------------------------------------------
/src/main/resources/classes/shaman/totem_tick.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.attribute import Attribute
3 | from org.bukkit.entity import EntityType, Mob, Player
4 |
5 | from com.wynnlab.api import PersistentDataAPI
6 | from com.wynnlab.spells import PySpell
7 |
8 | from java.lang import Math
9 |
10 | class Spell(PySpell):
11 | def __init__(self, totem, holo, hit):
12 | self.totem = totem
13 | self.holo = holo
14 |
15 | self.hit = hit
16 |
17 | def tick(self):
18 | if self.t == 0:
19 | PersistentDataAPI.setInt(PersistentDataAPI.getData(self.player), 'totem_task', self.getTaskId())
20 |
21 | if not self.hit:
22 | if not self.totem.isOnGround():
23 | self.particle(self.totem.getLocation().clone().add(0, 1, 0), Particle.END_ROD if self.clone else Particle.VILLAGER_HAPPY, 1, 0, 0, 0, 0)
24 | self.delay()
25 |
26 | else:
27 | self.hit = True
28 |
29 | self.totem.setMarker(True)
30 |
31 | self.holo = self.player.getWorld().spawnEntity(self.totem.getLocation().clone().add(0, 2.7, 0), EntityType.ARMOR_STAND)
32 |
33 | self.holo.setMarker(True)
34 | self.holo.setVisible(False)
35 | self.holo.setInvulnerable(True)
36 | self.holo.setCustomName(PySpell.colorText('20s', 'c'))
37 | self.holo.setCustomNameVisible(True)
38 |
39 | PersistentDataAPI.setInt(PersistentDataAPI.getData(self.player), 'totem_holo', self.holo.getEntityId())
40 |
41 | l = self.totem.getLocation()
42 |
43 | self.particle(l.clone().add(0,-1,0), Particle.EXPLOSION_HUGE, 1, 0, 0, 0, 1)
44 | self.particle(l, Particle.FIREWORKS_SPARK if self.clone else Particle.CRIT_MAGIC, 5, 2, 2, 2, .8)
45 | self.particle(l, Particle.SQUID_INK, 5, 2, 2, 2, .5)
46 |
47 | self.sound(l, Sound.ENTITY_EVOKER_PREPARE_SUMMON, .9, 1.1)
48 | self.sound(l, Sound.ENTITY_IRON_GOLEM_DEATH, 1, .8)
49 | self.sound(l, Sound.ITEM_TOTEM_USE, .9, 1)
50 | if self.clone:
51 | self.sound(l, Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, 1, .7)
52 | self.sound(l, Sound.BLOCK_FIRE_EXTINGUISH, .5, .5)
53 | self.sound(l, Sound.ENTITY_BLAZE_DEATH, .3, 1)
54 |
55 | for e in self.nearbyMobs(l, 4, 4, 4):
56 | self.damage(e, False, 1, .8, 0, 0, 0, .2, 0)
57 | PySpell.knockback(e, VectorUP, .5)
58 |
59 | else:
60 | if self.totem.isOnGround() and self.t >= 20:
61 | self.totem.setMarker(True)
62 |
63 | if self.t < 400:
64 | if self.t % 20 == 0:
65 | self.holo.setCustomName(PySpell.colorText('{0}s'.format((400 - self.t) // 20), 'c'))
66 |
67 | for e in self.player.getWorld().getNearbyEntities(self.totem.getLocation(), 8, 4, 8):
68 | if not isinstance(e, Mob):
69 | continue
70 |
71 | if isinstance(e, Player):
72 | PySpell.heal(e, self.player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue() / 10)
73 |
74 | else:
75 | self.damage(e, False, .2, .8, 0, 0, 0, 0, .2)
76 |
77 | l = self.totem.getLocation().clone().add(Math.sin(self.t * 10 * DEG2RAD) * 8, .7, Math.cos(self.t * 10 * DEG2RAD) * 8)
78 | self.particle(l, Particle.FIREWORKS_SPARK if self.clone else Particle.TOTEM, 1, 0, 0, 0, 0)
79 |
80 | self.particle(self.totem.getLocation().clone().add(0, 1, 0), Particle.SPELL_MOB, 2, .5, 1, .5, .5)
81 |
82 | self.holo.teleport(self.totem.getLocation().clone().add(0, 2.7, 0))
83 |
84 | else:
85 | self.totem.remove()
86 | self.holo.remove()
87 |
88 | self.player.removeScoreboardTag('totem')
--------------------------------------------------------------------------------
/src/main/resources/classes/warrior/bash.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Material, Particle, Sound
2 | from org.bukkit.potion import PotionEffect, PotionEffectType
3 |
4 | from com.wynnlab.spells import PySpell
5 |
6 | from java.lang import Math
7 |
8 | class Spell(PySpell):
9 | def __init__(self):
10 | self.bash_loc = None
11 |
12 | def tick(self):
13 | if self.t == 0:
14 | self.bash_loc = self.player.getLocation().clone().add(self.player.getEyeLocation().getDirection().multiply(2).setY(1))
15 | self.bash()
16 |
17 | self.sound(self.bash_loc, Sound.ENTITY_GHAST_SHOOT, 1, 1)
18 | if self.clone:
19 | self.sound(self.bash_loc, Sound.ENTITY_EVOKER_CAST_SPELL, 1, .4)
20 |
21 | elif self.t == 10:
22 | self.bash_loc.add(self.player.getEyeLocation().getDirection().multiply(4).setY(0))
23 | self.bash()
24 |
25 | self.sound(self.bash_loc, Sound.ENTITY_WITHER_BREAK_BLOCK, .4 if self.clone else .8, 1.8 if self.clone else .8)
26 | if self.clone:
27 | self.sound(self.bash_loc, Sound.BLOCK_GLASS_BREAK, 1, 1)
28 | self.sound(self.bash_loc, Sound.ENTITY_BLAZE_AMBIENT, .2, .8)
29 |
30 | for i in range(0, 360, 36):
31 | block_loc = self.bash_loc.clone().add(Math.sin(i * DEG2RAD) * 3, .5, Math.cos(i * DEG2RAD) * 3)
32 | block_data = (Material.GLOWSTONE if self.clone else Material.DIRT).createBlockData()
33 |
34 | self.particle(block_loc, Particle.BLOCK_CRACK, 10, .5, .5, .5, .2, block_data)
35 |
36 | block = self.player.getWorld().spawnFallingBlock(block_loc, block_data)
37 | block.setDropItem(False)
38 | block.setVelocity(block_loc.subtract(self.bash_loc).toVector().multiply(.05).setY(.4))
39 |
40 |
41 | def bash(self):
42 | if not self.clone:
43 | self.particle(self.bash_loc, Particle.SMOKE_LARGE, 15, .5, .5, .5, .1)
44 | self.particle(self.bash_loc, Particle.FIREWORKS_SPARK if self.clone else Particle.SQUID_INK, 10 if self.clone else 5, .4, .4, .4, .4 if self.clone else .2)
45 | self.particle(self.bash_loc, Particle.CLOUD, 5, .2, .2, .2, .2)
46 | self.particle(self.bash_loc, Particle.EXPLOSION_LARGE, 1, 0, 0, 0, 0)
47 | self.sound(self.bash_loc, Sound.ENTITY_GENERIC_EXPLODE, 1, 1)
48 |
49 | hit_count = 0
50 | for e in self.nearbyMobs(self.bash_loc, 6, 6, 6):
51 | self.damage(e, False, 1.3, .6, .4, 0, 0, 0, 0)
52 | self.knockback(e, 2)
53 | hit_count += 1
54 |
55 | self.player.addPotionEffect(PotionEffect(PotionEffectType.INCREASE_DAMAGE, hit_count * 20, 1, True, False, True))
--------------------------------------------------------------------------------
/src/main/resources/classes/warrior/charge.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.potion import PotionEffect, PotionEffectType
3 |
4 | from com.wynnlab.spells import PySpell
5 |
6 | class Spell(PySpell):
7 | def __init__(self):
8 | self.ground_start = False
9 |
10 | def tick(self):
11 | if self.t == 0:
12 | p_loc = self.player.getLocation().clone().add(0, 1, 0)
13 | self.particle(p_loc, Particle.VILLAGER_HAPPY if self.clone else Particle.SMOKE_LARGE, 5, .5, 2, .5, 0.1)
14 | self.particle(p_loc, Particle.CLOUD, 5, .5, 2, .5, .3)
15 | self.particle(p_loc, Particle.SQUID_INK, 8, .5, 2, .5, .2)
16 |
17 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK if self.clone else Sound.ENTITY_PLAYER_ATTACK_CRIT, .3, .6)
18 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, .8, 1)
19 | self.sound(Sound.ENTITY_BLAZE_SHOOT, 1, 1.1)
20 |
21 | if self.player.isOnGround():
22 | self.ground_start = True
23 | #else:
24 | # self.player.playSound(self.player.getLocation(), Sound.ITEM_ELYTRA_FLYING, 1, .9)
25 |
26 | self.player.setVelocity(self.player.getEyeLocation().getDirection().setY(1) if self.ground_start else self.player.getEyeLocation().getDirection().multiply(2).setY(.2))
27 |
28 | if self.t <= 5:
29 | self.particle(self.player.getLocation(), Particle.CLOUD if self.clone else Particle.SQUID_INK, 3, .2, .2, .2, .6)
30 |
31 | elif self.t < 10:
32 | if not self.player.isOnGround():
33 | self.player.setVelocity(self.player.getEyeLocation().getDirection().multiply(2).setY(-.3))
34 | self.particle(self.player.getLocation(), Particle.FIREWORKS_SPARK if self.clone else Particle.LAVA, 5 if self.clone else 2, .1, .1, .1, .4)
35 | else:
36 | self.particle(self.player.getLocation().clone().add(0, 2, 0), Particle.VILLAGER_HAPPY if self.clone else Particle.FLAME, 1, 0, 0, 0, .05)
37 |
38 | self.sound(Sound.ENTITY_GENERIC_EXPLODE, 1, 1.3)
39 | self.sound(Sound.BLOCK_STONE_STEP, 1, 1.3)
40 | if self.clone:
41 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1, 1.3)
42 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .2, 1.3)
43 |
44 | #self.player.stopSound(Sound.ITEM_ELYTRA_FLYING)
45 |
46 | self.cancel()
47 |
48 | else:
49 | self.sound(Sound.ENTITY_GENERIC_EXPLODE, 1, 1.3)
50 | self.sound(Sound.BLOCK_STONE_STEP, 1, 1.3)
51 |
52 | #self.player.stopSound(Sound.ITEM_ELYTRA_FLYING)
53 |
54 | hit_count = 0
55 | for e in self.nearbyMobs(1.5, 2, 1.5):
56 | self.damage(e, False, 1.5, .6, 0, 0, 0, .4, 0)
57 | PySpell.knockback(e, e.getLocation().clone().subtract(self.player.getLocation()).toVector(), 1)
58 | hit_count += 1
59 |
60 | self.player.addPotionEffect(PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, hit_count * 20, 1, True, False, True))
61 |
--------------------------------------------------------------------------------
/src/main/resources/classes/warrior/uppercut.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Material, Particle, Sound
2 | from org.bukkit.util import Vector
3 |
4 | from com.wynnlab.spells import PySpell
5 | from com.wynnlab.util import BukkitUtils
6 |
7 | class Spell(PySpell):
8 | def __init__(self):
9 | self.ripple_loc = None
10 | self.ripple_dir = None
11 |
12 | self.hit = set()
13 |
14 | self.has_hit = False
15 | self.shift = False
16 |
17 | def init(self):
18 | self.ripple_loc = self.player.getLocation().clone().add(0, .1, 0)
19 | self.ripple_dir = BukkitUtils.normalizeOnXZ(self.player.getEyeLocation().getDirection())
20 | self.shift = self.player.isSneaking()
21 |
22 | def tick(self):
23 | if self.t == 0 and self.clone:
24 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, .7, .7)
25 |
26 | if self.t <= 5:
27 | self.ripple_loc.add(self.ripple_dir)
28 |
29 | self.sound(self.ripple_loc, Sound.BLOCK_GLASS_BREAK if self.clone else Sound.ENTITY_WITHER_BREAK_BLOCK, 1 if self.clone else .2, 1)
30 | if self.clone:
31 | self.sound(self.ripple_loc, Sound.BLOCK_LAVA_EXTINGUISH, .6, 1.2)
32 |
33 | self.particle(self.ripple_loc, Particle.BLOCK_CRACK, 10, .5, .5, .5, .5, (Material.GLOWSTONE if self.clone else Material.DIRT).createBlockData())
34 |
35 | for e in self.nearbyMobs(self.ripple_loc, 3, 3, 3):
36 | if e in self.hit:
37 | continue
38 | self.hit.add(e)
39 |
40 | self.castSpell('WARRIOR', 5, e)
41 | self.has_hit = True
42 |
43 | if self.t == 5 and self.has_hit and self.shift:
44 | self.player.setVelocity(Vector(0, 1.5, 0))
--------------------------------------------------------------------------------
/src/main/resources/classes/warrior/uppercut_throw.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.util import Vector
3 |
4 | from com.wynnlab.spells import PySpell
5 |
6 | class Spell(PySpell):
7 | def __init__(self, e):
8 | self.e = e
9 |
10 | def tick(self):
11 | if self.t == 0:
12 | self.e.setVelocity(Vector(0, 1.75, 0))
13 | self.damage(self.e, False, 3, .7, .2, .1, 0, 0, 0)
14 | self.sound(self.e.getLocation(), Sound.ENTITY_ENDER_DRAGON_HURT, 1 if self.clone else .5, 1)
15 |
16 | elif self.t < 8:
17 | self.particle(self.e.getLocation(), Particle.CLOUD if self.clone else Particle.LAVA, 3 if self.clone else 1, .6, .1, .6, 0)
18 | if self.clone:
19 | self.particle(self.e.getLocation(), Particle.FIREWORKS_SPARK, 1, .6, .1, .6, .5)
20 |
21 | elif self.t == 8:
22 | self.e.setVelocity(Vector(0, 0, 0))
23 | self.damage(self.e, False, .5, .6, 0, .4, 0, 0, 0)
24 |
25 | self.explode()
26 |
27 | self.sound(self.e.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1, .9)
28 | if self.clone:
29 | self.sound(self.e.getLocation(), Sound.ENTITY_BLAZE_AMBIENT, .2, .8)
30 |
31 | elif self.t == 10:
32 | self.e.setVelocity(Vector(0, -2, 0))
33 |
34 | elif (not self.e.isOnGround()) and self.t < 20:
35 | self.particle(self.e.getLocation(), Particle.FIREWORKS_SPARK if self.clone else Particle.SMOKE_LARGE, 10 if self.clone else 2, .6, .6, .6, .5 if self.clone else 0)
36 |
37 | else:
38 | self.damage(self.e, False, .5, .8, 0, .2, 0, 0, 0)
39 | self.explode()
40 | self.cancel()
41 |
42 | def explode(self):
43 | self.particle(self.e.getLocation(), Particle.LAVA, 10, .5, .5, .5, 0)
44 | self.particle(self.e.getLocation(), Particle.FIREWORKS_SPARK if self.clone else Particle.SMOKE_LARGE, 10 if self.clone else 2, .6, .6, .6, .5 if self.clone else 0)
45 | self.particle(self.e.getLocation(), Particle.SQUID_INK, 5 if self.clone else 10, .4, .4, .4, .3)
46 | self.particle(self.e.getLocation(), Particle.CLOUD, 10, 1, 1, 1, 1)
--------------------------------------------------------------------------------
/src/main/resources/classes/warrior/war_scream.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 | from org.bukkit.entity import Player
3 | from org.bukkit.potion import PotionEffect, PotionEffectType
4 |
5 | from com.wynnlab.spells import PySpell
6 | from com.wynnlab.util import BukkitUtils
7 |
8 | from java.lang import Math
9 |
10 | class Spell(PySpell):
11 | def __init__(self):
12 | self.scream_loc = None
13 | self.scream_dir = None
14 |
15 | def init(self):
16 | self.scream_loc = self.player.getEyeLocation().clone()
17 | self.scream_dir = BukkitUtils.normalizeOnXZ(self.player.getEyeLocation().getDirection())
18 |
19 | def tick(self):
20 | if self.t == 0:
21 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, .5, .5)
22 | self.sound(Sound.ENTITY_ENDER_DRAGON_FLAP, 1, 1)
23 | self.sound(Sound.ENTITY_ENDER_DRAGON_GROWL, .4, 1)
24 |
25 | for p in self.player.getWorld().getNearbyEntities(self.player.getLocation(), 8, 8, 8):
26 | if not isinstance(p, Player):
27 | continue
28 |
29 | p.addPotionEffect(PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 4800, 2, True, False, True))
30 | p.addPotionEffect(PotionEffect(PotionEffectType.INCREASE_DAMAGE, 4800, 1, True, False, True))
31 |
32 | if self.t <= 8:
33 | for i in range(0, 360, 45):
34 | l = self.player.getLocation().clone().add(Math.sin(i * DEG2RAD) * (self.t + 1), .2, Math.cos(i * DEG2RAD) * (self.t + 1))
35 | self.particle(l, Particle.CLOUD if self.clone else Particle.SQUID_INK, 3, .1, 0, .1, .1)
36 | self.particle(l, Particle.CRIT, 3, .1, 0, .1, .1)
37 | self.particle(l, Particle.SPELL_MOB if self.clone else Particle.LAVA, 5 if self.clone else 1, .2, .2, .2, .5)
38 |
39 | self.scream_loc.add(self.scream_dir)
40 |
41 | if self.t >= 2:
42 | self.particle(self.scream_loc, Particle.EXPLOSION_LARGE, 1, 0, 0, 0, 0)
43 |
44 | for e in self.nearbyMobs(self.scream_loc, 3, 3, 3):
45 | self.damage(e, False, .3, 0, 0, 0, 0, .75, .25)
--------------------------------------------------------------------------------
/src/main/resources/classes/warrior/warrior.yml:
--------------------------------------------------------------------------------
1 | class:
2 | ==: com.wynnlab.WynnClass
3 | id: WARRIOR
4 | item: IRON_SHOVEL
5 | metaStats:
6 | damage: 2
7 | defence: 3
8 | range: 3
9 | spells: 5
10 | invertedControls: false
11 | spells:
12 | - ==: com.wynnlab.spells.PythonSpell
13 | maxTick: 0
14 | script: warrior_main.py
15 | - ==: com.wynnlab.spells.PythonSpell
16 | cost: 6
17 | maxTick: 10
18 | script: bash.py
19 | - ==: com.wynnlab.spells.PythonSpell
20 | cost: 4
21 | maxTick: 10
22 | script: charge.py
23 | - ==: com.wynnlab.spells.PythonSpell
24 | cost: 8
25 | maxTick: 5
26 | script: uppercut.py
27 | - ==: com.wynnlab.spells.PythonSpell
28 | cost: 4
29 | maxTick: 20
30 | script: war_scream.py
31 | - ==: com.wynnlab.spells.PythonSpell
32 | maxTick: 20
33 | script: uppercut_throw.py
--------------------------------------------------------------------------------
/src/main/resources/classes/warrior/warrior_main.py:
--------------------------------------------------------------------------------
1 | from org.bukkit import Particle, Sound
2 |
3 | from com.wynnlab.spells import PySpell
4 |
5 | class Spell(PySpell):
6 | def tick(self):
7 | self.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .8)
8 | l = self.player.getEyeLocation().clone().add(self.player.getEyeLocation().getDirection().multiply(2))
9 | self.particle(l, Particle.SWEEP_ATTACK, 1, 0, 0, 0, 0)
10 |
11 | for e in self.nearbyMobs(l, 3, 3, 3):
12 | self.damage(e, True, 1)
13 | self.knockback(e, 1)
--------------------------------------------------------------------------------
/src/main/resources/lang/ar_SA.yml:
--------------------------------------------------------------------------------
1 | classes:
2 | MAGE:
3 | className: 'ساحر'
4 | cloneName: 'ساحر اسود'
5 | lore: |
6 | &7Mages are naturally talented
7 | &7in the magical arts. While
8 | &7their raw damage may be
9 | &7considered weaker, they
10 | &7offer a great amount of
11 | &7utility and versatility
12 | &7with their spells.
13 | ARCHER:
14 | className: رامي اسهم
15 | cloneName: صياد
16 | lore: |
17 | &7Benefiting from the highest
18 | &7range in the game, Archers
19 | &7can comfortably keep their
20 | &7distance from enemies while
21 | &7dishing out high levels
22 | &7of damage. But they must
23 | &7be wary of attacks, as their
24 | &7defence is low.
25 | ASSASSIN:
26 | className: مغتال
27 | cloneName: نينجا
28 | lore: |
29 | &7The Assassin is the deadliest
30 | &7of all the classes, exploiting
31 | &7enemies weak spots to deal
32 | &7massive amounts of damage
33 | &7from the shadows, however
34 | &7they endanger themselves
35 | &7by having to get extremely
36 | &7close to the enemy.
37 | gui:
38 | class:
39 | select: 'انت الان &3[%s]'
40 | item:
41 | title: '&fحدد &6&l%s'
42 | damage: '&6⚔ الدمج %s'
43 | defence: '&c❤ الدفاع %s'
44 | range: '&a➸ النطاق %s'
45 | spells: '&d✺ التعويذات %s'
46 | clone: '&8اظغط الزر الايمن لـ &b&l%s'
47 |
--------------------------------------------------------------------------------
/src/main/resources/locations.yml:
--------------------------------------------------------------------------------
1 | locations:
2 | - ==: com.wynnlab.locations.Location
3 | name: Insunis
4 | pos1:
5 | ==: org.bukkit.Location
6 | world: neww
7 | x: 2041
8 | y: 56
9 | z: 1819
10 | pos2:
11 | ==: org.bukkit.Location
12 | world: neww
13 | x: 2102
14 | y: 111
15 | z: 1884
16 | announce: true
--------------------------------------------------------------------------------
/src/main/resources/mobs/dummy.yml:
--------------------------------------------------------------------------------
1 | mob:
2 | ==: com.wynnlab.entities.WynnMob
3 | name: '&cDummy'
4 | mob_type: VINDICATOR
5 | ai: MELEE
6 | level: 0
7 | health: 100000
8 | regen: 0
9 | damage: 0-0
10 | attack_speed: 1
11 | speed: .2
12 | vision: 10
13 | defense: 0
14 | equipment:
15 | ==: com.wynnlab.entities.WynnMob$Equipment
16 | main_hand:
17 | ==: org.bukkit.inventory.ItemStack
18 | type: IRON_AXE
19 | spells:
20 | - ==: com.wynnlab.spells.MobSpell
21 | name: Pull
22 | max_tick: 0
23 | script: pull.ws2
24 | - ==: com.wynnlab.spells.MobSpell
25 | name: BBPull
26 | max_tick: 0
27 | has_boss_bar: true
28 | script: pull.ws2
--------------------------------------------------------------------------------
/src/main/resources/mobs/scripts/pull.ws2:
--------------------------------------------------------------------------------
1 | # MobSpell
2 |
3 | function tick(t, caster, target) {
4 | target.player.velocity = caster.location.clone().subtract(target.location).toVector();
5 | }
--------------------------------------------------------------------------------
/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | name: WynnLab
2 | version: @VERSION@
3 | main: com.wynnlab.Main
4 | depend: [ KBukkit, WynnLabAPI, WynnScript2, PyBukkit ]
5 | authors: [ Siinus ]
6 | description: Wynncraft systematic recreation @API@
7 | api-version: @API@
8 | prefix: WynnLab
9 | website: wynnlab.com
10 | commands:
11 | class:
12 | description: Select your Wynncraft class
13 | usage: /class []
14 | item:
15 | description: Give yourself a Wynncraft item
16 | usage: /item ...
17 | cast:
18 | description: Cast a spell
19 | usage: /cast
20 | rank:
21 | description: Apply the rank to the player
22 | usage: /rank []
23 | itemdata:
24 | description: Get the metadata of an item
25 | usage: /itemdata - []
26 | getid:
27 | description: Get the identification sum of a player
28 | usage: /getid []
29 | script:
30 | description: Executes a script
31 | usage: /script
32 | msg:
33 | description: Message a single player
34 | usage: /msg
35 | r:
36 | description: Reply to your current conversation
37 | usage: /r
38 | party:
39 | description: Manage a party
40 | usage: /party create|invite|join|leave
41 | p:
42 | description: Send a message to your party
43 | usage: /p
44 | dummy:
45 | description: Spawns a dummy
46 | usage: /dummy
47 | upload:
48 | description: Uploads a file
49 | usage: /upload item|mob|mob_spell|music/*|file*/
50 | wlrl:
51 | description: WynnLab reload
52 | usage: /wlrl (mobs|mob |classes|class )
53 | mob:
54 | description: Spawn a WynnLab mob
55 | usage: /mob
56 | pvp:
57 | description: Toggle pvp
58 | usage: /pvp
59 | hub:
60 | description: Go to the hub
61 | usage: /hub
62 | leave:
63 | description: Leave the game you're in
64 | usage: /leave
65 | aliases: [ l ]
66 | stats:
67 | description: Show your stats in the current game mode
68 | usage: /stats []
69 | build:
70 | description: Builds actions
71 | usage: /build (save |equip |delete |publish ...|show)
--------------------------------------------------------------------------------
/src/test/kotlin/Optional performance.kt:
--------------------------------------------------------------------------------
1 | fun main() {
2 | val o = Optional("Hi")
3 | val t1 = System.nanoTime()
4 | repeat(100) {
5 | val l = o.ifSome1 { it.length }
6 | }
7 | val t2 = System.nanoTime()
8 | repeat(100) {
9 | val l = o.ifSome2 { it.length }
10 | }
11 | val t3 = System.nanoTime()
12 | println(t2 - t1)
13 | println(t3 - t2)
14 | }
15 |
16 | sealed class Optional {
17 | class Some(val value: T) : Optional() {
18 | override fun ifSome1(block: (T) -> R) = Some(block(value))
19 | override infix fun or1(block: () -> T): T = value
20 | override fun toString(): String = value.toString()
21 | }
22 |
23 | class None : Optional() {
24 | override fun ifSome1(block: (T) -> R): Optional = None()
25 | override infix fun or1(block: () -> T): T = block()
26 | override fun toString(): String = "NONE"
27 | }
28 |
29 | abstract fun ifSome1(block: (T) -> R): Optional
30 |
31 | inline fun ifSome2(block: (T) -> R): Optional = when (this) {
32 | is Some -> Some(block(value))
33 | is None -> None()
34 | }
35 |
36 | abstract infix fun or1(block: () -> T): T
37 |
38 | inline infix fun or2(block: () -> T): T = when (this) {
39 | is Some -> value
40 | is None -> block()
41 | }
42 |
43 | companion object {
44 | operator fun invoke(nullable: T?): Optional = nullable?.let { Some(it) } ?: None()
45 | }
46 | }
--------------------------------------------------------------------------------
/src/test/kotlin/Optional test.kt:
--------------------------------------------------------------------------------
1 | import com.wynnlab.util.Optional
2 | import com.wynnlab.util.optionalAs
3 |
4 | fun main() {
5 | val some: Optional = Optional("Hello")
6 | val none: Optional = Optional(null)
7 |
8 | println(some)
9 | println(none)
10 |
11 | val l1 = some.ifSome { it.length }
12 | val l2 = none.ifSome { it.length }
13 |
14 | println(l1)
15 | println(l2)
16 |
17 | val any1: Any = "Any"
18 | val any2: Any? = null
19 | val a1Opt = any1.optionalAs()
20 | val a2Opt = any2.optionalAs()
21 |
22 | println(a1Opt)
23 | println(a2Opt)
24 | }
--------------------------------------------------------------------------------
/src/test/kotlin/api test.kt:
--------------------------------------------------------------------------------
1 | import com.wynnlab.items.getAPIResults
2 |
3 | fun main() {
4 | val items = getAPIResults("Crusade")
5 | print(items)
6 |
7 | //val wynnItem = WynnItem.parse(items[0])
8 | //print(wynnItem)
9 | }
--------------------------------------------------------------------------------
/src/test/kotlin/jstest.kt:
--------------------------------------------------------------------------------
1 | import javax.script.ScriptEngineManager
2 |
3 | fun main() {
4 | val js = ScriptEngineManager().getEngineByName("javascript")
5 | //js.eval("var a = Java.type(\"p.IC\");")
6 | println(js.get("Java")::class.java)
7 | /*js.eval("""
8 | function tick() {
9 | print(this.str);
10 | }
11 | """.trimIndent())
12 | val tick1 = js.get("tick").also { println(it::class.java.name) }
13 | js.eval("""
14 | function tick() {
15 | print("2: "+this.str);
16 | }
17 | """.trimIndent())
18 | val tick2 = js.get("tick").also { println(it::class.java.name) }
19 | js.eval("tick()")
20 | (tick1 as ScriptObjectMirror).call(null)
21 | println(js["no"])*/
22 | /*val obj = TestT("1") {
23 | tick.call(this)
24 | }
25 | obj.start()
26 | val obj2 = TestT("2") {
27 | tick.call(this)
28 | }
29 | obj2.start()*/
30 | /*js.put("coll", listOf("a", "b", "c") as Collection)
31 | js.eval("""
32 | coll.forEach(function (it) {
33 | print(it);
34 | });
35 | """.trimIndent())*/
36 | /*js.put("IC", p.IC::class.java)
37 | js.eval("print(IC)")*/
38 | /*js.put("_ac", ::acceptClass)
39 | js.eval("function ac(clazz) { _ac.invoke(clazz); }")
40 | js.eval("ac(Java.type(\"p.IC\"))")*/
41 | }
42 |
43 | fun acceptClass(c: Class<*>) {
44 | print("Class: ${c.name}")
45 | }
46 |
47 | class TestT(val str: String, val runnable: TestT.() -> Unit) : Thread() {
48 | override fun run() {
49 | repeat(10) {
50 | this.runnable()
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/test/kotlin/p/IC.kt:
--------------------------------------------------------------------------------
1 | package p
2 |
3 | data class IC(var i: Int) {
4 | data class U(val a: String)
5 | }
6 |
7 | data class FC(var f: Float)
8 |
9 | fun acceptClass(clazz: Class) {
10 | println(clazz.interfaces.contentToString())
11 | }
12 |
13 | class Predicate(test: (T) -> Boolean): java.util.function.Predicate by java.util.function.Predicate(test)
--------------------------------------------------------------------------------
/src/test/kotlin/scripting.kt:
--------------------------------------------------------------------------------
1 | import org.python.util.PythonInterpreter
2 | import java.util.function.Predicate
3 |
4 | fun main() {
5 | val pythonInterpreter = PythonInterpreter()
6 | pythonInterpreter.use { py ->
7 | py.setOut(System.out)
8 |
9 | val code = py.compile("""
10 | def doSth(ic):
11 | print(ic)
12 | True
13 |
14 | #s = S(Predicate(lambda a: doSth(a)))
15 |
16 | #s.fn.invoke('Hi')
17 | """.trimIndent())
18 |
19 | py.set("S", S::class.java)
20 | py.set("Predicate", p.Predicate::class.java)
21 |
22 | py.exec(code)
23 | println(py.get("doSth")::class.java)
24 | }
25 | }
26 |
27 | fun PythonInterpreter.print(name: String) {
28 | val value = get(name)
29 | println("${value::class.simpleName} $name = $value")
30 | }
31 |
32 | class S(val fn: Predicate)
33 |
34 | fun echo(it: String) = println(it)
35 |
36 | data class IC(val i: Int)
37 |
38 | fun interface Tick {
39 | fun tick()
40 | }
--------------------------------------------------------------------------------