9
0
mirror of https://github.com/Auxilor/EcoMobs.git synced 2025-12-19 23:19:17 +00:00

Compare commits

...

171 Commits

Author SHA1 Message Date
Auxilor
ed0fd90df8 libreforge-updater 2023-04-02 17:44:13 +01:00
Auxilor
42af89c79a libreforge-updater 2023-03-30 15:30:24 +01:00
Auxilor
d453461eeb why is model engine like this 2023-03-29 19:31:03 +01:00
Auxilor
e4093a0fd5 libreforge-updater 2023-03-29 19:21:02 +01:00
Auxilor
7e950ea508 libreforge-updater 2023-03-29 15:47:17 +01:00
Auxilor
ac79baa2d3 Fixed workflows 2023-03-29 13:44:06 +01:00
Auxilor
50adfae567 Moved to repo.auxilor.io 2023-03-29 13:39:57 +01:00
Auxilor
153022c3bf Fixed permissions on paper 2023-03-28 21:42:33 +01:00
Auxilor
8d37635381 Cleanup 2023-03-28 21:19:12 +01:00
Auxilor
299d3ee1d6 Updated to reflect libreforge change 2023-03-28 19:28:06 +01:00
Auxilor
f0a2d32b95 Moved integration 2023-03-28 18:58:58 +01:00
Auxilor
4e86750c7d Fixed duplicated messages for lifespan 2023-03-28 17:23:24 +01:00
Auxilor
b3b7695218 Fixed several bugs 2023-03-28 16:04:59 +01:00
Auxilor
1aa0a27c65 Fixed publications 2023-03-28 14:55:23 +01:00
Auxilor
392a76bad8 Updated to libreforge 4 2023-03-28 14:32:53 +01:00
Auxilor
95afe96860 Changed load order 2023-03-22 22:10:03 +00:00
Auxilor
21d24a5198 libreforge-updater 2023-03-13 13:40:30 +00:00
Auxilor
af9766a391 libreforge-updater 2023-03-02 12:56:01 +00:00
Auxilor
df70871bad libreforge-updater 2023-02-22 15:02:39 +00:00
Auxilor
b030af609a libreforge-updater 2023-02-15 20:59:05 +00:00
Auxilor
344e71cd9a libreforge-updater 2023-02-12 16:55:42 +00:00
Auxilor
7b7a16f9c6 libreforge-updater 2023-02-09 14:12:44 +00:00
Auxilor
ba1c348f8e libreforge-updater 2023-02-07 14:46:53 +00:00
Auxilor
c81f7174e2 libreforge-updater 2023-02-04 15:36:59 +00:00
Auxilor
53b037816d libreforge-updater 2023-01-24 10:09:30 +00:00
Auxilor
d7e07c1a62 libreforge-updater 2023-01-17 16:48:42 +00:00
Auxilor
d939296d96 libreforge-updater 2023-01-13 18:08:48 +00:00
Auxilor
2505ddd845 libreforge-updater 2023-01-07 12:17:46 +00:00
Auxilor
ea7371db9e libreforge-updater 2023-01-02 15:58:40 +00:00
Auxilor
b53ab306ed libreforge-updater 2022-12-26 14:01:48 +01:00
Auxilor
33f82117e4 Updated modelengine 2022-12-20 15:20:45 +00:00
Auxilor
a80e060a7e libreforge-updater 2022-12-20 15:15:33 +00:00
Auxilor
a915752922 libreforge-updater 2022-12-12 14:01:34 +00:00
Auxilor
06eb724bd8 libreforge-updater 2022-12-09 17:01:53 +00:00
Auxilor
18c66ef10c libreforge-updater 2022-12-05 10:51:14 +00:00
Auxilor
ae0c8531b0 libreforge-updater 2022-11-30 17:38:55 +00:00
Auxilor
705eafb9af libreforge-updater 2022-11-27 21:45:04 +00:00
Auxilor
e83ede56f0 libreforge-updater 2022-11-26 19:20:59 +00:00
Auxilor
6bddf72111 libreforge-updater 2022-11-24 14:30:48 +00:00
Auxilor
d32d07f4e2 libreforge-updater 2022-11-23 17:25:42 +00:00
Auxilor
8c40d9861d libreforge-updater 2022-11-21 16:03:34 +00:00
Auxilor
03272f794e libreforge-updater 2022-11-17 08:39:07 +00:00
Auxilor
8ff42da43c libreforge-updater 2022-11-12 17:35:11 +00:00
Auxilor
7f61f6a66a libreforge-updater 2022-11-06 19:52:34 +00:00
Auxilor
c1dde026b7 Updated chains 2022-11-06 17:00:48 +00:00
Auxilor
983246a7c4 Added illusioner 2022-11-06 16:56:39 +00:00
Auxilor
ee32897b1c libreforge-updater 2022-11-01 16:23:35 +00:00
Auxilor
67b38896ca libreforge-updater 2022-10-28 11:35:44 +01:00
Auxilor
39b91bc828 libreforge-updater 2022-10-26 22:12:03 +01:00
Auxilor
e2e7b44a75 Fix 2022-10-24 17:11:42 +01:00
Auxilor
3c1e5ee192 libreforge-updater 2022-10-24 17:05:27 +01:00
Auxilor
56789f331b libreforge-updater 2022-10-21 19:26:42 +01:00
Auxilor
e99b96132f libreforge-updater 2022-10-19 20:44:41 +01:00
Auxilor
c0297cd3db libreforge-updater 2022-10-18 14:14:41 +01:00
Auxilor
3b798a8ed7 libreforge-updater 2022-10-16 23:27:19 +01:00
Auxilor
bc73201ec5 libreforge-updater 2022-10-13 20:13:11 +01:00
Auxilor
b1365855af libreforge-updater 2022-10-10 21:04:32 +01:00
Auxilor
1ce50cb0b9 libreforge-updater 2022-10-09 15:03:11 +01:00
Auxilor
2a50868624 libreforge-updater 2022-10-07 19:51:54 +01:00
Auxilor
0a0e7a9661 libreforge-updater 2022-10-06 12:04:55 +01:00
Auxilor
8cd4ccdbd7 libreforge-updater 2022-10-04 15:53:28 +01:00
Auxilor
429bc6a61f libreforge-updater 2022-10-03 18:30:03 +01:00
Auxilor
b92ea06667 Fixed _example.yml 2022-10-02 17:01:40 +01:00
Auxilor
1e332bf845 libreforge-updater 2022-10-02 14:58:47 +01:00
Auxilor
7cec9f3e30 Added separator ambivalence to boss configs and Model Engine animation support 2022-09-29 08:40:30 +01:00
Auxilor
7db3af5dca oops 2022-09-28 17:55:29 +01:00
Auxilor
137f4e3732 libreforge-updater 2022-09-28 17:53:14 +01:00
Auxilor
7338a24b81 Fix 2022-09-28 16:12:42 +01:00
Auxilor
bde5de1d77 Fixed plugin.yml 2022-09-28 16:12:23 +01:00
Auxilor
b48cc66383 Updated to 8.91.1 2022-09-28 16:12:00 +01:00
Auxilor
bf59ba4d4a Improved _example.yml 2022-09-28 16:11:48 +01:00
Auxilor
127a43e032 PR Improvements 2022-09-28 16:10:21 +01:00
Will FP
383893c8f6 Merge pull request #50
fix: boss transformations
2022-09-28 16:01:24 +01:00
Will FP
37926bd016 Merge pull request #52
Feature/modelengine
2022-09-28 16:01:08 +01:00
Will FP
6778058150 Merge pull request #53
fix: handle spawning of bosses from droppers and dispensers
2022-09-28 15:59:45 +01:00
Auxilor
8addad09d2 fix 2022-09-26 18:54:34 +01:00
DaRacci
7fe0eece16 fix: handle spawning of bosses from droppers and dispensers 2022-09-27 01:13:42 +10:00
DaRacci
eca8726323 fix: check if the model exists 2022-09-27 00:10:20 +10:00
DaRacci
16ba41f39a feat: ModelEngine support 2022-09-27 00:07:28 +10:00
Auxilor
685f40a71b Merge branch 'fix/publishing'
# Conflicts:
#	build.gradle
2022-09-26 13:54:00 +01:00
Auxilor
76c6d22a00 libreforge-updater 2022-09-26 10:52:49 +01:00
DaRacci
38629407bc fix: Use component from subproject 2022-09-26 14:44:12 +10:00
DaRacci
1eee00b88e fix: Publishing
Also converted gradle build to kotlin.
Also updated gradle to 7.5.1

Closes: https://github.com/Auxilor/EcoBosses/issues/49, https://github.com/Auxilor/EcoBosses/issues/41
2022-09-25 23:39:05 +10:00
DaRacci
de47ccf159 fix: boss transformations
Closes: https://github.com/Auxilor/EcoBosses/issues/36
2022-09-25 22:27:08 +10:00
Auxilor
b81e7af836 libreforge-updater 2022-09-22 17:31:03 +01:00
Auxilor
fcde21c21a libreforge-updater 2022-09-21 15:29:05 +01:00
Auxilor
405659f293 libreforge-updater 2022-09-20 10:57:39 +01:00
Auxilor
2d6154d11f libreforge-updater 2022-09-17 15:46:02 +01:00
Auxilor
9fad76ffad libreforge-updater 2022-09-15 12:15:47 +01:00
Auxilor
e4a40470b8 libreforge-updater 2022-09-15 12:09:44 +01:00
Auxilor
f966629e21 libreforge-updater 2022-09-14 18:53:14 +01:00
Auxilor
93d09c1f3d libreforge-updater 2022-09-14 15:12:30 +01:00
Auxilor
56763be02d libreforge-updater 2022-09-14 15:09:33 +01:00
Auxilor
bd05d4474f libreforge-updater 2022-09-14 12:59:22 +01:00
Auxilor
aa0f9c195d libreforge-updater 2022-09-13 19:15:06 +01:00
Auxilor
e9e0214d1e libreforge-updater 2022-09-12 21:20:54 +01:00
Auxilor
744e3a943d libreforge-updater 2022-09-12 17:14:59 +01:00
Auxilor
fcaea262e8 libreforge-updater 2022-09-11 19:27:24 +01:00
Auxilor
062d2eea77 libreforge-updater 2022-09-10 12:58:21 +01:00
Auxilor
25844170eb libreforge-updater 2022-09-10 10:51:17 +01:00
Auxilor
00cc509b40 libreforge-updater 2022-09-06 15:43:31 +01:00
Auxilor
77e46ffb55 libreforge-updater 2022-09-06 13:46:10 +01:00
Auxilor
1f72e3b9b3 libreforge-updater 2022-09-06 11:25:17 +01:00
Auxilor
a94a5cc04d libreforge-updater 2022-09-05 18:00:28 +01:00
Auxilor
2b8d8eb20a libreforge-updater 2022-09-04 17:22:44 +01:00
Auxilor
1b4851fb9c libreforge-updater 2022-09-04 16:22:01 +01:00
Auxilor
80181bb66e libreforge-updater 2022-09-03 14:20:18 +01:00
Auxilor
d2d6355003 libreforge-updater 2022-09-01 13:05:26 +01:00
Auxilor
b44016d4fe libreforge-updater 2022-08-31 12:45:30 +01:00
Auxilor
74f1953074 libreforge-updater 2022-08-30 20:29:05 +01:00
Auxilor
041e8e070e libreforge-updater 2022-08-30 19:21:42 +01:00
Auxilor
d69b205de5 libreforge-updater 2022-08-29 10:58:32 +01:00
Auxilor
ad827f2b65 libreforge-updater 2022-08-28 15:40:32 +01:00
Auxilor
e8b8dcd2c4 libreforge-updater 2022-08-27 11:22:55 +01:00
Auxilor
e54660cf5e libreforge-updater 2022-08-24 12:52:49 +02:00
Auxilor
7a21d1897d libreforge-updater 2022-08-24 12:50:14 +02:00
Auxilor
64726f665f libreforge-updater 2022-08-24 11:57:32 +02:00
Auxilor
e4fdaeec1d libreforge-updater 2022-08-23 11:07:42 +02:00
Auxilor
3c5fbd6151 libreforge-updater 2022-08-22 12:46:27 +02:00
Auxilor
4329431994 libreforge-updater 2022-08-20 10:00:02 +02:00
Auxilor
c55692e89f libreforge-updater 2022-08-17 14:21:54 +02:00
Auxilor
03466f7892 libreforge-updater 2022-08-17 12:09:45 +02:00
Auxilor
1a6ebd4455 libreforge-updater 2022-08-16 18:45:53 +02:00
Auxilor
486f071dea libreforge-updater 2022-08-14 17:30:33 +02:00
Auxilor
fb4eac5e5e Updated to 8.67.1 2022-08-13 12:12:27 +02:00
Will FP
49d1d3f054 Merge pull request #47 from grzybeek/chunkticker
small chunkticker code cleanup
2022-08-13 12:00:09 +02:00
Auxilor
6dc7426146 libreforge-updater 2022-08-13 11:58:15 +02:00
Auxilor
00c5ead347 libreforge-updater 2022-08-05 18:41:40 +01:00
Auxilor
9bd501dfbe libreforge-updater 2022-08-05 18:39:49 +01:00
Auxilor
67d55bbdc2 libreforge-updater 2022-08-04 13:03:36 +01:00
Auxilor
46aa086366 lang 2022-08-04 12:38:01 +01:00
Auxilor
9f00334ea4 lang 2022-08-04 12:31:24 +01:00
Auxilor
e6db159bfb libreforge-updater 2022-08-04 12:26:42 +01:00
Auxilor
3df7b75737 libreforge-updater 2022-08-04 12:24:14 +01:00
Auxilor
c243a425b3 libreforge-updater 2022-08-02 16:26:52 +01:00
Auxilor
e57fe61d22 libreforge-updater 2022-08-02 16:21:24 +01:00
Auxilor
9830aed484 libreforge-updater 2022-08-02 16:16:46 +01:00
Auxilor
999b89bcb0 libreforge-updater 2022-08-01 11:19:06 +01:00
Auxilor
e7f326efbb libreforge-updater 2022-07-29 17:50:41 +01:00
Auxilor
0cb5b0b7b7 libreforge-updater 2022-07-27 20:17:09 +01:00
Auxilor
8e2d901e9b Updated to 8.63.2 2022-07-26 14:41:50 +01:00
Auxilor
724eede36e Fixed boss death tracking 2022-07-26 14:41:22 +01:00
Auxilor
01a2cc7118 libreforge-updater 2022-07-25 17:53:55 +01:00
Auxilor
20aace3727 libreforge-updater 2022-07-25 17:02:32 +01:00
Auxilor
ec9d4c0dd6 libreforge-updater 2022-07-24 22:49:25 +01:00
Auxilor
b3a0c1fa67 libreforge-updater 2022-07-24 21:50:54 +01:00
Auxilor
88294a17cd libreforge-updater 2022-07-23 17:42:53 +01:00
Auxilor
1ac6a350ec libreforge-updater 2022-07-22 14:20:45 +01:00
Auxilor
a9333cb8b5 libreforge-updater 2022-07-21 20:14:10 +01:00
grzybeek
05cf399e77 remove useless mob getter 2022-07-21 17:07:37 +02:00
grzybeek
de2b8f7526 small chunkticker code cleanup 2022-07-21 17:02:42 +02:00
Auxilor
23085e74e2 Codestyle 2022-07-21 15:48:46 +01:00
Auxilor
80f02a07a4 Updated to 8.60.1 2022-07-21 15:48:22 +01:00
Will FP
a63625593d Merge pull request #45 from grzybeek/chunkticker
Fix spawning bosses on unloaded chunks
2022-07-21 15:26:05 +01:00
Auxilor
1dfd7bac1f libreforge-updater 2022-07-20 00:10:12 +01:00
Auxilor
34b983b185 libreforge-updater 2022-07-13 21:22:38 +01:00
Auxilor
33b2fd9e13 libreforge-updater 2022-07-12 14:58:43 +01:00
Auxilor
85cfb542dc libreforge-updater 2022-07-11 16:16:12 +01:00
Auxilor
197f9e91aa libreforge-updater 2022-07-09 12:10:35 +01:00
grzybeek
9d4a91805a Fix spawning bosses on unloaded chunks, keep them loaded and remove afterwards
Entity is no longer null, change not needed "?: return"
2022-07-06 02:06:46 +02:00
Auxilor
87b91c46d1 libreforge-updater 2022-07-05 18:32:14 +01:00
Auxilor
4a7e6e9ff1 libreforge-updater 2022-07-04 18:45:14 +01:00
Auxilor
b59e54be01 libreforge-updater 2022-06-30 22:54:36 +01:00
Auxilor
d26f0294cc libreforge-updater 2022-06-30 22:34:13 +01:00
Auxilor
150433d46b libreforge-updater 2022-06-26 13:03:03 +01:00
Auxilor
7de4d75c93 libreforge-updater 2022-06-25 22:22:48 +01:00
Auxilor
9790459a26 libreforge-updater 2022-06-24 13:57:52 +01:00
Auxilor
666a80b401 libreforge-updater 2022-06-22 22:24:46 +01:00
Auxilor
59810059aa libreforge-updater 2022-06-22 12:42:49 +01:00
Auxilor
7b604c7812 libreforge-updater 2022-06-21 08:29:23 +01:00
Auxilor
81eab18e42 libreforge-updater 2022-06-20 21:37:23 +01:00
58 changed files with 1261 additions and 791 deletions

View File

@@ -1,8 +1,5 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: Auxilor Community Discord - name: Discord
url: https://discord.gg/ZcwpSsE/ url: https://discord.gg/ZcwpSsE/
about: Join the Auxilor discord to get help from support staff and the general community! about: Issues have moved to Discord, please join the server to get help!
- name: The most common issues people have
url: https://github.com/Auxilor/eco/issues/78
about: Check the list of known common issues to see if your issue has already been solved

View File

@@ -4,28 +4,8 @@ about: Report an issue with the plugin
title: '' title: ''
labels: bug labels: bug
assignees: '' assignees: ''
--- ---
**Describe the bug** # Please report bugs on the discord!
A clear and concise description of what the bug is.
**To Reproduce** [Join by clicking here](https://discord.gg/ZcwpSsE/)
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Server Information (please complete the following information):**
- Version: (output of `/ver` command)
- Version of plugin and eco (`/ver eco`, `/ver <plugin>`)
**Additional context**
Add any other context about the problem here.

View File

@@ -1,20 +0,0 @@
---
name: Request a Feature
about: Suggest an idea for this plugin
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

33
.github/workflows/publish-release.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Publish Packages
on:
workflow_dispatch:
release:
types: [ created ]
push:
tags:
- '*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 17
- name: Change wrapper permissions
run: chmod +x ./gradlew
- name: Publish package
uses: gradle/gradle-build-action@v2
with:
arguments: publish
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}

View File

@@ -1,135 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
}
}
plugins {
id 'java-library'
id 'com.github.johnrengelman.shadow' version '7.0.0'
id 'maven-publish'
id 'java'
}
dependencies {
implementation project(":eco-core").getSubprojects()
}
allprojects {
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'maven-publish'
apply plugin: 'com.github.johnrengelman.shadow'
repositories {
mavenCentral()
mavenLocal()
maven { url 'https://jitpack.io' }
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
maven { url 'https://repo.codemc.org/repository/nms/' }
maven { url 'https://repo.codemc.org/repository/maven-public' }
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url 'https://oss.sonatype.org/content/groups/public/' }
maven { url 'https://maven.enginehub.org/repo/' }
maven { url 'https://ci.ender.zone/plugin/repository/project/' }
maven { url 'https://ci.ender.zone/plugin/repository/everything/' }
maven { url 'https://repo.md-5.net/content/repositories/snapshots/' }
maven { url 'https://repo.dmulloy2.net/nexus/repository/public/' }
maven { url 'https://papermc.io/repo/repository/maven-public/' }
maven { url 'https://repo.maven.apache.org/maven2/' }
maven { url 'https://repo.dustplanet.de/artifactory/ext-release-local/' }
maven { url 'https://maven.seyfahni.de/repository/snapshots/' }
maven { url 'https://libraries.minecraft.net/' }
maven { url 'https://repo.spongepowered.org/maven/' }
maven { url 'https://org.kitteh.pastegg' }
maven { url 'https://repo.mikeprimm.com/' }
maven { url 'https://maven.sk89q.com/repo/' }
maven { url 'https://github.com/factions-site/repo/raw/public/' }
maven { url 'https://repo.extendedclip.com/content/repositories/placeholderapi/' }
}
jar {
onlyIf { !sourceSets.main.allSource.files.isEmpty() }
}
shadowJar {
relocate('com.willfp.libreforge', 'com.willfp.ecobosses.libreforge')
relocate('org.joml', 'com.willfp.ecobosses.libreforge.joml')
}
dependencies {
compileOnly 'com.willfp:eco:6.35.1'
implementation 'com.willfp:libreforge:3.66.0'
implementation 'org.joml:joml:1.10.4'
compileOnly 'org.jetbrains:annotations:23.0.0'
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.6.21'
}
tasks.withType(JavaCompile) {
options.deprecation = true
options.encoding = 'UTF-8'
}
processResources {
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**", "**lang.yml"]) {
expand projectVersion: project.version
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
kotlinOptions {
jvmTarget = "17"
}
}
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17
compileJava.options.encoding = 'UTF-8'
compileJava.dependsOn clean
build.dependsOn shadowJar
}
tasks.withType(Jar) {
destinationDirectory = file("$rootDir/bin/")
}
clean.doLast {
file("${rootDir}/bin").deleteDir()
}
shadowJar {
archiveFileName = findProperty("plugin-name") + " v" + findProperty("version") + ".jar"
}
jar {
archiveFileName = findProperty("plugin-name") + " v" + findProperty("version") + " " + "unshaded" + ".jar"
}
group = 'com.willfp'
archivesBaseName = project.name
version = findProperty("version")
compileJava.options.encoding = 'UTF-8'
build.dependsOn shadowJar
build.dependsOn publishToMavenLocal
task buyThePlugins {
dependsOn subprojects.build
doLast {
println 'If you like the plugin, please consider buying it on Spigot or Polymart!'
println 'Spigot: https://www.spigotmc.org/resources/authors/auxilor.507394/'
println 'Polymart: https://polymart.org/user/auxilor.1107/'
println 'Buying gives you access to support and the plugin auto-updater, and it allows me to keep developing plugins.'
}
}
build.finalizedBy buyThePlugins

83
build.gradle.kts Normal file
View File

@@ -0,0 +1,83 @@
plugins {
java
`java-library`
`maven-publish`
kotlin("jvm") version "1.7.10"
id("com.github.johnrengelman.shadow") version "8.0.0"
id("com.willfp.libreforge-gradle-plugin") version "1.0.0"
}
group = "com.willfp"
version = findProperty("version")!!
val libreforgeVersion = findProperty("libreforge-version")
base {
archivesName.set(project.name)
}
dependencies {
project(":eco-core").dependencyProject.subprojects {
implementation(this)
}
}
allprojects {
apply(plugin = "java")
apply(plugin = "kotlin")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
repositories {
mavenLocal()
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.auxilor.io/repository/maven-public/")
maven("https://jitpack.io")
maven("https://mvn.lumine.io/repository/maven-public/")
}
dependencies {
compileOnly("com.willfp:eco:6.53.0")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.7.10")
}
java {
withSourcesJar()
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
tasks {
shadowJar {
relocate("com.willfp.libreforge.loader", "com.willfp.ecobosses.libreforge.loader")
}
compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
}
compileJava {
options.isDeprecation = true
options.encoding = "UTF-8"
dependsOn(clean)
}
processResources {
filesMatching(listOf("**plugin.yml", "**eco.yml")) {
expand(
"version" to project.version,
"libreforgeVersion" to libreforgeVersion,
"pluginName" to rootProject.name
)
}
}
build {
dependsOn(shadowJar)
}
}
}

View File

@@ -1,2 +0,0 @@
group 'com.willfp'
version rootProject.version

View File

@@ -0,0 +1,2 @@
group = "com.willfp"
version = rootProject.version

View File

@@ -1,8 +0,0 @@
group 'com.willfp'
version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'com.github.lokka30:LevelledMobs:3.1.4'
compileOnly 'net.kyori:adventure-api:4.9.3'
}

View File

@@ -0,0 +1,34 @@
group = "com.willfp"
version = rootProject.version
dependencies {
compileOnly("io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT")
compileOnly("com.github.lokka30:LevelledMobs:3.1.4")
compileOnly("com.ticxo.modelengine:api:R3.1.6")
}
publishing {
publications {
register("maven", MavenPublication::class) {
from(components["java"])
artifactId = rootProject.name
}
}
repositories {
maven {
name = "auxilor"
url = uri("https://repo.auxilor.io/repository/maven-releases/")
credentials {
username = System.getenv("MAVEN_USERNAME")
password = System.getenv("MAVEN_PASSWORD")
}
}
}
}
tasks {
build {
dependsOn(publishToMavenLocal)
}
}

View File

@@ -6,13 +6,15 @@ import com.willfp.eco.core.integrations.IntegrationLoader
import com.willfp.ecobosses.bosses.Bosses import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.bosses.EggDisplay import com.willfp.ecobosses.bosses.EggDisplay
import com.willfp.ecobosses.bosses.bossHolders import com.willfp.ecobosses.bosses.bossHolders
import com.willfp.ecobosses.commands.CommandEcobosses import com.willfp.ecobosses.commands.CommandEcoBosses
import com.willfp.ecobosses.config.EcoBossesYml
import com.willfp.ecobosses.defence.DamageMultiplierHandler import com.willfp.ecobosses.defence.DamageMultiplierHandler
import com.willfp.ecobosses.defence.ImmunitiesHandler import com.willfp.ecobosses.defence.ImmunitiesHandler
import com.willfp.ecobosses.defence.MountHandler import com.willfp.ecobosses.defence.MountHandler
import com.willfp.ecobosses.defence.PickupHandler import com.willfp.ecobosses.defence.PickupHandler
import com.willfp.ecobosses.integrations.levelledmobs.IntegrationLevelledMobs import com.willfp.ecobosses.integrations.levelledmobs.IntegrationLevelledMobs
import com.willfp.ecobosses.libreforge.EffectBossDropChanceMultiplier
import com.willfp.ecobosses.libreforge.TriggerKillBoss
import com.willfp.ecobosses.libreforge.TriggerSpawnBoss
import com.willfp.ecobosses.lifecycle.CompatibilityListeners import com.willfp.ecobosses.lifecycle.CompatibilityListeners
import com.willfp.ecobosses.lifecycle.ConsoleLoggers import com.willfp.ecobosses.lifecycle.ConsoleLoggers
import com.willfp.ecobosses.lifecycle.DeathListeners import com.willfp.ecobosses.lifecycle.DeathListeners
@@ -22,27 +24,39 @@ import com.willfp.ecobosses.spawn.SpawnEggHandler
import com.willfp.ecobosses.spawn.SpawnTotemHandler import com.willfp.ecobosses.spawn.SpawnTotemHandler
import com.willfp.ecobosses.util.DiscoverRecipeListener import com.willfp.ecobosses.util.DiscoverRecipeListener
import com.willfp.ecobosses.util.TopDamagerListener import com.willfp.ecobosses.util.TopDamagerListener
import com.willfp.libreforge.LibReforgePlugin import com.willfp.libreforge.effects.Effects
import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory
import com.willfp.libreforge.registerHolderProvider
import com.willfp.libreforge.triggers.Triggers
import org.bukkit.event.Listener import org.bukkit.event.Listener
class EcoBossesPlugin : LibReforgePlugin() { class EcoBossesPlugin : LibreforgePlugin() {
val ecoBossesYml: EcoBossesYml
init { init {
instance = this instance = this
ecoBossesYml = EcoBossesYml(this) }
override fun loadConfigCategories(): List<ConfigCategory> {
return listOf(
Bosses
)
}
override fun handleEnable() {
Effects.register(EffectBossDropChanceMultiplier)
Triggers.register(TriggerKillBoss)
Triggers.register(TriggerSpawnBoss)
registerHolderProvider { it.bossHolders } registerHolderProvider { it.bossHolders }
} }
override fun handleReloadAdditional() { override fun handleReload() {
Bosses.getAllAlive().forEach { it.remove() } Bosses.getAllAlive().forEach { it.remove() }
logger.info(Bosses.values().size.toString() + " Bosses Loaded")
AutospawnHandler.startSpawning(this) AutospawnHandler.startSpawning(this)
} }
override fun handleDisableAdditional() { override fun handleDisable() {
Bosses.getAllAlive().forEach { it.remove() } Bosses.getAllAlive().forEach { it.remove() }
} }
@@ -52,7 +66,7 @@ class EcoBossesPlugin : LibReforgePlugin() {
override fun loadPluginCommands(): List<PluginCommand> { override fun loadPluginCommands(): List<PluginCommand> {
return listOf( return listOf(
CommandEcobosses(this) CommandEcoBosses(this)
) )
} }
@@ -61,7 +75,7 @@ class EcoBossesPlugin : LibReforgePlugin() {
DiscoverRecipeListener(this), DiscoverRecipeListener(this),
TopDamagerListener(), TopDamagerListener(),
LifecycleHandlers(), LifecycleHandlers(),
SpawnEggHandler(), SpawnEggHandler(this),
DamageMultiplierHandler(), DamageMultiplierHandler(),
MountHandler(), MountHandler(),
PickupHandler(), PickupHandler(),
@@ -73,16 +87,12 @@ class EcoBossesPlugin : LibReforgePlugin() {
) )
} }
override fun loadAdditionalIntegrations(): List<IntegrationLoader> { override fun loadIntegrationLoaders(): List<IntegrationLoader> {
return listOf( return listOf(
IntegrationLoader("LevelledMobs") { this.eventManager.registerListener(IntegrationLevelledMobs()) } IntegrationLoader("LevelledMobs") { this.eventManager.registerListener(IntegrationLevelledMobs()) }
) )
} }
override fun getMinimumEcoVersion(): String {
return "6.35.1"
}
companion object { companion object {
@JvmStatic @JvmStatic
lateinit var instance: EcoBossesPlugin lateinit var instance: EcoBossesPlugin

View File

@@ -2,26 +2,26 @@ package com.willfp.ecobosses.bosses
import com.willfp.eco.core.fast.fast import com.willfp.eco.core.fast.fast
import com.willfp.ecobosses.EcoBossesPlugin import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.libreforge.Holder import com.willfp.ecobosses.util.EntityProvidedHolder
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import kotlin.math.pow import kotlin.math.pow
val Player.bossHolders: Iterable<Holder> val Player.bossHolders: Collection<EntityProvidedHolder>
get() { get() {
val holders = mutableListOf<Holder>() val holders = mutableListOf<EntityProvidedHolder>()
for (boss in Bosses.values()) { for (boss in Bosses.values()) {
for (livingBoss in boss.getAllAlive()) { for (livingBoss in boss.getAllAlive()) {
val entity = livingBoss.entity ?: continue val entity = livingBoss.entity
if (entity.world != this.world) { if (entity.world != this.world) {
continue continue
} }
if (entity.location.distanceSquared(this.location) <= boss.influence.pow(2)) { if (entity.location.distanceSquared(this.location) <= boss.influence.pow(2)) {
holders.add(boss) holders.add(EntityProvidedHolder(boss, entity))
} }
} }
} }
@@ -38,7 +38,7 @@ var ItemStack.bossEgg: EcoBoss?
if (value == null) { if (value == null) {
pdc.remove(spawnEggKey) pdc.remove(spawnEggKey)
} else { } else {
pdc.set(spawnEggKey, PersistentDataType.STRING, value.id) pdc.set(spawnEggKey, PersistentDataType.STRING, value.id.key)
} }
this.itemMeta = meta this.itemMeta = meta
} }

View File

@@ -1,19 +1,29 @@
package com.willfp.ecobosses.bosses package com.willfp.ecobosses.bosses
import com.google.common.collect.BiMap
import com.google.common.collect.HashBiMap
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.readConfig
import com.willfp.eco.core.config.updating.ConfigUpdater import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.eco.core.registry.Registry
import com.willfp.ecobosses.EcoBossesPlugin import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.libreforge.chains.EffectChains import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory
import com.willfp.libreforge.loader.configs.LegacyLocation
import com.willfp.libreforge.separatorAmbivalent
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import java.io.File
import java.util.UUID import java.util.UUID
object Bosses { object Bosses : ConfigCategory("boss", "bosses") {
/** /** Registered bosses. */
* Registered bosses. private val registry = Registry<EcoBoss>()
*/
private val BY_ID: BiMap<String, EcoBoss> = HashBiMap.create() override val legacyLocation = LegacyLocation(
"ecobosses.yml",
"bosses"
)
/** /**
* Get all registered [EcoBoss]s. * Get all registered [EcoBoss]s.
@@ -22,7 +32,7 @@ object Bosses {
*/ */
@JvmStatic @JvmStatic
fun values(): List<EcoBoss> { fun values(): List<EcoBoss> {
return ImmutableList.copyOf(BY_ID.values) return ImmutableList.copyOf(registry.values())
} }
/** /**
@@ -33,49 +43,15 @@ object Bosses {
*/ */
@JvmStatic @JvmStatic
fun getByID(name: String): EcoBoss? { fun getByID(name: String): EcoBoss? {
return BY_ID[name] return registry[name]
} }
/** override fun clear(plugin: LibreforgePlugin) {
* Update all [EcoBoss]s. registry.clear()
*
* @param plugin Instance of EcoBosses.
*/
@ConfigUpdater
@JvmStatic
fun update(plugin: EcoBossesPlugin) {
plugin.ecoBossesYml.getSubsections("chains").mapNotNull {
EffectChains.compile(it, "Effect Chains")
}
for (boss in values()) {
removeBoss(boss)
}
for (bossConfig in plugin.ecoBossesYml.getSubsections("bosses")) {
addNewBoss(EcoBoss(bossConfig, plugin))
}
} }
/** override fun acceptConfig(plugin: LibreforgePlugin, id: String, config: Config) {
* Add new [EcoBoss] to EcoBosses. registry.register(EcoBoss(id, config, plugin as EcoBossesPlugin))
*
* @param set The [EcoBoss] to add.
*/
@JvmStatic
fun addNewBoss(set: EcoBoss) {
BY_ID.remove(set.id)
BY_ID[set.id] = set
}
/**
* Remove [EcoBoss] from EcoBosses.
*
* @param set The [EcoBoss] to remove.
*/
@JvmStatic
fun removeBoss(set: EcoBoss) {
BY_ID.remove(set.id)
} }
/** /**
@@ -119,4 +95,14 @@ object Bosses {
operator fun get(entity: LivingEntity): LivingEcoBoss? { operator fun get(entity: LivingEntity): LivingEcoBoss? {
return get(entity.uniqueId) return get(entity.uniqueId)
} }
/** If an entity is a boss. */
val Entity?.isBoss: Boolean
get() {
if (this !is LivingEntity) {
return false
}
return Bosses[this] != null
}
} }

View File

@@ -1,24 +1,45 @@
package com.willfp.ecobosses.bosses package com.willfp.ecobosses.bosses
import com.ticxo.modelengine.api.ModelEngineAPI
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.interfaces.Config import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.entities.CustomEntity import com.willfp.eco.core.entities.CustomEntity
import com.willfp.eco.core.entities.Entities import com.willfp.eco.core.entities.Entities
import com.willfp.eco.core.entities.TestableEntity import com.willfp.eco.core.entities.TestableEntity
import com.willfp.eco.core.entities.ai.* import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.core.entities.ai.EntityGoal
import com.willfp.eco.core.entities.ai.EntityGoals
import com.willfp.eco.core.entities.ai.TargetGoal
import com.willfp.eco.core.entities.ai.TargetGoals
import com.willfp.eco.core.items.CustomItem import com.willfp.eco.core.items.CustomItem
import com.willfp.eco.core.items.Items import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.recipe.Recipes import com.willfp.eco.core.recipe.Recipes
import com.willfp.eco.core.recipe.parts.EmptyTestableItem import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.core.recipe.recipes.CraftingRecipe import com.willfp.eco.core.recipe.recipes.CraftingRecipe
import com.willfp.eco.core.registry.Registrable
import com.willfp.eco.util.NamespacedKeyUtils import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.toComponent import com.willfp.eco.util.toComponent
import com.willfp.ecobosses.events.BossKillEvent import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.lifecycle.BossLifecycle import com.willfp.ecobosses.lifecycle.BossLifecycle
import com.willfp.ecobosses.tick.* import com.willfp.ecobosses.tick.BossBarTicker
import com.willfp.ecobosses.util.* import com.willfp.ecobosses.tick.BossTicker
import com.willfp.ecobosses.tick.ChunkTicker
import com.willfp.ecobosses.tick.DisplayNameTicker
import com.willfp.ecobosses.tick.LifespanTicker
import com.willfp.ecobosses.tick.TargetTicker
import com.willfp.ecobosses.tick.TeleportHandler
import com.willfp.ecobosses.util.BossDrop
import com.willfp.ecobosses.util.CommandReward
import com.willfp.ecobosses.util.ConfiguredSound
import com.willfp.ecobosses.util.LocalBroadcast
import com.willfp.ecobosses.util.LocalCommands
import com.willfp.ecobosses.util.PlayableSound
import com.willfp.ecobosses.util.SpawnTotem
import com.willfp.ecobosses.util.XpReward
import com.willfp.ecobosses.util.topDamagers
import com.willfp.libreforge.Holder import com.willfp.libreforge.Holder
import com.willfp.libreforge.ViolationContext
import com.willfp.libreforge.conditions.Conditions import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.effects.Effects import com.willfp.libreforge.effects.Effects
import net.kyori.adventure.bossbar.BossBar import net.kyori.adventure.bossbar.BossBar
@@ -30,15 +51,17 @@ import org.bukkit.entity.Mob
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import java.util.* import java.util.Objects
import java.util.UUID
class EcoBoss( class EcoBoss(
id: String,
val config: Config, val config: Config,
private val plugin: EcoPlugin private val plugin: EcoPlugin
) : Holder { ) : Holder, Registrable {
override val id: String = config.getString("id") override val id = plugin.createNamespacedKey(id)
val displayName: String = config.getString("displayName") val displayName: String = config.getString("display-name")
val lifespan = config.getInt("lifespan") val lifespan = config.getInt("lifespan")
@@ -48,23 +71,23 @@ class EcoBoss(
val targetMode = TargetMode.getByID(config.getString("target.mode"))!! val targetMode = TargetMode.getByID(config.getString("target.mode"))!!
val isBossBarEnabled = config.getBool("bossBar.enabled") val isBossBarEnabled = config.getBool("boss-bar.enabled")
val bossBarRadius = config.getDouble("bossBar.radius") val bossBarRadius = config.getDouble("boss-bar.radius")
val isPreventingMounts = config.getBool("defence.preventMounts") val isPreventingMounts = config.getBool("defence.prevent-mounts")
val isImmuneToExplosions = config.getBool("defence.explosionImmune") val isImmuneToExplosions = config.getBool("defence.explosion-immune")
val isImmuneToFire = config.getBool("defence.fireImmune") val isImmuneToFire = config.getBool("defence.fire-immune")
val isImmuneToDrowning = config.getBool("defence.drowningImmune") val isImmuneToDrowning = config.getBool("defence.drowning-immune")
val isImmuneToSuffocation = config.getBool("defence.suffocationImmune") val isImmuneToSuffocation = config.getBool("defence.suffocation-immune")
val meleeDamageMultiplier = config.getDouble("defence.meleeDamageMultiplier") val meleeDamageMultiplier = config.getDouble("defence.melee-damage-multiplier")
val projectileDamageMultiplier = config.getDouble("defence.projectileDamageMultiplier") val projectileDamageMultiplier = config.getDouble("defence.projectile-damage-multiplier")
val canTeleport = config.getBool("defence.teleportation.enabled") val canTeleport = config.getBool("defence.teleportation.enabled")
@@ -119,7 +142,7 @@ class EcoBoss(
val recipe = Recipes.createAndRegisterRecipe( val recipe = Recipes.createAndRegisterRecipe(
this@EcoBoss.plugin, this@EcoBoss.plugin,
"${this.id}_spawn_egg", "${this.id.key}_spawn_egg",
spawnEggBacker, spawnEggBacker,
config.getStrings("spawn.egg.recipe") config.getStrings("spawn.egg.recipe")
) )
@@ -139,7 +162,7 @@ class EcoBoss(
) )
} }
val disabledTotemWorlds: List<String> = config.getStrings("spawn.totem.notInWorlds") val disabledTotemWorlds: List<String> = config.getStrings("spawn.totem.not-in-worlds")
val autoSpawnInterval = config.getInt("spawn.autospawn.interval") val autoSpawnInterval = config.getInt("spawn.autospawn.interval")
@@ -151,47 +174,46 @@ class EcoBoss(
val x = config.getDouble("x") val x = config.getDouble("x")
val y = config.getDouble("y") val y = config.getDouble("y")
val z = config.getDouble("z") val z = config.getDouble("z")
locations.add( locations.add(Location(world, x, y, z))
Location(
world, x, y, z
)
)
} }
locations locations
} }
val hasCustomAI = config.getBool("customai.enabled") val hasCustomAI = config.getBool("custom-ai.enabled")
val targetGoals = config.getSubsections("customai.target-goals").mapNotNull { val targetGoals = config.getSubsections("custom-ai.target-goals").mapNotNull {
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
val deserializer = TargetGoals.getByKey(key) ?: return@mapNotNull null val deserializer = TargetGoals.getByKey(key) ?: return@mapNotNull null
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
ConfiguredGoal(it.getInt("priority"), goal) ConfiguredGoal(it.getInt("priority"), goal)
} }
val entityGoals = config.getSubsections("customai.ai-goals").mapNotNull { val entityGoals = config.getSubsections("custom-ai.ai-goals").mapNotNull {
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
val deserializer = EntityGoals.getByKey(key) ?: return@mapNotNull null val deserializer = EntityGoals.getByKey(key) ?: return@mapNotNull null
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
ConfiguredGoal(it.getInt("priority"), goal) ConfiguredGoal(it.getInt("priority"), goal)
} }
val spawnConditions = config.getSubsections("spawn.conditions").mapNotNull { val spawnConditions = Conditions.compile(
Conditions.compile(it, "$id Spawn Conditions") config.getSubsections("spawn.conditions"),
} ViolationContext(plugin, "$id Spawn Conditions")
)
private val bossBarColor = BossBar.Color.valueOf(config.getString("bossBar.color").uppercase()) private val bossBarColor = BossBar.Color.valueOf(config.getString("boss-bar.color").uppercase())
private val bossBarStyle = BossBar.Overlay.valueOf(config.getString("bossBar.style").uppercase()) private val bossBarStyle = BossBar.Overlay.valueOf(config.getString("boss-bar.style").uppercase())
private val sounds: Map<BossLifecycle, PlayableSound> = run { private val sounds: Map<BossLifecycle, PlayableSound> = run {
val map = mutableMapOf<BossLifecycle, PlayableSound>() val map = mutableMapOf<BossLifecycle, PlayableSound>()
for (value in BossLifecycle.values()) { for (value in BossLifecycle.values()) {
map[value] = PlayableSound(config.getSubsections("sounds.${value.name.lowercase()}").map { map[value] = PlayableSound(
ConfiguredSound.fromConfig(it) config.getSubsections("sounds.${value.name.lowercase()}").map {
}) ConfiguredSound.fromConfig(it)
}
)
} }
map map
@@ -222,10 +244,10 @@ class EcoBoss(
private val commandRewards: Map<Int, Iterable<CommandReward>> = run { private val commandRewards: Map<Int, Iterable<CommandReward>> = run {
val map = mutableMapOf<Int, Iterable<CommandReward>>() val map = mutableMapOf<Int, Iterable<CommandReward>>()
for (rank in config.getSubsection("rewards.topDamagerCommands").getKeys(false)) { for (rank in config.getSubsection("rewards.top-damager-commands").getKeys(false)) {
val rankRewards = mutableListOf<CommandReward>() val rankRewards = mutableListOf<CommandReward>()
for (config in config.getSubsections("rewards.topDamagerCommands.$rank")) { for (config in config.getSubsections("rewards.top-damager-commands.$rank")) {
rankRewards.add( rankRewards.add(
CommandReward( CommandReward(
config.getDouble("chance"), config.getDouble("chance"),
@@ -240,12 +262,12 @@ class EcoBoss(
map map
} }
private val nearbyCommandRewardRadius = config.getDouble("rewards.nearbyPlayerCommands.radius") private val nearbyCommandRewardRadius = config.getDouble("rewards.nearby-player-commands.radius")
private val nearbyCommands: Iterable<CommandReward> = run { private val nearbyCommands: Iterable<CommandReward> = run {
val list = mutableListOf<CommandReward>() val list = mutableListOf<CommandReward>()
for (config in config.getSubsections("rewards.nearbyPlayerCommands.commands")) { for (config in config.getSubsections("rewards.nearby-player-commands.commands")) {
list.add( list.add(
CommandReward( CommandReward(
config.getDouble("chance"), config.getDouble("chance"),
@@ -262,7 +284,6 @@ class EcoBoss(
config.getInt("rewards.xp.maximum") config.getInt("rewards.xp.maximum")
) )
private val drops: Iterable<BossDrop> = run { private val drops: Iterable<BossDrop> = run {
val list = mutableListOf<BossDrop>() val list = mutableListOf<BossDrop>()
@@ -283,15 +304,21 @@ class EcoBoss(
private val mob: TestableEntity = Entities.lookup(config.getString("mob")) private val mob: TestableEntity = Entities.lookup(config.getString("mob"))
private val modelEngineID = config.getStringOrNull("model-engine-id")
private val modelEngineAnimation = config.getStringOrNull("model-engine-animation")
private val currentlyAlive = mutableMapOf<UUID, LivingEcoBoss>() private val currentlyAlive = mutableMapOf<UUID, LivingEcoBoss>()
override val conditions = config.getSubsections("conditions").mapNotNull { override val conditions = Conditions.compile(
Conditions.compile(it, "Boss ID $id") config.getSubsections("conditions"),
}.toSet() ViolationContext(plugin, "Boss ID $id")
)
override val effects = config.getSubsections("effects").mapNotNull { override val effects = Effects.compile(
Effects.compile(it, "Boss ID $id") config.getSubsections("effects"),
}.toSet() ViolationContext(plugin, "Boss ID $id")
)
fun markDead(uuid: UUID) { fun markDead(uuid: UUID) {
currentlyAlive.remove(uuid) currentlyAlive.remove(uuid)
@@ -317,12 +344,11 @@ class EcoBoss(
mob.persistentDataContainer.set( mob.persistentDataContainer.set(
plugin.namespacedKeyFactory.create("boss"), plugin.namespacedKeyFactory.create("boss"),
PersistentDataType.STRING, PersistentDataType.STRING,
this.id this.id.key
) )
if (hasCustomAI) { if (hasCustomAI) {
val controller = EntityController.getFor(mob) val controller = EntityController.getFor(mob).clearAllGoals()
.clearAllGoals()
@Suppress("UNCHECKED_CAST") // What could go wrong? @Suppress("UNCHECKED_CAST") // What could go wrong?
targetGoals.forEach { controller.addTargetGoal(it.priority, it.goal as TargetGoal<in Mob>) } targetGoals.forEach { controller.addTargetGoal(it.priority, it.goal as TargetGoal<in Mob>) }
@@ -330,9 +356,38 @@ class EcoBoss(
entityGoals.forEach { controller.addEntityGoal(it.priority, it.goal as EntityGoal<in Mob>) } entityGoals.forEach { controller.addEntityGoal(it.priority, it.goal as EntityGoal<in Mob>) }
} }
if (modelEngineID != null && Bukkit.getPluginManager().isPluginEnabled("ModelEngine")) {
val model = ModelEngineAPI.createActiveModel(modelEngineID)
if (model == null) {
plugin.logger.warning("Invalid Model Engine ID for boss $id")
}
if (modelEngineAnimation != null) {
val animationHandler = model.animationHandler
val animationProperty = animationHandler.getAnimation(modelEngineAnimation)
if (animationProperty != null) {
animationHandler.playAnimation(animationProperty, true)
} else {
plugin.logger.warning("Animation $modelEngineAnimation not found in model $modelEngineID, defaulting to walk!")
val animationPropertyWalk = animationHandler.getAnimation("walk")
if (animationPropertyWalk != null) {
animationHandler.playAnimation(animationPropertyWalk, true)
} else {
plugin.logger.warning("Walk animation not found in $modelEngineID!")
}
}
}
val modelled = ModelEngineAPI.createModeledEntity(mob)
modelled.addModel(model, true)
modelled.isBaseEntityVisible = false
}
val boss = LivingEcoBoss( val boss = LivingEcoBoss(
plugin, plugin,
mob.uniqueId, mob,
this, this,
createTickers() createTickers()
) )
@@ -345,7 +400,8 @@ class EcoBoss(
LifespanTicker(), LifespanTicker(),
DisplayNameTicker(), DisplayNameTicker(),
TargetTicker(), TargetTicker(),
TeleportHandler() TeleportHandler(),
ChunkTicker()
) )
if (isBossBarEnabled) { if (isBossBarEnabled) {
@@ -371,7 +427,7 @@ class EcoBoss(
} }
fun processRewards(event: BossKillEvent) { fun processRewards(event: BossKillEvent) {
val entity = event.boss.entity ?: return val entity = event.boss.entity
val location = entity.location val location = entity.location
val player = event.killer val player = event.killer
@@ -419,6 +475,9 @@ class EcoBoss(
) )
} }
override fun getID(): String {
return this.id.key
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (other !is EcoBoss) { if (other !is EcoBoss) {
@@ -433,8 +492,10 @@ class EcoBoss(
} }
override fun toString(): String { override fun toString(): String {
return ("EcoBoss{" return (
+ id "EcoBoss{" +
+ "}") id +
"}"
)
} }
} }

View File

@@ -5,6 +5,7 @@ import com.willfp.eco.core.display.Display
import com.willfp.eco.core.display.DisplayModule import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.display.DisplayPriority import com.willfp.eco.core.display.DisplayPriority
import com.willfp.eco.core.fast.fast import com.willfp.eco.core.fast.fast
import com.willfp.libreforge.SimpleProvidedHolder
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
@@ -26,8 +27,8 @@ class EggDisplay(
val egg = itemStack.bossEgg ?: return val egg = itemStack.bossEgg ?: return
val lines = egg.spawnConditions val lines = egg.spawnConditions
.filterNot { it.isMet(player) } .filterNot { it.isMet(player, SimpleProvidedHolder(egg)) }
.mapNotNull { it.notMetLines?.map { line -> Display.PREFIX + line } } .map { it.notMetLines.map { line -> Display.PREFIX + line } }
.flatten() .flatten()

View File

@@ -2,13 +2,12 @@ package com.willfp.ecobosses.bosses
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.ecobosses.tick.BossTicker import com.willfp.ecobosses.tick.BossTicker
import org.bukkit.Bukkit import org.bukkit.Chunk
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
import java.util.UUID
class LivingEcoBoss( class LivingEcoBoss(
plugin: EcoPlugin, plugin: EcoPlugin,
private val uuid: UUID, val entity: Mob,
val boss: EcoBoss, val boss: EcoBoss,
private val tickers: Set<BossTicker> private val tickers: Set<BossTicker>
) { ) {
@@ -18,15 +17,17 @@ class LivingEcoBoss(
} }
}.apply { runTaskTimer(1, 1) } }.apply { runTaskTimer(1, 1) }
val entity: Mob? val chunk: Chunk
get() = Bukkit.getEntity(uuid) as? Mob get() = entity.location.chunk
val forceLoadedChunks = mutableListOf<Chunk>()
val deathTime = System.currentTimeMillis() + (boss.lifespan * 1000) val deathTime = System.currentTimeMillis() + (boss.lifespan * 1000)
private var currentTick = 1 // Start at 1 as 0 is divisible by everything private var currentTick = 1 // Start at 1 as 0 is divisible by everything
private fun tick(): Boolean { private fun tick(): Boolean {
if (entity == null || entity?.isDead == true) { if (entity.isDead) {
remove() remove()
return true return true
} }
@@ -40,13 +41,13 @@ class LivingEcoBoss(
fun remove() { fun remove() {
ticker.cancel() ticker.cancel()
entity?.remove() entity.remove()
tickers.forEach { it.onDeath(this, currentTick) } tickers.forEach { it.onDeath(this, currentTick) }
boss.markDead(uuid) boss.markDead(entity.uniqueId)
} }
override fun toString(): String { override fun toString(): String {
return "LivingEcoBoss{boss=${boss}, uuid=${uuid}}" return "LivingEcoBoss{boss=$boss, uuid=${entity.uniqueId}}"
} }
} }

View File

@@ -17,7 +17,7 @@ class TargetMode(
} }
fun getTarget(boss: LivingEcoBoss): LivingEntity? { fun getTarget(boss: LivingEcoBoss): LivingEntity? {
val entity = boss.entity ?: return null val entity = boss.entity
return function( return function(
entity.getNearbyEntities( entity.getNearbyEntities(

View File

@@ -4,7 +4,7 @@ import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.ecobosses.EcoBossesPlugin import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
class CommandEcobosses(plugin: EcoBossesPlugin) : PluginCommand( class CommandEcoBosses(plugin: EcoBossesPlugin) : PluginCommand(
plugin, plugin,
"ecobosses", "ecobosses",
"ecobosses.command.ecobosses", "ecobosses.command.ecobosses",

View File

@@ -47,7 +47,7 @@ class CommandGive(plugin: EcoPlugin) : Subcommand(
} }
var message = plugin.langYml.getMessage("give-success") var message = plugin.langYml.getMessage("give-success")
message = message.replace("%boss%", boss.id).replace("%recipient%", reciever.name) message = message.replace("%boss%", boss.id.key).replace("%recipient%", reciever.name)
sender.sendMessage(message) sender.sendMessage(message)
val itemStack = boss.spawnEgg!! val itemStack = boss.spawnEgg!!
@@ -94,7 +94,7 @@ class CommandGive(plugin: EcoPlugin) : Subcommand(
* The cached names. * The cached names.
*/ */
private val BOSS_NAMES: List<String> private val BOSS_NAMES: List<String>
get() = Bosses.values().map { it.id } get() = Bosses.values().map { it.id.key }
/** /**

View File

@@ -166,7 +166,7 @@ class CommandSpawn(plugin: EcoBossesPlugin) : Subcommand(
* The cached names. * The cached names.
*/ */
private val BOSS_NAMES: List<String> private val BOSS_NAMES: List<String>
get() = Bosses.values().map { it.id } get() = Bosses.values().map { it.id.key }
/** /**
* The cached numbers. * The cached numbers.

View File

@@ -1,12 +0,0 @@
package com.willfp.ecobosses.config
import com.willfp.eco.core.config.BaseConfig
import com.willfp.eco.core.config.ConfigType
import com.willfp.ecobosses.EcoBossesPlugin
class EcoBossesYml(plugin: EcoBossesPlugin) : BaseConfig(
"ecobosses",
plugin,
true,
ConfigType.YAML
)

View File

@@ -1,10 +1,8 @@
package com.willfp.ecobosses.events package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss import com.willfp.ecobosses.bosses.LivingEcoBoss
import com.willfp.ecobosses.lifecycle.BossLifecycle
import org.bukkit.event.Event import org.bukkit.event.Event
import org.bukkit.event.HandlerList import org.bukkit.event.HandlerList
import org.bukkit.event.entity.EntityDeathEvent
abstract class BossDeathEvent( abstract class BossDeathEvent(
val boss: LivingEcoBoss val boss: LivingEcoBoss

View File

@@ -1,7 +1,6 @@
package com.willfp.ecobosses.events package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss import com.willfp.ecobosses.bosses.LivingEcoBoss
import com.willfp.ecobosses.lifecycle.BossLifecycle
import org.bukkit.event.HandlerList import org.bukkit.event.HandlerList
class BossDespawnEvent( class BossDespawnEvent(

View File

@@ -1,7 +1,6 @@
package com.willfp.ecobosses.events package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.LivingEcoBoss import com.willfp.ecobosses.bosses.LivingEcoBoss
import com.willfp.ecobosses.lifecycle.BossLifecycle
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.HandlerList import org.bukkit.event.HandlerList
import org.bukkit.event.entity.EntityDeathEvent import org.bukkit.event.entity.EntityDeathEvent

View File

@@ -1,7 +1,6 @@
package com.willfp.ecobosses.events package com.willfp.ecobosses.events
import com.willfp.ecobosses.bosses.EcoBoss import com.willfp.ecobosses.bosses.EcoBoss
import com.willfp.ecobosses.bosses.LivingEcoBoss
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.Event import org.bukkit.event.Event
@@ -14,7 +13,7 @@ class BossTryDropItemEvent(
var items: MutableCollection<ItemStack>, var items: MutableCollection<ItemStack>,
var chance: Double, var chance: Double,
val player: Player? val player: Player?
): Event() { ) : Event() {
override fun getHandlers(): HandlerList { override fun getHandlers(): HandlerList {
return HANDLERS return HANDLERS
} }

View File

@@ -0,0 +1,28 @@
package com.willfp.ecobosses.libreforge
import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.bosses.EcoBoss
import com.willfp.ecobosses.events.BossTryDropItemEvent
import com.willfp.libreforge.effects.templates.MultiMultiplierEffect
import org.bukkit.event.EventHandler
object EffectBossDropChanceMultiplier : MultiMultiplierEffect<EcoBoss>("boss_drop_chance_multiplier") {
override val key = "bosses"
override fun getElement(key: String): EcoBoss? {
return Bosses.getByID(key)
}
override fun getAllElements(): Collection<EcoBoss> {
return Bosses.values()
}
@EventHandler(ignoreCancelled = true)
fun handle(event: BossTryDropItemEvent) {
val player = event.player ?: return
val multiplier = getMultiplier(player, event.boss)
event.chance *= multiplier
}
}

View File

@@ -0,0 +1,32 @@
package com.willfp.ecobosses.libreforge
import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.attribute.Attribute
import org.bukkit.event.EventHandler
object TriggerKillBoss : Trigger("kill_boss") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.VICTIM,
TriggerParameter.LOCATION
)
@EventHandler(ignoreCancelled = true)
fun handle(event: BossKillEvent) {
val killer = event.killer ?: return
val entity = event.boss.entity
this.dispatch(
killer,
TriggerData(
player = killer,
victim = entity,
location = entity.location,
value = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.value
)
)
}
}

View File

@@ -0,0 +1,28 @@
package com.willfp.ecobosses.libreforge
import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.event.EventHandler
object TriggerSpawnBoss : Trigger("spawn_boss") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.LOCATION
)
@EventHandler(ignoreCancelled = true)
fun handle(event: BossSpawnEvent) {
val player = event.spawner ?: return
val location = event.location
this.dispatch(
player,
TriggerData(
player = player,
location = location
)
)
}
}

View File

@@ -1,16 +1,25 @@
package com.willfp.ecobosses.lifecycle package com.willfp.ecobosses.lifecycle
import com.willfp.ecobosses.bosses.Bosses import com.willfp.ecobosses.bosses.Bosses.isBoss
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityTransformEvent
import org.bukkit.event.entity.SlimeSplitEvent import org.bukkit.event.entity.SlimeSplitEvent
class CompatibilityListeners : Listener { class CompatibilityListeners : Listener {
@EventHandler @EventHandler
fun handle(event: SlimeSplitEvent) { fun handle(event: SlimeSplitEvent) {
if (Bosses[event.entity as? LivingEntity ?: return] != null) { if (!event.entity.isBoss) {
event.isCancelled = true return
} }
event.isCancelled = true
}
@EventHandler
fun handle(event: EntityTransformEvent) {
if (!event.entity.isBoss) {
return
}
event.isCancelled = true
} }
} }

View File

@@ -1,15 +1,15 @@
package com.willfp.ecobosses.lifecycle package com.willfp.ecobosses.lifecycle
import com.willfp.eco.core.EcoPlugin
import com.willfp.ecobosses.events.BossDespawnEvent import com.willfp.ecobosses.events.BossDespawnEvent
import com.willfp.ecobosses.events.BossKillEvent import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.events.BossSpawnEvent import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.libreforge.LibReforgePlugin
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority import org.bukkit.event.EventPriority
import org.bukkit.event.Listener import org.bukkit.event.Listener
class ConsoleLoggers( class ConsoleLoggers(
private val plugin: LibReforgePlugin private val plugin: EcoPlugin
) : Listener { ) : Listener {
@EventHandler( @EventHandler(
ignoreCancelled = true, ignoreCancelled = true,
@@ -34,8 +34,8 @@ class ConsoleLoggers(
return return
} }
val loc = event.boss.entity?.location val loc = event.boss.entity.location
val location = "${loc?.world?.name}: ${loc?.x}, ${loc?.y}, ${loc?.z}" val location = "${loc.world?.name}: ${loc.x}, ${loc.y}, ${loc.z}"
plugin.logger.info("&a${event.boss.boss.id}&r was killed by &a${event.killer?.name}&r at &a$location") plugin.logger.info("&a${event.boss.boss.id}&r was killed by &a${event.killer?.name}&r at &a$location")
} }
@@ -48,8 +48,8 @@ class ConsoleLoggers(
if (!plugin.configYml.getBool("log-spawn-kill")) { if (!plugin.configYml.getBool("log-spawn-kill")) {
return return
} }
val loc = event.boss.entity?.location val loc = event.boss.entity.location
val location = "${loc?.world?.name}: ${loc?.x}, ${loc?.y}, ${loc?.z}" val location = "${loc.world?.name}: ${loc.x}, ${loc.y}, ${loc.z}"
plugin.logger.info("&a${event.boss.boss.id}&r despawned at &a$location") plugin.logger.info("&a${event.boss.boss.id}&r despawned at &a$location")
} }

View File

@@ -6,6 +6,7 @@ import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossKillEvent import com.willfp.ecobosses.events.BossKillEvent
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDeathEvent import org.bukkit.event.entity.EntityDeathEvent
@@ -25,7 +26,8 @@ class DeathListeners : Listener {
} }
@EventHandler( @EventHandler(
ignoreCancelled = true ignoreCancelled = true,
priority = EventPriority.HIGHEST
) )
fun handle(event: EntityDeathEvent) { fun handle(event: EntityDeathEvent) {
val boss = Bosses[event.entity] ?: return val boss = Bosses[event.entity] ?: return

View File

@@ -1,7 +1,6 @@
package com.willfp.ecobosses.lifecycle package com.willfp.ecobosses.lifecycle
import com.willfp.ecobosses.bosses.Bosses import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossDeathEvent
import com.willfp.ecobosses.events.BossDespawnEvent import com.willfp.ecobosses.events.BossDespawnEvent
import com.willfp.ecobosses.events.BossKillEvent import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.events.BossSpawnEvent import com.willfp.ecobosses.events.BossSpawnEvent
@@ -28,7 +27,7 @@ class LifecycleHandlers : Listener {
priority = EventPriority.MONITOR priority = EventPriority.MONITOR
) )
fun handle(event: BossKillEvent) { fun handle(event: BossKillEvent) {
val entity = event.boss.entity ?: return val entity = event.boss.entity
event.boss.boss.handleLifecycle(BossLifecycle.KILL, entity.location, entity) event.boss.boss.handleLifecycle(BossLifecycle.KILL, entity.location, entity)
} }
@@ -38,7 +37,7 @@ class LifecycleHandlers : Listener {
priority = EventPriority.MONITOR priority = EventPriority.MONITOR
) )
fun handle(event: BossDespawnEvent) { fun handle(event: BossDespawnEvent) {
val entity = event.boss.entity ?: return val entity = event.boss.entity
event.boss.boss.handleLifecycle(BossLifecycle.DESPAWN, entity.location, entity) event.boss.boss.handleLifecycle(BossLifecycle.DESPAWN, entity.location, entity)
} }

View File

@@ -23,7 +23,7 @@ object AutospawnHandler {
val world = location.world ?: continue val world = location.world ?: continue
if (plugin.configYml.getBool("autospawn.one-boss-per-world")) { if (plugin.configYml.getBool("autospawn.one-boss-per-world")) {
if (Bosses.getAllAlive().mapNotNull { it.entity }.any { it.world == world }) { if (Bosses.getAllAlive().map { it.entity }.any { it.world == world }) {
continue continue
} }
} }

View File

@@ -1,16 +1,26 @@
package com.willfp.ecobosses.spawn package com.willfp.ecobosses.spawn
import com.willfp.ecobosses.EcoBossesPlugin
import com.willfp.ecobosses.bosses.bossEgg import com.willfp.ecobosses.bosses.bossEgg
import com.willfp.ecobosses.events.BossSpawnEvent import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.libreforge.SimpleProvidedHolder
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.block.Container
import org.bukkit.block.data.Directional
import org.bukkit.entity.Player
import org.bukkit.event.Event import org.bukkit.event.Event
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.event.block.Action import org.bukkit.event.block.Action
import org.bukkit.event.block.BlockDispenseEvent
import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.EquipmentSlot import org.bukkit.inventory.EquipmentSlot
import org.bukkit.inventory.ItemStack
class SpawnEggHandler : Listener { class SpawnEggHandler(
private val plugin: EcoBossesPlugin
) : Listener {
@EventHandler( @EventHandler(
ignoreCancelled = true ignoreCancelled = true
) )
@@ -19,28 +29,13 @@ class SpawnEggHandler : Listener {
return return
} }
val item = event.item ?: return if (!this.handleSpawnEgg(event.item, event.clickedBlock?.location?.add(0.0, 1.5, 0.0), event.player)) {
val boss = item.bossEgg ?: return return
}
event.isCancelled = true event.isCancelled = true
event.setUseItemInHand(Event.Result.DENY) event.setUseItemInHand(Event.Result.DENY)
val location = event.clickedBlock?.location?.add(0.0, 1.5, 0.0) ?: return
val player = event.player
if (!boss.spawnConditions.all { it.condition.isConditionMet(player, it.config) }) {
return
}
val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.EGG, player)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (spawnEvent.isCancelled) {
return
}
if (event.hand == EquipmentSlot.HAND) { if (event.hand == EquipmentSlot.HAND) {
val hand = event.player.inventory.itemInMainHand val hand = event.player.inventory.itemInMainHand
hand.amount = hand.amount - 1 hand.amount = hand.amount - 1
@@ -48,7 +43,56 @@ class SpawnEggHandler : Listener {
val hand = event.player.inventory.itemInOffHand val hand = event.player.inventory.itemInOffHand
hand.amount = hand.amount - 1 hand.amount = hand.amount - 1
} }
}
@EventHandler(
ignoreCancelled = true
)
fun handle(event: BlockDispenseEvent) {
val facing = (event.block.blockData as Directional).facing
val location = event.block.location.add(facing.direction.multiply(1.7))
if (!this.handleSpawnEgg(event.item, location, null)) return
event.isCancelled = true
val dispenser = event.block.state as? Container ?: return
// This is needed as the event must finish first,
// Otherwise the dispenser/dropper thinks the item is already removed from this event.
plugin.scheduler.run {
val item = dispenser.inventory.find { it?.isSimilar(event.item) == true } ?: return@run
item.amount--
dispenser.update()
}
}
private fun handleSpawnEgg(
item: ItemStack?,
location: Location?,
player: Player?
): Boolean {
val boss = item?.bossEgg ?: return false
if (location == null) {
return false
}
if (player != null) {
if (!boss.spawnConditions.areMet(player, SimpleProvidedHolder(boss))) {
return false
}
}
val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.EGG, player)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (spawnEvent.isCancelled) {
return false
}
boss.spawn(location) boss.spawn(location)
return true
} }
} }

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.util.containsIgnoreCase
import com.willfp.ecobosses.bosses.Bosses import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossSpawnEvent import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.ecobosses.util.SpawnTotem import com.willfp.ecobosses.util.SpawnTotem
import com.willfp.libreforge.SimpleProvidedHolder
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.block.Block import org.bukkit.block.Block
@@ -28,11 +29,13 @@ class SpawnTotemHandler : Listener {
middle = event.block.getRelative(0, -1, 0) middle = event.block.getRelative(0, -1, 0)
bottom = event.block.getRelative(0, -2, 0) bottom = event.block.getRelative(0, -2, 0)
} }
1 -> { 1 -> {
top = event.block.getRelative(0, 2, 0) top = event.block.getRelative(0, 2, 0)
middle = event.block.getRelative(0, 1, 0) middle = event.block.getRelative(0, 1, 0)
bottom = event.block bottom = event.block
} }
2 -> { 2 -> {
top = event.block.getRelative(0, 1, 0) top = event.block.getRelative(0, 1, 0)
middle = event.block middle = event.block
@@ -52,7 +55,7 @@ class SpawnTotemHandler : Listener {
val player = event.player val player = event.player
if (!boss.spawnConditions.all { it.condition.isConditionMet(player, it.config) }) { if (!boss.spawnConditions.areMet(player, SimpleProvidedHolder(boss))) {
return return
} }

View File

@@ -12,8 +12,9 @@ class BossBarTicker(
private val bar: BossBar private val bar: BossBar
) : BossTicker { ) : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) { override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity ?: return val entity = boss.entity
@Suppress("DEPRECATION")
bar.name(entity.customName!!.toComponent()) bar.name(entity.customName!!.toComponent())
bar.progress((entity.health / entity.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.value).toFloat()) bar.progress((entity.health / entity.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.value).toFloat())

View File

@@ -0,0 +1,26 @@
package com.willfp.ecobosses.tick
import com.willfp.ecobosses.bosses.LivingEcoBoss
class ChunkTicker : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) {
val currentChunk = boss.chunk
if (tick % 10 != 0) {
return
}
if (currentChunk.isLoaded && currentChunk.isForceLoaded) {
return
}
currentChunk.load()
currentChunk.isForceLoaded = true
boss.forceLoadedChunks.add(currentChunk)
}
override fun onDeath(boss: LivingEcoBoss, tick: Int) {
boss.forceLoadedChunks.forEach { it.isForceLoaded = false }
boss.forceLoadedChunks.clear()
}
}

View File

@@ -7,7 +7,7 @@ import kotlin.math.ceil
class DisplayNameTicker : BossTicker { class DisplayNameTicker : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) { override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity ?: return val entity = boss.entity
val timeLeft = ceil( val timeLeft = ceil(
(boss.deathTime - System.currentTimeMillis()) / 1000.0 (boss.deathTime - System.currentTimeMillis()) / 1000.0
@@ -15,6 +15,7 @@ class DisplayNameTicker : BossTicker {
val formattedTime = String.format("%d:%02d", timeLeft / 60, timeLeft % 60) val formattedTime = String.format("%d:%02d", timeLeft / 60, timeLeft % 60)
@Suppress("DEPRECATION")
entity.customName = boss.boss.displayName entity.customName = boss.boss.displayName
.replace("%health%", NumberUtils.format(entity.health)) .replace("%health%", NumberUtils.format(entity.health))
.replace("%time%", formattedTime) .replace("%time%", formattedTime)

View File

@@ -14,11 +14,6 @@ class LifespanTicker : BossTicker {
Bukkit.getPluginManager().callEvent(event) Bukkit.getPluginManager().callEvent(event)
boss.remove() boss.remove()
boss.boss.handleLifecycle(
BossLifecycle.DESPAWN,
boss.entity?.location ?: return,
boss.entity
)
} }
} }
} }

View File

@@ -4,7 +4,7 @@ import com.willfp.ecobosses.bosses.LivingEcoBoss
class TargetTicker : BossTicker { class TargetTicker : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) { override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity ?: return val entity = boss.entity
if (tick % 10 != 0) { if (tick % 10 != 0) {
return return

View File

@@ -7,7 +7,7 @@ import org.bukkit.block.BlockFace
class TeleportHandler : BossTicker { class TeleportHandler : BossTicker {
override fun tick(boss: LivingEcoBoss, tick: Int) { override fun tick(boss: LivingEcoBoss, tick: Int) {
val entity = boss.entity ?: return val entity = boss.entity
if (!boss.boss.canTeleport) { if (!boss.boss.canTeleport) {
return return
} }

View File

@@ -0,0 +1,24 @@
package com.willfp.ecobosses.util
import com.willfp.libreforge.Holder
import com.willfp.libreforge.ProvidedHolder
import org.bukkit.entity.LivingEntity
class EntityProvidedHolder(
override val holder: Holder,
override val provider: LivingEntity
) : ProvidedHolder {
override fun equals(other: Any?): Boolean {
if (other !is EntityProvidedHolder) {
return false
}
return other.holder == holder && other.provider == provider
}
override fun hashCode(): Int {
var result = holder.hashCode()
result = 31 * result + provider.hashCode()
return result
}
}

View File

@@ -38,6 +38,7 @@ data class LocalBroadcast(
if (radius < 0) { if (radius < 0) {
for (message in toBroadcast) { for (message in toBroadcast) {
@Suppress("DEPRECATION")
Bukkit.broadcastMessage(message) Bukkit.broadcastMessage(message)
} }
} else { } else {

View File

@@ -1,6 +1,5 @@
package com.willfp.ecobosses.util package com.willfp.ecobosses.util
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.util.NumberUtils import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.savedDisplayName import com.willfp.eco.util.savedDisplayName
import com.willfp.ecobosses.EcoBossesPlugin import com.willfp.ecobosses.EcoBossesPlugin
@@ -32,7 +31,7 @@ data class LocalCommands(
} }
for (s in toDispatch) { for (s in toDispatch) {
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s); Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s)
} }
} }
} }

View File

@@ -0,0 +1,209 @@
# The ID of the boss is the name of the .yml file,
# for example steel_golem.yml has the ID of steel_golem
# You can place bosses anywhere in this folder,
# including in subfolders if you want to organize your boss configs
# _example.yml is not loaded.
# A base mob and modifiers
# View an explanation for this system here: https://plugins.auxilor.io/all-plugins/the-entity-lookup-system
mob: iron_golem attack-damage:90 movement-speed:1.5 follow-range:16 health:1200
# If you're using model engine, you can specify the ID and animation here. You can also specify these in the mob with the lookup system.
model-engine-id: ""
model-engine-animation: ""
# Supported placeholders: %health%, %time% (formats as minutes:seconds, eg 1:56)
display-name: "&8Steel Golem &7| &c%health%♥ &7| &e%time%"
influence: 40 # The distance at which effects will be applied to players
custom-ai: # Custom mob AI using the entity goal system.
enabled: false # If custom AI should be enabled, this will override the vanilla mob behaviour.
target-goals: [ ] # How the boss decides who to attack, if the target mode isn't being used.
ai-goals: [ ] # How the boss should behave.
effects: # Effects are done from the player's perspective: to treat the player as the victim, use the self_as_victim option in args
- id: run_chain
args:
chain: blind
self_as_victim: true
chance: 20
triggers:
- static_20
conditions: [ ] # Conditions to apply effects to players; useful if you don't want to affect low-level players
lifespan: 120 # The lifespan of the boss before it despawns, in seconds. Set to a massive number to disable.
defence:
prevent-mounts: true # If the boss shouldn't be able to get into boats, minecarts, etc
explosion-immune: true # If the boss should be immune to explosions
fire-immune: true # If the boss should be immune to fire damage
drowning-immune: true # If the boss should be immune to drowning damage
suffocation-immune: true # If the boss should be immune to suffocation
melee-damage-multiplier: 0.8 # Incoming melee damage will be multiplied by this value. Set to 0 to render immune against melee
projectile-damage-multiplier: 0.2 # Same as melee multiplier, but for projectiles
teleportation: # Teleport every x ticks in order to avoid being caged in obsidian or similar
enabled: true # If the boss should teleport
interval: 100 # Ticks between teleportation attempts
range: 20 # The range that the boss should check for safe teleportation blocks.
rewards:
xp: # Experience will be randomly generated between these values
minimum: 30000
maximum: 60000
top-damager-commands:
# You can specify as many ranks as you want (adding 4, 5, etc)
# You can use %player% as a placeholder for the player name
1:
- chance: 100 # As a percentage
commands:
- eco give %player% 10000
2: [ ]
3: [ ]
nearby-player-commands:
# Commands to be executed for all players near the boss death location
radius: 10
# Uses the same syntax as top damager commands (chance and a list of commands, can use %player%)
commands: [ ]
# You can specify as many drops as you want, and group several drops together under one chance
drops:
- chance: 100
items:
- diamond_sword unbreaking:1 name:"Example Sword"
target:
# How the boss should choose which player to attack, choices are:
# highest_health, lowest_health, closest, random
mode: highest_health
# The distance to scan for players
range: 40
boss-bar:
# If the boss should have a boss bar
enabled: true
color: white # Options: blue, green, pink, purple, red, white, yellow
style: progress # Options: progress, notched_20, notched_12, notched_10, notched_6
radius: 120 # The distance from the boss where the boss bar is visible
spawn:
# A list of conditions required for a player to be able to spawn a boss, useful to set
# minimum skill levels, etc
conditions: [ ]
autospawn:
# Spawn the boss automatically every x ticks. Picks a random location, but will only
# ever spawn in a world if there are no other bosses of that type in the world.
interval: -1 # The interval in ticks, set to -1 to disable
locations: # Add as many locations as you want
- world: world
x: 100
y: 100
z: 100
totem:
enabled: false # A spawn totem is a set of 3 blocks on top of each other to spawn a boss (like a snow golem)
top: netherite_block
middle: iron_block
bottom: magma_block
not-in-worlds: [ ] # If spawn totems should be disallowed in certain worlds, specify them here
egg:
enabled: true # If the boss should have a spawn egg
item: evoker_spawn_egg unbreaking:1 hide_enchants
name: "&8Steel Golem&f Spawn Egg"
lore:
- ""
- "&8&oPlace on the ground to"
- "&8&osummon a &8Steel Golem"
craftable: true
recipe:
- iron_block
- netherite_block
- iron_block
- air
- ecoitems:boss_core ? nether_star
- air
- iron_block
- netherite_block
- iron_block
commands:
# For each category, you can add as many commands as you want, which will be executed by
# console. Supported placeholders are the same as for messages (see below)
spawn: [ ]
kill: [ ]
despawn: [ ]
injure: [ ]
messages:
# For each category, you can add as many messages as you want, each with their own radius.
# Radius is the distance from the boss where the player will be sent the message
# Set to -1 to broadcast globally to all players online
# Supported placeholders: %x%, %y%, %z% (coordinates)
spawn:
- message:
- ""
- "&fA &8&lSteel Golem&r&f has been spawned!"
- "&fCome fight it at &8%x%&f, &8%y%&f, &8%z%&f!"
- ""
radius: -1
# Supported placeholders: %damage_<x>_player%, %damage_<X>%
# You can include as many ranks as you want - if there is no player at a certain rank,
# it will be replaced with N/A (change in lang.yml)
kill:
- message:
- ""
- "&fThe &8&lSteel Golem&r&f has been killed!"
- "&fMost Damage:"
- "&f - &8%damage_1_player%&f (%damage_1% Damage)"
- "&f - &8%damage_2_player%&f (%damage_2% Damage)"
- "&f - &8%damage_3_player%&f (%damage_3% Damage)"
- ""
radius: -1
despawn:
- message:
- ""
- "&fYou ran out of time to kill the &8&lSteel Golem&r&f!"
- ""
radius: -1
injure: [ ]
# All sounds will be played together at the same time
# A list of sounds can be found here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html
# Volume functions as the distance at which the sound will be heard
# Pitch is any value between 0.5 and 2
# If you don't want the vanilla mob sounds, add 'silent' as an option to the mob
sounds:
spawn:
- sound: entity_iron_golem_death
pitch: 0.8
volume: 100
- sound: entity_iron_golem_hurt
pitch: 0.5
volume: 100
- sound: entity_ender_dragon_growl
pitch: 0.5
volume: 100
kill:
- sound: entity_ender_dragon_death
pitch: 1.8
volume: 100
- sound: entity_wither_death
pitch: 1.2
volume: 100
despawn:
- sound: entity_ender_dragon_ambient
pitch: 0.5
volume: 50
- sound: entity_enderman_death
pitch: 0.5
volume: 50
injure:
- sound: entity_iron_golem_damage
pitch: 0.7
volume: 10

View File

@@ -0,0 +1,210 @@
mob: illusioner attack-damage:50 health:600 hand:"iron_sword sharpness:5"
model-engine-id: ""
model-engine-animation: ""
display-name: "&9Illusioner &7| &c%health%♥ &7| &e%time%"
influence: 40
custom-ai:
enabled: true
target-goals:
- key: minecraft:hurt_by
priority: 0
args:
blacklist: [ ]
- key: minecraft:nearest_attackable
priority: 1
args:
target:
- player
checkVisibility: false
checkCanNavigate: true
reciprocalChance: 300
- key: minecraft:nearest_attackable
priority: 2
args:
target:
- iron_golem
- villager
checkVisibility: false
checkCanNavigate: true
reciprocalChance: 300
ai-goals:
- key: minecraft:float
priority: 0
- key: minecraft:illusioner_mirror_spell
priority: 1
- key: minecraft:melee_attack
priority: 2
args:
speed: 1.6
pauseWhenMobIdle: false
- key: minecraft:random_stroll
priority: 8
args:
speed: 0.6
interval: 80
canDespawn: false
- key: minecraft:look_at_player
priority: 9
args:
range: 6
chance: 1
effects:
- id: run_chain
args:
chain: blind
self_as_victim: true
chance: 20
triggers:
- static_20
conditions: [ ]
lifespan: 120
defence:
prevent-mounts: true
explosion-immune: true
fire-immune: true
drowning-immune: true
suffocation-immune: true
melee-damage-multiplier: 1
projectile-damage-multiplier: 0.8
teleportation:
enabled: true
interval: 200
range: 20
rewards:
xp:
minimum: 20000
maximum: 40000
top-damager-commands:
1:
- chance: 100 # As a percentage
commands:
- eco give %player% 10000
2: [ ]
3: [ ]
nearby-player-commands:
radius: 10
commands: [ ]
drops: []
target:
mode: closest
range: 40
boss-bar:
enabled: true
color: blue
style: notched_20
radius: 120
spawn:
conditions: [ ]
autospawn:
interval: -1
locations: []
totem:
enabled: false
top: carved_pumpkin
middle: beacon
bottom: diamond_block
not-in-worlds: [ ]
egg:
enabled: true
item: dolphin_spawn_egg unbreaking:1 hide_enchants
name: "&9Illusioner&f Spawn Egg"
lore:
- ""
- "&8&oPlace on the ground to"
- "&8&osummon an &9Illusioner"
craftable: true
recipe:
- ""
- fermented_spider_eye 64
- ""
- fermented_spider_eye 64
- ecoitems:boss_core ? nether_star
- fermented_spider_eye 64
- ""
- fermented_spider_eye 64
- ""
commands:
spawn: [ ]
kill: [ ]
despawn: [ ]
injure: [ ]
messages:
spawn:
- message:
- ""
- "&fAn &9&lIllusioner&r&f has been spawned!"
- "&fCome fight it at &9%x%&f, &9%y%&f, &9%z%&f!"
- ""
radius: -1
kill:
- message:
- ""
- "&fThe &9&lIllusioner&r&f has been killed!"
- "&fMost Damage:"
- "&f - &9%damage_1_player%&f (%damage_1% Damage)"
- "&f - &9%damage_2_player%&f (%damage_2% Damage)"
- "&f - &9%damage_3_player%&f (%damage_3% Damage)"
- ""
radius: -1
despawn:
- message:
- ""
- "&fYou ran out of time to kill the &9&lIllusioner&r&f!"
- ""
radius: -1
injure: [ ]
sounds:
spawn:
- sound: entity_illusioner_mirror_move
pitch: 0.5
volume: 100
- sound: entity_wither_spawn
pitch: 2
volume: 100
kill:
- sound: entity_evoker_prepare_wololo
pitch: 0.8
volume: 100
- sound: entity_illusioner_prepare_blindness
pitch: 1
volume: 100
- sound: entity_wither_death
pitch: 2
volume: 100
despawn:
- sound: entity_ender_dragon_ambient
pitch: 0.6
volume: 50
- sound: entity_enderman_death
pitch: 0.8
volume: 50
injure:
- sound: entity_illusioner_cast_spell
pitch: 2
volume: 10

View File

@@ -8,42 +8,3 @@ log-spawn-kill: true
autospawn: autospawn:
one-boss-per-world: true # If only one boss can auto-spawn per world at once. one-boss-per-world: true # If only one boss can auto-spawn per world at once.
cooldown:
in-actionbar: true
sound:
enabled: true
sound: "BLOCK_NOTE_BLOCK_PLING"
pitch: 0.5
cannot-afford:
in-actionbar: true
sound:
enabled: true
sound: "BLOCK_NOTE_BLOCK_PLING"
pitch: 0.5
cannot-afford-type:
in-actionbar: true
sound:
enabled: true
sound: "BLOCK_NOTE_BLOCK_PLING"
pitch: 0.5
point-names: # If you have point names that look ugly (eg g_souls) then you can map them to nice names to be shown to players.
example_point: "Nicely Formatted Point"
use-faster-move-trigger: true # Disable if you want move trigger to detect sub-1-block movements
raytrace-distance: 80 # The distance that alt_click should check for a location
block-item-drop-place-check: true # If the block_item_drop trigger should only fire on naturally placed blocks (prevents dupes)
potions:
icon:
permanent: true
triggered: true
ambient:
permanent: false
triggered: true
particles:
permanent: false
triggered: true

View File

@@ -1,3 +1,8 @@
resource-id: 525 environment:
bstats-id: 10635 - name: libreforge version
color: "&9" value: ${libreforgeVersion}
options:
resource-id: 525
bstats-id: 10635
color: "&9"

View File

@@ -1,205 +0,0 @@
chains:
- id: blind
effects:
- id: teleport
- id: potion_effect
args:
effect: blindness
level: 3
duration: 30
apply_to_player: true
- id: send_message
args:
message: "&cYou have been blinded!"
action_bar: true
- id: play_sound
args:
sound: entity_dragon_fireball_explode
pitch: 1.5
volume: 4
bosses:
- id: steel_golem
# A base mob and modifiers
# View an explanation for this system here: https://plugins.auxilor.io/all-plugins/the-entity-lookup-system
mob: iron_golem attack-damage:90 movement-speed:1.5 follow-range:16 health:1200
# Supported placeholders: %health%, %time% (formats as minutes:seconds, eg 1:56)
displayName: "&8Steel Golem &7| &c%health%♥ &7| &e%time%"
influence: 40 # The distance at which effects will be applied to players
customai: # Custom mob AI using the entity goal system.
enabled: false # If custom AI should be enabled, this will override the vanilla mob behaviour.
target-goals: [ ] # How the boss decides who to attack, if the target mode isn't being used.
ai-goals: [ ] # How the boss should behave.
effects: # Effects are done from the player's perspective: to treat the player as the victim, use the self_as_victim option in args
- id: run_chain
args:
chain: blind
self_as_victim: true
chance: 20
triggers:
- static_20
conditions: [ ] # Conditions to apply effects to players; useful if you don't want to affect low-level players
lifespan: 120 # The lifespan of the boss before it despawns, in seconds. Set to a massive number to disable.
defence:
preventMounts: true # If the boss shouldn't be able to get into boats, minecarts, etc
explosionImmune: true # If the boss should be immune to explosions
fireImmune: true # If the boss should be immune to fire damage
drowningImmune: true # If the boss should be immune to drowning damage
suffocationImmune: true # If the boss should be immune to suffocation
meleeDamageMultiplier: 0.8 # Incoming melee damage will be multiplied by this value. Set to 0 to render immune against melee
projectileDamageMultiplier: 0.2 # Same as melee multiplier, but for projectiles
teleportation: # Teleport every x ticks in order to avoid being caged in obsidian or similar
enabled: true # If the boss should teleport
interval: 100 # Ticks between teleportation attempts
range: 20 # The range that the boss should check for safe teleportation blocks.
rewards:
xp: # Experience will be randomly generated between these values
minimum: 30000
maximum: 60000
topDamagerCommands:
# You can specify as many ranks as you want (adding 4, 5, etc)
# You can use %player% as a placeholder for the player name
1:
- chance: 100 # As a percentage
commands:
- eco give %player% 10000
2: [ ]
3: [ ]
nearbyPlayerCommands:
# Commands to be executed for all players near the boss death location
radius: 10
# Uses the same syntax as top damager commands (chance and a list of commands, can use %player%)
commands: [ ]
# You can specify as many drops as you want, and group several drops together under one chance
drops:
- chance: 100
items:
- diamond_sword unbreaking:1 name:"Example Sword"
target:
# How the boss should choose which player to attack, choices are:
# highest_health, lowest_health, closest, random
mode: highest_health
# The distance to scan for players
range: 40
bossBar:
# If the boss should have a boss bar
enabled: true
color: white # Options: blue, green, pink, purple, red, white, yellow
style: progress # Options: progress, notched_20, notched_12, notched_10, notched_6
radius: 120 # The distance from the boss where the boss bar is visible
spawn:
# A list of conditions required for a player to be able to spawn a boss, useful to set
# minimum skill levels, etc
conditions: [ ]
autospawn:
# Spawn the boss automatically every x ticks. Picks a random location, but will only
# ever spawn in a world if there are no other bosses of that type in the world.
interval: -1 # The interval in ticks, set to -1 to disable
locations: # Add as many locations as you want
- world: world
x: 100
y: 100
z: 100
totem:
enabled: false # A spawn totem is a set of 3 blocks on top of each other to spawn a boss (like a snow golem)
top: netherite_block
middle: iron_block
bottom: magma_block
notInWorlds: [ ] # If spawn totems should be disallowed in certain worlds, specify them here
egg:
enabled: true # If the boss should have a spawn egg
item: evoker_spawn_egg unbreaking:1 hide_enchants
name: "&8Steel Golem&f Spawn Egg"
lore:
- ""
- "&8&oPlace on the ground to"
- "&8&osummon a &8Steel Golem"
craftable: true
recipe:
- iron_block
- netherite_block
- iron_block
- air
- ecoitems:boss_core ? nether_star
- air
- iron_block
- netherite_block
- iron_block
commands:
# For each category, you can add as many commands as you want, which will be executed by
# console. Supported placeholders are the same as for messages (see below)
spawn: [ ]
kill: [ ]
despawn: [ ]
injure: [ ]
messages:
# For each category, you can add as many messages as you want, each with their own radius.
# Radius is the distance from the boss where the player will be sent the message
# Set to -1 to broadcast globally to all players online
# Supported placeholders: %x%, %y%, %z% (coordinates)
spawn:
- message:
- ""
- "&fA &8&lSteel Golem&r&f has been spawned!"
- "&fCome fight it at &8%x%&f, &8%y%&f, &8%z%&f!"
- ""
radius: -1
# Supported placeholders: %damage_<x>_player%, %damage_<X>%
# You can include as many ranks as you want - if there is no player at a certain rank,
# it will be replaced with N/A (change in lang.yml)
kill:
- message:
- ""
- "&fThe &8&lSteel Golem&r&f has been killed!"
- "&fMost Damage:"
- "&f - &8%damage_1_player%&f (%damage_1% Damage)"
- "&f - &8%damage_2_player%&f (%damage_2% Damage)"
- "&f - &8%damage_3_player%&f (%damage_3% Damage)"
- ""
radius: -1
despawn:
- message:
- ""
- "&fYou ran out of time to kill the &8&lSteel Golem&r&f!"
- ""
radius: -1
injure: [ ]
# All sounds will be played together at the same time
# A list of sounds can be found here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html
# Volume functions as the distance at which the sound will be heard
# Pitch is any value between 0.5 and 2
# If you don't want the vanilla mob sounds, add 'silent' as an option to the mob
sounds:
spawn:
- sound: entity_iron_golem_death
pitch: 0.8
volume: 100
- sound: entity_iron_golem_hurt
pitch: 0.5
volume: 100
- sound: entity_ender_dragon_growl
pitch: 0.5
volume: 100
kill:
- sound: entity_ender_dragon_death
pitch: 1.8
volume: 100
- sound: entity_wither_death
pitch: 1.2
volume: 100
despawn:
- sound: entity_ender_dragon_ambient
pitch: 0.5
volume: 50
- sound: entity_enderman_death
pitch: 0.5
volume: 50
injure:
- sound: entity_iron_golem_damage
pitch: 0.7
volume: 10

View File

@@ -1,9 +1,10 @@
messages: messages:
prefix: "&9&lEcoBosses &f» " prefix: "&9&lEcoBosses &f» "
no-permission: "&cYou don't have permission to do this!" no-permission: "&cYou don't have permission to do this!"
invalid-command: "&cUnknown subcommand!"
not-player: "&cThis command must be run by a player" not-player: "&cThis command must be run by a player"
invalid-command: "&cUnknown subcommand!"
reloaded: "Reloaded!" reloaded: "Reloaded!"
sent-drop: "Check console for the drop!" sent-drop: "Check console for the drop!"
specify-boss: "&cYou must specify a valid boss!" specify-boss: "&cYou must specify a valid boss!"
invalid-location: "&cInvalid location!" invalid-location: "&cInvalid location!"
@@ -15,9 +16,5 @@ messages:
invalid-stone: "&cInvalid boss!" invalid-stone: "&cInvalid boss!"
give-success: "Gave &a%boss%&r spawn egg to &a%recipient%" give-success: "Gave &a%boss%&r spawn egg to &a%recipient%"
requirements-not-met: "&cYou can't spawn this boss!" requirements-not-met: "&cYou can't spawn this boss!"
on-cooldown: "&cThis effect is on cooldown! &fTime left: &a%seconds% seconds"
cannot-afford: "&cYou can't afford to do this! &fCost: &a$$%cost%"
cannot-afford-type: "&cYou can't afford to do this! &fCost: &a%cost% %type%"
cannot-transmit: "&cYou can't transmit here!"
na: "N/A" na: "N/A"

View File

@@ -0,0 +1,53 @@
name: ${pluginName}
version: ${version}
main: com.willfp.ecobosses.EcoBossesPlugin
api-version: 1.19
dependencies:
- name: eco
required: true
bootstrap: false
- name: libreforge
required: false
bootstrap: false
load-after:
- name: eco
bootstrap: false
permissions:
ecobosses.*:
description: All ecobosses permissions
default: op
children:
ecobosses.command.*: true
ecobosses.command.*:
description: All ecobosses commands
default: op
children:
ecobosses.command.ecobosses: true
ecobosses.command.reload: true
ecobosses.command.spawn: true
ecobosses.command.give: true
ecobosses.command.ecobosses:
description: Allows the use of /ecobosses
default: true
ecobosses.command.give:
description: Allows the use of /ecobosses give
default: op
ecobosses.command.spawn:
description: Allows the use of /ecobosses spawn
default: op
ecobosses.command.killall:
description: Allows the use of /ecobosses killall
default: op
ecobosses.command.reload:
description: Allows the use of /ecobosses reload
default: op

View File

@@ -1,25 +1,15 @@
name: EcoBosses name: ${pluginName}
version: ${projectVersion} version: ${version}
main: com.willfp.ecobosses.EcoBossesPlugin main: com.willfp.ecobosses.EcoBossesPlugin
api-version: 1.17 api-version: 1.17
authors: [Auxilor] authors: [Auxilor]
website: willfp.com website: willfp.com
load: STARTUP
depend: depend:
- eco - eco
softdepend: softdepend:
- libreforge
- LevelledMobs - LevelledMobs
- AureliumSkills - AureliumSkills
- Jobs
- mcMMO
- Vault
- TMMobcoins
- EcoEnchants
- Talismans
- EcoArmor
- EcoItems
- EcoSkills
- Boosters
commands: commands:
ecobosses: ecobosses:
@@ -59,4 +49,4 @@ permissions:
ecobosses.command.reload: ecobosses.command.reload:
description: Allows the use of /ecobosses reload description: Allows the use of /ecobosses reload
default: op default: op

View File

@@ -1,4 +1,5 @@
#libreforge-updater #libreforge-updater
#Mon Jun 20 14:16:54 BST 2022 #Sun Apr 02 17:44:13 BST 2023
version=8.51.0 kotlin.code.style=official
plugin-name=EcoBosses libreforge-version=4.2.1
version=9.2.1

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

269
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

View File

@@ -1,12 +0,0 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven { url "https://repo.jpenilla.xyz/snapshots/" }
}
}
rootProject.name = 'EcoBosses'
// Core
include ':eco-core'
include ':eco-core:core-plugin'

14
settings.gradle.kts Normal file
View File

@@ -0,0 +1,14 @@
pluginManagement {
repositories {
gradlePluginPortal()
mavenLocal()
maven("https://repo.jpenilla.xyz/snapshots/")
maven("https://repo.auxilor.io/repository/maven-public/")
}
}
rootProject.name = "EcoBosses"
// Core
include(":eco-core")
include(":eco-core:core-plugin")