forked from SteamWar/SteamWar
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de4f32feb2 | ||
|
|
a3d2d2be1e | ||
|
|
7a000efb93 | ||
|
|
42c9d6d612 | ||
|
|
67c679a20f | ||
|
|
a071d8a1f2 | ||
|
|
7b25bd31fc | ||
|
|
139a2c275c | ||
|
|
aa787b5a25 | ||
|
|
54adc12045 |
@@ -1,60 +0,0 @@
|
|||||||
name: Bug Report
|
|
||||||
about: Du hast einen Fehler gefunden? Melde ihn hier!
|
|
||||||
labels: [ "typ/bug" ]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
ACHTUNG: Sollte es bei dem Bug ein Sicherheitsrisiko geben, melde es bitte auf unserem Discord Server
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: |
|
|
||||||
Beschreibe deinen Bug in kurzer Form.
|
|
||||||
- type: input
|
|
||||||
id: mc-ver
|
|
||||||
attributes:
|
|
||||||
label: Minecraft Version
|
|
||||||
description: Minecraft Version des Clients
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
id: mc-ver-ser
|
|
||||||
attributes:
|
|
||||||
label: Minecraft Version Server
|
|
||||||
description: Minecraft Version des Servers, nur bei Bau oder Arenen Servern
|
|
||||||
- type: dropdown
|
|
||||||
id: can-reproduce
|
|
||||||
attributes:
|
|
||||||
label: Kannst du den Fehler wiederholen?
|
|
||||||
description: |
|
|
||||||
Wenn du den Fehler wiederholen kannst, können wir dieses Problem schneller beheben.
|
|
||||||
Solltest du den Fehler nicht wiederholen können, melde dich bitte auf unserem Discord Server.
|
|
||||||
options:
|
|
||||||
- "Yes"
|
|
||||||
- "No"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: reproduce-steps
|
|
||||||
attributes:
|
|
||||||
label: Wie kannst du den Fehler wiederholen?
|
|
||||||
description: Welche Schritte musst du ausführen, um den Fehler wiederholen zu können?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: expected-result
|
|
||||||
attributes:
|
|
||||||
label: Was sollte passieren?
|
|
||||||
description: Was sollte hier deiner Erwartung nach passieren?
|
|
||||||
- type: input
|
|
||||||
id: logs
|
|
||||||
attributes:
|
|
||||||
label: Auf welchem Server ist der Fehler aufgetreten?
|
|
||||||
description: Gebe bitte den Namen des Servers an, auf dem der Fehler aufgetreten ist. z.B. "Lobby", "Lixfels Bauserver" etc.
|
|
||||||
- type: textarea
|
|
||||||
id: screenshots
|
|
||||||
attributes:
|
|
||||||
label: Screenshots
|
|
||||||
description: Sollte es ein Visuelles Problem geben, kannst du hier Screenshots hinzufügen.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
blank_issues_enabled: true
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
name: Feature Idee
|
|
||||||
about: Du hast eine Idee für ein neues Feature, welches SteamWar nicht hat? Stelle sie hier vor.
|
|
||||||
labels: [ "typ/idee" ]
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: Feature Beschreibung
|
|
||||||
placeholder: |
|
|
||||||
Ich glaube, dass ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: screenshots
|
|
||||||
attributes:
|
|
||||||
label: Screenshots
|
|
||||||
description: Wenn es sich um etwas grafisches handelt, kannst du hier Screenshots hinzufügen.
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
name: Backport CommonCore
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
BACKPORT_PATH: CommonCore
|
|
||||||
BACKPORT_BRANCH_PREFIX: backport/commoncore
|
|
||||||
DISABLE_BACKPORT_LABEL: no-backport
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
backport:
|
|
||||||
name: Create CommonCore backport PRs
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout sources
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Check backport eligibility
|
|
||||||
id: eligibility
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
|
|
||||||
|
|
||||||
echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
|
|
||||||
echo "Backport debug: server=${GITHUB_SERVER_URL}"
|
|
||||||
echo "Backport debug: api=${api_url}"
|
|
||||||
echo "Backport debug: repository=${GITHUB_REPOSITORY}"
|
|
||||||
echo "Backport debug: action=$(jq -r '.action // ""' "$GITHUB_EVENT_PATH")"
|
|
||||||
|
|
||||||
merged="$(jq -r '.pull_request.merged // (.pull_request.merged_at != null)' "$GITHUB_EVENT_PATH")"
|
|
||||||
base_branch="$(jq -r '.pull_request.base.ref' "$GITHUB_EVENT_PATH")"
|
|
||||||
has_disable_label="$(jq -r --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.pull_request.labels[]?; .name == $disable_backport_label)' "$GITHUB_EVENT_PATH")"
|
|
||||||
echo "Backport debug: pr=$(jq -r '.pull_request.number // ""' "$GITHUB_EVENT_PATH") base=${base_branch} merged=${merged}"
|
|
||||||
echo "Backport debug: disable label present=${has_disable_label}"
|
|
||||||
|
|
||||||
{
|
|
||||||
echo "should_backport=$([[ "$merged" == "true" && "$base_branch" == "main" && "$has_disable_label" != "true" ]] && echo true || echo false)"
|
|
||||||
echo "pr_number=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")"
|
|
||||||
echo "pr_title<<EOF"
|
|
||||||
jq -r '.pull_request.title' "$GITHUB_EVENT_PATH"
|
|
||||||
echo "EOF"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
labels="$(curl -fsS \
|
|
||||||
-H "Accept: application/json" \
|
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
"${api_url}/repos/${GITHUB_REPOSITORY}/labels")"
|
|
||||||
|
|
||||||
if ! jq -e --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.[]; .name == $disable_backport_label)' <<< "$labels" >/dev/null; then
|
|
||||||
curl -fsS -X POST \
|
|
||||||
-H "Accept: application/json" \
|
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "$(jq -n --arg name "$DISABLE_BACKPORT_LABEL" --arg color "ededed" --arg description "Disable automatic CommonCore backporting for this pull request." '{name: $name, color: $color, description: $description}')" \
|
|
||||||
"${api_url}/repos/${GITHUB_REPOSITORY}/labels"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create backport pull requests
|
|
||||||
if: steps.eligibility.outputs.should_backport == 'true'
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
|
|
||||||
PR_NUMBER: ${{ steps.eligibility.outputs.pr_number }}
|
|
||||||
PR_TITLE: ${{ steps.eligibility.outputs.pr_title }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
|
|
||||||
repo_api_path="/repos/${GITHUB_REPOSITORY}"
|
|
||||||
|
|
||||||
api_request() {
|
|
||||||
local method="$1"
|
|
||||||
local path="$2"
|
|
||||||
local output="$3"
|
|
||||||
local data_file="${4:-}"
|
|
||||||
local status
|
|
||||||
local args=(-sS -X "$method" -H "Accept: application/json" -H "Authorization: token ${GITHUB_TOKEN}" -w "%{http_code}" -o "$output")
|
|
||||||
|
|
||||||
if [[ -n "$data_file" ]]; then
|
|
||||||
args+=(-H "Content-Type: application/json" --data-binary "@${data_file}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Backport debug: ${method} ${path}"
|
|
||||||
if ! status="$(curl "${args[@]}" "${api_url}${path}")"; then
|
|
||||||
echo "Backport debug: ${method} ${path} failed before HTTP status was captured."
|
|
||||||
if [[ -s "$output" ]]; then
|
|
||||||
echo "Backport debug: response body:"
|
|
||||||
cat "$output"
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Backport debug: ${method} ${path} -> HTTP ${status}"
|
|
||||||
if [[ ! "$status" =~ ^2 ]]; then
|
|
||||||
echo "Backport debug: response body:"
|
|
||||||
cat "$output"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
|
|
||||||
echo "Backport debug: server=${GITHUB_SERVER_URL}"
|
|
||||||
echo "Backport debug: api=${api_url}"
|
|
||||||
echo "Backport debug: repository=${GITHUB_REPOSITORY}"
|
|
||||||
echo "Backport debug: pr=${PR_NUMBER}"
|
|
||||||
echo "Backport debug: actor=${GITHUB_ACTOR:-unknown}"
|
|
||||||
|
|
||||||
git config user.name "SteamWar Backport Bot"
|
|
||||||
git config user.email "actions@steamwar.de"
|
|
||||||
|
|
||||||
if [[ "${GITHUB_SERVER_URL}" == https://* ]]; then
|
|
||||||
auth_host="${GITHUB_SERVER_URL#https://}"
|
|
||||||
git remote set-url origin "https://oauth2:${GITHUB_TOKEN}@${auth_host}/${GITHUB_REPOSITORY}.git"
|
|
||||||
fi
|
|
||||||
|
|
||||||
git fetch --prune origin '+refs/heads/version/*:refs/remotes/origin/version/*'
|
|
||||||
|
|
||||||
api_request GET "${repo_api_path}" repo-debug.json
|
|
||||||
jq -r '"Backport debug: repo permissions admin=\(.permissions.admin // "unknown") push=\(.permissions.push // "unknown") pull=\(.permissions.pull // "unknown")"' repo-debug.json || true
|
|
||||||
|
|
||||||
echo "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff"
|
|
||||||
curl -fsSL -w "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff -> HTTP %{http_code}\n" \
|
|
||||||
-H "Accept: text/plain" \
|
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
"${api_url}${repo_api_path}/pulls/${PR_NUMBER}.diff" \
|
|
||||||
-o pull-request.diff
|
|
||||||
|
|
||||||
if ! grep -Eq "^diff --git a/${BACKPORT_PATH}/" pull-request.diff; then
|
|
||||||
echo "Pull request #${PR_NUMBER} has no ${BACKPORT_PATH} changes to backport."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
mapfile -t target_branches < <(git for-each-ref --format='%(refname:strip=3)' refs/remotes/origin/version)
|
|
||||||
if [[ "${#target_branches[@]}" -eq 0 ]]; then
|
|
||||||
echo "No version/* branches found."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
for target_branch in "${target_branches[@]}"; do
|
|
||||||
safe_target="${target_branch//\//-}"
|
|
||||||
backport_branch="${BACKPORT_BRANCH_PREFIX}/pr-${PR_NUMBER}-to-${safe_target}"
|
|
||||||
|
|
||||||
git checkout -B "${backport_branch}" "origin/${target_branch}"
|
|
||||||
git reset --hard "origin/${target_branch}"
|
|
||||||
|
|
||||||
if ! git apply --3way --index --include="${BACKPORT_PATH}/**" pull-request.diff; then
|
|
||||||
echo "Failed to apply CommonCore backport for ${target_branch}."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "CommonCore changes from #${PR_NUMBER} are already present in ${target_branch}."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
git commit -m "Backport CommonCore changes from #${PR_NUMBER}" -m "${PR_TITLE}"
|
|
||||||
git push --force-with-lease origin "${backport_branch}"
|
|
||||||
|
|
||||||
api_request GET "${repo_api_path}/pulls?state=open" open-pulls.json
|
|
||||||
open_pr_number="$(jq -r --arg base "$target_branch" --arg head "$backport_branch" '[.[] | select(.base.ref == $base and .head.ref == $head) | (.number // .index)][0] // empty' open-pulls.json)"
|
|
||||||
|
|
||||||
if [[ -n "$open_pr_number" ]]; then
|
|
||||||
echo "Backport PR #${open_pr_number} already exists for ${target_branch}."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
pr_body="$(printf 'Automatic CommonCore backport of #%s.\n\nOriginal PR title: %s\n\nOnly files below `CommonCore/` are included.' "$PR_NUMBER" "$PR_TITLE")"
|
|
||||||
|
|
||||||
jq -n \
|
|
||||||
--arg base "$target_branch" \
|
|
||||||
--arg head "$backport_branch" \
|
|
||||||
--arg title "Backport CommonCore changes from #${PR_NUMBER} to ${target_branch}" \
|
|
||||||
--arg body "$pr_body" \
|
|
||||||
'{base: $base, head: $head, title: $title, body: $body}' > create-pull.json
|
|
||||||
|
|
||||||
echo "Backport debug: create PR base=${target_branch} head=${backport_branch}"
|
|
||||||
api_request POST "${repo_api_path}/pulls" create-pull-response.json create-pull.json
|
|
||||||
done
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
name: Deploy
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- version/*
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout sources
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
- name: Setup Java 8
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 8
|
|
||||||
- name: Setup Java 11
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 11
|
|
||||||
- name: Setup Java 17
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 21
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
- name: Setup Maven Repository
|
|
||||||
env:
|
|
||||||
SW_MAVEN_CREDENTIALS: ${{ secrets.SW_MAVEN_CREDENTIALS }}
|
|
||||||
run: |
|
|
||||||
echo "$SW_MAVEN_CREDENTIALS" > steamwar.properties
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew clean build --no-daemon --no-build-cache --refresh-dependencies
|
|
||||||
|
|
||||||
- name: Stage deploy artifacts
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
rm -rf deploy
|
|
||||||
mkdir -p deploy
|
|
||||||
|
|
||||||
cp "AccessWidener/build/libs/AccessWidener-all.jar" "deploy/AccessWidener.jar"
|
|
||||||
cp "BauSystem/build/libs/BauSystem-all.jar" "deploy/BauSystem.jar"
|
|
||||||
cp "FightSystem/build/libs/FightSystem-all.jar" "deploy/FightSystem.jar"
|
|
||||||
cp "KotlinCore/build/libs/KotlinCore-all.jar" "deploy/KotlinCore.jar"
|
|
||||||
cp "TNTLeague/build/libs/TNTLeague.jar" "deploy/TNTLeague.jar"
|
|
||||||
cp "LobbySystem/build/libs/LobbySystem.jar" "deploy/LobbySystem.jar"
|
|
||||||
cp "MissileWars/build/libs/MissileWars.jar" "deploy/MissileWars.jar"
|
|
||||||
cp "Realtime/build/libs/Realtime.jar" "deploy/RealTime.jar"
|
|
||||||
cp "SchematicSystem/build/libs/SchematicSystem-all.jar" "deploy/SchematicSystem.jar"
|
|
||||||
cp "SpigotCore/build/libs/SpigotCore-all.jar" "deploy/SpigotCore.jar"
|
|
||||||
cp "Teamserver/build/libs/Teamserver.jar" "deploy/Builder.jar"
|
|
||||||
cp "TowerRun/build/libs/TowerRun.jar" "deploy/TowerRun.jar"
|
|
||||||
cp "VelocityCore/Persistent/build/libs/Persistent.jar" "deploy/PersistentVelocityCore.jar"
|
|
||||||
cp "VelocityCore/Dependencies/build/libs/Dependencies-all.jar" "deploy/DependenciesVelocityCore.jar"
|
|
||||||
cp "VelocityCore/build/libs/VelocityCore-all.jar" "deploy/VelocityCore.jar"
|
|
||||||
cp "WebsiteBackend/build/libs/WebsiteBackend-all.jar" "deploy/website-api.jar"
|
|
||||||
cp "CLI/build/distributions/sw.zip" "deploy/sw.zip"
|
|
||||||
|
|
||||||
- name: Upload deploy artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: steamwar-jars
|
|
||||||
path: deploy/
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
name: Deploy
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
steps:
|
|
||||||
- name: Download deploy artifacts
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: steamwar-jars
|
|
||||||
path: deploy
|
|
||||||
|
|
||||||
- name: Resolve deploy target
|
|
||||||
id: target
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [[ "${GITHUB_REF_NAME}" == "main" ]]; then
|
|
||||||
echo "path=/jars/current" >> "$GITHUB_OUTPUT"
|
|
||||||
elif [[ "${GITHUB_REF_NAME}" == version/* ]]; then
|
|
||||||
version="${GITHUB_REF_NAME#version/}"
|
|
||||||
if [[ ! "$version" =~ ^[A-Za-z0-9._-]+$ ]]; then
|
|
||||||
echo "Unsupported version branch name: ${GITHUB_REF_NAME}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "path=/jars/${version}" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "Unsupported deployment branch: ${GITHUB_REF_NAME}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload jars with scp
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
|
||||||
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
|
||||||
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
|
|
||||||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
|
||||||
DEPLOY_PATH: ${{ steps.target.outputs.path }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
: "${DEPLOY_HOST:?Missing DEPLOY_HOST secret}"
|
|
||||||
: "${DEPLOY_USER:?Missing DEPLOY_USER secret}"
|
|
||||||
: "${DEPLOY_SSH_KEY:?Missing DEPLOY_SSH_KEY secret}"
|
|
||||||
|
|
||||||
port="${DEPLOY_PORT:-22}"
|
|
||||||
|
|
||||||
mkdir -p ~/.ssh
|
|
||||||
chmod 700 ~/.ssh
|
|
||||||
echo "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key
|
|
||||||
chmod 600 ~/.ssh/deploy_key
|
|
||||||
ssh-keyscan -p "$port" "$DEPLOY_HOST" >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH'"
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH/upload'"
|
|
||||||
scp -i ~/.ssh/deploy_key -P "$port" deploy/* "${DEPLOY_USER}@${DEPLOY_HOST}:$DEPLOY_PATH/upload"
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -f '$DEPLOY_PATH'/*.jar '$DEPLOY_PATH'/*.zip"
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mv '$DEPLOY_PATH'/upload/* '$DEPLOY_PATH'"
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -r '$DEPLOY_PATH/upload'"
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "chmod o-w '$DEPLOY_PATH'/*"
|
|
||||||
- name: Restart Services
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
|
||||||
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
|
||||||
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
|
|
||||||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$DEPLOY_PORT" "${DEPLOY_USER}@${DEPLOY_HOST}" "sudo systemctl restart api.service"
|
|
||||||
ssh -i ~/.ssh/deploy_key -p "$DEPLOY_PORT" "${DEPLOY_USER}@${DEPLOY_HOST}" "unzip -o /jars/current/sw.zip -d /jars"
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
name: Pull Request Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout sources
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
- name: Setup Java 8
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 8
|
|
||||||
- name: Setup Java 11
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 11
|
|
||||||
- name: Setup Java 17
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 21
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
- name: Setup Maven Repository
|
|
||||||
env:
|
|
||||||
SW_MAVEN_CREDENTIALS: ${{ secrets.SW_MAVEN_CREDENTIALS }}
|
|
||||||
run: |
|
|
||||||
echo "$SW_MAVEN_CREDENTIALS" > steamwar.properties
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew build --no-daemon
|
|
||||||
|
|
||||||
- name: Merge successful backport PR
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
|
|
||||||
BACKPORT_BRANCH_PREFIX: backport/commoncore
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
head_branch="$(jq -r '.pull_request.head.ref // ""' "$GITHUB_EVENT_PATH")"
|
|
||||||
base_branch="$(jq -r '.pull_request.base.ref // ""' "$GITHUB_EVENT_PATH")"
|
|
||||||
pr_number="$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")"
|
|
||||||
|
|
||||||
if [[ "${head_branch}" != "${BACKPORT_BRANCH_PREFIX}/"* ]]; then
|
|
||||||
echo "Not a CommonCore backport PR."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${base_branch}" != version/* ]]; then
|
|
||||||
echo "Backport PR target is not a version/* branch."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
|
|
||||||
|
|
||||||
curl -fsS -X POST \
|
|
||||||
-H "Accept: application/json" \
|
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"Do":"merge","delete_branch_after_merge":true}' \
|
|
||||||
"${api_url}/repos/${GITHUB_REPOSITORY}/pulls/${pr_number}/merge"
|
|
||||||
+1
-11
@@ -8,22 +8,12 @@
|
|||||||
steamwar.properties
|
steamwar.properties
|
||||||
|
|
||||||
# IntelliJ IDEA
|
# IntelliJ IDEA
|
||||||
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
# VSCode
|
# VSCode
|
||||||
bin/
|
bin/
|
||||||
.vscode
|
.vscode
|
||||||
.settings
|
|
||||||
|
|
||||||
# Language Server
|
|
||||||
**/.project
|
|
||||||
**/.factorypath
|
|
||||||
**/.classpath
|
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
lib
|
lib
|
||||||
/WebsiteBackend/data
|
|
||||||
/WebsiteBackend/logs
|
|
||||||
/WebsiteBackend/skins
|
|
||||||
/WebsiteBackend/config.json
|
|
||||||
/WebsiteBackend/sessions
|
|
||||||
|
|||||||
Generated
-32
@@ -1,32 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
/AndroidProjectSystem.xml
|
|
||||||
/checkstyle-idea.xml
|
|
||||||
/compiler.xml
|
|
||||||
/copilot.data.migration.agent.xml
|
|
||||||
/copilot.data.migration.ask.xml
|
|
||||||
/copilot.data.migration.ask2agent.xml
|
|
||||||
/copilot.data.migration.edit.xml
|
|
||||||
/dataSources.xml
|
|
||||||
/encodings.xml
|
|
||||||
/git_toolbox_blame.xml
|
|
||||||
/git_toolbox_prj.xml
|
|
||||||
/gradle.xml
|
|
||||||
/jarRepositories.xml
|
|
||||||
/jpa.xml
|
|
||||||
/kotlinc.xml
|
|
||||||
/misc.xml
|
|
||||||
/modules.xml
|
|
||||||
/scala_compiler.xml
|
|
||||||
/swagger-settings.xml
|
|
||||||
/uiDesigner.xml
|
|
||||||
/vcs.xml
|
|
||||||
/codeStyles/
|
|
||||||
/inspectionProfiles/
|
|
||||||
/modules/
|
|
||||||
Generated
-7
@@ -1,7 +0,0 @@
|
|||||||
<component name="CopyrightManager">
|
|
||||||
<settings default="sw">
|
|
||||||
<module2copyright>
|
|
||||||
<element module="All" copyright="sw" />
|
|
||||||
</module2copyright>
|
|
||||||
</settings>
|
|
||||||
</component>
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<component name="CopyrightManager">
|
|
||||||
<copyright>
|
|
||||||
<option name="notice" value=" This file is a part of the SteamWar software. Copyright (C) &#36;today.year SteamWar.de-Serverteam This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>." />
|
|
||||||
<option name="myName" value="sw" />
|
|
||||||
</copyright>
|
|
||||||
</component>
|
|
||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Remote JVM Debugger" type="Remote">
|
|
||||||
<option name="USE_SOCKET_TRANSPORT" value="true" />
|
|
||||||
<option name="SERVER_MODE" value="false" />
|
|
||||||
<option name="SHMEM_ADDRESS" />
|
|
||||||
<option name="HOST" value="localhost" />
|
|
||||||
<option name="PORT" value="5005" />
|
|
||||||
<option name="AUTO_RESTART" value="false" />
|
|
||||||
<RunnerSettings RunnerId="Debug">
|
|
||||||
<option name="DEBUG_PORT" value="5005" />
|
|
||||||
<option name="LOCAL" value="false" />
|
|
||||||
</RunnerSettings>
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A single parsed line from a .accesswidener file.
|
|
||||||
* <p>
|
|
||||||
* Examples:
|
|
||||||
* accessible class net/minecraft/server/level/ServerPlayer
|
|
||||||
* accessible method net/minecraft/server/level/ServerPlayer getStats ()V
|
|
||||||
* mutable field net/minecraft/world/entity/Entity id I
|
|
||||||
* extendable class net/minecraft/world/level/chunk/LevelChunk
|
|
||||||
*/
|
|
||||||
public record AccessWidenerEntry(
|
|
||||||
/** accessible | mutable | extendable (may have "transitive-" prefix) */
|
|
||||||
String directive,
|
|
||||||
/** class | method | field */
|
|
||||||
String memberType,
|
|
||||||
/** Internal class name, e.g. net/minecraft/server/level/ServerPlayer */
|
|
||||||
String target,
|
|
||||||
/** Method/field name, null for class entries */
|
|
||||||
String name,
|
|
||||||
/** Descriptor, null for class entries */
|
|
||||||
String descriptor) {
|
|
||||||
/**
|
|
||||||
* Returns true if this entry targets the class with the given internal name.
|
|
||||||
*/
|
|
||||||
public boolean targets(String internalName) {
|
|
||||||
return target.equals(internalName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses Fabric-compatible .accesswidener files.
|
|
||||||
* <p>
|
|
||||||
* Supported format:
|
|
||||||
* <pre>
|
|
||||||
* accessWidener v2 named
|
|
||||||
*
|
|
||||||
* # comments are supported
|
|
||||||
* accessible class net/minecraft/Foo
|
|
||||||
* accessible method net/minecraft/Foo someMethod ()V
|
|
||||||
* accessible field net/minecraft/Foo someField I
|
|
||||||
* mutable field net/minecraft/Foo someField I
|
|
||||||
* extendable class net/minecraft/Foo
|
|
||||||
* extendable method net/minecraft/Foo someMethod ()V
|
|
||||||
*
|
|
||||||
* # transitive variants (expose widening to dependents)
|
|
||||||
* transitive-accessible class net/minecraft/Foo
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public final class AccessWidenerParser {
|
|
||||||
|
|
||||||
private AccessWidenerParser() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<AccessWidenerEntry> parse(InputStream in) throws IOException {
|
|
||||||
List<AccessWidenerEntry> entries = new ArrayList<>();
|
|
||||||
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
|
|
||||||
|
|
||||||
String line;
|
|
||||||
boolean headerSeen = false;
|
|
||||||
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
// Strip inline comments
|
|
||||||
int commentIdx = line.indexOf('#');
|
|
||||||
if (commentIdx >= 0) line = line.substring(0, commentIdx);
|
|
||||||
line = line.strip();
|
|
||||||
|
|
||||||
if (line.isEmpty()) continue;
|
|
||||||
|
|
||||||
if (!headerSeen) {
|
|
||||||
// First non-blank, non-comment line must be the header
|
|
||||||
if (!line.startsWith("accessWidener")) {
|
|
||||||
throw new IOException("Missing accessWidener header, got: " + line);
|
|
||||||
}
|
|
||||||
headerSeen = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessWidenerEntry entry = parseLine(line);
|
|
||||||
if (entry != null) entries.add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AccessWidenerEntry parseLine(String line) {
|
|
||||||
String[] parts = line.split("\\s+");
|
|
||||||
if (parts.length < 3) return null;
|
|
||||||
|
|
||||||
String directive = parts[0]; // accessible / mutable / extendable / transitive-*
|
|
||||||
String memberType = parts[1]; // class / method / field
|
|
||||||
String target = parts[2]; // internal class name
|
|
||||||
|
|
||||||
return switch (memberType) {
|
|
||||||
case "class" -> new AccessWidenerEntry(directive, "class", target, null, null);
|
|
||||||
case "method", "field" -> {
|
|
||||||
if (parts.length < 5) yield null;
|
|
||||||
yield new AccessWidenerEntry(directive, memberType, target, parts[3], parts[4]);
|
|
||||||
}
|
|
||||||
default -> null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Java agent entry point.
|
|
||||||
* <p>
|
|
||||||
* At JVM startup: java -javaagent:paper-access-widener-agent.jar -jar server.jar
|
|
||||||
* <p>
|
|
||||||
* On attach the agent:
|
|
||||||
* <ol>
|
|
||||||
* <li>Find all .jar files inside the plugins folder</li>
|
|
||||||
* <li>Scan all found jars for *.accesswidener resources</li>
|
|
||||||
* <li>Transform any class during loading</li>
|
|
||||||
* </ol>
|
|
||||||
*/
|
|
||||||
public class Agent {
|
|
||||||
private Agent() {
|
|
||||||
throw new IllegalStateException("Utility class");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
|
|
||||||
|
|
||||||
// -javaagent: startup
|
|
||||||
public static void premain(String args, Instrumentation inst) {
|
|
||||||
init(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void init(Instrumentation inst) {
|
|
||||||
LOG.info("[AccessWidener] Agent initialising.");
|
|
||||||
|
|
||||||
List<AccessWidenerEntry> entries = new ArrayList<>();
|
|
||||||
File file = new File(new File(".").getAbsoluteFile(), "plugins/");
|
|
||||||
File[] files = file.listFiles();
|
|
||||||
if (files == null) files = new File[0];
|
|
||||||
for (File jarFile : files) {
|
|
||||||
if (!jarFile.isFile()) continue;
|
|
||||||
if (!jarFile.getName().endsWith(".jar")) continue;
|
|
||||||
try {
|
|
||||||
entries.addAll(Utils.findAndParseAccessWideners(jarFile.toPath()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.warning("Failed to parse access wideners from " + jarFile.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG.info("[AccessWidener] Loaded " + entries.size() + " access wideners.");
|
|
||||||
|
|
||||||
inst.addTransformer(new WideningTransformer(entries), false);
|
|
||||||
LOG.info("[AccessWidener] Agent ready.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassReader;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uses ASM to patch class bytecode according to a list of access widener entries.
|
|
||||||
*
|
|
||||||
* Returns {@code null} if the class is not targeted by any entry (no-op signal
|
|
||||||
* to the caller so it can skip the write).
|
|
||||||
*/
|
|
||||||
public class ClassPatcher {
|
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger("ClassPatcher");
|
|
||||||
|
|
||||||
private final List<AccessWidenerEntry> entries;
|
|
||||||
|
|
||||||
/** Pre-computed set of targeted internal names for fast filtering. */
|
|
||||||
private final Set<String> targets;
|
|
||||||
|
|
||||||
private final Set<String> targetsPublicConstructor;
|
|
||||||
|
|
||||||
public ClassPatcher(List<AccessWidenerEntry> entries) {
|
|
||||||
this.entries = entries;
|
|
||||||
this.targets = entries.stream()
|
|
||||||
.map(AccessWidenerEntry::target)
|
|
||||||
.flatMap(s -> {
|
|
||||||
if (!s.contains("$")) return Stream.of(s);
|
|
||||||
int index = s.lastIndexOf('$');
|
|
||||||
return Stream.of(s, s.substring(0, index));
|
|
||||||
})
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
this.targetsPublicConstructor = entries.stream()
|
|
||||||
.filter(entry -> entry.directive().equals("transitive-extendable"))
|
|
||||||
.map(AccessWidenerEntry::target)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Patches {@code classBytes} if {@code className} is targeted.
|
|
||||||
*
|
|
||||||
* @return patched bytes, or {@code null} if no changes were needed
|
|
||||||
*/
|
|
||||||
public byte[] patch(String className, byte[] classBytes) {
|
|
||||||
if (!targets.contains(className)) return null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
ClassReader cr = new ClassReader(classBytes);
|
|
||||||
ClassWriter cw = new ClassWriter(cr, 0);
|
|
||||||
cr.accept(new ClassTransformer(cw, className, entries, targetsPublicConstructor.contains(className)), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
|
||||||
return cw.toByteArray();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.warning("[AccessWidener] Failed to transform " + className + ": " + e.getMessage());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassVisitor;
|
|
||||||
import org.objectweb.asm.FieldVisitor;
|
|
||||||
import org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ClassTransformer extends ClassVisitor {
|
|
||||||
|
|
||||||
private final String internalName;
|
|
||||||
private final List<AccessWidenerEntry> entries;
|
|
||||||
private final boolean appendPublicConstructor;
|
|
||||||
|
|
||||||
public ClassTransformer(ClassVisitor cv, String internalName, List<AccessWidenerEntry> entries, boolean appendPublicConstructor) {
|
|
||||||
super(Opcodes.ASM9, cv);
|
|
||||||
this.internalName = internalName;
|
|
||||||
this.entries = entries;
|
|
||||||
this.appendPublicConstructor = appendPublicConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
|
||||||
int newAccess = access;
|
|
||||||
for (AccessWidenerEntry e : entries) {
|
|
||||||
if (!e.targets(internalName) || !"class".equals(e.memberType())) continue;
|
|
||||||
newAccess = applyDirective(e.directive(), newAccess, false);
|
|
||||||
}
|
|
||||||
if (appendPublicConstructor) {
|
|
||||||
MethodVisitor methodVisitor = visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
|
|
||||||
methodVisitor.visitCode();
|
|
||||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
|
||||||
methodVisitor.visitMethodInsn(
|
|
||||||
Opcodes.INVOKESPECIAL,
|
|
||||||
"java/lang/Object",
|
|
||||||
"<init>",
|
|
||||||
"()V",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
methodVisitor.visitInsn(Opcodes.RETURN);
|
|
||||||
methodVisitor.visitMaxs(1, 1);
|
|
||||||
methodVisitor.visitEnd();
|
|
||||||
}
|
|
||||||
super.visit(version, newAccess, name, signature, superName, interfaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
|
||||||
int newAccess = access;
|
|
||||||
for (AccessWidenerEntry e : entries) {
|
|
||||||
if (!e.target().equals(name) || !"class".equals(e.memberType())) continue;
|
|
||||||
newAccess = applyDirective(e.directive(), newAccess, false);
|
|
||||||
}
|
|
||||||
super.visitInnerClass(name, outerName, innerName, newAccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
|
||||||
int newAccess = access;
|
|
||||||
for (AccessWidenerEntry e : entries) {
|
|
||||||
if (!e.targets(internalName) || !"method".equals(e.memberType())) continue;
|
|
||||||
if (!name.equals(e.name()) || !descriptor.equals(e.descriptor())) continue;
|
|
||||||
newAccess = applyDirective(e.directive(), newAccess, false);
|
|
||||||
}
|
|
||||||
return super.visitMethod(newAccess, name, descriptor, signature, exceptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
|
||||||
int newAccess = access;
|
|
||||||
for (AccessWidenerEntry e : entries) {
|
|
||||||
if (!e.targets(internalName) || !"field".equals(e.memberType())) continue;
|
|
||||||
if (!name.equals(e.name())) continue;
|
|
||||||
newAccess = applyDirective(e.directive(), newAccess, true);
|
|
||||||
}
|
|
||||||
return super.visitField(newAccess, name, descriptor, signature, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply a directive to an access bitmask.
|
|
||||||
*
|
|
||||||
* @param directive accessible / mutable / extendable (with optional "transitive-" prefix)
|
|
||||||
* @param access current access flags
|
|
||||||
* @param isField true when processing a field (mutable removes final)
|
|
||||||
*/
|
|
||||||
private static int applyDirective(String directive, int access, boolean isField) {
|
|
||||||
// Strip transitive- prefix — the widening itself is the same
|
|
||||||
String effective = directive.startsWith("transitive-") ? directive.substring("transitive-".length()) : directive;
|
|
||||||
|
|
||||||
return switch (effective) {
|
|
||||||
case "accessible" -> makePublic(access);
|
|
||||||
case "extendable" -> makePublic(removeFinal(access));
|
|
||||||
case "mutable" -> isField ? removeFinal(access) : access;
|
|
||||||
default -> access;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int makePublic(int access) {
|
|
||||||
return (access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int removeFinal(int access) {
|
|
||||||
return access & ~Opcodes.ACC_FINAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command-line tool that produces a widened copy of a JAR for use as a
|
|
||||||
* compile-time stub in IntelliJ / Gradle.
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* java -jar jar-widener.jar <input.jar> <output.jar> [file.accesswidener ...]
|
|
||||||
*
|
|
||||||
* The output JAR is identical to the input JAR except that every class
|
|
||||||
* targeted by the access widener entries has its access flags patched:
|
|
||||||
* accessible → public
|
|
||||||
* extendable → public + non-final
|
|
||||||
* mutable → non-final field
|
|
||||||
*
|
|
||||||
* Intended for use as a Gradle task so IntelliJ sees the already-widened
|
|
||||||
* class when you Ctrl+click NMS code, and javac compiles without complaints.
|
|
||||||
*/
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if (args.length < 2) {
|
|
||||||
System.err.println("Usage: jar-widener <input.jar> <output.jar> [*.accesswidener ...]");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path inputJar = Path.of(args[0]);
|
|
||||||
Path outputJar = Path.of(args[1]);
|
|
||||||
|
|
||||||
if (!Files.exists(inputJar)) {
|
|
||||||
System.err.println("Input JAR not found: " + inputJar);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Collect all access widener entries ---
|
|
||||||
List<AccessWidenerEntry> entries = new ArrayList<>();
|
|
||||||
|
|
||||||
if (args.length > 2) {
|
|
||||||
for (int i = 2; i < args.length; i++) {
|
|
||||||
Path awFile = Path.of(args[i]);
|
|
||||||
if (!Files.exists(awFile)) {
|
|
||||||
System.err.println("Warning: access widener file not found, skipping: " + awFile);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try (InputStream in = Files.newInputStream(awFile)) {
|
|
||||||
List<AccessWidenerEntry> parsed = AccessWidenerParser.parse(in);
|
|
||||||
System.out.println("Loaded " + parsed.size() + " entries from " + awFile.getFileName());
|
|
||||||
entries.addAll(parsed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entries.isEmpty()) {
|
|
||||||
System.out.println("No access widener entries found — copying JAR unchanged.");
|
|
||||||
Files.createDirectories(outputJar.getParent());
|
|
||||||
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Widening " + inputJar.getFileName()
|
|
||||||
+ " with " + entries.size() + " total entr"
|
|
||||||
+ (entries.size() == 1 ? "y" : "ies") + "...");
|
|
||||||
|
|
||||||
// --- Copy input → output, transforming .class files in place ---
|
|
||||||
Files.createDirectories(outputJar.getParent());
|
|
||||||
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
|
|
||||||
ClassPatcher patcher = new ClassPatcher(entries);
|
|
||||||
|
|
||||||
try (FileSystem fs = FileSystems.newFileSystem(outputJar)) {
|
|
||||||
// Walk every .class entry in the JAR
|
|
||||||
try (var stream = Files.walk(fs.getPath("/"))) {
|
|
||||||
stream.filter(p -> p.toString().endsWith(".class"))
|
|
||||||
.forEach(classPath -> patchClass(fs, classPath, patcher));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Done. Widened JAR written to " + outputJar);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void patchClass(FileSystem fs, Path classPath, ClassPatcher patcher) {
|
|
||||||
// Derive internal class name from path e.g. /net/minecraft/Foo.class → net/minecraft/Foo
|
|
||||||
String internalName = classPath.toString()
|
|
||||||
.replaceFirst("^/", "")
|
|
||||||
.replace(".class", "");
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] original = Files.readAllBytes(classPath);
|
|
||||||
byte[] patched = patcher.patch(internalName, original);
|
|
||||||
|
|
||||||
if (patched != null) {
|
|
||||||
Files.write(classPath, patched);
|
|
||||||
System.out.println(" Widened: " + internalName);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println(" Warning: failed to patch " + internalName + ": " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
public class Utils {
|
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
|
|
||||||
|
|
||||||
private Utils() {
|
|
||||||
throw new IllegalStateException("Utility class");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<AccessWidenerEntry> findAndParseAccessWideners(Path jarPath) throws IOException {
|
|
||||||
List<AccessWidenerEntry> results = new ArrayList<>();
|
|
||||||
|
|
||||||
try (ZipFile zip = new ZipFile(jarPath.toFile())) {
|
|
||||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
ZipEntry entry = entries.nextElement();
|
|
||||||
if (entry.isDirectory() || !entry.getName().endsWith(".accesswidener")) continue;
|
|
||||||
|
|
||||||
try (InputStream in = zip.getInputStream(entry)) {
|
|
||||||
results.addAll(AccessWidenerParser.parse(in));
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.warning("[AccessWidener] Failed to parse " + entry.getName()
|
|
||||||
+ " in " + jarPath.getFileName() + ": " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar;
|
|
||||||
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms class bytecode to apply access widening rules.
|
|
||||||
* <p>
|
|
||||||
* Also monitors for new plugin ClassLoaders appearing (when plugins load after
|
|
||||||
* the agent attaches) and automatically picks up their .accesswidener files.
|
|
||||||
*/
|
|
||||||
public class WideningTransformer implements ClassFileTransformer {
|
|
||||||
|
|
||||||
private final ClassPatcher patcher;
|
|
||||||
|
|
||||||
public WideningTransformer(List<AccessWidenerEntry> entries) {
|
|
||||||
patcher = new ClassPatcher(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
|
|
||||||
return patcher.patch(className, classfileBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
steamwar.java
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
||||||
|
compileOnly(project(":SpigotCore", "default"))
|
||||||
|
|
||||||
|
compileOnly(libs.nms15)
|
||||||
|
compileOnly(libs.worldedit15)
|
||||||
|
}
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||||
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||||
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
|
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||||
|
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||||
|
import com.sk89q.worldedit.function.operation.Operations;
|
||||||
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
|
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||||
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
|
import de.steamwar.bausystem.region.Point;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.block.data.Waterlogged;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class FlatteningWrapper15 implements FlatteningWrapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNoBook(ItemStack item) {
|
||||||
|
return item.getType() != Material.WRITABLE_BOOK && item.getType() != Material.WRITTEN_BOOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Set<Material> unpushable = new HashSet<>(Arrays.asList(Material.BARRIER, Material.BEACON, Material.COMMAND_BLOCK, Material.CHAIN_COMMAND_BLOCK, Material.REPEATING_COMMAND_BLOCK, Material.ENCHANTING_TABLE, Material.END_GATEWAY, Material.END_PORTAL, Material.ENDER_CHEST, Material.GRINDSTONE, Material.JIGSAW, Material.JUKEBOX, Material.NETHER_PORTAL, Material.OBSIDIAN, Material.STRUCTURE_VOID, Material.BARREL, Material.BEEHIVE, Material.BEE_NEST, Material.BLAST_FURNACE, Material.BREWING_STAND, Material.CHEST, Material.DAYLIGHT_DETECTOR, Material.DISPENSER, Material.DROPPER, Material.FURNACE, Material.HOPPER, Material.LECTERN, Material.SMOKER, Material.TRAPPED_CHEST));
|
||||||
|
|
||||||
|
// TODO: FLOWER
|
||||||
|
private static final Set<Material> breaking = new HashSet<>(Arrays.asList(Material.BAMBOO, Material.CACTUS, Material.CAKE, Material.CARVED_PUMPKIN, Material.CHORUS_FLOWER, Material.CHORUS_PLANT, Material.COBWEB, Material.COCOA, Material.DRAGON_EGG, Material.FIRE, Material.FLOWER_POT, Material.JACK_O_LANTERN, Material.LADDER, Material.LAVA, Material.LAVA, Material.LEVER, Material.LILY_PAD, Material.MELON, Material.NETHER_WART, Material.PUMPKIN, Material.COMPARATOR, Material.REDSTONE_WIRE, Material.REPEATER, Material.TORCH, Material.STRUCTURE_VOID, Material.SCAFFOLDING, Material.SEA_PICKLE, Material.SNOW, Material.SUGAR_CANE, Material.TORCH, Material.TRIPWIRE, Material.TRIPWIRE_HOOK, Material.TURTLE_EGG, Material.VINE, Material.WATER, Material.WHEAT));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnpusheable(Material material) {
|
||||||
|
if (unpushable.contains(material)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String name = material.name();
|
||||||
|
return name.contains("BANNER") || name.contains("SIGN");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBreakingOnPush(Material material) {
|
||||||
|
if (breaking.contains(material)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String name = material.name();
|
||||||
|
return name.contains("BED") || name.contains("BUTTON") || name.contains("CARPET") || (name.contains("DOOR") && !name.contains("TRAPDOOR")) || name.contains("HEAD") || name.contains("LEAVES") || name.contains("MUSHROOM") || name.contains("PRESSURE_PLATE") || name.contains("SHULKER_BOX");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWorldEditCommand(String command) {
|
||||||
|
if (command.startsWith("/")) {
|
||||||
|
command = command.replaceFirst("/", "");
|
||||||
|
}
|
||||||
|
command = command.toLowerCase();
|
||||||
|
return WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().containsCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final WorldEditPlugin WORLDEDIT_PLUGIN = Objects.requireNonNull((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"));
|
||||||
|
private static final World BUKKITWORLD = new BukkitWorld(Bukkit.getWorlds().get(0));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSelection(Player p, Point minPoint, Point maxPoint) {
|
||||||
|
WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, minPoint.toBlockVector3(), maxPoint.toBlockVector3()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Clipboard loadSchematic(File file) {
|
||||||
|
Clipboard clipboard;
|
||||||
|
try (ClipboardReader reader = Objects.requireNonNull(ClipboardFormats.findByFile(file)).getReader(new FileInputStream(file))) {
|
||||||
|
clipboard = reader.read();
|
||||||
|
} catch (NullPointerException | IOException e) {
|
||||||
|
throw new SecurityException("Bausystem schematic not found", e);
|
||||||
|
}
|
||||||
|
return clipboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EditSession paste(PasteBuilder pasteBuilder) {
|
||||||
|
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) {
|
||||||
|
Clipboard clipboard = pasteBuilder.getClipboard();
|
||||||
|
|
||||||
|
if (!pasteBuilder.getMappers().isEmpty()) {
|
||||||
|
BlockVector3 minimum = clipboard.getRegion().getMinimumPoint();
|
||||||
|
for (int x = 0; x < clipboard.getDimensions().getX(); x++) {
|
||||||
|
for (int y = 0; y < clipboard.getDimensions().getY(); y++) {
|
||||||
|
for (int z = 0; z < clipboard.getDimensions().getZ(); z++) {
|
||||||
|
BlockVector3 pos = minimum.add(x, y, z);
|
||||||
|
pasteBuilder.getMappers().forEach(mapper -> mapper.accept(clipboard, pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicReference<BlockVector3> pastePoint = new AtomicReference<>();
|
||||||
|
if (!pasteBuilder.getPredicates().isEmpty()) {
|
||||||
|
e.setMask(new Mask() {
|
||||||
|
@Override
|
||||||
|
public boolean test(BlockVector3 blockVector3) {
|
||||||
|
BaseBlock block = clipboard.getFullBlock(blockVector3.subtract(pastePoint.get()).add(clipboard.getRegion().getMinimumPoint()));
|
||||||
|
String blockName = block.getBlockType().toString().toLowerCase();
|
||||||
|
for (BiPredicate<BaseBlock, String> predicate : pasteBuilder.getPredicates()) {
|
||||||
|
if (!predicate.test(block, blockName)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mask copy() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Mask2D toMask2D() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardHolder ch = new ClipboardHolder(clipboard);
|
||||||
|
BlockVector3 dimensions = clipboard.getDimensions();
|
||||||
|
BlockVector3 v = BlockVector3.at(pasteBuilder.getPastPoint().getX(), pasteBuilder.getPastPoint().getY(), pasteBuilder.getPastPoint().getZ());
|
||||||
|
BlockVector3 offset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
|
||||||
|
if (pasteBuilder.isRotate()) {
|
||||||
|
ch.setTransform(new AffineTransform().rotateY(180));
|
||||||
|
v = v.add(dimensions.getX() / 2, 0, dimensions.getZ() / 2).subtract(offset.multiply(-1, 1, -1)).subtract(0, 0, 1);
|
||||||
|
} else {
|
||||||
|
v = v.subtract(dimensions.getX() / 2, 0, dimensions.getZ() / 2).subtract(offset);
|
||||||
|
}
|
||||||
|
pastePoint.set(v);
|
||||||
|
|
||||||
|
if (pasteBuilder.isReset()) {
|
||||||
|
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
|
||||||
|
if (pasteBuilder.getWaterLevel() != 0) {
|
||||||
|
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3().withY(pasteBuilder.getWaterLevel())), Objects.requireNonNull(BlockTypes.WATER).getDefaultState().toBaseBlock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(pasteBuilder.isIgnoreAir()).build());
|
||||||
|
return e;
|
||||||
|
} catch (WorldEditException e) {
|
||||||
|
throw new SecurityException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Clipboard copy(Point minPoint, Point maxPoint, Point copyPoint) {
|
||||||
|
BukkitWorld bukkitWorld = new BukkitWorld(Bukkit.getWorlds().get(0));
|
||||||
|
CuboidRegion region = new CuboidRegion(bukkitWorld, minPoint.toBlockVector3(), maxPoint.toBlockVector3());
|
||||||
|
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
||||||
|
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(bukkitWorld, -1)) {
|
||||||
|
ForwardExtentCopy copy = new ForwardExtentCopy(
|
||||||
|
e, region, clipboard, region.getMinimumPoint()
|
||||||
|
);
|
||||||
|
|
||||||
|
copy.setCopyingEntities(false);
|
||||||
|
copy.setCopyingBiomes(false);
|
||||||
|
|
||||||
|
Operations.complete(copy);
|
||||||
|
clipboard.setOrigin(copyPoint.toBlockVector3());
|
||||||
|
return clipboard;
|
||||||
|
} catch (WorldEditException e) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean backup(Point minPoint, Point maxPoint, File file) {
|
||||||
|
Clipboard clipboard = copy(minPoint, maxPoint, minPoint);
|
||||||
|
try (ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) {
|
||||||
|
writer.write(clipboard);
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean inWater(org.bukkit.World world, Vector tntPosition) {
|
||||||
|
Block block = world.getBlockAt(tntPosition.getBlockX(), tntPosition.getBlockY(), tntPosition.getBlockZ());
|
||||||
|
if (block.getType() == Material.WATER)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
BlockData data = block.getBlockData();
|
||||||
|
if (!(data instanceof Waterlogged))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ((Waterlogged) data).isWaterlogged();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import de.steamwar.bausystem.features.util.NoClipCommand;
|
||||||
|
import net.minecraft.server.v1_15_R1.*;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class NMSWrapper15 implements NMSWrapper {
|
||||||
|
|
||||||
|
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void setInternalGameMode(Player player, GameMode gameMode) {
|
||||||
|
playerGameMode.set(((CraftPlayer) player).getHandle().playerInteractManager, EnumGamemode.getById(gameMode.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSlotToItemStack(Player player, Object o) {
|
||||||
|
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
||||||
|
int index = packetPlayInSetCreativeSlot.b();
|
||||||
|
if (index >= 36 && index <= 44) {
|
||||||
|
index -= 36;
|
||||||
|
} else if (index > 44) {
|
||||||
|
index -= 5;
|
||||||
|
} else if (index <= 8) {
|
||||||
|
index = index - 8 + 36;
|
||||||
|
}
|
||||||
|
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItemStack()));
|
||||||
|
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Field<Integer> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, int.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameStateChangeReason(Object packet) {
|
||||||
|
gameStateChangeReason.set(packet, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerBuildAbilities(Player player) {
|
||||||
|
((CraftPlayer) player).getHandle().abilities.mayBuild = true;
|
||||||
|
((CraftPlayer) player).getHandle().abilities.canInstantlyBuild = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material pathMaterial() {
|
||||||
|
return Material.GRASS_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int threshold = 2048;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkItemStack(ItemStack item) {
|
||||||
|
net.minecraft.server.v1_15_R1.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
||||||
|
NBTTagCompound tag = nmsItem.getTag();
|
||||||
|
if (tag != null && tag.hasKey("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = tag.getCompound("BlockEntityTag");
|
||||||
|
if (blockTag.hasKey("Items")) {
|
||||||
|
return drillDown(blockTag.getList("Items", 10), 0, 0) > threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int drillDown(NBTTagList items, int layer, int start) {
|
||||||
|
if (layer > 2) return start + threshold;
|
||||||
|
int invalid = start;
|
||||||
|
for (NBTBase nbtBase : items) {
|
||||||
|
if (!(nbtBase instanceof NBTTagCompound))
|
||||||
|
continue;
|
||||||
|
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
||||||
|
if (slot.hasKey("tag")) {
|
||||||
|
invalid += slot.getByte("Count");
|
||||||
|
NBTTagCompound iTag = slot.getCompound("tag");
|
||||||
|
if (iTag.hasKey("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = iTag.getCompound("BlockEntityTag");
|
||||||
|
if (blockTag.hasKey("Items")) {
|
||||||
|
invalid = drillDown(blockTag.getList("Items", 10), layer + 1, invalid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalid > threshold)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
||||||
|
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
||||||
|
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
||||||
|
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
||||||
|
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
||||||
|
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resetExplosionKnockback(Object packet) {
|
||||||
|
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
||||||
|
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), Vec3D.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public class PlaceItemWrapper15 implements PlaceItemWrapper {
|
||||||
|
|
||||||
|
public PlaceItemWrapper15() {
|
||||||
|
for (Material material : Material.values()) {
|
||||||
|
if (!material.isBlock()) continue;
|
||||||
|
if (material.isLegacy()) continue;
|
||||||
|
|
||||||
|
String nonWall = material.name().replace("_WALL_", "").replace("WALL_", "").replace("_WALL", "");
|
||||||
|
try {
|
||||||
|
Material nonWallMaterial = Material.valueOf(nonWall);
|
||||||
|
if (nonWallMaterial != material && nonWallMaterial.isItem() && !nonWallMaterial.isBlock()) {
|
||||||
|
BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.put(nonWallMaterial, material);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ITEM_MATERIAL_TO_BLOCK_MATERIAL.put(Material.REDSTONE, Material.REDSTONE_WIRE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import net.minecraft.server.v1_15_R1.EntityPlayer;
|
||||||
|
import net.minecraft.server.v1_15_R1.PacketPlayInFlying;
|
||||||
|
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PlayerMovementWrapper15 implements PlayerMovementWrapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPosition(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
||||||
|
if (Float.isNaN(packetPlayInFlying.a(Float.NaN))) {
|
||||||
|
entityPlayer.e(packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0));
|
||||||
|
} else {
|
||||||
|
entityPlayer.setLocation(packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0), packetPlayInFlying.a(0F), packetPlayInFlying.b(0F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertToOut(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
Object packet = Reflection.newInstance(teleportPacket);
|
||||||
|
teleportEntity.set(packet, player.getEntityId());
|
||||||
|
teleportPosition.set(packet, packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0),
|
||||||
|
Float.isNaN(packetPlayInFlying.a(Float.NaN)) ? player.getLocation().getYaw() : packetPlayInFlying.a(0.0F),
|
||||||
|
Float.isNaN(packetPlayInFlying.b(Float.NaN)) ? player.getLocation().getPitch() : packetPlayInFlying.b(0.0F));
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-5
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -17,9 +17,7 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.entity;
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
public enum REntityAction {
|
public class TickListener15 implements TickListener {
|
||||||
INTERACT,
|
|
||||||
ATTACK,
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
steamwar.java
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
||||||
|
compileOnly(project(":SpigotCore", "default"))
|
||||||
|
|
||||||
|
compileOnly(libs.spigotapi)
|
||||||
|
compileOnly(libs.nms18)
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import de.steamwar.bausystem.features.util.NoClipCommand;
|
||||||
|
import net.minecraft.nbt.NBTBase;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.nbt.NBTTagList;
|
||||||
|
import net.minecraft.network.protocol.game.*;
|
||||||
|
import net.minecraft.server.level.PlayerInteractManager;
|
||||||
|
import net.minecraft.world.level.EnumGamemode;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class NMSWrapper18 implements NMSWrapper {
|
||||||
|
|
||||||
|
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void setInternalGameMode(Player player, GameMode gameMode) {
|
||||||
|
playerGameMode.set(((CraftPlayer) player).getHandle().d, EnumGamemode.a(gameMode.getValue()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSlotToItemStack(Player player, Object o) {
|
||||||
|
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
||||||
|
int index = packetPlayInSetCreativeSlot.b();
|
||||||
|
if (index >= 36 && index <= 44) {
|
||||||
|
index -= 36;
|
||||||
|
} else if (index > 44) {
|
||||||
|
index -= 5;
|
||||||
|
} else if (index <= 8) {
|
||||||
|
index = index - 8 + 36;
|
||||||
|
}
|
||||||
|
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
|
||||||
|
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameStateChangeReason(Object packet) {
|
||||||
|
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerBuildAbilities(Player player) {
|
||||||
|
((CraftPlayer) player).getHandle().fs().d = true;
|
||||||
|
((CraftPlayer) player).getHandle().fs().e = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material pathMaterial() {
|
||||||
|
return Material.DIRT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int threshold = 2048;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkItemStack(ItemStack item) {
|
||||||
|
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
||||||
|
NBTTagCompound tag = nmsItem.t();
|
||||||
|
if (tag != null && tag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = tag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int drillDown(NBTTagList items, int layer, int start) {
|
||||||
|
if (layer > 2) return start + threshold;
|
||||||
|
int invalid = start;
|
||||||
|
for (NBTBase nbtBase : items) {
|
||||||
|
if (!(nbtBase instanceof NBTTagCompound))
|
||||||
|
continue;
|
||||||
|
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
||||||
|
if (slot.e("tag")) {
|
||||||
|
invalid += slot.f("Count");
|
||||||
|
NBTTagCompound iTag = slot.p("tag");
|
||||||
|
if (iTag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalid > threshold)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
||||||
|
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
||||||
|
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
||||||
|
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
||||||
|
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
||||||
|
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resetExplosionKnockback(Object packet) {
|
||||||
|
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
||||||
|
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayInFlying;
|
||||||
|
import net.minecraft.server.level.EntityPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PlayerMovementWrapper18 implements PlayerMovementWrapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPosition(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
||||||
|
if (packetPlayInFlying.h) {
|
||||||
|
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
|
||||||
|
} else {
|
||||||
|
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertToOut(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
Object packet = Reflection.newInstance(teleportPacket);
|
||||||
|
teleportEntity.set(packet, player.getEntityId());
|
||||||
|
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
|
||||||
|
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
|
||||||
|
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-15
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,27 +21,17 @@ plugins {
|
|||||||
steamwar.java
|
steamwar.java
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileJava {
|
|
||||||
options.isWarnings = false
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_21
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_21
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
compileOnly(project(":SpigotCore", "default"))
|
||||||
|
|
||||||
|
compileOnly(libs.spigotapi)
|
||||||
compileOnly(libs.paperapi)
|
compileOnly(libs.paperapi)
|
||||||
compileOnly(libs.axiom)
|
|
||||||
compileOnly(libs.authlib)
|
|
||||||
compileOnly(libs.viaapi)
|
|
||||||
|
|
||||||
compileOnly(libs.nms)
|
compileOnly(libs.nms19)
|
||||||
compileOnly(libs.fawe)
|
|
||||||
|
|
||||||
implementation(libs.luaj)
|
|
||||||
implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import de.steamwar.bausystem.features.util.NoClipCommand;
|
||||||
|
import net.minecraft.nbt.NBTBase;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.nbt.NBTTagList;
|
||||||
|
import net.minecraft.network.protocol.game.*;
|
||||||
|
import net.minecraft.server.level.PlayerInteractManager;
|
||||||
|
import net.minecraft.world.level.EnumGamemode;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class NMSWrapper19 implements NMSWrapper {
|
||||||
|
|
||||||
|
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void setInternalGameMode(Player player, GameMode gameMode) {
|
||||||
|
playerGameMode.set(((CraftPlayer) player).getHandle().d, EnumGamemode.a(gameMode.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSlotToItemStack(Player player, Object o) {
|
||||||
|
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
||||||
|
int index = packetPlayInSetCreativeSlot.b();
|
||||||
|
if (index >= 36 && index <= 44) {
|
||||||
|
index -= 36;
|
||||||
|
} else if (index > 44) {
|
||||||
|
index -= 5;
|
||||||
|
} else if (index <= 8) {
|
||||||
|
index = index - 8 + 36;
|
||||||
|
}
|
||||||
|
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
|
||||||
|
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameStateChangeReason(Object packet) {
|
||||||
|
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerBuildAbilities(Player player) {
|
||||||
|
((CraftPlayer) player).getHandle().fF().d = true;
|
||||||
|
((CraftPlayer) player).getHandle().fF().e = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material pathMaterial() {
|
||||||
|
return Material.DIRT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int threshold = 2048;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkItemStack(ItemStack item) {
|
||||||
|
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
||||||
|
NBTTagCompound tag = nmsItem.v();
|
||||||
|
if (tag != null && tag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = tag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int drillDown(NBTTagList items, int layer, int start) {
|
||||||
|
if (layer > 2) return start + threshold;
|
||||||
|
int invalid = start;
|
||||||
|
for (NBTBase nbtBase : items) {
|
||||||
|
if (!(nbtBase instanceof NBTTagCompound))
|
||||||
|
continue;
|
||||||
|
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
||||||
|
if (slot.e("tag")) {
|
||||||
|
invalid += slot.f("Count");
|
||||||
|
NBTTagCompound iTag = slot.p("tag");
|
||||||
|
if (iTag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalid > threshold)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
||||||
|
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
||||||
|
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
||||||
|
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
||||||
|
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
||||||
|
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resetExplosionKnockback(Object packet) {
|
||||||
|
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
||||||
|
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayInFlying;
|
||||||
|
import net.minecraft.server.level.EntityPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PlayerMovementWrapper19 implements PlayerMovementWrapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPosition(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
||||||
|
if (packetPlayInFlying.h) {
|
||||||
|
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
|
||||||
|
} else {
|
||||||
|
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertToOut(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
Object packet = Reflection.newInstance(teleportPacket);
|
||||||
|
teleportEntity.set(packet, player.getEntityId());
|
||||||
|
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
|
||||||
|
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
|
||||||
|
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
|
||||||
|
import com.destroystokyo.paper.event.server.ServerTickStartEvent;
|
||||||
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
public class TickListener19 implements TickListener, Listener {
|
||||||
|
|
||||||
|
private boolean tickStartRan = false;
|
||||||
|
|
||||||
|
public TickListener19() {
|
||||||
|
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onServerTickStart(ServerTickStartEvent event) {
|
||||||
|
if (TPSFreezeUtils.isFrozen()) return;
|
||||||
|
Bukkit.getPluginManager().callEvent(new TickStartEvent());
|
||||||
|
tickStartRan = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onServerTickEnd(ServerTickEndEvent event) {
|
||||||
|
if (!tickStartRan) return;
|
||||||
|
Bukkit.getPluginManager().callEvent(new TickEndEvent());
|
||||||
|
tickStartRan = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
steamwar.java
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
||||||
|
compileOnly(project(":SpigotCore", "default"))
|
||||||
|
|
||||||
|
compileOnly(libs.spigotapi)
|
||||||
|
|
||||||
|
compileOnly(libs.nms20)
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import de.steamwar.bausystem.features.util.NoClipCommand;
|
||||||
|
import net.minecraft.nbt.NBTBase;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.nbt.NBTTagList;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutExplosion;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange;
|
||||||
|
import net.minecraft.server.level.PlayerInteractManager;
|
||||||
|
import net.minecraft.world.level.EnumGamemode;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class NMSWrapper20 implements NMSWrapper {
|
||||||
|
|
||||||
|
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void setInternalGameMode(Player player, GameMode gameMode) {
|
||||||
|
playerGameMode.set(((CraftPlayer) player).getHandle().e, EnumGamemode.a(gameMode.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSlotToItemStack(Player player, Object o) {
|
||||||
|
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
||||||
|
int index = packetPlayInSetCreativeSlot.a();
|
||||||
|
if (index >= 36 && index <= 44) {
|
||||||
|
index -= 36;
|
||||||
|
} else if (index > 44) {
|
||||||
|
index -= 5;
|
||||||
|
} else if (index <= 8) {
|
||||||
|
index = index - 8 + 36;
|
||||||
|
}
|
||||||
|
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
|
||||||
|
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameStateChangeReason(Object packet) {
|
||||||
|
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerBuildAbilities(Player player) {
|
||||||
|
((CraftPlayer) player).getHandle().fO().d = true;
|
||||||
|
((CraftPlayer) player).getHandle().fO().e = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material pathMaterial() {
|
||||||
|
return Material.DIRT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int threshold = 2048;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkItemStack(ItemStack item) {
|
||||||
|
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
||||||
|
NBTTagCompound tag = nmsItem.v();
|
||||||
|
if (tag != null && tag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = tag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int drillDown(NBTTagList items, int layer, int start) {
|
||||||
|
if (layer > 2) return start + threshold;
|
||||||
|
int invalid = start;
|
||||||
|
for (NBTBase nbtBase : items) {
|
||||||
|
if (!(nbtBase instanceof NBTTagCompound))
|
||||||
|
continue;
|
||||||
|
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
||||||
|
if (slot.e("tag")) {
|
||||||
|
invalid += slot.f("Count");
|
||||||
|
NBTTagCompound iTag = slot.p("tag");
|
||||||
|
if (iTag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalid > threshold)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
||||||
|
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
||||||
|
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
||||||
|
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
||||||
|
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
||||||
|
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resetExplosionKnockback(Object packet) {
|
||||||
|
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
||||||
|
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
|
||||||
|
public class PlaceItemWrapper20 implements PlaceItemWrapper {
|
||||||
|
|
||||||
|
public PlaceItemWrapper20() {
|
||||||
|
for (Material material : Material.values()) {
|
||||||
|
if (!material.isBlock()) continue;
|
||||||
|
if (material.isLegacy()) continue;
|
||||||
|
BlockData blockData = material.createBlockData();
|
||||||
|
Material placementMaterial = blockData.getPlacementMaterial();
|
||||||
|
if (material == placementMaterial) continue;
|
||||||
|
if (placementMaterial == Material.AIR) continue;
|
||||||
|
if (placementMaterial.isItem() && !placementMaterial.isBlock()) {
|
||||||
|
ITEM_MATERIAL_TO_BLOCK_MATERIAL.put(placementMaterial, material);
|
||||||
|
}
|
||||||
|
if (material.name().contains("WALL")) {
|
||||||
|
BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.put(placementMaterial, material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayInFlying;
|
||||||
|
import net.minecraft.server.level.EntityPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PlayerMovementWrapper20 implements PlayerMovementWrapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPosition(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
||||||
|
if (packetPlayInFlying.h) {
|
||||||
|
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
|
||||||
|
} else {
|
||||||
|
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertToOut(Player player, Object object) {
|
||||||
|
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
||||||
|
Object packet = Reflection.newInstance(teleportPacket);
|
||||||
|
teleportEntity.set(packet, player.getEntityId());
|
||||||
|
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
|
||||||
|
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
|
||||||
|
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
steamwar.java
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_21
|
||||||
|
targetCompatibility = JavaVersion.VERSION_21
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
||||||
|
compileOnly(project(":SpigotCore", "default"))
|
||||||
|
|
||||||
|
compileOnly(libs.paperapi21)
|
||||||
|
|
||||||
|
compileOnly(libs.nms21)
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import de.steamwar.Reflection;
|
||||||
|
import de.steamwar.bausystem.features.util.NoClipCommand;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.nbt.NBTBase;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.nbt.NBTTagList;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutExplosion;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange;
|
||||||
|
import net.minecraft.server.level.EntityPlayer;
|
||||||
|
import net.minecraft.server.level.PlayerInteractManager;
|
||||||
|
import net.minecraft.world.entity.player.EntityHuman;
|
||||||
|
import net.minecraft.world.entity.player.PlayerAbilities;
|
||||||
|
import net.minecraft.world.item.component.CustomData;
|
||||||
|
import net.minecraft.world.level.EnumGamemode;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R2.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class NMSWrapper21 implements NMSWrapper {
|
||||||
|
|
||||||
|
private static final Reflection.Field<PlayerInteractManager> playerInteractManager = Reflection.getField(EntityPlayer.class, null, PlayerInteractManager.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInternalGameMode(Player player, GameMode gameMode) {
|
||||||
|
playerInteractManager.get(((CraftPlayer) player).getHandle()).a(EnumGamemode.a(gameMode.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSlotToItemStack(Player player, Object o) {
|
||||||
|
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
||||||
|
int index = packetPlayInSetCreativeSlot.b();
|
||||||
|
if (index >= 36 && index <= 44) {
|
||||||
|
index -= 36;
|
||||||
|
} else if (index > 44) {
|
||||||
|
index -= 5;
|
||||||
|
} else if (index <= 8) {
|
||||||
|
index = index - 8 + 36;
|
||||||
|
}
|
||||||
|
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.e()));
|
||||||
|
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameStateChangeReason(Object packet) {
|
||||||
|
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Field<PlayerAbilities> playerAbilities = Reflection.getField(EntityHuman.class, null, PlayerAbilities.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerBuildAbilities(Player player) {
|
||||||
|
PlayerAbilities abilities = playerAbilities.get(((CraftPlayer) player).getHandle());
|
||||||
|
abilities.d = true;
|
||||||
|
abilities.e = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material pathMaterial() {
|
||||||
|
return Material.DIRT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int threshold = 2048;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkItemStack(ItemStack item) {
|
||||||
|
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
||||||
|
NBTTagCompound tag = nmsItem.a(DataComponents.b, CustomData.a).c();
|
||||||
|
if (tag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = tag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int drillDown(NBTTagList items, int layer, int start) {
|
||||||
|
if (layer > 2) return start + threshold;
|
||||||
|
int invalid = start;
|
||||||
|
for (NBTBase nbtBase : items) {
|
||||||
|
if (!(nbtBase instanceof NBTTagCompound slot))
|
||||||
|
continue;
|
||||||
|
if (slot.e("tag")) {
|
||||||
|
invalid += slot.f("Count");
|
||||||
|
NBTTagCompound iTag = slot.p("tag");
|
||||||
|
if (iTag.e("BlockEntityTag")) {
|
||||||
|
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
|
||||||
|
if (blockTag.e("Items")) {
|
||||||
|
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalid > threshold)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resetExplosionKnockback(Object packet) {
|
||||||
|
PacketPlayOutExplosion explosion = (PacketPlayOutExplosion) packet;
|
||||||
|
|
||||||
|
return new PacketPlayOutExplosion(
|
||||||
|
explosion.b(),
|
||||||
|
Optional.empty(),
|
||||||
|
explosion.f(),
|
||||||
|
explosion.g()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
steamwar.java
|
steamwar.java
|
||||||
widener
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileJava {
|
tasks.compileJava {
|
||||||
@@ -27,29 +26,21 @@ tasks.compileJava {
|
|||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_21
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_21
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(libs.classindex)
|
compileOnly(libs.classindex)
|
||||||
annotationProcessor(libs.classindex)
|
annotationProcessor(libs.classindex)
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
compileOnly(project(":SpigotCore", "default"))
|
||||||
compileOnly(project(":KotlinCore", "default"))
|
|
||||||
|
|
||||||
|
compileOnly(libs.spigotapi)
|
||||||
compileOnly(libs.axiom)
|
compileOnly(libs.axiom)
|
||||||
compileOnly(libs.authlib)
|
compileOnly(libs.authlib)
|
||||||
|
|
||||||
compileOnly(libs.paperapi)
|
compileOnly(libs.fawe18)
|
||||||
compileOnly(libs.nms)
|
|
||||||
|
|
||||||
compileOnly(libs.fawe)
|
|
||||||
compileOnly(libs.netty)
|
|
||||||
|
|
||||||
implementation(libs.luaj)
|
implementation(libs.luaj)
|
||||||
// implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
|
implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
|
||||||
}
|
|
||||||
|
|
||||||
widener {
|
|
||||||
fromCatalog(libs.nms)
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,13 +0,0 @@
|
|||||||
accessWidener v2 named
|
|
||||||
|
|
||||||
# For NoClipCommand
|
|
||||||
accessible field net/minecraft/server/level/ServerPlayerGameMode gameModeForPlayer Lnet/minecraft/world/level/GameType;
|
|
||||||
|
|
||||||
# For PlaceItemUtils
|
|
||||||
accessible field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
|
|
||||||
mutable field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
|
|
||||||
accessible field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
|
|
||||||
mutable field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
|
|
||||||
|
|
||||||
# For TickManager
|
|
||||||
accessible field net/minecraft/server/ServerTickRateManager remainingSprintTicks J
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -20,53 +20,60 @@
|
|||||||
package de.steamwar.bausystem;
|
package de.steamwar.bausystem;
|
||||||
|
|
||||||
import de.steamwar.bausystem.config.BauServer;
|
import de.steamwar.bausystem.config.BauServer;
|
||||||
import de.steamwar.bausystem.config.ConfigStore;
|
import de.steamwar.bausystem.configplayer.Config;
|
||||||
|
import de.steamwar.bausystem.configplayer.ConfigConverter;
|
||||||
import de.steamwar.bausystem.features.gui.BauGUI;
|
import de.steamwar.bausystem.features.gui.BauGUI;
|
||||||
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
|
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
|
||||||
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
|
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
|
||||||
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
|
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
|
||||||
import de.steamwar.bausystem.features.slaves.panzern.Panzern;
|
import de.steamwar.bausystem.features.slaves.panzern.Panzern;
|
||||||
import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm;
|
import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm;
|
||||||
|
import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils;
|
||||||
import de.steamwar.bausystem.features.tracer.TraceManager;
|
import de.steamwar.bausystem.features.tracer.TraceManager;
|
||||||
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
||||||
import de.steamwar.bausystem.features.world.BauScoreboard;
|
import de.steamwar.bausystem.features.world.BauScoreboard;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.loader.PrototypeLoader;
|
||||||
import de.steamwar.bausystem.region.RegionSystem;
|
import de.steamwar.bausystem.region.loader.RegionLoader;
|
||||||
|
import de.steamwar.bausystem.region.loader.Updater;
|
||||||
import de.steamwar.bausystem.utils.ScoreboardElement;
|
import de.steamwar.bausystem.utils.ScoreboardElement;
|
||||||
import de.steamwar.bausystem.utils.TickManager;
|
import de.steamwar.bausystem.utils.TickListener;
|
||||||
|
import de.steamwar.bausystem.worlddata.WorldData;
|
||||||
import de.steamwar.command.AbstractValidator;
|
import de.steamwar.command.AbstractValidator;
|
||||||
|
import de.steamwar.command.SWCommand;
|
||||||
import de.steamwar.command.SWCommandUtils;
|
import de.steamwar.command.SWCommandUtils;
|
||||||
import de.steamwar.core.CRIUSleepEvent;
|
|
||||||
import de.steamwar.core.Core;
|
import de.steamwar.core.Core;
|
||||||
import de.steamwar.core.WorldIdentifier;
|
import de.steamwar.linkage.LinkedInstance;
|
||||||
import de.steamwar.core.worldedit.SteamEdit;
|
import de.steamwar.linkage.MaxVersion;
|
||||||
import de.steamwar.core.worldedit.WorldEditRendererCUIEditor;
|
import de.steamwar.linkage.MinVersion;
|
||||||
import de.steamwar.linkage.AbstractLinker;
|
import de.steamwar.linkage.PluginCheck;
|
||||||
import de.steamwar.linkage.SpigotLinker;
|
import de.steamwar.linkage.api.Disable;
|
||||||
|
import de.steamwar.linkage.api.Enable;
|
||||||
import de.steamwar.message.Message;
|
import de.steamwar.message.Message;
|
||||||
import de.steamwar.providers.BauServerInfo;
|
import de.steamwar.network.packets.PacketHandler;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameRule;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.io.OutputStream;
|
import java.lang.reflect.Field;
|
||||||
import java.io.PrintStream;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class BauSystem extends JavaPlugin implements Listener {
|
public class BauSystem extends JavaPlugin {
|
||||||
|
|
||||||
// This should be treated as final!
|
// This should be treated as final!
|
||||||
public static Message MESSAGE;
|
public static Message MESSAGE;
|
||||||
@@ -75,7 +82,7 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
@Getter
|
@Getter
|
||||||
private static BauSystem instance;
|
private static BauSystem instance;
|
||||||
|
|
||||||
private SpigotLinker linker;
|
private final Map<Class<?>, Object> instances = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
@@ -87,17 +94,82 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
instance = this;
|
instance = this;
|
||||||
SWUtils.setBausystem(instance);
|
SWUtils.setBausystem(instance);
|
||||||
|
|
||||||
RegionSystem.INSTANCE.load();
|
try {
|
||||||
|
PrototypeLoader.load();
|
||||||
|
RegionLoader.load();
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
Bukkit.shutdown();
|
||||||
|
System.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new Updater(PrototypeLoader.file, PrototypeLoader::load);
|
||||||
|
new Updater(RegionLoader.file, RegionLoader::load);
|
||||||
|
|
||||||
SWCommandUtils.addValidator(Player.class, validator(Permission.BUILD));
|
SWCommandUtils.addValidator(Player.class, validator(Permission.BUILD));
|
||||||
SWCommandUtils.addValidator(CommandSender.class, validator(Permission.BUILD));
|
SWCommandUtils.addValidator(CommandSender.class, validator(Permission.BUILD));
|
||||||
SWCommandUtils.addValidator("supervisor", validator(Permission.SUPERVISOR));
|
SWCommandUtils.addValidator("supervisor", validator(Permission.SUPERVISOR));
|
||||||
SWCommandUtils.addValidator("owner", validator(Permission.OWNER));
|
SWCommandUtils.addValidator("owner", validator(Permission.OWNER));
|
||||||
|
|
||||||
linker = new SpigotLinker(BauSystem.getInstance(), BauSystem.MESSAGE) {
|
instances.put(BauServer.class, BauServer.getInstance());
|
||||||
@Override
|
List<Class<?>> classes = new BufferedReader(new InputStreamReader(BauSystem.class.getResourceAsStream("/META-INF/annotations/de.steamwar.linkage.Linked")))
|
||||||
protected void linkObject(Object any) {
|
.lines()
|
||||||
super.linkObject(any);
|
.map(s -> {
|
||||||
|
try {
|
||||||
|
return Class.forName(s, false, BauSystem.class.getClassLoader());
|
||||||
|
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||||
|
if (e.getMessage().equals(s)) {
|
||||||
|
Bukkit.shutdown();
|
||||||
|
throw new SecurityException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
classes.forEach(clazz -> {
|
||||||
|
MinVersion minVersion = clazz.getAnnotation(MinVersion.class);
|
||||||
|
MaxVersion maxVersion = clazz.getAnnotation(MaxVersion.class);
|
||||||
|
PluginCheck[] pluginChecks = clazz.getAnnotationsByType(PluginCheck.class);
|
||||||
|
if (minVersion != null && Core.getVersion() < minVersion.value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (maxVersion != null && Core.getVersion() > maxVersion.value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (PluginCheck pluginCheck : pluginChecks) {
|
||||||
|
if (pluginCheck.has() == PluginCheck.Has.THIS && Bukkit.getPluginManager().getPlugin(pluginCheck.value()) != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pluginCheck.has() == PluginCheck.Has.NOT && Bukkit.getPluginManager().getPlugin(pluginCheck.value()) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object any;
|
||||||
|
try {
|
||||||
|
any = clazz.newInstance();
|
||||||
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
|
getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
Bukkit.shutdown();
|
||||||
|
throw new SecurityException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
instances.put(clazz, any);
|
||||||
|
if (any instanceof Enable) {
|
||||||
|
((Enable) any).enable();
|
||||||
|
}
|
||||||
|
if (any instanceof SWCommand) {
|
||||||
|
((SWCommand) any).setMessage(BauSystem.MESSAGE);
|
||||||
|
}
|
||||||
|
if (any instanceof Listener) {
|
||||||
|
Bukkit.getPluginManager().registerEvents((Listener) any, BauSystem.getInstance());
|
||||||
|
}
|
||||||
|
if (any instanceof PacketHandler) {
|
||||||
|
((PacketHandler) any).register();
|
||||||
|
}
|
||||||
if (any instanceof LuaLib) {
|
if (any instanceof LuaLib) {
|
||||||
SteamWarLuaPlugin.add((LuaLib) any);
|
SteamWarLuaPlugin.add((LuaLib) any);
|
||||||
}
|
}
|
||||||
@@ -110,53 +182,45 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
if (any instanceof PanzernAlgorithm) {
|
if (any instanceof PanzernAlgorithm) {
|
||||||
Panzern.add((PanzernAlgorithm) any);
|
Panzern.add((PanzernAlgorithm) any);
|
||||||
}
|
}
|
||||||
|
if (any instanceof ConfigConverter) {
|
||||||
|
Config.addConfigConverter((ConfigConverter) any);
|
||||||
|
}
|
||||||
if (any instanceof BoundingBoxLoader) {
|
if (any instanceof BoundingBoxLoader) {
|
||||||
((BoundingBoxLoader) any).load();
|
((BoundingBoxLoader) any).load();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
instances.forEach((clazz, o) -> {
|
||||||
|
for (Field field : clazz.getFields()) {
|
||||||
|
if (field.getAnnotation(LinkedInstance.class) != null) {
|
||||||
try {
|
try {
|
||||||
linker.addLinkableInstance(BauServer.getInstance());
|
field.set(o, instances.get(field.getType()));
|
||||||
linker.link();
|
} catch (IllegalAccessException e) {
|
||||||
} catch (AbstractLinker.LinkException e) {
|
throw new RuntimeException(e);
|
||||||
getLogger().log(Level.SEVERE, "Could not link a class.", e);
|
|
||||||
Bukkit.shutdown();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TickListener.impl.init();
|
||||||
|
|
||||||
TraceManager.instance.init();
|
TraceManager.instance.init();
|
||||||
TraceRecorder.instance.init();
|
TraceRecorder.instance.init();
|
||||||
|
|
||||||
SteamEdit.init();
|
|
||||||
SteamEdit.ADJACENT_FILTERS = location -> {
|
|
||||||
Region region = Region.getRegion(location);
|
|
||||||
Region.Area area;
|
|
||||||
if (region.getBuildArea().inRegion(location, true)) {
|
|
||||||
area = region.getBuildArea();
|
|
||||||
} else if (region.getTestblockArea().inRegion(location, true)) {
|
|
||||||
area = region.getTestblockArea();
|
|
||||||
} else {
|
|
||||||
return SteamEdit.AdjacentFilter.ALWAYS;
|
|
||||||
}
|
|
||||||
return (x, y, z) -> area.inRegion(new Location(null, x, y, z), true);
|
|
||||||
};
|
|
||||||
|
|
||||||
Bukkit.getWorlds().get(0).setGameRule(GameRule.SEND_COMMAND_FEEDBACK, false);
|
|
||||||
|
|
||||||
String identifier = BauServerInfo.getOwnerUser().getUUID().toString().replace("-", "");
|
|
||||||
WorldIdentifier.set("bau/" + Core.getVersion() + "/" + identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onCRIUSleep(CRIUSleepEvent event) {
|
|
||||||
RegionSystem.INSTANCE.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
linker.unlink();
|
instances.forEach((aClass, o) -> {
|
||||||
RegionSystem.INSTANCE.save();
|
if (o instanceof Listener) {
|
||||||
ConfigStore.saveAll();
|
HandlerList.unregisterAll((Listener) o);
|
||||||
|
}
|
||||||
|
if (o instanceof Disable) {
|
||||||
|
((Disable) o).disable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
WorldData.write();
|
||||||
|
Config.getInstance().saveAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends CommandSender> AbstractValidator<T, ?> validator(Permission permission) {
|
private <T extends CommandSender> AbstractValidator<T, ?> validator(Permission permission) {
|
||||||
@@ -199,7 +263,7 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (TickManager.impl.isFrozen()) return;
|
if (TPSFreezeUtils.isFrozen()) return;
|
||||||
if (counter >= delay) {
|
if (counter >= delay) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
cancel();
|
cancel();
|
||||||
@@ -217,7 +281,7 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (TickManager.impl.isFrozen()) return;
|
if (TPSFreezeUtils.isFrozen()) return;
|
||||||
if (counter >= (first ? delay : period)) {
|
if (counter >= (first ? delay : period)) {
|
||||||
first = false;
|
first = false;
|
||||||
runnable.run();
|
runnable.run();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,12 +21,15 @@ package de.steamwar.bausystem;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.config.BauServer;
|
import de.steamwar.bausystem.config.BauServer;
|
||||||
import de.steamwar.bausystem.features.world.BauMemberUpdate;
|
import de.steamwar.bausystem.features.world.BauMemberUpdate;
|
||||||
import de.steamwar.bausystem.linkage.GuiItem;
|
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
||||||
import de.steamwar.sql.BauweltMember;
|
import de.steamwar.sql.BauweltMember;
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@@ -37,21 +40,44 @@ public enum Permission {
|
|||||||
return bauweltMember.isSupervisor();
|
return bauweltMember.isSupervisor();
|
||||||
}),
|
}),
|
||||||
BUILD(bauweltMember -> {
|
BUILD(bauweltMember -> {
|
||||||
|
if (isTempOnlySpectator(bauweltMember)) return false;
|
||||||
return bauweltMember.isBuild() || SUPERVISOR.permissionPredicate.test(bauweltMember);
|
return bauweltMember.isBuild() || SUPERVISOR.permissionPredicate.test(bauweltMember);
|
||||||
}),
|
}),
|
||||||
/**
|
/**
|
||||||
* Only used for {@link BauMemberUpdate}
|
* Only used for {@link BauMemberUpdate}
|
||||||
*/
|
*/
|
||||||
SPECTATOR(bauweltMember -> {
|
REAL_SPECTATOR(bauweltMember -> {
|
||||||
return !bauweltMember.isBuild() && !bauweltMember.isSupervisor();
|
return !bauweltMember.isBuild() && !bauweltMember.isSupervisor();
|
||||||
}),
|
}),
|
||||||
/**
|
/**
|
||||||
* Primarily used for {@link GuiItem}
|
* Primarily used for {@link de.steamwar.bausystem.linkage.specific.GuiItem}
|
||||||
*/
|
*/
|
||||||
MEMBER(bauweltMember -> {
|
MEMBER(bauweltMember -> {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private static final Set<Integer> TEMP_ONLY_SPECTATOR = new HashSet<>();
|
||||||
|
|
||||||
|
private static boolean isTempOnlySpectator(BauweltMember bauweltMember) {
|
||||||
|
return TEMP_ONLY_SPECTATOR.contains(bauweltMember.getMemberID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTempOnlySpectator(Player player) {
|
||||||
|
return TEMP_ONLY_SPECTATOR.contains(SteamwarUser.get(player.getUniqueId()).getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void forceOnlySpectator(Player player) {
|
||||||
|
TEMP_ONLY_SPECTATOR.add(SteamwarUser.get(player.getUniqueId()).getId());
|
||||||
|
BauMemberUpdate.baumemberUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only used by {@link BauMemberUpdate}
|
||||||
|
*/
|
||||||
|
public static void removeForceOnlySpectator(Player player) {
|
||||||
|
TEMP_ONLY_SPECTATOR.remove(SteamwarUser.get(player.getUniqueId()).getId());
|
||||||
|
}
|
||||||
|
|
||||||
private final Predicate<BauweltMember> permissionPredicate;
|
private final Predicate<BauweltMember> permissionPredicate;
|
||||||
|
|
||||||
public boolean hasPermission(BauweltMember bauweltMember) {
|
public boolean hasPermission(BauweltMember bauweltMember) {
|
||||||
@@ -61,10 +87,10 @@ public enum Permission {
|
|||||||
|
|
||||||
public boolean hasPermission(Player member) {
|
public boolean hasPermission(Player member) {
|
||||||
if (SteamwarUser.get(member.getUniqueId()).getId() == BauServer.getInstance().getOwnerID()) {
|
if (SteamwarUser.get(member.getUniqueId()).getId() == BauServer.getInstance().getOwnerID()) {
|
||||||
return this != SPECTATOR;
|
return this != REAL_SPECTATOR;
|
||||||
}
|
}
|
||||||
BauweltMember bauweltMember = BauweltMember.getBauMember(BauServer.getInstance().getOwner(), member.getUniqueId());
|
BauweltMember bauweltMember = BauweltMember.getBauMember(BauServer.getInstance().getOwner(), member.getUniqueId());
|
||||||
if (bauweltMember == null) return this == SPECTATOR;
|
if (bauweltMember == null) return this == REAL_SPECTATOR;
|
||||||
return permissionPredicate.test(bauweltMember);
|
return permissionPredicate.test(bauweltMember);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -36,7 +36,7 @@ public class BauServer {
|
|||||||
private Integer owner;
|
private Integer owner;
|
||||||
|
|
||||||
public UUID getOwner() {
|
public UUID getOwner() {
|
||||||
return SteamwarUser.byId(getOwnerID()).getUUID();
|
return SteamwarUser.get(getOwnerID()).getUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOwnerID() {
|
public int getOwnerID() {
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a config of one version into the next version, e.g. ConfigV1 to
|
|
||||||
* ConfigV2. The converter for the second newest version converts into the
|
|
||||||
* current version. Converters are registered in the {@link ConfigStore}
|
|
||||||
* of the config.
|
|
||||||
*
|
|
||||||
* @param <F> the config version to convert from
|
|
||||||
* @param <T> the config version to convert to
|
|
||||||
*/
|
|
||||||
public interface ConfigConverter<F extends VersionedConfig, T extends VersionedConfig> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the version this converter converts from
|
|
||||||
*/
|
|
||||||
int version();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the config to the next version. If anything goes wrong do not
|
|
||||||
* silently exit this method, throw an Exception. The {@link ConfigStore}
|
|
||||||
* will deal with it.
|
|
||||||
*
|
|
||||||
* @param config the config to convert
|
|
||||||
* @return the converted config
|
|
||||||
*/
|
|
||||||
T convert(F config);
|
|
||||||
}
|
|
||||||
@@ -1,364 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.config;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import de.steamwar.sql.UserConfig;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads, converts and saves a versioned config stored as JSON. Older versions
|
|
||||||
* are converted with the registered {@link ConfigConverter}s, legacy formats
|
|
||||||
* that are not JSON can be read with {@link #legacy(Predicate, Function)}.
|
|
||||||
* <p>
|
|
||||||
* A store can be bound to where the config is stored:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link #userConfig(String)}: one config per player in the {@link UserConfig}, use {@link #get(Player)}</li>
|
|
||||||
* <li>{@link #file(File)}: one config in a file, use {@link #get()}</li>
|
|
||||||
* <li>unbound: use {@link #load(File)} and {@link #save(File, VersionedConfig)}</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param <T> the current config version
|
|
||||||
*/
|
|
||||||
public class ConfigStore<T extends VersionedConfig> {
|
|
||||||
|
|
||||||
private static final List<ConfigStore<?>> STORES = new ArrayList<>();
|
|
||||||
|
|
||||||
private final Class<T> type;
|
|
||||||
private final int version;
|
|
||||||
private final Supplier<T> defaultConfig;
|
|
||||||
|
|
||||||
private final Map<Integer, Class<? extends VersionedConfig>> jsonVersions = new HashMap<>();
|
|
||||||
private final Map<Integer, ConfigConverter<?, ?>> converters = new HashMap<>();
|
|
||||||
private final List<LegacyFormat> legacyFormats = new ArrayList<>();
|
|
||||||
private Gson gson = new Gson();
|
|
||||||
private Integer unversionedVersion = null;
|
|
||||||
|
|
||||||
private String userConfigKey = null;
|
|
||||||
private Predicate<T> removeIf = config -> false;
|
|
||||||
private final Map<UUID, T> playerConfigs = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private File file = null;
|
|
||||||
private File legacyFile = null;
|
|
||||||
private Function<String, ? extends VersionedConfig> legacyFileReader = null;
|
|
||||||
private T fileConfig = null;
|
|
||||||
|
|
||||||
private record LegacyFormat(Predicate<String> matches, Function<String, ? extends VersionedConfig> reader) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConfigStore(Class<T> type, int version, Supplier<T> defaultConfig) {
|
|
||||||
this.type = type;
|
|
||||||
this.version = version;
|
|
||||||
this.defaultConfig = defaultConfig;
|
|
||||||
jsonVersions.put(version, type);
|
|
||||||
STORES.add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConfigStore<T> gson(Gson gson) {
|
|
||||||
this.gson = gson;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers an older config version that is stored as JSON.
|
|
||||||
*/
|
|
||||||
public ConfigStore<T> jsonVersion(int version, Class<? extends VersionedConfig> type) {
|
|
||||||
jsonVersions.put(version, type);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConfigStore<T> converter(ConfigConverter<?, ?> converter) {
|
|
||||||
if (converters.putIfAbsent(converter.version(), converter) != null) {
|
|
||||||
throw new IllegalStateException("Duplicate converter for version " + converter.version() + " of " + type.getSimpleName());
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a legacy format that is not JSON, stored strings matching the predicate are read by the reader.
|
|
||||||
*/
|
|
||||||
public ConfigStore<T> legacy(Predicate<String> matches, Function<String, ? extends VersionedConfig> reader) {
|
|
||||||
legacyFormats.add(new LegacyFormat(matches, reader));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The version of stored JSON without a version field.
|
|
||||||
*/
|
|
||||||
public ConfigStore<T> unversioned(int version) {
|
|
||||||
this.unversionedVersion = version;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds this store to the {@link UserConfig} with the given key, one config per player.
|
|
||||||
*/
|
|
||||||
public ConfigStore<T> userConfig(String key) {
|
|
||||||
this.userConfigKey = key;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the config from the {@link UserConfig} instead of saving it, if the predicate matches.
|
|
||||||
*/
|
|
||||||
public ConfigStore<T> removeIf(Predicate<T> removeIf) {
|
|
||||||
this.removeIf = removeIf;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds this store to a single file.
|
|
||||||
*/
|
|
||||||
public ConfigStore<T> file(File file) {
|
|
||||||
this.file = file;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Legacy file to read, if the file of this store does not exist yet.
|
|
||||||
*/
|
|
||||||
public ConfigStore<T> legacyFile(File legacyFile, Function<String, ? extends VersionedConfig> reader) {
|
|
||||||
this.legacyFile = legacyFile;
|
|
||||||
this.legacyFileReader = reader;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a stored config and converts it to the current version.
|
|
||||||
*
|
|
||||||
* @throws RuntimeException if the config could not be read or converted
|
|
||||||
*/
|
|
||||||
public T read(String stored) {
|
|
||||||
for (LegacyFormat legacyFormat : legacyFormats) {
|
|
||||||
if (legacyFormat.matches().test(stored)) {
|
|
||||||
return update(legacyFormat.reader().apply(stored));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonObject json = JsonParser.parseString(stored).getAsJsonObject();
|
|
||||||
int storedVersion;
|
|
||||||
if (json.has("version")) {
|
|
||||||
storedVersion = json.get("version").getAsInt();
|
|
||||||
} else if (unversionedVersion != null) {
|
|
||||||
storedVersion = unversionedVersion;
|
|
||||||
json.addProperty("version", storedVersion);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Missing version of " + type.getSimpleName());
|
|
||||||
}
|
|
||||||
Class<? extends VersionedConfig> storedType = jsonVersions.get(storedVersion);
|
|
||||||
if (storedType == null) {
|
|
||||||
throw new IllegalStateException("Unknown version " + storedVersion + " of " + type.getSimpleName());
|
|
||||||
}
|
|
||||||
return update(gson.fromJson(json, storedType));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String write(T config) {
|
|
||||||
return gson.toJson(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a config to the current version.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
public T update(VersionedConfig config) {
|
|
||||||
while (config.getVersion() < version) {
|
|
||||||
ConfigConverter converter = converters.get(config.getVersion());
|
|
||||||
if (converter == null) {
|
|
||||||
throw new IllegalStateException("No converter found for version " + config.getVersion() + " of " + type.getSimpleName());
|
|
||||||
}
|
|
||||||
VersionedConfig converted = converter.convert(config);
|
|
||||||
if (converted.getVersion() <= config.getVersion()) {
|
|
||||||
throw new IllegalStateException("Version did not increase after conversion of version " + config.getVersion() + " of " + type.getSimpleName());
|
|
||||||
}
|
|
||||||
config = converted;
|
|
||||||
}
|
|
||||||
if (!type.isInstance(config)) {
|
|
||||||
throw new IllegalStateException("Version " + config.getVersion() + " is not the current version of " + type.getSimpleName());
|
|
||||||
}
|
|
||||||
return type.cast(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the config stored in the file, or the default config if the file is missing or empty
|
|
||||||
* @throws RuntimeException if the config could not be read or converted
|
|
||||||
*/
|
|
||||||
public T load(File file) throws IOException {
|
|
||||||
if (file.length() == 0) {
|
|
||||||
return defaultConfig.get();
|
|
||||||
}
|
|
||||||
return read(Files.readString(file.toPath(), StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(File file, T config) throws IOException {
|
|
||||||
Files.writeString(file.toPath(), write(config), StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the config of a player, loads it from the {@link UserConfig} and converts it if necessary.
|
|
||||||
*/
|
|
||||||
public T get(Player player) {
|
|
||||||
requireUserConfig();
|
|
||||||
return playerConfigs.computeIfAbsent(player.getUniqueId(), this::loadPlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the config of a player, this does not unload the config.
|
|
||||||
*/
|
|
||||||
public void save(Player player) {
|
|
||||||
requireUserConfig();
|
|
||||||
T config = playerConfigs.get(player.getUniqueId());
|
|
||||||
if (config != null) {
|
|
||||||
savePlayer(player.getUniqueId(), config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save and unload the config of a player.
|
|
||||||
*/
|
|
||||||
public void unload(Player player) {
|
|
||||||
if (userConfigKey == null) return;
|
|
||||||
T config = playerConfigs.remove(player.getUniqueId());
|
|
||||||
if (config != null) {
|
|
||||||
savePlayer(player.getUniqueId(), config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private T loadPlayer(UUID uuid) {
|
|
||||||
String stored = UserConfig.getConfig(uuid, userConfigKey);
|
|
||||||
if (stored == null) {
|
|
||||||
return defaultConfig.get();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return read(stored);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "Could not load " + type.getSimpleName() + " of " + uuid, e);
|
|
||||||
return defaultConfig.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void savePlayer(UUID uuid, T config) {
|
|
||||||
if (removeIf.test(config)) {
|
|
||||||
UserConfig.removePlayerConfig(uuid, userConfigKey);
|
|
||||||
} else {
|
|
||||||
UserConfig.updatePlayerConfig(uuid, userConfigKey, write(config));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requireUserConfig() {
|
|
||||||
if (userConfigKey == null) {
|
|
||||||
throw new IllegalStateException(type.getSimpleName() + " is not stored in the UserConfig");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the config of the file of this store, loads it and converts it if necessary.
|
|
||||||
*/
|
|
||||||
public T get() {
|
|
||||||
requireFile();
|
|
||||||
if (fileConfig == null) {
|
|
||||||
fileConfig = loadFile();
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
return fileConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the config to the file of this store, if it was loaded.
|
|
||||||
*/
|
|
||||||
public void save() {
|
|
||||||
requireFile();
|
|
||||||
if (fileConfig == null) return;
|
|
||||||
try {
|
|
||||||
save(file, fileConfig);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "Could not write " + file, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private T loadFile() {
|
|
||||||
try {
|
|
||||||
if (file.length() != 0) {
|
|
||||||
return load(file);
|
|
||||||
}
|
|
||||||
if (legacyFile != null && legacyFile.length() != 0) {
|
|
||||||
return update(legacyFileReader.apply(Files.readString(legacyFile.toPath(), StandardCharsets.UTF_8)));
|
|
||||||
}
|
|
||||||
return defaultConfig.get();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "Could not load " + file + ", using default " + type.getSimpleName(), e);
|
|
||||||
backupBrokenFile();
|
|
||||||
return defaultConfig.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void backupBrokenFile() {
|
|
||||||
if (file.length() == 0) return;
|
|
||||||
try {
|
|
||||||
Files.copy(file.toPath(), new File(file.getParentFile(), file.getName() + ".broken").toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "Could not backup broken " + file, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requireFile() {
|
|
||||||
if (file == null) {
|
|
||||||
throw new IllegalStateException(type.getSimpleName() + " is not bound to a file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unloadAll(Player player) {
|
|
||||||
STORES.forEach(store -> store.unload(player));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves every loaded config and unloads the configs of the players.
|
|
||||||
*/
|
|
||||||
public static void saveAll() {
|
|
||||||
for (ConfigStore<?> store : STORES) {
|
|
||||||
if (store.userConfigKey != null) {
|
|
||||||
store.playerConfigs.forEach((uuid, config) -> saveUnchecked(store, uuid, config));
|
|
||||||
store.playerConfigs.clear();
|
|
||||||
}
|
|
||||||
if (store.file != null) {
|
|
||||||
store.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static <T extends VersionedConfig> void saveUnchecked(ConfigStore<T> store, UUID uuid, Object config) {
|
|
||||||
store.savePlayer(uuid, (T) config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.config;
|
|
||||||
|
|
||||||
import de.steamwar.core.CRIUSleepEvent;
|
|
||||||
import de.steamwar.linkage.Linked;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves and unloads the configs of the {@link ConfigStore}s bound to the UserConfig
|
|
||||||
* when a player quits, configs are loaded on first use.
|
|
||||||
*/
|
|
||||||
@Linked
|
|
||||||
public class ConfigStoreListener implements Listener {
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
|
||||||
ConfigStore.unloadAll(event.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onCRIUSleep(CRIUSleepEvent event) {
|
|
||||||
ConfigStore.saveAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-95
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.config.legacy;
|
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserializes {@link ItemStack}s that were serialized by YAPION, read with {@link YapionReader}.
|
|
||||||
*/
|
|
||||||
@UtilityClass
|
|
||||||
@Deprecated
|
|
||||||
public class YapionItemDeserializer {
|
|
||||||
|
|
||||||
private static final String TYPE_IDENTIFIER = "@type";
|
|
||||||
|
|
||||||
public ItemStack deserializeItem(Object yapion) {
|
|
||||||
if (yapion == null) return null;
|
|
||||||
Object result = deserialize(yapion);
|
|
||||||
if (result instanceof ItemStack itemStack) return itemStack;
|
|
||||||
throw new IllegalArgumentException("Not an ItemStack: " + result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object deserialize(Object yapion) {
|
|
||||||
if (yapion instanceof List<?> list) {
|
|
||||||
List<Object> result = new ArrayList<>();
|
|
||||||
list.forEach(o -> result.add(deserialize(o)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (yapion instanceof YapionReader.YapionMap map) {
|
|
||||||
Map<Object, Object> result = new LinkedHashMap<>();
|
|
||||||
map.entries().forEach((key, value) -> result.put(deserialize(key), deserialize(value)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (yapion instanceof Map<?, ?> object) {
|
|
||||||
return deserializeObject(object);
|
|
||||||
}
|
|
||||||
return yapion;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object deserializeObject(Map<?, ?> object) {
|
|
||||||
Map<String, Object> data = new LinkedHashMap<>();
|
|
||||||
object.forEach((key, value) -> {
|
|
||||||
if (!TYPE_IDENTIFIER.equals(key)) data.put((String) key, deserialize(value));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!(object.get(TYPE_IDENTIFIER) instanceof String type)) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<?> javaType = javaUtilClass(type);
|
|
||||||
if (javaType != null && Collection.class.isAssignableFrom(javaType)) {
|
|
||||||
return data.getOrDefault("values", new ArrayList<>());
|
|
||||||
}
|
|
||||||
if (javaType != null && Map.class.isAssignableFrom(javaType)) {
|
|
||||||
return data.containsKey("values") ? data.get("values") : data;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, type.equals("org.bukkit.inventory.meta.ItemMeta") ? "ItemMeta" : type);
|
|
||||||
return ConfigurationSerialization.deserializeObject(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> javaUtilClass(String type) {
|
|
||||||
if (!type.startsWith("java.util.")) return null;
|
|
||||||
try {
|
|
||||||
return Class.forName(type);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,323 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.config.legacy;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimal reader for the legacy YAPION format, only used to migrate old data.
|
|
||||||
* <p>
|
|
||||||
* The result is built from plain java objects:
|
|
||||||
* <ul>
|
|
||||||
* <li>YAPION objects {@code {key(value)}} become a {@link LinkedHashMap} of String to value</li>
|
|
||||||
* <li>YAPION arrays {@code [a,b]} become a {@link List}</li>
|
|
||||||
* <li>YAPION maps {@code <(a):(b)>} become a {@link YapionMap}</li>
|
|
||||||
* <li>YAPION values {@code (value)} become null, Boolean, Number or String</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class YapionReader {
|
|
||||||
|
|
||||||
private static final Pattern INTEGER = Pattern.compile("[-+]?\\d+");
|
|
||||||
private static final Pattern DECIMAL = Pattern.compile("[-+]?(\\d+\\.\\d*|\\.\\d+|\\d+)([eE][-+]?\\d+)?");
|
|
||||||
|
|
||||||
public record YapionMap(Map<Object, Object> entries) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, Object> parse(String yapion) {
|
|
||||||
YapionReader reader = new YapionReader(yapion);
|
|
||||||
reader.skipWhitespace();
|
|
||||||
Map<String, Object> result = reader.readObject();
|
|
||||||
reader.skipWhitespace();
|
|
||||||
if (reader.index != yapion.length()) {
|
|
||||||
throw reader.error("Unexpected trailing content");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getDouble(Map<?, ?> object, String key, double defaultValue) {
|
|
||||||
return object.get(key) instanceof Number value ? value.doubleValue() : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getInt(Map<?, ?> object, String key, int defaultValue) {
|
|
||||||
return object.get(key) instanceof Number value ? value.intValue() : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getBoolean(Map<?, ?> object, String key, boolean defaultValue) {
|
|
||||||
return object.get(key) instanceof Boolean value ? value : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getString(Map<?, ?> object, String key, String defaultValue) {
|
|
||||||
return object.get(key) instanceof String value ? value : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the entries of the array that are YAPION objects
|
|
||||||
*/
|
|
||||||
public static List<Map<?, ?>> getObjects(Map<?, ?> object, String key) {
|
|
||||||
List<Map<?, ?>> objects = new ArrayList<>();
|
|
||||||
if (object.get(key) instanceof List<?> array) {
|
|
||||||
array.forEach(o -> {
|
|
||||||
if (o instanceof Map<?, ?> map) objects.add(map);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String input;
|
|
||||||
private int index = 0;
|
|
||||||
|
|
||||||
private YapionReader(String input) {
|
|
||||||
this.input = input;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object readAny() {
|
|
||||||
return switch (peek()) {
|
|
||||||
case '{' -> readObject();
|
|
||||||
case '[' -> readArray();
|
|
||||||
case '<' -> readMap();
|
|
||||||
case '(' -> readValue();
|
|
||||||
default -> throw error("Expected '{', '[', '<' or '('");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> readObject() {
|
|
||||||
expect('{');
|
|
||||||
Map<String, Object> object = new LinkedHashMap<>();
|
|
||||||
while (true) {
|
|
||||||
skipWhitespace();
|
|
||||||
if (peek() == '}') {
|
|
||||||
index++;
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
StringBuilder key = new StringBuilder();
|
|
||||||
while (true) {
|
|
||||||
char c = peek();
|
|
||||||
if (c == '(' || c == '{' || c == '[' || c == '<') break;
|
|
||||||
if (c == '}') throw error("Key without value");
|
|
||||||
key.append(readChar());
|
|
||||||
}
|
|
||||||
object.put(key.toString(), readAny());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Object> readArray() {
|
|
||||||
expect('[');
|
|
||||||
List<Object> array = new ArrayList<>();
|
|
||||||
skipWhitespace();
|
|
||||||
if (peek() == ']') {
|
|
||||||
index++;
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
while (true) {
|
|
||||||
int start = index;
|
|
||||||
skipWhitespace();
|
|
||||||
char c = peek();
|
|
||||||
if (c == '{' || c == '[' || c == '<' || c == '(') {
|
|
||||||
array.add(readAny());
|
|
||||||
skipWhitespace();
|
|
||||||
} else {
|
|
||||||
// Whitespace is part of plain values
|
|
||||||
index = start;
|
|
||||||
StringBuilder value = new StringBuilder();
|
|
||||||
while (peek() != ',' && peek() != ']') {
|
|
||||||
value.append(readChar());
|
|
||||||
}
|
|
||||||
array.add(typed(value.toString()));
|
|
||||||
}
|
|
||||||
char separator = input.charAt(index++);
|
|
||||||
if (separator == ']') return array;
|
|
||||||
if (separator != ',') throw error("Expected ',' or ']'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private YapionMap readMap() {
|
|
||||||
expect('<');
|
|
||||||
Map<Object, Object> map = new LinkedHashMap<>();
|
|
||||||
while (true) {
|
|
||||||
skipWhitespace();
|
|
||||||
if (peek() == '>') {
|
|
||||||
index++;
|
|
||||||
return new YapionMap(map);
|
|
||||||
}
|
|
||||||
Object key = readAny();
|
|
||||||
skipWhitespace();
|
|
||||||
expect(':');
|
|
||||||
skipWhitespace();
|
|
||||||
map.put(key, readAny());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* YAPION does not escape parentheses in values, balanced parentheses are part of the value.
|
|
||||||
* A backslash only escapes a backslash, a unicode sequence or a control character, otherwise it is kept.
|
|
||||||
*/
|
|
||||||
private Object readValue() {
|
|
||||||
expect('(');
|
|
||||||
StringBuilder value = new StringBuilder();
|
|
||||||
int depth = 0;
|
|
||||||
while (true) {
|
|
||||||
char c = peek();
|
|
||||||
if (c == '\\') {
|
|
||||||
value.append(readValueEscape());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
if (c == '(') {
|
|
||||||
depth++;
|
|
||||||
} else if (c == ')') {
|
|
||||||
if (depth == 0) break;
|
|
||||||
depth--;
|
|
||||||
}
|
|
||||||
value.append(c);
|
|
||||||
}
|
|
||||||
return typed(value.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readValueEscape() {
|
|
||||||
index++;
|
|
||||||
if (index >= input.length()) return "\\";
|
|
||||||
char escaped = input.charAt(index);
|
|
||||||
switch (escaped) {
|
|
||||||
case '\\', '(', ')':
|
|
||||||
index++;
|
|
||||||
return String.valueOf(escaped);
|
|
||||||
case 'n':
|
|
||||||
index++;
|
|
||||||
return "\n";
|
|
||||||
case 't':
|
|
||||||
index++;
|
|
||||||
return "\t";
|
|
||||||
case 'r':
|
|
||||||
index++;
|
|
||||||
return "\r";
|
|
||||||
case 'u':
|
|
||||||
if (index + 5 <= input.length() && input.substring(index + 1, index + 5).matches("[0-9a-fA-F]{4}")) {
|
|
||||||
char unicode = (char) Integer.parseInt(input.substring(index + 1, index + 5), 16);
|
|
||||||
index += 5;
|
|
||||||
return String.valueOf(unicode);
|
|
||||||
}
|
|
||||||
return "\\";
|
|
||||||
default:
|
|
||||||
return "\\";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads one character of a key or plain array value, resolving backslash escapes.
|
|
||||||
* A backslash that does not escape anything is kept, as the old player config
|
|
||||||
* collapsed escaped backslashes into a single one.
|
|
||||||
*/
|
|
||||||
private char readChar() {
|
|
||||||
char c = input.charAt(index++);
|
|
||||||
if (c != '\\') return c;
|
|
||||||
if (index >= input.length()) throw error("Unterminated escape");
|
|
||||||
char escaped = input.charAt(index);
|
|
||||||
switch (escaped) {
|
|
||||||
case 'n':
|
|
||||||
index++;
|
|
||||||
return '\n';
|
|
||||||
case 't':
|
|
||||||
index++;
|
|
||||||
return '\t';
|
|
||||||
case 'r':
|
|
||||||
index++;
|
|
||||||
return '\r';
|
|
||||||
case 'u':
|
|
||||||
if (index + 5 <= input.length() && input.substring(index + 1, index + 5).matches("[0-9a-fA-F]{4}")) {
|
|
||||||
char unicode = (char) Integer.parseInt(input.substring(index + 1, index + 5), 16);
|
|
||||||
index += 5;
|
|
||||||
return unicode;
|
|
||||||
}
|
|
||||||
return '\\';
|
|
||||||
case '\\', ',', ' ', '(', ')', '{', '}', '[', ']', '<', '>', '"', ':', '@':
|
|
||||||
index++;
|
|
||||||
return escaped;
|
|
||||||
default:
|
|
||||||
return '\\';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Object typed(String value) {
|
|
||||||
if (value.equals("null")) return null;
|
|
||||||
if (value.equals("true")) return true;
|
|
||||||
if (value.equals("false")) return false;
|
|
||||||
if (value.length() >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
|
|
||||||
return value.substring(1, value.length() - 1);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (INTEGER.matcher(value).matches()) {
|
|
||||||
long l = Long.parseLong(value);
|
|
||||||
if (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE) return (int) l;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
if (value.length() > 1) {
|
|
||||||
String number = value.substring(0, value.length() - 1);
|
|
||||||
switch (value.charAt(value.length() - 1)) {
|
|
||||||
case 'L':
|
|
||||||
if (INTEGER.matcher(number).matches()) return Long.parseLong(number);
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
if (INTEGER.matcher(number).matches()) return Short.parseShort(number);
|
|
||||||
break;
|
|
||||||
case 'B':
|
|
||||||
if (INTEGER.matcher(number).matches()) return Byte.parseByte(number);
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
if (DECIMAL.matcher(number).matches()) return Float.parseFloat(number);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
if (DECIMAL.matcher(number).matches()) return Double.parseDouble(number);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DECIMAL.matcher(value).matches()) return Double.parseDouble(value);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// Not a number, fall through to String
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void skipWhitespace() {
|
|
||||||
while (index < input.length() && Character.isWhitespace(input.charAt(index))) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private char peek() {
|
|
||||||
if (index >= input.length()) throw error("Unexpected end of input");
|
|
||||||
return input.charAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void expect(char c) {
|
|
||||||
if (peek() != c) throw error("Expected '" + c + "'");
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IllegalArgumentException error(String message) {
|
|
||||||
return new IllegalArgumentException(message + " at index " + index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-63
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.config.serializer;
|
|
||||||
|
|
||||||
import com.google.gson.TypeAdapter;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonToken;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores an {@link ItemStack} as Base64 of {@link ItemStack#serializeAsBytes()}, which
|
|
||||||
* contains the data version and gets upgraded on newer Minecraft versions.
|
|
||||||
* Empty items are stored as null, items that can't be read are deserialized as null.
|
|
||||||
*/
|
|
||||||
public class ItemStackTypeAdapter extends TypeAdapter<ItemStack> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(JsonWriter out, ItemStack itemStack) throws IOException {
|
|
||||||
if (itemStack == null || itemStack.isEmpty()) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
out.value(Base64.getEncoder().encodeToString(itemStack.serializeAsBytes()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack read(JsonReader in) throws IOException {
|
|
||||||
if (in.peek() == JsonToken.NULL) {
|
|
||||||
in.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String value = in.nextString();
|
|
||||||
try {
|
|
||||||
return ItemStack.deserializeBytes(Base64.getDecoder().decode(value));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "Could not deserialize ItemStack", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -19,77 +19,129 @@
|
|||||||
|
|
||||||
package de.steamwar.bausystem.configplayer;
|
package de.steamwar.bausystem.configplayer;
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
import de.steamwar.bausystem.configplayer.serializer.ConfigurationSerializableSerializer;
|
||||||
import de.steamwar.bausystem.config.ConfigConverter;
|
import de.steamwar.linkage.Linked;
|
||||||
import de.steamwar.bausystem.config.ConfigStore;
|
import de.steamwar.sql.UserConfig;
|
||||||
import de.steamwar.bausystem.config.VersionedConfig;
|
|
||||||
import de.steamwar.bausystem.config.serializer.ItemStackTypeAdapter;
|
|
||||||
import de.steamwar.bausystem.configplayer.converter.ConfigV1ToV2Converter;
|
|
||||||
import de.steamwar.bausystem.features.hotbar.DefaultHotbar;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.inventory.ItemStack;
|
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 yapion.hierarchy.output.StringOutput;
|
||||||
|
import yapion.hierarchy.types.YAPIONObject;
|
||||||
|
import yapion.parser.YAPIONParser;
|
||||||
|
import yapion.serializing.SerializeManager;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
@Linked
|
||||||
* The current player config. It is stored as JSON, fields missing in the
|
public class Config implements Listener {
|
||||||
* stored JSON keep the default value of their initializer, so adding a new
|
|
||||||
* field does not need a new version.
|
|
||||||
* <p>
|
|
||||||
* When a field gets removed, renamed or its meaning changes, copy this class
|
|
||||||
* to ConfigV{@link #VERSION} (without the {@link #STORE}), increase {@link #VERSION},
|
|
||||||
* write a {@link ConfigConverter} from the copy to this class and register it in the {@link #STORE}.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class Config implements VersionedConfig {
|
|
||||||
|
|
||||||
public static final int VERSION = 2;
|
static {
|
||||||
|
SerializeManager.add(new ConfigurationSerializableSerializer());
|
||||||
|
}
|
||||||
|
|
||||||
public static final ConfigStore<Config> STORE = new ConfigStore<>(Config.class, VERSION, Config::new)
|
@Getter
|
||||||
.gson(new GsonBuilder().registerTypeHierarchyAdapter(ItemStack.class, new ItemStackTypeAdapter()).create())
|
private static Config instance;
|
||||||
.legacy(s -> s.startsWith("{@version(1)"), ConfigV1::parse)
|
|
||||||
.converter(new ConfigV1ToV2Converter())
|
|
||||||
.userConfig("bausystem");
|
|
||||||
|
|
||||||
@Setter(AccessLevel.NONE)
|
{
|
||||||
protected int version = VERSION;
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<UUID, YAPIONObject> playerConfigurations = new HashMap<>();
|
||||||
|
|
||||||
|
private static final Map<Integer, ConfigConverter> CONFIG_CONVERTER_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
public static void addConfigConverter(ConfigConverter configConverter) {
|
||||||
|
CONFIG_CONVERTER_MAP.putIfAbsent(configConverter.version(), configConverter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
get(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
save(event.getPlayer());
|
||||||
|
playerConfigurations.remove(event.getPlayer().getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BauGui item id to inventory slot
|
* Get a PlayerConfig, optionally loads it from the DataBase and migrates it if necessary.
|
||||||
|
*
|
||||||
|
* @param player the player from whom to get the config.
|
||||||
|
* @return the config object
|
||||||
*/
|
*/
|
||||||
protected Map<Integer, Integer> bauGui = defaultBauGui();
|
public YAPIONObject get(Player player) {
|
||||||
protected int bauGuiSize = 45;
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (!playerConfigurations.containsKey(uuid)) {
|
||||||
|
String s = UserConfig.getConfig(uuid, "bausystem");
|
||||||
|
YAPIONObject yapionObject;
|
||||||
|
if (s == null) {
|
||||||
|
yapionObject = ConfigCreator.createDefaultConfig();
|
||||||
|
} else {
|
||||||
|
yapionObject = YAPIONParser.parse(s);
|
||||||
|
}
|
||||||
|
yapionObject = update(yapionObject);
|
||||||
|
playerConfigurations.put(uuid, yapionObject);
|
||||||
|
return yapionObject;
|
||||||
|
}
|
||||||
|
return playerConfigurations.get(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveAll() {
|
||||||
|
playerConfigurations.forEach((uuid, yapionObject) -> {
|
||||||
|
String string = yapionObject.toYAPION(new StringOutput()).getResult().replaceAll("\\+", "\\");
|
||||||
|
UserConfig.updatePlayerConfig(uuid, "bausystem", string);
|
||||||
|
});
|
||||||
|
playerConfigurations.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slots 0-8 are the hotbar, slots 9-12 the armor contents
|
* Save a PlayerConfig, this does not remove the key value mapping from the map.
|
||||||
|
*
|
||||||
|
* @param player the player to save the config.
|
||||||
*/
|
*/
|
||||||
protected ItemStack[] hotbar = DefaultHotbar.defaultHotbar();
|
public void save(Player player) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (playerConfigurations.containsKey(uuid)) {
|
||||||
|
YAPIONObject yapionObject = playerConfigurations.get(uuid);
|
||||||
|
String string = yapionObject.toYAPION(new StringOutput()).getResult().replaceAll("\\\\+", "\\\\");
|
||||||
|
UserConfig.updatePlayerConfig(uuid, "bausystem", string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean nightVision = false;
|
private YAPIONObject update(YAPIONObject yapionObject) {
|
||||||
protected boolean tntClickDetails = true;
|
int version = yapionObject.getPlainValue("@version");
|
||||||
protected boolean detonatorAutostart = false;
|
while (version < ConfigCreator.currentVersion) {
|
||||||
protected boolean inventoryFill = false;
|
ConfigConverter configConverter = CONFIG_CONVERTER_MAP.getOrDefault(version, null);
|
||||||
protected boolean rayVisualizer = false;
|
if (configConverter == null) {
|
||||||
protected boolean smartPlace = false;
|
Bukkit.getLogger().log(Level.SEVERE, "No updater found for version " + version);
|
||||||
protected boolean blockCounter = false;
|
return ConfigCreator.createDefaultConfig();
|
||||||
protected boolean depthMessage = true;
|
}
|
||||||
|
try {
|
||||||
public static Map<Integer, Integer> defaultBauGui() {
|
configConverter.update(yapionObject);
|
||||||
// 0: ? | 1: ? | 2: 10 | 3: 3 | 4: 7 | 5: 17 | 6: 15 | 7: ? | 8: ?
|
} catch (Exception e) {
|
||||||
// 9: 5 | 10: ? | 11: ? | 12: ? | 13: ? | 14: ? | 15: ? | 16: ? | 17: 16
|
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
// 18: 4 | 19: ? | 20: 19 | 21: 21 | 22: 9 | 23: 0 | 24: 1 | 25: ? | 26: 11
|
return ConfigCreator.createDefaultConfig();
|
||||||
// 27: 6 | 28: ? | 29: ? | 30: ? | 31: ? | 32: ? | 33: ? | 34: ? | 35: 18
|
}
|
||||||
// 36: ? | 37: 23 | 38: 20 | 39: 8 | 40: 22 | 41: 26 | 42: 12 | 43: 14 | 44: ?
|
int newVersion = yapionObject.getPlainValue("@version");
|
||||||
Map<Integer, Integer> bauGui = new HashMap<>();
|
if (version == newVersion) {
|
||||||
bauGui.put(10, 2); bauGui.put(3, 3); bauGui.put(7, 4); bauGui.put(17, 5); bauGui.put(15, 6);
|
Bukkit.getLogger().log(Level.SEVERE, "Version Tag was the same after conversion");
|
||||||
bauGui.put(5, 9); bauGui.put(4, 18); bauGui.put(6, 27);
|
return ConfigCreator.createDefaultConfig();
|
||||||
bauGui.put(16, 17); bauGui.put(11, 26); bauGui.put(18, 35);
|
}
|
||||||
bauGui.put(19, 20); bauGui.put(21, 21); bauGui.put(9, 22); bauGui.put(0, 23); bauGui.put(1, 24);
|
if (newVersion < version) {
|
||||||
bauGui.put(23, 37); bauGui.put(20, 38); bauGui.put(8, 39); bauGui.put(22, 40); bauGui.put(26, 41); bauGui.put(12, 42); bauGui.put(14, 43);
|
Bukkit.getLogger().log(Level.SEVERE, "Version Tag was earlier after conversion");
|
||||||
return bauGui;
|
return ConfigCreator.createDefaultConfig();
|
||||||
|
}
|
||||||
|
version = newVersion;
|
||||||
|
}
|
||||||
|
return yapionObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package de.steamwar.bausystem.configplayer;
|
||||||
|
|
||||||
|
import yapion.hierarchy.types.YAPIONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A new {@link ConfigConverter} should be written when you remove anything
|
||||||
|
* from the Config or modify any mayor part. When you move anything from
|
||||||
|
* any key to any other key you should write a new {@link ConfigConverter}.
|
||||||
|
* For adding any new key you should be able to get the default without
|
||||||
|
* having it in the Config. Anything you need to change you should also
|
||||||
|
* change the {@link ConfigCreator} accordingly, to produce the new Config.
|
||||||
|
*/
|
||||||
|
public interface ConfigConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This describes the version this Converter can convert from. The version
|
||||||
|
* it should convert to is the version 1 above this number. But this is not
|
||||||
|
* a necessity. In the config Object as parameter given in {@link #update(YAPIONObject)}
|
||||||
|
* you should update the <b>@version</b> variable in the root object to the
|
||||||
|
* new version this converter produced.
|
||||||
|
*
|
||||||
|
* @return the version number
|
||||||
|
*/
|
||||||
|
int version();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should update everything needed to go from a lower config
|
||||||
|
* version to a higher. It should update the <b>@version</b> variable
|
||||||
|
* accordingly. Anything else is up the implementation. If anything goes wrong
|
||||||
|
* do not silently exit this method, throw an Exception. The updater Code will
|
||||||
|
* deal with it. Never leave the inputted object in a corrupted state.
|
||||||
|
*
|
||||||
|
* @param config the config object to update
|
||||||
|
*/
|
||||||
|
void update(YAPIONObject config);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.configplayer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.hotbar.DefaultHotbar;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import yapion.hierarchy.types.YAPIONObject;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class ConfigCreator {
|
||||||
|
|
||||||
|
public static final int currentVersion = 1;
|
||||||
|
|
||||||
|
public YAPIONObject createDefaultConfig() {
|
||||||
|
YAPIONObject yapionObject = new YAPIONObject();
|
||||||
|
// This call should never be touched
|
||||||
|
yapionObject.add("@version", currentVersion);
|
||||||
|
|
||||||
|
// Any initialising goes into here
|
||||||
|
yapionObject.add("baugui", defaultBauGui());
|
||||||
|
|
||||||
|
// Default Hotbar Gui
|
||||||
|
yapionObject.add("hotbar", DefaultHotbar.defaultHotbar());
|
||||||
|
return yapionObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private YAPIONObject defaultBauGui() {
|
||||||
|
YAPIONObject yapionObject = new YAPIONObject();
|
||||||
|
|
||||||
|
// 0: ? | 1: ? | 2: 10 | 3: 3 | 4: 7 | 5: 17 | 6: 15 | 7: ? | 8: ?
|
||||||
|
// 9: 5 | 10: ? | 11: ? | 12: ? | 13: ? | 14: ? | 15: ? | 16: ? | 17: 16
|
||||||
|
// 18: 4 | 19: ? | 20: 19 | 21: 21 | 22: 9 | 23: 0 | 24: 1 | 25: ? | 26: 11
|
||||||
|
// 27: 6 | 28: ? | 29: ? | 30: ? | 31: ? | 32: ? | 33: ? | 34: ? | 35: 18
|
||||||
|
// 36: ? | 37: 23 | 38: 20 | 39: 8 | 40: 22 | 41: 26 | 42: 12 | 43: 14 | 44: ?
|
||||||
|
|
||||||
|
yapionObject.add("10", 2).add("3", 3).add("7", 4).add("17", 5).add("15", 6);
|
||||||
|
yapionObject.add("5", 9).add("4", 18).add("6", 27);
|
||||||
|
yapionObject.add("16", 17).add("11", 26).add("18", 35);
|
||||||
|
yapionObject.add("19", 20).add("21", 21).add("9", 22).add("0", 23).add("1", 24);
|
||||||
|
yapionObject.add("23", 37).add("20", 38).add("8", 39).add("22", 40).add("26", 41).add("12", 42).add("14", 43);
|
||||||
|
yapionObject.add("size", 45);
|
||||||
|
return yapionObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.configplayer;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.config.VersionedConfig;
|
|
||||||
import de.steamwar.bausystem.config.legacy.YapionReader;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The legacy config that was stored in the YAPION format.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class ConfigV1 implements VersionedConfig {
|
|
||||||
|
|
||||||
public static final int VERSION = 1;
|
|
||||||
|
|
||||||
@Setter(AccessLevel.NONE)
|
|
||||||
protected int version = VERSION;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BauGui item id to inventory slot
|
|
||||||
*/
|
|
||||||
protected Map<Integer, Integer> bauGui = new HashMap<>();
|
|
||||||
protected int bauGuiSize = 45;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minecraft version to the hotbar serialized by YAPION, read with {@link YapionReader}.
|
|
||||||
* Use {@link de.steamwar.bausystem.config.legacy.YapionItemDeserializer} to get the items.
|
|
||||||
*/
|
|
||||||
protected Map<Integer, List<?>> hotbars = new HashMap<>();
|
|
||||||
|
|
||||||
protected boolean nightVision = false;
|
|
||||||
protected boolean tntClickDetails = true;
|
|
||||||
protected boolean detonatorAutostart = false;
|
|
||||||
protected boolean inventoryFill = false;
|
|
||||||
protected boolean rayVisualizer = false;
|
|
||||||
protected boolean smartPlace = false;
|
|
||||||
protected boolean blockCounter = false;
|
|
||||||
protected boolean depthMessage = true;
|
|
||||||
|
|
||||||
public static ConfigV1 parse(String yapion) {
|
|
||||||
Map<String, Object> object = YapionReader.parse(yapion);
|
|
||||||
ConfigV1 config = new ConfigV1();
|
|
||||||
config.version = (Integer) object.get("@version");
|
|
||||||
|
|
||||||
if (object.get("baugui") instanceof Map<?, ?> bauGui) {
|
|
||||||
bauGui.forEach((key, value) -> {
|
|
||||||
if (key.equals("size")) {
|
|
||||||
config.bauGuiSize = (Integer) value;
|
|
||||||
} else {
|
|
||||||
config.bauGui.put(Integer.parseInt((String) key), (Integer) value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
object.forEach((key, value) -> {
|
|
||||||
if (!(value instanceof List<?> hotbar)) return;
|
|
||||||
if (key.equals("hotbar")) {
|
|
||||||
// Hotbars were stored without version prior to 1.19
|
|
||||||
config.hotbars.putIfAbsent(19, hotbar);
|
|
||||||
} else if (key.startsWith("hotbar-")) {
|
|
||||||
config.hotbars.put(Integer.parseInt(key.substring("hotbar-".length())), hotbar);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
config.nightVision = getBoolean(object, "nightvision", config.nightVision);
|
|
||||||
config.tntClickDetails = getBoolean(object, "tnt_click_details", config.tntClickDetails);
|
|
||||||
config.detonatorAutostart = getBoolean(object, "detonator-autostart", config.detonatorAutostart);
|
|
||||||
config.inventoryFill = getBoolean(object, "inventoryfill", config.inventoryFill);
|
|
||||||
config.rayVisualizer = getBoolean(object, "rayvisualizer", config.rayVisualizer);
|
|
||||||
config.smartPlace = getBoolean(object, "smartPlace", config.smartPlace);
|
|
||||||
config.blockCounter = getBoolean(object, "blockCounter", config.blockCounter);
|
|
||||||
config.depthMessage = getBoolean(object, "depth_message", config.depthMessage);
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean getBoolean(Map<String, Object> object, String key, boolean defaultValue) {
|
|
||||||
return object.get(key) instanceof Boolean value ? value : defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-75
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.configplayer.converter;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.config.ConfigConverter;
|
|
||||||
import de.steamwar.bausystem.config.legacy.YapionItemDeserializer;
|
|
||||||
import de.steamwar.bausystem.configplayer.Config;
|
|
||||||
import de.steamwar.bausystem.configplayer.ConfigV1;
|
|
||||||
import de.steamwar.core.Core;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public class ConfigV1ToV2Converter implements ConfigConverter<ConfigV1, Config> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int version() {
|
|
||||||
return ConfigV1.VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Config convert(ConfigV1 old) {
|
|
||||||
Config config = new Config();
|
|
||||||
config.setBauGui(new HashMap<>(old.getBauGui()));
|
|
||||||
config.setBauGuiSize(old.getBauGuiSize());
|
|
||||||
|
|
||||||
List<?> hotbar = old.getHotbars().get(Core.getVersion());
|
|
||||||
if (hotbar != null) {
|
|
||||||
config.setHotbar(convertHotbar(hotbar));
|
|
||||||
}
|
|
||||||
|
|
||||||
config.setNightVision(old.isNightVision());
|
|
||||||
config.setTntClickDetails(old.isTntClickDetails());
|
|
||||||
config.setDetonatorAutostart(old.isDetonatorAutostart());
|
|
||||||
config.setInventoryFill(old.isInventoryFill());
|
|
||||||
config.setRayVisualizer(old.isRayVisualizer());
|
|
||||||
config.setSmartPlace(old.isSmartPlace());
|
|
||||||
config.setBlockCounter(old.isBlockCounter());
|
|
||||||
config.setDepthMessage(old.isDepthMessage());
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ItemStack[] convertHotbar(List<?> hotbar) {
|
|
||||||
ItemStack[] items = new ItemStack[13];
|
|
||||||
for (int i = 0; i < Math.min(hotbar.size(), items.length); i++) {
|
|
||||||
try {
|
|
||||||
items[i] = YapionItemDeserializer.deserializeItem(hotbar.get(i));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "Could not convert hotbar item " + i, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.configplayer.serializer;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||||
|
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import yapion.hierarchy.api.groups.YAPIONAnyType;
|
||||||
|
import yapion.hierarchy.types.YAPIONObject;
|
||||||
|
import yapion.serializing.api.SerializerObject;
|
||||||
|
import yapion.serializing.data.DeserializeData;
|
||||||
|
import yapion.serializing.data.SerializeData;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static yapion.utils.IdentifierUtils.TYPE_IDENTIFIER;
|
||||||
|
|
||||||
|
public class ConfigurationSerializableSerializer extends SerializerObject<ConfigurationSerializable> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<ConfigurationSerializable> type() {
|
||||||
|
return ConfigurationSerializable.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInterface() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public YAPIONObject serialize(SerializeData<ConfigurationSerializable> serializeData) {
|
||||||
|
YAPIONObject yapionObject = new YAPIONObject();
|
||||||
|
yapionObject.add(TYPE_IDENTIFIER, serializeData.object.getClass().getTypeName());
|
||||||
|
if (serializeData.object instanceof ItemStack) {
|
||||||
|
yapionObject.add(TYPE_IDENTIFIER, ItemStack.class.getTypeName());
|
||||||
|
}
|
||||||
|
if (serializeData.object instanceof ItemMeta) {
|
||||||
|
yapionObject.add(TYPE_IDENTIFIER, ItemMeta.class.getTypeName());
|
||||||
|
}
|
||||||
|
Map<String, Object> serializeDataMap = serializeData.object.serialize();
|
||||||
|
serializeDataMap.forEach((s, o) -> {
|
||||||
|
YAPIONAnyType yapionAnyType = serializeData.serialize(o);
|
||||||
|
if (yapionAnyType instanceof YAPIONObject) {
|
||||||
|
YAPIONObject object = (YAPIONObject) yapionAnyType;
|
||||||
|
if (object.containsKey(TYPE_IDENTIFIER) && object.getPlainValue(TYPE_IDENTIFIER).equals("com.google.common.collect.RegularImmutableList")) {
|
||||||
|
object.put(TYPE_IDENTIFIER, ArrayList.class.getTypeName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yapionObject.add(s, yapionAnyType);
|
||||||
|
});
|
||||||
|
return yapionObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigurationSerializable deserialize(DeserializeData<YAPIONObject> deserializeData) {
|
||||||
|
Map<String, Object> deserializeDataMap = new HashMap<>();
|
||||||
|
deserializeData.object.forEach((s, yapionAnyType) -> {
|
||||||
|
if (s.equals(TYPE_IDENTIFIER)) {
|
||||||
|
if (yapionAnyType.toString().equals("(org.bukkit.inventory.meta.ItemMeta)")) {
|
||||||
|
deserializeDataMap.put("==", "ItemMeta");
|
||||||
|
} else {
|
||||||
|
deserializeDataMap.put("==", deserializeData.deserialize(yapionAnyType));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deserializeDataMap.put(s, deserializeData.deserialize(yapionAnyType));
|
||||||
|
});
|
||||||
|
return ConfigurationSerialization.deserializeObject(deserializeDataMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -24,6 +24,7 @@ import de.steamwar.command.PreviousArguments;
|
|||||||
import de.steamwar.command.SWCommand;
|
import de.steamwar.command.SWCommand;
|
||||||
import de.steamwar.command.TypeMapper;
|
import de.steamwar.command.TypeMapper;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
|
import de.steamwar.linkage.MinVersion;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+5
-13
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -76,21 +76,13 @@ public class AttributesCopyCommand extends SWCommand {
|
|||||||
if (itemStack.getType() == Material.ZOMBIE_HEAD && block.getType() == Material.ZOMBIE_WALL_HEAD) return true;
|
if (itemStack.getType() == Material.ZOMBIE_HEAD && block.getType() == Material.ZOMBIE_WALL_HEAD) return true;
|
||||||
if (itemStack.getType() == Material.CREEPER_HEAD && block.getType() == Material.CREEPER_WALL_HEAD) return true;
|
if (itemStack.getType() == Material.CREEPER_HEAD && block.getType() == Material.CREEPER_WALL_HEAD) return true;
|
||||||
if (itemStack.getType() == Material.DRAGON_HEAD && block.getType() == Material.DRAGON_WALL_HEAD) return true;
|
if (itemStack.getType() == Material.DRAGON_HEAD && block.getType() == Material.DRAGON_WALL_HEAD) return true;
|
||||||
if (itemStack.getType() == Material.SKELETON_SKULL && block.getType() == Material.SKELETON_WALL_SKULL) {
|
if (itemStack.getType() == Material.SKELETON_SKULL && block.getType() == Material.SKELETON_WALL_SKULL) return true;
|
||||||
return true;
|
if (itemStack.getType() == Material.WITHER_SKELETON_SKULL && block.getType() == Material.WITHER_SKELETON_WALL_SKULL) return true;
|
||||||
}
|
|
||||||
if (itemStack.getType() == Material.WITHER_SKELETON_SKULL && block.getType() == Material.WITHER_SKELETON_WALL_SKULL) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (itemStack.getType() == Material.TORCH && block.getType() == Material.WALL_TORCH) return true;
|
if (itemStack.getType() == Material.TORCH && block.getType() == Material.WALL_TORCH) return true;
|
||||||
if (itemStack.getType() == Material.SOUL_TORCH && block.getType() == Material.SOUL_WALL_TORCH) return true;
|
if (itemStack.getType() == Material.SOUL_TORCH && block.getType() == Material.SOUL_WALL_TORCH) return true;
|
||||||
if (itemStack.getType() == Material.REDSTONE_TORCH && block.getType() == Material.REDSTONE_WALL_TORCH) {
|
if (itemStack.getType() == Material.REDSTONE_TORCH && block.getType() == Material.REDSTONE_WALL_TORCH) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (itemStack.getType() == Material.WHEAT_SEEDS && block.getType() == Material.WHEAT) return true;
|
if (itemStack.getType() == Material.WHEAT_SEEDS && block.getType() == Material.WHEAT) return true;
|
||||||
if (itemStack.getType().name().contains("_BANNER") && block.getType().name().contains("_WALL_BANNER")) {
|
if (itemStack.getType().name().contains("_BANNER") && block.getType().name().contains("_WALL_BANNER")) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -41,7 +41,7 @@ public class AttributesPlaceListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockPlace(BlockPlaceEvent event) {
|
public void onBlockPlace(BlockPlaceEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
ItemStack itemStack = event.getItemInHand();
|
ItemStack itemStack = event.getItemInHand();
|
||||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
if (itemMeta == null) return;
|
if (itemMeta == null) return;
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
package de.steamwar.bausystem.features.autostart;
|
package de.steamwar.bausystem.features.autostart;
|
||||||
|
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|||||||
+22
-12
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -24,6 +24,8 @@ import de.steamwar.bausystem.Permission;
|
|||||||
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.RegionUtils;
|
import de.steamwar.bausystem.region.RegionUtils;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionType;
|
||||||
import de.steamwar.bausystem.utils.ItemUtils;
|
import de.steamwar.bausystem.utils.ItemUtils;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
@@ -31,8 +33,9 @@ import lombok.Getter;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.data.type.Chest;
|
import org.bukkit.block.data.type.Chest;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
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.EntityExplodeEvent;
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||||
@@ -40,9 +43,9 @@ import org.bukkit.event.inventory.InventoryCloseEvent;
|
|||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
public class AutostartListener implements Listener {
|
public class AutostartListener implements Listener {
|
||||||
@@ -65,7 +68,7 @@ public class AutostartListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!ItemUtils.isItem(event.getItem(), "autostart")) {
|
if (!ItemUtils.isItem(event.getItem(), "autostart")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -89,7 +92,7 @@ public class AutostartListener implements Listener {
|
|||||||
if (!(event.getPlayer() instanceof Player)) {
|
if (!(event.getPlayer() instanceof Player)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!Permission.BUILD.hasPermission((Player) event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission((Player) event.getPlayer())) return;
|
||||||
if (!ItemUtils.isItem(event.getPlayer().getInventory().getItemInMainHand(), "autostart")) {
|
if (!ItemUtils.isItem(event.getPlayer().getInventory().getItemInMainHand(), "autostart")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -103,11 +106,11 @@ public class AutostartListener implements Listener {
|
|||||||
|
|
||||||
public void activate(Player player) {
|
public void activate(Player player) {
|
||||||
Region region = Region.getRegion(player.getLocation());
|
Region region = Region.getRegion(player.getLocation());
|
||||||
if (region.getType().isGlobal()) {
|
if (region.isGlobal()) {
|
||||||
BauSystem.MESSAGE.send("AUTOSTART_MESSAGE_NO_REGION", player);
|
BauSystem.MESSAGE.send("AUTOSTART_MESSAGE_NO_REGION", player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (region.getTestblockArea().isEmpty()) {
|
if (!region.hasType(RegionType.TESTBLOCK)) {
|
||||||
BauSystem.MESSAGE.send("AUTOSTART_MESSAGE_NO_REGION", player);
|
BauSystem.MESSAGE.send("AUTOSTART_MESSAGE_NO_REGION", player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -121,7 +124,6 @@ public class AutostartListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onEntityExplode(EntityExplodeEvent event) {
|
public void onEntityExplode(EntityExplodeEvent event) {
|
||||||
if (!(event.getEntity() instanceof TNTPrimed)) return;
|
|
||||||
if (regionStartTime.isEmpty()) {
|
if (regionStartTime.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -129,12 +131,20 @@ public class AutostartListener implements Listener {
|
|||||||
event.blockList().forEach(block -> {
|
event.blockList().forEach(block -> {
|
||||||
Region region = Region.getRegion(block.getLocation());
|
Region region = Region.getRegion(block.getLocation());
|
||||||
if (!regionStartTime.containsKey(region)) return;
|
if (!regionStartTime.containsKey(region)) return;
|
||||||
if (!region.getTestblockArea().inRegion(block.getLocation(), true)) return;
|
if (!region.hasType(RegionType.TESTBLOCK)) return;
|
||||||
|
if (!region.inRegion(block.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) return;
|
||||||
long tickDiff = TPSUtils.currentRealTick.get() - regionStartTime.remove(region);
|
long tickDiff = TPSUtils.currentRealTick.get() - regionStartTime.remove(region);
|
||||||
long preFightDurationInSeconds = region.getGameModeConfig().Times.PreFightDuration;
|
long preFightDurationInSeconds = getPreFightDurationInSeconds(region);
|
||||||
RegionUtils.message(region, "AUTOSTART_MESSAGE_RESULT1", tickDiff);
|
RegionUtils.message(region, "AUTOSTART_MESSAGE_RESULT1", tickDiff);
|
||||||
RegionUtils.message(region, "AUTOSTART_MESSAGE_RESULT2", preFightDurationInSeconds, ((preFightDurationInSeconds * 20) - tickDiff));
|
RegionUtils.message(region, "AUTOSTART_MESSAGE_RESULT2", preFightDurationInSeconds, ((preFightDurationInSeconds * 20) - tickDiff));
|
||||||
RegionUtils.message(region, "AUTOSTART_MESSAGE_RESULT3");
|
RegionUtils.message(region, "AUTOSTART_MESSAGE_RESULT3");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getPreFightDurationInSeconds(Region region) {
|
||||||
|
File file = region.gameModeConfig();
|
||||||
|
if (file == null) return 30;
|
||||||
|
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||||
|
return config.getInt("Times.PreFightDuration", 30);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-41
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -19,23 +19,31 @@
|
|||||||
|
|
||||||
package de.steamwar.bausystem.features.backup;
|
package de.steamwar.bausystem.features.backup;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.bausystem.Permission;
|
||||||
|
import de.steamwar.bausystem.region.Color;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.RegionBackups;
|
|
||||||
import de.steamwar.bausystem.region.flags.ChangedMode;
|
|
||||||
import de.steamwar.bausystem.region.flags.Flag;
|
import de.steamwar.bausystem.region.flags.Flag;
|
||||||
import de.steamwar.command.PreviousArguments;
|
import de.steamwar.bausystem.region.flags.flagvalues.ColorMode;
|
||||||
|
import de.steamwar.bausystem.region.tags.Tag;
|
||||||
|
import de.steamwar.bausystem.utils.PasteBuilder;
|
||||||
import de.steamwar.command.SWCommand;
|
import de.steamwar.command.SWCommand;
|
||||||
|
import de.steamwar.command.SWCommandUtils;
|
||||||
import de.steamwar.command.TypeMapper;
|
import de.steamwar.command.TypeMapper;
|
||||||
|
import de.steamwar.command.TypeValidator;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import de.steamwar.inventory.SWListInv;
|
import de.steamwar.inventory.SWListInv;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
@@ -46,7 +54,7 @@ public class BackupCommand extends SWCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean checkGlobalRegion(Region region, Player p) {
|
static boolean checkGlobalRegion(Region region, Player p) {
|
||||||
if (region.getType().isGlobal()) {
|
if (region.isGlobal()) {
|
||||||
BauSystem.MESSAGE.send("BACKUP_REGION_NO_REGION", p);
|
BauSystem.MESSAGE.send("BACKUP_REGION_NO_REGION", p);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -59,12 +67,11 @@ public class BackupCommand extends SWCommand {
|
|||||||
if (checkGlobalRegion(region, p)) {
|
if (checkGlobalRegion(region, p)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (region.getRegionData().get(Flag.CHANGED).isWithDefault(ChangedMode.NO_CHANGE)) {
|
if (!region.get(Tag.CHANGED)) {
|
||||||
BauSystem.MESSAGE.send("BACKUP_CREATE_NO_CHANGE", p);
|
BauSystem.MESSAGE.send("BACKUP_CREATE_NO_CHANGE", p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Optional<RegionBackups.Backup> backup = region.getBackups().create(RegionBackups.BackupType.MANUAL);
|
if (region.backup()) {
|
||||||
if (backup.isPresent()) {
|
|
||||||
BauSystem.MESSAGE.send("BACKUP_CREATE_SUCCESS", p);
|
BauSystem.MESSAGE.send("BACKUP_CREATE_SUCCESS", p);
|
||||||
} else {
|
} else {
|
||||||
BauSystem.MESSAGE.send("BACKUP_CREATE_FAILURE", p);
|
BauSystem.MESSAGE.send("BACKUP_CREATE_FAILURE", p);
|
||||||
@@ -72,12 +79,25 @@ public class BackupCommand extends SWCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = "load", description = "BACKUP_HELP_LOAD")
|
@Register(value = "load", description = "BACKUP_HELP_LOAD")
|
||||||
public void backupLoad(@Validator("owner") Player p, @Mapper("backup") @ErrorMessage("BACKUP_LOAD_FAILURE") RegionBackups.Backup backup) {
|
public void backupLoad(@Validator("owner") Player p, @Mapper("backupName") String backupName) {
|
||||||
if (backup.load()) {
|
Region region = Region.getRegion(p.getLocation());
|
||||||
BauSystem.MESSAGE.send("BACKUP_LOAD", p);
|
if (checkGlobalRegion(region, p)) {
|
||||||
} else {
|
return;
|
||||||
BauSystem.MESSAGE.send("BACKUP_LOAD_FAILURE", p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File backupFile = region.getBackupFile(backupName.replace('_', ' '));
|
||||||
|
if (backupFile == null) {
|
||||||
|
BauSystem.MESSAGE.send("BACKUP_LOAD_FAILURE", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EditSession editSession = new PasteBuilder(new PasteBuilder.FileProvider(backupFile))
|
||||||
|
.pastePoint(region.getMinPoint().add(region.getPrototype().getSizeX() / 2, 0, region.getPrototype().getSizeZ() / 2))
|
||||||
|
.minPoint(region.getMinPoint())
|
||||||
|
.maxPoint(region.getMaxPoint())
|
||||||
|
.waterLevel(region.getWaterLevel())
|
||||||
|
.run();
|
||||||
|
region.remember(editSession);
|
||||||
|
BauSystem.MESSAGE.send("BACKUP_LOAD", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = "list", description = "BACKUP_HELP_LIST")
|
@Register(value = "list", description = "BACKUP_HELP_LIST")
|
||||||
@@ -86,10 +106,10 @@ public class BackupCommand extends SWCommand {
|
|||||||
if (checkGlobalRegion(region, p)) {
|
if (checkGlobalRegion(region, p)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<RegionBackups.Backup> backups = listBackup(p);
|
List<String> backups = listBackup(p);
|
||||||
BauSystem.MESSAGE.send("BACKUP_LIST_HEAD", p, backups.size());
|
BauSystem.MESSAGE.send("BACKUP_LIST_HEAD", p, backups.size());
|
||||||
backups.forEach(backup -> {
|
backups.forEach(s -> {
|
||||||
BauSystem.MESSAGE.send("BACKUP_LIST_ENTRY", p, "/backup load " + backup.getName(), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/backup load " + backup.getName()), backup.getName());
|
BauSystem.MESSAGE.send("BACKUP_LIST_ENTRY", p, "/backup load " + s, new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/backup load " + s), s);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,45 +119,34 @@ public class BackupCommand extends SWCommand {
|
|||||||
if (checkGlobalRegion(region, p)) {
|
if (checkGlobalRegion(region, p)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<RegionBackups.Backup> backups = listBackup(p);
|
List<String> backups = listBackup(p);
|
||||||
List<SWListInv.SWListEntry<RegionBackups.Backup>> swListEntries = new ArrayList<>();
|
List<SWListInv.SWListEntry<String>> swListEntries = new ArrayList<>();
|
||||||
List<String> lore = Arrays.asList(BauSystem.MESSAGE.parse("BACKUP_LORE", p));
|
List<String> lore = Arrays.asList(BauSystem.MESSAGE.parse("BACKUP_LORE", p));
|
||||||
for (int i = 0; i < backups.size(); i++) {
|
for (int i = 0; i < backups.size(); i++) {
|
||||||
RegionBackups.Backup backup = backups.get(i);
|
String s = backups.get(i);
|
||||||
SWItem swItem = new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("BACKUP_ITEM_NAME", p, backup.getName()), lore, false, clickType -> {
|
SWItem swItem = new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("BACKUP_ITEM_NAME", p, s), lore, false, clickType -> {});
|
||||||
});
|
|
||||||
swItem.getItemStack().setAmount(i + 1);
|
swItem.getItemStack().setAmount(i + 1);
|
||||||
swListEntries.add(new SWListInv.SWListEntry<>(swItem, backup));
|
swListEntries.add(new SWListInv.SWListEntry<>(swItem, s));
|
||||||
}
|
}
|
||||||
SWListInv<RegionBackups.Backup> swListInv = new SWListInv<>(p, BauSystem.MESSAGE.parse("BACKUP_INV_NAME", p), swListEntries, (clickType, s) -> {
|
SWListInv<String> swListInv = new SWListInv<>(p, BauSystem.MESSAGE.parse("BACKUP_INV_NAME", p), swListEntries, (clickType, s) -> {
|
||||||
p.getOpenInventory().close();
|
p.getOpenInventory().close();
|
||||||
backupLoad(p, s);
|
p.performCommand("backup load " + s);
|
||||||
});
|
});
|
||||||
swListInv.open();
|
swListInv.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mapper(value = "backup", local = true)
|
@Mapper(value = "backupName", local = true)
|
||||||
public TypeMapper<RegionBackups.Backup> backupMapper() {
|
public TypeMapper<String> backupMapper() {
|
||||||
return new TypeMapper<>() {
|
return SWCommandUtils.createMapper(s -> s, (commandSender, s) -> listBackup((Player) commandSender));
|
||||||
@Override
|
|
||||||
public RegionBackups.Backup map(CommandSender commandSender, String[] previousArguments, String s) {
|
|
||||||
return Region.getRegion(((Player) commandSender).getLocation()).getBackups().get(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private List<String> listBackup(Player p) {
|
||||||
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
|
|
||||||
return listBackup((Player) sender).stream().map(RegionBackups.Backup::getName).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<RegionBackups.Backup> listBackup(Player p) {
|
|
||||||
Region region = Region.getRegion(p.getLocation());
|
Region region = Region.getRegion(p.getLocation());
|
||||||
if (checkGlobalRegion(region, p)) {
|
if (checkGlobalRegion(region, p)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return region.getBackups().list();
|
return region.listBackup().stream().map(s -> s.substring(0, s.length() - 6).replace(' ', '_')).collect(Collectors.toList());
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-7
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -22,10 +22,10 @@ package de.steamwar.bausystem.features.bau;
|
|||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.config.BauServer;
|
import de.steamwar.bausystem.config.BauServer;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.bausystem.region.FlagOptional;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.flags.Flag;
|
import de.steamwar.bausystem.region.flags.Flag;
|
||||||
|
import de.steamwar.core.Core;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
@@ -56,10 +56,15 @@ public class BauInfoBauGuiItem extends BauGuiItem {
|
|||||||
Region region = Region.getRegion(player.getLocation());
|
Region region = Region.getRegion(player.getLocation());
|
||||||
List<String> stringList = new ArrayList<>();
|
List<String> stringList = new ArrayList<>();
|
||||||
for (Flag flag : Flag.getFlags()) {
|
for (Flag flag : Flag.getFlags()) {
|
||||||
if (!region.getRegionData().has(flag).isApplicable()) continue;
|
if (flag == Flag.PROTECT && region.getFloorLevel() == 0) {
|
||||||
FlagOptional<?> value = region.getRegionData().get(flag);
|
continue;
|
||||||
if (value.isPresent()) {
|
}
|
||||||
stringList.add(BauSystem.MESSAGE.parse("BAU_INFO_ITEM_LORE_" + flag.name(), player, BauSystem.MESSAGE.parse(value.getWithDefault().getChatValue(), player)));
|
if (flag == Flag.ITEMS && Core.getVersion() < 19) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Flag.Value<?> value = region.get(flag);
|
||||||
|
if (value != null) {
|
||||||
|
stringList.add(BauSystem.MESSAGE.parse("BAU_INFO_ITEM_LORE_" + flag.name(), player, BauSystem.MESSAGE.parse(value.getChatValue(), player)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
itemStack.setLore(stringList);
|
itemStack.setLore(stringList);
|
||||||
|
|||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.features.bau;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.bausystem.Permission;
|
||||||
|
import de.steamwar.command.PreviousArguments;
|
||||||
|
import de.steamwar.command.SWCommand;
|
||||||
|
import de.steamwar.command.TypeMapper;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
|
import de.steamwar.techhider.TechHider;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Linked
|
||||||
|
public class ForceSpectatorCommand extends SWCommand {
|
||||||
|
|
||||||
|
public ForceSpectatorCommand() {
|
||||||
|
super("forcespectator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void forceSpectator(@Validator("supervisor") Player player, @Mapper("builder") Player other) {
|
||||||
|
Permission.forceOnlySpectator(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mapper("builder")
|
||||||
|
public TypeMapper<Player> spectatorMapper() {
|
||||||
|
return new TypeMapper<>() {
|
||||||
|
@Override
|
||||||
|
public Player map(CommandSender commandSender, String[] previousArguments, String s) {
|
||||||
|
Player player = Bukkit.getPlayer(s);
|
||||||
|
if (player == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (Permission.BUILD.hasPermission(player) && !Permission.SUPERVISOR.hasPermission(player)) {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return Bukkit.getOnlinePlayers().stream()
|
||||||
|
.filter(Permission.BUILD::hasPermission)
|
||||||
|
.filter(player -> !Permission.SUPERVISOR.hasPermission(player))
|
||||||
|
.map(Player::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +1,8 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.features.bau;
|
package de.steamwar.bausystem.features.bau;
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.config.BauServer;
|
import de.steamwar.bausystem.config.BauServer;
|
||||||
import de.steamwar.bausystem.region.FlagOptional;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.flags.Flag;
|
import de.steamwar.bausystem.region.flags.Flag;
|
||||||
import de.steamwar.command.SWCommand;
|
import de.steamwar.command.SWCommand;
|
||||||
@@ -47,13 +27,15 @@ public class InfoCommand extends SWCommand {
|
|||||||
|
|
||||||
@Register(description = "BAU_INFO_COMMAND_HELP")
|
@Register(description = "BAU_INFO_COMMAND_HELP")
|
||||||
public void genericCommand(Player p) {
|
public void genericCommand(Player p) {
|
||||||
BauSystem.MESSAGE.send("BAU_INFO_COMMAND_OWNER", p, SteamwarUser.byId(bauServer.getOwnerID()).getUserName());
|
BauSystem.MESSAGE.send("BAU_INFO_COMMAND_OWNER", p, SteamwarUser.get(bauServer.getOwnerID()).getUserName());
|
||||||
Region region = Region.getRegion(p.getLocation());
|
Region region = Region.getRegion(p.getLocation());
|
||||||
for (Flag flag : Flag.getFlags()) {
|
for (Flag flag : Flag.getFlags()) {
|
||||||
if (!region.getRegionData().has(flag).isApplicable()) continue;
|
if (flag == Flag.PROTECT && region.getFloorLevel() == 0) {
|
||||||
FlagOptional<?> value = region.getRegionData().get(flag);
|
continue;
|
||||||
if (value.isPresent()) {
|
}
|
||||||
BauSystem.MESSAGE.send("BAU_INFO_COMMAND_FLAG", p, BauSystem.MESSAGE.parse(flag.getChatValue(), p), BauSystem.MESSAGE.parse(value.getWithDefault().getChatValue(), p));
|
Flag.Value<?> value = region.get(flag);
|
||||||
|
if (value != null) {
|
||||||
|
BauSystem.MESSAGE.send("BAU_INFO_COMMAND_FLAG", p, BauSystem.MESSAGE.parse(flag.getChatValue(), p), BauSystem.MESSAGE.parse(value.getChatValue(), p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +79,7 @@ public class InfoCommand extends SWCommand {
|
|||||||
st.append("§8, ");
|
st.append("§8, ");
|
||||||
}
|
}
|
||||||
st.append("§7");
|
st.append("§7");
|
||||||
st.append(SteamwarUser.byId(bauweltMembers.get(i).getMemberID()).getUserName());
|
st.append(SteamwarUser.get(bauweltMembers.get(i).getMemberID()).getUserName());
|
||||||
}
|
}
|
||||||
return st.toString();
|
return st.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -23,6 +23,7 @@ import de.steamwar.bausystem.BauSystem;
|
|||||||
import de.steamwar.bausystem.features.cannon.depth.Depth;
|
import de.steamwar.bausystem.features.cannon.depth.Depth;
|
||||||
import de.steamwar.bausystem.features.cannon.depth.DepthManager;
|
import de.steamwar.bausystem.features.cannon.depth.DepthManager;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionType;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.TNTPrimed;
|
import org.bukkit.entity.TNTPrimed;
|
||||||
@@ -84,8 +85,8 @@ public class CannonDetector implements Listener {
|
|||||||
grouped.forEach((cannonKey, tntPrimeds) -> {
|
grouped.forEach((cannonKey, tntPrimeds) -> {
|
||||||
if (tntPrimeds.size() <= 5) return;
|
if (tntPrimeds.size() <= 5) return;
|
||||||
Region region = Region.getRegion(tntPrimeds.get(0).getLocation());
|
Region region = Region.getRegion(tntPrimeds.get(0).getLocation());
|
||||||
if (region.getType().isGlobal()) return;
|
if (region.isGlobal()) return;
|
||||||
if (region.getTestblockArea().isEmpty()) return;
|
if (!region.hasType(RegionType.TESTBLOCK)) return;
|
||||||
Depth depth = new Depth(region);
|
Depth depth = new Depth(region);
|
||||||
DepthManager.init(tntPrimeds, depth);
|
DepthManager.init(tntPrimeds, depth);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.cannon;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.bukkit.entity.TNTPrimed;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -23,6 +23,8 @@ import de.steamwar.bausystem.BauSystem;
|
|||||||
import de.steamwar.bausystem.configplayer.Config;
|
import de.steamwar.bausystem.configplayer.Config;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.RegionUtils;
|
import de.steamwar.bausystem.region.RegionUtils;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionType;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
@@ -48,7 +50,7 @@ public class Depth {
|
|||||||
|
|
||||||
public void update(List<Block> blocks) {
|
public void update(List<Block> blocks) {
|
||||||
List<Block> blocksList = blocks.stream()
|
List<Block> blocksList = blocks.stream()
|
||||||
.filter(block -> region.getTestblockArea().inRegion(block.getLocation(), true))
|
.filter(block -> region.inRegion(block.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
tntCount++;
|
tntCount++;
|
||||||
for (Block block : blocksList) {
|
for (Block block : blocksList) {
|
||||||
@@ -64,7 +66,7 @@ public class Depth {
|
|||||||
dimensions.setZ(Math.abs(dimensions.getZ()));
|
dimensions.setZ(Math.abs(dimensions.getZ()));
|
||||||
|
|
||||||
RegionUtils.message(region, player -> {
|
RegionUtils.message(region, player -> {
|
||||||
if (Config.STORE.get(player).isDepthMessage()) {
|
if (Config.getInstance().get(player).getPlainValueOrDefault("depth_message", true)) {
|
||||||
player.spigot().sendMessage(getMessage(player, dimensions.getBlockX() + 1, dimensions.getBlockY() + 1, dimensions.getBlockZ() + 1, tntCount));
|
player.spigot().sendMessage(getMessage(player, dimensions.getBlockX() + 1, dimensions.getBlockY() + 1, dimensions.getBlockZ() + 1, tntCount));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+4
-4
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -34,11 +34,11 @@ public class DepthCommand extends SWCommand {
|
|||||||
|
|
||||||
@Register
|
@Register
|
||||||
public void toggle(Player player) {
|
public void toggle(Player player) {
|
||||||
if (Config.STORE.get(player).isDepthMessage()) {
|
if (Config.getInstance().get(player).getPlainValueOrDefault("depth_message", true)) {
|
||||||
Config.STORE.get(player).setDepthMessage(false);
|
Config.getInstance().get(player).put("depth_message", false);
|
||||||
BauSystem.MESSAGE.send("DEPTH_COUNTER_DISABLE", player);
|
BauSystem.MESSAGE.send("DEPTH_COUNTER_DISABLE", player);
|
||||||
} else {
|
} else {
|
||||||
Config.STORE.get(player).setDepthMessage(true);
|
Config.getInstance().get(player).put("depth_message", true);
|
||||||
BauSystem.MESSAGE.send("DEPTH_COUNTER_ENABLE", player);
|
BauSystem.MESSAGE.send("DEPTH_COUNTER_ENABLE", player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+55
-34
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,10 +21,9 @@ package de.steamwar.bausystem.features.countingwand;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.region.Point;
|
import de.steamwar.bausystem.region.Point;
|
||||||
|
import de.steamwar.bausystem.shared.Pair;
|
||||||
import de.steamwar.bausystem.utils.ItemUtils;
|
import de.steamwar.bausystem.utils.ItemUtils;
|
||||||
import de.steamwar.core.SWPlayer;
|
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -32,32 +31,13 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class Countingwand {
|
public class Countingwand {
|
||||||
|
|
||||||
@Data
|
|
||||||
public class CountingWandComponent implements SWPlayer.Component {
|
|
||||||
private Point pos1;
|
|
||||||
private Point pos2;
|
|
||||||
|
|
||||||
public boolean setPosition(boolean pos1, Point point) {
|
|
||||||
if (this.pos1 == null || this.pos2 == null) {
|
|
||||||
this.pos1 = point;
|
|
||||||
this.pos2 = point;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Point current = pos1 ? this.pos1 : this.pos2;
|
|
||||||
if (current.equals(point)) return false;
|
|
||||||
if (pos1) {
|
|
||||||
this.pos1 = point;
|
|
||||||
} else {
|
|
||||||
this.pos2 = point;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ItemStack getWandItem(Player player) {
|
public static ItemStack getWandItem(Player player) {
|
||||||
ItemStack itemStack = new SWItem(Material.STICK, BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE1", player), BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE2", player)), false, null).getItemStack();
|
ItemStack itemStack = new SWItem(Material.STICK, BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE1", player), BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE2", player)), false, null).getItemStack();
|
||||||
ItemUtils.setItem(itemStack, "countingwand");
|
ItemUtils.setItem(itemStack, "countingwand");
|
||||||
@@ -67,20 +47,61 @@ public class Countingwand {
|
|||||||
return itemStack;
|
return itemStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Map<String, Pair<Point, Point>> selections = new HashMap<>();
|
||||||
|
|
||||||
public boolean isCountingwand(ItemStack itemStack) {
|
public boolean isCountingwand(ItemStack itemStack) {
|
||||||
return ItemUtils.isItem(itemStack, "countingwand");
|
return ItemUtils.isItem(itemStack, "countingwand");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkSelection(final Point point, final boolean pos1, final Player p) {
|
public void checkSelection(final Point point, final boolean pos1, final Player p) {
|
||||||
SWPlayer player = SWPlayer.of(p);
|
Pair<Point, Point> selection = selections.get(p.getUniqueId().toString());
|
||||||
CountingWandComponent countingWandComponent = player.getComponentOrDefault(CountingWandComponent.class, CountingWandComponent::new);
|
final boolean newPos;
|
||||||
if (countingWandComponent.setPosition(pos1, point)) {
|
if (selection != null) {
|
||||||
Point point1 = countingWandComponent.pos1;
|
if (pos1) {
|
||||||
Point point2 = countingWandComponent.pos2;
|
newPos = !point.equals(selection.setKey(point));
|
||||||
int amount = (Math.abs(point1.getX() - point2.getX()) + 1) * (Math.abs(point1.getY() - point2.getY()) + 1) * (Math.abs(point1.getZ() - point2.getZ()) + 1);
|
} else {
|
||||||
String dimension = player.using(BauSystem.MESSAGE).parse("COUNTINGWAND_MESSAGE_VOLUME", amount);
|
newPos = !point.equals(selection.setValue(point));
|
||||||
String volume = player.parse("COUNTINGWAND_MESSAGE_DIMENSION", Math.abs(point1.getX() - point2.getX()) + 1, Math.abs(point1.getY() - point2.getY()) + 1, Math.abs(point1.getZ() - point2.getZ()) + 1);
|
|
||||||
player.sendMessage(pos1 ? "COUNTINGWAND_MESSAGE_RCLICK" : "COUNTINGWAND_MESSAGE_LCLICK", point.getX(), point.getY(), point.getZ(), dimension, volume);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (pos1) {
|
||||||
|
selection = new Pair<>(point, null);
|
||||||
|
} else {
|
||||||
|
selection = new Pair<>(null, point);
|
||||||
|
}
|
||||||
|
selections.put(p.getUniqueId().toString(), selection);
|
||||||
|
newPos = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPos) {
|
||||||
|
String dimension = getDimensions(p, selection.getKey(), selection.getValue());
|
||||||
|
String volume = getVolume(p, selection.getKey(), selection.getValue());
|
||||||
|
if (pos1) {
|
||||||
|
BauSystem.MESSAGE.send("COUNTINGWAND_MESSAGE_RCLICK", p, point.getX(), point.getY(), point.getZ(), dimension, volume);
|
||||||
|
} else {
|
||||||
|
BauSystem.MESSAGE.send("COUNTINGWAND_MESSAGE_LCLICK", p, point.getX(), point.getY(), point.getZ(), dimension, volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePlayer(Player p) {
|
||||||
|
selections.remove(p.getUniqueId().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVolume(Player player, final Point point1, final Point point2) {
|
||||||
|
if (point1 == null || point2 == null) {
|
||||||
|
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_VOLUME", player, 0);
|
||||||
|
}
|
||||||
|
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_VOLUME", player, getAmount(point1, point2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDimensions(Player player, final Point point1, final Point point2) {
|
||||||
|
if (point1 == null || point2 == null) {
|
||||||
|
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_DIMENSION", player, 0, 0, 0);
|
||||||
|
}
|
||||||
|
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_DIMENSION", player, Math.abs(point1.getX() - point2.getX()) + 1, Math.abs(point1.getY() - point2.getY()) + 1, Math.abs(point1.getZ() - point2.getZ()) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAmount(final Point point1, final Point point2) {
|
||||||
|
return (Math.abs(point1.getX() - point2.getX()) + 1) * (Math.abs(point1.getY() - point2.getY()) + 1) * (Math.abs(point1.getZ() - point2.getZ()) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
package de.steamwar.bausystem.features.countingwand;
|
package de.steamwar.bausystem.features.countingwand;
|
||||||
|
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
|||||||
+7
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -27,6 +27,7 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.util.RayTraceResult;
|
import org.bukkit.util.RayTraceResult;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -66,4 +67,9 @@ public class CountingwandListener implements Listener {
|
|||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(event.getClickedBlock()).getLocation()), false, event.getPlayer());
|
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(event.getClickedBlock()).getLocation()), false, event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onLeave(PlayerQuitEvent event) {
|
||||||
|
Countingwand.removePlayer(event.getPlayer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+27
-31
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,7 +21,9 @@ package de.steamwar.bausystem.features.design.endstone;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.entity.*;
|
import de.steamwar.entity.REntity;
|
||||||
|
import de.steamwar.entity.REntityServer;
|
||||||
|
import de.steamwar.entity.RFallingBlockEntity;
|
||||||
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.Location;
|
import org.bukkit.Location;
|
||||||
@@ -29,8 +31,10 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.stream.Collectors;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class DesignEndStone {
|
public class DesignEndStone {
|
||||||
|
|
||||||
@@ -40,32 +44,27 @@ public class DesignEndStone {
|
|||||||
private REntityServer entityServer = new REntityServer();
|
private REntityServer entityServer = new REntityServer();
|
||||||
private List<REntity> entities = new ArrayList<>();
|
private List<REntity> entities = new ArrayList<>();
|
||||||
private Set<Location> locations = new HashSet<>();
|
private Set<Location> locations = new HashSet<>();
|
||||||
private Set<Material> limited;
|
private boolean wsOrAs;
|
||||||
private boolean calculateFromBottom;
|
private double maxBlastResistance;
|
||||||
|
|
||||||
public DesignEndStone(Region region) {
|
public DesignEndStone(Region region) {
|
||||||
this.minX = region.getBuildArea().getMinPoint(false).getX();
|
this.minX = region.getMinPointBuild().getX();
|
||||||
this.minY = region.getBuildArea().getMinPoint(false).getY();
|
this.minY = region.getMinPointBuild().getY();
|
||||||
this.minZ = region.getBuildArea().getMinPoint(false).getZ();
|
this.minZ = region.getMinPointBuild().getZ();
|
||||||
this.maxX = region.getBuildArea().getMaxPoint(false).getX();
|
this.maxX = region.getMaxPointBuild().getX();
|
||||||
this.maxY = region.getBuildArea().getMaxPoint(false).getY();
|
this.maxY = region.getMaxPointBuild().getY();
|
||||||
this.maxZ = region.getBuildArea().getMaxPoint(false).getZ();
|
this.maxZ = region.getMaxPointBuild().getZ();
|
||||||
|
wsOrAs = region.getName().startsWith("ws") || region.getName().startsWith("as");
|
||||||
|
maxBlastResistance = wsOrAs ? 6.1 : 9.0;
|
||||||
|
|
||||||
limited = Arrays.stream(Material.values())
|
entityServer.setCallback((player, rEntity, entityAction) -> {
|
||||||
.filter(Material::isBlock)
|
if (entityAction != REntityServer.EntityAction.ATTACK) return;
|
||||||
.filter(material -> !material.isLegacy())
|
Location location = new Location(WORLD, rEntity.getX(), rEntity.getY(), rEntity.getZ());
|
||||||
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void interact(Player player, RInteraction entity, REntityAction action) {
|
|
||||||
if (action != REntityAction.ATTACK) return;
|
|
||||||
Location location = new Location(WORLD, entity.getX(), entity.getY(), entity.getZ());
|
|
||||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||||
location.getBlock().breakNaturally();
|
location.getBlock().breakNaturally();
|
||||||
calc();
|
calc();
|
||||||
}, 1);
|
}, 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calc() {
|
public void calc() {
|
||||||
@@ -77,7 +76,7 @@ public class DesignEndStone {
|
|||||||
calc(minX, minY, maxZ, maxX, maxY, maxZ, 0, 0, -1, maxZ - minZ);
|
calc(minX, minY, maxZ, maxX, maxY, maxZ, 0, 0, -1, maxZ - minZ);
|
||||||
calc(minX, minY, minZ, minX, maxY, maxZ, 1, 0, 0, maxX - minX);
|
calc(minX, minY, minZ, minX, maxY, maxZ, 1, 0, 0, maxX - minX);
|
||||||
calc(maxX, minY, minZ, maxX, maxY, maxZ, -1, 0, 0, maxX - minX);
|
calc(maxX, minY, minZ, maxX, maxY, maxZ, -1, 0, 0, maxX - minX);
|
||||||
if (calculateFromBottom) {
|
if (wsOrAs) {
|
||||||
calc(minX, minY, minZ, maxX, minY, maxZ, 0, 1, 0, maxY - minY + 1);
|
calc(minX, minY, minZ, maxX, minY, maxZ, 0, 1, 0, maxY - minY + 1);
|
||||||
} else {
|
} else {
|
||||||
int airBlocks = 0;
|
int airBlocks = 0;
|
||||||
@@ -107,16 +106,13 @@ public class DesignEndStone {
|
|||||||
int cz = z + step * dirZ;
|
int cz = z + step * dirZ;
|
||||||
Material material = WORLD.getBlockAt(cx, cy, cz).getType();
|
Material material = WORLD.getBlockAt(cx, cy, cz).getType();
|
||||||
|
|
||||||
if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) {
|
if (material != Material.WATER && material != Material.LAVA && material.getBlastResistance() >= maxBlastResistance) {
|
||||||
Location location = new Location(WORLD, cx, cy, cz);
|
Location location = new Location(WORLD, cx + 0.5, cy, cz + 0.5);
|
||||||
if (!locations.add(location)) break;
|
if (!locations.add(location)) break;
|
||||||
RBlockDisplay entity = new RBlockDisplay(entityServer, location);
|
RFallingBlockEntity entity = new RFallingBlockEntity(entityServer, location, Material.RED_STAINED_GLASS);
|
||||||
entity.setBlock(Material.RED_STAINED_GLASS.createBlockData());
|
entity.setNoGravity(true);
|
||||||
entity.setGlowing(true);
|
entity.setGlowing(true);
|
||||||
entities.add(entity);
|
entities.add(entity);
|
||||||
RInteraction interaction = new RInteraction(entityServer, location);
|
|
||||||
interaction.setCallback(this::interact);
|
|
||||||
entities.add(interaction);
|
|
||||||
break;
|
break;
|
||||||
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
|
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
+3
-6
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.design.endstone;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionType;
|
||||||
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
||||||
import de.steamwar.command.SWCommand;
|
import de.steamwar.command.SWCommand;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
@@ -48,11 +49,7 @@ public class DesignEndStoneCommand extends SWCommand implements Listener {
|
|||||||
@Register(description = "DESIGN_ENDSTONE_COMMAND_HELP")
|
@Register(description = "DESIGN_ENDSTONE_COMMAND_HELP")
|
||||||
public void genericCommand(@Validator Player player) {
|
public void genericCommand(@Validator Player player) {
|
||||||
Region region = Region.getRegion(player.getLocation());
|
Region region = Region.getRegion(player.getLocation());
|
||||||
if (region.getBuildArea().isEmpty()) {
|
if (!region.hasType(RegionType.BUILD)) {
|
||||||
BauSystem.MESSAGE.send("DESIGN_ENDSTONE_REGION_ERROR", player);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!region.getGameModeConfig().loaded) {
|
|
||||||
BauSystem.MESSAGE.send("DESIGN_ENDSTONE_REGION_ERROR", player);
|
BauSystem.MESSAGE.send("DESIGN_ENDSTONE_REGION_ERROR", player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+18
-34
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -25,12 +25,8 @@ import de.steamwar.bausystem.configplayer.Config;
|
|||||||
import de.steamwar.bausystem.features.autostart.AutostartListener;
|
import de.steamwar.bausystem.features.autostart.AutostartListener;
|
||||||
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
|
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
|
||||||
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
|
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
|
||||||
import de.steamwar.core.SWPlayer;
|
|
||||||
import de.steamwar.entity.RBlockDisplay;
|
|
||||||
import de.steamwar.entity.REntityServer;
|
import de.steamwar.entity.REntityServer;
|
||||||
import de.steamwar.entity.RInteraction;
|
import de.steamwar.entity.RFallingBlockEntity;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -49,53 +45,41 @@ import java.util.*;
|
|||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class Detonator {
|
public class Detonator {
|
||||||
|
|
||||||
public class DetonatorComponent implements SWPlayer.Component {
|
private static final Map<Player, REntityServer> ENTITIES_MAP = new HashMap<>();
|
||||||
private final REntityServer entities = new REntityServer();
|
private static final Vector HALF = new Vector(0.5, 0, 0.5);
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private boolean hasUpdated = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMount(SWPlayer player) {
|
|
||||||
entities.addPlayer(player.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUnmount(SWPlayer player) {
|
|
||||||
entities.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isDetonator(ItemStack itemStack) {
|
public static boolean isDetonator(ItemStack itemStack) {
|
||||||
return ItemStorage.isDetonator(itemStack);
|
return ItemStorage.isDetonator(itemStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showDetonator(Player p, List<Location> locs) {
|
public static void showDetonator(Player p, List<Location> locs) {
|
||||||
DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
|
if (ENTITIES_MAP.containsKey(p)) return;
|
||||||
locs.forEach(location -> {
|
REntityServer entities = new REntityServer();
|
||||||
RBlockDisplay blockDisplay = new RBlockDisplay(detonatorComponent.entities, location);
|
entities.setCallback((player, rEntity, entityAction) -> {
|
||||||
blockDisplay.setBlock(Material.RED_STAINED_GLASS.createBlockData());
|
Vector vector = new Vector(rEntity.getX(), rEntity.getY(), rEntity.getZ());
|
||||||
|
|
||||||
RInteraction interaction = new RInteraction(detonatorComponent.entities, location);
|
|
||||||
interaction.setCallback((player, entity, action) -> {
|
|
||||||
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
|
|
||||||
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
|
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
|
||||||
|
DetonatorListener.HAS_UPDATED.add(player);
|
||||||
});
|
});
|
||||||
|
entities.addPlayer(p);
|
||||||
|
ENTITIES_MAP.put(p, entities);
|
||||||
|
|
||||||
|
locs.forEach(location -> {
|
||||||
|
RFallingBlockEntity entity = new RFallingBlockEntity(entities, location.clone().add(HALF), Material.RED_STAINED_GLASS);
|
||||||
|
entity.setNoGravity(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void hideDetonator(Player p) {
|
public static void hideDetonator(Player p) {
|
||||||
SWPlayer.of(p).removeComponent(DetonatorComponent.class);
|
ENTITIES_MAP.remove(p).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasActiveDetonatorShow(Player p) {
|
public static boolean hasActiveDetonatorShow(Player p) {
|
||||||
return SWPlayer.of(p).hasComponent(DetonatorComponent.class);
|
return ENTITIES_MAP.containsKey(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void activateDetonator(DetonatorStorage detonator) {
|
public static void activateDetonator(DetonatorStorage detonator) {
|
||||||
Player p = detonator.getPlayer();
|
Player p = detonator.getPlayer();
|
||||||
if (Config.STORE.get(p).isDetonatorAutostart()) {
|
if (Config.getInstance().get(p).getPlainValueOrDefault("detonator-autostart", false)) {
|
||||||
AutostartListener.instance.activate(p);
|
AutostartListener.instance.activate(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
package de.steamwar.bausystem.features.detonator;
|
package de.steamwar.bausystem.features.detonator;
|
||||||
|
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -76,8 +76,8 @@ public class DetonatorCommand extends SWCommand {
|
|||||||
|
|
||||||
@Register(value = "autostart", description = "DETONATOR_HELP_AUTOSTART")
|
@Register(value = "autostart", description = "DETONATOR_HELP_AUTOSTART")
|
||||||
public void toggleAutostartTimer(Player p) {
|
public void toggleAutostartTimer(Player p) {
|
||||||
boolean current = Config.STORE.get(p).isDetonatorAutostart();
|
boolean current = Config.getInstance().get(p).getPlainValueOrDefault("detonator-autostart", false);
|
||||||
Config.STORE.get(p).setDetonatorAutostart(!current);
|
Config.getInstance().get(p).put("detonator-autostart", !current);
|
||||||
if (!current) {
|
if (!current) {
|
||||||
BauSystem.MESSAGE.send("DETONATOR_AUTOSTART_ENABLE", p);
|
BauSystem.MESSAGE.send("DETONATOR_AUTOSTART_ENABLE", p);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+30
-22
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -24,7 +24,6 @@ import de.steamwar.bausystem.Permission;
|
|||||||
import de.steamwar.bausystem.SWUtils;
|
import de.steamwar.bausystem.SWUtils;
|
||||||
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
|
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
|
||||||
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
|
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
|
||||||
import de.steamwar.core.SWPlayer;
|
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -37,11 +36,15 @@ import org.bukkit.event.player.PlayerItemHeldEvent;
|
|||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
|
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
public class DetonatorListener implements Listener {
|
public class DetonatorListener implements Listener {
|
||||||
|
|
||||||
|
static final Set<Player> HAS_UPDATED = new HashSet<>();
|
||||||
|
|
||||||
static void addLocationToDetonator(Location location, Player p) {
|
static void addLocationToDetonator(Location location, Player p) {
|
||||||
SWPlayer.of(p).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
|
|
||||||
Detoblock detoblock = Detonator.getBlock(location.getBlock());
|
Detoblock detoblock = Detonator.getBlock(location.getBlock());
|
||||||
if (detoblock == Detoblock.INVALID) {
|
if (detoblock == Detoblock.INVALID) {
|
||||||
SWUtils.sendToActionbar(p, BauSystem.MESSAGE.parse("DETONATOR_INVALID_BLOCK", p));
|
SWUtils.sendToActionbar(p, BauSystem.MESSAGE.parse("DETONATOR_INVALID_BLOCK", p));
|
||||||
@@ -63,59 +66,64 @@ public class DetonatorListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
Player p = event.getPlayer();
|
Player p = event.getPlayer();
|
||||||
if (Detonator.isDetonator(p.getInventory().getItemInMainHand())) {
|
if (Detonator.isDetonator(p.getInventory().getItemInMainHand())) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
addLocationToDetonator(event.getBlock().getLocation(), p);
|
addLocationToDetonator(event.getBlock().getLocation(), p);
|
||||||
|
HAS_UPDATED.add(event.getPlayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!Detonator.isDetonator(event.getItem())) return;
|
if (!Detonator.isDetonator(event.getItem())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
DetonatorStorage detonator = new ItemStorage(event.getPlayer());
|
DetonatorStorage detonator = new ItemStorage(event.getPlayer());
|
||||||
Detonator.activateDetonator(detonator);
|
Detonator.activateDetonator(detonator);
|
||||||
SWPlayer.of(event.getPlayer()).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
|
HAS_UPDATED.add(event.getPlayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onPlayerMove(PlayerMoveEvent event) {
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer()) || !Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) {
|
if (!Permission.BUILD.hasPermission(event.getPlayer()) ||!Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) {
|
||||||
if (Detonator.hasActiveDetonatorShow(event.getPlayer())) {
|
if (Detonator.hasActiveDetonatorShow(event.getPlayer())) {
|
||||||
Detonator.hideDetonator(event.getPlayer());
|
Detonator.hideDetonator(event.getPlayer());
|
||||||
}
|
}
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
if (!Detonator.hasActiveDetonatorShow(event.getPlayer())) {
|
if (!Detonator.hasActiveDetonatorShow(event.getPlayer())) {
|
||||||
Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
|
Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
Detonator.DetonatorComponent component = SWPlayer.of(event.getPlayer())
|
}
|
||||||
.getComponentAndFilter(Detonator.DetonatorComponent.class, Detonator.DetonatorComponent::isHasUpdated)
|
|
||||||
.orElse(null);
|
if (HAS_UPDATED.contains(event.getPlayer())) {
|
||||||
if (component == null) return;
|
HAS_UPDATED.remove(event.getPlayer());
|
||||||
component.setHasUpdated(false);
|
if (Detonator.hasActiveDetonatorShow(event.getPlayer())) {
|
||||||
Detonator.hideDetonator(event.getPlayer());
|
Detonator.hideDetonator(event.getPlayer());
|
||||||
Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
|
Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
|
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) return;
|
if (Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) {
|
||||||
SWPlayer.of(event.getPlayer()).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
|
HAS_UPDATED.add(event.getPlayer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!(Detonator.isDetonator(event.getMainHandItem()) || Detonator.isDetonator(event.getOffHandItem()))) return;
|
if (Detonator.isDetonator(event.getMainHandItem()) || Detonator.isDetonator(event.getOffHandItem())) {
|
||||||
SWPlayer.of(event.getPlayer()).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
|
HAS_UPDATED.add(event.getPlayer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.features.dev;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.command.SWCommand;
|
|
||||||
import de.steamwar.linkage.Linked;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@Linked
|
|
||||||
public class CreateKitCommand extends SWCommand {
|
|
||||||
|
|
||||||
public CreateKitCommand() {
|
|
||||||
super("createkit");
|
|
||||||
if (!BauSystem.DEV_SERVER) unregister();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Register
|
|
||||||
public void onCommand(Player player, String name) {
|
|
||||||
YamlConfiguration yaml = new YamlConfiguration();
|
|
||||||
|
|
||||||
yaml.set("Items", player.getInventory().getContents());
|
|
||||||
yaml.set("Armor", player.getInventory().getArmorContents());
|
|
||||||
yaml.set("Effects", player.getActivePotionEffects());
|
|
||||||
yaml.set("LeaderAllowed", true);
|
|
||||||
yaml.set("MemberAllowed", true);
|
|
||||||
yaml.set("EnterStage", 0);
|
|
||||||
yaml.set("TNT", true);
|
|
||||||
|
|
||||||
YamlConfiguration kits = new YamlConfiguration();
|
|
||||||
|
|
||||||
kits.set("Kits." + name, yaml);
|
|
||||||
|
|
||||||
try {
|
|
||||||
kits.save(new File("new.kits.yaml"));
|
|
||||||
|
|
||||||
player.sendMessage("Kit created!");
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-135
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.features.experimental.redstone_engine;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.experimental.ExperimentalCommand;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import de.steamwar.bausystem.utils.ScoreboardElement;
|
|
||||||
import de.steamwar.command.AbstractSWCommand;
|
|
||||||
import de.steamwar.command.SWCommand;
|
|
||||||
import de.steamwar.linkage.Linked;
|
|
||||||
import io.papermc.paper.configuration.WorldConfiguration;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.title.TitlePart;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@AbstractSWCommand.PartOf(ExperimentalCommand.class)
|
|
||||||
@Linked
|
|
||||||
public class RedstoneEngine extends SWCommand implements Listener, ScoreboardElement {
|
|
||||||
|
|
||||||
public RedstoneEngine() {
|
|
||||||
super("");
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldConfiguration.Misc getConfig() {
|
|
||||||
return ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle().paperConfig().misc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Register("redstone")
|
|
||||||
@Register("redstoneengine")
|
|
||||||
public void setRedstoneEngine(Player player, @StaticValue("alternate_current") String __, WorldConfiguration.Misc.AlternateCurrentUpdateOrder updateOrder) {
|
|
||||||
WorldConfiguration.Misc misc = getConfig();
|
|
||||||
misc.redstoneImplementation = WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT;
|
|
||||||
misc.alternateCurrentUpdateOrder = updateOrder;
|
|
||||||
broadcastTitle(Bukkit.getOnlinePlayers());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Register("redstone")
|
|
||||||
@Register("redstoneengine")
|
|
||||||
public void setRedstoneEngine(Player player, WorldConfiguration.Misc.RedstoneImplementation implementation) {
|
|
||||||
getConfig().redstoneImplementation = implementation;
|
|
||||||
broadcastTitle(Bukkit.getOnlinePlayers());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
WorldConfiguration.Misc misc = getConfig();
|
|
||||||
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
|
|
||||||
broadcastTitle(List.of(event.getPlayer()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void broadcastTitle(Collection<? extends Player> players) {
|
|
||||||
WorldConfiguration.Misc misc = getConfig();
|
|
||||||
Component title = switch (misc.redstoneImplementation) {
|
|
||||||
case VANILLA -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: Vanilla ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
|
|
||||||
case EIGENCRAFT -> Component.text("Redstone: Eigencraft");
|
|
||||||
case ALTERNATE_CURRENT -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: AC ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
|
|
||||||
};
|
|
||||||
Component subtitle;
|
|
||||||
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
|
||||||
subtitle = Component.text().build();
|
|
||||||
} else {
|
|
||||||
subtitle = switch (misc.alternateCurrentUpdateOrder) {
|
|
||||||
case VERTICAL_FIRST_INWARD -> Component.text("Y first inwards"); // Y before XZ
|
|
||||||
case VERTICAL_FIRST_OUTWARD -> Component.text("Y first outwards"); // XZ before Y
|
|
||||||
case HORIZONTAL_FIRST_INWARD -> Component.text("XZ first inwards"); // Y before XZ
|
|
||||||
case HORIZONTAL_FIRST_OUTWARD -> Component.text("XZ first outwards"); // XZ before Y
|
|
||||||
};
|
|
||||||
}
|
|
||||||
players.forEach(player -> {
|
|
||||||
player.sendTitlePart(TitlePart.TITLE, title);
|
|
||||||
player.sendTitlePart(TitlePart.SUBTITLE, subtitle);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ScoreboardGroup getGroup() {
|
|
||||||
return ScoreboardGroup.FOOTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int order() {
|
|
||||||
return Integer.MAX_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String get(Region region, Player p) {
|
|
||||||
WorldConfiguration.Misc misc = getConfig();
|
|
||||||
switch (misc.redstoneImplementation) {
|
|
||||||
case ALTERNATE_CURRENT:
|
|
||||||
switch (misc.alternateCurrentUpdateOrder) {
|
|
||||||
case VERTICAL_FIRST_INWARD:
|
|
||||||
return "§eRedstone§8: §cAC §8(§7Y in§8)";
|
|
||||||
case VERTICAL_FIRST_OUTWARD:
|
|
||||||
return "§eRedstone§8: §cAC §8(§7Y out§8)";
|
|
||||||
case HORIZONTAL_FIRST_INWARD:
|
|
||||||
return "§eRedstone§8: §cAC §8(§7XZ in§8)";
|
|
||||||
case HORIZONTAL_FIRST_OUTWARD:
|
|
||||||
return "§eRedstone§8: §cAC §8(§7XZ out§8)";
|
|
||||||
}
|
|
||||||
return "§eRedstone§8: §cAC";
|
|
||||||
case EIGENCRAFT:
|
|
||||||
return null;
|
|
||||||
case VANILLA:
|
|
||||||
default:
|
|
||||||
return "§eRedstone§8: §cVanilla";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -23,7 +23,7 @@ import de.steamwar.bausystem.BauSystem;
|
|||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.SWUtils;
|
import de.steamwar.bausystem.SWUtils;
|
||||||
import de.steamwar.bausystem.features.gui.editor.BauGuiMapping;
|
import de.steamwar.bausystem.features.gui.editor.BauGuiMapping;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.inventory.SWInventory;
|
import de.steamwar.inventory.SWInventory;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,7 +21,7 @@ package de.steamwar.bausystem.features.gui;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+5
-5
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,8 +21,8 @@ package de.steamwar.bausystem.features.gui.editor;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.features.gui.BauGUI;
|
import de.steamwar.bausystem.features.gui.BauGUI;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.data.CMDs;
|
import de.steamwar.core.TrickyTrialsWrapper;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import de.steamwar.inventory.SWListInv;
|
import de.steamwar.inventory.SWListInv;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
@@ -73,8 +73,8 @@ public class BauGuiEditor implements Listener {
|
|||||||
|
|
||||||
inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> {
|
inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> {
|
||||||
}).getItemStack());
|
}).getItemStack());
|
||||||
inv.setItem(mapping.getSize() + 6, new SWItem(Material.TURTLE_SCUTE, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
|
inv.setItem(mapping.getSize() + 6, new SWItem(TrickyTrialsWrapper.impl.getTurtleScute(), BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
|
||||||
inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).setCustomModelData(CMDs.BACK).getItemStack());
|
inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).getItemStack());
|
||||||
|
|
||||||
p.openInventory(inv);
|
p.openInventory(inv);
|
||||||
p.getOpenInventory().setCursor(cursor == null ? new SWItem().getItemStack() : cursor);
|
p.getOpenInventory().setCursor(cursor == null ? new SWItem().getItemStack() : cursor);
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -21,7 +21,7 @@ package de.steamwar.bausystem.features.gui.editor;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
|||||||
+18
-17
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -22,12 +22,13 @@ package de.steamwar.bausystem.features.gui.editor;
|
|||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.configplayer.Config;
|
import de.steamwar.bausystem.configplayer.Config;
|
||||||
import de.steamwar.bausystem.features.gui.BauGUI;
|
import de.steamwar.bausystem.features.gui.BauGUI;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
import yapion.hierarchy.types.YAPIONObject;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -51,15 +52,15 @@ public class BauGuiMapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Config config;
|
private final YAPIONObject object;
|
||||||
@Getter
|
@Getter
|
||||||
private final Player owner;
|
private final Player owner;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private boolean saved;
|
private boolean saved;
|
||||||
|
|
||||||
protected BauGuiMapping(Config config, Player p) {
|
protected BauGuiMapping(YAPIONObject object, Player p) {
|
||||||
this.config = config;
|
this.object = object;
|
||||||
this.owner = p;
|
this.owner = p;
|
||||||
fromUUID.put(p.getUniqueId(), this);
|
fromUUID.put(p.getUniqueId(), this);
|
||||||
mappings.add(this);
|
mappings.add(this);
|
||||||
@@ -69,18 +70,19 @@ public class BauGuiMapping {
|
|||||||
BauGuiMapping mapping = fromUUID.get(p.getUniqueId());
|
BauGuiMapping mapping = fromUUID.get(p.getUniqueId());
|
||||||
|
|
||||||
if (mapping == null) {
|
if (mapping == null) {
|
||||||
mapping = new BauGuiMapping(Config.STORE.get(p), p);
|
YAPIONObject yapionObject = Config.getInstance().get(p);
|
||||||
|
mapping = new BauGuiMapping(yapionObject.getObject("baugui"), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShown(int id) {
|
public boolean isShown(int id) {
|
||||||
return config.getBauGui().getOrDefault(id, -1) >= 0;
|
return object.getPlainValueOrDefault(Integer.toString(id), -1) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSlot(int id) {
|
public int getSlot(int id) {
|
||||||
return config.getBauGui().get(id);
|
return object.getPlainValue(Integer.toString(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, Integer> getMapping() {
|
public Map<Integer, Integer> getMapping() {
|
||||||
@@ -92,7 +94,7 @@ public class BauGuiMapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return config.getBauGuiSize();
|
return object.getPlainValueOrDefault("size", 45);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSize(int size) {
|
public void setSize(int size) {
|
||||||
@@ -100,7 +102,7 @@ public class BauGuiMapping {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.setBauGuiSize(size);
|
object.add("size", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tick() {
|
private void tick() {
|
||||||
@@ -109,17 +111,16 @@ public class BauGuiMapping {
|
|||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
if (saved) return;
|
if (saved) return;
|
||||||
Config current = Config.STORE.get(owner);
|
YAPIONObject config = Config.getInstance().get(owner);
|
||||||
current.setBauGui(config.getBauGui());
|
config.add("baugui", object);
|
||||||
current.setBauGuiSize(config.getBauGuiSize());
|
Config.getInstance().save(owner);
|
||||||
Config.STORE.save(owner);
|
|
||||||
saved = true;
|
saved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Integer, Integer> internalReadMap() {
|
private Map<Integer, Integer> internalReadMap() {
|
||||||
Map<Integer, Integer> map = new HashMap<>();
|
Map<Integer, Integer> map = new HashMap<>();
|
||||||
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
||||||
Integer value = config.getBauGui().getOrDefault(e.getKey(), -1);
|
Integer value = object.getPlainValueOrDefault(e.getKey().toString(), -1);
|
||||||
if (value == -1) continue;
|
if (value == -1) continue;
|
||||||
map.put(e.getKey(), value);
|
map.put(e.getKey(), value);
|
||||||
}
|
}
|
||||||
@@ -128,10 +129,10 @@ public class BauGuiMapping {
|
|||||||
|
|
||||||
private void internalWriteMap(Map<Integer, Integer> map) {
|
private void internalWriteMap(Map<Integer, Integer> map) {
|
||||||
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
||||||
config.getBauGui().remove(e.getKey());
|
object.remove(e.getKey().toString());
|
||||||
Integer value = map.getOrDefault(e.getKey(), -1);
|
Integer value = map.getOrDefault(e.getKey(), -1);
|
||||||
if (value == -1) continue;
|
if (value == -1) continue;
|
||||||
config.getBauGui().put(e.getKey(), value);
|
object.add(e.getKey().toString(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-31
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -20,23 +20,39 @@
|
|||||||
package de.steamwar.bausystem.features.hotbar;
|
package de.steamwar.bausystem.features.hotbar;
|
||||||
|
|
||||||
import de.steamwar.bausystem.configplayer.Config;
|
import de.steamwar.bausystem.configplayer.Config;
|
||||||
|
import de.steamwar.core.Core;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import yapion.hierarchy.types.YAPIONArray;
|
||||||
|
import yapion.hierarchy.types.YAPIONObject;
|
||||||
|
import yapion.hierarchy.types.YAPIONValue;
|
||||||
|
import yapion.parser.YAPIONParser;
|
||||||
|
import yapion.serializing.YAPIONDeserializer;
|
||||||
|
import yapion.serializing.YAPIONSerializer;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class DefaultHotbar {
|
public class DefaultHotbar {
|
||||||
|
|
||||||
|
private final YAPIONArray DEFAULT_HOTBAR = YAPIONParser.parse("{[{@type(org.bukkit.inventory.ItemStack)v(2230)type(WOODEN_AXE)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(WorldEdit Wand)lore{@type(java.util.ArrayList)values[Left click: select pos #1,Right click: select pos #2]}}},{@type(org.bukkit.inventory.ItemStack)v(2230)type(COMPASS)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(Navigation Wand)lore{@type(java.util.ArrayList)values[Left click: jump to location,Right click: pass through walls]}}},null,null,null,null,null,null,{@type(org.bukkit.inventory.ItemStack)v(2230)type(NETHER_STAR)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(§eBau GUI)}},null,null,{@type(org.bukkit.inventory.ItemStack)v(3117)type(ELYTRA)},null]}").getArray("");
|
||||||
|
|
||||||
public void updateHotbar(Player p) {
|
public void updateHotbar(Player p) {
|
||||||
ItemStack[] hotbar = new ItemStack[13];
|
ItemStack[] hotbar = new ItemStack[13];
|
||||||
System.arraycopy(p.getInventory().getContents(), 0, hotbar, 0, 9);
|
System.arraycopy(p.getInventory().getContents(), 0, hotbar, 0, 9);
|
||||||
System.arraycopy(p.getInventory().getArmorContents(), 0, hotbar, 9, 4);
|
System.arraycopy(p.getInventory().getArmorContents(), 0, hotbar, 9, 4);
|
||||||
Config.STORE.get(p).setHotbar(copy(hotbar));
|
YAPIONArray yapionArray = new YAPIONArray();
|
||||||
Config.STORE.save(p);
|
for (ItemStack itemStack : hotbar) {
|
||||||
|
if (itemStack != null) {
|
||||||
|
yapionArray.add(YAPIONSerializer.serialize(itemStack));
|
||||||
|
} else {
|
||||||
|
yapionArray.add(new YAPIONValue<>(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Config.getInstance().get(p).add("hotbar-" + Core.getVersion(), yapionArray);
|
||||||
|
Config.getInstance().save(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHotbar(Player p) {
|
public void setHotbar(Player p) {
|
||||||
@@ -50,34 +66,28 @@ public class DefaultHotbar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack[] getItems(Player p) {
|
public ItemStack[] getItems(Player p) {
|
||||||
return copy(Config.STORE.get(p).getHotbar());
|
Config.getInstance().get(p).remap("hotbar", "hotbar-19");
|
||||||
}
|
YAPIONArray yapionArray = Config.getInstance().get(p).getYAPIONArrayOrSetDefault("hotbar-" + Core.getVersion(), defaultHotbar());
|
||||||
|
|
||||||
public ItemStack[] defaultHotbar() {
|
|
||||||
ItemStack[] hotbar = new ItemStack[13];
|
ItemStack[] hotbar = new ItemStack[13];
|
||||||
hotbar[0] = item(Material.WOODEN_AXE, "WorldEdit Wand", "Left click: select pos #1", "Right click: select pos #2");
|
Set<Integer> invalid = new HashSet<>();
|
||||||
hotbar[1] = item(Material.COMPASS, "Navigation Wand", "Left click: jump to location", "Right click: pass through walls");
|
yapionArray.forEach((integer, yapionAnyType) -> {
|
||||||
hotbar[8] = item(Material.NETHER_STAR, "§eBau GUI");
|
if (yapionAnyType instanceof YAPIONValue) {
|
||||||
hotbar[11] = new ItemStack(Material.ELYTRA);
|
hotbar[integer] = null;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
hotbar[integer] = YAPIONDeserializer.deserialize((YAPIONObject) yapionAnyType);
|
||||||
|
} catch (Exception e) {
|
||||||
|
invalid.add(integer);
|
||||||
|
hotbar[integer] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
invalid.forEach(i -> yapionArray.set(i, new YAPIONValue<>(null)));
|
||||||
|
if (!invalid.isEmpty()) Config.getInstance().save(p);
|
||||||
return hotbar;
|
return hotbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ItemStack item(Material material, String name, String... lore) {
|
public YAPIONArray defaultHotbar() {
|
||||||
ItemStack itemStack = new ItemStack(material);
|
return DEFAULT_HOTBAR;
|
||||||
ItemMeta meta = itemStack.getItemMeta();
|
|
||||||
meta.setDisplayName(name);
|
|
||||||
if (lore.length > 0) {
|
|
||||||
meta.setLore(List.of(lore));
|
|
||||||
}
|
|
||||||
itemStack.setItemMeta(meta);
|
|
||||||
return itemStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ItemStack[] copy(ItemStack[] hotbar) {
|
|
||||||
ItemStack[] copy = new ItemStack[13];
|
|
||||||
for (int i = 0; i < Math.min(hotbar.length, copy.length); i++) {
|
|
||||||
copy[i] = hotbar[i] == null ? null : hotbar[i].clone();
|
|
||||||
}
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -31,7 +31,7 @@ public class HotbarListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (allNull(event.getPlayer().getInventory().getContents()) && allNull(event.getPlayer().getInventory().getArmorContents())) {
|
if (allNull(event.getPlayer().getInventory().getContents()) && allNull(event.getPlayer().getInventory().getArmorContents())) {
|
||||||
DefaultHotbar.setHotbar(event.getPlayer());
|
DefaultHotbar.setHotbar(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user