Compare commits
56 commits
tweaks-0.1
...
master
Author | SHA1 | Date | |
---|---|---|---|
4f752bef61 | |||
41583939ac | |||
22bb2d16d2 | |||
![]() |
598902ef33 | ||
![]() |
7cd334f4a2 | ||
![]() |
b421b48e51 | ||
![]() |
684e31bf07 | ||
![]() |
cf654fcb42 | ||
![]() |
0c4690e2e7 | ||
![]() |
05b9ca4cb8 | ||
![]() |
316d479fd8 | ||
![]() |
6ff6ec9d6b | ||
![]() |
541f095075 | ||
![]() |
1fafc90e04 | ||
![]() |
ad1a699d38 | ||
![]() |
7de46b879b | ||
![]() |
cbe9f77cca | ||
![]() |
c096674a15 | ||
![]() |
232e0bfa9a | ||
![]() |
9345efe1d4 | ||
![]() |
2761ed8757 | ||
![]() |
2a65e9dbcb | ||
![]() |
29f79a8771 | ||
![]() |
7b65be86ad | ||
![]() |
2788829967 | ||
![]() |
cbfbdf8ce3 | ||
![]() |
1ac32a093f | ||
![]() |
15c97ee256 | ||
![]() |
7ed9a702ca | ||
![]() |
bcd6827c29 | ||
![]() |
2890f00acd | ||
![]() |
f43b17078e | ||
![]() |
174d0ae10c | ||
![]() |
35ddd0563c | ||
![]() |
832a5edccc | ||
![]() |
6e0d7e5a40 | ||
![]() |
b9b0484d24 | ||
![]() |
f891fbbb90 | ||
![]() |
0c044febd5 | ||
![]() |
e5d2938845 | ||
![]() |
2430416915 | ||
![]() |
19ab653181 | ||
![]() |
e0d7e636a6 | ||
![]() |
9bcdcc17ba | ||
![]() |
a48fe97b4d | ||
![]() |
648535fd22 | ||
![]() |
e59b95e2ef | ||
![]() |
724a36c803 | ||
![]() |
6e45491508 | ||
![]() |
afed2a8f78 | ||
![]() |
4bf6ec5ae7 | ||
![]() |
fa96487ef6 | ||
![]() |
81fa6440a0 | ||
![]() |
6ad6550f5d | ||
![]() |
0d87ca8f76 | ||
![]() |
32bacc96e8 |
100 changed files with 3008 additions and 1423 deletions
|
@ -2,31 +2,30 @@ on: [push]
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container: debian:sid
|
container: eclipse-temurin:21-alpine
|
||||||
steps:
|
steps:
|
||||||
- name: Install JDK and other deps
|
- name: Install build dependencies
|
||||||
run: apt update && apt install --no-install-recommends -y openjdk-21-jdk-headless maven git nodejs curl zstd
|
run: apk add nodejs curl tar zstd
|
||||||
|
|
||||||
- name: Clone repository
|
- name: Checkout
|
||||||
run: git clone -b ${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} https://git.m724.eu/Minecon724/tweaks724.git .
|
uses: https://github.com/actions/checkout@v4
|
||||||
|
|
||||||
- name: Download NMS
|
- name: Download NMS
|
||||||
run: ./tools/download_nms.sh ~
|
run: ./tools/download_nms.sh ~
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build for 1.21.4
|
||||||
- name: Build for 1.21.1
|
run: ./mvnw package -Dproject.minecraft.version=1.21.4 -Dproject.craftbukkit.version=v1_21_R3
|
||||||
run: mvn package -Dproject.minecraft.version=1.21.1 -Dproject.nms.version=v1_21_R1
|
|
||||||
|
|
||||||
- name: Build for 1.21.3
|
- name: Build for 1.21.3
|
||||||
run: mvn package -Dproject.minecraft.version=1.21.3 -Dproject.nms.version=v1_21_R2
|
run: ./mvnw package -Dproject.minecraft.version=1.21.3 -Dproject.craftbukkit.version=v1_21_R2
|
||||||
|
|
||||||
- name: Build for 1.21.4
|
- name: Build for 1.21.1
|
||||||
run: mvn package -Dproject.minecraft.version=1.21.4 -Dproject.nms.version=v1_21_R3
|
run: ./mvnw package -Dproject.minecraft.version=1.21.1 -Dproject.craftbukkit.version=v1_21_R1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: https://github.com/actions/upload-artifact@v3
|
uses: https://github.com/actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: target
|
path: target/tweaks-*.jar
|
19
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
19
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
wrapperVersion=3.3.2
|
||||||
|
distributionType=only-script
|
||||||
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
60
README.md
60
README.md
|
@ -12,37 +12,37 @@ Please report all suspicious behavior. You can do so on any of those:
|
||||||
Stuff no<sub><sup>t many</sup></sub> other plugins do.
|
Stuff no<sub><sup>t many</sup></sub> other plugins do.
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
- **1.21.1**, recommended as the plugin uses NMS for some stuff \
|
- **1.21.1 and newer**
|
||||||
However, it's not forced, so it's quite probable it'll work on other versions. Please test. If you get an error, it's most often because of a module using NMS. Disable that module, and report the error \
|
|
||||||
Why not latest? The focus is on [a widely used version](https://bstats.org/global/bukkit) that has [good mod support](https://modrinth.com/modpack/fabulously-optimized/versions?c=release)
|
|
||||||
- [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/)
|
- [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/)
|
||||||
|
- To use modules marked <sup><sub>N</sub></sup>, you must use a JAR [made for the exact server version.](/Minecon724/tweaks724/src/branch/master/docs/BUILDING.md)
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
### Expand world border
|
<sup><sub>N</sub></sup> - requires a specific version \
|
||||||
|
<sup><sub>P</sub></sup> - requires ProtocolLib
|
||||||
|
|
||||||
|
### Expand world border <sup><sub>N</sub></sup>
|
||||||
Expands the world border to 30,000,000 (from 29,999,984)
|
Expands the world border to 30,000,000 (from 29,999,984)
|
||||||
|
|
||||||
### Hide world border
|
### Hide world border <sup><sub>P</sub></sup>
|
||||||
Hides the world border. It's still there, just invisible.
|
Hides the world border. It's still there, just invisible.
|
||||||
|
|
||||||
### Server brand
|
### Server brand <sup><sub>N P</sub></sup>
|
||||||
Modify the F3 brand, optionally include player's ping and server performance
|
Modify the F3 brand, optionally include player's ping and server performance
|
||||||
|
|
||||||
### Doors
|
### Doors
|
||||||
Open two doors with one click. Knock on doors.
|
Open two doors with one click. Knock on doors.
|
||||||
|
|
||||||
### MOTD
|
### MOTD <sup><sub>N P</sub></sup>
|
||||||
Random MOTD for every ping
|
Random MOTD for every ping
|
||||||
|
|
||||||
### Chat rooms
|
### Chat mods <sup><sub>N</sub></sup>
|
||||||
Chat rooms players can freely create and join. Alerts like death and join messages are only within the player's chat room.
|
- Chat rooms players can freely create and join. Alerts like death and join messages are only within the player's chat room.
|
||||||
|
- Proximity chat
|
||||||
|
|
||||||
`/chat` - switch chat room \
|
`/chat` - switch chat room \
|
||||||
`/chatmanage` - create, delete, modify etc. (`tweaks724.chatmanage`)
|
`/chatmanage` - create, delete, modify etc. (`tweaks724.chatmanage`)
|
||||||
|
|
||||||
### Proximity chat
|
|
||||||
Self-explanatory
|
|
||||||
|
|
||||||
### Compass
|
### Compass
|
||||||
Holding a compass shows a bar with 4 directions and stuff like beds, lodestones, death pos (TODO) etc.
|
Holding a compass shows a bar with 4 directions and stuff like beds, lodestones, death pos (TODO) etc.
|
||||||
|
|
||||||
|
@ -52,20 +52,23 @@ Self-discipline with a pomodoro timer that's actually forced
|
||||||
`/pomodoro` (`tweaks724.pomodoro`)
|
`/pomodoro` (`tweaks724.pomodoro`)
|
||||||
|
|
||||||
### Updater
|
### Updater
|
||||||
Updates ALL* your plugins \
|
Checks for updates of ALL* your plugins \
|
||||||
|
Updates are still installed manually \
|
||||||
<sub>*Those on SpigotMC and that release updates there</sub>
|
<sub>*Those on SpigotMC and that release updates there</sub>
|
||||||
|
|
||||||
`/updates` - shows available updates (`tweaks724.updates`)
|
`/updates` - shows available updates (`tweaks724.updates`)
|
||||||
|
|
||||||
### Hardcore
|
### Hardcore <sup><sub>N P</sub></sup>
|
||||||
Hardcore hearts by chance
|
Hardcore hearts by chance
|
||||||
|
|
||||||
### Sleep
|
### Sleep
|
||||||
Sleeping doesn't skip night, but speeds it up. The more players, the faster it goes.
|
Sleeping doesn't skip night, but speeds it up. The more players, the faster it goes.
|
||||||
- Instant sleep \
|
- Instant sleep \
|
||||||
One can instantly skip, but only a part of the night. \
|
One can instantly skip, but only a part of the night. \
|
||||||
There's 5 players on the server. A night is 10 minutes long. \
|
There's 5 players on the server. A night is 10 minutes long. \
|
||||||
Each player can instantly skip 2 minutes of the night at any time, even if others aren't sleeping
|
Each player can instantly skip 2 minutes of the night at any time, even if others aren't sleeping
|
||||||
|
- Heal \
|
||||||
|
Sleeping heals
|
||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
Players are given a unique subdomain like "\<key>.example.com" and they must use it to join \
|
Players are given a unique subdomain like "\<key>.example.com" and they must use it to join \
|
||||||
|
@ -76,21 +79,38 @@ It can be enabled that new players can't join the server without a key
|
||||||
### Full join
|
### Full join
|
||||||
Players with `tweaks724.bypass-full` can join even when the server is full
|
Players with `tweaks724.bypass-full` can join even when the server is full
|
||||||
|
|
||||||
### Emergency alerts
|
### Emergency alerts <sup><sub>P</sub></sup>
|
||||||
Issue messages that the player needs to read to keep playing, and that make an attention grabbing sound
|
Issue messages that the player needs to read to keep playing, and that make an attention grabbing sound
|
||||||
|
|
||||||
`/emergencyalerts` (`tweaks724.emergencyalerts`)
|
`/emergencyalerts` (`tweaks724.emergencyalerts`)
|
||||||
|
|
||||||
### Remote redstone
|
### Remote redstone
|
||||||
Adds a "gateway" item that are controlled over internet. \
|
Adds a "gateway" item that are controlled over internet. \
|
||||||
[RETSTONE.md for more info](/Minecon724/tweaks724/src/branch/master/RETSTONE.md)
|
[RETSTONE.md for more info](/Minecon724/tweaks724/src/branch/master/docs/RETSTONE.md)
|
||||||
|
|
||||||
### Knockback
|
### Knockback
|
||||||
Control knockback dealt by entities
|
Control knockback dealt by entities
|
||||||
|
|
||||||
|
### Kill switch
|
||||||
|
Quickly kills (terminates) the server on trigger, via command or HTTP request.
|
||||||
|
[KILLSWITCH.md for more info](/Minecon724/tweaks724/src/branch/master/docs/KILLSWITCH.md)
|
||||||
|
|
||||||
|
### Swing through grass
|
||||||
|
Self-explanatory
|
||||||
|
|
||||||
|
### Durability alert
|
||||||
|
Self-explanatory too.
|
||||||
|
|
||||||
|
`/durabilityalert` (`tweaks724.durabilityalert`)
|
||||||
|
|
||||||
|
### Word coords
|
||||||
|
Convert coordinates to easier to remember words
|
||||||
|
|
||||||
|
`/wordcoords` (`tweaks724.tauth`)
|
||||||
|
|
||||||
### Utility commands
|
### Utility commands
|
||||||
|
|
||||||
- `/ping` - displays player ping \
|
- `/ping` - displays player ping <sup><sub>P</sub></sup> \
|
||||||
**Ping is calculated by the plugin**. \
|
**Ping is calculated by the plugin**. \
|
||||||
That allows for more precision (decimal places) and to get the ping immediately after a player join
|
That allows for more precision (decimal places) and to get the ping immediately after a player join
|
||||||
|
|
||||||
|
|
32
docs/BUILDING.md
Normal file
32
docs/BUILDING.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
First, download NMS. There are two ways:
|
||||||
|
|
||||||
|
- Use `tools/download_nms.sh`
|
||||||
|
- Download BuildTools, move it into an empty directory and run:
|
||||||
|
```
|
||||||
|
java -jar BuildTools.jar --rev 1.21.4 --remapped
|
||||||
|
```
|
||||||
|
You must run this for every version you want to build for.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Then build the plugin:
|
||||||
|
|
||||||
|
1. Clone this repository:
|
||||||
|
```
|
||||||
|
git clone https://git.m724.eu/Minecon724/tweaks724
|
||||||
|
cd tweaks724
|
||||||
|
```
|
||||||
|
- You might want to `checkout` a release:
|
||||||
|
```
|
||||||
|
git checkout tags/tweaks-0.1.12
|
||||||
|
```
|
||||||
|
2. For the "native" version:
|
||||||
|
```
|
||||||
|
./mvnw package
|
||||||
|
```
|
||||||
|
For another compatible version:
|
||||||
|
```
|
||||||
|
./mvnw package -Dproject.craftbukkit.version=v1_21_R3 -Dproject.minecraft.version=1.21.4
|
||||||
|
```
|
||||||
|
|
||||||
|
Look for `tweaks-0.1.12+1.21.4.jar` in `target/`
|
|
@ -1,5 +0,0 @@
|
||||||
To setup NMS:
|
|
||||||
1. Download BuildTools, move it into an empty directory and open terminal
|
|
||||||
2. ```
|
|
||||||
java -jar BuildTools.jar --rev 1.21.1 --remapped
|
|
||||||
```
|
|
3
docs/README.md
Normal file
3
docs/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Here's the documentation.
|
||||||
|
|
||||||
|
Click above on a file to read more about a topic.
|
259
mvnw
vendored
Executable file
259
mvnw
vendored
Executable file
|
@ -0,0 +1,259 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||||
|
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
set -euf
|
||||||
|
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||||
|
|
||||||
|
# OS specific support.
|
||||||
|
native_path() { printf %s\\n "$1"; }
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN* | MINGW*)
|
||||||
|
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||||
|
native_path() { cygpath --path --windows "$1"; }
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# set JAVACMD and JAVACCMD
|
||||||
|
set_java_home() {
|
||||||
|
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||||
|
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"
|
||||||
|
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||||
|
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||||
|
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v java
|
||||||
|
)" || :
|
||||||
|
JAVACCMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v javac
|
||||||
|
)" || :
|
||||||
|
|
||||||
|
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||||
|
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# hash string like Java String::hashCode
|
||||||
|
hash_string() {
|
||||||
|
str="${1:-}" h=0
|
||||||
|
while [ -n "$str" ]; do
|
||||||
|
char="${str%"${str#?}"}"
|
||||||
|
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||||
|
str="${str#?}"
|
||||||
|
done
|
||||||
|
printf %x\\n $h
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose() { :; }
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf %s\\n "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
# MWRAPPER-139:
|
||||||
|
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||||
|
# Needed for removing poorly interpreted newline sequences when running in more
|
||||||
|
# exotic environments such as mingw bash on Windows.
|
||||||
|
printf "%s" "${1}" | tr -d '[:space:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
case "${key-}" in
|
||||||
|
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||||
|
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||||
|
esac
|
||||||
|
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
|
||||||
|
case "${distributionUrl##*/}" in
|
||||||
|
maven-mvnd-*bin.*)
|
||||||
|
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||||
|
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||||
|
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||||
|
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||||
|
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||||
|
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||||
|
*)
|
||||||
|
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||||
|
distributionPlatform=linux-amd64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||||
|
;;
|
||||||
|
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||||
|
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||||
|
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||||
|
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||||
|
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||||
|
|
||||||
|
exec_maven() {
|
||||||
|
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||||
|
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -d "$MAVEN_HOME" ]; then
|
||||||
|
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
exec_maven "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${distributionUrl-}" in
|
||||||
|
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||||
|
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||||
|
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||||
|
trap clean HUP INT TERM EXIT
|
||||||
|
else
|
||||||
|
die "cannot create temp dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
verbose "Downloading from: $distributionUrl"
|
||||||
|
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
# select .zip or .tar.gz
|
||||||
|
if ! command -v unzip >/dev/null; then
|
||||||
|
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# verbose opt
|
||||||
|
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||||
|
|
||||||
|
# normalize http auth
|
||||||
|
case "${MVNW_PASSWORD:+has-password}" in
|
||||||
|
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||||
|
verbose "Found wget ... using wget"
|
||||||
|
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||||
|
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||||
|
verbose "Found curl ... using curl"
|
||||||
|
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||||
|
elif set_java_home; then
|
||||||
|
verbose "Falling back to use Java to download"
|
||||||
|
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||||
|
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
cat >"$javaSource" <<-END
|
||||||
|
public class Downloader extends java.net.Authenticator
|
||||||
|
{
|
||||||
|
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||||
|
{
|
||||||
|
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||||
|
}
|
||||||
|
public static void main( String[] args ) throws Exception
|
||||||
|
{
|
||||||
|
setDefault( new Downloader() );
|
||||||
|
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END
|
||||||
|
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||||
|
verbose " - Compiling Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||||
|
verbose " - Running Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
if [ -n "${distributionSha256Sum-}" ]; then
|
||||||
|
distributionSha256Result=false
|
||||||
|
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||||
|
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||||
|
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
elif command -v sha256sum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
elif command -v shasum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||||
|
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $distributionSha256Result = false ]; then
|
||||||
|
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||||
|
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
if command -v unzip >/dev/null; then
|
||||||
|
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||||
|
else
|
||||||
|
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||||
|
fi
|
||||||
|
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
||||||
|
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||||
|
|
||||||
|
clean || :
|
||||||
|
exec_maven "$@"
|
149
mvnw.cmd
vendored
Normal file
149
mvnw.cmd
vendored
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
<# : batch portion
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||||
|
@SET __MVNW_CMD__=
|
||||||
|
@SET __MVNW_ERROR__=
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||||
|
@SET PSModulePath=
|
||||||
|
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||||
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||||
|
)
|
||||||
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=
|
||||||
|
@SET __MVNW_ARG0_NAME__=
|
||||||
|
@SET MVNW_USERNAME=
|
||||||
|
@SET MVNW_PASSWORD=
|
||||||
|
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
||||||
|
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||||
|
@GOTO :EOF
|
||||||
|
: end batch / begin powershell #>
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
if ($env:MVNW_VERBOSE -eq "true") {
|
||||||
|
$VerbosePreference = "Continue"
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||||
|
if (!$distributionUrl) {
|
||||||
|
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||||
|
"maven-mvnd-*" {
|
||||||
|
$USE_MVND = $true
|
||||||
|
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||||
|
$MVN_CMD = "mvnd.cmd"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$USE_MVND = $false
|
||||||
|
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
if ($env:MVNW_REPOURL) {
|
||||||
|
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||||
|
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
||||||
|
}
|
||||||
|
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||||
|
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||||
|
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
if ($env:MAVEN_USER_HOME) {
|
||||||
|
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
}
|
||||||
|
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||||
|
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||||
|
|
||||||
|
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||||
|
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||||
|
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||||
|
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||||
|
trap {
|
||||||
|
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
Write-Verbose "Downloading from: $distributionUrl"
|
||||||
|
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||||
|
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||||
|
}
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||||
|
if ($distributionSha256Sum) {
|
||||||
|
if ($USE_MVND) {
|
||||||
|
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||||
|
}
|
||||||
|
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||||
|
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||||
|
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||||
|
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||||
|
try {
|
||||||
|
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||||
|
} catch {
|
||||||
|
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||||
|
Write-Error "fail to move MAVEN_HOME"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
65
pom.xml
65
pom.xml
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
~ Copyright (C) 2024 Minecon724
|
~ Copyright (C) 2025 Minecon724
|
||||||
~ Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
~ Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
~ in the project root for the full license text.
|
~ in the project root for the full license text.
|
||||||
-->
|
-->
|
||||||
|
@ -10,15 +10,15 @@
|
||||||
|
|
||||||
<groupId>eu.m724</groupId>
|
<groupId>eu.m724</groupId>
|
||||||
<artifactId>tweaks</artifactId>
|
<artifactId>tweaks</artifactId>
|
||||||
<version>0.1.11</version>
|
<version>0.1.15-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|
||||||
<project.nms.version>v1_21_R1</project.nms.version>
|
<project.craftbukkit.version>v1_21_R3</project.craftbukkit.version>
|
||||||
<project.minecraft.version>1.21.1</project.minecraft.version>
|
<project.minecraft.version>1.21.4</project.minecraft.version>
|
||||||
<project.spigot.version>${project.minecraft.version}-R0.1-SNAPSHOT</project.spigot.version>
|
<project.spigot.version>${project.minecraft.version}-R0.1-SNAPSHOT</project.spigot.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<target>
|
<target>
|
||||||
<replace token="v1_21_R1" value="${project.nms.version}" dir="src/main">
|
<replace token="v1_21_R3" value="${project.craftbukkit.version}" dir="src/main">
|
||||||
<include name="**/*.java" />
|
<include name="**/*.java" />
|
||||||
</replace>
|
</replace>
|
||||||
</target>
|
</target>
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<target>
|
<target>
|
||||||
<replace token="${project.nms.version}" value="v1_21_R1" dir="src/main">
|
<replace token="${project.craftbukkit.version}" value="v1_21_R3" dir="src/main">
|
||||||
<include name="**/*.java" />
|
<include name="**/*.java" />
|
||||||
</replace>
|
</replace>
|
||||||
</target>
|
</target>
|
||||||
|
@ -67,37 +67,6 @@
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.6.0</version>
|
|
||||||
<configuration>
|
|
||||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
|
||||||
<minimizeJar>true</minimizeJar>
|
|
||||||
<artifactSet>
|
|
||||||
<includes>
|
|
||||||
<include>eu.m724:tweaks</include>
|
|
||||||
</includes>
|
|
||||||
</artifactSet>
|
|
||||||
<filters>
|
|
||||||
<filter>
|
|
||||||
<artifact>*</artifact>
|
|
||||||
<excludes>
|
|
||||||
<exclude>META-INF/**</exclude>
|
|
||||||
</excludes>
|
|
||||||
</filter>
|
|
||||||
</filters>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>specialsource-maven-plugin</artifactId>
|
<artifactId>specialsource-maven-plugin</artifactId>
|
||||||
|
@ -111,10 +80,8 @@
|
||||||
<id>remap-obf</id>
|
<id>remap-obf</id>
|
||||||
<configuration>
|
<configuration>
|
||||||
<srgIn>org.spigotmc:minecraft-server:${project.spigot.version}:txt:maps-mojang</srgIn>
|
<srgIn>org.spigotmc:minecraft-server:${project.spigot.version}:txt:maps-mojang</srgIn>
|
||||||
<reverse>true</reverse>
|
|
||||||
<remappedDependencies>org.spigotmc:spigot:${project.spigot.version}:jar:remapped-mojang</remappedDependencies>
|
<remappedDependencies>org.spigotmc:spigot:${project.spigot.version}:jar:remapped-mojang</remappedDependencies>
|
||||||
<remappedArtifactAttached>true</remappedArtifactAttached>
|
<reverse>true</reverse>
|
||||||
<remappedClassifierName>remapped-obf-temp-dont-use</remappedClassifierName>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
|
@ -124,7 +91,6 @@
|
||||||
</goals>
|
</goals>
|
||||||
<id>remap-spigot</id>
|
<id>remap-spigot</id>
|
||||||
<configuration>
|
<configuration>
|
||||||
<inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf-temp-dont-use.jar</inputFile>
|
|
||||||
<srgIn>org.spigotmc:minecraft-server:${project.spigot.version}:csrg:maps-spigot</srgIn>
|
<srgIn>org.spigotmc:minecraft-server:${project.spigot.version}:csrg:maps-spigot</srgIn>
|
||||||
<remappedDependencies>org.spigotmc:spigot:${project.spigot.version}:jar:remapped-obf</remappedDependencies>
|
<remappedDependencies>org.spigotmc:spigot:${project.spigot.version}:jar:remapped-obf</remappedDependencies>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -152,11 +118,6 @@
|
||||||
<id>dmulloy2-repo</id>
|
<id>dmulloy2-repo</id>
|
||||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||||
</repository>
|
</repository>
|
||||||
<!-- this repo has no ipv6 so keep that in mind -->
|
|
||||||
<repository>
|
|
||||||
<id>maxhenkel-repo</id>
|
|
||||||
<url>https://maven.maxhenkel.de/repository/public</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
<repository>
|
||||||
<id>m724-repo</id>
|
<id>m724-repo</id>
|
||||||
<url>https://git.m724.eu/api/packages/Minecon724/maven</url>
|
<url>https://git.m724.eu/api/packages/Minecon724/maven</url>
|
||||||
|
@ -167,7 +128,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>${project.spigot.version}</version>
|
<version>1.21.1-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -183,16 +144,10 @@
|
||||||
<version>5.3.0</version>
|
<version>5.3.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>de.maxhenkel.voicechat</groupId>
|
|
||||||
<artifactId>voicechat-api</artifactId>
|
|
||||||
<version>2.5.0</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>eu.m724</groupId>
|
<groupId>eu.m724</groupId>
|
||||||
<artifactId>mstats-spigot</artifactId>
|
<artifactId>mstats-spigot</artifactId>
|
||||||
<version>0.1.0</version>
|
<version>0.1.2</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -213,6 +168,6 @@
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<developerConnection>scm:git:git@git.m724.eu:Minecon724/tweaks724.git</developerConnection>
|
<developerConnection>scm:git:git@git.m724.eu:Minecon724/tweaks724.git</developerConnection>
|
||||||
<tag>tweaks-0.1.11</tag>
|
<tag>HEAD</tag>
|
||||||
</scm>
|
</scm>
|
||||||
</project>
|
</project>
|
|
@ -6,42 +6,58 @@
|
||||||
|
|
||||||
package eu.m724.tweaks;
|
package eu.m724.tweaks;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class DebugLogger {
|
public class DebugLogger {
|
||||||
static Logger logger;
|
static Logger logger;
|
||||||
|
|
||||||
public static void info(String message) {
|
public static void info(String message, Object... format) {
|
||||||
log(Level.INFO, message);
|
log(Level.INFO, message, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void warning(String message) {
|
public static void warning(String message, Object... format) {
|
||||||
log(Level.WARNING, message);
|
log(Level.WARNING, message, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void severe(String message) {
|
public static void severe(String message, Object... format) {
|
||||||
log(Level.SEVERE, message);
|
log(Level.SEVERE, message, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fine(String message) {
|
public static void fine(String message, Object... format) {
|
||||||
log(Level.FINE, message);
|
log(Level.FINE, message, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void log(Level level, String message) {
|
public static void finer(String message, Object... format) {
|
||||||
|
log(Level.FINER, message, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void log(Level level, String message, Object... format) {
|
||||||
if (logger.getLevel().intValue() > level.intValue()) return;
|
if (logger.getLevel().intValue() > level.intValue()) return;
|
||||||
|
|
||||||
var caller = Thread.currentThread().getStackTrace()[3].getClassName();
|
var caller = Thread.currentThread().getStackTrace()[3].getClassName();
|
||||||
|
|
||||||
|
if (caller.equals(TweaksModule.class.getName())) {
|
||||||
|
var pcaller = Thread.currentThread().getStackTrace()[4].getClassName();
|
||||||
|
if (pcaller.endsWith("Module"))
|
||||||
|
caller = pcaller;
|
||||||
|
}
|
||||||
|
|
||||||
if (caller.startsWith("eu.m724.tweaks."))
|
if (caller.startsWith("eu.m724.tweaks."))
|
||||||
caller = caller.substring(15);
|
caller = caller.substring(15);
|
||||||
|
|
||||||
message = "[" + caller + "] " + message;
|
message = "[" + caller + "] " + message.formatted(format);
|
||||||
|
|
||||||
if (level.intValue() < Level.INFO.intValue()) { // levels below info are never logged even if set for some reason
|
if (level.intValue() < Level.INFO.intValue()) { // levels below info are never logged even if set for some reason
|
||||||
level = Level.INFO;
|
|
||||||
// colors text gray (cyan is close to gray)
|
// colors text gray (cyan is close to gray)
|
||||||
message = "\033[36m" + message + "\033[39m";
|
if (level == Level.FINE) {
|
||||||
|
message = "\033[38;5;250m" + message + "\033[39m";
|
||||||
|
} else {
|
||||||
|
message = "\033[38;5;245m" + message + "\033[39m";
|
||||||
|
}
|
||||||
|
level = Level.INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(level, message);
|
logger.log(level, message);
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks;
|
|
||||||
|
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public record TweaksConfig(
|
|
||||||
boolean metrics,
|
|
||||||
boolean debug,
|
|
||||||
String locale,
|
|
||||||
|
|
||||||
boolean worldborderExpand,
|
|
||||||
boolean worldborderHide,
|
|
||||||
|
|
||||||
boolean brandEnabled,
|
|
||||||
String brandText,
|
|
||||||
boolean brandShowPing,
|
|
||||||
boolean brandShowMspt,
|
|
||||||
|
|
||||||
boolean doorDoubleOpen,
|
|
||||||
boolean doorKnocking,
|
|
||||||
|
|
||||||
boolean motdEnabled,
|
|
||||||
String motdSet,
|
|
||||||
|
|
||||||
boolean chatEnabled,
|
|
||||||
boolean chatLocalEvents,
|
|
||||||
String chatDefaultName,
|
|
||||||
int chatRadius,
|
|
||||||
|
|
||||||
boolean compassEnabled,
|
|
||||||
int compassWidth,
|
|
||||||
int compassPrecision,
|
|
||||||
|
|
||||||
boolean pomodoroEnabled,
|
|
||||||
boolean pomodoroForce,
|
|
||||||
|
|
||||||
boolean updaterEnabled,
|
|
||||||
|
|
||||||
boolean hardcoreEnabled,
|
|
||||||
float hardcoreChance,
|
|
||||||
|
|
||||||
boolean sleepEnabled,
|
|
||||||
boolean sleepInstant,
|
|
||||||
|
|
||||||
boolean authEnabled,
|
|
||||||
boolean authForce,
|
|
||||||
String authDomain,
|
|
||||||
|
|
||||||
boolean redstoneEnabled,
|
|
||||||
String redstoneListen,
|
|
||||||
|
|
||||||
Map<String, Object> knockbackModifiers,
|
|
||||||
|
|
||||||
boolean killswitchEnabled,
|
|
||||||
String killswitchListen
|
|
||||||
) {
|
|
||||||
public static final int CONFIG_VERSION = 2;
|
|
||||||
private static TweaksConfig config;
|
|
||||||
|
|
||||||
public static TweaksConfig getConfig() {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TweaksConfig load(Plugin plugin) {
|
|
||||||
plugin.saveDefaultConfig();
|
|
||||||
FileConfiguration config = plugin.getConfig();
|
|
||||||
|
|
||||||
int configVersion = config.getInt("magic number don't modify this", 0);
|
|
||||||
RuntimeException exception = new RuntimeException("Config version is %d, expected %d".formatted(configVersion, CONFIG_VERSION));
|
|
||||||
|
|
||||||
if (configVersion == 0) {
|
|
||||||
throw exception;
|
|
||||||
} else if (configVersion < CONFIG_VERSION) {
|
|
||||||
throw new RuntimeException("Please follow update instructions https://www.spigotmc.org/resources/tweaks724.121057/updates", exception);
|
|
||||||
} else if (configVersion > CONFIG_VERSION) {
|
|
||||||
throw new RuntimeException("Did you downgrade the plugin? Remove config.yml and let the plugin re-create it", exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean metrics = config.getBoolean("metrics");
|
|
||||||
boolean debug = config.getBoolean("debug", false);
|
|
||||||
String locale = config.getString("locale", "US");
|
|
||||||
|
|
||||||
boolean worldborderExpand = config.getBoolean("worldborder.expand");
|
|
||||||
boolean worldborderHide = config.getBoolean("worldborder.hide");
|
|
||||||
|
|
||||||
boolean brandEnabled = config.getBoolean("brand.enabled");
|
|
||||||
String brandText = config.getString("brand.text");
|
|
||||||
boolean brandShowPing = config.getBoolean("brand.showPing");
|
|
||||||
boolean brandShowMspt = config.getBoolean("brand.showMspt");
|
|
||||||
|
|
||||||
boolean doorDoubleOpen = config.getBoolean("doors.doubleOpen");
|
|
||||||
boolean doorKnocking = config.getBoolean("doors.knocking");
|
|
||||||
|
|
||||||
String motdSet = config.getString("motd.set");
|
|
||||||
boolean motdEnabled = !(motdSet.equals("false") || motdSet.isBlank());
|
|
||||||
|
|
||||||
boolean chatEnabled = config.getBoolean("chat.enabled");
|
|
||||||
boolean chatLocalEvents = config.getBoolean("chat.localEvents");
|
|
||||||
String chatDefaultName = config.getString("chat.defaultName");
|
|
||||||
int chatRadius = config.getInt("chat.radius");
|
|
||||||
|
|
||||||
boolean compassEnabled = config.getBoolean("compass.enabled");
|
|
||||||
int compassWidth = config.getInt("compass.width");
|
|
||||||
int compassPrecision = config.getInt("compass.precision");
|
|
||||||
|
|
||||||
boolean pomodoroEnabled = config.getBoolean("pomodoro.enabled");
|
|
||||||
boolean pomodoroForce = config.getBoolean("pomodoro.force");
|
|
||||||
|
|
||||||
boolean updaterEnabled = config.getBoolean("updater.enabled");
|
|
||||||
|
|
||||||
boolean hardcoreEnabled = config.getBoolean("hardcore.enabled");
|
|
||||||
float hardcoreChance = (float) config.getDouble("hardcore.chance");
|
|
||||||
|
|
||||||
boolean sleepEnabled = config.getBoolean("sleep.enabled");
|
|
||||||
boolean sleepInstant = config.getBoolean("sleep.instant");
|
|
||||||
|
|
||||||
boolean authEnabled = config.getBoolean("auth.enabled");
|
|
||||||
boolean authForce = config.getBoolean("auth.force");
|
|
||||||
String authHostname = config.getString("auth.domain");
|
|
||||||
|
|
||||||
boolean redstoneEnabled = config.getBoolean("retstone.enabled");
|
|
||||||
String redstoneListen = config.getString("retstone.listen");
|
|
||||||
|
|
||||||
// this is processed when initing
|
|
||||||
Map<String, Object> knockbackModifiers = config.getConfigurationSection("knockback").getValues(false);
|
|
||||||
|
|
||||||
boolean killswitchEnabled = config.getBoolean("killswitch.enabled");
|
|
||||||
String killswitchListen = config.getString("killswitch.listen");
|
|
||||||
|
|
||||||
TweaksConfig.config = new TweaksConfig(
|
|
||||||
debug, metrics, locale,
|
|
||||||
worldborderExpand, worldborderHide,
|
|
||||||
brandEnabled, brandText, brandShowPing, brandShowMspt,
|
|
||||||
doorDoubleOpen, doorKnocking,
|
|
||||||
motdEnabled, motdSet,
|
|
||||||
chatEnabled, chatLocalEvents, chatDefaultName, chatRadius,
|
|
||||||
compassEnabled, compassWidth, compassPrecision,
|
|
||||||
pomodoroEnabled, pomodoroForce,
|
|
||||||
updaterEnabled,
|
|
||||||
hardcoreEnabled, hardcoreChance,
|
|
||||||
sleepEnabled, sleepInstant,
|
|
||||||
authEnabled, authForce, authHostname,
|
|
||||||
redstoneEnabled, redstoneListen,
|
|
||||||
knockbackModifiers,
|
|
||||||
killswitchEnabled, killswitchListen
|
|
||||||
);
|
|
||||||
|
|
||||||
return TweaksConfig.config;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,32 +7,40 @@
|
||||||
package eu.m724.tweaks;
|
package eu.m724.tweaks;
|
||||||
|
|
||||||
import eu.m724.mstats.MStatsPlugin;
|
import eu.m724.mstats.MStatsPlugin;
|
||||||
import eu.m724.tweaks.alert.AlertManager;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import eu.m724.tweaks.auth.AuthManager;
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import eu.m724.tweaks.chat.ChatManager;
|
import eu.m724.tweaks.module.alert.AlertModule;
|
||||||
import eu.m724.tweaks.door.DoorKnockListener;
|
import eu.m724.tweaks.module.auth.AuthModule;
|
||||||
import eu.m724.tweaks.door.DoorOpenListener;
|
import eu.m724.tweaks.module.chat.ChatModule;
|
||||||
import eu.m724.tweaks.full.FullListener;
|
import eu.m724.tweaks.module.door.DoorKnockModule;
|
||||||
import eu.m724.tweaks.hardcore.HardcoreManager;
|
import eu.m724.tweaks.module.door.DoorOpenModule;
|
||||||
import eu.m724.tweaks.killswitch.KillswitchManager;
|
import eu.m724.tweaks.module.durability.DurabilityModule;
|
||||||
import eu.m724.tweaks.knockback.KnockbackListener;
|
import eu.m724.tweaks.module.full.FullModule;
|
||||||
import eu.m724.tweaks.motd.MotdManager;
|
import eu.m724.tweaks.module.hardcore.HardcoreModule;
|
||||||
import eu.m724.tweaks.ping.F3NameListener;
|
import eu.m724.tweaks.module.killswitch.KillswitchModule;
|
||||||
import eu.m724.tweaks.ping.PingChecker;
|
import eu.m724.tweaks.module.knockback.KnockbackModule;
|
||||||
import eu.m724.tweaks.pomodoro.PomodoroManager;
|
import eu.m724.tweaks.module.motd.MotdModule;
|
||||||
import eu.m724.tweaks.redstone.RedstoneManager;
|
import eu.m724.tweaks.module.ping.F3NameListener;
|
||||||
import eu.m724.tweaks.sleep.SleepManager;
|
import eu.m724.tweaks.module.ping.PingChecker;
|
||||||
import eu.m724.tweaks.updater.UpdaterManager;
|
import eu.m724.tweaks.module.pomodoro.PomodoroModule;
|
||||||
import eu.m724.tweaks.worldborder.WorldBorderExpander;
|
import eu.m724.tweaks.module.redstone.RedstoneModule;
|
||||||
import eu.m724.tweaks.worldborder.WorldBorderHider;
|
import eu.m724.tweaks.module.sleep.SleepModule;
|
||||||
|
import eu.m724.tweaks.module.swing.SwingModule;
|
||||||
|
import eu.m724.tweaks.module.updater.UpdaterModule;
|
||||||
|
import eu.m724.tweaks.module.wordcoords.WordCoordsModule;
|
||||||
|
import eu.m724.tweaks.module.worldborder.WorldBorderExpandModule;
|
||||||
|
import eu.m724.tweaks.module.worldborder.WorldBorderHideModule;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class TweaksPlugin extends MStatsPlugin {
|
public class TweaksPlugin extends MStatsPlugin {
|
||||||
|
private static TweaksPlugin INSTANCE;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
long start = System.nanoTime();
|
long start = System.nanoTime();
|
||||||
|
INSTANCE = this;
|
||||||
|
|
||||||
if (getServer().getPluginManager().getPlugin("ProtocolLib") == null) {
|
if (getServer().getPluginManager().getPlugin("ProtocolLib") == null) {
|
||||||
getLogger().severe("ProtocolLib is required for this plugin.");
|
getLogger().severe("ProtocolLib is required for this plugin.");
|
||||||
|
@ -41,41 +49,61 @@ public class TweaksPlugin extends MStatsPlugin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TweaksConfig config = TweaksConfig.load(this);
|
TweaksConfig config;
|
||||||
|
try {
|
||||||
|
config = TweaksConfig.load(this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Exception loading config", e);
|
||||||
|
}
|
||||||
|
|
||||||
getLogger().setLevel(config.debug() ? Level.FINEST : Level.INFO);
|
getLogger().setLevel(config.debug() ? Level.FINEST : Level.INFO);
|
||||||
DebugLogger.logger = getLogger();
|
DebugLogger.logger = getLogger();
|
||||||
DebugLogger.fine("Debug enabled. There may be performance issues.");
|
|
||||||
|
|
||||||
DebugLogger.fine("Enabling Language");
|
if (config.debug()) {
|
||||||
|
DebugLogger.warning("Debug harms performance");
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugLogger.fine("Language");
|
||||||
new Language(Locale.of(config.locale())); // TODO
|
new Language(Locale.of(config.locale())); // TODO
|
||||||
DebugLogger.fine(Language.getString("languageNotice", Language.getString("language"), Language.getString("languageEnglish")));
|
DebugLogger.fine(Language.getString("languageNotice", Language.getString("language"), Language.getString("languageEnglish")));
|
||||||
|
|
||||||
|
var runningVersion = getServer().getBukkitVersion();
|
||||||
|
var targetVersion = getTargetVersion();
|
||||||
|
|
||||||
|
if (!runningVersion.equals(targetVersion)) {
|
||||||
|
// the incompatibility can be between 1.21.4-R0.1-SNAPSHOT and 1.21.4-R1-SNAPSHOT
|
||||||
|
var runningMc = runningVersion.split("-")[0];
|
||||||
|
var targetMc = targetVersion.split("-")[0];
|
||||||
|
if (!runningMc.equals(targetMc)) {
|
||||||
|
targetVersion = targetMc;
|
||||||
|
runningVersion = runningMc;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger().warning("This plugin was built for %s. This server is running %s.".formatted(targetVersion, runningVersion));
|
||||||
|
getLogger().warning("Some modules will not work. Disable those modules, or make a compatible build yourself:");
|
||||||
|
getLogger().warning("https://git.m724.eu/Minecon724/tweaks724/src/branch/master/docs/BUILDING.md");
|
||||||
|
}
|
||||||
|
|
||||||
/* start modules */
|
/* start modules */
|
||||||
|
|
||||||
if (config.worldborderHide()) {
|
if (config.worldborderHide()) {
|
||||||
DebugLogger.fine("Enabling Worldborder hide");
|
TweaksModule.init(WorldBorderHideModule.class);
|
||||||
new WorldBorderHider().init(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.worldborderExpand()) {
|
if (config.worldborderExpand()) {
|
||||||
DebugLogger.fine("Enabling Worldborder expand");
|
TweaksModule.init(WorldBorderExpandModule.class);
|
||||||
new WorldBorderExpander().init(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.chatEnabled()) {
|
if (config.chatEnabled()) {
|
||||||
DebugLogger.fine("Enabling Chat");
|
TweaksModule.init(ChatModule.class);
|
||||||
new ChatManager(this).init(getCommand("chat"), getCommand("chatmanage"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.doorKnocking()) {
|
if (config.doorKnocking()) {
|
||||||
DebugLogger.fine("Enabling Door knock");
|
TweaksModule.init(DoorKnockModule.class);
|
||||||
getServer().getPluginManager().registerEvents(new DoorKnockListener(), this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.doorDoubleOpen()) {
|
if (config.doorDoubleOpen()) {
|
||||||
DebugLogger.fine("Enabling Door double open");
|
TweaksModule.init(DoorOpenModule.class);
|
||||||
getServer().getPluginManager().registerEvents(new DoorOpenListener(), this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.brandEnabled()) {
|
if (config.brandEnabled()) {
|
||||||
|
@ -87,54 +115,51 @@ public class TweaksPlugin extends MStatsPlugin {
|
||||||
new PingChecker(this).init(getCommand("ping"));
|
new PingChecker(this).init(getCommand("ping"));
|
||||||
|
|
||||||
if (config.motdEnabled()) {
|
if (config.motdEnabled()) {
|
||||||
DebugLogger.fine("Enabling MOTD");
|
TweaksModule.init(MotdModule.class);
|
||||||
new MotdManager(this).init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.pomodoroEnabled()) {
|
if (config.pomodoroEnabled()) {
|
||||||
DebugLogger.fine("Enabling Pomodoro");
|
TweaksModule.init(PomodoroModule.class);
|
||||||
new PomodoroManager(this).init(getCommand("pomodoro"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.updaterEnabled()) {
|
if (config.updaterEnabled()) {
|
||||||
DebugLogger.fine("Enabling Updater");
|
TweaksModule.init(UpdaterModule.class);
|
||||||
new UpdaterManager(this).init(getCommand("updates"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.hardcoreEnabled()) {
|
if (config.hardcoreEnabled()) {
|
||||||
DebugLogger.fine("Enabling Hardcore");
|
TweaksModule.init(HardcoreModule.class);
|
||||||
new HardcoreManager().init(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.sleepEnabled()) {
|
if (config.sleepEnabled()) {
|
||||||
DebugLogger.fine("Enabling Sleep");
|
TweaksModule.init(SleepModule.class);
|
||||||
new SleepManager().init(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.authEnabled()) {
|
if (config.authEnabled()) {
|
||||||
DebugLogger.fine("Enabling Auth");
|
TweaksModule.init(AuthModule.class);
|
||||||
new AuthManager(this).init(getCommand("tauth"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugLogger.fine("Enabling Alert");
|
TweaksModule.init(AlertModule.class);
|
||||||
new AlertManager(this).init(getCommand("emergencyalert"));
|
|
||||||
|
|
||||||
DebugLogger.fine("Enabling Full");
|
TweaksModule.init(FullModule.class);
|
||||||
getServer().getPluginManager().registerEvents(new FullListener(), this);
|
|
||||||
|
|
||||||
if (config.redstoneEnabled()) {
|
if (config.redstoneEnabled()) {
|
||||||
DebugLogger.fine("Enabling Redstone");
|
TweaksModule.init(RedstoneModule.class);
|
||||||
new RedstoneManager(this).init(getCommand("retstone"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugLogger.fine("Enabling Knockback");
|
TweaksModule.init(KnockbackModule.class);
|
||||||
new KnockbackListener(this);
|
|
||||||
|
|
||||||
if (config.killswitchEnabled()) {
|
if (config.killswitchEnabled()) {
|
||||||
DebugLogger.fine("Enabling Killswitch");
|
TweaksModule.init(KillswitchModule.class);
|
||||||
new KillswitchManager(this).init(getCommand("servkill"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.swingEnabled()) {
|
||||||
|
TweaksModule.init(SwingModule.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
TweaksModule.init(DurabilityModule.class);
|
||||||
|
|
||||||
|
TweaksModule.init(WordCoordsModule.class);
|
||||||
|
|
||||||
/* end modules */
|
/* end modules */
|
||||||
|
|
||||||
if (config.metrics()) {
|
if (config.metrics()) {
|
||||||
|
@ -142,10 +167,23 @@ public class TweaksPlugin extends MStatsPlugin {
|
||||||
mStats(1);
|
mStats(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugLogger.fine("Took %.3f milliseconds".formatted((System.nanoTime() - start) / 1000000.0));
|
DebugLogger.fine("Took %.3f milliseconds", (System.nanoTime() - start) / 1000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTargetVersion() {
|
||||||
|
var permission = getServer().getPluginManager().getPermission("7weaks724.ignore.this");
|
||||||
|
|
||||||
|
var desc = permission.getDescription().substring("Internal, not for use. ".length()).split(",");
|
||||||
|
var version = desc[0];
|
||||||
|
|
||||||
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasResource(String resource) {
|
public boolean hasResource(String resource) {
|
||||||
return this.getClassLoader().getResource(resource) != null;
|
return this.getClassLoader().getResource(resource) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TweaksPlugin getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.alert;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.ListenerPriority;
|
|
||||||
import com.comphenix.protocol.events.PacketAdapter;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
|
||||||
import eu.m724.tweaks.TweaksPlugin;
|
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class AlertManager {
|
|
||||||
private final TweaksPlugin plugin;
|
|
||||||
|
|
||||||
private BukkitTask notifyTask;
|
|
||||||
static Alert current;
|
|
||||||
static Map<Player, Integer> pages = new HashMap<>();
|
|
||||||
|
|
||||||
public AlertManager(TweaksPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(PluginCommand command) {
|
|
||||||
command.setExecutor(new AlertCommand(this));
|
|
||||||
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
|
||||||
plugin,
|
|
||||||
ListenerPriority.NORMAL,
|
|
||||||
PacketType.Play.Client.ENCHANT_ITEM
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onPacketReceiving(PacketEvent event) {
|
|
||||||
if (current == null) return;
|
|
||||||
if (!current.isOpen(event.getPlayer())) return;
|
|
||||||
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
|
|
||||||
int windowId, buttonId;
|
|
||||||
windowId = packet.getIntegers().read(0);
|
|
||||||
buttonId = packet.getIntegers().read(1);
|
|
||||||
|
|
||||||
var page = pages.getOrDefault(event.getPlayer(),1);
|
|
||||||
|
|
||||||
if (buttonId == 1) { // prev page
|
|
||||||
page--;
|
|
||||||
} else if (buttonId == 2) { // nextc page
|
|
||||||
page++;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pages.put(event.getPlayer(), page);
|
|
||||||
var npacket = new PacketContainer(PacketType.Play.Server.WINDOW_DATA);
|
|
||||||
npacket.getIntegers().write(0, windowId);
|
|
||||||
npacket.getIntegers().write(1, 0);
|
|
||||||
npacket.getIntegers().write(2, page);
|
|
||||||
ProtocolLibrary.getProtocolManager().sendServerPacket(event.getPlayer(), npacket);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Alert start(String... content) {
|
|
||||||
stop();
|
|
||||||
current = new Alert(content);
|
|
||||||
notifyTask = new AlertRunnable(current, v -> this.stop()).runTaskTimer(plugin, 0, 10);
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
if (current == null) return;
|
|
||||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
|
||||||
if (current.isOpen(player))
|
|
||||||
player.closeInventory();
|
|
||||||
}
|
|
||||||
pages.clear();
|
|
||||||
notifyTask.cancel();
|
|
||||||
current = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.auth;
|
|
||||||
|
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class AuthManager {
|
|
||||||
private final AuthStorage authStorage;
|
|
||||||
private final Plugin plugin;
|
|
||||||
|
|
||||||
public AuthManager(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.authStorage = new AuthStorage(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(PluginCommand command) {
|
|
||||||
plugin.getServer().getPluginManager().registerEvents(new AuthListener(authStorage), plugin);
|
|
||||||
command.setExecutor(new AuthCommands(authStorage));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.chat;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.Language;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class ChatCommands implements CommandExecutor {
|
|
||||||
private final ChatManager manager;
|
|
||||||
|
|
||||||
public ChatCommands(ChatManager manager) {
|
|
||||||
this.manager = manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, Command command, @NotNull String label, String[] args) {
|
|
||||||
if (command.getName().equals("chat")) {
|
|
||||||
Player player = (Player) sender;
|
|
||||||
ChatRoom chatRoom = manager.getPlayerChatRoom(player);
|
|
||||||
|
|
||||||
if (args.length == 0) { // show room
|
|
||||||
player.spigot().sendMessage(chatRoom.getInfoComponent());
|
|
||||||
} else { // join room
|
|
||||||
String id = args[0];
|
|
||||||
|
|
||||||
if (id.equals(chatRoom.id)) {
|
|
||||||
sender.spigot().sendMessage(Language.getComponent("chatAlreadyHere", ChatColor.GRAY));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String password = null;
|
|
||||||
if (args.length > 1) {
|
|
||||||
password = Arrays.stream(args).skip(1).collect(Collectors.joining(" "));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean authenticated = false;
|
|
||||||
BaseComponent component = null;
|
|
||||||
ChatRoom newRoom = manager.getById(id);
|
|
||||||
if (newRoom != null) {
|
|
||||||
if (newRoom.password != null) {
|
|
||||||
if (newRoom.password.equals(password)) {
|
|
||||||
authenticated = true;
|
|
||||||
} else if (password == null) {
|
|
||||||
component = Language.getComponent("chatPasswordProtected", ChatColor.RED);
|
|
||||||
} else {
|
|
||||||
component = Language.getComponent("chatWrongPassword", ChatColor.RED);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
authenticated = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
component = Language.getComponent("chatNoSuchRoom", ChatColor.RED, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authenticated) {
|
|
||||||
/*component = new ComponentBuilder(Language.getComponent("chatJoined", ChatColor.GOLD))
|
|
||||||
.append(" ")
|
|
||||||
.append(ChatFormatUtils.formatChatRoom(chatRoom)).color(newRoom.color)
|
|
||||||
.build();*/
|
|
||||||
player.sendMessage("");
|
|
||||||
manager.setPlayerChatRoom(newRoom, player);
|
|
||||||
} else {
|
|
||||||
player.spigot().sendMessage(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else if (command.getName().equals("chatmanage")) {
|
|
||||||
Player player = (Player) sender;
|
|
||||||
ChatRoom chatRoom = manager.getPlayerChatRoom(player);
|
|
||||||
boolean isOwner = player.equals(chatRoom.owner);
|
|
||||||
|
|
||||||
if (args.length > 1) {
|
|
||||||
String action = args[0];
|
|
||||||
String argument = args[1];
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case "create" -> {
|
|
||||||
try {
|
|
||||||
ChatRoom newRoom = manager.createChatRoom(argument, null, player);
|
|
||||||
sender.sendMessage("Created a chat room. Join it: /c " + newRoom.id);
|
|
||||||
sender.sendMessage("You might also want to protect it with a password: /cm setpassword");
|
|
||||||
} catch (ChatManager.InvalidIdException e) {
|
|
||||||
sender.sendMessage("ID is invalid: " + e.getMessage());
|
|
||||||
} catch (ChatManager.ChatRoomExistsException e) {
|
|
||||||
sender.sendMessage("Room %s already exists".formatted(argument));
|
|
||||||
} catch (IOException e) {
|
|
||||||
sender.sendMessage("Failed to create room");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "delete" -> {
|
|
||||||
if (argument.equals(chatRoom.id)) {
|
|
||||||
if (isOwner) {
|
|
||||||
manager.deleteChatRoom(chatRoom);
|
|
||||||
sender.sendMessage("Room %s deleted".formatted(chatRoom.id));
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("Pass %s as an argument to confirm".formatted(chatRoom.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "setowner" -> {
|
|
||||||
if (isOwner) {
|
|
||||||
Player newOwner = Bukkit.getPlayer(argument);
|
|
||||||
if (newOwner != null && newOwner.isOnline()) {
|
|
||||||
chatRoom.owner = newOwner;
|
|
||||||
try {
|
|
||||||
manager.saveChatRoom(chatRoom);
|
|
||||||
sender.sendMessage("Owner changed to " + newOwner.getName());
|
|
||||||
} catch (IOException e) {
|
|
||||||
sender.sendMessage("Failed to change owner");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("Player must be online");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "setpassword" -> {
|
|
||||||
if (isOwner) {
|
|
||||||
chatRoom.password = Arrays.stream(args).skip(1).collect(Collectors.joining(" "));
|
|
||||||
try {
|
|
||||||
manager.saveChatRoom(chatRoom);
|
|
||||||
sender.sendMessage("Password changed");
|
|
||||||
} catch (IOException e) {
|
|
||||||
sender.sendMessage("Failed to change password");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "setcolor" -> {
|
|
||||||
if (isOwner) {
|
|
||||||
ChatColor newColor = ChatColor.of(argument);
|
|
||||||
if (newColor != null) {
|
|
||||||
chatRoom.color = newColor;
|
|
||||||
try {
|
|
||||||
manager.saveChatRoom(chatRoom);
|
|
||||||
sender.sendMessage("Message color changed to " + newColor.getName());
|
|
||||||
} catch (IOException e) {
|
|
||||||
sender.sendMessage("Failed to change color");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("Invalid color");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
sender.sendMessage("Actions: create, delete, setowner, setpassword, setcolor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (args.length > 0) {
|
|
||||||
switch (args[0]) {
|
|
||||||
case "create" ->
|
|
||||||
sender.sendMessage("Please pass a room name as an argument. The room name must be of characters and digits.");
|
|
||||||
case "delete" ->
|
|
||||||
sender.sendMessage("You want to delete room %s. Confirm by passing its name as an argument for this action.".formatted(chatRoom.id));
|
|
||||||
case "setowner" ->
|
|
||||||
sender.sendMessage("To transfer ownership of room %s, pass the new owner name as an argument for this action.".formatted(chatRoom.id));
|
|
||||||
case "setpassword" ->
|
|
||||||
sender.sendMessage("To change the password of room %s, pass the new password as an argument for this action.".formatted(chatRoom.id));
|
|
||||||
case "setcolor" ->
|
|
||||||
sender.sendMessage("To change the message color of room %s, pass the new color as an argument for this action. #hex or color name.".formatted(chatRoom.id));
|
|
||||||
default ->
|
|
||||||
sender.sendMessage("Actions: create, delete, setowner, setpassword, setcolor");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("Actions: create, delete, setowner, setpassword, setcolor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.compass;
|
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class CompassManager {
|
|
||||||
private final Plugin plugin;
|
|
||||||
|
|
||||||
public CompassManager(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
plugin.getServer().getPluginManager().registerEvents(new CompassListener(), plugin);
|
|
||||||
}
|
|
||||||
}
|
|
143
src/main/java/eu/m724/tweaks/config/ConfigLoader.java
Normal file
143
src/main/java/eu/m724/tweaks/config/ConfigLoader.java
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.config;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
class ConfigLoader {
|
||||||
|
private final FileConfiguration configuration;
|
||||||
|
private final List<String> missing = new ArrayList<>();
|
||||||
|
|
||||||
|
ConfigLoader(FileConfiguration configuration) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> getMissing() {
|
||||||
|
return missing;
|
||||||
|
}
|
||||||
|
|
||||||
|
TweaksConfig load() {
|
||||||
|
boolean metrics = configuration.getBoolean("metrics", false);
|
||||||
|
boolean debug = configuration.getBoolean("debug", false);
|
||||||
|
String locale = configuration.getString("locale", "US");
|
||||||
|
|
||||||
|
boolean worldborderExpand = getBoolean("worldborder.expand");
|
||||||
|
boolean worldborderHide = getBoolean("worldborder.hide");
|
||||||
|
|
||||||
|
boolean brandEnabled = getBoolean("brand.enabled");
|
||||||
|
String brandText = getString("brand.text");
|
||||||
|
boolean brandShowPing = getBoolean("brand.showPing");
|
||||||
|
boolean brandShowMspt = getBoolean("brand.showMspt");
|
||||||
|
|
||||||
|
boolean doorDoubleOpen = getBoolean("doors.doubleOpen");
|
||||||
|
boolean doorKnocking = getBoolean("doors.knocking");
|
||||||
|
|
||||||
|
boolean motdEnabled = getBoolean("motd.enabled");
|
||||||
|
String motdSet = getString("motd.set");
|
||||||
|
|
||||||
|
boolean chatEnabled = getBoolean("chat.enabled");
|
||||||
|
boolean chatLocalEvents = getBoolean("chat.localEvents");
|
||||||
|
String chatDefaultName = getString("chat.defaultName");
|
||||||
|
int chatRadius = getInt("chat.radius");
|
||||||
|
|
||||||
|
boolean compassEnabled = getBoolean("compass.enabled");
|
||||||
|
int compassWidth = getInt("compass.width");
|
||||||
|
int compassPrecision = getInt("compass.precision");
|
||||||
|
|
||||||
|
boolean pomodoroEnabled = getBoolean("pomodoro.enabled");
|
||||||
|
boolean pomodoroForce = getBoolean("pomodoro.force");
|
||||||
|
|
||||||
|
boolean updaterEnabled = getBoolean("updater.enabled");
|
||||||
|
|
||||||
|
boolean hardcoreEnabled = getBoolean("hardcore.enabled");
|
||||||
|
double hardcoreChance = getDouble("hardcore.chance");
|
||||||
|
|
||||||
|
boolean sleepEnabled = getBoolean("sleep.enabled");
|
||||||
|
boolean sleepInstant = getBoolean("sleep.instant");
|
||||||
|
double sleepHeal = getDouble("sleep.heal");
|
||||||
|
|
||||||
|
boolean authEnabled = getBoolean("auth.enabled");
|
||||||
|
boolean authForce = getBoolean("auth.force");
|
||||||
|
String authHostname = getString("auth.domain");
|
||||||
|
|
||||||
|
boolean redstoneEnabled = getBoolean("retstone.enabled");
|
||||||
|
String redstoneListen = getString("retstone.listen");
|
||||||
|
|
||||||
|
// this is processed when initing knockback module
|
||||||
|
Map<String, Object> knockbackModifiers = getValues("knockback");
|
||||||
|
|
||||||
|
boolean killswitchEnabled = getBoolean("killswitch.enabled");
|
||||||
|
String killswitchListen = getString("killswitch.listen");
|
||||||
|
|
||||||
|
boolean swingEnabled = getBoolean("swing.enabled");
|
||||||
|
|
||||||
|
return new TweaksConfig(
|
||||||
|
metrics, debug, locale,
|
||||||
|
worldborderExpand, worldborderHide,
|
||||||
|
brandEnabled, brandText, brandShowPing, brandShowMspt,
|
||||||
|
doorDoubleOpen, doorKnocking,
|
||||||
|
motdEnabled, motdSet,
|
||||||
|
chatEnabled, chatLocalEvents, chatDefaultName, chatRadius,
|
||||||
|
compassEnabled, compassWidth, compassPrecision,
|
||||||
|
pomodoroEnabled, pomodoroForce,
|
||||||
|
updaterEnabled,
|
||||||
|
hardcoreEnabled, hardcoreChance,
|
||||||
|
sleepEnabled, sleepInstant, sleepHeal,
|
||||||
|
authEnabled, authForce, authHostname,
|
||||||
|
redstoneEnabled, redstoneListen,
|
||||||
|
knockbackModifiers,
|
||||||
|
killswitchEnabled, killswitchListen,
|
||||||
|
swingEnabled
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getDouble(String key) {
|
||||||
|
if (!configuration.contains(key))
|
||||||
|
missing.add(key);
|
||||||
|
|
||||||
|
// we return the whatever default value
|
||||||
|
return configuration.getDouble(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getInt(String key) {
|
||||||
|
if (!configuration.contains(key))
|
||||||
|
missing.add(key);
|
||||||
|
|
||||||
|
return configuration.getInt(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getBoolean(String key) {
|
||||||
|
if (!configuration.contains(key))
|
||||||
|
missing.add(key);
|
||||||
|
|
||||||
|
return configuration.getBoolean(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getString(String key) {
|
||||||
|
if (!configuration.contains(key))
|
||||||
|
missing.add(key);
|
||||||
|
|
||||||
|
return configuration.getString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getValues(String key) {
|
||||||
|
var cs = configuration.getConfigurationSection(key);
|
||||||
|
|
||||||
|
if (cs == null) {
|
||||||
|
missing.add(key);
|
||||||
|
// the default is null, which is bad
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs.getValues(false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class MissingFieldsException extends Exception {
|
||||||
|
private final List<String> missing;
|
||||||
|
|
||||||
|
MissingFieldsException(List<String> missing) {
|
||||||
|
this.missing = missing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return String.join(", ", missing);
|
||||||
|
}
|
||||||
|
}
|
103
src/main/java/eu/m724/tweaks/config/TweaksConfig.java
Normal file
103
src/main/java/eu/m724/tweaks/config/TweaksConfig.java
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.config;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public record TweaksConfig(
|
||||||
|
boolean metrics,
|
||||||
|
boolean debug,
|
||||||
|
String locale,
|
||||||
|
|
||||||
|
boolean worldborderExpand,
|
||||||
|
boolean worldborderHide,
|
||||||
|
|
||||||
|
boolean brandEnabled,
|
||||||
|
String brandText,
|
||||||
|
boolean brandShowPing,
|
||||||
|
boolean brandShowMspt,
|
||||||
|
|
||||||
|
boolean doorDoubleOpen,
|
||||||
|
boolean doorKnocking,
|
||||||
|
|
||||||
|
boolean motdEnabled,
|
||||||
|
String motdSet,
|
||||||
|
|
||||||
|
boolean chatEnabled,
|
||||||
|
boolean chatLocalEvents,
|
||||||
|
String chatDefaultName,
|
||||||
|
int chatRadius,
|
||||||
|
|
||||||
|
boolean compassEnabled,
|
||||||
|
int compassWidth,
|
||||||
|
int compassPrecision,
|
||||||
|
|
||||||
|
boolean pomodoroEnabled,
|
||||||
|
boolean pomodoroForce,
|
||||||
|
|
||||||
|
boolean updaterEnabled,
|
||||||
|
|
||||||
|
boolean hardcoreEnabled,
|
||||||
|
double hardcoreChance,
|
||||||
|
|
||||||
|
boolean sleepEnabled,
|
||||||
|
boolean sleepInstant,
|
||||||
|
double sleepHeal,
|
||||||
|
|
||||||
|
boolean authEnabled,
|
||||||
|
boolean authForce,
|
||||||
|
String authDomain,
|
||||||
|
|
||||||
|
boolean redstoneEnabled,
|
||||||
|
String redstoneListen,
|
||||||
|
|
||||||
|
Map<String, Object> knockbackModifiers,
|
||||||
|
|
||||||
|
boolean killswitchEnabled,
|
||||||
|
String killswitchListen,
|
||||||
|
|
||||||
|
boolean swingEnabled
|
||||||
|
) {
|
||||||
|
public static final int CONFIG_VERSION = 2;
|
||||||
|
private static TweaksConfig config;
|
||||||
|
|
||||||
|
public static TweaksConfig getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TweaksConfig load(Plugin plugin) throws Exception {
|
||||||
|
plugin.saveDefaultConfig();
|
||||||
|
var pluginConfig = plugin.getConfig();
|
||||||
|
|
||||||
|
var configVersion = pluginConfig.getInt("magic number don't modify this", 0);
|
||||||
|
var exception = new RuntimeException("Config version is %d, expected %d".formatted(configVersion, CONFIG_VERSION));
|
||||||
|
|
||||||
|
if (configVersion == 0) {
|
||||||
|
throw exception;
|
||||||
|
} else if (configVersion < CONFIG_VERSION) {
|
||||||
|
throw new Exception("Please follow update instructions https://www.spigotmc.org/resources/tweaks724.121057/updates", exception);
|
||||||
|
} else if (configVersion > CONFIG_VERSION) {
|
||||||
|
throw new Exception("Did you downgrade the plugin? Delete config.yml and let the plugin re-create it", exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
var loader = new ConfigLoader(pluginConfig);
|
||||||
|
var config = loader.load();
|
||||||
|
|
||||||
|
if (loader.getMissing().isEmpty()) {
|
||||||
|
TweaksConfig.config = config;
|
||||||
|
return config;
|
||||||
|
} else {
|
||||||
|
throw new Exception(
|
||||||
|
"One or more fields are missing from config.yml. Did you follow the update instructions? https://www.spigotmc.org/resources/tweaks724.121057/updates",
|
||||||
|
new MissingFieldsException(loader.getMissing())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.hardcore;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.*;
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class HardcoreManager {
|
|
||||||
private final float chance = TweaksConfig.getConfig().hardcoreChance();
|
|
||||||
|
|
||||||
public void init(Plugin plugin) {
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
|
||||||
plugin,
|
|
||||||
ListenerPriority.NORMAL,
|
|
||||||
PacketType.Play.Server.LOGIN
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
int entityId = packet.getIntegers().read(0);
|
|
||||||
|
|
||||||
if (chance > ((48271 * entityId) % 65537) / 65537f) // gotta be fast
|
|
||||||
// the "is hardcore" boolean https://wiki.vg/Protocol#Login_.28play.29
|
|
||||||
packet.getBooleans().write(0, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
89
src/main/java/eu/m724/tweaks/module/TweaksModule.java
Normal file
89
src/main/java/eu/m724/tweaks/module/TweaksModule.java
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.events.ListenerPriority;
|
||||||
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
|
import eu.m724.tweaks.TweaksPlugin;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public abstract class TweaksModule {
|
||||||
|
protected abstract void onInit();
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
var name = getClass().getSimpleName();
|
||||||
|
DebugLogger.finer("Initializing " + name);
|
||||||
|
long start = System.nanoTime();
|
||||||
|
|
||||||
|
this.onInit();
|
||||||
|
|
||||||
|
long end = System.nanoTime();
|
||||||
|
DebugLogger.fine("Initialized %s in %d µs", name, (end - start) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TweaksPlugin getPlugin() {
|
||||||
|
return TweaksPlugin.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TweaksConfig getConfig() {
|
||||||
|
return TweaksConfig.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerEvents(Listener listener) {
|
||||||
|
DebugLogger.finer("Registered listener: " + listener.getClass().getName());
|
||||||
|
getPlugin().getServer().getPluginManager().registerEvents(listener, getPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPacketSend(PacketType packetType, Consumer<PacketEvent> consumer) {
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(getPlugin(), ListenerPriority.NORMAL, packetType) {
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(PacketEvent event) {
|
||||||
|
consumer.accept(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DebugLogger.finer("Registered packet send: " + packetType.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPacketReceive(PacketType packetType, Consumer<PacketEvent> consumer) {
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(getPlugin(), ListenerPriority.NORMAL, packetType) {
|
||||||
|
@Override
|
||||||
|
public void onPacketReceiving(PacketEvent event) {
|
||||||
|
consumer.accept(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DebugLogger.finer("Registered packet receive: " + packetType.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerCommand(String command, CommandExecutor executor) {
|
||||||
|
getPlugin().getCommand(command).setExecutor(executor);
|
||||||
|
DebugLogger.finer("Registered command: " + command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends TweaksModule> T init(Class<T> clazz) {
|
||||||
|
T module;
|
||||||
|
try {
|
||||||
|
module = clazz.getDeclaredConstructor().newInstance();
|
||||||
|
} catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.init();
|
||||||
|
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.alert;
|
package eu.m724.tweaks.module.alert;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.alert;
|
package eu.m724.tweaks.module.alert;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
|
@ -20,9 +20,9 @@ public class AlertCommand implements CommandExecutor {
|
||||||
private List<String> pending;
|
private List<String> pending;
|
||||||
private long when;
|
private long when;
|
||||||
|
|
||||||
private final AlertManager manager;
|
private final AlertModule manager;
|
||||||
|
|
||||||
public AlertCommand(AlertManager manager) {
|
public AlertCommand(AlertModule manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class AlertCommand implements CommandExecutor {
|
||||||
} else if (args[0].equalsIgnoreCase("confirm")) {
|
} else if (args[0].equalsIgnoreCase("confirm")) {
|
||||||
sender.sendMessage("CONFIRM must be in all caps");
|
sender.sendMessage("CONFIRM must be in all caps");
|
||||||
} else if (args[0].equalsIgnoreCase("cancel")) {
|
} else if (args[0].equalsIgnoreCase("cancel")) {
|
||||||
if (AlertManager.current != null) {
|
if (AlertModule.current != null) {
|
||||||
manager.stop();
|
manager.stop();
|
||||||
sender.sendMessage("Cancelled alert");
|
sender.sendMessage("Cancelled alert");
|
||||||
} else if (pending != null) {
|
} else if (pending != null) {
|
||||||
|
@ -86,7 +86,7 @@ public class AlertCommand implements CommandExecutor {
|
||||||
|
|
||||||
if (pending != null) {
|
if (pending != null) {
|
||||||
when = System.currentTimeMillis();
|
when = System.currentTimeMillis();
|
||||||
if (AlertManager.current != null) {
|
if (AlertModule.current != null) {
|
||||||
sender.sendMessage("Broadcasting a new alert will cancel the currently active one");
|
sender.sendMessage("Broadcasting a new alert will cancel the currently active one");
|
||||||
}
|
}
|
||||||
sender.sendMessage("Please confirm broadcast with /emergencyalert CONFIRM within 15 seconds");
|
sender.sendMessage("Please confirm broadcast with /emergencyalert CONFIRM within 15 seconds");
|
74
src/main/java/eu/m724/tweaks/module/alert/AlertModule.java
Normal file
74
src/main/java/eu/m724/tweaks/module/alert/AlertModule.java
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.alert;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class AlertModule extends TweaksModule {
|
||||||
|
private BukkitTask notifyTask;
|
||||||
|
static Alert current;
|
||||||
|
static Map<Player, Integer> pages = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerCommand("emergencyalert", new AlertCommand(this));
|
||||||
|
|
||||||
|
onPacketReceive(PacketType.Play.Client.ENCHANT_ITEM, (event) -> {
|
||||||
|
if (current == null) return;
|
||||||
|
if (!current.isOpen(event.getPlayer())) return;
|
||||||
|
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
|
||||||
|
int windowId, buttonId;
|
||||||
|
windowId = packet.getIntegers().read(0);
|
||||||
|
buttonId = packet.getIntegers().read(1);
|
||||||
|
|
||||||
|
var page = pages.getOrDefault(event.getPlayer(),1);
|
||||||
|
|
||||||
|
if (buttonId == 1) { // prev page
|
||||||
|
page--;
|
||||||
|
} else if (buttonId == 2) { // nextc page
|
||||||
|
page++;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pages.put(event.getPlayer(), page);
|
||||||
|
var npacket = new PacketContainer(PacketType.Play.Server.WINDOW_DATA);
|
||||||
|
npacket.getIntegers().write(0, windowId);
|
||||||
|
npacket.getIntegers().write(1, 0);
|
||||||
|
npacket.getIntegers().write(2, page);
|
||||||
|
ProtocolLibrary.getProtocolManager().sendServerPacket(event.getPlayer(), npacket);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Alert start(String... content) {
|
||||||
|
stop();
|
||||||
|
current = new Alert(content);
|
||||||
|
notifyTask = new AlertRunnable(current, v -> this.stop()).runTaskTimer(getPlugin(), 0, 10);
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (current == null) return;
|
||||||
|
for (Player player : getPlugin().getServer().getOnlinePlayers()) {
|
||||||
|
if (current.isOpen(player))
|
||||||
|
player.closeInventory();
|
||||||
|
}
|
||||||
|
pages.clear();
|
||||||
|
notifyTask.cancel();
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.alert;
|
package eu.m724.tweaks.module.alert;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
|
@ -1,13 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.auth;
|
package eu.m724.tweaks.module.auth;
|
||||||
|
|
||||||
import eu.m724.tweaks.Language;
|
import eu.m724.tweaks.Language;
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
|
@ -1,19 +1,21 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.auth;
|
package eu.m724.tweaks.module.auth;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.Language;
|
import eu.m724.tweaks.Language;
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerLoginEvent;
|
import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class AuthListener implements Listener {
|
public class AuthListener implements Listener {
|
||||||
private final AuthStorage authStorage;
|
private final AuthStorage authStorage;
|
||||||
|
@ -40,6 +42,10 @@ public class AuthListener implements Listener {
|
||||||
allowed = true; // key just assigned
|
allowed = true; // key just assigned
|
||||||
} catch (FileNotFoundException | AuthStorage.AlreadyClaimedException | AuthStorage.InvalidKeyException e) {
|
} catch (FileNotFoundException | AuthStorage.AlreadyClaimedException | AuthStorage.InvalidKeyException e) {
|
||||||
allowed = !force; // If forced all players must have a key
|
allowed = !force; // If forced all players must have a key
|
||||||
|
} catch (IOException e) {
|
||||||
|
DebugLogger.severe("Error assigning key to player. " + e.getMessage());
|
||||||
|
event.disallow(PlayerLoginEvent.Result.KICK_OTHER, Language.getString("authKickError"));
|
||||||
|
allowed = true; // to skip the below checks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
src/main/java/eu/m724/tweaks/module/auth/AuthModule.java
Normal file
19
src/main/java/eu/m724/tweaks/module/auth/AuthModule.java
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.auth;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
|
||||||
|
public class AuthModule extends TweaksModule {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
var authStorage = new AuthStorage(getPlugin());
|
||||||
|
|
||||||
|
registerEvents(new AuthListener(authStorage));
|
||||||
|
registerCommand("tauth", new AuthCommands(authStorage));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,25 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.auth;
|
package eu.m724.tweaks.module.auth;
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class AuthStorage {
|
public class AuthStorage {
|
||||||
|
private static final char[] KEY_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
|
||||||
|
private static final int KEY_LENGTH = 10;
|
||||||
|
private static final SecureRandom RANDOM = new SecureRandom();
|
||||||
|
|
||||||
private final File playersDirectory;
|
private final File playersDirectory;
|
||||||
private final File keysDirectory;
|
private final File keysDirectory;
|
||||||
|
|
||||||
|
@ -71,7 +76,7 @@ public class AuthStorage {
|
||||||
byte[] bytes = is.readNBytes(50);
|
byte[] bytes = is.readNBytes(50);
|
||||||
return new String(bytes, StandardCharsets.UTF_8);
|
return new String(bytes, StandardCharsets.UTF_8);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e); // TODO
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -121,7 +126,7 @@ public class AuthStorage {
|
||||||
* @throws FileNotFoundException if no such key
|
* @throws FileNotFoundException if no such key
|
||||||
* @throws AlreadyClaimedException if key is claimed or user owns another key
|
* @throws AlreadyClaimedException if key is claimed or user owns another key
|
||||||
*/
|
*/
|
||||||
void assignOwner(String key, UUID uuid) throws FileNotFoundException, AlreadyClaimedException {
|
void assignOwner(String key, UUID uuid) throws IOException, FileNotFoundException, AlreadyClaimedException {
|
||||||
if (isInvalid(key)) throw new InvalidKeyException();
|
if (isInvalid(key)) throw new InvalidKeyException();
|
||||||
|
|
||||||
if (getUserOfKey(key) != null) throw new AlreadyClaimedException();
|
if (getUserOfKey(key) != null) throw new AlreadyClaimedException();
|
||||||
|
@ -136,34 +141,25 @@ public class AuthStorage {
|
||||||
|
|
||||||
try (FileOutputStream os = new FileOutputStream(file)) {
|
try (FileOutputStream os = new FileOutputStream(file)) {
|
||||||
os.write(byteBuffer.array());
|
os.write(byteBuffer.array());
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e); // TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
File file2 = new File(playersDirectory, uuid.toString());
|
File file2 = new File(playersDirectory, uuid.toString());
|
||||||
|
|
||||||
try (FileOutputStream os = new FileOutputStream(file2)) {
|
try (FileOutputStream os = new FileOutputStream(file2)) {
|
||||||
os.write(key.getBytes(StandardCharsets.UTF_8));
|
os.write(key.getBytes(StandardCharsets.UTF_8));
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e); // TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO improve
|
|
||||||
String generateKey() {
|
String generateKey() {
|
||||||
char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
|
StringBuilder builder = new StringBuilder();
|
||||||
Random random = new Random();
|
|
||||||
int length = random.nextInt(8, 10);
|
|
||||||
|
|
||||||
StringBuilder key = new StringBuilder();
|
for (int i=0; i<KEY_LENGTH; i++) {
|
||||||
|
builder.append(KEY_CHARS[RANDOM.nextInt(KEY_CHARS.length)]);
|
||||||
for (int i=0; i<length; i++) {
|
|
||||||
key.append(chars[random.nextInt(chars.length)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return key.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class InvalidKeyException extends RuntimeException {}
|
static class InvalidKeyException extends RuntimeException { }
|
||||||
static class AlreadyClaimedException extends Exception {}
|
static class AlreadyClaimedException extends Exception { }
|
||||||
}
|
}
|
247
src/main/java/eu/m724/tweaks/module/chat/ChatCommands.java
Normal file
247
src/main/java/eu/m724/tweaks/module/chat/ChatCommands.java
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.chat;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.Language;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ChatCommands implements CommandExecutor {
|
||||||
|
private final ChatModule manager;
|
||||||
|
|
||||||
|
public ChatCommands(ChatModule manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, Command command, @NotNull String label, String[] args) {
|
||||||
|
if (command.getName().equals("chat")) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
ChatRoom chatRoom = manager.getPlayerChatRoom(player);
|
||||||
|
|
||||||
|
if (args.length == 0) { // show room
|
||||||
|
player.spigot().sendMessage(chatRoom.getInfoComponent());
|
||||||
|
} else { // join room
|
||||||
|
String id = args[0];
|
||||||
|
|
||||||
|
if (id.equals(chatRoom.id)) {
|
||||||
|
sender.spigot().sendMessage(Language.getComponent("chatAlreadyHere", ChatColor.GRAY));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String password = null;
|
||||||
|
if (args.length > 1) {
|
||||||
|
password = Arrays.stream(args).skip(1).collect(Collectors.joining(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean authenticated = false;
|
||||||
|
BaseComponent component = null;
|
||||||
|
ChatRoom newRoom = manager.getById(id);
|
||||||
|
if (newRoom != null) {
|
||||||
|
if (newRoom.password != null) {
|
||||||
|
if (newRoom.password.equals(password)) {
|
||||||
|
authenticated = true;
|
||||||
|
} else if (password == null) {
|
||||||
|
component = Language.getComponent("chatPasswordProtected", ChatColor.RED);
|
||||||
|
} else {
|
||||||
|
component = Language.getComponent("chatWrongPassword", ChatColor.RED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authenticated = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ChatRoomLoader.validateId(id) == 0) {
|
||||||
|
component = Language.getComponent("chatNoSuchRoom", ChatColor.RED, id);
|
||||||
|
} else {
|
||||||
|
component = Language.getComponent("chatNoSuchRoomInvalidId", ChatColor.RED, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authenticated) {
|
||||||
|
/*component = new ComponentBuilder(Language.getComponent("chatJoined", ChatColor.GOLD))
|
||||||
|
.append(" ")
|
||||||
|
.append(ChatFormatUtils.formatChatRoom(chatRoom)).color(newRoom.color)
|
||||||
|
.build();*/
|
||||||
|
player.sendMessage("");
|
||||||
|
manager.setPlayerChatRoom(newRoom, player);
|
||||||
|
} else {
|
||||||
|
player.spigot().sendMessage(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (command.getName().equals("chatmanage")) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
ChatRoom chatRoom = manager.getPlayerChatRoom(player);
|
||||||
|
boolean isOwner = player.equals(chatRoom.owner);
|
||||||
|
|
||||||
|
String action = args.length > 0 ? args[0] : null;
|
||||||
|
String argument = args.length > 1 ? args[1] : null;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case "create" -> {
|
||||||
|
if (argument == null) {
|
||||||
|
sender.sendMessage("Please pass a room name as an argument. The room name can contain only characters and digits.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ChatRoom newRoom = manager.createChatRoom(argument, null, player);
|
||||||
|
|
||||||
|
var component = new ComponentBuilder("Created a chat room. Join it: ").color(ChatColor.GOLD)
|
||||||
|
.append("/c " + newRoom.id).color(ChatColor.AQUA)
|
||||||
|
.event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/c " + newRoom.id))
|
||||||
|
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Language.getString("clickToExecuteCommand"))))
|
||||||
|
.append("\n")
|
||||||
|
.append("To protect it with a password, join it and use ").color(ChatColor.GRAY)
|
||||||
|
.append("/cm setpassword <password>").color(ChatColor.DARK_PURPLE)
|
||||||
|
.event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/cm setpassword "))
|
||||||
|
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Language.getString("clickToExecuteCommand"))));
|
||||||
|
|
||||||
|
sender.spigot().sendMessage(component.build());
|
||||||
|
} catch (ChatModule.InvalidIdException e) {
|
||||||
|
var component = new ComponentBuilder("ID is invalid: ").color(ChatColor.GRAY)
|
||||||
|
.append(e.getMessage()).color(ChatColor.RED);
|
||||||
|
|
||||||
|
sender.spigot().sendMessage(component.build());
|
||||||
|
} catch (ChatModule.ChatRoomExistsException e) {
|
||||||
|
sender.sendMessage("Room %s already exists".formatted(argument));
|
||||||
|
} catch (IOException e) {
|
||||||
|
sender.sendMessage("Error creating room");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "delete" -> {
|
||||||
|
if (isOwner) {
|
||||||
|
if (argument == null) {
|
||||||
|
sender.sendMessage("You want to delete room \"%s\". Confirm by passing the ID as an argument.".formatted(chatRoom.id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument.equals(chatRoom.id)) {
|
||||||
|
manager.deleteChatRoom(chatRoom);
|
||||||
|
sender.sendMessage("Room %s deleted".formatted(chatRoom.id));
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Pass \"%s\" as an argument to confirm".formatted(chatRoom.id));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "setowner" -> {
|
||||||
|
if (isOwner) {
|
||||||
|
if (argument == null) {
|
||||||
|
sender.sendMessage("To transfer ownership of room %s, pass the new owner name as an argument for this action.".formatted(chatRoom.id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player newOwner = Bukkit.getPlayer(argument);
|
||||||
|
if (newOwner != null && newOwner.isOnline()) {
|
||||||
|
chatRoom.owner = newOwner;
|
||||||
|
try {
|
||||||
|
manager.saveChatRoom(chatRoom);
|
||||||
|
sender.sendMessage("Owner changed to " + newOwner.getName());
|
||||||
|
} catch (IOException e) {
|
||||||
|
sender.sendMessage("Error changing owner");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Player must be online");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "setpassword" -> {
|
||||||
|
if (isOwner) {
|
||||||
|
if (argument == null) {
|
||||||
|
sender.sendMessage("To change the password of room %s, pass the new password as an argument for this action.".formatted(chatRoom.id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatRoom.password = Arrays.stream(args).skip(1).collect(Collectors.joining(" "));
|
||||||
|
try {
|
||||||
|
manager.saveChatRoom(chatRoom);
|
||||||
|
|
||||||
|
var component = new ComponentBuilder("Password changed to ").color(ChatColor.GREEN)
|
||||||
|
.append("(hover to view)").color(ChatColor.AQUA)
|
||||||
|
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(chatRoom.password)))
|
||||||
|
.append("\n")
|
||||||
|
.append("To unset, ").color(ChatColor.GRAY)
|
||||||
|
.append("/cm unsetpassword").color(ChatColor.DARK_PURPLE)
|
||||||
|
.event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/cm unsetpassword"))
|
||||||
|
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Language.getString("clickToExecuteCommand"))));
|
||||||
|
|
||||||
|
sender.spigot().sendMessage(component.build());
|
||||||
|
} catch (IOException e) {
|
||||||
|
sender.sendMessage("Error changing password");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "unsetpassword" -> {
|
||||||
|
if (isOwner) {
|
||||||
|
chatRoom.password = null;
|
||||||
|
try {
|
||||||
|
manager.saveChatRoom(chatRoom);
|
||||||
|
sender.sendMessage("Password removed from " + chatRoom.id);
|
||||||
|
} catch (IOException e) {
|
||||||
|
sender.sendMessage("Error removing password");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "setcolor" -> {
|
||||||
|
if (isOwner) {
|
||||||
|
if (argument == null) {
|
||||||
|
sender.sendMessage("To change the message color of room %s, pass the new color as an argument for this action. #hex or color name.".formatted(chatRoom.id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatColor newColor = ChatColor.of(argument);
|
||||||
|
if (newColor != null) {
|
||||||
|
chatRoom.color = newColor;
|
||||||
|
try {
|
||||||
|
manager.saveChatRoom(chatRoom);
|
||||||
|
sender.sendMessage("Message color changed to " + newColor.getName());
|
||||||
|
} catch (IOException e) {
|
||||||
|
sender.sendMessage("Error changing color");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Invalid color");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case null, default -> {
|
||||||
|
sender.sendMessage("Actions: create, delete, setowner, setpassword, unsetpassword, setcolor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.chat;
|
package eu.m724.tweaks.module.chat;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
@ -1,12 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.chat;
|
package eu.m724.tweaks.module.chat;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
@ -14,8 +14,8 @@ import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import org.bukkit.craftbukkit.v1_21_R1.CraftRegistry;
|
import org.bukkit.craftbukkit.v1_21_R3.CraftRegistry;
|
||||||
import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer;
|
import org.bukkit.craftbukkit.v1_21_R3.entity.CraftPlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
@ -25,13 +25,14 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
public class ChatListener implements Listener {
|
public class ChatListener implements Listener {
|
||||||
private final ChatManager chatManager;
|
private final ChatModule chatModule;
|
||||||
private final String defaultRoom = TweaksConfig.getConfig().chatDefaultName();
|
private final String defaultRoom = TweaksConfig.getConfig().chatDefaultName();
|
||||||
private final boolean localEvents = TweaksConfig.getConfig().chatLocalEvents();
|
private final boolean localEvents = TweaksConfig.getConfig().chatLocalEvents();
|
||||||
private final int radius;
|
private final int radius;
|
||||||
|
|
||||||
public ChatListener(ChatManager chatManager) {
|
public ChatListener(ChatModule chatModule) {
|
||||||
this.chatManager = chatManager;
|
this.chatModule = chatModule;
|
||||||
|
|
||||||
if (TweaksConfig.getConfig().chatRadius() < 0) {
|
if (TweaksConfig.getConfig().chatRadius() < 0) {
|
||||||
radius = 0;
|
radius = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -52,7 +53,7 @@ public class ChatListener implements Listener {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
ChatRoom chatRoom = chatModule.getPlayerChatRoom(player);
|
||||||
|
|
||||||
if (localEvents) {
|
if (localEvents) {
|
||||||
var cb = new ComponentBuilder()
|
var cb = new ComponentBuilder()
|
||||||
|
@ -77,7 +78,7 @@ public class ChatListener implements Listener {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
ChatRoom chatRoom = chatManager.removePlayer(player);
|
ChatRoom chatRoom = chatModule.removePlayer(player);
|
||||||
|
|
||||||
if (localEvents) {
|
if (localEvents) {
|
||||||
var cb = new ComponentBuilder()
|
var cb = new ComponentBuilder()
|
||||||
|
@ -103,7 +104,7 @@ public class ChatListener implements Listener {
|
||||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
if (localEvents) {
|
if (localEvents) {
|
||||||
Player player = event.getEntity();
|
Player player = event.getEntity();
|
||||||
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
ChatRoom chatRoom = chatModule.getPlayerChatRoom(player);
|
||||||
|
|
||||||
// would be easier on Paper but this is not Paper
|
// would be easier on Paper but this is not Paper
|
||||||
BaseComponent deathMessage = ComponentSerializer.deserialize(Component.Serializer.toJson(((CraftPlayer)player).getHandle().getCombatTracker().getDeathMessage(), CraftRegistry.getMinecraftRegistry()));
|
BaseComponent deathMessage = ComponentSerializer.deserialize(Component.Serializer.toJson(((CraftPlayer)player).getHandle().getCombatTracker().getDeathMessage(), CraftRegistry.getMinecraftRegistry()));
|
||||||
|
@ -124,7 +125,7 @@ public class ChatListener implements Listener {
|
||||||
|
|
||||||
// broadcast to killer if available
|
// broadcast to killer if available
|
||||||
if (player.getLastDamageCause().getDamageSource().getCausingEntity() instanceof Player killer) {
|
if (player.getLastDamageCause().getDamageSource().getCausingEntity() instanceof Player killer) {
|
||||||
ChatRoom chatRoom2 = chatManager.getPlayerChatRoom(killer);
|
ChatRoom chatRoom2 = chatModule.getPlayerChatRoom(killer);
|
||||||
if (chatRoom != chatRoom2) {
|
if (chatRoom != chatRoom2) {
|
||||||
if (proximityFor(chatRoom)) {
|
if (proximityFor(chatRoom)) {
|
||||||
chatRoom2.broadcastNear(killer.getLocation(), radius, component);
|
chatRoom2.broadcastNear(killer.getLocation(), radius, component);
|
||||||
|
@ -142,7 +143,7 @@ public class ChatListener implements Listener {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
|
public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
ChatRoom chatRoom = chatModule.getPlayerChatRoom(player);
|
||||||
String message = event.getMessage();
|
String message = event.getMessage();
|
||||||
|
|
||||||
var component = new ComponentBuilder()
|
var component = new ComponentBuilder()
|
|
@ -1,50 +1,45 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.chat;
|
package eu.m724.tweaks.module.chat;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ChatManager {
|
public class ChatModule extends TweaksModule {
|
||||||
private final Plugin plugin;
|
private final NamespacedKey chatRoomKey = new NamespacedKey(getPlugin(), "chatRoom");
|
||||||
private final NamespacedKey chatRoomKey;
|
private final String defaultRoom = getConfig().chatDefaultName();
|
||||||
private final String defaultRoom;
|
|
||||||
|
|
||||||
private final Map<Player, ChatRoom> playerMap = new HashMap<>();
|
private final Map<Player, ChatRoom> playerMap = new HashMap<>();
|
||||||
private final Map<String, ChatRoom> roomIdMap = new HashMap<>();
|
private final Map<String, ChatRoom> roomIdMap = new HashMap<>();
|
||||||
|
|
||||||
public ChatManager(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.chatRoomKey = new NamespacedKey(plugin, "chatRoom");
|
|
||||||
this.defaultRoom = TweaksConfig.getConfig().chatDefaultName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(PluginCommand chatCommand, PluginCommand chatManageCommand) {
|
@Override
|
||||||
if (plugin.getServer().isEnforcingSecureProfiles()) {
|
protected void onInit() {
|
||||||
|
if (getPlugin().getServer().isEnforcingSecureProfiles()) {
|
||||||
throw new RuntimeException("Please disable enforce-secure-profile in server.properties to use chatrooms");
|
throw new RuntimeException("Please disable enforce-secure-profile in server.properties to use chatrooms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatRoomLoader.init(getPlugin());
|
||||||
getById(defaultRoom);
|
getById(defaultRoom);
|
||||||
plugin.getServer().getPluginManager().registerEvents(new ChatListener(this), plugin);
|
registerEvents(new ChatListener(this));
|
||||||
|
|
||||||
var chatCommands = new ChatCommands(this);
|
var chatCommands = new ChatCommands(this);
|
||||||
chatCommand.setExecutor(chatCommands);
|
registerCommand("chat", chatCommands);
|
||||||
chatManageCommand.setExecutor(chatCommands);
|
registerCommand("chatmanage", chatCommands);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,11 +155,11 @@ public class ChatManager {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
throw new InvalidIdException("ID is too short, make it at least 2 chars");
|
throw new InvalidIdException("ID is too short, it must be at least 2 chars long");
|
||||||
case 2:
|
case 2:
|
||||||
throw new InvalidIdException("ID is too long, make it 20 chars or shorter");
|
throw new InvalidIdException("ID is too long, it mustn't be longer than 20 chars");
|
||||||
case 4:
|
case 4:
|
||||||
throw new InvalidIdException("ID must be composed from characters a-z and numbers 0-9");
|
throw new InvalidIdException("ID must be of characters a-z and numbers 0-9");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getById(id) != null)
|
if (getById(id) != null)
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.chat;
|
package eu.m724.tweaks.module.chat;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.chat;
|
package eu.m724.tweaks.module.chat;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
@ -29,7 +29,7 @@ public class ChatRoomLoader {
|
||||||
*/
|
*/
|
||||||
static File getFile(String id) {
|
static File getFile(String id) {
|
||||||
if (validateId(id) != 0)
|
if (validateId(id) != 0)
|
||||||
throw new RuntimeException("Invalid id: " + id);
|
return null;
|
||||||
|
|
||||||
return new File(chatRoomsDir, id + ".yml");
|
return new File(chatRoomsDir, id + ".yml");
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,8 @@ public class ChatRoomLoader {
|
||||||
*/
|
*/
|
||||||
static ChatRoom load(String id) {
|
static ChatRoom load(String id) {
|
||||||
File chatRoomFile = getFile(id);
|
File chatRoomFile = getFile(id);
|
||||||
if (!chatRoomFile.exists()) return null;
|
if (chatRoomFile == null || !chatRoomFile.exists())
|
||||||
|
return null;
|
||||||
|
|
||||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(chatRoomFile);
|
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(chatRoomFile);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.compass;
|
package eu.m724.tweaks.module.compass;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
@ -25,9 +25,9 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
// TODO dimension check
|
// TODO dimension check
|
||||||
public class CompassListener implements Listener {
|
public class CompassModule extends TweaksModule implements Listener {
|
||||||
private final int precision = TweaksConfig.getConfig().compassPrecision(); // degrees every point
|
private final int precision = getConfig().compassPrecision(); // degrees every point
|
||||||
private final int width = TweaksConfig.getConfig().compassWidth(); // points left to right
|
private final int width = getConfig().compassWidth(); // points left to right
|
||||||
|
|
||||||
private final Map<Integer, String> points = Map.of(
|
private final Map<Integer, String> points = Map.of(
|
||||||
0, ChatColor.DARK_GRAY + "S",
|
0, ChatColor.DARK_GRAY + "S",
|
||||||
|
@ -36,6 +36,11 @@ public class CompassListener implements Listener {
|
||||||
270, ChatColor.DARK_GRAY + "E"
|
270, ChatColor.DARK_GRAY + "E"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
||||||
if (event.getMainHandItem().getType() == Material.COMPASS || event.getOffHandItem().getType() == Material.COMPASS) {
|
if (event.getMainHandItem().getType() == Material.COMPASS || event.getOffHandItem().getType() == Material.COMPASS) {
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.compass;
|
package eu.m724.tweaks.module.compass;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.door;
|
package eu.m724.tweaks.module.door;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
|
@ -22,7 +23,12 @@ import org.bukkit.util.RayTraceResult;
|
||||||
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
public class DoorKnockListener implements Listener {
|
public class DoorKnockModule extends TweaksModule implements Listener {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockDamageAbort(BlockDamageAbortEvent event) {
|
public void onBlockDamageAbort(BlockDamageAbortEvent event) {
|
||||||
Block block = event.getBlock();
|
Block block = event.getBlock();
|
|
@ -1,11 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.door;
|
package eu.m724.tweaks.module.door;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
|
@ -15,7 +16,11 @@ import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
|
||||||
public class DoorOpenListener implements Listener {
|
public class DoorOpenModule extends TweaksModule implements Listener {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
|
@ -71,5 +76,4 @@ public class DoorOpenListener implements Listener {
|
||||||
location.getBlock().setBlockData(nextDoor);
|
location.getBlock().setBlockData(nextDoor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.durability;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.TweaksPlugin;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class DPlayerProperties implements Listener {
|
||||||
|
private final NamespacedKey namespacedKey = new NamespacedKey(TweaksPlugin.getInstance(), "durability_enabled");
|
||||||
|
private final Set<Player> players = new HashSet<>();
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
var player = event.getPlayer();
|
||||||
|
|
||||||
|
if (player.hasPermission("tweaks724.durabilityalert")) {
|
||||||
|
var enabled = player.getPersistentDataContainer().get(namespacedKey, PersistentDataType.BOOLEAN);
|
||||||
|
if (enabled != null && enabled) {
|
||||||
|
players.add(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
players.remove(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Player> getPlayers() {
|
||||||
|
return Set.copyOf(players);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPlayerEnabled(Player player) {
|
||||||
|
return players.contains(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disableForPlayer(Player player) {
|
||||||
|
players.remove(player);
|
||||||
|
player.getPersistentDataContainer().set(namespacedKey, PersistentDataType.BOOLEAN, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableForPlayer(Player player) {
|
||||||
|
players.add(player);
|
||||||
|
player.getPersistentDataContainer().set(namespacedKey, PersistentDataType.BOOLEAN, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.durability;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DurabilityCaches {
|
||||||
|
private final Map<Player, Long> lastFullReminder = new HashMap<>();
|
||||||
|
// BAD
|
||||||
|
private final Map<Player, Map<Material, Long>> lastUse = new HashMap<>();
|
||||||
|
// BAD
|
||||||
|
private final Map<Player, Map<Material, Long>> lastPing = new HashMap<>();
|
||||||
|
|
||||||
|
boolean shouldFullRemind(Player player, long now) {
|
||||||
|
var lfr = lastFullReminder.getOrDefault(player, 0L);
|
||||||
|
|
||||||
|
if (now - lfr > 300 * 1000) {
|
||||||
|
lastFullReminder.put(player, now);
|
||||||
|
return true;
|
||||||
|
} else if (now - lfr < 3 * 1000) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldRemind(Player player, ItemStack itemStack, long now) {
|
||||||
|
var lu = lastUse.computeIfAbsent(player, (k) -> new HashMap<>()).getOrDefault(itemStack.getType(), 0L);
|
||||||
|
|
||||||
|
if (now - lu > 180 * 1000) {
|
||||||
|
lastUse.get(player).put(itemStack.getType(), now);
|
||||||
|
return true;
|
||||||
|
} else if (now - lu < 3 * 1000) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldPing(Player player, ItemStack itemStack, long now) {
|
||||||
|
var lp = lastPing.computeIfAbsent(player, (k) -> new HashMap<>()).getOrDefault(itemStack.getType(), 0L);
|
||||||
|
|
||||||
|
if (now - lp > 60 * 1000) {
|
||||||
|
lastPing.get(player).put(itemStack.getType(), now);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.durability;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.Language;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class DurabilityCommands implements CommandExecutor {
|
||||||
|
private final DPlayerProperties properties;
|
||||||
|
|
||||||
|
public DurabilityCommands(DPlayerProperties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!(sender instanceof Player player)) {
|
||||||
|
sender.sendMessage("Only players can use this command");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.isPlayerEnabled(player)) {
|
||||||
|
properties.disableForPlayer(player);
|
||||||
|
sender.spigot().sendMessage(Language.getComponent("durabilityDisabled", ChatColor.GRAY));
|
||||||
|
} else {
|
||||||
|
properties.enableForPlayer(player);
|
||||||
|
sender.spigot().sendMessage(Language.getComponent("durabilityEnabled", ChatColor.GRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.durability;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerItemDamageEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.Damageable;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
public class DurabilityModule extends TweaksModule implements Listener {
|
||||||
|
private final DurabilityCaches cache = new DurabilityCaches();
|
||||||
|
private final DPlayerProperties properties = new DPlayerProperties();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerEvents(this);
|
||||||
|
|
||||||
|
registerCommand("durabilityalert", new DurabilityCommands(properties));
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
properties.getPlayers().forEach(p -> refreshBar(p));
|
||||||
|
}
|
||||||
|
}.runTaskTimerAsynchronously(getPlugin(), 0, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerItemDamage(PlayerItemDamageEvent event) {
|
||||||
|
refreshBar(event.getPlayer(), event.getItem(), event.getDamage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshBar(Player player) {
|
||||||
|
refreshBar(player, null, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshBar(Player player, ItemStack justDamaged, int damage) {
|
||||||
|
if (!properties.isPlayerEnabled(player)) return;
|
||||||
|
|
||||||
|
var items = new ItemStack[] {
|
||||||
|
player.getInventory().getHelmet(),
|
||||||
|
player.getInventory().getChestplate(),
|
||||||
|
player.getInventory().getLeggings(),
|
||||||
|
player.getInventory().getBoots(),
|
||||||
|
player.getInventory().getItemInMainHand(),
|
||||||
|
player.getInventory().getItemInOffHand()
|
||||||
|
};
|
||||||
|
|
||||||
|
var builder = new ComponentBuilder();
|
||||||
|
|
||||||
|
var now = System.currentTimeMillis();
|
||||||
|
var all = cache.shouldFullRemind(player, now);
|
||||||
|
|
||||||
|
for (var itemStack : items) {
|
||||||
|
if (itemStack == null || !itemStack.hasItemMeta()) continue;
|
||||||
|
|
||||||
|
if (itemStack.getItemMeta() instanceof Damageable meta) {
|
||||||
|
var target = itemStack.equals(justDamaged);
|
||||||
|
|
||||||
|
var maxDurability = itemStack.getType().getMaxDurability();
|
||||||
|
var durability = maxDurability - meta.getDamage() - (target ? damage : 0);
|
||||||
|
durability = Math.max(0, durability);
|
||||||
|
var percentage = (double) durability / maxDurability;
|
||||||
|
|
||||||
|
var notify = durability < 30 && (durability < 10 || percentage < 0.1);
|
||||||
|
|
||||||
|
var remind = cache.shouldRemind(player, itemStack, now);
|
||||||
|
var important = target && notify && cache.shouldPing(player, itemStack, now);
|
||||||
|
|
||||||
|
DebugLogger.finer("%s's %s: %d / %d (%.2f%%)%s%s", player.getName(), itemStack.getType().name(), durability, maxDurability, percentage * 100, notify ? " notify" : "", important ? " important" : "");
|
||||||
|
|
||||||
|
if (notify || all || remind) {
|
||||||
|
var longName = remind || important;
|
||||||
|
var label = longName ? getMaterialLongName(itemStack.getType()) : getMaterialShortName(itemStack.getType());
|
||||||
|
var labelColor = percentage > 0 ? matColor(itemStack.getType()) : ChatColor.DARK_RED;
|
||||||
|
|
||||||
|
var percentageStr = (int) (percentage * 100) + "%";
|
||||||
|
var percentageColor = mixColor(labelColor, ChatColor.DARK_RED, 1.0 - percentage * 10);
|
||||||
|
|
||||||
|
builder.append(label + " ").color(labelColor);
|
||||||
|
builder.append(percentageStr + " ").color(percentageColor);
|
||||||
|
|
||||||
|
if (important) {
|
||||||
|
player.playSound(player, Sound.BLOCK_ANVIL_PLACE, 0.5f, 1.5f);
|
||||||
|
player.sendTitle("", labelColor + label + " " + percentageColor + percentageStr, 5, 20, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var component = builder.create();
|
||||||
|
if (component.length > 0)
|
||||||
|
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMaterialLongName(Material material) {
|
||||||
|
var sp = material.name().split("_");
|
||||||
|
var str = sp[sp.length - 1];
|
||||||
|
return str.charAt(0) + str.substring(1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMaterialShortName(Material material) {
|
||||||
|
return getMaterialLongName(material).substring(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChatColor mixColor(ChatColor from, ChatColor to, double percentage) {
|
||||||
|
percentage = Math.clamp(percentage, 0.0, 1.0);
|
||||||
|
|
||||||
|
var diffR = to.getColor().getRed() - from.getColor().getRed();
|
||||||
|
var diffG = to.getColor().getGreen() - from.getColor().getGreen();
|
||||||
|
var diffB = to.getColor().getBlue() - from.getColor().getBlue();
|
||||||
|
|
||||||
|
var r = from.getColor().getRed() + (int) (diffR * percentage);
|
||||||
|
var g = from.getColor().getGreen() + (int) (diffG * percentage);
|
||||||
|
var b = from.getColor().getBlue() + (int) (diffB * percentage);
|
||||||
|
|
||||||
|
return ChatColor.of(new Color(r, g, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChatColor matColor(Material material) {
|
||||||
|
var color = ChatColor.DARK_GRAY;
|
||||||
|
|
||||||
|
if (material.name().startsWith("DIAMOND_")) {
|
||||||
|
color = ChatColor.AQUA;
|
||||||
|
} else if (material.name().startsWith("NETHERITE_")) {
|
||||||
|
color = ChatColor.DARK_PURPLE;
|
||||||
|
} else if (material.name().startsWith("IRON_")) {
|
||||||
|
color = ChatColor.WHITE;
|
||||||
|
} else if (material.name().startsWith("STONE_")) {
|
||||||
|
color = ChatColor.GRAY;
|
||||||
|
} else if (material.name().startsWith("WOODEN_")) {
|
||||||
|
color = ChatColor.DARK_GREEN;
|
||||||
|
} else if (material.name().startsWith("GOLDEN_")) {
|
||||||
|
color = ChatColor.GOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,22 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.full;
|
package eu.m724.tweaks.module.full;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerLoginEvent;
|
import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
|
|
||||||
public class FullListener implements Listener {
|
public class FullModule extends TweaksModule implements Listener {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||||
if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL && event.getPlayer().hasPermission("tweaks724.bypass-full")) {
|
if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL && event.getPlayer().hasPermission("tweaks724.bypass-full")) {
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.hardcore;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
import net.minecraft.world.level.levelgen.RandomSupport;
|
||||||
|
import net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
// how we do it is much faster than any Random
|
||||||
|
public class HardcoreModule extends TweaksModule {
|
||||||
|
private final Xoroshiro128PlusPlus rng;
|
||||||
|
private final long chanceLong;
|
||||||
|
|
||||||
|
public HardcoreModule() {
|
||||||
|
this.rng = new Xoroshiro128PlusPlus(
|
||||||
|
RandomSupport.generateUniqueSeed(),
|
||||||
|
RandomSupport.generateUniqueSeed()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.chanceLong = BigInteger.valueOf(Long.MIN_VALUE)
|
||||||
|
.add(
|
||||||
|
new BigDecimal(
|
||||||
|
BigInteger.valueOf(Long.MAX_VALUE).subtract(BigInteger.valueOf(Long.MIN_VALUE))
|
||||||
|
).multiply(
|
||||||
|
BigDecimal.valueOf(getConfig().hardcoreChance())
|
||||||
|
).toBigInteger()
|
||||||
|
).longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
DebugLogger.fine("Chance long: " + chanceLong);
|
||||||
|
|
||||||
|
onPacketSend(PacketType.Play.Server.LOGIN, (event) -> {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
|
||||||
|
if (rng.nextLong() < chanceLong)
|
||||||
|
// the "is hardcore" boolean https://wiki.vg/Protocol#Login_.28play.29
|
||||||
|
packet.getBooleans().write(0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,19 +4,16 @@
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.killswitch;
|
package eu.m724.tweaks.module.killswitch;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import com.sun.net.httpserver.HttpHandler;
|
import com.sun.net.httpserver.HttpHandler;
|
||||||
import com.sun.net.httpserver.HttpServer;
|
import com.sun.net.httpserver.HttpServer;
|
||||||
import eu.m724.tweaks.DebugLogger;
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import eu.m724.tweaks.TweaksPlugin;
|
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -27,17 +24,12 @@ import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
public class KillswitchManager implements CommandExecutor, HttpHandler {
|
public class KillswitchModule extends TweaksModule implements CommandExecutor, HttpHandler {
|
||||||
private final Plugin plugin;
|
|
||||||
private final Ratelimit ratelimit = new Ratelimit();
|
private final Ratelimit ratelimit = new Ratelimit();
|
||||||
|
|
||||||
private byte[] secret;
|
private byte[] secret;
|
||||||
private String secretEncoded;
|
private String secretEncoded;
|
||||||
|
|
||||||
public KillswitchManager(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadKey(File file) {
|
private void loadKey(File file) {
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
|
@ -63,15 +55,16 @@ public class KillswitchManager implements CommandExecutor, HttpHandler {
|
||||||
this.secretEncoded = Base64.getEncoder().encodeToString(secret);
|
this.secretEncoded = Base64.getEncoder().encodeToString(secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(PluginCommand serverKillCommand) {
|
@Override
|
||||||
serverKillCommand.setExecutor(this);
|
protected void onInit() {
|
||||||
|
registerCommand("servkill", this);
|
||||||
|
|
||||||
if (TweaksConfig.getConfig().killswitchListen() != null) {
|
if (getConfig().killswitchListen() != null) {
|
||||||
loadKey(new File(plugin.getDataFolder(), "storage/killswitch key"));
|
loadKey(new File(getPlugin().getDataFolder(), "storage/killswitch key"));
|
||||||
|
|
||||||
ratelimit.runTaskTimerAsynchronously(plugin, 0, 20 * 300);
|
ratelimit.runTaskTimerAsynchronously(getPlugin(), 0, 20 * 300);
|
||||||
|
|
||||||
var listenAddress = TweaksConfig.getConfig().killswitchListen().split(":");
|
var listenAddress = getConfig().killswitchListen().split(":");
|
||||||
InetSocketAddress bindAddress;
|
InetSocketAddress bindAddress;
|
||||||
if (listenAddress.length == 1) {
|
if (listenAddress.length == 1) {
|
||||||
bindAddress = new InetSocketAddress(Integer.parseInt(listenAddress[0]));
|
bindAddress = new InetSocketAddress(Integer.parseInt(listenAddress[0]));
|
|
@ -4,7 +4,7 @@
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.killswitch;
|
package eu.m724.tweaks.module.killswitch;
|
||||||
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.knockback;
|
package eu.m724.tweaks.module.knockback;
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.entity.EntityKnockbackByEntityEvent;
|
import org.bukkit.event.entity.EntityKnockbackByEntityEvent;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class KnockbackListener implements Listener {
|
public class KnockbackModule extends TweaksModule implements Listener {
|
||||||
private final Map<EntityType, Double> modifiers = new HashMap<>();
|
private final Map<EntityType, Vector> modifiers = new HashMap<>();
|
||||||
|
|
||||||
public KnockbackListener(Plugin plugin) {
|
@Override
|
||||||
TweaksConfig.getConfig().knockbackModifiers().forEach((k, v) -> {
|
protected void onInit() {
|
||||||
|
getConfig().knockbackModifiers().forEach((k, v) -> {
|
||||||
EntityType type;
|
EntityType type;
|
||||||
double mod;
|
double mod;
|
||||||
|
|
||||||
|
@ -45,11 +46,17 @@ public class KnockbackListener implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mod == 1) return;
|
if (mod == 1) return;
|
||||||
modifiers.put(type, mod);
|
modifiers.put(type, new Vector(mod, mod >= 1 ? mod : 1, mod)); // don't touch vertical
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!modifiers.isEmpty())
|
if (!modifiers.isEmpty()) {
|
||||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
registerEvents(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class.forName("com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent");
|
||||||
|
DebugLogger.warning("Ignore that. Server performance will NOT be affected.");
|
||||||
|
} catch (ClassNotFoundException ignored) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
108
src/main/java/eu/m724/tweaks/module/motd/MotdModule.java
Normal file
108
src/main/java/eu/m724/tweaks/module/motd/MotdModule.java
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.motd;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.events.InternalStructure;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import net.minecraft.SharedConstants;
|
||||||
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.protocol.status.ServerStatus;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileAlreadyExistsException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class MotdModule extends TweaksModule {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
Path motdSetPath = getPlugin().getDataFolder().toPath().resolve("motd sets").resolve(getConfig().motdSet() + ".txt");
|
||||||
|
|
||||||
|
// create "motd sets" directory
|
||||||
|
try {
|
||||||
|
Files.createDirectories(motdSetPath);
|
||||||
|
} catch (FileAlreadyExistsException ignored) {
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this is a builtin set
|
||||||
|
if (!Files.exists(motdSetPath) && getPlugin().hasResource("motd sets/" + motdSetPath.getFileName()))
|
||||||
|
getPlugin().saveResource("motd sets/" + motdSetPath.getFileName(), false);
|
||||||
|
|
||||||
|
if (!Files.exists(motdSetPath)) {
|
||||||
|
throw new RuntimeException("MOTD set \"%s\" doesn't exist".formatted(getConfig().motdSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileContent;
|
||||||
|
try {
|
||||||
|
fileContent = Files.readString(motdSetPath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Reading motd set", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MOTDs are split with an empty line
|
||||||
|
Component[] motds = Arrays.stream(fileContent.split("\n\n"))
|
||||||
|
.map(entry -> {
|
||||||
|
entry = entry.strip();
|
||||||
|
JsonElement json = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
json = JsonParser.parseString(entry);
|
||||||
|
DebugLogger.finer("JSON line: %s...", entry.substring(0, Math.min(entry.length(), 10)));
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
DebugLogger.finer("JSON line: %s...", entry.substring(0, Math.min(entry.length(), 10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json == null) {
|
||||||
|
json = ComponentSerializer.toJson(TextComponent.fromLegacy(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Component.Serializer.fromJson(json, RegistryAccess.EMPTY);
|
||||||
|
})
|
||||||
|
.toArray(Component[]::new);
|
||||||
|
|
||||||
|
onPacketSend(PacketType.Status.Server.SERVER_INFO, (event) -> {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
|
||||||
|
Component motd = motds[ThreadLocalRandom.current().nextInt(motds.length)];
|
||||||
|
|
||||||
|
ServerStatus serverStatus = (ServerStatus) packet.getStructures().read(0).getHandle();
|
||||||
|
|
||||||
|
/* this:
|
||||||
|
* removes server mod prefix (Paper, Spigot, any brand)
|
||||||
|
* hides players
|
||||||
|
*/
|
||||||
|
ServerStatus newStatus = new ServerStatus(
|
||||||
|
motd,
|
||||||
|
Optional.empty(),
|
||||||
|
Optional.of(new ServerStatus.Version(
|
||||||
|
SharedConstants.getCurrentVersion().getName(),
|
||||||
|
SharedConstants.getProtocolVersion()
|
||||||
|
)),
|
||||||
|
serverStatus.favicon(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
packet.getStructures().write(0, new InternalStructure(newStatus, new StructureModifier<>(ServerStatus.class)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.ping;
|
package eu.m724.tweaks.module.ping;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
import com.comphenix.protocol.events.*;
|
import com.comphenix.protocol.events.*;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import net.minecraft.network.protocol.common.custom.BrandPayload;
|
import net.minecraft.network.protocol.common.custom.BrandPayload;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.ping;
|
package eu.m724.tweaks.module.ping;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.ping;
|
package eu.m724.tweaks.module.ping;
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
@ -1,16 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.ping;
|
package eu.m724.tweaks.module.ping;
|
||||||
|
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class PingChecker {
|
public class PingChecker {
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.ping;
|
package eu.m724.tweaks.module.ping;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.ping;
|
package eu.m724.tweaks.module.ping;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
package eu.m724.tweaks.module.pomodoro;
|
||||||
|
|
||||||
public class PlayerPomodoro {
|
public class PlayerPomodoro {
|
||||||
private int pomodori = 0;
|
private int pomodori = 0;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
package eu.m724.tweaks.module.pomodoro;
|
||||||
|
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
|
@ -1,12 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
package eu.m724.tweaks.module.pomodoro;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.pomodoro;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
|
||||||
|
public class PomodoroModule extends TweaksModule {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerEvents(new PomodoroListener());
|
||||||
|
new PomodoroRunnable().runTaskTimerAsynchronously(getPlugin(), 0, 20L);
|
||||||
|
|
||||||
|
registerCommand("pomodoro", new PomodoroCommands());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
package eu.m724.tweaks.module.pomodoro;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.TweaksPlugin;
|
||||||
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
|
@ -15,15 +16,12 @@ import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
public class PomodoroRunnable extends BukkitRunnable {
|
public class PomodoroRunnable extends BukkitRunnable {
|
||||||
private final boolean force = TweaksConfig.getConfig().pomodoroForce();
|
private final boolean force = TweaksConfig.getConfig().pomodoroForce();
|
||||||
private final Plugin plugin;
|
private final Plugin plugin = TweaksPlugin.getInstance(); // used only to kick
|
||||||
|
|
||||||
public PomodoroRunnable(Plugin plugin) {
|
|
||||||
this.plugin = plugin; // only used for kicking
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long now = System.nanoTime();
|
long now = System.nanoTime();
|
||||||
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||||
PlayerPomodoro pomodoro = Pomodoros.get(player);
|
PlayerPomodoro pomodoro = Pomodoros.get(player);
|
||||||
if (pomodoro == null) return;
|
if (pomodoro == null) return;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
package eu.m724.tweaks.module.pomodoro;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
@ -1,11 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
package eu.m724.tweaks.module.redstone;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.Language;
|
import eu.m724.tweaks.Language;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
|
@ -18,14 +19,21 @@ public class GatewayItem {
|
||||||
private final NamespacedKey gatewayKey;
|
private final NamespacedKey gatewayKey;
|
||||||
|
|
||||||
public GatewayItem(Plugin plugin) {
|
public GatewayItem(Plugin plugin) {
|
||||||
this.gatewayKey = new NamespacedKey(plugin, "gateway");
|
var start = System.nanoTime();
|
||||||
|
|
||||||
|
this.gatewayKey = new NamespacedKey(plugin, "gateway");
|
||||||
var recipe = new ShapelessRecipe(gatewayKey, itemStack());
|
var recipe = new ShapelessRecipe(gatewayKey, itemStack());
|
||||||
|
|
||||||
|
// this takes a long time for some reason. The first one especially
|
||||||
|
// do this somewhere off measure to JIT and skew the measurement: new RecipeChoice.MaterialChoice(Material.DIRT);
|
||||||
recipe.addIngredient(Material.NETHER_STAR);
|
recipe.addIngredient(Material.NETHER_STAR);
|
||||||
recipe.addIngredient(Material.ENDER_CHEST);
|
recipe.addIngredient(Material.ENDER_CHEST);
|
||||||
recipe.addIngredient(Material.CHORUS_FLOWER);
|
recipe.addIngredient(Material.CHORUS_FLOWER);
|
||||||
recipe.addIngredient(Material.DAYLIGHT_DETECTOR);
|
recipe.addIngredient(Material.DAYLIGHT_DETECTOR);
|
||||||
|
|
||||||
plugin.getServer().addRecipe(recipe);
|
plugin.getServer().addRecipe(recipe);
|
||||||
|
|
||||||
|
DebugLogger.finer("Adding the recipe took %d ms, which is a long time", (System.nanoTime() - start) / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack itemStack() {
|
public ItemStack itemStack() {
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
package eu.m724.tweaks.module.redstone;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
package eu.m724.tweaks.module.redstone;
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.HashBiMap;
|
import com.google.common.collect.HashBiMap;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
package eu.m724.tweaks.module.redstone;
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.Language;
|
import eu.m724.tweaks.Language;
|
|
@ -1,43 +1,36 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
package eu.m724.tweaks.module.redstone;
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import org.bukkit.command.PluginCommand;
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class RedstoneManager {
|
public class RedstoneModule extends TweaksModule {
|
||||||
private final Plugin plugin;
|
private final RedstoneGateways redstoneGateways = new RedstoneGateways(getPlugin());
|
||||||
private final RedstoneGateways redstoneGateways;
|
|
||||||
|
|
||||||
private DatagramSocket socket;
|
private DatagramSocket socket;
|
||||||
private RedstoneStateUpdateRunnable runnable;
|
private RedstoneStateUpdateRunnable runnable;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
RedstoneStore.init(getPlugin());
|
||||||
|
var gatewayItem = new GatewayItem(getPlugin());
|
||||||
|
|
||||||
public RedstoneManager(Plugin plugin) {
|
registerEvents(new RedstoneListener(redstoneGateways, gatewayItem));
|
||||||
this.plugin = plugin;
|
registerCommand("retstone", new RedstoneCommands(gatewayItem));
|
||||||
this.redstoneGateways = new RedstoneGateways(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(PluginCommand command) {
|
|
||||||
RedstoneStore.init(plugin);
|
|
||||||
var gatewayItem = new GatewayItem(plugin);
|
|
||||||
|
|
||||||
plugin.getServer().getPluginManager().registerEvents(new RedstoneListener(redstoneGateways, gatewayItem), plugin);
|
|
||||||
command.setExecutor(new RedstoneCommands(gatewayItem));
|
|
||||||
|
|
||||||
this.runnable = new RedstoneStateUpdateRunnable(redstoneGateways);
|
this.runnable = new RedstoneStateUpdateRunnable(redstoneGateways);
|
||||||
this.runnable.runTaskTimer(plugin, 0, 20); // TODO configurable
|
this.runnable.runTaskTimer(getPlugin(), 0, 20); // TODO configurable
|
||||||
|
|
||||||
var listenAddress = TweaksConfig.getConfig().redstoneListen().split(":");
|
var listenAddress = TweaksConfig.getConfig().redstoneListen().split(":");
|
||||||
InetSocketAddress bindAddress;
|
InetSocketAddress bindAddress;
|
||||||
|
@ -52,7 +45,6 @@ public class RedstoneManager {
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
throw new RuntimeException("Starting socket", e);
|
throw new RuntimeException("Starting socket", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initSocket(SocketAddress bindAddress) throws SocketException {
|
private void initSocket(SocketAddress bindAddress) throws SocketException {
|
||||||
|
@ -96,12 +88,12 @@ public class RedstoneManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enqueueUpdate(int gatewayId, byte power) {
|
private void enqueueUpdate(int gatewayId, byte power) {
|
||||||
DebugLogger.fine("Update enqueued " + gatewayId + " " + power);
|
DebugLogger.finer("Update enqueued " + gatewayId + " " + power);
|
||||||
runnable.enqueueUpdate(gatewayId, power);
|
runnable.enqueueUpdate(gatewayId, power);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enqueueRetrieve(int gatewayId, Consumer<Byte> consumer) {
|
private void enqueueRetrieve(int gatewayId, Consumer<Byte> consumer) {
|
||||||
DebugLogger.fine("Retrieve enqueued " + gatewayId);
|
DebugLogger.finer("Retrieve enqueued " + gatewayId);
|
||||||
runnable.enqueueRetrieve(gatewayId, consumer);
|
runnable.enqueueRetrieve(gatewayId, consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
package eu.m724.tweaks.module.redstone;
|
||||||
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
package eu.m724.tweaks.module.redstone;
|
||||||
|
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import eu.m724.tweaks.DebugLogger;
|
import eu.m724.tweaks.DebugLogger;
|
|
@ -1,14 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.sleep;
|
package eu.m724.tweaks.module.sleep;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.config.TweaksConfig;
|
||||||
import org.bukkit.GameRule;
|
import org.bukkit.GameRule;
|
||||||
import org.bukkit.World;
|
import org.bukkit.attribute.Attribute;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
@ -21,6 +21,7 @@ import java.util.Set;
|
||||||
|
|
||||||
public class SleepListener implements Listener {
|
public class SleepListener implements Listener {
|
||||||
private final boolean instant = TweaksConfig.getConfig().sleepInstant();
|
private final boolean instant = TweaksConfig.getConfig().sleepInstant();
|
||||||
|
private final double heal = TweaksConfig.getConfig().sleepHeal() * 2; // hearts to half hearts
|
||||||
|
|
||||||
private final Set<Player> skippedCurrentNight = new HashSet<>();
|
private final Set<Player> skippedCurrentNight = new HashSet<>();
|
||||||
private long lastDay = 0;
|
private long lastDay = 0;
|
||||||
|
@ -30,18 +31,21 @@ public class SleepListener implements Listener {
|
||||||
if (event.getBedEnterResult() == PlayerBedEnterEvent.BedEnterResult.OK) {
|
if (event.getBedEnterResult() == PlayerBedEnterEvent.BedEnterResult.OK) {
|
||||||
SleepState.playersSleeping++;
|
SleepState.playersSleeping++;
|
||||||
|
|
||||||
if (instant) {
|
var player = event.getPlayer();
|
||||||
World world = event.getPlayer().getWorld();
|
var world = player.getWorld();
|
||||||
|
|
||||||
long day = world.getFullTime() / 24000;
|
long day = world.getFullTime() / 24000;
|
||||||
if (day != lastDay) skippedCurrentNight.clear();
|
if (day != lastDay) skippedCurrentNight.clear();
|
||||||
lastDay = day;
|
lastDay = day;
|
||||||
|
|
||||||
if (!skippedCurrentNight.contains(event.getPlayer())) {
|
if (skippedCurrentNight.add(player)) {
|
||||||
double onePlayerRatio = 1 / (event.getPlayer().getServer().getOnlinePlayers().size() * (world.getGameRuleValue(GameRule.PLAYERS_SLEEPING_PERCENTAGE) / 100.0));
|
if (instant) {
|
||||||
|
double onePlayerRatio = 1 / (player.getServer().getOnlinePlayers().size() * (world.getGameRuleValue(GameRule.PLAYERS_SLEEPING_PERCENTAGE) / 100.0));
|
||||||
world.setTime(Math.min(world.getTime() + (long) (10917 * onePlayerRatio), 23459));
|
world.setTime(Math.min(world.getTime() + (long) (10917 * onePlayerRatio), 23459));
|
||||||
skippedCurrentNight.add(event.getPlayer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var maxHealth = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue();
|
||||||
|
player.setHealth(Math.min(player.getHealth() + heal, maxHealth));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +57,9 @@ public class SleepListener implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerBedLeave(TimeSkipEvent event) {
|
public void onTimeSkip(TimeSkipEvent event) {
|
||||||
if (event.getSkipReason() == TimeSkipEvent.SkipReason.NIGHT_SKIP)
|
if (event.getSkipReason() == TimeSkipEvent.SkipReason.NIGHT_SKIP) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
19
src/main/java/eu/m724/tweaks/module/sleep/SleepModule.java
Normal file
19
src/main/java/eu/m724/tweaks/module/sleep/SleepModule.java
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.sleep;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
|
||||||
|
public class SleepModule extends TweaksModule {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
registerEvents(new SleepListener());
|
||||||
|
|
||||||
|
if (!getConfig().sleepInstant())
|
||||||
|
new TimeForwardRunnable(getPlugin()).runTaskTimer(getPlugin(), 0, 1); // TODO maybe not
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.sleep;
|
package eu.m724.tweaks.module.sleep;
|
||||||
|
|
||||||
public class SleepState {
|
public class SleepState {
|
||||||
static int playersSleeping;
|
static int playersSleeping;
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.sleep;
|
||||||
|
|
||||||
|
import org.bukkit.GameRule;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
public class TimeForwardRunnable extends BukkitRunnable {
|
||||||
|
private final Server server;
|
||||||
|
|
||||||
|
public TimeForwardRunnable(Plugin plugin) {
|
||||||
|
this.server = plugin.getServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (World world : server.getWorlds()) {
|
||||||
|
var gameRuleValue = world.getGameRuleValue(GameRule.PLAYERS_SLEEPING_PERCENTAGE);
|
||||||
|
if (gameRuleValue == null) gameRuleValue = 100;
|
||||||
|
double percentage = gameRuleValue / 100.0;
|
||||||
|
|
||||||
|
int playersSleeping = SleepState.playersSleeping;
|
||||||
|
//System.out.println(playersSleeping);
|
||||||
|
if (playersSleeping == 0) return;
|
||||||
|
|
||||||
|
int onlinePlayers = (int) (world.getPlayers().size() / percentage);
|
||||||
|
|
||||||
|
double sleepPercentage = (double) playersSleeping / onlinePlayers;
|
||||||
|
|
||||||
|
// we want sleep to take 200 ticks which is 10 seconds assuming all palyres onilien
|
||||||
|
|
||||||
|
long time = world.getTime();
|
||||||
|
long untilDay = 23459 - time;
|
||||||
|
|
||||||
|
if (untilDay == 0) return;
|
||||||
|
|
||||||
|
long perSkip = 200 + (100000 / -untilDay);
|
||||||
|
perSkip = Math.clamp(perSkip, 20, 200);
|
||||||
|
perSkip = (long) (perSkip * sleepPercentage);
|
||||||
|
|
||||||
|
world.setTime(world.getTime() + perSkip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
src/main/java/eu/m724/tweaks/module/swing/SwingModule.java
Normal file
68
src/main/java/eu/m724/tweaks/module/swing/SwingModule.java
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.swing;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.attribute.Attribute;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class SwingModule extends TweaksModule implements Listener {
|
||||||
|
private final Set<Material> tools = new HashSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
Arrays.stream(Material.values())
|
||||||
|
.filter(m -> m.name().contains("SWORD"))
|
||||||
|
.forEach(tools::add);
|
||||||
|
|
||||||
|
DebugLogger.finer("Tools: " + tools.size());
|
||||||
|
|
||||||
|
registerEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onBreak(BlockBreakEvent event) {
|
||||||
|
var type = event.getBlock().getType();
|
||||||
|
if (type.isOccluding()) return;
|
||||||
|
|
||||||
|
var player = event.getPlayer();
|
||||||
|
var tool = player.getInventory().getItemInMainHand().getType();
|
||||||
|
Entity entity = null;
|
||||||
|
|
||||||
|
if (tools.contains(tool)) { // if sword, raycast to hit farther
|
||||||
|
var result = player.getWorld().rayTraceEntities(
|
||||||
|
player.getEyeLocation(),
|
||||||
|
player.getEyeLocation().getDirection(),
|
||||||
|
player.getAttribute(Attribute.PLAYER_ENTITY_INTERACTION_RANGE).getValue(),
|
||||||
|
e -> e != player
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
entity = result.getHitEntity();
|
||||||
|
} else {
|
||||||
|
entity = event.getBlock().getWorld()
|
||||||
|
.getNearbyEntities(event.getBlock().getLocation().add(0.5, 0.5, 0.5), 0.5, 0.5, 0.5)
|
||||||
|
.stream().filter(e -> (e instanceof LivingEntity && e != player))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity != null) {
|
||||||
|
player.attack(entity);
|
||||||
|
DebugLogger.fine("Swing " + player.getName() + " hit " + entity.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
package eu.m724.tweaks.module.updater;
|
||||||
|
|
||||||
import eu.m724.tweaks.Language;
|
import eu.m724.tweaks.Language;
|
||||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
import eu.m724.tweaks.module.updater.backend.UpdateChecker;
|
||||||
|
import eu.m724.tweaks.module.updater.object.VersionedResource;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
@ -20,18 +21,25 @@ import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
public class UpdaterCommands implements CommandExecutor {
|
public class UpdaterCommands implements CommandExecutor {
|
||||||
|
private final UpdateChecker updateChecker;
|
||||||
|
|
||||||
|
public UpdaterCommands(UpdateChecker updateChecker) {
|
||||||
|
this.updateChecker = updateChecker;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
if (UpdateChecker.lastChecked == null) {
|
var lastChecked = updateChecker.getLastChecked();
|
||||||
|
if (updateChecker.getLastChecked() == -1) {
|
||||||
sender.sendMessage(Language.getString("updatesNotChecked"));
|
sender.sendMessage(Language.getString("updatesNotChecked"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String lastChecked = UpdateChecker.lastChecked.format(DateTimeFormatter.ofPattern("HH:mm"));
|
int n = updateChecker.getAvailableUpdates().size();
|
||||||
int n = UpdateChecker.availableUpdates.size();
|
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
sender.spigot().sendMessage(
|
sender.spigot().sendMessage(
|
||||||
|
@ -39,13 +47,14 @@ public class UpdaterCommands implements CommandExecutor {
|
||||||
);
|
);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (VersionedResource v : UpdateChecker.availableUpdates) {
|
for (VersionedResource v : updateChecker.getAvailableUpdates()) {
|
||||||
sender.spigot().sendMessage(
|
sender.spigot().sendMessage(
|
||||||
new ComponentBuilder(++i + ". ").color(ChatColor.GRAY).build(), resourceToBaseComponent(v)
|
new ComponentBuilder(++i + ". ").color(ChatColor.GRAY).build(), resourceToBaseComponent(v)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sender.spigot().sendMessage(Language.getComponent("updatesNoUpdates", ChatColor.GREEN, lastChecked));
|
var lastCheckedFormat = DateTimeFormatter.ofPattern("HH:mm").format(Instant.ofEpochMilli(lastChecked));
|
||||||
|
sender.spigot().sendMessage(Language.getComponent("updatesNoUpdates", ChatColor.GREEN, lastCheckedFormat));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.updater;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
import eu.m724.tweaks.module.updater.backend.UpdateChecker;
|
||||||
|
import eu.m724.tweaks.module.updater.backend.VersionCache;
|
||||||
|
import eu.m724.tweaks.module.updater.object.ResourceVersion;
|
||||||
|
import eu.m724.tweaks.module.updater.object.SpigotResource;
|
||||||
|
import eu.m724.tweaks.module.updater.object.VersionedResource;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class UpdaterModule extends TweaksModule {
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
var resources = loadInstalledPlugins();
|
||||||
|
|
||||||
|
// load installed versions from cache
|
||||||
|
var cacheFile = new File(getPlugin().getDataFolder(), "storage/cache/updater");
|
||||||
|
|
||||||
|
final var installedVersions = loadInstalledVersionCache(cacheFile);
|
||||||
|
|
||||||
|
var versionedResources = resources.stream()
|
||||||
|
.map(res -> new VersionedResource(
|
||||||
|
res, installedVersions.stream().filter(iv -> iv.resourceId() == res.resourceId()).findFirst().orElse(null), null
|
||||||
|
))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
|
||||||
|
var updateChecker = new UpdateChecker(getPlugin().getLogger(), cacheFile, versionedResources);
|
||||||
|
updateChecker.runTaskTimerAsynchronously(getPlugin(), 600, 12 * 3600 * 20); // 12 hours
|
||||||
|
|
||||||
|
registerCommand("updates", new UpdaterCommands(updateChecker));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<ResourceVersion> loadInstalledVersionCache(File cacheFile) {
|
||||||
|
try (FileInputStream inputStream = new FileInputStream(cacheFile)) {
|
||||||
|
return VersionCache.loadAll(inputStream);
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
} catch (IOException e) {
|
||||||
|
DebugLogger.warning("Error loading installed version cache, starting fresh. " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<SpigotResource> loadInstalledPlugins() {
|
||||||
|
File installedPluginsYml = new File(getPlugin().getDataFolder(), "installed_plugins.yml");
|
||||||
|
|
||||||
|
if (!installedPluginsYml.exists()) {
|
||||||
|
getPlugin().saveResource("installed_plugins.yml", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(installedPluginsYml);
|
||||||
|
|
||||||
|
Plugin[] plugins = getPlugin().getServer().getPluginManager().getPlugins();
|
||||||
|
Set<SpigotResource> spigotResources = new HashSet<>();
|
||||||
|
|
||||||
|
for (Plugin plugin : plugins) {
|
||||||
|
String pluginName = plugin.getName();
|
||||||
|
|
||||||
|
if (!configuration.isSet(pluginName)) {
|
||||||
|
configuration.set(pluginName, -1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pluginId = configuration.getInt(pluginName);
|
||||||
|
if (pluginId > 0) {
|
||||||
|
spigotResources.add(
|
||||||
|
new SpigotResource(plugin, pluginId, pluginName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
configuration.save(installedPluginsYml);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to update installed_plugins.yml", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return spigotResources;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,89 +1,115 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
package eu.m724.tweaks.module.updater.backend;
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.Language;
|
import eu.m724.tweaks.Language;
|
||||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
import eu.m724.tweaks.module.updater.object.VersionedResource;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.ZoneOffset;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class UpdateChecker extends BukkitRunnable {
|
public class UpdateChecker extends BukkitRunnable {
|
||||||
|
private final Logger logger;
|
||||||
|
private final File cacheFile;
|
||||||
private final Set<VersionedResource> resources;
|
private final Set<VersionedResource> resources;
|
||||||
|
|
||||||
static final Set<VersionedResource> availableUpdates = new HashSet<>();
|
private final Set<VersionedResource> availableUpdates = new HashSet<>();
|
||||||
static LocalTime lastChecked = null;
|
private long lastChecked = -1;
|
||||||
|
|
||||||
UpdateChecker(Set<VersionedResource> resources) {
|
public UpdateChecker(Logger logger, File cacheFile, Set<VersionedResource> resources) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.cacheFile = cacheFile;
|
||||||
this.resources = resources; // TODO make a copy?
|
this.resources = resources; // TODO make a copy?
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAll() {
|
private void checkAll() {
|
||||||
//logger.info("Checking for updates");
|
DebugLogger.fine("Checking for updates");
|
||||||
lastChecked = LocalTime.now(ZoneOffset.UTC);
|
lastChecked = System.currentTimeMillis();
|
||||||
availableUpdates.clear();
|
availableUpdates.clear();
|
||||||
|
var errors = 0;
|
||||||
|
|
||||||
for (VersionedResource versionedResource : Set.copyOf(resources)) {
|
for (VersionedResource versionedResource : Set.copyOf(resources)) {
|
||||||
String pluginName = versionedResource.resource().plugin().getName();
|
String pluginName = versionedResource.resource().plugin().getName();
|
||||||
//logger.info(versionedResource.resource().resourceId() + " " + versionedResource.resource().plugin().getName());
|
|
||||||
int page = versionedResource.running() != null ? versionedResource.running().page() : 1;
|
int page = versionedResource.running() != null ? versionedResource.running().page() : 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
VersionedResource newResource = new VersionFinder(versionedResource.resource(), page).join(); // this runs async so it's ok
|
VersionedResource newResource = new VersionScanner(versionedResource.resource(), page).join(); // this runs async so it's ok
|
||||||
if (!versionedResource.equals(newResource)) {
|
if (!versionedResource.equals(newResource)) {
|
||||||
resources.remove(versionedResource);
|
resources.remove(versionedResource);
|
||||||
|
|
||||||
if (newResource.running() == null) {
|
if (newResource.running() == null) {
|
||||||
DebugLogger.info("Unable to find installed version of %s".formatted(pluginName));
|
var pluginVersion = versionedResource.resource().plugin().getDescription().getVersion();
|
||||||
if (versionedResource.running() != null) {
|
var message = "";
|
||||||
DebugLogger.info("Did you downgrade %s? If so, clear cache".formatted(pluginName));
|
|
||||||
|
if (pluginVersion.endsWith("-SNAPSHOT")) {
|
||||||
|
message = "Is it a development build?";
|
||||||
|
} else if (versionedResource.running() != null) {
|
||||||
|
message = "Did you downgrade it? If so, clear cache (delete Tweaks724/storage/cache/updater)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DebugLogger.warning("This version of %s doesn't exist on SpigotMC. %s", pluginName, message);
|
||||||
|
errors++;
|
||||||
} else {
|
} else {
|
||||||
if (!newResource.running().equals(newResource.latest())) {
|
if (!newResource.running().equals(newResource.latest())) {
|
||||||
availableUpdates.add(newResource);
|
availableUpdates.add(newResource);
|
||||||
//logger.info("Update available for %s. %d -> %d".formatted(pluginName, newResource.running().updateId(), newResource.latest().updateId()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resources.add(newResource);
|
resources.add(newResource);
|
||||||
}
|
}
|
||||||
} catch (CompletionException e) {
|
} catch (CompletionException e) {
|
||||||
DebugLogger.severe("Unable to refresh %s: %s".formatted(pluginName, e.getMessage()));
|
DebugLogger.severe("Unable to refresh %s: %s".formatted(pluginName, e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errors > 0) {
|
||||||
|
DebugLogger.info("To disable the updater for specific plugins, refer to updater_config.yml");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void alert() {
|
private void alert() {
|
||||||
int n = availableUpdates.size();
|
int n = availableUpdates.size();
|
||||||
if (n == 0) return;
|
if (n == 0) return;
|
||||||
DebugLogger.info(Language.getString("updateAvailableNotice", n));
|
logger.info(Language.getString("updateAvailableNotice", n));
|
||||||
|
|
||||||
availableUpdates.stream()
|
availableUpdates.stream()
|
||||||
.map(u -> "- %s (%s -> %s)".formatted(u.resource().name(), u.running().label(), u.latest().label()))
|
.map(u -> "- %s (%s -> %s)".formatted(u.resource().name(), u.running().label(), u.latest().label()))
|
||||||
.forEach(DebugLogger::info);
|
.forEach(logger::info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
checkAll();
|
checkAll();
|
||||||
|
|
||||||
try (FileOutputStream outputStream = new FileOutputStream(UpdaterManager.cacheFile)) {
|
DebugLogger.finer("Done checking, now saving");
|
||||||
VersionCheckCache.writeAll(outputStream, resources.stream().map(VersionedResource::running).filter(Objects::nonNull).collect(Collectors.toSet()));
|
cacheFile.getParentFile().mkdirs();
|
||||||
|
try (FileOutputStream outputStream = new FileOutputStream(cacheFile)) {
|
||||||
|
VersionCache.writeAll(outputStream, resources.stream().map(VersionedResource::running).filter(Objects::nonNull).collect(Collectors.toSet()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
alert();
|
alert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getLastChecked() {
|
||||||
|
return lastChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<VersionedResource> getAvailableUpdates() {
|
||||||
|
return availableUpdates;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
package eu.m724.tweaks.module.updater.backend;
|
||||||
|
|
||||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
import eu.m724.tweaks.module.updater.object.ResourceVersion;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -15,7 +15,7 @@ import java.io.OutputStream;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class VersionCheckCache {
|
public class VersionCache {
|
||||||
private static final byte FILE_VERSION = 1;
|
private static final byte FILE_VERSION = 1;
|
||||||
|
|
||||||
public static Set<ResourceVersion> loadAll(FileInputStream inputStream) throws IOException {
|
public static Set<ResourceVersion> loadAll(FileInputStream inputStream) throws IOException {
|
|
@ -1,19 +1,20 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
package eu.m724.tweaks.module.updater.backend;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
import eu.m724.tweaks.DebugLogger;
|
||||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
import eu.m724.tweaks.module.updater.object.SpigotResource;
|
||||||
import eu.m724.tweaks.updater.cache.UpdateDescription;
|
import eu.m724.tweaks.module.updater.object.ResourceVersion;
|
||||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
import eu.m724.tweaks.module.updater.object.UpdateDescription;
|
||||||
|
import eu.m724.tweaks.module.updater.object.VersionedResource;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
@ -26,23 +27,24 @@ import java.util.concurrent.Executors;
|
||||||
|
|
||||||
// TODO optimize
|
// TODO optimize
|
||||||
|
|
||||||
public class VersionFinder extends CompletableFuture<VersionedResource> {
|
public class VersionScanner extends CompletableFuture<VersionedResource> {
|
||||||
private final SpigotResource resource;
|
private final SpigotResource resource;
|
||||||
private final int fromPage;
|
private final int fromPage;
|
||||||
|
|
||||||
VersionFinder(SpigotResource resource, int fromPage) {
|
VersionScanner(SpigotResource resource, int fromPage) {
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
this.fromPage = fromPage;
|
this.fromPage = fromPage;
|
||||||
|
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionFinder(SpigotResource resource) {
|
VersionScanner(SpigotResource resource) {
|
||||||
this(resource, 1);
|
this(resource, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start() {
|
private void start() {
|
||||||
//System.out.printf("STarting for %d %s\n", resource.resourceId(), resource.plugin().getName());
|
DebugLogger.finer("Scanning %s (#%d) from page %d", resource.name(), resource.resourceId(), fromPage);
|
||||||
|
|
||||||
try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
|
try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -51,13 +53,14 @@ public class VersionFinder extends CompletableFuture<VersionedResource> {
|
||||||
|
|
||||||
int page;
|
int page;
|
||||||
for (page = fromPage; page < 1000; page++) {
|
for (page = fromPage; page < 1000; page++) {
|
||||||
//System.out.println("Page " + page);
|
DebugLogger.finer("Scan %s now at page %d", resource.name(), page);
|
||||||
|
|
||||||
String url = "https://api.spigotmc.org/simple/0.2/index.php?action=getResourceUpdates&page=%d&id=%d".formatted(page, resource.resourceId());
|
String url = "https://api.spigotmc.org/simple/0.2/index.php?action=getResourceUpdates&page=%d&id=%d".formatted(page, resource.resourceId());
|
||||||
|
|
||||||
HttpRequest request;
|
HttpRequest request;
|
||||||
try {
|
try {
|
||||||
request = HttpRequest.newBuilder(new URI(url))
|
request = HttpRequest.newBuilder(new URI(url))
|
||||||
.header("User-Agent", "twu/1")
|
.header("User-Agent", "twu/1") // tweaks updater v1
|
||||||
.build();
|
.build();
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -68,6 +71,7 @@ public class VersionFinder extends CompletableFuture<VersionedResource> {
|
||||||
|
|
||||||
String body = response.body();
|
String body = response.body();
|
||||||
if (body.isBlank()) {
|
if (body.isBlank()) {
|
||||||
|
DebugLogger.finer("Body is blank, stopping");
|
||||||
page--;
|
page--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -75,15 +79,7 @@ public class VersionFinder extends CompletableFuture<VersionedResource> {
|
||||||
JsonArray jsonArray = JsonParser.parseString(body).getAsJsonArray();
|
JsonArray jsonArray = JsonParser.parseString(body).getAsJsonArray();
|
||||||
for (JsonElement ele : jsonArray) {
|
for (JsonElement ele : jsonArray) {
|
||||||
JsonObject versionJson = ele.getAsJsonObject();
|
JsonObject versionJson = ele.getAsJsonObject();
|
||||||
if (isRunningVersion(versionJson)) {
|
|
||||||
runningVersion = new ResourceVersion(
|
|
||||||
resource.resourceId(),
|
|
||||||
page,
|
|
||||||
versionJson.get("id").getAsInt(),
|
|
||||||
versionJson.get("resource_version").getAsString(),
|
|
||||||
null // no need for changelog of running version
|
|
||||||
);
|
|
||||||
}
|
|
||||||
latestVersion = new ResourceVersion(
|
latestVersion = new ResourceVersion(
|
||||||
resource.resourceId(),
|
resource.resourceId(),
|
||||||
page,
|
page,
|
||||||
|
@ -94,14 +90,17 @@ public class VersionFinder extends CompletableFuture<VersionedResource> {
|
||||||
versionJson.get("message").getAsString()
|
versionJson.get("message").getAsString()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
//System.out.printf("%d %d %s\n", page, versionJson.get("id").getAsInt(), versionJson.get("resource_version").getAsString());
|
|
||||||
|
if (isRunningVersion(versionJson))
|
||||||
|
runningVersion = latestVersion;
|
||||||
|
|
||||||
|
DebugLogger.finer("%s - %s #%d", resource.name(), latestVersion.updateId(), latestVersion.updateId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonArray.size() < 10) break;
|
if (jsonArray.size() < 10) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//System.out.println("Done");
|
|
||||||
|
|
||||||
if (page > 999) {
|
if (page > 999) {
|
||||||
throw new Exception("Too many pages");
|
throw new Exception("Too many pages");
|
||||||
|
@ -117,7 +116,8 @@ public class VersionFinder extends CompletableFuture<VersionedResource> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isRunningVersion(JsonObject versionJson) {
|
private boolean isRunningVersion(JsonObject versionJson) {
|
||||||
// TODO
|
// TODO make it work with more advanced strings
|
||||||
return versionJson.get("resource_version").getAsString().equals(resource.plugin().getDescription().getVersion());
|
return versionJson.get("resource_version").getAsString()
|
||||||
|
.equals(resource.plugin().getDescription().getVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater.cache;
|
package eu.m724.tweaks.module.updater.object;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater.cache;
|
package eu.m724.tweaks.module.updater.object;
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
@ -12,5 +12,4 @@ public record SpigotResource(
|
||||||
Plugin plugin,
|
Plugin plugin,
|
||||||
int resourceId,
|
int resourceId,
|
||||||
String name
|
String name
|
||||||
) {
|
) { }
|
||||||
}
|
|
|
@ -1,13 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater.cache;
|
package eu.m724.tweaks.module.updater.object;
|
||||||
|
|
||||||
public record UpdateDescription(
|
public record UpdateDescription(
|
||||||
String title,
|
String title,
|
||||||
String description
|
String description
|
||||||
) {
|
) { }
|
||||||
}
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater.cache;
|
package eu.m724.tweaks.module.updater.object;
|
||||||
|
|
||||||
public record VersionedResource(
|
public record VersionedResource(
|
||||||
SpigotResource resource,
|
SpigotResource resource,
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.wordcoords;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.wordcoords.converter.Decoder;
|
||||||
|
import eu.m724.tweaks.module.wordcoords.converter.Encoder;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
public class WordCoordsConverter {
|
||||||
|
private final Encoder encoder;
|
||||||
|
private final Decoder decoder;
|
||||||
|
|
||||||
|
|
||||||
|
public WordCoordsConverter(WordList wordList) {
|
||||||
|
this.encoder = new Encoder(wordList);
|
||||||
|
this.decoder = new Decoder(wordList);
|
||||||
|
|
||||||
|
DebugLogger.fine("Words: %d (%d bits)", wordList.getWordCount(), wordList.getBitsPerWord());
|
||||||
|
DebugLogger.fine("Bits per word: %d", wordList.getBitsPerWord());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] encode(int x, int z) {
|
||||||
|
return encoder.encode(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] decode(String[] words) throws NoSuchElementException {
|
||||||
|
return decoder.decode(words);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.wordcoords;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.Language;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||||
|
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
public class WordCoordsModule extends TweaksModule implements CommandExecutor, Listener {
|
||||||
|
private WordList wordList;
|
||||||
|
private WordCoordsConverter converter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
try {
|
||||||
|
this.wordList = WordList.fromFile(getPlugin().getDataFolder().toPath().resolve("storage/wordlist.txt"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.converter = new WordCoordsConverter(wordList);
|
||||||
|
|
||||||
|
registerCommand("wordcoords", this);
|
||||||
|
registerEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
int x = 0, z = 0;
|
||||||
|
String[] words = new String[0];
|
||||||
|
|
||||||
|
boolean encode = false; // means encode pos to words
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
if (!(sender instanceof Player player)) {
|
||||||
|
sender.sendMessage(Language.getString("wordCoordsPlayerOnly"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = player.getLocation().getBlockX();
|
||||||
|
z = player.getLocation().getBlockZ();
|
||||||
|
|
||||||
|
encode = true;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
try {
|
||||||
|
double dx = Double.parseDouble(args[0]);
|
||||||
|
double dz = Double.parseDouble(args[args.length > 2 ? 2 : 1]);
|
||||||
|
|
||||||
|
if (dx > Integer.MAX_VALUE || dx < Integer.MIN_VALUE || dz > Integer.MAX_VALUE || dz < Integer.MIN_VALUE) {
|
||||||
|
sender.spigot().sendMessage(Language.getComponent("wordCoordsOutOfRange", ChatColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = (int) dx;
|
||||||
|
z = (int) dz;
|
||||||
|
|
||||||
|
encode = true;
|
||||||
|
} catch (NumberFormatException ignored) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encode) {
|
||||||
|
words = converter.encode(x, z);
|
||||||
|
String encoded = "///" + String.join(".", words);
|
||||||
|
|
||||||
|
BaseComponent[] components = new ComponentBuilder()
|
||||||
|
.append(String.format("%d, %d encodes to ", x, z))
|
||||||
|
.color(ChatColor.GRAY)
|
||||||
|
.append(encoded)
|
||||||
|
.color(ChatColor.AQUA) // TODO improve color
|
||||||
|
.event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, encoded))
|
||||||
|
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Click to copy")))
|
||||||
|
.create();
|
||||||
|
|
||||||
|
sender.spigot().sendMessage(components);
|
||||||
|
} else {
|
||||||
|
String strArgs = String.join(" ", args);
|
||||||
|
words = smartDetectWords(strArgs);
|
||||||
|
|
||||||
|
if (words.length == 0) {
|
||||||
|
sender.spigot().sendMessage(Language.getComponent("wordCoordsNoWords", ChatColor.GRAY));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int[] xz = converter.decode(words);
|
||||||
|
x = xz[0];
|
||||||
|
z = xz[1];
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
sender.spigot().sendMessage(Language.getComponent("wordCoordsInvalidWord", ChatColor.RED, e.getMessage()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String encoded = "///" + String.join(".", words);
|
||||||
|
|
||||||
|
BaseComponent[] components = new ComponentBuilder()
|
||||||
|
.append(encoded + " decodes to ")
|
||||||
|
.color(ChatColor.GRAY)
|
||||||
|
.append("%d, %d".formatted(x, z))
|
||||||
|
.color(ChatColor.AQUA) // TODO improve color
|
||||||
|
.event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, "%d, %d".formatted(x, z)))
|
||||||
|
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Click to copy")))
|
||||||
|
.append(" ±8")
|
||||||
|
.color(ChatColor.GRAY)
|
||||||
|
.create();
|
||||||
|
sender.spigot().sendMessage(components);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] smartDetectWords(String str) {
|
||||||
|
List<String> words = new ArrayList<>();
|
||||||
|
StringBuilder currentWord = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i=0; i<str.length(); i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
|
||||||
|
if (Character.isLetter(c)) {
|
||||||
|
currentWord.append(c);
|
||||||
|
} else {
|
||||||
|
if (!currentWord.isEmpty()) {
|
||||||
|
words.add(currentWord.toString());
|
||||||
|
currentWord.setLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentWord.isEmpty()) {
|
||||||
|
words.add(currentWord.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return words.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onCommand(PlayerCommandPreprocessEvent event) {
|
||||||
|
if (event.getMessage().startsWith("///")) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
event.getPlayer().performCommand("wordcoords " + event.getMessage().substring(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
src/main/java/eu/m724/tweaks/module/wordcoords/WordList.java
Normal file
63
src/main/java/eu/m724/tweaks/module/wordcoords/WordList.java
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.wordcoords;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WordList {
|
||||||
|
private final List<String> wordList;
|
||||||
|
private final int bitsPerWord;
|
||||||
|
|
||||||
|
public WordList(List<String> words) {
|
||||||
|
this.wordList = words;
|
||||||
|
this.bitsPerWord = 32 - Integer.numberOfLeadingZeros(words.size()) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWord(int index) {
|
||||||
|
return wordList.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWordIndex(String word) {
|
||||||
|
return wordList.indexOf(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getWords(int... indexes) {
|
||||||
|
return Arrays.stream(indexes)
|
||||||
|
.mapToObj(this::getWord)
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getIndexes(String... words) {
|
||||||
|
return Arrays.stream(words)
|
||||||
|
.mapToInt(wordList::indexOf)
|
||||||
|
.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWordCount() {
|
||||||
|
return wordList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBitsPerWord() {
|
||||||
|
return bitsPerWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WordList fromFile(Path path) throws IOException {
|
||||||
|
try (var lines = Files.lines(path)) {
|
||||||
|
var list = lines.filter(s -> !s.isBlank())
|
||||||
|
.map(String::toLowerCase)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return new WordList(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.wordcoords.converter;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.wordcoords.WordList;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class Decoder {
|
||||||
|
private final WordList wordList;
|
||||||
|
private final int bitsPerWord;
|
||||||
|
|
||||||
|
public Decoder(WordList wordList) {
|
||||||
|
this.wordList = wordList;
|
||||||
|
this.bitsPerWord = wordList.getBitsPerWord();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] decode(String[] words) throws NoSuchElementException {
|
||||||
|
int[] wordIndexes = new int[words.length];
|
||||||
|
|
||||||
|
for (int i=0; i<words.length; i++) {
|
||||||
|
wordIndexes[i] = wordList.getWordIndex(words[i]);
|
||||||
|
if (wordIndexes[i] == -1)
|
||||||
|
throw new NoSuchElementException(words[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return decode(wordIndexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] decode(int[] wordIndexes) {
|
||||||
|
DebugLogger.finer("Decoding word indexes: %s", Arrays.toString(wordIndexes));
|
||||||
|
|
||||||
|
int bitsRequired = wordIndexes.length * wordList.getBitsPerWord();
|
||||||
|
int bitsRequiredPerCoordinate = bitsRequired / 2;
|
||||||
|
DebugLogger.finer("Bits required: %d (per coord: %d)", bitsRequired, bitsRequiredPerCoordinate);
|
||||||
|
|
||||||
|
|
||||||
|
long combinedValue = wordIndexesToCombinedValue(wordIndexes);
|
||||||
|
DebugLogger.finer("Combined value: %d", combinedValue);
|
||||||
|
|
||||||
|
|
||||||
|
int[] decodedCoords = decodeCoords(combinedValue, bitsRequiredPerCoordinate);
|
||||||
|
int chunkX = decodedCoords[0];
|
||||||
|
int chunkZ = decodedCoords[1];
|
||||||
|
DebugLogger.finer("Chunk: %d, %d", chunkX, chunkZ);
|
||||||
|
|
||||||
|
// +8 to make it center of chunk
|
||||||
|
int xCoord = chunkX * 16 + 8;
|
||||||
|
int zCoord = chunkZ * 16 + 8;
|
||||||
|
DebugLogger.finer("Decoded to coordinates: %d, %d", xCoord, zCoord);
|
||||||
|
|
||||||
|
return new int[] { xCoord, zCoord };
|
||||||
|
}
|
||||||
|
|
||||||
|
private long wordIndexesToCombinedValue(int[] wordIndexes) {
|
||||||
|
long combinedValue = 0;
|
||||||
|
|
||||||
|
for (int i=0; i<wordIndexes.length; i++) {
|
||||||
|
combinedValue <<= bitsPerWord;
|
||||||
|
combinedValue |= wordIndexes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return combinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] decodeCoords(long combinedValue, int bitsRequiredPerCoordinate) {
|
||||||
|
int coordinateMask = (1 << bitsRequiredPerCoordinate) - 1;
|
||||||
|
int coordinateOffset = 1 << (bitsRequiredPerCoordinate - 1);
|
||||||
|
|
||||||
|
int z = (int) (combinedValue & coordinateMask) - coordinateOffset;
|
||||||
|
int x = (int) (combinedValue >> bitsRequiredPerCoordinate) - coordinateOffset;
|
||||||
|
|
||||||
|
return new int[] { x, z };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.wordcoords.converter;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.DebugLogger;
|
||||||
|
import eu.m724.tweaks.module.wordcoords.WordList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
public class Encoder {
|
||||||
|
private final WordList wordList;
|
||||||
|
private final int bitsPerWord;
|
||||||
|
|
||||||
|
public Encoder(WordList wordList) {
|
||||||
|
this.wordList = wordList;
|
||||||
|
this.bitsPerWord = wordList.getBitsPerWord();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] encode(int xCoord, int zCoord) {
|
||||||
|
int chunkX = Math.floorDiv(xCoord, 16);
|
||||||
|
int chunkZ = Math.floorDiv(zCoord, 16);
|
||||||
|
DebugLogger.finer("Chunk: %d, %d", chunkX, chunkZ);
|
||||||
|
|
||||||
|
// Calculate minimum bits required per coordinate based on range
|
||||||
|
int bitsRequiredPerCoordinate = findBitsRequiredPerCoordinate(chunkX, chunkZ);
|
||||||
|
int minTotalBits = bitsRequiredPerCoordinate * 2;
|
||||||
|
DebugLogger.finer("Min bits required per coordinate: %d (total: %d)", bitsRequiredPerCoordinate, minTotalBits);
|
||||||
|
|
||||||
|
// Calculate words required, ensuring total bits is sufficient and even
|
||||||
|
int wordsRequired = 0;
|
||||||
|
int actualTotalBits = 0;
|
||||||
|
if (minTotalBits > 0) { // Avoid division by zero if bitsPerWord is 0, or log(0)
|
||||||
|
wordsRequired = Math.ceilDiv(minTotalBits, bitsPerWord);
|
||||||
|
actualTotalBits = wordsRequired * bitsPerWord;
|
||||||
|
// Ensure total bits is sufficient
|
||||||
|
while (actualTotalBits < minTotalBits) {
|
||||||
|
wordsRequired++;
|
||||||
|
actualTotalBits = wordsRequired * bitsPerWord;
|
||||||
|
}
|
||||||
|
} // else: coords are 0 or -1, minTotalBits=0, wordsRequired=0, actualTotalBits=0. Need special handling?
|
||||||
|
// If x/z are 0/-1, findBitsRequired returns 1, minTotalBits=2. The loop handles it.
|
||||||
|
|
||||||
|
// Final bits per coordinate based on words
|
||||||
|
bitsRequiredPerCoordinate = actualTotalBits / 2;
|
||||||
|
DebugLogger.finer("Final Words required: %d", wordsRequired);
|
||||||
|
DebugLogger.finer("Final Bits required: %d (per coord: %d)", actualTotalBits, bitsRequiredPerCoordinate);
|
||||||
|
|
||||||
|
int encodedX = encodeCoord(chunkX, bitsRequiredPerCoordinate);
|
||||||
|
int encodedZ = encodeCoord(chunkZ, bitsRequiredPerCoordinate);
|
||||||
|
DebugLogger.finer("Encoded coordinates: %d, %d", encodedX, encodedZ);
|
||||||
|
|
||||||
|
long combinedValue = ((long) encodedX << bitsRequiredPerCoordinate) | encodedZ;
|
||||||
|
DebugLogger.finer("Combined value: %d", combinedValue);
|
||||||
|
|
||||||
|
int[] wordIndexes = combinedValueToWordIndexes(combinedValue, wordsRequired);
|
||||||
|
DebugLogger.finer("Word indexes: %s", Arrays.toString(wordIndexes));
|
||||||
|
|
||||||
|
return wordList.getWords(wordIndexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the minimum number of bits required to represent the coordinate
|
||||||
|
// using the encoding scheme (offset + coord) & mask, such that the coordinate
|
||||||
|
// fits within the range [-(1 << (bits - 1)), (1 << (bits - 1)) - 1].
|
||||||
|
private int findBitsRequiredPerCoordinate(int x, int z) {
|
||||||
|
int maxVal = Math.max(x, z);
|
||||||
|
int minVal = Math.min(x, z);
|
||||||
|
|
||||||
|
// Determine the required positive magnitude for the encoding range's positive side.
|
||||||
|
// We need `(1 << (bits - 1)) >= max(maxVal + 1, -minVal)`
|
||||||
|
int requiredPositiveMagnitude = Math.max(maxVal + 1, -minVal);
|
||||||
|
|
||||||
|
if (requiredPositiveMagnitude <= 0) {
|
||||||
|
// Occurs only if maxVal <= -1 and minVal >= 0, which is impossible,
|
||||||
|
// OR maxVal <= 0 and -minVal <= 0 => maxVal <= 0 and minVal >= 0.
|
||||||
|
// This means x and z are both 0.
|
||||||
|
// The range for 1 bit is [-1, 0]. If coords are 0, 1 bit is not enough for offset+coord.
|
||||||
|
// Example: bits=1. offset=1<<0=1. mask=(1<<1)-1=1.
|
||||||
|
// encodeCoord(0, 1) = (1+0)&1 = 1.
|
||||||
|
// decodeCoord(1, 1): val=1. mask=1. offset=1. (1&1)-1 = 0. Correct.
|
||||||
|
// What if we need to represent -1? encodeCoord(-1, 1) = (1-1)&1 = 0.
|
||||||
|
// decodeCoord(0, 1): val=0. (0&1)-1 = -1. Correct.
|
||||||
|
// So 1 bit works for range [-1, 0]. Let's check the condition:
|
||||||
|
// x=0, z=0 -> maxVal=0, minVal=0. reqPosMag = max(1, 0) = 1.
|
||||||
|
// x=-1, z=-1 -> maxVal=-1, minVal=-1. reqPosMag = max(0, 1) = 1.
|
||||||
|
// x=0, z=-1 -> maxVal=0, minVal=-1. reqPosMag = max(1, 1) = 1.
|
||||||
|
// So requiredPositiveMagnitude is 1 for the range [-1, 0].
|
||||||
|
requiredPositiveMagnitude = 1; // Ensure it's at least 1 if coords are 0 or -1.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate p = bits - 1
|
||||||
|
// We need the smallest integer p such that (1 << p) >= requiredPositiveMagnitude.
|
||||||
|
// If requiredPositiveMagnitude = 1, we need 1 << p >= 1, smallest p is 0.
|
||||||
|
// If requiredPositiveMagnitude > 1, this is equivalent to finding the number of bits
|
||||||
|
// needed to represent (requiredPositiveMagnitude - 1) in binary.
|
||||||
|
int p;
|
||||||
|
if (requiredPositiveMagnitude == 1) {
|
||||||
|
p = 0;
|
||||||
|
} else {
|
||||||
|
p = 32 - Integer.numberOfLeadingZeros(requiredPositiveMagnitude - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bits = p + 1
|
||||||
|
return p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int encodeCoord(int coord, int bitsRequiredPerCoordinate) {
|
||||||
|
// Bitmask and offset for positive integer conversion
|
||||||
|
int coordinateMask = (1 << bitsRequiredPerCoordinate) - 1;
|
||||||
|
int coordinateOffset = 1 << (bitsRequiredPerCoordinate - 1);
|
||||||
|
|
||||||
|
// Encode coordinates with offset into positive range
|
||||||
|
return (coordinateOffset + coord) & coordinateMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] combinedValueToWordIndexes(long combinedValue, int wordsRequired) {
|
||||||
|
int bitsRequired = wordsRequired * bitsPerWord;
|
||||||
|
|
||||||
|
// Break into word indexes
|
||||||
|
int[] wordIndexes = new int[wordsRequired];
|
||||||
|
int currentIndex = wordsRequired; // Start filling from end of array
|
||||||
|
|
||||||
|
for (int remainingBits = bitsRequired; remainingBits > 0; remainingBits -= bitsPerWord) {
|
||||||
|
int wordMask = (1 << bitsPerWord) - 1;
|
||||||
|
wordIndexes[--currentIndex] = (int) (combinedValue & wordMask);
|
||||||
|
combinedValue >>= bitsPerWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wordIndexes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,25 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Minecon724
|
* Copyright (C) 2025 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.worldborder;
|
package eu.m724.tweaks.module.worldborder;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_21_R3.CraftWorld;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.world.WorldLoadEvent;
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class WorldBorderExpander implements Listener {
|
public class WorldBorderExpandModule extends TweaksModule implements Listener {
|
||||||
public void init(Plugin plugin) {
|
@Override
|
||||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
protected void onInit() {
|
||||||
|
registerEvents(this);
|
||||||
|
|
||||||
// because the plugin loads "post world"
|
// because the plugin loads "post world"
|
||||||
plugin.getServer().getWorlds().forEach(w -> {
|
getPlugin().getServer().getWorlds().forEach(w -> {
|
||||||
onWorldLoad(new WorldLoadEvent(w));
|
onWorldLoad(new WorldLoadEvent(w));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -33,7 +34,7 @@ public class WorldBorderExpander implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
level.getWorldBorder().setAbsoluteMaxSize(30000000);
|
level.getWorldBorder().setAbsoluteMaxSize(30000000);
|
||||||
// to align with player hitbox because player can't go beyond 30m - 1 and player's hitbox is 0.6 wide so we make it "hug" the border
|
// to align with player hitbox because player can't go beyond 30m - 1 and player's hitbox is 0.6 wide, multiply by 2 for - and +, that's 1.2 and 60000000 - 1.2 = 59999998.6
|
||||||
level.getWorldBorder().setSize(59999998.6);
|
level.getWorldBorder().setSize(59999998.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.module.worldborder;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import eu.m724.tweaks.module.TweaksModule;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class WorldBorderHideModule extends TweaksModule {
|
||||||
|
private static final int EXTENSION_RADIUS = 512;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInit() {
|
||||||
|
getPlugin().getServer().getMessenger().registerOutgoingPluginChannel(getPlugin(), "tweaks724:worldborder");
|
||||||
|
|
||||||
|
byte[] infoArray = ByteBuffer.allocate(4).putInt(EXTENSION_RADIUS).array();
|
||||||
|
|
||||||
|
onPacketSend(PacketType.Play.Server.INITIALIZE_BORDER, (event) -> {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
// old diameter
|
||||||
|
packet.getDoubles().write(2, packet.getDoubles().read(2) + EXTENSION_RADIUS * 2);
|
||||||
|
// new diameter
|
||||||
|
packet.getDoubles().write(3, packet.getDoubles().read(3) + EXTENSION_RADIUS * 2);
|
||||||
|
|
||||||
|
// border radius
|
||||||
|
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
||||||
|
// warning distance
|
||||||
|
packet.getIntegers().write(1, packet.getIntegers().read(1) + EXTENSION_RADIUS);
|
||||||
|
|
||||||
|
event.getPlayer().sendPluginMessage(getPlugin(), "tweaks724:worldborder", infoArray);
|
||||||
|
});
|
||||||
|
|
||||||
|
onPacketSend(PacketType.Play.Server.SET_BORDER_SIZE, (event) -> {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
// diameter
|
||||||
|
packet.getDoubles().write(0, packet.getDoubles().read(0) + EXTENSION_RADIUS * 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
onPacketSend(PacketType.Play.Server.SET_BORDER_WARNING_DISTANCE, (event) -> {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
// warning distance
|
||||||
|
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,125 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.motd;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.*;
|
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
|
||||||
import eu.m724.tweaks.TweaksPlugin;
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
|
||||||
import net.minecraft.SharedConstants;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.protocol.status.ServerStatus;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
public class MotdManager {
|
|
||||||
private final TweaksPlugin plugin;
|
|
||||||
|
|
||||||
private Component[] motds;
|
|
||||||
|
|
||||||
public MotdManager(TweaksPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
// TODO adding more MOTD features would require checking whether to enable set
|
|
||||||
|
|
||||||
String motdSetName = TweaksConfig.getConfig().motdSet();
|
|
||||||
String motdSetPath = "motd sets/" + motdSetName + ".txt";
|
|
||||||
File motdSetsFile = new File(plugin.getDataFolder(), motdSetPath);
|
|
||||||
|
|
||||||
// create "motd sets" directory
|
|
||||||
motdSetsFile.getParentFile().mkdirs();
|
|
||||||
|
|
||||||
// if this is a builtin set
|
|
||||||
if (!motdSetsFile.exists() && plugin.hasResource(motdSetPath))
|
|
||||||
plugin.saveResource(motdSetPath, false);
|
|
||||||
|
|
||||||
if (!motdSetsFile.exists()) {
|
|
||||||
throw new RuntimeException("MOTD set \"%s\" doesn't exist".formatted(motdSetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
String fileContent = null;
|
|
||||||
try {
|
|
||||||
fileContent = Files.readString(motdSetsFile.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Reading motd set", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MOTDs are split with an empty line
|
|
||||||
motds = Arrays.stream(fileContent.split("\n\n"))
|
|
||||||
.map(entry -> {
|
|
||||||
entry = entry.strip();
|
|
||||||
JsonElement json = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
json = JsonParser.parseString(entry);
|
|
||||||
DebugLogger.fine("JSON line: " + entry);
|
|
||||||
} catch (JsonParseException e) {
|
|
||||||
DebugLogger.fine("Not a JSON line: " + entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json == null) {
|
|
||||||
json = ComponentSerializer.toJson(TextComponent.fromLegacy(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Component.Serializer.fromJson(json, RegistryAccess.EMPTY);
|
|
||||||
})
|
|
||||||
.toArray(Component[]::new);
|
|
||||||
|
|
||||||
registerListener(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerListener(Plugin plugin) {
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
|
||||||
plugin,
|
|
||||||
ListenerPriority.NORMAL,
|
|
||||||
PacketType.Status.Server.SERVER_INFO
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
|
|
||||||
Component motd = motds[ThreadLocalRandom.current().nextInt(motds.length)];
|
|
||||||
|
|
||||||
ServerStatus serverStatus = (ServerStatus) packet.getStructures().read(0).getHandle();
|
|
||||||
|
|
||||||
/* this:
|
|
||||||
* removes server mod prefix (Paper, Spigot, any brand)
|
|
||||||
* hides players
|
|
||||||
*/
|
|
||||||
ServerStatus newStatus = new ServerStatus(
|
|
||||||
motd,
|
|
||||||
Optional.empty(),
|
|
||||||
Optional.of(new ServerStatus.Version(
|
|
||||||
SharedConstants.getCurrentVersion().getName(),
|
|
||||||
SharedConstants.getProtocolVersion()
|
|
||||||
)),
|
|
||||||
serverStatus.favicon(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
packet.getStructures().write(0, new InternalStructure(newStatus, new StructureModifier<>(ServerStatus.class)));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
|
||||||
|
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class PomodoroManager {
|
|
||||||
private final Plugin plugin;
|
|
||||||
|
|
||||||
public PomodoroManager(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(PluginCommand pomodoroCommand) {
|
|
||||||
plugin.getServer().getPluginManager().registerEvents(new PomodoroListener(), plugin);
|
|
||||||
new PomodoroRunnable(plugin).runTaskTimerAsynchronously(plugin, 0, 20L);
|
|
||||||
|
|
||||||
pomodoroCommand.setExecutor(new PomodoroCommands());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.sleep;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class SleepManager {
|
|
||||||
public void init(Plugin plugin) {
|
|
||||||
plugin.getServer().getPluginManager().registerEvents(new SleepListener(), plugin);
|
|
||||||
if (!TweaksConfig.getConfig().sleepInstant())
|
|
||||||
new TimeForwardRunnable(plugin).runTaskTimer(plugin, 0, 1); // TODO maybe not
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.sleep;
|
|
||||||
|
|
||||||
import org.bukkit.GameRule;
|
|
||||||
import org.bukkit.Server;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
|
||||||
|
|
||||||
public class TimeForwardRunnable extends BukkitRunnable {
|
|
||||||
private final Server server;
|
|
||||||
private final World world; // TODO multi worlds
|
|
||||||
|
|
||||||
private final double percentage;
|
|
||||||
|
|
||||||
public TimeForwardRunnable(Plugin plugin) {
|
|
||||||
this.server = plugin.getServer();
|
|
||||||
this.world = server.getWorld("world");
|
|
||||||
this.percentage = (world.getGameRuleValue(GameRule.PLAYERS_SLEEPING_PERCENTAGE) / 100.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
int playersSleeping = SleepState.playersSleeping;
|
|
||||||
//System.out.println(playersSleeping);
|
|
||||||
if (playersSleeping == 0) return;
|
|
||||||
|
|
||||||
int onlinePlayers = (int) (server.getOnlinePlayers().size() / percentage); // TODO optimize remove size every tick maybe
|
|
||||||
|
|
||||||
double sleepPercentage = (double) playersSleeping / onlinePlayers;
|
|
||||||
|
|
||||||
// we want sleep to take 200 ticks which is 10 seconds assuming all palyres onilien
|
|
||||||
|
|
||||||
long time = world.getTime();
|
|
||||||
long untilDay = 23459 - time;
|
|
||||||
|
|
||||||
if (untilDay == 0) return;
|
|
||||||
|
|
||||||
long perSkip = 200 + (100000 / -untilDay);
|
|
||||||
perSkip = Math.clamp(perSkip, 20, 200);
|
|
||||||
perSkip = (long) (perSkip * sleepPercentage);
|
|
||||||
|
|
||||||
world.setTime(world.getTime() + perSkip);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class PluginScanner {
|
|
||||||
private final Plugin thisPlugin;
|
|
||||||
|
|
||||||
PluginScanner(Plugin thisPlugin) {
|
|
||||||
this.thisPlugin = thisPlugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<SpigotResource> load() throws IOException {
|
|
||||||
File installedPluginsYml = new File(thisPlugin.getDataFolder(), "installed_plugins.yml");
|
|
||||||
|
|
||||||
if (!installedPluginsYml.exists()) {
|
|
||||||
thisPlugin.saveResource("installed_plugins.yml", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(installedPluginsYml);
|
|
||||||
|
|
||||||
|
|
||||||
Plugin[] plugins = thisPlugin.getServer().getPluginManager().getPlugins();
|
|
||||||
Set<SpigotResource> spigotResources = new HashSet<>();
|
|
||||||
|
|
||||||
for (Plugin plugin : plugins) {
|
|
||||||
String pluginName = plugin.getName();
|
|
||||||
|
|
||||||
if (!configuration.isSet(pluginName)) {
|
|
||||||
configuration.set(pluginName, -1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pluginId = configuration.getInt(pluginName);
|
|
||||||
if (pluginId > 0) {
|
|
||||||
spigotResources.add(
|
|
||||||
new SpigotResource(plugin, pluginId, pluginName)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration.save(installedPluginsYml);
|
|
||||||
|
|
||||||
return spigotResources;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
|
||||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
|
||||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class UpdaterManager {
|
|
||||||
static File cacheFile;
|
|
||||||
|
|
||||||
private final Plugin plugin;
|
|
||||||
|
|
||||||
public UpdaterManager(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
cacheFile = new File(plugin.getDataFolder(), "storage/cache/updater");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(PluginCommand updatesCommand){
|
|
||||||
// scan installed plugins
|
|
||||||
Set<SpigotResource> resources = null;
|
|
||||||
try {
|
|
||||||
resources = new PluginScanner(plugin).load();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Loading plugins", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
cacheFile.getParentFile().mkdirs(); // TODO move this somewhere else
|
|
||||||
|
|
||||||
// load installed versions from cache
|
|
||||||
Set<ResourceVersion> installedVersions;
|
|
||||||
try (FileInputStream inputStream = new FileInputStream(cacheFile)) {
|
|
||||||
installedVersions = VersionCheckCache.loadAll(inputStream);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
installedVersions = new HashSet<>();
|
|
||||||
} catch (IOException e) {
|
|
||||||
DebugLogger.warning("Error loading installed version cache, starting fresh. " + e.getMessage());
|
|
||||||
installedVersions = new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
final Set<ResourceVersion> ivf = installedVersions;
|
|
||||||
Set<VersionedResource> versionedResources = resources.stream()
|
|
||||||
.map(res -> new VersionedResource(
|
|
||||||
res, ivf.stream().filter(iv -> iv.resourceId() == res.resourceId()).findFirst().orElse(null), null
|
|
||||||
)).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
|
|
||||||
new UpdateChecker(versionedResources)
|
|
||||||
.runTaskTimerAsynchronously(plugin, 600, 12 * 3600 * 20);
|
|
||||||
|
|
||||||
updatesCommand.setExecutor(new UpdaterCommands());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.worldborder;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.ListenerPriority;
|
|
||||||
import com.comphenix.protocol.events.PacketAdapter;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class WorldBorderHider {
|
|
||||||
private static final int EXTENSION_RADIUS = 512;
|
|
||||||
|
|
||||||
public void init(Plugin plugin) {
|
|
||||||
plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, "tweaks724:worldborder");
|
|
||||||
byte[] infoArray = ByteBuffer.allocate(4).putInt(EXTENSION_RADIUS).array();
|
|
||||||
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
|
||||||
plugin,
|
|
||||||
ListenerPriority.NORMAL,
|
|
||||||
PacketType.Play.Server.INITIALIZE_BORDER
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
// old diameter
|
|
||||||
packet.getDoubles().write(2, packet.getDoubles().read(2) + EXTENSION_RADIUS * 2);
|
|
||||||
// new diameter
|
|
||||||
packet.getDoubles().write(3, packet.getDoubles().read(3) + EXTENSION_RADIUS * 2);
|
|
||||||
|
|
||||||
// border radius
|
|
||||||
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
|
||||||
// warning distance
|
|
||||||
packet.getIntegers().write(1, packet.getIntegers().read(1) + EXTENSION_RADIUS);
|
|
||||||
|
|
||||||
event.getPlayer().sendPluginMessage(plugin, "tweaks724:worldborder", infoArray);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
|
||||||
plugin,
|
|
||||||
ListenerPriority.NORMAL,
|
|
||||||
PacketType.Play.Server.SET_BORDER_SIZE
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
// diameter
|
|
||||||
packet.getDoubles().write(0, packet.getDoubles().read(0) + EXTENSION_RADIUS * 2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
|
||||||
plugin,
|
|
||||||
ListenerPriority.NORMAL,
|
|
||||||
PacketType.Play.Server.SET_BORDER_WARNING_DISTANCE
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
// warning distance
|
|
||||||
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@
|
||||||
# - https://discord.gg/86X4Z5JUeq
|
# - https://discord.gg/86X4Z5JUeq
|
||||||
# - https://www.spigotmc.org/threads/tweaks724.670906/
|
# - https://www.spigotmc.org/threads/tweaks724.670906/
|
||||||
|
|
||||||
# Metrics toggle. Ideally opt-in, but the system is very new and it needs testing.
|
# Metrics toggle. Please keep this on.
|
||||||
metrics: true
|
metrics: true
|
||||||
|
|
||||||
# Warning: Don't use /worldborder while this is on
|
# Warning: Don't use /worldborder while this is on
|
||||||
|
@ -36,9 +36,9 @@ doors:
|
||||||
knocking: true
|
knocking: true
|
||||||
|
|
||||||
motd:
|
motd:
|
||||||
|
enabled: true
|
||||||
# Name of the set containing the MOTDs
|
# Name of the set containing the MOTDs
|
||||||
# (random displayed every ping)
|
# (random displayed every ping)
|
||||||
# "" or false to disable
|
|
||||||
set: "example"
|
set: "example"
|
||||||
|
|
||||||
chat:
|
chat:
|
||||||
|
@ -81,8 +81,10 @@ hardcore:
|
||||||
# 0.0 - 1.0 decimal. This is if you want to make it like an Easter egg
|
# 0.0 - 1.0 decimal. This is if you want to make it like an Easter egg
|
||||||
chance: 1.0
|
chance: 1.0
|
||||||
|
|
||||||
# Makes sleeping
|
# Sleep tweaks
|
||||||
# And adds a nice animation
|
# Percentage: playersSleepingPercentage gamerule
|
||||||
|
# If instant: how much % of players to skip the night
|
||||||
|
# If not: how much % make skipping full speed
|
||||||
sleep:
|
sleep:
|
||||||
enabled: true
|
enabled: true
|
||||||
# This gives every player a "share" of the night
|
# This gives every player a "share" of the night
|
||||||
|
@ -90,9 +92,8 @@ sleep:
|
||||||
# For example, if 5 players online and night is 5 minutes, one can go to sleep and skip 1 minute of the night
|
# For example, if 5 players online and night is 5 minutes, one can go to sleep and skip 1 minute of the night
|
||||||
# Leaving the bed and reentering it does nothing
|
# Leaving the bed and reentering it does nothing
|
||||||
instant: false
|
instant: false
|
||||||
# Percentage: playersSleepingPercentage gamerule
|
# How many hearts to heal after sleeping
|
||||||
# If instant: how much % of players to skip the night
|
heal: 2.0
|
||||||
# If not: how much % make skipping full speed
|
|
||||||
|
|
||||||
# "Hostname" authentication
|
# "Hostname" authentication
|
||||||
# This makes a player need to join a unique hostname like "asd123.example.com" where "asd123" is the key
|
# This makes a player need to join a unique hostname like "asd123.example.com" where "asd123" is the key
|
||||||
|
@ -126,6 +127,12 @@ killswitch:
|
||||||
# To disable HTTP server, set to null
|
# To disable HTTP server, set to null
|
||||||
listen: 127.0.0.1:57932
|
listen: 127.0.0.1:57932
|
||||||
|
|
||||||
|
# Swing through grass (and alike)
|
||||||
|
# If using sword, you can also hit behind the grass
|
||||||
|
# If not, you can only hit the entity in the grass
|
||||||
|
swing:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
|
||||||
# Finally, thank you for downloading Tweaks724, I hope you enjoy!
|
# Finally, thank you for downloading Tweaks724, I hope you enjoy!
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ api-version: 1.21.1
|
||||||
softdepend: [ProtocolLib]
|
softdepend: [ProtocolLib]
|
||||||
|
|
||||||
libraries:
|
libraries:
|
||||||
- eu.m724:mstats-spigot:0.1.0
|
- eu.m724:mstats-spigot:0.1.2
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
chat:
|
chat:
|
||||||
|
@ -40,22 +40,36 @@ commands:
|
||||||
servkill:
|
servkill:
|
||||||
description: Immediately stop the server
|
description: Immediately stop the server
|
||||||
permission: tweaks724.servkill
|
permission: tweaks724.servkill
|
||||||
|
durabilityalert:
|
||||||
|
description: Durability alert toggle
|
||||||
|
permission: tweaks724.durabilityalert
|
||||||
|
wordcoords:
|
||||||
|
description: Word to coords conversion
|
||||||
|
permission: tweaks724.wordcoords
|
||||||
|
aliases: [woco, wc, w3w]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
tweaks724:
|
tweaks724.chatmanage:
|
||||||
chatmanage:
|
default: true
|
||||||
default: true
|
tweaks724.pomodoro:
|
||||||
pomodoro:
|
default: true
|
||||||
default: true
|
tweaks724.updates:
|
||||||
updates:
|
default: op
|
||||||
default: op
|
tweaks724.tauth:
|
||||||
tauth:
|
default: op
|
||||||
default: op
|
tweaks724.bypass-full:
|
||||||
bypass-full:
|
default: op
|
||||||
default: op
|
tweaks724.emergencyalert:
|
||||||
emergencyalert:
|
default: op
|
||||||
default: op
|
tweaks724.retstone:
|
||||||
retstone:
|
default: op
|
||||||
default: op
|
tweaks724.servkill:
|
||||||
servkill:
|
default: false
|
||||||
default: false
|
tweaks724.durabilityalert:
|
||||||
|
default: true
|
||||||
|
tweaks724.wordcoords:
|
||||||
|
default: true
|
||||||
|
|
||||||
|
7weaks724.ignore.this:
|
||||||
|
description: "Internal, not for use. ${project.spigot.version}"
|
||||||
|
default: false
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (C) 2024 Minecon724
|
# Copyright (C) 2025 Minecon724
|
||||||
# Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
# Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
# in the project root for the full license text.
|
# in the project root for the full license text.
|
||||||
#
|
#
|
||||||
|
@ -13,23 +13,35 @@ languageEnglish = English
|
||||||
updateAvailableNotice = Available updates (%d):
|
updateAvailableNotice = Available updates (%d):
|
||||||
|
|
||||||
# Used in /updates
|
# Used in /updates
|
||||||
updatesNotChecked = Not checked yet
|
updatesNotChecked = Not checked yet.
|
||||||
# %s is time as HH:mm
|
# %s is time as HH:mm
|
||||||
updatesNoUpdates = No available updates. Last checked: %s
|
updatesNoUpdates = No available updates. Last checked: %s
|
||||||
# %s is update title
|
# %s is update title
|
||||||
updatesClickToOpen = Click to open on SpigotMC "%s"
|
updatesClickToOpen = Click to open on SpigotMC "%s"
|
||||||
|
|
||||||
# Used in /chat
|
# Used in /chat
|
||||||
chatPasswordProtected = This room is password protected
|
chatPasswordProtected = This room is password protected.
|
||||||
chatWrongPassword = Wrong password
|
chatWrongPassword = Wrong password.
|
||||||
chatNoSuchRoom = No room named %s
|
chatNoSuchRoom = Room %s doesn't exist.
|
||||||
chatAlreadyHere = You're already in this room
|
chatNoSuchRoomInvalidId = Room %s doesn't exist, because the ID is invalid.
|
||||||
|
chatAlreadyHere = You're already in this room.
|
||||||
|
|
||||||
# Used when a player joins using the wrong key or no key
|
# Used when a player joins using the wrong key or no key
|
||||||
authKickWrongKey = You're connecting to the wrong server address. You must connect to the one you're registered to.
|
authKickWrongKey = You're connecting to the wrong server address. You must connect to the one you're registered to.
|
||||||
# If force is enabled and player is not registered. Changing this reveals you're using this plugin
|
# If force is enabled and player is not registered. Changing this reveals you're using this plugin
|
||||||
authKickUnregistered = You are not whitelisted on this server!
|
authKickUnregistered = You are not whitelisted on this server!
|
||||||
|
authKickError = An error occured. Please try again. If this persists, contact an administrator.
|
||||||
|
|
||||||
redstoneGatewayItem = Redstone gateway
|
redstoneGatewayItem = Redstone gateway
|
||||||
|
|
||||||
clickToCopy = Click to copy to clipboard
|
clickToCopy = Click to copy to clipboard
|
||||||
|
clickToExecuteCommand = Click to execute command
|
||||||
|
|
||||||
|
durabilityEnabled = Enabled durability alert
|
||||||
|
durabilityDisabled = Disabled durability alert
|
||||||
|
|
||||||
|
# When console executes /wordcoords without arguments
|
||||||
|
wordCoordsPlayerOnly = Only players can execute this command without arguments.
|
||||||
|
wordCoordsOutOfRange = Those coordinates are invalid.
|
||||||
|
wordCoordsInvalidWord = Invalid word: "%s"
|
||||||
|
wordCoordsNoWords = Please provide the Z coordinate.
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (C) 2024 Minecon724
|
# Copyright (C) 2025 Minecon724
|
||||||
# Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
# Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
# in the project root for the full license text.
|
# in the project root for the full license text.
|
||||||
#
|
#
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue