9
0
mirror of https://github.com/Auxilor/EcoJobs.git synced 2025-12-20 15:39:26 +00:00

Compare commits

...

198 Commits

Author SHA1 Message Date
Will FP
ec1fe90c8c libreforge-updater 2025-03-29 14:21:51 +00:00
Will FP
7420415514 Merge pull request #33 from Exanthiax/reset-all-command
added "all" args to reset command
2025-03-29 14:18:16 +00:00
Will FP
11bce9975d Merge pull request #34 from Exanthiax/level-up-effects
added level-up-effects
2025-03-29 14:18:00 +00:00
Will FP
013d8a0068 Merge branch 'master' into level-up-effects 2025-03-29 14:17:28 +00:00
Will FP
338c1c3499 Merge pull request #35 from Exanthiax/trigger-effects
added join-effects and leave-effects
2025-03-29 14:16:40 +00:00
Exanthiax
cdcc45aef8 update all current jobs 2025-03-09 22:52:32 +00:00
Exanthiax
533d036a18 moved below placeholders 2025-02-04 23:12:04 +00:00
Exanthiax
03e99e2e1e updated ymls 2025-02-04 23:05:41 +00:00
Exanthiax
86b7ad2971 added level-up-effects
added `level-up-effects`
deprecated `level-commands` with message
2025-02-04 21:39:57 +00:00
Exanthiax
7065642d97 Update _example.yml 2025-02-04 18:04:56 +00:00
Exanthiax
e6c486bc3a added join-effects and leave-effects 2025-02-04 18:02:48 +00:00
Exanthiax
c99769a1e3 added "all" args
Within reset command, you can now use "all" as player or job.
Added new lang messages accordingly.
2025-01-31 13:38:06 +00:00
Will FP
6fc1ba72d8 libreforge-updater 2025-01-31 11:53:47 +00:00
Will FP
b08687eba2 Merge pull request #31 from Penumbrae/patch-1
Wrong usage of a filter
2025-01-31 11:41:53 +00:00
Will FP
8cd544b327 Merge pull request #32 from Exanthiax/new-xp-methods
New xp methods
2025-01-31 11:41:44 +00:00
Exanthiax
5d40c32c1e Fixed xp-required and placeholders. 2025-01-28 23:35:34 +00:00
Exanthiax
ee155ccca6 Update _example.yml 2025-01-28 20:04:22 +00:00
Exanthiax
acdb4d0f78 added xp-formula and max-level 2025-01-28 19:45:56 +00:00
Will FP
b99a72808c libreforge-updater 2025-01-25 13:49:33 +00:00
Will FP
6bd56c8d95 Fix 2025-01-25 13:48:09 +00:00
Will FP
e90f321517 libreforge-updater 2025-01-25 13:45:31 +00:00
Penumbrae
4c021781e5 Wrong usage of a filter
This job had the filter "items" to filter pickaxes, which doesn't work in this case. This essentially means that the players would be able to earn money and xp by breaking a block in any way.

Changed it to the in_mainhand condition.
2025-01-25 00:37:55 +00:00
Will FP
abfce4428f libreforge-updater 2024-11-06 18:31:32 +00:00
Will FP
d7b7f6895e libreforge-updater 2024-10-22 12:12:52 +01:00
Will FP
2a97bc2d29 libreforge-updater 2024-09-22 16:58:16 +01:00
Auxilor
af4d3058e8 libreforge-updater 2024-09-02 11:29:55 +01:00
Auxilor
802360e885 libreforge-updater 2024-08-30 17:24:55 +01:00
Auxilor
79a396f5d3 libreforge-updater 2024-08-29 12:09:03 +01:00
Auxilor
e264e49b05 libreforge-updater 2024-08-23 15:35:08 +01:00
Auxilor
d9263bcb53 libreforge-updater 2024-08-21 18:58:06 +01:00
Auxilor
4681bd63e1 libreforge-updater 2024-08-15 15:07:19 +01:00
Auxilor
998e25e7ec libreforge-updater 2024-08-03 13:41:10 +01:00
Auxilor
f1f7ec5afd libreforge-updater 2024-07-25 10:04:20 +01:00
Auxilor
875928b4c2 libreforge-updater 2024-07-21 12:19:05 +01:00
Auxilor
049cb72385 libreforge-updater 2024-07-19 20:28:24 +01:00
Auxilor
b7decc9eb8 libreforge-updater 2024-07-18 13:23:59 +01:00
Auxilor
44c59de546 libreforge-updater 2024-07-16 17:13:29 +01:00
Auxilor
fdbbf8102c libreforge-updater 2024-07-13 20:45:06 +01:00
Auxilor
cf7084fd44 libreforge-updater 2024-07-08 15:58:17 +01:00
Auxilor
fa4e0dc67a libreforge-updater 2024-07-05 13:02:32 +01:00
Auxilor
210a6e821e libreforge-updater 2024-07-03 17:43:43 +01:00
Auxilor
b520442dee libreforge-updater 2024-06-29 16:43:48 +01:00
Auxilor
58966f04ff libreforge-updater 2024-06-28 15:56:11 +01:00
Auxilor
4588122b20 libreforge-updater 2024-06-27 18:54:14 +01:00
Auxilor
b98ee1d0dc libreforge-updater 2024-06-26 16:52:06 +01:00
Auxilor
929e6d59d8 libreforge-updater 2024-06-25 15:13:45 +01:00
Auxilor
e6884a0320 libreforge-updater 2024-06-24 15:06:21 +01:00
Auxilor
569f63e22d Updated to Java 21 2024-06-24 14:00:38 +01:00
Auxilor
49aecb54bf libreforge-updater 2024-06-23 17:26:20 +01:00
Auxilor
da80fbdcce libreforge-updater 2024-06-23 13:18:38 +01:00
Will FP
c66919ec49 libreforge-updater 2024-05-31 20:35:53 +01:00
Will FP
117f412ed3 libreforge-updater 2024-05-11 18:20:35 +01:00
Will FP
1bd643eb8a libreforge-updater 2024-04-17 20:32:58 +01:00
Auxilor
2eb7625711 libreforge-updater 2024-04-15 18:19:26 +01:00
Auxilor
48b86099c9 libreforge-updater 2024-04-11 13:17:25 +01:00
Auxilor
966051bc21 libreforge-updater 2024-03-29 16:08:35 +00:00
Will FP
442ea73366 libreforge-updater 2024-03-11 17:36:28 +00:00
Will FP
52a6b45c85 libreforge-updater 2024-03-10 20:07:46 +00:00
Will FP
dfff7c339c libreforge-updater 2024-03-02 15:19:29 +00:00
Will FP
eb13e26512 libreforge-updater 2024-02-22 13:16:51 +00:00
Will FP
7219918101 libreforge-updater 2024-02-15 13:00:56 +00:00
Will FP
92787738b6 libreforge-updater 2024-02-08 19:47:41 +00:00
Will FP
05cf850aab libreforge-updater 2024-01-30 11:25:31 +00:00
Will FP
ac9f26bcce libreforge-updater 2024-01-18 17:01:43 +00:00
Will FP
72f30769ad libreforge-updater 2024-01-16 13:25:44 +00:00
Will FP
7282046ba0 libreforge-updater 2024-01-13 14:22:59 +00:00
Will FP
0646965c9f libreforge-updater 2024-01-07 13:50:30 +00:00
Will FP
243407ce3c libreforge-updater 2024-01-06 09:18:30 +00:00
Auxilor
1e2b101011 libreforge-updater 2024-01-04 17:25:16 +00:00
Auxilor
ecf99839bf libreforge-updater 2024-01-01 20:02:16 +00:00
Will FP
b414ff57ab libreforge-updater 2023-12-27 14:15:49 +01:00
Will FP
a476fac03e libreforge-updater 2023-12-24 14:54:07 +01:00
Auxilor
50b42f38ba libreforge-updater 2023-12-20 15:57:06 +00:00
Will FP
08d5fa6b0c libreforge-updater 2023-12-14 16:12:08 +00:00
Will FP
c3febb89ec libreforge-updater 2023-12-11 12:11:41 +00:00
Will FP
7e3ba5293f libreforge-updater 2023-12-07 17:23:58 +00:00
Will FP
19ef0341fa libreforge-updater 2023-12-03 15:57:13 +00:00
Will FP
1bfaf7f7e1 libreforge-updater 2023-11-30 14:26:14 +00:00
Will FP
827f8430e1 libreforge-updater 2023-11-26 23:23:30 +00:00
Will FP
6192ce5bb6 libreforge-updater 2023-11-23 13:20:15 +00:00
Auxilor
fe59c30f52 libreforge-updater 2023-11-21 22:40:38 +00:00
Auxilor
7763ea48fd libreforge-updater 2023-11-19 14:13:20 +00:00
Auxilor
aef5d348bc libreforge-updater 2023-11-17 19:01:23 +00:00
Auxilor
d0bf9c848b libreforge-updater 2023-11-11 17:57:58 +00:00
Auxilor
6468ba5312 libreforge-updater 2023-11-10 13:58:22 +00:00
Auxilor
649253b82a libreforge-updater 2023-11-05 13:40:57 +00:00
Auxilor
e2cafdf031 libreforge-updater 2023-10-30 13:30:02 +00:00
Auxilor
3bc5661ea6 Updated to 3.37.2 2023-10-30 12:50:20 +00:00
Auxilor
c83bf6e607 The Job level GUI title is now customisable 2023-10-30 12:50:10 +00:00
Auxilor
b161bc4adf libreforge-updater 2023-10-28 14:14:29 +01:00
Auxilor
30af9048af libreforge-updater 2023-10-24 15:37:59 +01:00
Auxilor
8cb2fd8700 libreforge-updater 2023-10-19 12:51:32 +01:00
Auxilor
e0efc21da9 libreforge-updater 2023-10-14 14:19:51 +01:00
Auxilor
24951ea269 libreforge-updater 2023-10-14 14:17:54 +01:00
Auxilor
1041aa6f5f libreforge-updater 2023-10-02 11:52:57 +01:00
Auxilor
691e08fb44 libreforge-updater 2023-09-26 14:43:48 +01:00
Auxilor
f049f31778 libreforge-updater 2023-09-20 15:32:48 +01:00
Auxilor
01d24cd517 libreforge-updater 2023-09-17 11:19:20 +01:00
Auxilor
12c4d1938f libreforge-updater 2023-09-13 15:07:52 +01:00
Auxilor
edc1f58b40 libreforge-updater 2023-09-07 16:01:46 +01:00
Auxilor
9c0a8ee1dc libreforge-updater 2023-09-02 17:34:33 +01:00
Auxilor
8315707aed libreforge-updater 2023-08-31 16:59:34 +01:00
Auxilor
1f1ece53ce libreforge-updater 2023-08-30 11:31:28 +01:00
Auxilor
92af313c43 Added use-local-storage 2023-08-30 09:49:12 +01:00
Auxilor
0d207545b8 libreforge-updater 2023-08-26 18:11:33 +01:00
Auxilor
83ece163c0 libreforge-updater 2023-08-23 15:31:48 +01:00
Auxilor
608c16d554 libreforge-updater 2023-08-19 15:32:41 +01:00
Auxilor
fd6f525a65 libreforge-updater 2023-08-15 18:50:13 +01:00
Auxilor
9c01b582eb libreforge-updater 2023-08-13 14:42:40 +01:00
Auxilor
30ae94e8e2 libreforge-updater 2023-08-10 19:59:29 +01:00
Auxilor
9e15f12800 libreforge-updater 2023-08-10 19:57:27 +01:00
Auxilor
aaf922c79a libreforge-updater 2023-08-09 15:58:38 +01:00
Auxilor
4008d0a9d0 libreforge-updater 2023-08-09 14:40:33 +01:00
Auxilor
7cbcbaad8d libreforge-updater 2023-08-09 14:37:18 +01:00
Auxilor
496dff834d libreforge-updater 2023-08-08 17:59:18 +01:00
Auxilor
d81e03ef6f libreforge-updater 2023-08-05 21:06:57 +01:00
Auxilor
85a6a03d41 libreforge-updater 2023-07-27 15:21:35 +01:00
Auxilor
6f78e4b704 libreforge-updater 2023-07-27 15:18:43 +01:00
Auxilor
2656156bcf libreforge-updater 2023-07-25 14:38:13 +01:00
Auxilor
4e3d419e53 libreforge-updater 2023-07-23 11:40:21 +01:00
Auxilor
436b176e36 libreforge-updater 2023-07-22 14:59:42 +01:00
Auxilor
efb8bda519 libreforge-updater 2023-07-21 12:32:56 +01:00
Auxilor
097582fe5e libreforge-updater 2023-07-20 13:06:54 +01:00
Auxilor
1a6a8b3e38 libreforge-updater 2023-07-19 14:14:47 +01:00
Auxilor
3f54f8af2d libreforge-updater 2023-07-17 18:32:24 +01:00
Auxilor
94ca19447f libreforge-updater 2023-07-16 13:33:11 +01:00
Auxilor
2d67115569 libreforge-updater 2023-07-12 13:07:18 +01:00
Auxilor
6e9e9b000f libreforge-updater 2023-07-09 17:24:37 +01:00
Auxilor
a34727feb5 libreforge-updater 2023-07-06 18:46:59 +01:00
Auxilor
b744fbfe2d libreforge-updater 2023-07-04 14:49:45 +01:00
Auxilor
2db3a90049 libreforge-updater 2023-06-27 10:41:45 +01:00
Auxilor
466f80f860 libreforge-updater 2023-06-21 10:22:36 +01:00
Auxilor
2f177f34f1 libreforge-updater 2023-06-19 11:11:32 +02:00
Will FP
2c2b008678 Create CODEOWNERS 2023-06-17 21:22:31 +02:00
Auxilor
9c26ba3b91 libreforge-updater 2023-06-10 13:32:36 +01:00
Auxilor
1c16e52b97 libreforge-updater 2023-06-05 16:26:02 +01:00
Auxilor
f6fe3477c6 Fixed Publications 2023-06-03 18:03:16 +01:00
Auxilor
ee3298d260 libreforge-updater 2023-06-03 15:44:50 +01:00
Auxilor
65dcbf2d98 libreforge-updater 2023-06-01 12:32:47 +01:00
Auxilor
cba4ed6e49 libreforge-updater 2023-05-30 16:09:51 +01:00
Auxilor
241435dafe libreforge-updater 2023-05-24 14:57:27 +01:00
Auxilor
84277d5b68 libreforge-updater 2023-05-23 16:11:17 +01:00
Auxilor
6f63dd2af6 libreforge-updater 2023-05-20 17:40:09 +01:00
Auxilor
7b577dca25 libreforge-updater 2023-05-18 16:24:52 +01:00
Auxilor
59a5bcb68d libreforge-updater 2023-05-17 15:56:32 +01:00
Auxilor
6592a6ff73 libreforge-updater 2023-05-16 20:29:31 +01:00
Auxilor
c9c82e4591 libreforge-updater 2023-05-15 10:51:56 +01:00
Auxilor
dcba6b07ca libreforge-updater 2023-05-14 13:07:48 +01:00
Auxilor
fe812fc11a libreforge-updater 2023-05-09 17:44:57 +01:00
Auxilor
b94ee51499 libreforge-updater 2023-05-05 18:54:12 +01:00
Auxilor
edfeba8b4d libreforge-updater 2023-05-03 14:47:13 +01:00
Auxilor
edab673d6c libreforge-updater 2023-04-30 19:56:37 +01:00
Auxilor
7ab1cbb9f6 libreforge-updater 2023-04-29 17:18:32 +01:00
Auxilor
87760be002 libreforge-updater 2023-04-25 16:05:45 +01:00
Auxilor
84a5a1684f libreforge-updater 2023-04-25 13:12:41 +01:00
Auxilor
0e415ee27f libreforge-updater 2023-04-24 22:48:29 +01:00
Auxilor
56466a43f3 libreforge-updater 2023-04-20 20:21:04 +01:00
Auxilor
f872b6d210 libreforge-updater 2023-04-19 12:22:05 +01:00
Auxilor
35b48651ad libreforge-updater 2023-04-13 12:48:17 -04:00
Auxilor
dba01a929f libreforge-updater 2023-04-09 18:18:51 -04:00
Auxilor
03b2df5017 libreforge-updater 2023-04-06 20:08:44 +02:00
Auxilor
5270d3f719 libreforge-updater 2023-04-05 13:14:09 +01:00
Auxilor
4136826643 libreforge-updater 2023-04-03 17:50:11 +01:00
Auxilor
aa5cb1681d libreforge-updater 2023-04-02 17:44:31 +01:00
Auxilor
d7c6edd5c3 libreforge-updater 2023-03-30 15:29:58 +01:00
Auxilor
aa946416c0 libreforge-updater 2023-03-29 19:20:45 +01:00
Auxilor
b87fb28b45 libreforge-updater 2023-03-29 15:46:42 +01:00
Auxilor
3e61544ef1 Moved to repo.auxilor.io 2023-03-29 13:52:47 +01:00
Auxilor
55a991091f Fixed permissions on paper 2023-03-28 21:46:04 +01:00
Auxilor
b9e67b55ec Moved integration 2023-03-28 19:13:24 +01:00
Auxilor
1753e47534 Fixed JobXPAccumulator 2023-03-28 16:07:43 +01:00
Auxilor
94224e136c Fixed several bugs 2023-03-28 16:06:24 +01:00
Auxilor
22d2fb6caf Fixed publications 2023-03-28 15:01:37 +01:00
Auxilor
c36509f3ed Suppression 2023-03-27 18:57:00 +01:00
Auxilor
7f331dd5dc Updated to libreforge 4 2023-03-27 18:56:28 +01:00
Auxilor
3fdafa0f7d Changed load order 2023-03-22 22:21:36 +00:00
Auxilor
edf978fa28 libreforge-updater 2023-03-13 13:38:53 +00:00
Auxilor
5504a89f1b libreforge-updater 2023-03-02 12:54:27 +00:00
Auxilor
ae3f3ac2d3 Updated to 2.1.2 2023-02-25 17:53:51 +00:00
Auxilor
704dfc65e5 Fixed dependencies 2023-02-25 17:38:56 +00:00
Auxilor
2169581466 libreforge-updater 2023-02-22 15:01:32 +00:00
Auxilor
034265a0e9 Updated to 2.1.0 2023-02-18 12:11:11 +00:00
Will FP
4eded008fe Merge pull request #20 from PQguanfang/master
Add %level_numeral% placeholder in Job Main and Job Level Gui
2023-02-18 12:09:01 +00:00
Will FP
7492f3e548 Merge pull request #21
Fixed inappropriate xp gain handling
2023-02-18 12:07:38 +00:00
_OfTeN_
6bf9d371b9 Fixed leaderboard placeholders updating 2023-02-18 02:20:16 +03:00
_OfTeN_
4034f5098f Added %ecojobs_top_<job>_<place>_<name/amount>% placeholder 2023-02-17 04:45:45 +03:00
_OfTeN_
2014a6dd5f Updated eco 2023-02-17 04:44:33 +03:00
_OfTeN_
bcf5ef3b0f Fixed inappropriate xp gain handling 2023-02-17 03:54:57 +03:00
PQguanfang
7e10899c72 Merge pull request #1 from PQguanfang/dev
Update Job.kt
2023-02-16 15:10:08 +08:00
PQguanfang
9bd24ed4e9 Update Job.kt 2023-02-16 15:07:56 +08:00
Auxilor
935e9a7937 libreforge-updater 2023-02-15 20:57:47 +00:00
Auxilor
04c2571d0f Added %ecojobs_<id>_active% placeholder 2023-02-15 18:48:47 +00:00
Auxilor
bd1b1aaa75 Cleaned up default config 2023-02-15 18:47:26 +00:00
Auxilor
f942ebd9ed Updated to 2.0.0 2023-02-15 18:43:32 +00:00
Auxilor
dfbc77cd0a Updated GUI 2023-02-15 18:43:15 +00:00
Auxilor
760c3ce707 Updated to 2.0 with multiple jobs support (todo: GUI) 2023-02-15 18:01:43 +00:00
Auxilor
b4db83feb1 libreforge-updater 2023-02-12 16:54:39 +00:00
Auxilor
31980faf05 libreforge-updater 2023-02-09 14:11:37 +00:00
68 changed files with 1677 additions and 1218 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @WillFP

View File

@@ -1,8 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Auxilor Community Discord
- name: Discord
url: https://discord.gg/ZcwpSsE/
about: Join the Auxilor discord to get help from support staff and the general community!
- 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
about: Issues have moved to Discord, please join the server to get help!

View File

@@ -4,28 +4,8 @@ about: Report an issue with the plugin
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
# Please report bugs on the discord!
**To Reproduce**
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.
[Join by clicking here](https://discord.gg/ZcwpSsE/)

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 21
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 21
- 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,123 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10"
}
}
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.io/repository/maven-public/' }
maven { url 'https://repo.dmulloy2.net/repository/public/' }
maven { url 'https://repo.essentialsx.net/releases/' }
}
jar {
onlyIf { !sourceSets.main.allSource.files.isEmpty() }
}
shadowJar {
relocate('com.willfp.libreforge', 'com.willfp.ecojobs.libreforge')
relocate('com.willfp.ecomponent', 'com.willfp.ecojobs.ecomponent')
relocate('org.joml', 'com.willfp.ecojobs.libreforge.joml')
}
dependencies {
compileOnly 'com.willfp:eco:6.46.0'
implementation 'com.willfp:libreforge:3.128.2'
implementation 'com.willfp:ecomponent:1.0.0'
implementation 'org.joml:joml:1.10.4'
compileOnly 'org.jetbrains:annotations:23.0.0'
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.7.10'
}
tasks.withType(JavaCompile) {
options.deprecation = true
options.encoding = 'UTF-8'
}
processResources {
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**", "**/jobs/**", "**lang.yml"]) {
expand projectVersion: project.version
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = ['-Xjvm-default=all']
}
}
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

85
build.gradle.kts Normal file
View File

@@ -0,0 +1,85 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
java
`java-library`
`maven-publish`
kotlin("jvm") version "2.1.0"
id("com.gradleup.shadow") version "8.3.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.gradleup.shadow")
repositories {
mavenLocal()
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.auxilor.io/repository/maven-public/")
maven("https://jitpack.io")
}
dependencies {
compileOnly("com.willfp:eco:6.56.0")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
}
java {
withSourcesJar()
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
tasks {
shadowJar {
relocate("com.willfp.libreforge.loader", "com.willfp.ecojobs.libreforge.loader")
relocate("com.willfp.ecomponent", "com.willfp.ecojobs.ecomponent")
}
compileKotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_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,20 +0,0 @@
group 'com.willfp'
version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.7.0'
compileOnly 'net.kyori:adventure-api:4.10.1'
compileOnly 'net.essentialsx:EssentialsX:2.19.0'
compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6'
}
build.dependsOn publishToMavenLocal
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}

View File

@@ -0,0 +1,40 @@
group = "com.willfp"
version = rootProject.version
dependencies {
compileOnly("io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.5")
implementation("com.willfp:ecomponent:1.3.0")
}
publishing {
publications {
register<MavenPublication>("maven") {
groupId = project.group.toString()
version = project.version.toString()
artifactId = rootProject.name
artifact(rootProject.tasks.shadowJar.get().archiveFile)
}
}
publishing {
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

@@ -1,36 +0,0 @@
package com.willfp.ecojobs
import com.willfp.ecojobs.api.EcoJobsAPI
import com.willfp.ecojobs.jobs.Job
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.jobs.getJobLevel
import com.willfp.ecojobs.jobs.getJobProgress
import com.willfp.ecojobs.jobs.getJobXP
import com.willfp.ecojobs.jobs.getJobXPRequired
import com.willfp.ecojobs.jobs.giveJobExperience
import com.willfp.ecojobs.jobs.hasJob
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
internal object EcoJobsAPIImpl : EcoJobsAPI {
override fun hasJob(player: OfflinePlayer, job: Job) = player.hasJob(job)
override fun getActiveJob(player: OfflinePlayer): Job? = player.activeJob
override fun getJobLevel(player: OfflinePlayer, job: Job) = player.getJobLevel(job)
override fun giveJobExperience(player: Player, job: Job, amount: Double) =
player.giveJobExperience(job, amount)
override fun giveJobExperience(player: Player, job: Job, amount: Double, applyMultipliers: Boolean) =
player.giveJobExperience(job, amount, noMultiply = !applyMultipliers)
override fun getJobProgress(player: OfflinePlayer, job: Job) =
player.getJobProgress(job)
override fun getJobXPRequired(player: OfflinePlayer, job: Job) =
player.getJobXPRequired(job)
override fun getJobXP(player: OfflinePlayer, job: Job) =
player.getJobXP(job)
}

View File

@@ -1,44 +1,78 @@
package com.willfp.ecojobs
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.core.placeholder.DynamicPlaceholder
import com.willfp.eco.core.placeholder.PlayerPlaceholder
import com.willfp.eco.util.toSingletonList
import com.willfp.ecojobs.commands.CommandEcojobs
import com.willfp.eco.util.savedDisplayName
import com.willfp.eco.util.toNiceString
import com.willfp.ecojobs.api.activeJobs
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.ecojobs.api.jobLimit
import com.willfp.ecojobs.commands.CommandEcoJobs
import com.willfp.ecojobs.commands.CommandJobs
import com.willfp.ecojobs.jobs.JobLevelListener
import com.willfp.ecojobs.jobs.JobTriggerXPGainListener
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.PriceHandler
import com.willfp.ecojobs.jobs.ResetOnQuitListener
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.jobs.activeJobLevel
import com.willfp.ecojobs.jobs.getJobLevel
import com.willfp.libreforge.LibReforgePlugin
import com.willfp.ecojobs.libreforge.ConditionHasActiveJob
import com.willfp.ecojobs.libreforge.ConditionHasJobLevel
import com.willfp.ecojobs.libreforge.EffectGiveJobXp
import com.willfp.ecojobs.libreforge.EffectJobXpMultiplier
import com.willfp.ecojobs.libreforge.FilterJob
import com.willfp.ecojobs.libreforge.TriggerGainJobXp
import com.willfp.ecojobs.libreforge.TriggerJoinJob
import com.willfp.ecojobs.libreforge.TriggerLeaveJob
import com.willfp.ecojobs.libreforge.TriggerLevelUpJob
import com.willfp.libreforge.SimpleProvidedHolder
import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.effects.Effects
import com.willfp.libreforge.filters.Filters
import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory
import com.willfp.libreforge.registerHolderProvider
import com.willfp.libreforge.registerSpecificHolderProvider
import com.willfp.libreforge.triggers.Triggers
import org.bukkit.entity.Player
import org.bukkit.event.Listener
import java.util.regex.Pattern
class EcoJobsPlugin : LibReforgePlugin() {
class EcoJobsPlugin : LibreforgePlugin() {
init {
instance = this
registerHolderProvider { it.activeJobLevel?.toSingletonList() ?: emptyList() }
}
override fun handleEnableAdditional() {
this.copyConfigs("jobs")
override fun loadConfigCategories(): List<ConfigCategory> {
return listOf(
Jobs
)
}
override fun handleEnable() {
Conditions.register(ConditionHasJobLevel)
Conditions.register(ConditionHasActiveJob)
Effects.register(EffectJobXpMultiplier)
Effects.register(EffectGiveJobXp)
Triggers.register(TriggerGainJobXp)
Triggers.register(TriggerLevelUpJob)
Triggers.register(TriggerJoinJob)
Triggers.register(TriggerLeaveJob)
Filters.register(FilterJob)
registerSpecificHolderProvider<Player> { player ->
player.activeJobs.map { it.getLevel(player.getJobLevel(it)) }.map {
SimpleProvidedHolder(it)
}
}
PlayerPlaceholder(
this,
"job"
) { it.activeJob?.name ?: "" }.register()
"limit"
) { it.jobLimit.toString() }.register()
PlayerPlaceholder(
this,
"job_level"
) { it.activeJobLevel?.level?.toString() ?: "" }.register()
PlayerPlaceholder(
this,
"job_id"
) { it.activeJob?.id ?: "" }.register()
"in_jobs"
) { it.activeJobs.size.toString() }.register()
PlayerPlaceholder(
this,
@@ -50,11 +84,33 @@ class EcoJobsPlugin : LibReforgePlugin() {
}
level.toString()
}.register()
DynamicPlaceholder(
this,
Pattern.compile("top_[a-z]+_[0-9]+_[a-z]+")
) {
val split = it.split("_")
val jobId = split.getOrNull(1) ?: return@DynamicPlaceholder "You must specify the job id!"
val job = Jobs.getByID(jobId) ?: return@DynamicPlaceholder "Invalid job id!"
val placeString = split.getOrNull(2) ?: return@DynamicPlaceholder "You must specify the place!"
val place = placeString.toIntOrNull() ?: return@DynamicPlaceholder "Invalid place!"
val type = split.getOrNull(3) ?: return@DynamicPlaceholder "You must specify the top type!"
val topEntry = job.getTop(place)
return@DynamicPlaceholder when (type) {
"name" -> topEntry?.player?.savedDisplayName
?: this.langYml.getFormattedString("top.name-empty")
"amount" -> topEntry?.amount?.toNiceString()
?: this.langYml.getFormattedString("top.amount-empty")
else -> "Invalid type: $type! Available types: name/amount"
}
}.register()
}
override fun loadPluginCommands(): List<PluginCommand> {
return listOf(
CommandEcojobs(this),
CommandEcoJobs(this),
CommandJobs(this)
)
}
@@ -62,7 +118,6 @@ class EcoJobsPlugin : LibReforgePlugin() {
override fun loadListeners(): List<Listener> {
return listOf(
JobLevelListener(this),
JobTriggerXPGainListener,
ResetOnQuitListener,
PriceHandler
)

View File

@@ -1,117 +1,192 @@
@file:JvmName("EcoJobsAPI")
package com.willfp.ecojobs.api
import com.willfp.ecojobs.EcoJobsAPIImpl
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.event.PlayerJobExpGainEvent
import com.willfp.ecojobs.api.event.PlayerJobJoinEvent
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
import com.willfp.ecojobs.jobs.Job
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.getNumericalPermission
import com.willfp.ecojobs.jobs.jobExperienceMultiplier
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import kotlin.math.abs
interface EcoJobsAPI {
/**
* Get if a player has a job.
*
* @param player The player.
* @param job The job.
* @return If the player has the job unlocked.
*/
fun hasJob(
player: OfflinePlayer,
job: Job
): Boolean
private val plugin = EcoJobsPlugin.instance
/**
* Get a player's active job.
*
* @param player The player.
* @return The active job.
*/
fun getActiveJob(
player: OfflinePlayer
): Job?
/*
/**
* Get a player's level of a certain job.
*
* @param player The player.
* @param job The job.
* @return The level.
*/
fun getJobLevel(
player: OfflinePlayer,
job: Job
): Int
The old key is around for backwards compatibility with 1.x.x.
/**
* Give job experience to a player.
*
* @param player The player.
* @param job The job.
* @param amount The amount of experience to give.
*/
fun giveJobExperience(
player: Player,
job: Job,
amount: Double
)
*/
/**
* Give job experience to a player.
*
* @param player The player.
* @param job The job.
* @param amount The amount of experience to give.
* @param applyMultipliers If multipliers should be applied.
*/
fun giveJobExperience(
player: Player,
job: Job,
amount: Double,
applyMultipliers: Boolean
)
private val legacyActiveJobKey: PersistentDataKey<String> = PersistentDataKey(
plugin.namespacedKeyFactory.create("active_job"), PersistentDataKeyType.STRING, ""
)
/**
* Get progress to next level between 0 and 1, where 0 is none and 1 is complete.
*
* @param player The player.
* @param job The job.
* @return The progress.
*/
fun getJobProgress(
player: OfflinePlayer,
job: Job
): Double
private val activeJobsKey: PersistentDataKey<List<String>> = PersistentDataKey(
plugin.namespacedKeyFactory.create("active_jobs"), PersistentDataKeyType.STRING_LIST, listOf()
)
/**
* Get the experience required to advance to the next level.
*
* @param player The player.
* @param job The job.
* @return The experience required.
*/
fun getJobXPRequired(
player: OfflinePlayer,
job: Job
): Int
/**
* The job limit.
*/
val Player.jobLimit: Int
get() {
return this.getNumericalPermission("ecojobs.limit", plugin.configYml.getDouble("jobs.limit")).toInt()
}
/**
* Get experience to the next level.
*
* @param player The player.
* @param job The job.
* @return The experience.
*/
fun getJobXP(
player: OfflinePlayer,
job: Job
): Double
/**
* If a player can join a job.
*/
fun Player.canJoinJob(job: Job): Boolean {
return this.activeJobs.size < this.jobLimit && job !in this.activeJobs && this.hasJob(job)
}
companion object {
/**
* Get the instance of the API.
*
* @return The API.
*/
@JvmStatic
val instance: EcoJobsAPI
get() = EcoJobsAPIImpl
/**
* Get if a job is unlocked.
*/
fun OfflinePlayer.hasJob(job: Job) = this.getJobLevel(job) > 0
/**
* Get if a player has a job active.
*/
fun OfflinePlayer.hasJobActive(job: Job) = job in this.activeJobs
/**
* Get a player's active jobs.
*/
val OfflinePlayer.activeJobs: Collection<Job>
get() {
if (this.profile.read(legacyActiveJobKey).isNotBlank()) {
this.profile.write(activeJobsKey, listOf(this.profile.read(legacyActiveJobKey)))
this.profile.write(legacyActiveJobKey, "")
}
return this.profile.read(activeJobsKey).mapNotNull { Jobs.getByID(it) }
}
/**
* Join a job.
*/
fun OfflinePlayer.joinJob(job: Job) {
val event = PlayerJobJoinEvent(this, job)
Bukkit.getPluginManager().callEvent(event)
if (!event.isCancelled) {
this.profile.write(activeJobsKey, this.activeJobs.plus(job).map { it.id })
}
}
/**
* Leave a job.
*/
fun OfflinePlayer.leaveJob(job: Job) {
if (job !in this.activeJobs) {
return
}
val event = PlayerJobLeaveEvent(this, job)
Bukkit.getPluginManager().callEvent(event)
if (!event.isCancelled) {
this.forceLeaveJob(job)
}
}
/**
* Leave a job without checking.
*/
fun OfflinePlayer.forceLeaveJob(job: Job) {
this.profile.write(activeJobsKey, this.activeJobs.minus(job).map { it.id })
}
/**
* Get the level of a certain job.
*/
fun OfflinePlayer.getJobLevel(job: Job) = this.profile.read(job.levelKey)
/**
* Set the level of a certain job.
*/
fun OfflinePlayer.setJobLevel(job: Job, level: Int) = this.profile.write(job.levelKey, level)
/**
* Get current job experience.
*/
fun OfflinePlayer.getJobXP(job: Job) = this.profile.read(job.xpKey)
/**
* Set current job experience.
*/
fun OfflinePlayer.setJobXP(job: Job, xp: Double) = this.profile.write(job.xpKey, xp)
/**
* Reset a job.
*/
fun OfflinePlayer.resetJob(job: Job) {
this.setJobLevel(job, 1)
this.setJobXP(job, 0.0)
}
/**
* Get the experience required to advance to the next level.
*/
fun OfflinePlayer.getJobXPRequired(job: Job) = job.getFormattedExpForLevel(this.getJobLevel(job) + 1)
/**
* Get progress to next level between 0 and 1, where 0 is none and 1 is complete.
*/
fun OfflinePlayer.getJobProgress(job: Job): Double {
val currentXP = this.getJobXP(job)
val requiredXP = job.getExpForLevel(this.getJobLevel(job) + 1)
return currentXP / requiredXP
}
/**
* Give job experience.
*/
@JvmOverloads
fun Player.giveJobExperience(job: Job, experience: Double, withMultipliers: Boolean = true) {
val exp = abs(
if (withMultipliers) experience * this.jobExperienceMultiplier
else experience
)
val gainEvent = PlayerJobExpGainEvent(this, job, exp, !withMultipliers)
Bukkit.getPluginManager().callEvent(gainEvent)
if (gainEvent.isCancelled) {
return
}
this.giveExactJobExperience(job, gainEvent.amount)
}
/**
* Give exact job experience, without calling PlayerJobExpGainEvent.
*/
fun Player.giveExactJobExperience(job: Job, experience: Double) {
val level = this.getJobLevel(job)
val progress = this.getJobXP(job) + experience
if (progress >= job.getExpForLevel(level + 1) && level + 1 <= job.maxLevel) {
val overshoot = progress - job.getExpForLevel(level + 1)
this.setJobXP(job, 0.0)
this.setJobLevel(job, level + 1)
val levelUpEvent = PlayerJobLevelUpEvent(this, job, level + 1)
Bukkit.getPluginManager().callEvent(levelUpEvent)
this.giveExactJobExperience(job, overshoot)
} else {
this.setJobXP(job, progress)
}
}

View File

@@ -8,8 +8,7 @@ import org.bukkit.event.HandlerList
class PlayerJobJoinEvent(
val player: OfflinePlayer,
override val job: Job,
val oldJob: Job?
override val job: Job
) : Event(), Cancellable, JobEvent {
private var cancelled = false

View File

@@ -0,0 +1,20 @@
package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import org.bukkit.command.CommandSender
class CommandEcoJobs(plugin: EcoPlugin) : PluginCommand(plugin, "ecojobs", "ecojobs.command.ecojobs", false) {
init {
this.addSubcommand(CommandReload(plugin))
.addSubcommand(CommandUnlock(plugin))
.addSubcommand(CommandGiveXP(plugin))
.addSubcommand(CommandReset(plugin))
}
override fun onExecute(sender: CommandSender, args: List<String>) {
sender.sendMessage(
plugin.langYml.getMessage("invalid-command")
)
}
}

View File

@@ -1,34 +0,0 @@
package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.libreforge.LibReforgePlugin
import com.willfp.libreforge.lrcdb.CommandExport
import com.willfp.libreforge.lrcdb.CommandImport
import com.willfp.libreforge.lrcdb.ExportableConfig
import org.bukkit.command.CommandSender
class CommandEcojobs(plugin: LibReforgePlugin) : PluginCommand(plugin, "ecojobs", "ecojobs.command.ecojobs", false) {
init {
this.addSubcommand(CommandReload(plugin))
.addSubcommand(CommandUnlock(plugin))
.addSubcommand(CommandGiveXP(plugin))
.addSubcommand(CommandReset(plugin))
.addSubcommand(CommandImport("jobs", plugin))
.addSubcommand(CommandExport(plugin) {
Jobs.values().map {
ExportableConfig(
it.id,
it.config
)
}
})
}
override fun onExecute(sender: CommandSender, args: List<String>) {
sender.sendMessage(
plugin.langYml.getMessage("invalid-command")
)
}
}

View File

@@ -5,9 +5,9 @@ import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.eco.util.toNiceString
import com.willfp.ecojobs.api.giveExactJobExperience
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.giveExactJobExperience
import com.willfp.ecojobs.jobs.hasJob
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender

View File

@@ -2,9 +2,9 @@ package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.JobsGUI
import com.willfp.ecojobs.jobs.hasJob
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil

View File

@@ -3,9 +3,11 @@ package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.ecojobs.api.canJoinJob
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.joinJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.jobs.hasJob
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
@@ -28,13 +30,13 @@ class CommandJoin(plugin: EcoPlugin) : Subcommand(plugin, "join", "ecojobs.comma
return
}
if (player.activeJob == job) {
if (player.hasJobActive(job)) {
player.sendMessage(plugin.langYml.getMessage("job-already-joined"))
return
}
if (player.activeJob != null) {
player.sendMessage(plugin.langYml.getMessage("leave-current-job"))
if (!player.canJoinJob(job)) {
player.sendMessage(plugin.langYml.getMessage("cannot-join-job"))
return
}
@@ -42,7 +44,8 @@ class CommandJoin(plugin: EcoPlugin) : Subcommand(plugin, "join", "ecojobs.comma
plugin.langYml.getMessage("joined-job", StringUtils.FormatOption.WITHOUT_PLACEHOLDERS)
.replace("%job%", job.name)
)
player.activeJob = job
player.joinJob(job)
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
@@ -51,6 +54,7 @@ class CommandJoin(plugin: EcoPlugin) : Subcommand(plugin, "join", "ecojobs.comma
}
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Jobs.values().filter { sender.hasJob(it) }.map { it.id }
}

View File

@@ -2,24 +2,46 @@ package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.api.activeJobs
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.leaveJob
import com.willfp.ecojobs.jobs.Jobs
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandLeave(plugin: EcoPlugin) : Subcommand(plugin, "leave", "ecojobs.command.leave", true) {
override fun onExecute(player: CommandSender, args: List<String>) {
player as Player
if (player.activeJob == null) {
if (args.isEmpty()) {
player.sendMessage(plugin.langYml.getMessage("needs-job"))
return
}
if (player.activeJobs.isEmpty()) {
player.sendMessage(plugin.langYml.getMessage("no-job"))
return
}
val job = player.activeJob ?: return
val id = args[0]
player.activeJob = null
val job = Jobs.getByID(id)
if (player.activeJob == null) {
if (job == null || !player.hasJob(job)) {
player.sendMessage(plugin.langYml.getMessage("invalid-job"))
return
}
if (!player.hasJobActive(job)) {
player.sendMessage(plugin.langYml.getMessage("not-in-job"))
return
}
player.leaveJob(job)
if (!player.hasJobActive(job)) {
player.sendMessage(
plugin.langYml.getMessage("left-job")
.replace("%job%", job.name)
@@ -31,4 +53,27 @@ class CommandLeave(plugin: EcoPlugin) : Subcommand(plugin, "leave", "ecojobs.com
)
}
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
if (sender !is Player) {
return emptyList()
}
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Jobs.values().filter { sender.hasJobActive(it) }.map { it.id }
}
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Jobs.values().filter { sender.hasJobActive(it) }.map { it.id },
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -4,12 +4,13 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecojobs.api.forceLeaveJob
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.resetJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.jobs.hasJob
import com.willfp.ecojobs.jobs.resetJob
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.util.StringUtil
class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.command.reset", false) {
override fun onExecute(sender: CommandSender, args: List<String>) {
@@ -24,16 +25,68 @@ class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.com
}
val playerName = args[0]
val jobName = args[1]
// Reset all jobs for all players
if (playerName.equals("all", ignoreCase = true) && jobName.equals("all", ignoreCase = true)) {
Bukkit.getOnlinePlayers().forEach { player ->
Jobs.values().forEach { job ->
if (player.hasJob(job)) {
player.forceLeaveJob(job)
player.resetJob(job)
}
}
}
sender.sendMessage(plugin.langYml.getMessage("reset-all-players-all-jobs"))
return
}
// Reset a specific job for all players
if (playerName.equals("all", ignoreCase = true)) {
val job = Jobs.getByID(jobName)
if (job == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-job"))
return
}
Bukkit.getOnlinePlayers().forEach { player ->
if (player.hasJob(job)) {
player.forceLeaveJob(job)
player.resetJob(job)
}
}
sender.sendMessage(
plugin.langYml.getMessage("reset-all-players")
.replace("%job%", job.name)
)
return
}
// Reset all jobs for a specific player
val player = Bukkit.getPlayer(playerName)
if (player == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-player"))
return
}
val job = Jobs.getByID(args[1])
if (jobName.equals("all", ignoreCase = true)) {
Jobs.values().forEach { job ->
if (player.hasJob(job)) {
player.forceLeaveJob(job)
player.resetJob(job)
}
}
sender.sendMessage(
plugin.langYml.getMessage("reset-all-jobs")
.replace("%player%", player.savedDisplayName)
)
return
}
// Reset a specific job for a specific player
val job = Jobs.getByID(jobName)
if (job == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-job"))
return
@@ -44,9 +97,7 @@ class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.com
return
}
if (player.activeJob == job) {
player.activeJob = null
}
player.forceLeaveJob(job)
player.resetJob(job)
sender.sendMessage(
@@ -57,12 +108,23 @@ class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.com
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.size == 1) {
return Bukkit.getOnlinePlayers().map { it.name }
StringUtil.copyPartialMatches(
args[0],
listOf("all") union Bukkit.getOnlinePlayers().map { player -> player.name },
completions
)
return completions
}
if (args.size == 2) {
return Jobs.values().map { it.id }
StringUtil.copyPartialMatches(
args[1],
listOf("all") union Jobs.values().map { it.id },
completions
)
return completions
}
return emptyList()

View File

@@ -4,9 +4,9 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.setJobLevel
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.hasJob
import com.willfp.ecojobs.jobs.setJobLevel
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.util.StringUtil

View File

@@ -4,54 +4,67 @@ import com.github.benmanes.caffeine.cache.Caffeine
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.placeholder.PlayerPlaceholder
import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder
import com.willfp.eco.core.placeholder.context.placeholderContext
import com.willfp.eco.core.price.ConfiguredPrice
import com.willfp.eco.core.price.impl.PriceEconomy
import com.willfp.eco.core.registry.Registrable
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.NumberUtils.evaluateExpression
import com.willfp.eco.util.formatEco
import com.willfp.eco.util.toNiceString
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.event.PlayerJobExpGainEvent
import com.willfp.ecojobs.api.event.PlayerJobJoinEvent
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
import com.willfp.ecojobs.api.activeJobs
import com.willfp.ecojobs.api.canJoinJob
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.ecojobs.api.getJobProgress
import com.willfp.ecojobs.api.getJobXP
import com.willfp.ecojobs.api.getJobXPRequired
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.jobLimit
import com.willfp.ecojobs.util.LevelInjectable
import com.willfp.libreforge.ViolationContext
import com.willfp.libreforge.conditions.ConditionList
import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.conditions.ConfiguredCondition
import com.willfp.libreforge.effects.ConfiguredEffect
import com.willfp.libreforge.counters.Counters
import com.willfp.libreforge.effects.EffectList
import com.willfp.libreforge.effects.Effects
import com.willfp.libreforge.events.TriggerPreProcessEvent
import com.willfp.libreforge.triggers.Counters
import com.willfp.libreforge.effects.executors.impl.NormalExecutorFactory
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import java.time.Duration
import java.util.Objects
import java.util.concurrent.TimeUnit
import kotlin.math.abs
class Job(
val id: String,
val config: Config,
private val plugin: EcoJobsPlugin
) {
) : Registrable {
private val topCache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofSeconds(plugin.configYml.getInt("leaderboard-cache-lifetime").toLong()))
.build<Int, LeaderboardCacheEntry?>()
val name = config.getFormattedString("name")
val description = config.getFormattedString("description")
val isUnlockedByDefault = config.getBool("unlocked-by-default")
val resetsOnQuit = config.getBool("reset-on-quit")
val joinPrice = ConfiguredPrice.create(config.getSubsection("join-price")) ?: ConfiguredPrice(
PriceEconomy(config.getDouble("join-price")),
""
PriceEconomy(config.getDouble("join-price")), ""
)
val leavePrice = ConfiguredPrice.create(config.getSubsection("leave-price")) ?: ConfiguredPrice(
PriceEconomy(config.getDouble("leave-price")),
""
PriceEconomy(config.getDouble("leave-price")), ""
)
val levelKey: PersistentDataKey<Int> = PersistentDataKey(
@@ -61,14 +74,14 @@ class Job(
)
val xpKey: PersistentDataKey<Double> = PersistentDataKey(
EcoJobsPlugin.instance.namespacedKeyFactory.create("${id}_xp"),
PersistentDataKeyType.DOUBLE,
0.0
EcoJobsPlugin.instance.namespacedKeyFactory.create("${id}_xp"), PersistentDataKeyType.DOUBLE, 0.0
)
private val levelXpRequirements = listOf(0) + config.getInts("level-xp-requirements")
private val xpFormula = config.getStringOrNull("xp-formula")
val maxLevel = levelXpRequirements.size
private val levelXpRequirements = config.getDoublesOrNull("level-xp-requirements")
val maxLevel = config.getIntOrNull("max-level") ?: levelXpRequirements?.size ?: Int.MAX_VALUE
val levelGUI = JobLevelGUI(plugin, this)
@@ -76,53 +89,107 @@ class Job(
private val baseItem: ItemStack = Items.lookup(config.getString("icon")).item
private val effects: Set<ConfiguredEffect>
private val conditions: Set<ConfiguredCondition>
private val effects: EffectList
private val conditions: ConditionList
private val levels = Caffeine.newBuilder()
.build<Int, JobLevel>()
private val effectsDescription = Caffeine.newBuilder()
.build<Int, List<String>>()
private val rewardsDescription = Caffeine.newBuilder()
.build<Int, List<String>>()
private val levelUpMessages = Caffeine.newBuilder()
.build<Int, List<String>>()
private val levels = Caffeine.newBuilder().build<Int, JobLevel>()
private val effectsDescription = Caffeine.newBuilder().build<Int, List<String>>()
private val rewardsDescription = Caffeine.newBuilder().build<Int, List<String>>()
private val levelUpMessages = Caffeine.newBuilder().build<Int, List<String>>()
private val levelCommands = mutableMapOf<Int, MutableList<String>>()
private val levelPlaceholders = config.getSubsections("level-placeholders")
.map { sub ->
LevelPlaceholder(
sub.getString("id")
) {
NumberUtils.evaluateExpression(
sub.getString("value")
.replace("%level%", it.toString())
).toNiceString()
}
private val levelPlaceholders = config.getSubsections("level-placeholders").map { sub ->
LevelPlaceholder(
sub.getString("id")
) {
NumberUtils.evaluateExpression(
sub.getString("value").replace("%level%", it.toString())
).toNiceString()
}
}
private val jobXpGains = config.getSubsections("xp-gain-methods").mapNotNull {
Counters.compile(it, "Job $id")
Counters.compile(it, ViolationContext(plugin, "Job $id"))
}
init {
config.injectPlaceholders(
PlayerStaticPlaceholder(
"level"
) { p ->
p.getJobLevel(this).toString()
}
if (xpFormula == null && levelXpRequirements == null) {
throw InvalidConfigurationException("Skill $id has no requirements or xp formula")
}
config.injectPlaceholders(PlayerStaticPlaceholder(
"level"
) { p ->
p.getJobLevel(this).toString()
})
effects = Effects.compile(
config.getSubsections("effects"),
ViolationContext(plugin, "Job $id")
)
effects = config.getSubsections("effects").mapNotNull {
Effects.compile(it, "Job $id")
}.toSet()
conditions = Conditions.compile(
config.getSubsections("conditions"),
ViolationContext(plugin, "Job $id")
)
conditions = config.getSubsections("conditions").mapNotNull {
Conditions.compile(it, "Job $id")
}.toSet()
manageLevelCommands(config)
PlayerPlaceholder(
plugin, "${id}_percentage_progress"
) {
(it.getJobProgress(this) * 100).toNiceString()
}.register()
PlayerPlaceholder(
plugin, id
) {
it.getJobLevel(this).toString()
}.register()
PlayerPlaceholder(
plugin, "${id}_current_xp"
) {
NumberUtils.format(it.getJobXP(this))
}.register()
PlayerPlaceholder(
plugin, "${id}_required_xp"
) {
it.getJobXPRequired(this).toString()
}.register()
PlayerlessPlaceholder(
plugin, "${id}_name"
) {
this.name
}.register()
PlayerPlaceholder(
plugin, "${id}_level"
) {
it.getJobLevel(this).toString()
}.register()
PlayerPlaceholder(
plugin, "${id}_active"
) {
it.hasJobActive(this).toString()
}.register()
PlayerPlaceholder(
plugin, "${id}_total_players"
) {
Bukkit.getOfflinePlayers().count { this in it.activeJobs }.toString()
}.register()
}
@Deprecated("Use level-up-effects instead")
private fun manageLevelCommands(config: Config) {
if (config.getStrings("level-commands").isNotEmpty()) {
plugin.logger.warning("$id job: The `level-commands` key is deprecated and will be removed in future versions. Switch to `level-up-effects` instead. Refer to the wiki for more info.")
}
for (string in config.getStrings("level-commands")) {
val split = string.split(":")
@@ -141,59 +208,36 @@ class Job(
levelCommands[level] = commands
}
}
}
PlayerPlaceholder(
plugin,
"${id}_percentage_progress"
) {
(it.getJobProgress(this) * 100).toNiceString()
}.register()
val levelUpEffects = Effects.compileChain(
config.getSubsections("level-up-effects"),
NormalExecutorFactory.create(),
ViolationContext(plugin, "Job $id level-up-effects")
)
PlayerPlaceholder(
plugin,
id
) {
it.getJobLevel(this).toString()
}.register()
val joinEffects = Effects.compileChain(
config.getSubsections("join-effects"),
NormalExecutorFactory.create(),
ViolationContext(plugin, "Job $id join-effects")
)
PlayerPlaceholder(
plugin,
"${id}_current_xp"
) {
NumberUtils.format(it.getJobXP(this))
}.register()
val leaveEffects = Effects.compileChain(
config.getSubsections("leave-effects"),
NormalExecutorFactory.create(),
ViolationContext(plugin, "Job $id leave-effects")
)
PlayerPlaceholder(
plugin,
"${id}_required_xp"
) {
it.getJobXPRequired(this).toString()
}.register()
override fun onRegister() {
jobXpGains.forEach { it.bind(JobXPAccumulator(this)) }
}
PlayerlessPlaceholder(
plugin,
"${id}_name"
) {
this.name
}.register()
PlayerPlaceholder(
plugin,
"${id}_level"
) {
it.getJobLevel(this).toString()
}.register()
PlayerPlaceholder(
plugin,
"${id}_total_players"
) {
Bukkit.getOfflinePlayers().count { it.activeJob == this }.toString()
}.register()
override fun onRemove() {
jobXpGains.forEach { it.unbind() }
}
fun getLevel(level: Int): JobLevel = levels.get(level) {
JobLevel(this, it, effects, conditions)
JobLevel(plugin, this, it, effects, conditions)
}
private fun getLevelUpMessages(level: Int, whitespace: Int = 0): List<String> = levelUpMessages.get(level) {
@@ -208,13 +252,11 @@ class Job(
}
}
this.config.getStrings("level-up-messages.$highestConfiguredLevel")
.map {
levelPlaceholders.format(it, level)
}
.map {
" ".repeat(whitespace) + it
}
this.config.getStrings("level-up-messages.$highestConfiguredLevel").map {
levelPlaceholders.format(it, level)
}.map {
" ".repeat(whitespace) + it
}
}
private fun getEffectsDescription(level: Int, whitespace: Int = 0): List<String> = effectsDescription.get(level) {
@@ -229,13 +271,11 @@ class Job(
}
}
this.config.getStrings("effects-description.$highestConfiguredLevel")
.map {
levelPlaceholders.format(it, level)
}
.map {
" ".repeat(whitespace) + it
}
this.config.getStrings("effects-description.$highestConfiguredLevel").map {
levelPlaceholders.format(it, level)
}.map {
" ".repeat(whitespace) + it
}
}
private fun getRewardsDescription(level: Int, whitespace: Int = 0): List<String> = rewardsDescription.get(level) {
@@ -250,53 +290,36 @@ class Job(
}
}
this.config.getStrings("rewards-description.$highestConfiguredLevel")
.map {
levelPlaceholders.format(it, level)
}
.map {
" ".repeat(whitespace) + it
}
this.config.getStrings("rewards-description.$highestConfiguredLevel").map {
levelPlaceholders.format(it, level)
}.map {
" ".repeat(whitespace) + it
}
}
private fun getLeaveLore(level: Int, whitespace: Int = 0): List<String> =
this.config.getStrings("leave-lore")
.map {
levelPlaceholders.format(it, level)
}
.map {
" ".repeat(whitespace) + it
}
private fun getLeaveLore(level: Int, whitespace: Int = 0): List<String> = this.config.getStrings("leave-lore").map {
levelPlaceholders.format(it, level)
}.map {
" ".repeat(whitespace) + it
}
private fun getJoinLore(level: Int, whitespace: Int = 0): List<String> =
this.config.getStrings("join-lore")
.map {
levelPlaceholders.format(it, level)
}
.map {
" ".repeat(whitespace) + it
}
private fun getJoinLore(level: Int, whitespace: Int = 0): List<String> = this.config.getStrings("join-lore").map {
levelPlaceholders.format(it, level)
}.map {
" ".repeat(whitespace) + it
}
fun injectPlaceholdersInto(lore: List<String>, player: Player, forceLevel: Int? = null): List<String> {
val withPlaceholders = lore
.map {
it.replace("%percentage_progress%", (player.getJobProgress(this) * 100).toNiceString())
.replace("%current_xp%", player.getJobXP(this).toNiceString())
.replace("%required_xp%", this.getExpForLevel(player.getJobLevel(this) + 1).let { req ->
if (req == Int.MAX_VALUE) {
plugin.langYml.getFormattedString("infinity")
} else {
req.toNiceString()
}
}
)
.replace("%description%", this.description)
.replace("%job%", this.name)
.replace("%level%", (forceLevel ?: player.getJobLevel(this)).toString())
.replace("%join_price%", this.joinPrice.getDisplay(player))
.replace("%leave_price%", this.leavePrice.getDisplay(player))
}
.toMutableList()
val withPlaceholders = lore.map {
it.replace("%percentage_progress%", (player.getJobProgress(this) * 100).toNiceString())
.replace("%current_xp%", player.getJobXP(this).toNiceString())
.replace("%required_xp%", this.getFormattedExpForLevel(player.getJobLevel(this) + 1))
.replace("%description%", this.description).replace("%job%", this.name)
.replace("%level%", (forceLevel ?: player.getJobLevel(this)).toString())
.replace("%level_numeral%", NumberUtils.toNumeral(forceLevel ?: player.getJobLevel(this)))
.replace("%join_price%", this.joinPrice.getDisplay(player))
.replace("%leave_price%", this.leavePrice.getDisplay(player))
}.toMutableList()
val processed = mutableListOf<List<String>>()
@@ -328,45 +351,65 @@ class Job(
val level = player.getJobLevel(this)
return ItemStackBuilder(base)
.setDisplayName(
plugin.configYml.getFormattedString("gui.job-icon.name")
.replace("%level%", level.toString())
.replace("%job%", this.name)
)
.addLoreLines {
injectPlaceholdersInto(plugin.configYml.getStrings("gui.job-icon.lore"), player) +
when (player.activeJob) {
this -> plugin.configYml.getStrings("gui.job-icon.active-lore")
null -> plugin.configYml.getStrings("gui.job-icon.join-lore")
else -> emptyList()
}
return ItemStackBuilder(base).setDisplayName(
plugin.configYml.getFormattedString("gui.job-icon.name").replace("%level%", level.toString())
.replace("%level_numeral%", NumberUtils.toNumeral(level)).replace("%job%", this.name)
).addLoreLines {
injectPlaceholdersInto(
plugin.configYml.getStrings("gui.job-icon.lore"), player
) + if (player.hasJobActive(this)) {
plugin.configYml.getStrings("gui.job-icon.active-lore")
} else if (player.canJoinJob(this)) {
plugin.configYml.getStrings("gui.job-icon.join-lore")
} else if (player.activeJobs.size == player.jobLimit) {
plugin.configYml.getStrings("gui.job-icon.too-many-jobs-lore")
} else {
emptyList()
}
.build()
}.build()
}
fun getJobInfoIcon(player: Player): ItemStack {
val base = baseItem.clone()
return ItemStackBuilder(base)
.setDisplayName(
plugin.configYml.getFormattedString("gui.job-info.active.name")
.replace("%level%", player.getJobLevel(this).toString())
.replace("%job%", this.name)
)
.addLoreLines {
injectPlaceholdersInto(plugin.configYml.getStrings("gui.job-info.active.lore"), player)
}
.build()
return ItemStackBuilder(base).setDisplayName(
plugin.configYml.getFormattedString("gui.job-info.active.name")
.replace("%level%", player.getJobLevel(this).toString())
.replace("%level_numeral%", NumberUtils.toNumeral(player.getJobLevel(this))).replace("%job%", this.name)
).addLoreLines {
injectPlaceholdersInto(plugin.configYml.getStrings("gui.job-info.active.lore"), player)
}.build()
}
fun getExpForLevel(level: Int): Int {
if (level < 1 || level > maxLevel) {
return Int.MAX_VALUE
/**
* Get the XP required to reach the next level, if currently at [level].
*/
fun getExpForLevel(level: Int): Double {
if (xpFormula != null) {
return evaluateExpression(
xpFormula,
placeholderContext(
injectable = LevelInjectable(level)
)
)
}
return levelXpRequirements[level - 1]
if (levelXpRequirements != null) {
return levelXpRequirements.getOrNull(level) ?: Double.POSITIVE_INFINITY
}
return Double.POSITIVE_INFINITY
}
fun getFormattedExpForLevel(level: Int): String {
val required = getExpForLevel(level)
return if (required.isInfinite()) {
plugin.langYml.getFormattedString("infinity")
} else {
required.toNiceString()
}
}
@Deprecated("Use level-up-effects instead")
fun executeLevelCommands(player: Player, level: Int) {
val commands = levelCommands[level] ?: emptyList()
@@ -375,8 +418,16 @@ class Job(
}
}
fun getXP(event: TriggerPreProcessEvent): Double {
return jobXpGains.sumOf { it.getCount(event) }
fun getTop(place: Int): LeaderboardCacheEntry? {
return topCache.get(place) {
val players = Bukkit.getOfflinePlayers().sortedByDescending { it.getJobLevel(this) }
val target = players.getOrNull(place - 1) ?: return@get null
return@get LeaderboardCacheEntry(target, target.getJobLevel(this))
}
}
override fun getID(): String {
return this.id
}
override fun equals(other: Any?): Boolean {
@@ -393,12 +444,16 @@ class Job(
}
private class LevelPlaceholder(
val id: String,
private val function: (Int) -> String
val id: String, private val function: (Int) -> String
) {
operator fun invoke(level: Int) = function(level)
}
data class LeaderboardCacheEntry(
val player: OfflinePlayer,
val amount: Int
)
private fun Collection<LevelPlaceholder>.format(string: String, level: Int): String {
var process = string
for (placeholder in this) {
@@ -407,143 +462,5 @@ private fun Collection<LevelPlaceholder>.format(string: String, level: Int): Str
return process
}
private val activeJobKey: PersistentDataKey<String> = PersistentDataKey(
EcoJobsPlugin.instance.namespacedKeyFactory.create("active_job"),
PersistentDataKeyType.STRING,
""
)
fun OfflinePlayer.getJobLevelObject(job: Job): JobLevel = job.getLevel(this.getJobLevel(job))
var OfflinePlayer.activeJob: Job?
get() = Jobs.getByID(this.profile.read(activeJobKey))
set(job) {
val oldJob = this.activeJob
if (oldJob != job) {
// Have to check for oldJob too to have null safety
if (job == null && oldJob != null) {
val event = PlayerJobLeaveEvent(this, oldJob)
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) {
return
}
}
// Not using else because null safety as well
if (job != null) {
val event = PlayerJobJoinEvent(this, job, oldJob)
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) {
return
}
}
}
this.profile.write(activeJobKey, job?.id ?: "")
}
val OfflinePlayer.activeJobLevel: JobLevel?
get() {
val active = this.activeJob ?: return null
return this.getJobLevelObject(active)
}
fun OfflinePlayer.getJobLevel(job: Job): Int =
this.profile.read(job.levelKey)
fun OfflinePlayer.setJobLevel(job: Job, level: Int) =
this.profile.write(job.levelKey, level)
fun OfflinePlayer.resetJob(job: Job) {
this.setJobLevel(job, 1)
this.setJobXP(job, 0.0)
}
fun OfflinePlayer.getJobProgress(job: Job): Double {
val currentXP = this.getJobXP(job)
val requiredXP = job.getExpForLevel(this.getJobLevel(job) + 1)
return currentXP / requiredXP
}
fun OfflinePlayer.getJobLevelObject(job: Job): JobLevel =
job.getLevel(this.getJobLevel(job))
fun OfflinePlayer.hasJob(job: Job): Boolean =
this.getJobLevel(job) > 0
fun OfflinePlayer.getJobXP(job: Job): Double =
this.profile.read(job.xpKey)
fun OfflinePlayer.setJobXP(job: Job, xp: Double) =
this.profile.write(job.xpKey, xp)
fun OfflinePlayer.getJobXPRequired(job: Job): Int =
job.getExpForLevel(this.getJobLevel(job) + 1)
private val expMultiplierCache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
.build<Player, Double> {
it.cacheJobExperienceMultiplier()
}
val Player.jobExperienceMultiplier: Double
get() = expMultiplierCache.get(this)
private fun Player.cacheJobExperienceMultiplier(): Double {
if (this.hasPermission("ecojobs.xpmultiplier.quadruple")) {
return 4.0
}
if (this.hasPermission("ecojobs.xpmultiplier.triple")) {
return 3.0
}
if (this.hasPermission("ecojobs.xpmultiplier.double")) {
return 2.0
}
if (this.hasPermission("ecojobs.xpmultiplier.50percent")) {
return 1.5
}
val prefix = "ecojobs.xpmultiplier."
for (permissionAttachmentInfo in this.effectivePermissions) {
val permission = permissionAttachmentInfo.permission
if (permission.startsWith(prefix)) {
return ((permission.substring(permission.lastIndexOf(".") + 1).toDoubleOrNull() ?: 100.0) / 100) + 1
}
}
return 1.0
}
fun Player.giveJobExperience(job: Job, experience: Double, noMultiply: Boolean = false) {
val exp = abs(if (noMultiply) experience else experience * this.jobExperienceMultiplier)
val gainEvent = PlayerJobExpGainEvent(this, job, exp, !noMultiply)
Bukkit.getPluginManager().callEvent(gainEvent)
if (gainEvent.isCancelled) {
return
}
this.giveExactJobExperience(job, gainEvent.amount)
}
fun Player.giveExactJobExperience(job: Job, experience: Double) {
val level = this.getJobLevel(job)
val progress = this.getJobXP(job) + experience
if (progress >= job.getExpForLevel(level + 1) && level + 1 <= job.maxLevel) {
val overshoot = progress - job.getExpForLevel(level + 1)
this.setJobXP(job, 0.0)
this.setJobLevel(job, level + 1)
val levelUpEvent = PlayerJobLevelUpEvent(this, job, level + 1)
Bukkit.getPluginManager().callEvent(levelUpEvent)
this.giveExactJobExperience(job, overshoot)
} else {
this.setJobXP(job, progress)
}
}

View File

@@ -9,6 +9,8 @@ import com.willfp.eco.core.gui.slot.MaskItems
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.util.formatEco
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.leaveJob
import org.bukkit.entity.Player
class JobLeaveGUI(
@@ -59,9 +61,9 @@ class JobLeaveGUI(
.build()
}) {
onLeftClick { player, _, _, _ ->
player.activeJob = null
player.leaveJob(job)
if (player.activeJob == null) {
if (!player.hasJobActive(job)) {
player.sendMessage(
plugin.langYml.getMessage("left-job")
.replace("%job%", job.name)

View File

@@ -1,14 +1,16 @@
package com.willfp.ecojobs.jobs
import com.willfp.eco.core.EcoPlugin
import com.willfp.libreforge.Holder
import com.willfp.libreforge.conditions.ConfiguredCondition
import com.willfp.libreforge.effects.ConfiguredEffect
import com.willfp.libreforge.conditions.ConditionList
import com.willfp.libreforge.effects.EffectList
class JobLevel(
plugin: EcoPlugin,
val job: Job,
val level: Int,
override val effects: Set<ConfiguredEffect>,
override val conditions: Set<ConfiguredCondition>
): Holder {
override val id = "${job.id}_$level"
override val effects: EffectList,
override val conditions: ConditionList
) : Holder {
override val id = plugin.createNamespacedKey("${job.id}_$level")
}

View File

@@ -13,6 +13,8 @@ import com.willfp.eco.core.gui.slot.MaskItems
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.formatEco
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.ecomponent.components.LevelComponent
import com.willfp.ecomponent.components.LevelState
import org.bukkit.entity.Player
@@ -64,7 +66,9 @@ class JobLevelGUI(
}
menu = menu(plugin.configYml.getInt("level-gui.rows")) {
title = job.name
title = plugin.configYml.getString("level-gui.title")
.replace("%job%", job.name)
.formatEco()
maxPages(component.pages)

View File

@@ -2,6 +2,7 @@ package com.willfp.ecojobs.jobs
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
import com.willfp.libreforge.toDispatcher
import org.bukkit.Sound
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
@@ -16,6 +17,7 @@ class JobLevelListener(
val player = event.player
val level = event.level
job.levelUpEffects?.trigger(player.toDispatcher())
job.executeLevelCommands(player, level)
if (this.plugin.configYml.getBool("level-up.sound.enabled")) {

View File

@@ -1,22 +0,0 @@
package com.willfp.ecojobs.jobs
import com.willfp.libreforge.events.TriggerPreProcessEvent
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
object JobTriggerXPGainListener : Listener {
@EventHandler(ignoreCancelled = true)
fun handle(event: TriggerPreProcessEvent) {
val player = event.player
val job = event.player.activeJob ?: return
val amount = job.getXP(event)
if (amount <= 0.0) {
return
}
player.giveJobExperience(job, amount)
}
}

View File

@@ -0,0 +1,62 @@
package com.willfp.ecojobs.jobs
import com.github.benmanes.caffeine.cache.Caffeine
import com.willfp.ecojobs.api.giveJobExperience
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.libreforge.counters.Accumulator
import org.bukkit.entity.Player
import java.util.concurrent.TimeUnit
import kotlin.math.max
class JobXPAccumulator(
private val job: Job
) : Accumulator {
override fun accept(player: Player, count: Double) {
if (!player.hasJobActive(job)) {
return
}
player.giveJobExperience(job, count)
}
}
private val expMultiplierCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build<Player, Double> {
it.cacheJobExperienceMultiplier()
}
val Player.jobExperienceMultiplier: Double
get() = expMultiplierCache.get(this)
private fun Player.cacheJobExperienceMultiplier(): Double {
if (this.hasPermission("ecojobs.xpmultiplier.quadruple")) {
return 4.0
}
if (this.hasPermission("ecojobs.xpmultiplier.triple")) {
return 3.0
}
if (this.hasPermission("ecojobs.xpmultiplier.double")) {
return 2.0
}
if (this.hasPermission("ecojobs.xpmultiplier.50percent")) {
return 1.5
}
return 1 + getNumericalPermission("ecojobs.xpmultiplier", 0.0) / 100
}
fun Player.getNumericalPermission(permission: String, default: Double): Double {
var highest: Double? = null
for (permissionAttachmentInfo in this.effectivePermissions) {
val perm = permissionAttachmentInfo.permission
if (perm.startsWith(permission)) {
val found = perm.substring(perm.lastIndexOf(".") + 1).toDoubleOrNull() ?: continue
highest = max(highest ?: Double.MIN_VALUE, found)
}
}
return highest ?: default
}

View File

@@ -1,14 +1,17 @@
package com.willfp.ecojobs.jobs
import com.google.common.collect.BiMap
import com.google.common.collect.HashBiMap
import com.google.common.collect.ImmutableList
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.eco.core.registry.Registry
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory
import org.bukkit.OfflinePlayer
object Jobs {
private val BY_ID: BiMap<String, Job> = HashBiMap.create()
object Jobs : ConfigCategory("job", "jobs") {
private val registry = Registry<Job>()
/**
* Get all registered [Job]s.
@@ -17,7 +20,7 @@ object Jobs {
*/
@JvmStatic
fun values(): List<Job> {
return ImmutableList.copyOf(BY_ID.values)
return ImmutableList.copyOf(registry.values())
}
/**
@@ -28,45 +31,15 @@ object Jobs {
*/
@JvmStatic
fun getByID(name: String): Job? {
return BY_ID[name]
return registry[name]
}
/**
* Update all [Job]s.
*
* @param plugin Instance of EcoJobs.
*/
@ConfigUpdater
@JvmStatic
fun update(plugin: EcoJobsPlugin) {
for (job in values()) {
removeJob(job)
}
for ((id, jobConfig) in plugin.fetchConfigs("jobs")) {
addNewJob(Job(id, jobConfig, plugin))
}
override fun clear(plugin: LibreforgePlugin) {
registry.clear()
}
/**
* Add new [Job] to EcoJobs.
*
* @param job The [Job] to add.
*/
@JvmStatic
fun addNewJob(job: Job) {
BY_ID.remove(job.id)
BY_ID[job.id] = job
}
/**
* Remove [Job] from EcoJobs.
*
* @param job The [Job] to remove.
*/
@JvmStatic
fun removeJob(job: Job) {
BY_ID.remove(job.id)
override fun acceptConfig(plugin: LibreforgePlugin, id: String, config: Config) {
registry.register(Job(id, config, plugin as EcoJobsPlugin))
}
/**

View File

@@ -4,18 +4,28 @@ import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.eco.core.gui.menu
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.onLeftClick
import com.willfp.eco.core.gui.onRightClick
import com.willfp.eco.core.gui.page.PageChanger
import com.willfp.eco.core.gui.slot
import com.willfp.eco.core.gui.slot.ConfigSlot
import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.MaskItems
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.items.builder.SkullBuilder
import com.willfp.eco.util.formatEco
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.activeJobs
import com.willfp.ecojobs.api.canJoinJob
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.joinJob
import com.willfp.ecojobs.jobs.Jobs.unlockedJobs
import org.bukkit.Material
import org.bukkit.Sound
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.SkullMeta
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
@@ -23,17 +33,6 @@ import kotlin.math.min
object JobsGUI {
private lateinit var menu: Menu
private val jobAreaSlots = mutableListOf<Pair<Int, Int>>()
private const val pageKey = "page"
private fun getPage(menu: Menu, player: Player): Int {
val pages = ceil(Jobs.values()
.filter { player.getJobLevel(it) > 0 }
.size.toDouble() / jobAreaSlots.size).toInt()
val page = menu.getState(player, pageKey) ?: 1
return max(min(pages, page + 1), 1)
}
@JvmStatic
@ConfigUpdater
@@ -54,18 +53,8 @@ object JobsGUI {
}
private fun buildMenu(plugin: EcoJobsPlugin): Menu {
val jobInfoItemBuilder = { player: Player, _: Menu ->
val job = player.activeJob
job?.getJobInfoIcon(player)
?: ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.job-info.no-active.item")))
.setDisplayName(plugin.configYml.getFormattedString("gui.job-info.no-active.name"))
.addLoreLines(plugin.configYml.getFormattedStrings("gui.job-info.no-active.lore"))
.build()
}
val jobIconBuilder = { player: Player, menu: Menu, index: Int ->
val page = getPage(menu, player)
val page = menu.getPage(player)
val unlockedJobs = player.unlockedJobs
@@ -86,13 +75,47 @@ object JobsGUI {
)
setSlot(
plugin.configYml.getInt("gui.job-info.row"),
plugin.configYml.getInt("gui.job-info.column"),
slot(jobInfoItemBuilder) {
onLeftClick { event, _, _ ->
val player = event.whoClicked as Player
player.activeJob?.levelGUI?.open(player)
plugin.configYml.getInt("gui.player-info.row"),
plugin.configYml.getInt("gui.player-info.column"),
slot { player, _ ->
@Suppress("DEPRECATION")
val skullBuilder = SkullBuilder()
.setDisplayName(
plugin.configYml.getString("gui.player-info.name")
.replace("%player%", player.displayName)
.formatEco(player, true)
)
if (player.activeJobs.isEmpty()) {
skullBuilder.addLoreLines(
plugin.configYml.getStrings("gui.player-info.no-jobs")
.formatEco(player, true)
)
} else {
skullBuilder.addLoreLines(
plugin.configYml.getStrings("gui.player-info.has-jobs")
.flatMap {
if (it == "%jobs%") {
player.activeJobs.flatMap { job ->
job.injectPlaceholdersInto(
plugin.configYml.getStrings("gui.player-info.job-line"),
player
)
}
} else {
listOf(it)
}
}
.formatEco(player, true)
)
}
val skull = skullBuilder.build()
val meta = skull.itemMeta as SkullMeta
meta.owningPlayer = player
skull.itemMeta = meta
skull
}
)
@@ -100,10 +123,8 @@ object JobsGUI {
val (row, column) = pair
setSlot(row, column, slot({ p, m -> jobIconBuilder(p, m, index) }) {
onLeftClick { event, _, _ ->
val player = event.whoClicked as Player
val page = getPage(menu, player)
onLeftClick { player, _, _, menu ->
val page = menu.getPage(player)
val unlockedJobs = player.unlockedJobs
@@ -111,10 +132,22 @@ object JobsGUI {
val job = unlockedJobs.getOrNull(pagedIndex) ?: return@onLeftClick
if (player.activeJob == null) {
player.activeJob = job
if (player.hasJobActive(job)) {
job.levelGUI.open(player)
} else {
player.sendMessage(plugin.langYml.getMessage("leave-current-job"))
if (player.canJoinJob(job)) {
player.joinJob(job)
if (player.hasJobActive(job)) {
player.sendMessage(
plugin.langYml.getMessage("joined-job")
.replace("%job%", job.name)
)
}
} else {
player.sendMessage(plugin.langYml.getMessage("cannot-join-job"))
return@onLeftClick
}
}
player.playSound(
@@ -124,52 +157,58 @@ object JobsGUI {
plugin.configYml.getDouble("gui.job-icon.click.pitch").toFloat()
)
}
onRightClick { player, _, _, menu ->
val page = menu.getPage(player)
val unlockedJobs = player.unlockedJobs
val pagedIndex = ((page - 1) * jobAreaSlots.size) + index
val job = unlockedJobs.getOrNull(pagedIndex) ?: return@onRightClick
if (player.hasJobActive(job)) {
job.leaveGUI.open(player)
player.playSound(
player.location,
Sound.valueOf(plugin.configYml.getString("gui.job-icon.click.sound").uppercase()),
1f,
plugin.configYml.getDouble("gui.job-icon.click.pitch").toFloat()
)
}
}
})
}
setSlot(
addComponent(
plugin.configYml.getInt("gui.prev-page.location.row"),
plugin.configYml.getInt("gui.prev-page.location.column"),
slot(
PageChanger(
ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.prev-page.item")))
.setDisplayName(plugin.configYml.getString("gui.prev-page.name"))
.build()
) {
onLeftClick { event, _, menu ->
val player = event.whoClicked as Player
val page = getPage(menu, player)
val newPage = max(1, page - 1)
menu.setState(player, pageKey, newPage)
}
}
.build(),
PageChanger.Direction.BACKWARDS
)
)
setSlot(
addComponent(
plugin.configYml.getInt("gui.next-page.location.row"),
plugin.configYml.getInt("gui.next-page.location.column"),
slot(
PageChanger(
ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.next-page.item")))
.setDisplayName(plugin.configYml.getString("gui.next-page.name"))
.build()
) {
onLeftClick { event, _, menu ->
val player = event.whoClicked as Player
val pages = ceil(Jobs.values()
.filter { player.getJobLevel(it) > 0 }
.size.toDouble() / jobAreaSlots.size).toInt()
val page = getPage(menu, player)
val newPage = min(pages, page + 1)
menu.setState(player, pageKey, newPage)
}
}
.build(),
PageChanger.Direction.FORWARDS
)
)
maxPages { player ->
ceil(Jobs.values()
.filter { player.getJobLevel(it) > 0 }
.size.toDouble() / jobAreaSlots.size).toInt()
}
setSlot(plugin.configYml.getInt("gui.close.location.row"),
plugin.configYml.getInt("gui.close.location.column"),
slot(
@@ -181,19 +220,6 @@ object JobsGUI {
}
)
setSlot(plugin.configYml.getInt("gui.deactivate-job.location.row"),
plugin.configYml.getInt("gui.deactivate-job.location.column"),
slot(
ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.deactivate-job.item")))
.setDisplayName(plugin.configYml.getString("gui.deactivate-job.name"))
.build()
) {
onLeftClick { player, _, _, _ ->
player.activeJob?.leaveGUI?.open(player)
}
}
)
for (config in plugin.configYml.getSubsections("gui.custom-slots")) {
setSlot(
config.getInt("row"),

View File

@@ -2,6 +2,7 @@ package com.willfp.ecojobs.jobs
import com.willfp.ecojobs.api.event.PlayerJobJoinEvent
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.libreforge.toDispatcher
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
@@ -23,6 +24,7 @@ object PriceHandler : Listener {
}
price.pay(player)
job.joinEffects?.trigger(player.toDispatcher())
}
@EventHandler(
@@ -40,5 +42,6 @@ object PriceHandler : Listener {
}
price.pay(player)
job.leaveEffects?.trigger(player.toDispatcher())
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.ecojobs.jobs
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.ecojobs.api.resetJob
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener

View File

@@ -0,0 +1,28 @@
package com.willfp.ecojobs.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecojobs.api.activeJobs
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.arguments
import com.willfp.libreforge.conditions.Condition
import com.willfp.libreforge.get
import org.bukkit.entity.Player
object ConditionHasActiveJob : Condition<NoCompileData>("has_active_job") {
override val arguments = arguments {
require("job", "You must specify the job!")
}
override fun isMet(
dispatcher: Dispatcher<*>,
config: Config,
holder: ProvidedHolder,
compileData: NoCompileData
): Boolean {
val player = dispatcher.get<Player>() ?: return false
return player.activeJobs.any { it.id == config.getString("job").lowercase() }
}
}

View File

@@ -0,0 +1,42 @@
package com.willfp.ecojobs.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.arguments
import com.willfp.libreforge.conditions.Condition
import com.willfp.libreforge.get
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.updateEffects
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
object ConditionHasJobLevel : Condition<NoCompileData>("has_job_level") {
override val arguments = arguments {
require("job", "You must specify the job!")
require("level", "You must specify the level!")
}
override fun isMet(
dispatcher: Dispatcher<*>,
config: Config,
holder: ProvidedHolder,
compileData: NoCompileData
): Boolean {
val player = dispatcher.get<Player>() ?: return false
return player.getJobLevel(
Jobs.getByID(config.getString("job").lowercase()) ?: return false
) >= config.getIntFromExpression("level", player)
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
fun handle(event: PlayerJobLevelUpEvent) {
event.player.toDispatcher().updateEffects()
}
}

View File

@@ -0,0 +1,32 @@
package com.willfp.ecojobs.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecojobs.api.giveJobExperience
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.arguments
import com.willfp.libreforge.effects.Effect
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
object EffectGiveJobXp : Effect<NoCompileData>("give_job_xp") {
override val parameters = setOf(
TriggerParameter.PLAYER
)
override val arguments = arguments {
require("amount", "You must specify the amount of xp to give!")
require("job", "You must specify the job to give xp for!")
}
override fun onTrigger(config: Config, data: TriggerData, compileData: NoCompileData): Boolean {
val player = data.player ?: return false
player.giveJobExperience(
Jobs.getByID(config.getString("job")) ?: return false,
config.getDoubleFromExpression("amount", player)
)
return true
}
}

View File

@@ -0,0 +1,25 @@
package com.willfp.ecojobs.libreforge
import com.willfp.ecojobs.api.event.PlayerJobExpGainEvent
import com.willfp.ecojobs.jobs.Job
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.libreforge.effects.templates.MultiMultiplierEffect
import com.willfp.libreforge.toDispatcher
import org.bukkit.event.EventHandler
object EffectJobXpMultiplier : MultiMultiplierEffect<Job>("job_xp_multiplier") {
override val key = "jobs"
override fun getElement(key: String): Job? {
return Jobs.getByID(key)
}
override fun getAllElements(): Collection<Job> {
return Jobs.values()
}
@EventHandler(ignoreCancelled = true)
fun handle(event: PlayerJobExpGainEvent) {
event.amount *= getMultiplier(event.player.toDispatcher(), event.job)
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.ecojobs.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecojobs.api.event.JobEvent
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.filters.Filter
import com.willfp.libreforge.triggers.TriggerData
object FilterJob : Filter<NoCompileData, Collection<String>>("job") {
override fun getValue(config: Config, data: TriggerData?, key: String): Collection<String> {
return config.getStrings(key)
}
override fun isMet(data: TriggerData, value: Collection<String>, compileData: NoCompileData): Boolean {
val event = data.event as? JobEvent ?: return true
return value.any { jobName ->
jobName.equals(event.job.id, ignoreCase = true)
}
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.ecojobs.libreforge
import com.willfp.ecojobs.api.event.PlayerJobExpGainEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.event.EventHandler
object TriggerGainJobXp : Trigger("gain_job_xp") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.LOCATION,
TriggerParameter.EVENT
)
@EventHandler(ignoreCancelled = true)
fun handle(event: PlayerJobExpGainEvent) {
val player = event.player
this.dispatch(
player.toDispatcher(),
TriggerData(
player = player,
location = player.location,
event = event,
value = event.amount
)
)
}
}

View File

@@ -0,0 +1,33 @@
package com.willfp.ecojobs.libreforge
import com.willfp.ecojobs.api.event.PlayerJobJoinEvent
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
object TriggerJoinJob : Trigger("join_job") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.LOCATION,
TriggerParameter.EVENT
)
@EventHandler(ignoreCancelled = true)
fun handle(event: PlayerJobJoinEvent) {
val player = event.player as? Player ?: return
this.dispatch(
player.toDispatcher(),
TriggerData(
player = player,
location = player.location,
event = event,
value = player.getJobLevel(event.job).toDouble()
)
)
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.ecojobs.libreforge
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
object TriggerLeaveJob : Trigger("leave_job") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.LOCATION,
)
@EventHandler(ignoreCancelled = true)
fun handle(event: PlayerJobLeaveEvent) {
val player = event.player as? Player ?: return
this.dispatch(
player.toDispatcher(),
TriggerData(
player = player,
location = player.location,
value = player.getJobLevel(event.job).toDouble()
)
)
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.ecojobs.libreforge
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.event.EventHandler
object TriggerLevelUpJob : Trigger("level_up_job") {
override val parameters = setOf(
TriggerParameter.PLAYER,
TriggerParameter.LOCATION,
TriggerParameter.EVENT
)
@EventHandler(ignoreCancelled = true)
fun handle(event: PlayerJobLevelUpEvent) {
val player = event.player
this.dispatch(
player.toDispatcher(),
TriggerData(
player = player,
location = player.location,
event = event,
value = event.level.toDouble()
)
)
}
}

View File

@@ -0,0 +1,27 @@
package com.willfp.ecojobs.util
import com.willfp.eco.core.placeholder.InjectablePlaceholder
import com.willfp.eco.core.placeholder.PlaceholderInjectable
import com.willfp.eco.core.placeholder.StaticPlaceholder
class LevelInjectable(
level: Int
) : PlaceholderInjectable {
private val placeholders = listOf(
StaticPlaceholder(
"level"
) { level.toString() }
)
override fun getPlaceholderInjections(): List<InjectablePlaceholder> {
return placeholders
}
override fun addInjectablePlaceholder(p0: Iterable<InjectablePlaceholder>) {
return
}
override fun clearInjectedPlaceholders() {
return
}
}

View File

@@ -1,21 +0,0 @@
# Read more about chains: https://plugins.auxilor.io/effects/configuring-an-effect#effect-chains
chains:
- id: example_chain
effects:
- id: teleport
- id: potion_effect
args:
effect: blindness
level: 3
duration: 30
apply_to_player: true
- id: send_message
args:
message: "&fYou have been teleported!"
action_bar: true
- id: play_sound
args:
sound: entity_dragon_fireball_explode
pitch: 1.5
volume: 4

View File

@@ -3,6 +3,15 @@
# by Auxilor
#
# Even if eco is set up to use a database, you can
# force EcoJobs to save to local storage to disable
# cross-server sync.
use-local-storage: false
jobs:
limit: 3 # The most jobs a player can have at once.
# You can set custom limits with the ecojobs.limit.<number> permission
gui:
rows: 6
@@ -20,49 +29,43 @@ gui:
materials:
- black_stained_glass_pane
pattern:
- "111101111"
- "111111111"
- "101000001"
- "111000001"
- "101000001"
- "111111111"
- "111100011"
- "100000001"
- "100000001"
- "100000001"
- "111101111"
job-area:
top-left:
row: 2
column: 4
row: 3
column: 2
bottom-right:
row: 4
row: 5
column: 8
job-info:
row: 2
column: 2
player-info:
row: 1
column: 5
no-active:
name: "&cNo Active Job"
lore:
- ""
- "&cYou do not currently have a job active"
- "&fPick one from the options below!"
- ""
item: player_head texture:eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmFkYzA0OGE3Y2U3OGY3ZGFkNzJhMDdkYTI3ZDg1YzA5MTY4ODFlNTUyMmVlZWQxZTNkYWYyMTdhMzhjMWEifX19
name: "&r%player%&f's Jobs:"
# %join_price% and %leave_price% are also available as placeholders
no-jobs:
- ""
- "&cYou do not currently have a job active"
- "&fPick one from the options below!"
- ""
- "&fYou can have up to &a%ecojobs_limit% &fjobs at once!"
- ""
active:
name: "%job% &fLvl. &a%level%"
lore:
- "%description%"
- "&f"
- "&fJob Rewards:"
- "%effects%"
- ""
- "&fProgress:"
- "&8» &e%percentage_progress%%"
- "&8» &e%current_xp%&8/&7%required_xp% &fXP"
- ""
- "&eClick to view Level Progression!"
has-jobs:
- ""
- "%jobs%"
- ""
- "&fJob slots in use: &a%ecojobs_in_jobs%&8/&a%ecojobs_limit%"
job-line:
- " %job% &fLvl. &a%level%"
job-icon:
name: "%job% &fLvl. &a%level%"
@@ -76,9 +79,16 @@ gui:
- "&8» &e%percentage_progress%%"
- "&8» &e%current_xp%&8/&7%required_xp% &fXP"
# %join_price% and %leave_price% are also available as placeholders
active-lore:
- ""
- "&cYou've already joined this job!"
- "&eClick to view Level Progression!"
- "&eRight-click to leave this job!"
too-many-jobs-lore:
- ""
- "&cYou have too many jobs already!"
join-lore:
- ""
@@ -93,34 +103,28 @@ gui:
name: "&fPrevious Page"
location:
row: 6
column: 5
column: 4
next-page:
item: arrow
name: "&fNext Page"
location:
row: 6
column: 7
column: 6
close:
item: barrier
name: "&cClose"
location:
row: 6
column: 6
deactivate-job:
item: player_head texture:eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTRiZDlhNDViOTY4MWNlYTViMjhjNzBmNzVhNjk1NmIxZjU5NGZlYzg0MGI5NjA3Nzk4ZmIxZTcwNzc2NDQzMCJ9fX0=
name: "&cDeactivate Job"
location:
row: 4
column: 2
column: 5
# Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots
custom-slots: [ ]
level-gui:
rows: 6
title: "%job%"
mask:
# The way the mask works is by having a list of materials
@@ -280,48 +284,3 @@ level-up:
id: entity_player_levelup
# Pitch between 0.5 and 2
pitch: 1.3
cannot-afford:
in-actionbar: true
sound:
enabled: true
sound: "BLOCK_NOTE_BLOCK_PLING"
pitch: 0.5
cooldown:
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
cannot-afford-price:
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
potions:
icon:
permanent: true
triggered: true
ambient:
permanent: false
triggered: true
particles:
permanent: false
triggered: true

View File

@@ -1,3 +1,8 @@
resource-id: 2857
bstats-id: 16394
color: "&#964B00"
environment:
- name: libreforge version
value: ${libreforgeVersion}
options:
resource-id: 2857
bstats-id: 16394
color: "&#964B00"

View File

@@ -27,6 +27,13 @@ join-price:
# Reference with %join_lore%
join-lore: []
# A list of effects to run when the player joins the job.
# Read https://plugins.auxilor.io/effects/configuring-an-effect
join-effects:
- id: broadcast
args:
message: "&8» &a%player% &8joined the &6Miner &8job!"
# The price to leave this job (set to 0 to disable)
# Read here for more: https://plugins.auxilor.io/all-plugins/prices
leave-price:
@@ -39,7 +46,22 @@ leave-price:
leave-lore:
- " &8» This will cost %leave_price%"
# The xp requirements for each job level - add new levels by adding more to this list
# A list of effects to run when the player leaves the job.
# Read https://plugins.auxilor.io/effects/configuring-an-effect
leave-effects:
- id: send_message
args:
message: "&8» &8You left the &6Miner &8job!"
# There are two ways to specify level XP requirements:
# 1. A formula to calculate for infinite levels
# 2. A list of XP requirements for each level
# Formula
# xp-formula: (2 ^ %level%) * 25
# max-level: 100 # The max level of the job
# List
level-xp-requirements:
- 100
- 120
@@ -133,10 +155,13 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each &a%blocks%&8 blocks mined"
# Commands to be sent on levelup, can be formatted two ways:
# level:command (e.g. 10:eco give %player% 1000), which would execute that command for level 10
# command (e.g. eco give %player% 5000), which would execute that command for all levels
level-commands: [ ]
# Effects to run when the skill levels up
# %level% is the level the skill leveled up to.
# If you want to restrict this to certain levels, you can use
# require: %level% = 20, or require: %level% < 50, etc.
# If you want a reward to run every x levels, you can use
# every: 1, or every: 12, etc
level-up-effects: [ ]
# The effects for the job, has %level% as a placeholder
effects:

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -95,7 +99,7 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each bee you breed"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -94,7 +98,7 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each &a%blocks%&8 blocks placed"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -92,7 +96,7 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each enchanted item"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -107,7 +111,7 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each crop farmed"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -92,7 +96,7 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each fish caught"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -104,7 +108,7 @@ level-up-messages:
1:
- "&8» &7Earn &a$%money%&7 for each log chopped."
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -74,15 +78,17 @@ level-xp-requirements:
xp-gain-methods:
- trigger: mine_block
multiplier: 0.5
conditions: [ ]
filters:
items:
- "*wooden_pickaxe"
- "*stone_pickaxe"
- "*iron_pickaxe"
- "*golden_pickaxe"
- "*diamond_pickaxe"
- "*netherite_pickaxe"
filters: [ ]
conditions:
- id: in_mainhand
args:
items:
- "*wooden_pickaxe"
- "*stone_pickaxe"
- "*iron_pickaxe"
- "*golden_pickaxe"
- "*diamond_pickaxe"
- "*netherite_pickaxe"
level-placeholders:
- id: "money"
@@ -102,21 +108,23 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each &a%blocks%&8 blocks mined"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money
args:
every: "ceil(10 - %level% / 10)"
amount: "0.4 * %level%"
filters:
items:
- "*wooden_pickaxe"
- "*stone_pickaxe"
- "*iron_pickaxe"
- "*golden_pickaxe"
- "*diamond_pickaxe"
- "*netherite_pickaxe"
conditions:
- id: in_mainhand
args:
items:
- "*wooden_pickaxe"
- "*stone_pickaxe"
- "*iron_pickaxe"
- "*golden_pickaxe"
- "*diamond_pickaxe"
- "*netherite_pickaxe"
triggers:
- mine_block

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -95,7 +99,7 @@ level-up-messages:
- "&8» &8Earn &a$%money%&8 per heart of health that"
- " &8mobs you kill have"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -10,6 +10,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -17,6 +19,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -92,7 +96,7 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each smelted item"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -18,6 +18,8 @@ join-price:
type: coins
display: "&a$%value%"
join-effects: []
join-lore: []
leave-price:
@@ -25,6 +27,8 @@ leave-price:
type: coins
display: "&a$%value%"
leave-effects: []
leave-lore:
- ""
@@ -133,7 +137,7 @@ level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each tool crafted"
level-commands: [ ]
level-up-effects: [ ]
effects:
- id: give_money

View File

@@ -4,22 +4,13 @@ messages:
not-player: "&cThis command must be run by a player"
invalid-command: "&cUnknown subcommand!"
reloaded: "Reloaded!"
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-afford-price: "&cYou can't afford to do this! &fPrice: %price%"
on-cooldown: "&cThis effect is on cooldown! &fTime left: &a%seconds% seconds"
cannot-transmit: "&cYou can't transmit here!"
must-specify-lrcdb-id: "&cYou must specify the ID of the config to download! Not sure what this means? Go to &alrcdb.auxilor.io"
lrcdb-import-error: "&cError importing config: &f%message%"
lrcdb-import-success: "&fImported &a%name%&f! Reload the plugin to install it"
must-specify-config-name: "&cYou must specify the config name!"
invalid-config-name: "&cInvalid config name!"
lrcdb-export-error: "&cError exporting config: &f%message%"
lrcdb-export-success: "&fExported &a%name%&f! View it on &alrcdb.auxilor.io&f, or share your config ID: &f%id%"
needs-player: "&cYou must specify a player!"
gave-xp: "&fYou have given &a%xp% &fXP to %player%&f's %job%&f!"
reset-xp: "&fYou have reset %player%&f's %job%&f XP!"
reset-all-players: "&fYou have reset all players' %job%&f XP!"
reset-all-jobs: "&fYou have reset %player%&f's XP for all jobs!"
reset-all-players-all-jobs: "&fYou have reset all players' XP for all jobs!"
needs-job: "&cYou must specify a job!"
need-amount: "&cYou must specify a amount!"
invalid-player: "&cInvalid player!"
@@ -33,11 +24,16 @@ messages:
joined-job: "&fYou have joined the %job%&f job!"
left-job: "&fYou have left the %job%&f job!"
job-already-joined: "&cYou already have this job!"
leave-current-job: "&cYou must leave your current job before joining a new one!"
cannot-join-job: "&cYou are already in too many jobs, please leave one!"
cant-leave-job: "&cYou can't leave the %job%&f job!"
dont-have-job: "&cYou don't have this job unlocked!"
not-in-job: "&cYou are not in this job!"
menu:
title: "Jobs"
infinity: "∞"
top:
name-empty: "&cEmpty"
amount-empty: "0"

View File

@@ -1,19 +0,0 @@
# Options for lrcdb (https://lrcdb.auxilor.io), a website to share configs
# with other server owners, so you can get more configs without making them
# yourself!
author: "Unknown Author" # The name attached to configs you export
# Options about automatically sharing configs you create
share-configs:
# If you want all your configs to automatically be publicly available,
# set this to true. This really helps out other users!
publicly: false
# If you don't want your configs to be usable to gather information about
# plugin usage or to improve the plugins in the future, disable this.
# Nothing identifying is shared.
enabled: true
# If you disable share-configs, you can still share select configs publicly
# with /ecojobs export <config>.

View File

@@ -1,28 +1,13 @@
name: EcoJobs
version: ${projectVersion}
name: ${pluginName}
version: ${version}
main: com.willfp.ecojobs.EcoJobsPlugin
api-version: 1.17
authors: [ Auxilor ]
website: willfp.com
load: STARTUP
depend:
- eco
- ProtocolLib
- PlaceholderAPI
softdepend:
- AureliumSkills
- Vault
- mcMMO
- Jobs
- TMMobcoins
- EcoEnchants
- EcoBosses
- Talismans
- EcoArmor
- EcoItems
- Boosters
- EcoSkills
- Reforges
- libreforge
commands:
ecojobs:
description: Base Command
@@ -52,8 +37,6 @@ permissions:
ecojobs.command.join: true
ecojobs.command.leave: true
ecojobs.command.reset: true
ecojobs.command.import: true
ecojobs.command.export: true
ecojobs.command.reload:
description: Allows reloading the config
@@ -73,12 +56,6 @@ permissions:
ecojobs.command.reset:
description: Allows the use of /ecojobs reset.
default: op
ecojobs.command.import:
description: Allows the use of /ecojobs import.
default: op
ecojobs.command.export:
description: Allows the use of /ecojobs export.
default: op
ecojobs.command.join:
description: Allows the use of /jobs join.
default: true

View File

@@ -1,4 +1,5 @@
#libreforge-updater
#Tue Feb 07 14:45:38 GMT 2023
version=1.35.0
plugin-name=EcoJobs
#Sat Mar 29 14:21:51 GMT 2025
kotlin.code.style=official
libreforge-version=4.75.0
version=3.73.0

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
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");
# 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
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
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.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
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 [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
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."
fi
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.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --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
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
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" "$@"

View File

@@ -1,6 +0,0 @@
jdk: openjdk17
before_install:
- source "$HOME/.sdkman/bin/sdkman-init.sh"
- sdk update
- sdk install java 17.0.1-tem
- sdk use java 17.0.1-tem

View File

@@ -1,5 +0,0 @@
rootProject.name = 'EcoJobs'
// Core
include ':eco-core'
include ':eco-core:core-plugin'

18
settings.gradle.kts Normal file
View File

@@ -0,0 +1,18 @@
pluginManagement {
repositories {
gradlePluginPortal()
mavenLocal()
maven("https://repo.auxilor.io/repository/maven-public/")
maven("https://repo.papermc.io/repository/maven-public/")
}
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
rootProject.name = "EcoJobs"
// Core
include(":eco-core")
include(":eco-core:core-plugin")