diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..94f6f5c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +# Shared TFMC XML formatting; see Docs/POM-CONVENTIONS.md. +[*.xml] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.github/dependencies.sha256 b/.github/dependencies.sha256 new file mode 100644 index 0000000..b988d80 --- /dev/null +++ b/.github/dependencies.sha256 @@ -0,0 +1,2 @@ +14850d7454374d7312305d3e84a391be720301e5964963f869b27ae97f6264eb libs/MMOCore-1.13.1.jar +660ff2a6ec86bc8d7779948cf65c1637e271a16e1ef812d6a273f4a5c5eec73c libs/MythicLib-1.7.jar diff --git a/.github/scripts/install-local-dependencies.sh b/.github/scripts/install-local-dependencies.sh new file mode 100644 index 0000000..06358db --- /dev/null +++ b/.github/scripts/install-local-dependencies.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# Run from the repository root after downloading the pinned JARs. +# Hash-qualified versions prevent different private JARs sharing a Maven cache key. +sha256sum --check .github/dependencies.sha256 + +mvn -B --no-transfer-progress org.apache.maven.plugins:maven-install-plugin:3.1.4:install-file \ + -Dfile="libs/MMOCore-1.13.1.jar" -DgroupId="local" -DartifactId="MMOCore" \ + -Dversion="1.13.1-tfmc-14850d745437" -Dpackaging=jar -DgeneratePom=true "$@" +mvn -B --no-transfer-progress org.apache.maven.plugins:maven-install-plugin:3.1.4:install-file \ + -Dfile="libs/MythicLib-1.7.jar" -DgroupId="local" -DartifactId="MythicLib" \ + -Dversion="1.7-tfmc-660ff2a6ec86" -Dpackaging=jar -DgeneratePom=true "$@" diff --git a/.github/scripts/plugin-artifact.py b/.github/scripts/plugin-artifact.py new file mode 100644 index 0000000..c730186 --- /dev/null +++ b/.github/scripts/plugin-artifact.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Validate the Maven runtime JAR and optionally stage a release bundle.""" +import argparse +import hashlib +import json +import os +from pathlib import Path +import re +import shutil +import zipfile + + +def validate(source, version): + source = Path(source).resolve() + target = Path.cwd().resolve() / "target" + if not source.is_relative_to(target) or not source.is_file(): + raise ValueError("Expected the Maven runtime JAR inside target/") + if not re.fullmatch(r"[a-z][a-z0-9]*-" + re.escape(version) + r"\.jar", source.name): + raise ValueError("Runtime JAR filename must use a lowercase alphanumeric name followed by the Maven version") + with zipfile.ZipFile(source) as jar: + descriptors = {"plugin.yml", "paper-plugin.yml"}.intersection(jar.namelist()) + if not descriptors: + raise ValueError("Runtime JAR has no plugin descriptor") + if jar.testzip() is not None: + raise ValueError("Runtime JAR is corrupt") + for name in descriptors: + text = jar.read(name).decode("utf-8-sig") + versions = re.findall( + r'''^version:[ \t]*(?:"([^"\r\n]*)"|'([^'\r\n]*)'|([^\s#]+))(?:(?:[ \t]+\#[^\r\n]*)|[ \t]*)\r?$''', + text, re.MULTILINE, + ) + if len(versions) != 1 or next((v for v in versions[0] if v), "") != version: + raise ValueError(f"{name} version must match Maven version {version}") + return source + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--jar", required=True, type=Path) + parser.add_argument("--version", required=True) + parser.add_argument("--stage", type=Path) + parser.add_argument("--dependencies", type=Path) + args = parser.parse_args() + try: + source = validate(args.jar, args.version) + if args.stage: + if os.environ["TAG"] != f"v{args.version}": + raise ValueError("Release tag must match the Maven version") + dependencies = json.loads(args.dependencies.read_text()) if args.dependencies else [] + digest = hashlib.sha256(source.read_bytes()).hexdigest() + metadata = { + "repository": os.environ["GITHUB_REPOSITORY"], + "commit": os.environ["GITHUB_SHA"], + "tag": os.environ["TAG"], + "run": f"{os.environ['GITHUB_SERVER_URL']}/{os.environ['GITHUB_REPOSITORY']}/actions/runs/{os.environ['GITHUB_RUN_ID']}", + "plugin_dependencies": dependencies, + "artifact": source.name, + "sha256": digest, + } + args.stage.mkdir() + shutil.copyfile(source, args.stage / source.name) + (args.stage / "SHA256SUMS").write_text(f"{digest} {source.name}\n") + (args.stage / "build.json").write_text(json.dumps(metadata, indent=2) + "\n") + print(f"Verified {source.name}: filename and embedded version match {args.version}") + except (ValueError, OSError, KeyError, zipfile.BadZipFile) as error: + parser.exit(1, f"Plugin artifact validation failed: {error}\n") + + +if __name__ == "__main__": + main() diff --git a/.github/scripts/prepare-release.sh b/.github/scripts/prepare-release.sh new file mode 100644 index 0000000..c06d651 --- /dev/null +++ b/.github/scripts/prepare-release.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +: "${GH_TOKEN:?Set DEPS_TOKEN with Contents read access to TF-Minecraft/ServerAssets}" +ref=183a187cf6128371a31ad20f3b524f6f30d537b9 +mkdir -p libs +curl --fail --location --silent --show-error --retry 3 -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github.raw+json" "https://api.github.com/repos/TF-Minecraft/ServerAssets/contents/jars/14850d745437/MMOCore-1.13.1.jar?ref=$ref" > "libs/MMOCore-1.13.1.jar" +curl --fail --location --silent --show-error --retry 3 -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github.raw+json" "https://api.github.com/repos/TF-Minecraft/ServerAssets/contents/jars/660ff2a6ec86/MythicLib-1.7.jar?ref=$ref" > "libs/MythicLib-1.7.jar" +bash .github/scripts/install-local-dependencies.sh "$@" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..40b7935 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,77 @@ +name: Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: '21' + - name: Install shared plugin dependencies + uses: TF-Minecraft/TLibs/.github/actions/setup-plugins@4f7a3545063cb2e8d06a034687c817ab863f0835 + with: + mode: pinned + private-token: ${{ secrets.DEPS_TOKEN }} + + - name: Prepare pinned dependencies + env: + GH_TOKEN: ${{ secrets.DEPS_TOKEN }} + run: bash .github/scripts/prepare-release.sh + - name: Set build version + id: dev + shell: bash + run: | + dev_version="main-SNAPSHOT" + if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then + dev_version="DEV-$(date -u +%Y%m%d-%H%M)" + fi + mvn -B --no-transfer-progress -P'!deploy-live' org.codehaus.mojo:versions-maven-plugin:2.22.0:set \ + -DnewVersion="$dev_version" -DgenerateBackupPoms=false + mvn -B --no-transfer-progress -P'!deploy-live' help:evaluate \ + -Dexpression=project.build.finalName -Doutput="$RUNNER_TEMP/final-name" + final_name=$(cat "$RUNNER_TEMP/final-name") + [[ "$final_name" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || exit 1 + echo "version=$dev_version" >> "$GITHUB_OUTPUT" + echo "name=$final_name" >> "$GITHUB_OUTPUT" + echo "jar=target/$final_name.jar" >> "$GITHUB_OUTPUT" + + - name: Run unit tests and build + run: mvn -B --no-transfer-progress -P'!deploy-live' clean verify -DskipTests=false -Dmaven.test.skip=false + + - name: Verify runtime JAR + env: + ARTIFACT_PATH: ${{ steps.dev.outputs.jar }} + BUILD_VERSION: ${{ steps.dev.outputs.version }} + run: python3 .github/scripts/plugin-artifact.py --jar "$ARTIFACT_PATH" --version "$BUILD_VERSION" + + - if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.dev.outputs.name }}-${{ github.run_id }}-${{ github.run_attempt }} + path: | + ${{ steps.dev.outputs.jar }} + .build/plugin-dependencies.json + include-hidden-files: true + if-no-files-found: error + + - name: Upload unit test reports + if: ${{ !cancelled() && hashFiles('target/surefire-reports/*.xml') != '' }} + uses: actions/upload-artifact@v7 + with: + name: unit-test-reports-${{ github.run_id }}-${{ github.run_attempt }} + path: target/surefire-reports/ + if-no-files-found: error diff --git a/.github/workflows/maven-release.yml b/.github/workflows/maven-release.yml new file mode 100644 index 0000000..9d015e5 --- /dev/null +++ b/.github/workflows/maven-release.yml @@ -0,0 +1,138 @@ +name: Maven plugin release + +on: + workflow_call: + inputs: + java-version: + required: true + type: string + secrets: + DEPS_TOKEN: + required: false + +permissions: + contents: read + +concurrency: + group: plugin-release-${{ github.repository }}-${{ github.ref }} + cancel-in-progress: false + +defaults: + run: + shell: bash + +jobs: + build: + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: ${{ inputs.java-version }} + + - name: Validate release version + env: + TAG: ${{ github.ref_name }} + run: | + [[ "$TAG" =~ ^v[0-9]+\.[0-9]+(\.[0-9]+)?(-[0-9A-Za-z]+([.-][0-9A-Za-z]+)*)?$ ]] || { + echo '::error::Expected vMAJOR.MINOR or vMAJOR.MINOR.PATCH, with an optional prerelease suffix.' + exit 1 + } + [[ "${TAG^^}" != *SNAPSHOT* ]] || exit 1 + + - name: Install shared plugin dependencies + uses: TF-Minecraft/TLibs/.github/actions/setup-plugins@4f7a3545063cb2e8d06a034687c817ab863f0835 + with: + mode: pinned + private-token: ${{ secrets.DEPS_TOKEN }} + + - name: Prepare pinned dependencies + env: + GH_TOKEN: ${{ secrets.DEPS_TOKEN }} + run: | + if [[ -f .github/scripts/prepare-release.sh ]]; then + bash .github/scripts/prepare-release.sh + fi + + - name: Set version from tag and build + id: maven + env: + TAG: ${{ github.ref_name }} + run: | + mvn -B --no-transfer-progress -P'!deploy-live' org.codehaus.mojo:versions-maven-plugin:2.22.0:set \ + -DnewVersion="${TAG#v}" -DgenerateBackupPoms=false + mvn -B --no-transfer-progress -P'!deploy-live' help:evaluate \ + -Dexpression=project.build.finalName -Doutput="$RUNNER_TEMP/final-name" + final_name=$(cat "$RUNNER_TEMP/final-name") + [[ "$final_name" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || exit 1 + echo "jar=target/$final_name.jar" >> "$GITHUB_OUTPUT" + mvn -B --no-transfer-progress -P'!deploy-live' clean verify -DskipTests=false -Dmaven.test.skip=false + + - name: Stage only the release JAR + env: + ARTIFACT_PATH: ${{ steps.maven.outputs.jar }} + TAG: ${{ github.ref_name }} + run: | + python3 .github/scripts/plugin-artifact.py \ + --jar "$ARTIFACT_PATH" --version "${TAG#v}" \ + --stage "$RUNNER_TEMP/plugin-release" \ + --dependencies .build/plugin-dependencies.json + + - uses: actions/upload-artifact@v7 + with: + name: plugin-release-${{ github.sha }} + path: ${{ runner.temp }}/plugin-release/ + if-no-files-found: error + retention-days: 30 + + publish: + needs: build + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + contents: write + steps: + - uses: actions/download-artifact@v8 + with: + name: plugin-release-${{ github.sha }} + path: release + + - name: Create draft release + working-directory: release + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + TAG: ${{ github.ref_name }} + run: | + sha256sum --check SHA256SUMS + flags=() + if [[ "$TAG" == *-* ]]; then flags+=(--prerelease); fi + gh api --method POST "repos/$GH_REPO/releases/generate-notes" \ + -f tag_name="$TAG" --jq .body > "$RUNNER_TEMP/release-changes.md" + python3 - <<'PY' + import os, re + from pathlib import Path + from urllib.parse import quote + temp = Path(os.environ['RUNNER_TEMP']) + changes = (temp / 'release-changes.md').read_text().strip() + changes = re.sub(r"^## What's Changed\s*", '', changes) + changes = re.sub(r'^(#{1,5}) ', r'\1# ', changes, flags=re.MULTILINE) + lines = ['## Changes', '', changes or 'Initial release.', '', '## Downloads', ''] + assets = sorted([*Path('.').glob('*.jar'), *Path('.').glob('*.tar.gz')]) + assets += [Path('SHA256SUMS'), Path('build.json')] + base = f"https://github.com/{os.environ['GH_REPO']}/releases/download/{quote(os.environ['TAG'], safe='')}/" + for asset in assets: + if not asset.is_file(): + raise SystemExit(f'Missing release asset: {asset}') + description = {'SHA256SUMS': ' — SHA-256 checksums.', 'build.json': ' — Build metadata.'}.get(asset.name, '') + lines.append(f'- [`{asset.name}`]({base}{quote(asset.name)}){description}') + (temp / 'release-notes.md').write_text('\n'.join(lines) + '\n') + PY + gh release create "$TAG" ./*.jar SHA256SUMS build.json \ + --verify-tag --draft --title "$TAG" --notes-file "$RUNNER_TEMP/release-notes.md" "${flags[@]}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..241e773 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,18 @@ +name: Release + +on: + push: + tags: ['v*'] + +permissions: + contents: read + +jobs: + release: + permissions: + contents: write + uses: ./.github/workflows/maven-release.yml + with: + java-version: '21' + secrets: + DEPS_TOKEN: ${{ secrets.DEPS_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fee0cd8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +# Build output +target/ +build/ +out/ +dist/ +nbbuild/ +nbdist/ +*.class +dependency-reduced-pom.xml +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties + +# Build dependencies +/.build/ +*.jar +!.mvn/wrapper/maven-wrapper.jar + +# Python caches and environments +__pycache__/ +*.py[cod] +.venv/ +venv/ + +# IDE files +.idea/ +*.iml +*.ipr +*.iws +.vscode/ +.project +.classpath +.settings/ +nbproject/private/ +.nb-gradle/ + +# Logs and temporary files +*.log +hs_err_pid* +replay_pid* +*.bak +*.swp +*.tmp +*~ + +# Operating system files +.DS_Store +Thumbs.db +Desktop.ini + +# Local investigation notes and test artifacts +/.scratch/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9d00de5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5f5ae91 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Gathering + +> Scatter hidden gathering spots across the world for TF-Minecraft characters to discover and harvest. + +Gathering spawns hidden resource spots across configured regions of the world. +Roleplay characters notice nearby spots over time, guided by their attributes and +profession, and can then harvest them for configurable, weighted drops. + +## Features + +- **World spawning** — spots appear periodically in random chunks within configured + world bounds, filtered by biome, altitude, and surface block. +- **Character discovery** — each RPCharacters character discovers spots separately, + with a chance improved by wisdom, intelligence, and an optional MMOCore profession + level. +- **Visible only once found** — discovered spots are marked by a particle ring that + only that character can see. +- **Weighted drops** — spot types roll weighted drop categories, and each category + rolls weighted TLibs item paths with configurable amounts. +- **Chunk cooldowns** — a harvested chunk rests before it can host another spot, and + chunks with no valid surface are excluded from future spawning. +- **Administrator tools** — reload configuration, inspect status, force a spawn, + clear excluded chunks, and use an admin mode that reveals every spot. +- **Persistent state** — active spots, character discoveries, chunk cooldowns, and + excluded chunks survive server restarts. + +Originally created by [Drefvelin](https://github.com/Drefvelin). + +## Documentation + +[Project documentation](https://github.com/TF-Minecraft/Docs/blob/main/projects/Gathering/README.md) + +Technical documentation is maintained in [TF-Minecraft/Docs](https://github.com/TF-Minecraft/Docs). + +## License + +Copyright (c) 2026 TF-Minecraft contributors. + +TF-Minecraft-authored material in this repository is licensed under the +[Artistic License 2.0](LICENSE). Third-party dependencies and pre-existing +material retain their own licenses. diff --git a/pom.xml b/pom.xml index e0806e3..1334ba8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,82 +1,99 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 net.tfminecraft gathering - 0.1.0-ALPHA + main-SNAPSHOT + + Gathering + https://github.com/TF-Minecraft/Gathering - 17 - 17 + 21 + UTF-8 + full + 2.0.2 + 2.0.1 - local - gson - 2.10.1 - system - D:/Dokumenter/My Plugins/Reference Libs/gson-2.10.1.jar + io.papermc.paper + paper-api + 1.21.10-R0.1-SNAPSHOT + provided local - spigot-api - 1.21.8 - system - D:/Dokumenter/My Plugins/Reference Libs/spigot-api.jar + MMOCore + 1.13.1-tfmc-14850d745437 + provided local - TLibs - 1.0 - system - D:/Dokumenter/My Plugins/TFMC/TLibs/TLibs.jar + MythicLib + 1.7-tfmc-660ff2a6ec86 + provided - local - RPCharacters - 1.1.5 - system - D:/Dokumenter/My Plugins/TFMC/RPCharacters/rpcharacters-1.1.5.jar + me.plugins + tlibs + ${tlibs.version} + provided + + + * + * + + - local - MMOCore - 1.13.1 - system - D:/Dokumenter/My Plugins/Reference Libs/MMOCore-1.13.1.jar - - - local - MythicLib - 1.7 - system - D:/Dokumenter/My Plugins/Reference Libs/MythicLib-1.7.jar + net.tfminecraft + rpcharacters + ${rpcharacters.version} + provided + + + * + * + + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + + + + src/main/resources + true + + plugin.yml + + + + src/main/resources + false + + plugin.yml + + + org.apache.maven.plugins - maven-antrun-plugin - - - package - run - - - - - - - + maven-compiler-plugin + 3.14.1 - diff --git a/src/main/java/net/tfminecraft/gathering/discovery/SpotDiscoveryService.java b/src/main/java/net/tfminecraft/gathering/discovery/SpotDiscoveryService.java index 808063b..5718d15 100644 --- a/src/main/java/net/tfminecraft/gathering/discovery/SpotDiscoveryService.java +++ b/src/main/java/net/tfminecraft/gathering/discovery/SpotDiscoveryService.java @@ -6,9 +6,9 @@ import org.bukkit.entity.Player; -import me.Plugins.TLibs.Objects.API.SubAPI.StringFormatter; -import net.tfminecraft.RPCharacters.Objects.Attributes.AttributeModifier; -import net.tfminecraft.RPCharacters.Objects.RPCharacter; +import net.tfminecraft.tlibs.objects.api.subapi.StringFormatter; +import net.tfminecraft.rpcharacters.objects.attributes.AttributeModifier; +import net.tfminecraft.rpcharacters.objects.RPCharacter; import net.tfminecraft.gathering.cache.Cache; import net.tfminecraft.gathering.loader.SpotTypeLoader; import net.tfminecraft.gathering.manager.SpotManager; diff --git a/src/main/java/net/tfminecraft/gathering/loader/SpotTypeLoader.java b/src/main/java/net/tfminecraft/gathering/loader/SpotTypeLoader.java index 2df14d0..4095f30 100644 --- a/src/main/java/net/tfminecraft/gathering/loader/SpotTypeLoader.java +++ b/src/main/java/net/tfminecraft/gathering/loader/SpotTypeLoader.java @@ -12,7 +12,10 @@ import java.util.concurrent.ThreadLocalRandom; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.block.Biome; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; @@ -186,10 +189,12 @@ private Set parseBiomes(List names) { Set out = new HashSet<>(); for (String name : names) { if (name == null || name.isBlank()) continue; - try { - out.add(Biome.valueOf(name.trim().toUpperCase(Locale.ROOT))); - } catch (IllegalArgumentException ex) { + NamespacedKey key = NamespacedKey.fromString(name.trim().toLowerCase(Locale.ROOT)); + Biome biome = key == null ? null : RegistryAccess.registryAccess().getRegistry(RegistryKey.BIOME).get(key); + if (biome == null) { Gathering.plugin.getLogger().warning("Unknown biome in spot-types: " + name); + } else { + out.add(biome); } } return out; diff --git a/src/main/java/net/tfminecraft/gathering/utils/CharacterBridge.java b/src/main/java/net/tfminecraft/gathering/utils/CharacterBridge.java index d5e0317..e0f7174 100644 --- a/src/main/java/net/tfminecraft/gathering/utils/CharacterBridge.java +++ b/src/main/java/net/tfminecraft/gathering/utils/CharacterBridge.java @@ -4,9 +4,9 @@ import org.bukkit.entity.Player; -import net.tfminecraft.RPCharacters.Managers.PlayerManager; -import net.tfminecraft.RPCharacters.Objects.PlayerData; -import net.tfminecraft.RPCharacters.Objects.RPCharacter; +import net.tfminecraft.rpcharacters.managers.PlayerManager; +import net.tfminecraft.rpcharacters.objects.PlayerData; +import net.tfminecraft.rpcharacters.objects.RPCharacter; public final class CharacterBridge { diff --git a/src/main/java/net/tfminecraft/gathering/utils/ItemResolver.java b/src/main/java/net/tfminecraft/gathering/utils/ItemResolver.java index 791d0e8..cf53278 100644 --- a/src/main/java/net/tfminecraft/gathering/utils/ItemResolver.java +++ b/src/main/java/net/tfminecraft/gathering/utils/ItemResolver.java @@ -3,7 +3,7 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import me.Plugins.TLibs.TLibs; +import net.tfminecraft.tlibs.TLibs; public final class ItemResolver { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c6a380b..a627132 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ main: net.tfminecraft.gathering.Gathering -api-version: 1.20 +api-version: '1.21.10' name: Gathering -version: 0.1.0-ALPHA +version: '${project.version}' author: Drefvelin depend: [TLibs, RPCharacters]