diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 00000000000..560dcad5af7
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,4 @@
+# .git-blame-ignore-revs
+
+# cleanup lang package - mostly renaming variables
+98abf5d7773df11c65d66e4e9485d0f1e3ef8821
diff --git a/.github/assets/Cover.jpg b/.github/assets/Cover.jpg
new file mode 100644
index 00000000000..a77391fd6fe
Binary files /dev/null and b/.github/assets/Cover.jpg differ
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 7df8e33c9b1..5b930003730 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,15 +1,17 @@
version: 2
updates:
- package-ecosystem: "github-actions"
+ target-branch: "dev/patch"
directory: "/"
schedule:
- interval: "daily"
+ interval: "weekly"
labels:
- "dependencies"
- - package-ecosystem: gradle
+ - package-ecosystem: "gradle"
+ target-branch: "dev/patch"
directory: "/"
schedule:
- interval: daily
+ interval: "weekly"
labels:
- "dependencies"
open-pull-requests-limit: 10
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ce87d77a996..698a65a0554 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -2,6 +2,6 @@
---
-**Target Minecraft Versions:**
-**Requirements:**
-**Related Issues:**
+**Target Minecraft Versions:** any
+**Requirements:** none
+**Related Issues:** none
diff --git a/.github/workflows/cleanup-docs.yml b/.github/workflows/cleanup-docs.yml
new file mode 100644
index 00000000000..68d12e84dc1
--- /dev/null
+++ b/.github/workflows/cleanup-docs.yml
@@ -0,0 +1,39 @@
+name: Cleanup nightly documentation
+on: delete
+jobs:
+ cleanup-nightly-docs:
+ if: github.event.ref_type == 'branch'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ env:
+ DELETED_BRANCH: ${{ github.event.ref }}
+ run: |
+ BRANCH_NAME="${DELETED_BRANCH#refs/*/}"
+ echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/nightly/${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.repository.default_branch }}
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Cleanup nightly documentation
+ env:
+ DOCS_OUTPUT_DIR: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ run: |
+ rm -rf ${DOCS_OUTPUT_DIR} || true
+ - name: Push nightly documentation cleanup
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Nightly Docs Bot
+ git_email: nightlydocs@skriptlang.org
+ git_commit_message: "Delete ${{ steps.configuration.outputs.BRANCH_NAME }} branch nightly docs"
diff --git a/.github/workflows/docs/generate-docs/action.yml b/.github/workflows/docs/generate-docs/action.yml
new file mode 100644
index 00000000000..e033996868e
--- /dev/null
+++ b/.github/workflows/docs/generate-docs/action.yml
@@ -0,0 +1,109 @@
+name: Generate documentation
+
+inputs:
+ docs_output_dir:
+ description: "The directory to generate the documentation into"
+ required: true
+ type: string
+ docs_repo_dir:
+ description: "The skript-docs repository directory"
+ required: true
+ type: string
+ skript_repo_dir:
+ description: "The skript repository directory"
+ required: true
+ type: string
+ is_release:
+ description: "Designates whether to generate nightly or release documentation"
+ required: false
+ default: false
+ type: boolean
+ cleanup_pattern:
+ description: "A pattern designating which files to delete when cleaning the documentation output directory"
+ required: false
+ default: "*"
+ type: string
+ generate_javadocs:
+ description: "Designates whether to generate javadocs for this nightly documentation"
+ required: false
+ default: false
+ type: boolean
+
+outputs:
+ DOCS_CHANGED:
+ description: "Whether or not the documentation has changed since the last push"
+ value: ${{ steps.generate.outputs.DOCS_CHANGED }}
+
+runs:
+ using: 'composite'
+ steps:
+ - name: generate-docs
+ id: generate
+ shell: bash
+ env:
+ DOCS_OUTPUT_DIR: ${{ inputs.docs_output_dir }}
+ DOCS_REPO_DIR: ${{ inputs.docs_repo_dir }}
+ SKRIPT_REPO_DIR: ${{ inputs.skript_repo_dir }}
+ IS_RELEASE: ${{ inputs.is_release }}
+ CLEANUP_PATTERN: ${{ inputs.cleanup_pattern }}
+ GENERATE_JAVADOCS: ${{ inputs.generate_javadocs }}
+ run: |
+ replace_in_directory() {
+ find $1 -type f -exec sed -i -e "s/$2/$3/g" {} \;
+ }
+
+ # this should be replaced with a more reliable jq command,
+ # but it can't be right now because docs.json is actually not valid json.
+ get_skript_version_of_directory() {
+ grep skriptVersion "$1/docs.json" | cut -d\" -f 4
+ }
+
+ if [ -d "${DOCS_REPO_DIR}/docs/templates" ]
+ then
+ export SKRIPT_DOCS_TEMPLATE_DIR=${DOCS_REPO_DIR}/docs/templates
+ else # compatibility for older versions
+ export SKRIPT_DOCS_TEMPLATE_DIR=${DOCS_REPO_DIR}/doc-templates
+ fi
+
+ export SKRIPT_DOCS_OUTPUT_DIR=/tmp/generated-docs
+
+ cd $SKRIPT_REPO_DIR
+ if [[ "${IS_RELEASE}" == "true" ]]; then
+ ./gradlew genReleaseDocs releaseJavadoc
+ elif [[ "${GENERATE_JAVADOCS}" == "true" ]]; then
+ ./gradlew genNightlyDocs javadoc
+ else
+ ./gradlew genNightlyDocs
+ fi
+
+ if [ -d "${DOCS_OUTPUT_DIR}" ]; then
+ if [[ "${GENERATE_JAVADOCS}" == "true" ]]; then
+ mkdir -p "${SKRIPT_DOCS_OUTPUT_DIR}/javadocs" && cp -a "./build/docs/javadoc/." "$_"
+ fi
+
+ mkdir -p "/tmp/normalized-output-docs" && cp -a "${DOCS_OUTPUT_DIR}/." "$_"
+ mkdir -p "/tmp/normalized-generated-docs" && cp -a "${SKRIPT_DOCS_OUTPUT_DIR}/." "$_"
+
+ output_skript_version=$(get_skript_version_of_directory "/tmp/normalized-output-docs")
+ generated_skript_version=$(get_skript_version_of_directory "/tmp/normalized-generated-docs")
+
+ replace_in_directory "/tmp/normalized-output-docs" "${output_skript_version}" "Skript"
+ replace_in_directory "/tmp/normalized-generated-docs" "${generated_skript_version}" "Skript"
+
+ diff -qbr /tmp/normalized-output-docs /tmp/normalized-generated-docs || diff_exit_code=$?
+ # If diff exits with exit code 1, that means there were some differences
+ if [[ ${diff_exit_code} -eq 1 ]]; then
+ echo "DOCS_CHANGED=true" >> $GITHUB_OUTPUT
+ echo "Documentation has changed since last push"
+ else
+ echo "Documentation hasn't changed since last push"
+ fi
+ else
+ echo "DOCS_CHANGED=true" >> $GITHUB_OUTPUT
+ echo "No existing documentation found"
+ fi
+
+ rm -rf ${DOCS_OUTPUT_DIR}/${CLEANUP_PATTERN} || true
+ mkdir -p "${DOCS_OUTPUT_DIR}/" && cp -a "${SKRIPT_DOCS_OUTPUT_DIR}/." "$_"
+
+
diff --git a/.github/workflows/docs/push-docs/action.yml b/.github/workflows/docs/push-docs/action.yml
new file mode 100644
index 00000000000..477a4c46aa4
--- /dev/null
+++ b/.github/workflows/docs/push-docs/action.yml
@@ -0,0 +1,43 @@
+name: Push documentation
+
+inputs:
+ docs_repo_dir:
+ description: "The skript-docs repository directory"
+ required: true
+ type: string
+ git_email:
+ description: "The email to use for the Git commit"
+ required: true
+ type: string
+ git_name:
+ description: "The name to use for the Git commit"
+ required: true
+ type: string
+ git_commit_message:
+ description: "The message to use for the Git commit"
+ required: true
+ type: string
+
+runs:
+ using: 'composite'
+ steps:
+ - shell: bash
+ if: success()
+ env:
+ DOCS_REPO_DIR: ${{ inputs.docs_repo_dir }}
+ GIT_EMAIL: ${{ inputs.git_email }}
+ GIT_NAME: ${{ inputs.git_name }}
+ GIT_COMMIT_MESSAGE: ${{ inputs.git_commit_message }}
+ run: |
+ cd "${DOCS_REPO_DIR}"
+ git config user.name "${GIT_NAME}"
+ git config user.email "${GIT_EMAIL}"
+ git add -A
+ git commit -m "${GIT_COMMIT_MESSAGE}" || (echo "Nothing to push!" && exit 0)
+ # Attempt rebasing and pushing 5 times in case another job pushes before us
+ for i in 1 2 3 4 5
+ do
+ git pull --rebase -X theirs origin main
+ git push origin main && break
+ sleep 5
+ done
diff --git a/.github/workflows/docs/setup-docs/action.yml b/.github/workflows/docs/setup-docs/action.yml
new file mode 100644
index 00000000000..cd6c6a05216
--- /dev/null
+++ b/.github/workflows/docs/setup-docs/action.yml
@@ -0,0 +1,43 @@
+name: Setup documentation environment
+
+inputs:
+ docs_deploy_key:
+ description: "Deploy key for the skript-docs repo"
+ required: true
+ type: string
+ docs_output_dir:
+ description: "The directory to generate the documentation into"
+ required: true
+ type: string
+ cleanup_pattern:
+ description: "A pattern designating which files to delete when cleaning the documentation output directory"
+ required: false
+ default: "*"
+ type: string
+
+runs:
+ using: 'composite'
+ steps:
+ - name: Checkout skript-docs
+ uses: actions/checkout@v3
+ with:
+ repository: 'SkriptLang/skript-docs'
+ path: skript-docs
+ ssh-key: ${{ inputs.docs_deploy_key }}
+ - uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'adopt'
+ cache: gradle
+ - shell: bash
+ run: chmod +x ./skript/gradlew
+ - shell: bash
+ env:
+ DOCS_DEPLOY_KEY: ${{ inputs.docs_deploy_key }}
+ DOCS_OUTPUT_DIR: ${{ inputs.docs_output_dir }}
+ CLEANUP_PATTERN: ${{ inputs.cleanup_pattern }}
+ run: |
+ eval `ssh-agent`
+ echo "$DOCS_DEPLOY_KEY" | tr -d '\r' | ssh-add - > /dev/null
+ mkdir ~/.ssh
+ ssh-keyscan www.github.com >> ~/.ssh/known_hosts
diff --git a/.github/workflows/java-17-builds.yml b/.github/workflows/java-17-builds.yml
index 67007d76d90..a0c87141c13 100644
--- a/.github/workflows/java-17-builds.yml
+++ b/.github/workflows/java-17-builds.yml
@@ -12,9 +12,11 @@ jobs:
if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
@@ -26,7 +28,7 @@ jobs:
- name: Build Skript and run test scripts
run: ./gradlew clean skriptTestJava17
- name: Upload Nightly Build
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: success()
with:
name: skript-nightly
diff --git a/.github/workflows/java-8-builds.yml b/.github/workflows/java-8-builds.yml
index adcd71fb09b..090e6b3db6a 100644
--- a/.github/workflows/java-8-builds.yml
+++ b/.github/workflows/java-8-builds.yml
@@ -12,11 +12,13 @@ jobs:
if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt'
@@ -26,7 +28,7 @@ jobs:
- name: Build Skript and run test scripts
run: ./gradlew clean skriptTestJava8
- name: Upload Nightly Build
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: success()
with:
name: skript-nightly
diff --git a/.github/workflows/junit-17-builds.yml b/.github/workflows/junit-17-builds.yml
new file mode 100644
index 00000000000..ac8de249e1f
--- /dev/null
+++ b/.github/workflows/junit-17-builds.yml
@@ -0,0 +1,29 @@
+name: JUnit (MC 1.17+)
+
+on:
+ push:
+ branches:
+ - master
+ - 'dev/**'
+ pull_request:
+
+jobs:
+ build:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'adopt'
+ cache: gradle
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build Skript and run JUnit
+ run: ./gradlew clean JUnitJava17
diff --git a/.github/workflows/junit-8-builds.yml b/.github/workflows/junit-8-builds.yml
new file mode 100644
index 00000000000..2a9bf589e67
--- /dev/null
+++ b/.github/workflows/junit-8-builds.yml
@@ -0,0 +1,29 @@
+name: JUnit (MC 1.13-1.16)
+
+on:
+ push:
+ branches:
+ - master
+ - 'dev/**'
+ pull_request:
+
+jobs:
+ build:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'adopt'
+ cache: gradle
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build Skript and run JUnit
+ run: ./gradlew clean JUnitJava8
diff --git a/.github/workflows/nightly-docs.yml b/.github/workflows/nightly-docs.yml
new file mode 100644
index 00000000000..0d5cc824ad0
--- /dev/null
+++ b/.github/workflows/nightly-docs.yml
@@ -0,0 +1,61 @@
+name: Nightly documentation
+
+on:
+ push:
+ branches:
+ - 'dev/feature'
+ - 'dev/patch'
+ - 'enhancement/**'
+ - 'feature/**'
+ - 'fix/**'
+ tags-ignore:
+ - '**'
+
+jobs:
+ nightly-docs:
+ if: "!contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ env:
+ DOCS_DEPLOY_KEY: ${{ secrets.DOCS_DEPLOY_KEY }}
+ run: |
+ if [ -n "$DOCS_DEPLOY_KEY" ]
+ then
+ echo "DOCS_DEPLOY_KEY_PRESENT=true" >> $GITHUB_OUTPUT
+ else
+ echo "Secret 'DOCS_DEPLOY_KEY' not present. Exiting job."
+ fi
+ BRANCH_NAME="${GITHUB_REF#refs/*/}"
+ echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/nightly/${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ echo "SKRIPT_REPO_DIR=${GITHUB_WORKSPACE}/skript" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ if: steps.configuration.outputs.DOCS_DEPLOY_KEY_PRESENT == 'true'
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Generate documentation
+ id: generate
+ if: steps.configuration.outputs.DOCS_DEPLOY_KEY_PRESENT == 'true'
+ uses: ./skript/.github/workflows/docs/generate-docs
+ with:
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ skript_repo_dir: ${{ steps.configuration.outputs.SKRIPT_REPO_DIR }}
+ - name: Push nightly documentation
+ if: steps.generate.outputs.DOCS_CHANGED == 'true'
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Nightly Docs Bot
+ git_email: nightlydocs@skriptlang.org
+ git_commit_message: "Update ${{ steps.configuration.outputs.BRANCH_NAME }} branch nightly docs to ${{ github.repository }}@${{ github.sha }}"
diff --git a/.github/workflows/release-docs.yml b/.github/workflows/release-docs.yml
new file mode 100644
index 00000000000..f6f7ebc8a27
--- /dev/null
+++ b/.github/workflows/release-docs.yml
@@ -0,0 +1,80 @@
+name: Release documentation
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ release-docs:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ run: |
+ echo "BRANCH_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ echo "SKRIPT_REPO_DIR=${GITHUB_WORKSPACE}/skript" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Generate documentation
+ uses: ./skript/.github/workflows/docs/generate-docs
+ with:
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ skript_repo_dir: ${{ steps.configuration.outputs.SKRIPT_REPO_DIR }}
+ is_release: true
+ cleanup_pattern: "!(nightly|archives|templates)"
+ - name: Push release documentation
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Release Docs Bot
+ git_email: releasedocs@skriptlang.org
+ git_commit_message: "Update release docs to ${{ steps.configuration.outputs.BRANCH_NAME }}"
+
+ archive-docs:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ needs: release-docs
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ run: |
+ echo "BRANCH_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/archives/${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ echo "SKRIPT_REPO_DIR=${GITHUB_WORKSPACE}/skript" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Generate documentation
+ uses: ./skript/.github/workflows/docs/generate-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ skript_repo_dir: ${{ steps.configuration.outputs.SKRIPT_REPO_DIR }}
+ is_release: true
+ - name: Push archive documentation
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Archive Docs Bot
+ git_email: archivedocs@skriptlang.org
+ git_commit_message: "Update ${{ steps.configuration.outputs.BRANCH_NAME }} archive docs"
diff --git a/.github/workflows/repo.yml b/.github/workflows/repo.yml
index d7639b98a94..77b8a55fd4e 100644
--- a/.github/workflows/repo.yml
+++ b/.github/workflows/repo.yml
@@ -8,11 +8,13 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt'
diff --git a/.gitignore b/.gitignore
index 477d2c72451..47df9cbc0de 100755
--- a/.gitignore
+++ b/.gitignore
@@ -220,5 +220,9 @@ gradle-app.setting
# End of https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,java,eclipse,git
-# Skript test runners
+# TODO remove this in the future after some time since https://github.com/SkriptLang/Skript/pull/4979
+# This ensures developers don't upload their old existing test_runners/ folder.
test_runners/
+
+## Mac MetaData
+**/.DS_Store
diff --git a/CLOCKWORK_RELEASE_MODEL.md b/CLOCKWORK_RELEASE_MODEL.md
new file mode 100644
index 00000000000..e5e086f62eb
--- /dev/null
+++ b/CLOCKWORK_RELEASE_MODEL.md
@@ -0,0 +1,294 @@
+# Clockwork Release Model
+
+## Table of Contents
+1. [Introduction](#introduction)
+ - [Preamble](#preamble)
+ - [Motivations](#motivations)
+ - [Goals](#goals)
+ - [Non-Goals](#non-goals)
+2. [Release Types](#release-types)
+ - [Feature Releases](#feature-releases)
+ - [Patch Releases](#patch-releases)
+ - [Pre-Releases](#pre-releases)
+ - [Emergency Patch Releases](#emergency-patch-releases)
+3. [Timetable](#timetable)
+ - [Major Version Schedule](#major-version-schedule)
+ - [Pre-Release Schedule](#pre-release-schedule)
+ - [Patch Schedule](#patch-schedule)
+4. [Content Curation](#content-curation)
+ - [Labels](#labels)
+ - [Branches](#branches)
+5. [Conclusion](#conclusion)
+ - [Paradigm Versions](#addendum-1-paradigm-versions)
+ - [Failure Standards](#addendum-2-failure-standards)
+
+## Introduction
+
+### Preamble
+
+This document defines the structure of future Skript releases, the kinds of material included in releases and the outline of the dates on which releases will be published.
+
+A 'release' is the publication of a verified and signed build artefact on the GitHub releases tab, made available for all users to download and install.
+
+This document does *not* cover the distribution or publication of artifacts built in other ways (e.g. privately, from a nightly action) or those not published from our GitHub (e.g. test builds shared in our public testing group).
+
+Plans for a new release model began in March 2023 and several models were discussed, with this being the final version agreed upon by the organisation's administrative group and approved by the core contributors.
+
+### Motivations
+
+The release cycle for the `2.7.0` version was significant in that it took an unusually long time and included an unusually-large number of additions and changes.
+
+While it was not the first version to have taken a long time to finalise and produce, it was distinct in that a lot of time had passed since the previous public build of Skript having been marked stable.
+
+Members of the organisation and the wider community identified several problems that resulted from this, some of which are (not exhaustively) detailed below:
+- 291 days had passed since the previous release
+ - Users were unable to benefit from bug fixes or new features produced during that time
+ - Although beta versions were released, these were marked unstable and were not fully tested
+- When the release arrived it contained a very large number of changes and additions
+ - Some users were unaware of changes that could not be extensively documented in the changelog or were buried in a large list
+ - Users who obtained a build elsewhere (e.g. direct download, automatic installer) may have been unaware of the scale of the changes
+- Several additions were made at short notice and without sufficient testing
+ - Some of these introduced problems that required fixes in a following `2.7.1` patch
+- Several features could not be completed in time and had to be dropped to a future `2.8.0` version
+ - One result of this was that any corrections or improvements made as part of these were not present in `2.7.0`
+ - Aspects of some of these larger-scale changes had to be re-created or cherry-picked for the `2.7.0` version
+- The release lacked a clear timetable or vision for what additions to include
+ - The initial timetable was not adhered to; plans were made for pre-releases to begin at the end of November 2022, which was delayed to early December in order to accommodate a large feature PR (which was eventually dropped to `2.8.0`)
+ - Delays persisted, and the final release took place 7 months later in September 2023
+ - There was no clear cut-off point for new features; feature pull requests were being included even up to 3 days before release
+
+Of these, the principle complaint is that the `2.7.0` version took a significant amount of time to finish and this had an adverse effect on the community and the wider ecosystem.
+
+### Goals
+
+Our release model has been designed to achieve the following goals:
+1. To reduce the delay between finishing new features and releasing them to the public.
+2. To significantly reduce the time between an issue being fixed and that fix being made public in a stable build.
+3. To reduce the risk of untested changes going into a release.
+4. To make the release timetable clear and accessible.
+5. To prevent a version being indefinitely delayed to accommodate additional changes.
+
+### Non-Goals
+
+This release model is not intended to change any of the following:
+- The content or feature-theme of a particular version.
+- The process for reviewing or approving changes.
+
+## Release Types
+
+This section details the different categories of version for release.
+
+The versioning will follow the form `A.B.C`, where `B` is a [feature version](#Feature-Releases) containing changes and additions, `C` is a [patch version](#Patch-Releases) containing only issue fixes, and `A` is reserved for major paradigmatic changes.
+
+### Feature Releases
+A 'feature' version (labelled `0.X.0`) may contain:
+- Additions to the language (syntax, grammar, structures)
+- Bug fixes
+- Developer API additions and changes
+- Breaking changes1
+
+All content added to a feature version must pass through the typical review process.
+Content must also have been included in a prior [pre-release](#Pre-Releases) for public testing.
+
+> 1 Breaking changes are to be avoided where possible but may be necessary, such as in a case where a significant improvement could be made to an existing feature but only by changing its structure somehow.
+> Such changes should be clearly labelled and well documented, preferably giving users ample notice.
+
+### Patch Releases
+A 'patch' version (labelled `0.0.X`) may contain:
+- Bug fixes
+- Non-impactful2 improvements to existing features
+- Changes to meta content (e.g. documentation)
+
+There may be **very rare** occasions when a breaking change is necessary in a patch release. These may occur if and only if: either a breaking change is required in order to fix an issue, and the issue is significant enough to need fixing in a patch rather than waiting for a major release, or an issue occurred with an inclusion in the version immediately-prior to this, which must be changed or reverted in some way.
+
+All content added to a patch version must pass through the typical review process.
+
+> 2 A non-impactful change is one in which there is no apparent difference to the user in how a feature is employed or what it does but that may have a material difference in areas such as performance, efficiency or machine resource usage.
+
+### Pre-Releases
+
+A 'pre-release' version (labelled `0.X.0-preY`) will contain all of the content expected to be in the feature release immediately following this.
+
+Pre-release versions are a final opportunity for testing and getting public feedback on changes before a major release, allowing time to identify and fix any issues before the proper release, rather than needing an immediate patch.
+
+The content of a pre-release should be identical to the content of the upcoming release -- barring any bug fixes -- and new content should never be included after a pre-release.
+
+### Emergency Patch Releases
+
+An 'emergency patch' version will be released if a critical security vulnerability is reported that the organisation feels prevents an immediate risk to the user base, such that it cannot wait for the subsequent patch.
+
+An emergency patch will be labelled as another patch version (`0.0.X`). It should be noted that an emergency patch will *not* disrupt the typical timetable detailed below.
+
+These kinds of releases may be published immediately and do not have to go through the typical reviewing and testing process. \
+They must never include content, additions or unnecessary changes.
+
+The only content permitted in an emergency patch is the material needed to fix the security risk.
+
+The exact nature of the security vulnerability (such as the means to reproduce it) should not be included in the notes surrounding the release.
+
+## Timetable
+
+The 'clockwork' release model follows a strict monthly cycle, with versions being released on exact dates.
+
+A table of (expected) dates is displayed below.
+
+| Date | Release Type | Example Version Name |
+|----------|-----------------|-------------------------|
+| 1st Jan | Pre-release | 0.1.0-pre1 |
+| 15th Jan | Feature release | 0.1.0 |
+| 1st Feb | Patch | 0.1.1 |
+| 1st Mar | Patch | 0.1.2 |
+| 1st Apr | Patch | 0.1.3 |
+| 1st May | Patch | 0.1.4 |
+| 1st Jun | Patch | 0.1.5 |
+| 1st Jul | Pre-release | 0.2.0-pre1 |
+| 15th Jul | Feature release | 0.2.0 |
+| 1st Aug | Patch | 0.2.1 |
+| 1st Sep | Patch | 0.2.2 |
+| 1st Oct | Patch | 0.2.3 |
+| 1st Nov | Patch | 0.2.4 |
+| 1st Dec | Patch | 0.2.5 |
+
+An estimated 14 releases are expected per year, with 10 patches, 2 pre-releases and 2 feature-releases that immediately follow them.
+
+Please note that the actual number may differ from this in cases such as:
+- A version requiring multiple pre-releases to correct mistakes (`0.3.0-pre1`, `0.3.0-pre2`)
+- An emergency patch having to be released
+- No bug fixes being prepared in a month, meaning no patch is needed
+
+There is no fixed timetable for the circulation of unpublished builds to the public testing group or the addon developers group.
+
+### Major Version Schedule
+
+A [feature version](#feature-releases) will be released on the **15th of January** and the **15th of July**.
+
+This will include all finished content from the previous 6 months that was tested in the pre-release.
+
+Any features, additions or changes that were *not* ready or approved at the time of the pre-release may **not** be included in the feature release [according to goal 3](#goals). \
+The feature release must **not** be delayed to accomodate content that was not ready by the deadline [according to goal 5](#goals).
+
+If there is no content ready at the scheduled date of a feature release, the release will be skipped and a notice published explaining this.
+
+### Pre-Release Schedule
+
+A [pre-release](#pre-releases) will be released on the **1st of January** and the **1st of July**, leaving two weeks before the following release for public testing to occur.
+
+This pre-release may include all finished content from the previous 6 months.
+
+Any features, additions or changes that have *not* passed the review/approval process by the day of the pre-release may **not** be included in the pre-release [according to goal 3](#goals). \
+The pre-release must **not** be delayed to accomodate content that was not ready by the deadline [according to goal 5](#goals).
+
+If there is no content ready at the scheduled date of a pre-release, the entire feature-release will be skipped and a notice published explaining this.
+
+If issues are found requiring a new build be produced (e.g. the build fails to load, a core feature is non-functional, a fix was made but needs additional testing) then another version of the pre-release may be published.
+There is no limit on the number of pre-releases that can be published if required.
+
+### Patch Schedule
+
+A [patch](#patch-releases) will be released on the **1st** of every month (except January and July) containing any fixes prepared during the previous month(s).
+
+On the 1st of January and July the patch will be replaced by the pre-release.
+
+A patch should include all bug fixes from the previous month that have passed the review/approval process.
+
+Ideally, a patch build should be circulated in the public testing group prior to its release, but this is not a strict requirement.
+
+If there are no applicable bug fixes ready by the scheduled date of the patch then the month will be skipped and the patch will not take place. A public notice is not required to explain this.
+
+## Content Curation
+
+To help curate content on our GitHub repository we have designed a new branch model and accompanying labels for categorising contributions.
+
+### Labels
+
+We shall provide issue and pull request labels to help categorise changes to prevent contributions missing a release (or slipping into the incorrect kind of release).
+
+1. `patch-ready` \
+ to denote a pull request that has:
+ - passed the review/approval process
+ - is of the sufficient kind to be included in a monthly patch version
+2. `feature-ready` \
+ to denote a pull request that has:
+ - passed the review/approval process
+ - should wait for a biannual feature release
+ - is not suitable to be included in a patch
+
+### Branches
+
+We shall maintain three core branches: `dev/patch`, `dev/feature` and `master`, which function vertically3.
+
+We may also create legacy branches where necessary. \
+As an example, if a previous release, say `2.6.4` requires an emergency security update, a branch can be made from its release tag and the patch may directly target that branch (and be released).
+
+We may also maintain other assorted branches for individual features, for the purpose of group work or for experimentation. These are not detailed below.
+
+> 3 Changes are always made to the 'top' (working) branch and then this is merged downwards into the more stable branch below when required.
+>
+> Branches are never merged upwards.
+
+#### Patch
+
+Pull requests that only address issues or are otherwise suitable for a patch release should target the **`dev/patch` branch**. These may be merged whenever appropriate (i.e. all review and testing requirements have passed).
+
+At the time of the patch release, the **patch branch** will be merged downwards into the **master branch**, and a release will be created from the **master branch**.
+
+When a feature release occurs and all branches are merged into the master branch, the patch branch will be rebased off the current master commit, effectively bringing it up to speed with the new changes. \
+As an example, when feature version 0.5.0 releases, the patch branch will be at 0.4.5 and missing the new features, so must be rebased off the current release and catch up before changes for version 0.5.1 may be merged.
+
+#### Feature
+
+Pull requests that add features, make breaking changes or are otherwise unsuitable for a patch version should target the **`dev/feature` branch**. \
+These should be merged whenever appropriate (i.e. all review and testing requirements have passed), so that testing builds can be created and circulated in the public testing group.
+
+The **patch branch** may be merged downwards into the **feature branch** whenever appropriate (e.g. after changes have been made to it that may affect the state of contributions targeting the feature branch).
+
+The feature branch should __**never**__ be merged upwards into the patch branch4.
+
+The feature branch is only merged downwards into the master branch directly before a full feature release (i.e. after the pre-release and testing is complete.)
+
+Pre-releases are made directly from the feature branch5. At the end of the pre-release testing period the feature branch can be merged downwards into the master branch in order for the full release to be made.
+
+> 4 Merges only ever occur downwards. For the patch branch to see changes from the feature branch it must be rebased onto master branch after a feature release occurs.
+>
+> 5 Merging the branch down for the pre-release would introduce potentially-buggy, untested changes to the master branch.
+
+#### Master
+
+The **`master` branch** should reflect the most recent feature release.
+Pull requests should **never** directly target the master branch. Changes are made to one of the other branches (as applicable) and then that branch is merged downwards into the **master branch** only when it is time for a release.
+
+This means that any user building from the master branch is guaranteed to receive a safe, stable build of the quality that we would release.
+
+The master branch should never be merged upwards into the feature or patch branches. If these branches need to see changes from the master branch they must be rebased onto the latest master branch commit.
+
+## Conclusion
+
+It is our aim that this release model will address all of our goals and satisfy our motivations.
+
+Setting a strict and regular schedule ought to prevent too much time passing without a release, while also helping to prevent a single release from becoming bloated and overbearing.
+
+By including testing requirements and mandating public pre-releases we hope to solve the persistent issue of untested changes slipping into supposedly-stable versions.
+
+Finally, by scheduling regular patches we aim to reduce the time between a bug being 'fixed' by a contributor and the userbase being able to benefit from that fix. Keeping these patches as small, controlled releases allows us to mark them as 'stable' therefore letting the version reach a wider audience.
+
+### Addendum 1: Paradigm Versions
+
+Paradigmatic `X.0.0` versions were deliberately excluded from this proposal. \
+The reasoning behind this choice was that over 10 years have passed since the inception of major version`2.0.0` in 2012, the previous paradigmatic change.
+
+As of writing this document there are proposals and roadmaps for a version `3.0.0` but no timetable or predicted date on the horizon.
+
+This kind of version, were it to be released, would likely take the place of a typical feature release in the model calendar, i.e. occurring on the 15th of January or July. However, due to its potentially-significant nature it may require exceptional changes to the pre-release cycle.
+
+As details of such a version are neither known nor easy to predict, it has been left to the discretion of the future team to be decided when required.
+
+### Addendum 2: Failure Standards
+
+No proposal is complete without failure standards; this model can be deemed to have failed if, in two years' time:
+1. The delay between finishing new features and releasing them to the public has not been reduced.
+2. The delay between an issue being fixed and that fix being made public in a stable build has not been reduced.
+3. Untested features are being released in 'stable' builds.
+4. The release timetable is unclear or inaccessible.
+5. Versions are being indefinitely delayed to accommodate additional changes.
+
+Additionally, if this model is considered to have put an undue burden on the core development team, to the extent that it has hampered progress in a significant and measurable way, then it can be considered to have failed.
diff --git a/README.md b/README.md
index dcbd171e4b0..36c82e5c00f 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,9 @@
-# Skript [![Build Status](https://travis-ci.org/SkriptLang/Skript.svg?branch=master)](https://travis-ci.org/SkriptLang/Skript)
-Skript is a plugin for Paper/Spigot, which allows server owners and other people
+![Skript Language](.github/assets/Cover.jpg)
+
+---
+
+# Skript
+**Skript** is a Minecraft plugin for Paper/Spigot, which allows server owners and other people
to modify their servers without learning Java. It can also be useful if you
*do* know Java; some tasks are quicker to do with Skript, and so it can be used
for prototyping etc.
@@ -8,7 +12,7 @@ This Github fork of Skript is based on Mirreski's improvements which was built
on Njol's original Skript.
## Requirements
-Skript requires **Spigot** to work. You heard it right, Bukkit does *not* work.
+Skript requires **Spigot** to work. You heard it right, **CraftBukkit** does *not* work.
**Paper**, which is a fork of Spigot, is recommended; it is required for some
parts of Skript to be available.
@@ -22,8 +26,10 @@ versions will be supported as soon as possible.
## Download
You can find the downloads for each version with their release notes in the [releases page](https://github.com/SkriptLang/Skript/releases).
+Two major feature updates are expected each year in January and July, with monthly patches occurring in between. For full details, please review our [release model](CLOCKWORK_RELEASE_MODEL.md).
+
## Documentation
-Documentation is available [here](https://skriptlang.github.io/Skript) for the
+Documentation is available [here](https://docs.skriptlang.org/) for the
latest version of Skript.
## Reporting Issues
@@ -31,7 +37,11 @@ Please see our [contribution guidelines](https://github.com/SkriptLang/Skript/bl
before reporting issues.
## Help Us Test
-We have an [official Discord community](https://discord.gg/ZPsZAg6ygu) for testing Skript's new features and releases.
+Wanting to help test Skript's new features and releases?
+You can head on over to our [Official Testing Discord](https://discord.gg/ZPsZAg6ygu), and whenever we start testing new features/releases you will be the first to know.
+
+Please note this is not a help Discord.
+If you require assistance with how to use Skript please check out the [Relevant Links](https://github.com/SkriptLang/Skript#relevant-links) section for a list of available resources to assist you.
## A Note About Add-ons
We don't support add-ons here, even though some of Skript developers have also
@@ -168,7 +178,8 @@ Or, if you use Maven:
## Relevant Links
* [skUnity forums](https://forums.skunity.com)
-* [Add-on releases at skUnity](https://forums.skunity.com/forums/addon-releases)
+* [skUnity addon releases](https://forums.skunity.com/forums/addon-releases)
+* [skUnity Discord invite](https://discord.gg/0l3WlzBPKX7WNjkf)
* [Skript Chat Discord invite](https://discord.gg/0lx4QhQvwelCZbEX)
* [Skript Hub](https://skripthub.net)
* [Original Skript at Bukkit](https://dev.bukkit.org/bukkit-plugins/skript) (inactive)
diff --git a/build.gradle b/build.gradle
index c1bbdbd2945..92f13c47f46 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,16 +1,19 @@
-import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.apache.tools.ant.filters.ReplaceTokens
import java.time.LocalTime
plugins {
- id 'com.github.johnrengelman.shadow' version '7.1.2'
+ id 'com.github.johnrengelman.shadow' version '8.1.1'
id 'com.github.hierynomus.license' version '0.16.1'
id 'maven-publish'
id 'java'
}
+configurations {
+ testImplementation.extendsFrom testShadow
+}
+
allprojects {
repositories {
mavenCentral()
@@ -23,19 +26,22 @@ allprojects {
dependencies {
shadow group: 'io.papermc', name: 'paperlib', version: '1.0.8'
- shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.0'
- implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.19.3-R0.1-SNAPSHOT'
+ shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.2'
+ shadow group: 'net.kyori', name: 'adventure-text-serializer-bungeecord', version: '4.3.2'
+
+ implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.20.4-R0.1-SNAPSHOT'
implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.700'
implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1'
implementation group: 'com.sk89q.worldguard', name: 'worldguard-legacy', version: '7.0.0-SNAPSHOT'
- implementation group: 'net.milkbowl.vault', name: 'Vault', version: '1.7.1', {
+ implementation group: 'net.milkbowl.vault', name: 'Vault', version: '1.7.3', {
exclude group: 'org.bstats', module: 'bstats-bukkit'
}
+
implementation fileTree(dir: 'lib', include: '*.jar')
-}
-compileJava.options.encoding = 'UTF-8'
-compileTestJava.options.encoding = 'UTF-8'
+ testShadow group: 'junit', name: 'junit', version: '4.13.2'
+ testShadow group: 'org.easymock', name: 'easymock', version: '5.0.1'
+}
task checkAliases {
description 'Checks for the existence of the aliases.'
@@ -47,28 +53,35 @@ task checkAliases {
}
}
+task testJar(type: ShadowJar) {
+ dependsOn(compileTestJava, licenseTest)
+ archiveFileName = 'Skript-JUnit.jar'
+ from sourceSets.test.output, sourceSets.main.output, project.configurations.testShadow
+}
+
task jar(overwrite: true, type: ShadowJar) {
dependsOn checkAliases
- archiveName jarName ? 'Skript.jar' : jarName
+ archiveFileName = jarName ? 'Skript.jar' : jarName
from sourceSets.main.output
}
task build(overwrite: true, type: ShadowJar) {
- archiveName jarName ? 'Skript.jar' : jarName
+ archiveFileName = jarName ? 'Skript.jar' : jarName
from sourceSets.main.output
}
-task relocateShadowJar(type: ConfigureShadowRelocation) {
- target = tasks.shadowJar
+// Excludes the tests for the build task. Should be using junit, junitJava17, junitJava8, skriptTest, quickTest.
+// We do not want tests to run for building. That's time consuming and annoying. Especially in development.
+test {
+ exclude '**/*'
}
task sourceJar(type: Jar) {
from sourceSets.main.allJava
- archiveClassifier = "sources"
+ archiveClassifier = 'sources'
}
tasks.withType(ShadowJar) {
- dependsOn relocateShadowJar
configurations = [
project.configurations.shadow
]
@@ -76,6 +89,7 @@ tasks.withType(ShadowJar) {
include(dependency('io.papermc:paperlib'))
include(dependency('org.bstats:bstats-bukkit'))
include(dependency('org.bstats:bstats-base'))
+ include(dependency('net.kyori:adventure-text-serializer-bungeecord'))
}
relocate 'io.papermc.lib', 'ch.njol.skript.paperlib'
relocate 'org.bstats', 'ch.njol.skript.bstats'
@@ -106,8 +120,8 @@ processResources {
publishing {
publications {
maven(MavenPublication) {
- groupId "com.github.SkriptLang"
- artifactId "Skript"
+ groupId 'com.github.SkriptLang'
+ artifactId 'Skript'
version project.version
artifact sourceJar
artifact tasks.jar
@@ -116,11 +130,11 @@ publishing {
repositories {
maven {
- name = "repo"
- url = "https://repo.skriptlang.org/releases"
+ name = 'repo'
+ url = 'https://repo.skriptlang.org/releases'
credentials {
- username = System.getenv("MAVEN_USERNAME")
- password = System.getenv("MAVEN_PASSWORD")
+ username = System.getenv('MAVEN_USERNAME')
+ password = System.getenv('MAVEN_PASSWORD')
}
}
}
@@ -135,6 +149,15 @@ license {
exclude('**/*.json') // JSON files do not have headers
}
+task releaseJavadoc(type: Javadoc) {
+ title = project.name + ' ' + project.property('version')
+ source = sourceSets.main.allJava
+ classpath = configurations.compileClasspath
+ options.encoding = 'UTF-8'
+ // currently our javadoc has a lot of errors, so we need to suppress the linter
+ options.addStringOption('Xdoclint:none', '-quiet')
+}
+
// Task to check that test scripts are named correctly
tasks.register('testNaming') {
doLast {
@@ -158,53 +181,113 @@ tasks.register('testNaming') {
}
}
+enum Modifiers {
+ DEV_MODE, GEN_NIGHTLY_DOCS, GEN_RELEASE_DOCS, DEBUG, PROFILE, JUNIT
+}
+
// Create a test task with given name, environments dir/file, dev mode and java version.
-void createTestTask(String name, String environments, boolean devMode, int javaVersion, boolean genDocs) {
+// -1 on the timeout means it'll be disabled.
+void createTestTask(String name, String desc, String environments, int javaVersion, long timeout, Modifiers... modifiers) {
+ if (timeout == 0)
+ timeout = 300000 // 5 minutes
+ boolean junit = modifiers.contains(Modifiers.JUNIT)
+ boolean releaseDocs = modifiers.contains(Modifiers.GEN_RELEASE_DOCS)
+ boolean docs = modifiers.contains(Modifiers.GEN_NIGHTLY_DOCS) || releaseDocs
+ def artifact = 'build' + File.separator + 'libs' + File.separator
+ if (junit) {
+ artifact += 'Skript-JUnit.jar'
+ } else if (releaseDocs) {
+ artifact += 'Skript-github.jar'
+ } else {
+ artifact += 'Skript-nightly.jar'
+ }
tasks.register(name, JavaExec) {
- dependsOn nightlyRelease, testNaming
+ description = desc
+ dependsOn licenseTest
+ if (junit) {
+ dependsOn testJar
+ } else if (releaseDocs) {
+ dependsOn githubRelease, testNaming
+ } else {
+ dependsOn nightlyRelease, testNaming
+ }
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(javaVersion)
}
- if (devMode) {
+ if (modifiers.contains(Modifiers.DEV_MODE)) {
standardInput = System.in
}
group = 'execution'
classpath = files([
- 'build' + File.separator + 'libs' + File.separator + 'Skript-nightly.jar',
+ artifact,
project.configurations.runtimeClasspath.find { it.name.startsWith('gson') },
sourceSets.main.runtimeClasspath
])
- main = 'ch.njol.skript.tests.platform.PlatformMain'
+ main = 'ch.njol.skript.test.platform.PlatformMain'
args = [
- 'test_runners',
- 'src/test/skript/tests',
+ 'build/test_runners',
+ junit ? 'src/test/skript/junit' : 'src/test/skript/tests',
'src/test/resources/runner_data',
environments,
- devMode,
- genDocs
+ modifiers.contains(Modifiers.DEV_MODE),
+ docs,
+ junit,
+ modifiers.contains(Modifiers.DEBUG),
+ project.findProperty('verbosity') ?: "null",
+ timeout
]
+
+ // Do first is used when throwing exceptions.
+ // This way it's not called when defining the task.
+ doFirst {
+ if (!gradle.taskGraph.hasTask(":tasks") && !gradle.startParameter.dryRun && modifiers.contains(Modifiers.PROFILE)) {
+ if (!project.hasProperty('profiler'))
+ throw new MissingPropertyException('Add parameter -Pprofiler=', 'profiler', String.class)
+
+ args += '-agentpath:' + project.property('profiler') + '=port=8849,nowait'
+ }
+ }
}
}
-def latestEnv = 'java17/paper-1.19.3.json'
+def latestEnv = 'java17/paper-1.20.4.json'
def latestJava = 17
def oldestJava = 8
+java {
+ toolchain.languageVersion.set(JavaLanguageVersion.of(latestJava))
+}
+
tasks.withType(JavaCompile).configureEach {
- options.compilerArgs += ["-source", "" + oldestJava, "-target", "" + oldestJava]
+ options.compilerArgs += ['-source', '' + oldestJava, '-target', '' + oldestJava]
}
+compileJava.options.encoding = 'UTF-8'
+compileTestJava.options.encoding = 'UTF-8'
+
// Register different Skript testing tasks
-createTestTask('quickTest', 'src/test/skript/environments/' + latestEnv, false, latestJava, false)
-createTestTask('skriptTestJava17', 'src/test/skript/environments/java17', false, latestJava, false)
-createTestTask('skriptTestJava8', 'src/test/skript/environments/java8', false, oldestJava, false)
-createTestTask('skriptTestDev', 'src/test/skript/environments/' + (project.property('testEnv') == null
- ? latestEnv : project.property('testEnv') + '.json'), true, Integer.parseInt(project.property('testEnvJavaVersion') == null
- ? latestJava : project.property('testEnvJavaVersion')), false)
-tasks.register('skriptTest') {dependsOn skriptTestJava8, skriptTestJava17}
-createTestTask('genDocs', 'src/test/skript/environments/' + (project.property('testEnv') == null
- ? latestEnv : project.property('testEnv') + '.json'), false, Integer.parseInt(project.property('testEnvJavaVersion') == null
- ? latestJava : project.property('testEnvJavaVersion')), true)
+String environments = 'src/test/skript/environments/';
+String env = project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'
+int envJava = project.property('testEnvJavaVersion') == null ? latestJava : Integer.parseInt(project.property('testEnvJavaVersion') as String)
+createTestTask('quickTest', 'Runs tests on one environment being the latest supported Java and Minecraft.', environments + latestEnv, latestJava, 0)
+createTestTask('skriptTestJava17', 'Runs tests on all Java 17 environments.', environments + 'java17', latestJava, 0)
+createTestTask('skriptTestJava8', 'Runs tests on all Java 8 environments.', environments + 'java8', oldestJava, 0)
+createTestTask('skriptTestDev', 'Runs testing server and uses \'system.in\' for command input, stop server to finish.', environments + env, envJava, 0, Modifiers.DEV_MODE, Modifiers.DEBUG)
+createTestTask('skriptProfile', 'Starts the testing server with JProfiler support.', environments + latestEnv, latestJava, -1, Modifiers.PROFILE)
+createTestTask('genNightlyDocs', 'Generates the Skript documentation website html files.', environments + env, envJava, 0, Modifiers.GEN_NIGHTLY_DOCS)
+createTestTask('genReleaseDocs', 'Generates the Skript documentation website html files for a release.', environments + env, envJava, 0, Modifiers.GEN_RELEASE_DOCS)
+tasks.register('skriptTest') {
+ description = 'Runs tests on all environments.'
+ dependsOn skriptTestJava8, skriptTestJava17
+}
+
+createTestTask('JUnitQuick', 'Runs JUnit tests on one environment being the latest supported Java and Minecraft.', environments + latestEnv, latestJava, 0, Modifiers.JUNIT)
+createTestTask('JUnitJava17', 'Runs JUnit tests on all Java 17 environments.', environments + 'java17', latestJava, 0, Modifiers.JUNIT)
+createTestTask('JUnitJava8', 'Runs JUnit tests on all Java 8 environments.', environments + 'java8', oldestJava, 0, Modifiers.JUNIT)
+tasks.register('JUnit') {
+ description = 'Runs JUnit tests on all environments.'
+ dependsOn JUnitJava8, JUnitJava17
+}
// Build flavor configurations
task githubResources(type: ProcessResources) {
@@ -212,10 +295,8 @@ task githubResources(type: ProcessResources) {
include '**'
version = project.property('version')
def channel = 'stable'
- if (version.contains('alpha'))
- channel = 'alpha'
- else if (version.contains('beta'))
- channel = 'beta'
+ if (version.contains('pre'))
+ channel = 'prerelease'
filter ReplaceTokens, tokens: [
'version' : version,
'today' : '' + LocalTime.now(),
@@ -232,7 +313,7 @@ task githubResources(type: ProcessResources) {
task githubRelease(type: ShadowJar) {
from sourceSets.main.output
dependsOn githubResources
- archiveName = 'Skript-github.jar'
+ archiveFileName = 'Skript-github.jar'
manifest {
attributes(
'Name': 'ch/njol/skript',
@@ -247,10 +328,8 @@ task spigotResources(type: ProcessResources) {
include '**'
version = project.property('version')
def channel = 'stable'
- if (version.contains('alpha'))
- channel = 'alpha'
- else if (version.contains('beta'))
- channel = 'beta'
+ if (version.contains('pre'))
+ channel = 'prerelease'
filter ReplaceTokens, tokens: [
'version' : version,
'today' : '' + LocalTime.now(),
@@ -267,7 +346,7 @@ task spigotResources(type: ProcessResources) {
task spigotRelease(type: ShadowJar) {
from sourceSets.main.output
dependsOn spigotResources
- archiveName = 'Skript-spigot.jar'
+ archiveFileName = 'Skript-spigot.jar'
manifest {
attributes(
'Name': 'ch/njol/skript',
@@ -286,7 +365,7 @@ task nightlyResources(type: ProcessResources) {
'version' : version,
'today' : '' + LocalTime.now(),
'release-flavor' : 'skriptlang-nightly', // SkriptLang build, automatically done by CI
- 'release-channel' : 'alpha', // No update checking, but these are VERY unstable
+ 'release-channel' : 'prerelease', // No update checking, but these are VERY unstable
'release-updater' : 'ch.njol.skript.update.NoUpdateChecker', // No autoupdates for now
'release-source' : '',
'release-download': 'null'
@@ -298,7 +377,7 @@ task nightlyResources(type: ProcessResources) {
task nightlyRelease(type: ShadowJar) {
from sourceSets.main.output
dependsOn nightlyResources, licenseMain
- archiveName = 'Skript-nightly.jar'
+ archiveFileName = 'Skript-nightly.jar'
manifest {
attributes(
'Name': 'ch/njol/skript',
@@ -307,3 +386,26 @@ task nightlyRelease(type: ShadowJar) {
)
}
}
+
+javadoc {
+ dependsOn nightlyResources
+
+ source = sourceSets.main.allJava
+
+ exclude("ch/njol/skript/conditions/**")
+ exclude("ch/njol/skript/expressions/**")
+ exclude("ch/njol/skript/effects/**")
+ exclude("ch/njol/skript/events/**")
+ exclude("ch/njol/skript/sections/**")
+ exclude("ch/njol/skript/structures/**")
+ exclude("ch/njol/skript/lang/function/EffFunctionCall.java")
+ exclude("ch/njol/skript/lang/function/ExprFunctionCall.java")
+ exclude("ch/njol/skript/hooks/**")
+ exclude("ch/njol/skript/test/**")
+
+ classpath = configurations.compileClasspath + sourceSets.main.output
+ options.encoding = 'UTF-8'
+ // currently our javadoc has a lot of errors, so we need to suppress the linter
+ options.addStringOption('Xdoclint:none', '-quiet')
+}
+
diff --git a/buildbot-compile.sh b/buildbot-compile.sh
deleted file mode 100755
index 9d314893d5f..00000000000
--- a/buildbot-compile.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# Compiles Skript with some special settings used to produce unstable builds
-
-# Version identifier: 2.2, date YYMMDD, git head
-SKRIPT_VER="2.2-$(date +%y%m%d)-git-$(git rev-parse --short HEAD)"
-export SKRIPT_VERSION=$SKRIPT_VER
-
-./gradlew clean build # Clean all, then build
-
-# Write name for upload script in my server to use
-echo "$SKRIPT_VER" >buildbot-upload-version.txt
diff --git a/code-conventions.md b/code-conventions.md
index 37ac182cd62..327951d2299 100644
--- a/code-conventions.md
+++ b/code-conventions.md
@@ -127,9 +127,11 @@ If we need to remove or alter contributed code due to a licensing issue we will
- Static constant fields should be named in `UPPER_SNAKE_CASE`
* Localised messages should be named in `lower_snake_case`
- And that is the only place where snake_case is acceptable
-* Use prefixes only where their use has been already estabilished (such as `ExprSomeRandomThing`)
+* Use prefixes only where their use has been already established (such as `ExprSomeRandomThing`)
- Otherwise, use postfixes where necessary
- Common occurrences include: Struct (Structure), Sec (Section), EffSec (EffectSection), Eff (Effect), Cond (Condition), Expr (Expression)
+* Ensure variable/field names are descriptive. Avoid using shorthand names like `e`, or `c`.
+ - e.g. Event should be `event`, not `e`. `e` is ambiguous and could mean a number of things.
### Comments
* Prefer to comment *why* you're doing things instead of how you're doing them
diff --git a/docs/README.md b/docs/README.md
deleted file mode 100644
index 30f465c13e5..00000000000
--- a/docs/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Skript Documentation Templates
-
-Skript's features are documented directly in it's Java code. But we still need
-
-1. Clear tutorials, not just "you can check the syntax pattern"
-2. Examples explained, if needed
-
-When generating final result, each HTML file is surrounded by template.html,
-which provides head element, navigation bar and so on.
-
-## Template Patterns
-
-Patterns have syntax of ${pattern_here}. For example, ${skript.version} is replaced with
-current Skript version. Please see below for more...
-
-You can also include other files by using ${include }. Just please make
-sure that those included files don't have tags which are not allowed in position
-where include is called.
-
-## Pattern Reference
-```
-skript.* - Information of Skript
-version - Skript's version
-include - Load given file and place them here
-generate - Generated reference
-content - In template.html, marks the point where other file is placed
-```
-
-## Generating the documentation
-
-1. You will need to create a directory named `doc-templates` in `plugins/Skript/`, and copy everything from [here](https://github.com/SkriptLang/Skript/tree/master/docs) into that directory.
-2. Execute the command `/sk gen-docs`.
-3. The `docs/` directory will be created _(if not created already)_ in `plugins/Skript` containing the website's files.
-4. Open `index.html` and browse the documentation.
-5. _(Optionally)_ Add this system property `-Dskript.forceregisterhooks` in your server startup script (before the -jar property) to force generating hooks docs.
\ No newline at end of file
diff --git a/docs/assets/Logo/Skript Logo Circular.png b/docs/assets/Logo/Skript Logo Circular.png
deleted file mode 100644
index 8c93b07d381..00000000000
Binary files a/docs/assets/Logo/Skript Logo Circular.png and /dev/null differ
diff --git a/docs/assets/Logo/Skript Logo.jpg b/docs/assets/Logo/Skript Logo.jpg
deleted file mode 100644
index 2a1221730d2..00000000000
Binary files a/docs/assets/Logo/Skript Logo.jpg and /dev/null differ
diff --git a/docs/assets/Logo/Skript Logo.png b/docs/assets/Logo/Skript Logo.png
deleted file mode 100644
index d3965b280fe..00000000000
Binary files a/docs/assets/Logo/Skript Logo.png and /dev/null differ
diff --git a/docs/assets/icon.png b/docs/assets/icon.png
deleted file mode 100644
index 8c93b07d381..00000000000
Binary files a/docs/assets/icon.png and /dev/null differ
diff --git a/docs/assets/light-off.svg b/docs/assets/light-off.svg
deleted file mode 100644
index 1b7db07723c..00000000000
--- a/docs/assets/light-off.svg
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
diff --git a/docs/assets/light-on.svg b/docs/assets/light-on.svg
deleted file mode 100644
index 601ccea1f8e..00000000000
--- a/docs/assets/light-on.svg
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
diff --git a/docs/assets/search.svg b/docs/assets/search.svg
deleted file mode 100644
index 9895c46a2d2..00000000000
--- a/docs/assets/search.svg
+++ /dev/null
@@ -1,173 +0,0 @@
-
-
-
diff --git a/docs/classes.html b/docs/classes.html
deleted file mode 100644
index 8685ad71de0..00000000000
--- a/docs/classes.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
Types
-
-
- ${generate classes desc_full.html}
-
\ No newline at end of file
diff --git a/docs/conditions.html b/docs/conditions.html
deleted file mode 100644
index 091bdf2d1c4..00000000000
--- a/docs/conditions.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
\ No newline at end of file
diff --git a/docs/functions.html b/docs/functions.html
deleted file mode 100644
index f018161fc7a..00000000000
--- a/docs/functions.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
Functions
-
-
-
-
Note:
-
- These functions are defined by Skript. You may also create your own functions!
- Tutorial for doing so is planned, but right now you need to seek it elsewhere.
-
Skript is (surprise, surprise) a scripting plugin for the Bukkit platform. It is easy to use for
- simple tasks, but you can also create really complex things with it. The syntax of Skript is close to
- English, but it is still not magic. While you might succeed with experimentation for simple tasks, for
- anything more complex you will need some guidance.
-
This is Skript's documentation. You will find all supported features of the plugin here, along with some
- useful examples. We don't have tutorials yet, but you can find good ones using whatever search engine you
- prefer.
-
-
Quick Look
-
-command /sethome:
- permission: skript.home # Permission required for this command
- description: Set your home # Description of this command
- executable by: players # Console won't be able to run this command
- trigger: # The actual trigger/code that will run when someone do /sethome
- # Set a unique variable to sender's location
- set {home::%uuid of player%} to location of player
- # Send a message to the sender
- message "Set your home to <grey>%location of player%<reset>"
-
-command /home:
- permission: skript.home
- description: Teleport yourself to your home
- trigger:
- # Check if that variable we used in /sethome has been set (in other words, if player ever ran /sethome)
- if {home::%uuid of player%} is not set:
- message "You have not set your home yet!"
- stop trigger # stop the code here, lines below won't run
- # Teleport the player to their home
- teleport player to {home::%uuid of player%}
- send "&aYou have been teleported."
-
Found something incorrect in this documentation? Please report it to the issue tracker.
-
We are looking for docs authors! Currently, the only documentation is generated
- automatically. It would be nice to have some hand-written content such as tutorials on the docs as well. For
- example, currently we don't have a tutorial on how to use loops here; This makes it harder for newcomers to
- learn. Check this issue for more details and
- if you're interested in helping out.
-
-
-
-
SkriptLang Team •
- Site developed by Ayham Al-Ali • Site Version ${site-version} • Generated on ${skript.build.date}
-
\ No newline at end of file
diff --git a/docs/js/functions.js b/docs/js/functions.js
deleted file mode 100644
index d6f785ee7d9..00000000000
--- a/docs/js/functions.js
+++ /dev/null
@@ -1,353 +0,0 @@
-let isCookiesAccepted = getCookie("cookies-accepted") === "true";
-
-// <> Cookies
-function setCookie(cname, cvalue, exdays, force = false) {
- if (!isCookiesAccepted && !force)
- return;
-
- const d = new Date();
- d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
- let expires = "expires=" + d.toUTCString();
- document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/; SameSite=None; Secure";
-}
-
-function getCookie(cname) {
- let name = cname + "=";
- let ca = document.cookie.split(';');
- for (let i = 0; i < ca.length; i++) {
- let c = ca[i];
- while (c.charAt(0) == ' ') {
- c = c.substring(1);
- }
- if (c.indexOf(name) == 0) {
- return c.substring(name.length, c.length);
- }
- }
- return "";
-}
-
-// Cookies >
-
-// <> localStorage
-
-/**
- * Set the value of local storage item
- * @param {string} item id
- * @param {object} value
- * @param {double} exdays time in days
- */
-function setStorageItem(item, value, exdays, force = false) {
- if (!isCookiesAccepted && !force)
- return;
-
- const d = new Date();
- d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
- localStorage.setItem(item, value + "; " + d.getTime());
-}
-
-/**
- * Remove a local storage item
- * @param {string} item the id of the item
- */
-function removeStorageItem(item) {
- localStorage.removeItem(item)
-}
-
-/**
- * Get local storage item (value & time if has one)
- * @param {string} item the item id
- * @param {boolean} noExpireationCheck whether to check for expiration time and remove the item
- * @returns the item object
- */
-function getStorageItem(item, noExpireationCheck = false) {
- let result = localStorage.getItem(item);
- if (!result)
- return null;
-
- if (!noExpireationCheck) {
- if (isStorageItemExpired(result)) {
- removeStorageItem(item);
- return null;
- }
- }
- result = result.split("; ")[0];
- return result;
-}
-
-/**
- * Get local storage item value after split at ';'
- * @param {string} item the id of th item
- * @returns the item value
- */
-function getStorageItemValue(item) {
- let result = localStorage.getItem(item);
- if (!result)
- return null;
- return result.split("; ")[0];
-}
-
-/**
- * @param {string} string the value of the item not the item id (the value without splitting)
- * @returns the expiration date
- */
-function getStorageItemExpiration(value) {
- let expires = localStorage.getItem(value).split("; ")[1];
- if (!expires) { // item with no expiration date
- return null;
- }
- return new Date(expires);
-}
-
-/**
- *
- * @param string the value of the item not the item id (the value without splitting)
- * @returns whether expired or not
- */
-function isStorageItemExpired(value) {
- let expires = parseInt(value.split("; ")[1]);
- if (!expires) { // item with no expiration date
- return null;
- }
- return new Date(expires) < new Date();
-}
-
-// localStorage >
-
-
-
-function getApiValue(element, placeholder, apiPathName, callback, noReplace = false) {
- let placeholderName = placeholder.replace("ghapi-", "");
- let cv = getStorageItem(placeholder); // cached value
- if (noReplace) {
- if (cv) {
- callback(cv, true);
- } else {
- $.getJSON(ghAPI + `/${apiPathName}`, (data) => {
- let value = callback(data, false);
- setStorageItem(placeholder, value, 0.2);
- })
- }
- return;
- }
-
- let innerHTML = element.innerHTML;
- if (innerHTML.includes(`\${${placeholderName}}`)) {
- if (cv) {
- element.innerHTML = element.innerHTML.replaceAll(`\${${placeholderName}}`, cv);
- } else {
- $.getJSON(ghAPI + `/${apiPathName}`, (data) => {
- let value = callback(data, false);
- element.innerHTML = element.innerHTML.replaceAll(`\${${placeholderName}}`, value);
- setStorageItem(placeholder, value, 0.2);
- })
- }
- }
-}
-
-// Copy texts/links to clipboard
-function copyToClipboard(value) {
- setTimeout(() => {
- let cb = document.body.appendChild(document.createElement("input"));
- cb.value = value;
- cb.focus();
- cb.select();
- document.execCommand('copy');
- cb.parentNode.removeChild(cb);
- }, 50)
-}
-
-// Show notification
-function showNotification(text, bgColor, color) {
- var noti = document.body.appendChild(document.createElement("span"));
- noti.id = "notification-box";
-
- setTimeout(() => {
- noti.textContent = text;
- if (bgColor)
- noti.styles.backgroundColor = bgColor;
- if (color)
- noti.styles.backgroundColor = color;
- noti.classList.add("activate-notification");
- setTimeout(() => {
- noti.classList.remove("activate-notification");
- setTimeout(() => {
- noti.parentNode.removeChild(noti);
- }, 200);
- }, 1500);
- }, 50);
-}
-
-// <> Magic Text (&k)
-function getRandomChar() {
- chars = "ÂÃÉÊÐÑÙÚÛÜéêëãòóôēĔąĆćŇň1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()-=_+{}[";
- return chars.charAt(Math.floor(Math.random() * chars.length) + 1)
-}
-
-function magicTextGen(element) {
- var msg = element.textContent;
- var length = msg.length;
-
- setInterval(() => {
- var newMsg = "";
- for (i = 0; i <= length; i++) {
- newMsg += getRandomChar(msg.charAt(i));
- }
- element.textContent = newMsg;
-
- }, 30)
-}
-
-function renderMagicText() {
- document.querySelectorAll('.magic-text').forEach((e) => {
- magicTextGen(e);
- })
-}
-// Magic Text (&k) >
-
-// Replace Github placeholders
-function replacePlaceholders(element) {
- let innerHTML = element.innerHTML;
- if (innerHTML.includes("${latest-version}")) {
- getApiValue(element, "ghapi-latest-version", "releases", (data) => {
- return data[0]["tag_name"];
- });
- }
-
- if (innerHTML.includes("${latest-version-changelog}")) {
- getApiValue(element, "ghapi-latest-version-changelog", "releases", (data) => {
- return data["body"].replaceAll("\\r\\n", " ");
- });
- }
-
- if (innerHTML.includes("${stable-version}")) {
- getApiValue(element, "ghapi-stable-version", "releases/latest", (data) => {
- return data["tag_name"];
- });
- }
-
- if (innerHTML.includes("${stable-version-changelog}")) {
- getApiValue(element, "ghapi-stable-version-changelog", "releases/latest", (data) => {
- return data["body"].replaceAll("\\r\\n", " ");
- });
- }
-
- if (innerHTML.includes("${latest-issue-")) {
- getApiValue(element, "ghapi-latest-issue-user", "issues?per_page=1", (data) => {
- return data[0]["user"]["login"];
- });
- getApiValue(element, "ghapi-latest-issue-title", "issues?per_page=1", (data) => {
- return data[0]["title"];
- });
- getApiValue(element, "ghapi-latest-issue-date", "issues?per_page=1", (data) => {
- return data[0]["created_at"];
- });
- }
-
- if (innerHTML.includes("${latest-pull-")) {
- getApiValue(element, "ghapi-latest-pull-user", "pulls?per_page=1", (data) => {
- return data[0]["user"]["login"];
- });
- getApiValue(element, "ghapi-latest-pull-title", "pulls?per_page=1", (data) => {
- return data[0]["title"];
- });
- getApiValue(element, "ghapi-latest-pull-date", "pulls?per_page=1", (data) => {
- return data[0]["created_at"];
- });
- }
-
- if (innerHTML.includes("${site-version}")) {
- element.innerHTML = element.innerHTML.replaceAll("${site-version}", siteVersion);
- }
-
- if (innerHTML.includes("${contributors-size}")) {
- getApiValue(element, "ghapi-contributors-size", "contributors?per_page=500", (data) => {
- return data.length;
- });
- }
-}
-
-// <> Syntax Highlighting
-
-// ORDER MATTERS!!
-// All regexes must be sorrouneded with () to be able to use group 1 as the whole match since Js doesn't have group 0
-// Example: .+ = X
-// Example: (.+) = ✓
-var patterns = []; // [REGEX, CLASS]
-
-function registerSyntax(regexString, flags, clazz) {
- try {
- regex = new RegExp(regexString, flags);
- patterns.push([regex, clazz]);
- } catch (error) {
- console.warn(`Either your browser doesn't support this regex or the regex is incorrect (${regexString}):` + error);
- }
-}
-
-registerSyntax("((?")
-
- for (let j = 0; j < lines.length; j++) {
- Loop2: for (let i = 0; i < patterns.length; i++) {
- let match;
- let regex = patterns[i][0];
- let oldLine = lines[j];
-
- while ((match = regex.exec(oldLine)) != null) {
- lines[j] = lines[j].replaceAll(regex, `$1`)
- if (regex.lastIndex == 0) // Break after it reaches the end of exec count to avoid inf loop
- continue Loop2;
- }
- }
- }
- element.innerHTML = lines.join(" ")
-}
-// Syntax Highlighting >
-
-// Offset page's scroll - Used for anchor scroll correction
-function offsetAnchor(event, id) { // event can be null
- let content = document.querySelector("#content");
- let element = document.getElementById(id);
-
- if (content && element) {
- if (event != null)
- event.preventDefault();
- content.scroll(0, element.offsetTop - 25); // Should be less than the margin in .item-wrapper so it doesn't show the part of the previous .item-wrapper
- }
-}
-
-// <> Toggle a specific doc element block
-
-// Active syntax
-var lastActiveSyntaxID;
-function toggleSyntax(elementID) {
- let element = document.getElementById(elementID)
- if (!element)
- return
-
- if (lastActiveSyntaxID != null)
- document.getElementById(lastActiveSyntaxID).classList.remove("active-syntax");
-
- element.classList.add("active-syntax");
- lastActiveSyntaxID = elementID;
-}
-
-// Toggle a specific doc element block >
\ No newline at end of file
diff --git a/docs/js/main.js b/docs/js/main.js
deleted file mode 100644
index 0b48675990d..00000000000
--- a/docs/js/main.js
+++ /dev/null
@@ -1,408 +0,0 @@
-const siteVersion = "2.2.0"; // site version is different from skript version
-const ghAPI = "https://api.github.com/repos/SkriptLang/Skript";
-
-// ID Scroll
-const links = document.querySelectorAll("div.item-wrapper");
-const contents = document.querySelector("#content");
-
-lastActiveSideElement = null;
-navContents = document.getElementById("nav-contents");
-
-if (contents) {
- setTimeout(() => {
- contents.addEventListener('scroll', (e) => {
- links.forEach((ha) => {
- const rect = ha.getBoundingClientRect();
- if (rect.top > 0 && rect.top < 350) {
- // const location = window.location.toString().split("#")[0];
- // history.replaceState(null, null, location + "#" + ha.id); // Not needed since lastActiveSideElement + causes history spam
-
- if (lastActiveSideElement != null) {
- lastActiveSideElement.classList.remove("active-item");
- }
-
- lastActiveSideElement = document.querySelectorAll(`#nav-contents a[href="#${ha.id}"]`)[0];
- if (lastActiveSideElement != null) {
- lastActiveSideElement.classList.add("active-item");
- navContents.scroll(0, lastActiveSideElement.offsetTop - 100);
- }
- }
- });
- })}, 50); // respect auto hash scroll
-}
-
-
-// Active Tab
-const pageLink = window.location.toString().replaceAll(/(.*)\/(.+?).html(.*)/gi, '$2');
-if (pageLink === "" || pageLink == window.location.toString()) // home page - when there is no `.+?.html` pageLink will = windown.location due to current regex
- document.querySelectorAll('#global-navigation a[href="index.html"]')[0].classList.add("active-tab");
-else
- document.querySelectorAll(`#global-navigation a[href="${pageLink}.html"]`)[0].classList.add("active-tab");
-
-
-// No Left Panel
-for (e in {"content-no-docs": 0, "content": 1}) {
- let noLeftPanel = document.querySelectorAll(`#${e}.no-left-panel`)[0];
- if (noLeftPanel != null)
- document.querySelectorAll('#side-nav')[0].classList.add('no-left-panel');
-}
-
-// Magic Text
-renderMagicText();
-
-// Anchor scroll correction
-document.querySelectorAll(".link-icon").forEach((e) => {
- e.addEventListener("click", (event) => {
- let id = e.getAttribute("href").replace("#", "");
- if (id != "" && id != null) {
- // offsetAnchor(event, id);
- event.preventDefault();
- toggleSyntax(id);
- }
- });
-})
-
-// Open description/pattern links in same tab rather than scrolling because hash links uses search bar
-document.querySelectorAll(".item-wrapper a:not(.link-icon)").forEach((e) => {
- e.addEventListener("click", (event) => {
- event.preventDefault();
- window.open(e.href);
- });
-})
-
-
-// Anchor click copy link
-const currentPageLink = window.location.toString().replaceAll(/(.+?.html)(.*)/gi, '$1');
-document.querySelectorAll(".item-title > a").forEach((e) => {
- e.addEventListener("click", (event) => {
- copyToClipboard(window.location.toString().split(/[?#]/g)[0] + "?search=#" + e.parentElement.parentElement.id);
- showNotification("✅ Link copied successfully.")
- });
-})
-
-// New element label click
-document.querySelectorAll(".new-element").forEach((e) => {
- e.addEventListener("click", (event) => {
- searchNow("is:new");
- });
-})
-
-// <> Search Bar
-const versionComparePattern = /.*?(\d\.\d(?:\.\d|))(\+|-|).*/gi;
-const versionPattern = / ?v(?:ersion|):(\d\.\d(?:\.\d|-(?:beta|alpha|dev)\d*|))(\+|-|)/gi;
-const typePattern = / ?t(?:ype|):(condition|expression|type|effect|event|section|effectsection|function)/gi;
-const newPattern = / ?is:(new)/gi;
-const resultsFoundText = "result(s) found";
-
-function versionCompare(base, target) { // Return -1, 0, 1
- base = base.replaceAll(versionComparePattern, "$1").replaceAll(/[^0-9]/gi, "");
- target = target.replaceAll(versionComparePattern, "$1").replaceAll(/[^0-9]/gi, "");
-
- base = parseInt(base) < 100 ? parseInt(base) * 10 : parseInt(base); // convert ten's to hundred's to fix (2.5.1+ not triggering 2.6 by converting 26 -> 260)
- target = parseInt(target) < 100 ? parseInt(target) * 10 : parseInt(target);
-
- if (target > base)
- return 1
- if (target == base)
- return 0
- if (target < base)
- return -1
-}
-
-var searchBar;
-var searchIcon;
-
-// Load search link
-var linkParams = new URLSearchParams(window.location.href.replace("+", "%2B").split("?")[1]) // URLSearchParams decode '+' as space while encodeURI keeps + as is
-if (linkParams && linkParams.get("search")) {
- setTimeout(() => {
- searchNow(linkParams.get("search")) // anchor link sometimes appear after the search param so filter it
- }, 20) // Until searchBar is loaded
-} else {
- // Search the hash value if available
- requestedElementID = window.location.hash;
- if (requestedElementID != undefined && requestedElementID != "") {
- setTimeout(() => {
- searchNow(requestedElementID);
- }, 20) // Until searchBar is loaded
- }
-}
-
-var content = document.getElementById("content");
-if (content) {
- let isNewPage = linkParams.get("isNew") != null;
- content.insertAdjacentHTML('afterbegin', ``);
- content.insertAdjacentHTML('afterbegin', `0 ${resultsFoundText}`);
- searchBar = document.getElementById("search-bar");
- searchIcon = document.getElementById("search-icon");
-
- if (isNewPage) {
- let tags = []
- let options = ""
- content.insertAdjacentHTML('afterbegin', `${options}`);
- options = document.getElementById("search-version");
-
- getApiValue(null, "skript-versions", "tags?per_page=83&page=2", (data, isCached) => { // 83 and page 2 matters to filter dev branches (temporary solution)
- if (isCached)
- data = data.split(",");
-
- for (let i = 0; i < data.length; i++) {
- let tag;
- if (isCached) {
- tag = data[i];
- } else {
- tag = data[i]["name"];
- }
- tags.push(tag.replaceAll(/(.*)-(dev|beta|alpha).*/gi, "$1"));
- }
-
- tags = [...new Set(tags)] // remove duplicates
-
- for (let i = 0; i < tags.length; i++) {
- let option = document.createElement('option')
- option.value = tags[i]
- option.textContent = "Since v" + tags[i]
- options.appendChild(option)
- }
-
- if (!linkParams.get("search") && !window.location.href.match(/.*?#.+/))
- searchNow(`v:${tags[0]}+`)
-
- return tags;
- }, true)
-
- }
-} else {
- content = document.getElementById("content-no-docs")
-}
-
-// Copy search link
-if (searchIcon) {
- searchIcon.addEventListener('click', (event) => {
- let link = window.location.href.split(/[?#]/g)[0] // link without search param
- link += `?search=${encodeURI(searchBar.value)}`
- copyToClipboard(link)
- showNotification("✅ Search link copied.")
- })
-}
-
-// Used when selecting a version from the dropdown
-function checkVersionFilter() {
- let el = document.getElementById("search-version")
- if (el) {
- searchNow(`v:${el.value}+`)
- }
-}
-
-function searchNow(value = "") {
- if (value != "") // Update searchBar value
- searchBar.value = value;
-
- let allElements = document.querySelectorAll(".item-wrapper");
- let searchValue = searchBar.value;
- let count = 0; // Check if any matches found
- let pass;
-
- // version
- let version = "";
- let versionAndUp = false;
- let versionAndDown = false;
- if (searchValue.match(versionPattern)) {
- let verExec = versionPattern.exec(searchValue);
- version = verExec[1];
- if (verExec.length > 2) {
- versionAndUp = verExec[2] == "+" == true;
- versionAndDown = verExec[2] == "-" == true;
- }
- searchValue = searchValue.replaceAll(versionPattern, "") // Don't include filters in the search
- }
-
- // Type
- let filterType;
- if (searchValue.match(typePattern)) {
- filterType = typePattern.exec(searchValue)[1];
- searchValue = searchValue.replaceAll(typePattern, "")
- }
-
- // News
- let filterNew;
- if (searchValue.match(newPattern)) {
- filterNew = newPattern.exec(searchValue)[1] == "new";
- searchValue = searchValue.replaceAll(newPattern, "")
- }
-
- searchValue = searchValue.replaceAll(/( ){2,}/gi, " ") // Filter duplicate spaces
- searchValue = searchValue.replaceAll(/[^a-zA-Z0-9 #_]/gi, ""); // Filter none alphabet and digits to avoid regex errors
-
- allElements.forEach((e) => {
- let patterns = document.querySelectorAll(`#${e.id} .item-details .skript-code-block`);
- for (let i = 0; i < patterns.length; i++) { // Search in the patterns for better results
- let pattern = patterns[i];
- let regex = new RegExp(searchValue, "gi")
- let name = document.querySelectorAll(`#${e.id} .item-title h1`)[0].textContent // Syntax Name
- let desc = document.querySelectorAll(`#${e.id} .item-description`)[0].textContent // Syntax Desc
- let keywords = e.getAttribute("data-keywords")
- let id = e.id // Syntax ID
- let filtersFound = false;
-
- // Version check
- let versionFound;
- if (version != "") {
- versionFound = versionCompare(version, document.querySelectorAll(`#${e.id} .item-details:nth-child(2) td:nth-child(2)`)[0].textContent) == 0;
-
- if (versionAndUp || versionAndDown) {
- let versions = document.querySelectorAll(`#${e.id} .item-details:nth-child(2) td:nth-child(2)`)[0].textContent.split(",");
- for (const v in versions) { // split on ',' without space in case some version didn't have space and versionCompare will handle it
- if (versionAndUp) {
- if (versionCompare(version, versions[v]) == 1) {
- versionFound = true;
- break; // Performance
- }
- } else if (versionAndDown) {
- if (versionCompare(version, versions[v]) == -1) {
- versionFound = true;
- break; // Performance
- }
- }
- }
- }
- } else {
- versionFound = true;
- }
-
- let filterNewFound = true;
- if (filterNew) {
- filterNewFound = document.querySelector(`#${e.id} .item-title .new-element`) != null
- }
-
- let filterTypeFound = true;
- let filterTypeEl = document.querySelector(`#${e.id} .item-title .item-type`);
- if (filterType) {
- filterTypeFound = filterType.toLowerCase() === filterTypeEl.textContent.toLowerCase()
- }
-
- if (filterNewFound && versionFound && filterTypeFound)
- filtersFound = true
-
- if ((regex.test(pattern.textContent.replaceAll("[ ]", " ")) || regex.test(name) ||
- regex.test(desc) || regex.test(keywords) || "#" + id == searchValue || searchValue == "") && filtersFound) { // Replacing '[ ]' will improve some searching cases such as 'off[ ]hand'
- pass = true
- break; // Performance
- }
- }
-
- // Filter
- let sideNavItem = document.querySelectorAll(`#nav-contents a[href="#${e.id}"]`); // Since we have new addition filter we need to loop this
- if (pass) {
- e.style.display = null;
- if (sideNavItem)
- sideNavItem.forEach(e => {
- e.style.display = null;
- })
- count++;
- } else {
- e.style.display = "none";
- if (sideNavItem)
- sideNavItem.forEach(e => {
- e.style.display = "none";
- })
- }
-
- pass = false; // Reset
- })
-
- searchResultBox = document.getElementById("search-bar-after");
- if (count > 0 && (version != "" || searchValue != "" || filterType || filterNew)) {
- searchResultBox.textContent = `${count} ${resultsFoundText}`
- searchResultBox.style.display = null;
- } else {
- searchResultBox.style.display = "none";
- }
-
- if (count == 0) {
- if (document.getElementById("no-matches") == null)
- document.getElementById("content").insertAdjacentHTML('beforeend', '
No matches found.
');
- } else {
- if (document.getElementById("no-matches") != null)
- document.getElementById("no-matches").remove();
- }
-
- count = 0; // reset
-}
-
-if (searchBar) {
- searchBar.focus() // To easily search after page loading without the need to click
- searchBar.addEventListener('keydown', (event) => {
- setTimeout(() => { // Important to actually get the value after typing or deleting + better performance
- searchNow();
- }, 100);
- });
-}
-// Search Bar >
-
-// <> Placeholders
-// To save performance we use the class "placeholder" on the wrapper element of elements that contains the placeholder
-// To only select those elements and replace their innerHTML
-document.querySelectorAll(".placeholder").forEach(e => {
- replacePlaceholders(e);
-});
-// Placeholders >
-
-// <> Syntax Highlighting
-document.addEventListener("DOMContentLoaded", function (event) {
- setTimeout(() => {
- document.querySelectorAll('.item-examples .skript-code-block').forEach(el => {
- highlightElement(el);
- });
- document.querySelectorAll('pre code').forEach(el => {
- highlightElement(el);
- });
- document.querySelectorAll('.box.skript-code-block').forEach(el => {
- highlightElement(el);
- });
- }, 100);
-});
-// Syntax Highlighting >
-
-
-// <> Example Collapse
-var examples = document.querySelectorAll(".item-examples p");
-if (examples) {
- setTimeout(() => {
- examples.forEach(e => {
- let pElement = e;
- let divElement = e.parentElement.children[1];
- pElement.addEventListener("click", ev => {
- if (pElement.classList.contains("example-details-opened")) {
- pElement.classList.remove("example-details-opened");
- pElement.classList.add("example-details-closed");
- divElement.style.display = "none";
- } else {
- pElement.classList.remove("example-details-closed");
- pElement.classList.add("example-details-opened");
- divElement.style.display = "block";
- }
- })
- })
- }, 50)
-}
-// Example Collapse >
-
-// <> Cookies Accecpt
-if (!isCookiesAccepted) {
- content.insertAdjacentHTML('beforeend', `
We use cookies and local storage to enhance your browsing experience and store github related statistics. By clicking "Accept", you consent to our use of cookies and local storage.
`);
-}
-
-let cookiesBar = document.querySelector("#cookies-bar");;
-let cookiesAccept = document.querySelector("#cookies-accept");
-let cookiesDeny = document.querySelector("#cookies-deny");
-if (cookiesAccept && cookiesDeny) {
- cookiesAccept.addEventListener('click', () => {
- setCookie('cookies-accepted', true, 99, true);
- cookiesBar.remove();
- });
- cookiesDeny.addEventListener('click', () => {
- cookiesBar.remove();
- });
-}
-// Cookies Accecpt >
\ No newline at end of file
diff --git a/docs/js/theme-switcher.js b/docs/js/theme-switcher.js
deleted file mode 100644
index 9e6314187fb..00000000000
--- a/docs/js/theme-switcher.js
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// This file is made to fix theme flicker at load due to 'defer' in main.js loading
-//
-
-// Auto load DarkMode from cookies
-if (getCookie("darkMode") == "false") {
- document.body.setAttribute('data-theme', 'white')
- document.body.insertAdjacentHTML('beforeend', ``);
-} else {
- document.body.insertAdjacentHTML('beforeend', ``);
-
- // Auto load from system theme
- // const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)");
- // if (darkThemeMq.matches) {
- // document.body.removeAttribute('data-theme');
- // } else {
- // document.body.setAttribute('data-theme', 'white')
- // }
- }
-
-setTimeout(() => {
- var themeSwitcher = document.getElementById('theme-switch');
- themeSwitcher.addEventListener('click', (event) => {
- if (document.body.getAttribute("data-theme") == null) {
- document.body.setAttribute('data-theme', 'white');
- event.target.src = "./assets/light-on.svg";
- setCookie("darkMode", "false", 99);
- } else {
- event.target.src = "./assets/light-off.svg";
- document.body.removeAttribute('data-theme');
- setCookie("darkMode", "true", 99);
- }
- });
-}, 500); // For some reason this wouldn't work in index.html (only) unless some delay is added o.O
\ No newline at end of file
diff --git a/docs/sections.html b/docs/sections.html
deleted file mode 100644
index 679e7adae44..00000000000
--- a/docs/sections.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
- Skript allows you to write pieces of text (programmers usually call them strings) in the scripts. This is done by putting the text inside double quotes, as follows:
-
-
"this is text"
-
- Simple, isn't it? If an effect, expression, condition, trigger or function accepts something of type text or string, you can use this format to write it right there!
-
-
Formatting Text
-
- But isn't just text a bit boring? Worry not, as Minecraft has support for colors, styles and other formatting options in chat. Most of the options also work with item and entity names.
-
-
Colors
-
- Minecraft has 16 pre-set color codes to be used in text. Skript supports them in two different ways:
-
-
- Color name tags, for example <red> Minecraft color codes, like §c; using & works, too
-
-
- Here's a table of all colors, including both Skript names and color codes:
-
-
-
-
Color
-
Code
-
Name
-
Alternative Names
-
-
-
-
§0
-
black
-
-
-
-
-
§1
-
blue
-
dark blue
-
-
-
-
§2
-
green
-
dark green
-
-
-
-
§3
-
cyan
-
aqua, dark cyan, dark aqua, dark turquoise, dark turquois
-
-
-
-
§4
-
red
-
dark red
-
-
-
-
§5
-
purple
-
dark purple
-
-
-
-
§6
-
orange
-
orange, gold, dark yellow
-
-
-
-
§7
-
grey
-
light grey, gray, light gray, silver
-
-
-
-
§8
-
dark gray
-
dark grey
-
-
-
-
§9
-
light blue
-
light blue, indigo
-
-
-
-
§a
-
light green
-
lime, lime green
-
-
-
-
§b
-
light cyan
-
light aqua, turquoise, turquois, light blue
-
-
-
-
§c
-
light red
-
pink
-
-
-
-
§d
-
magenta
-
light purple
-
-
-
-
§e
-
yellow
-
light yellow
-
-
-
-
§f
-
white
-
-
-
-
- In Minecraft 1.16, support was added for
- 6-digit hexadecimal colors to specify custom colors other than the 16 default color codes. A new tag can be used to format with these colors. The tag looks like this:
-
-
<##hex code>
-
Here's what the tag would look like when used in a script:
-
- send "<##123456>Hey %player%!" to player
-
-
- For information not related to Skript, see
- Minecraft Wiki page
- concerning colors. Note that depending on Skript configuration, color
- codes may do more than just change color of text after them. By default,
- for backwards compatibility, they clear following styles: magic, bold,
- strikethrough, underlined, italic. Other styles are not affected, and
- this feature can be toggled of in config.sk.
-
-
Other Styles
-
- Minecraft also has various other styles available. The following are
- available everywhere, including item and entity names:
-
-
-
-
-
Code
-
Name
-
Alternative Names
-
-
-
§k
-
magic test
-
obfuscated
-
-
-
§l
-
bold
-
b
-
-
-
§m
-
strikethrough
-
strike, s
-
-
-
§n
-
underlined
-
underline, u
-
-
-
§o
-
italic
-
italics, i
-
-
-
§r
-
reset
-
r
-
-
-
- If it wasn't clear from the table, §r clears all other formatting and
- colors. You'll probably use it quite often when sending chat messages
- from scripts.
-
-
- Skript also supports certain newer features, which are only available in
- chat. Those do not have formatting codes, so you must use tags for them.
-
-
-
-
Name
-
Alternative Names
-
Description
-
-
-
link
-
open url, url
-
Opens a link when player clicks on text
-
-
-
run command
-
command, cmd
-
Makes player execute a chat command when they click on text
-
-
-
suggest command
-
sgt
-
Adds a command to chat prompt of player when clicked
-
-
-
tooltip
-
show text, ttp
-
Shows a tooltip when player hovers over text with their mouse
-
-
-
font
-
f
-
Change the font of the text (1.16+)
-
-
-
insertion
-
insert, ins
-
Will append a text at player's current cursor in chat input only while holding SHIFT.
-
-
-
All of these styles require a parameter, in format
-
- <name:parameter>
-
-
- For link, parameter must be either http or https url if you want clients
- to recognize it. For others, it can be any text you'd like (you can make
- player run invalid commands if you wish).
-
-
Text and Variables
-
- Variable names are text, but obviously formatting that text does no
- good. However, everything else you can do for text, you can do for
- variable names. A guide about this is coming... some day.
-
\ No newline at end of file
diff --git a/docs/tutorials.html b/docs/tutorials.html
deleted file mode 100644
index d4e74bb75c6..00000000000
--- a/docs/tutorials.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
Tutorials
-
-
Note:
-
- Skript Tutorials are coming soon.
-
-
-
Loops
-
Commands
-
Functions
-
Variables
-
Visual effects
-
-
-
-
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index bfe06bfd9d6..3271da70815 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,11 @@
+# Done to increase the memory available to gradle.
+# Ensure encoding is consistent across systems.
+org.gradle.jvmargs=-Xmx1G -Dfile.encoding=UTF-8
+org.gradle.parallel=true
+
groupid=ch.njol
name=skript
-version=2.7.0-dev
+version=2.8.4
jarName=Skript.jar
-testEnv=java17/paper-1.19.3
+testEnv=java17/paper-1.20.4
testEnvJavaVersion=17
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 41d9927a4d4..7f93135c49b 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index aa991fceae6..ac72c34e8ac 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c787337f..0adc8e1a532 100755
--- a/gradlew
+++ b/gradlew
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac
done
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
fi
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
@@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32c4e..93e3f59f135 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/security.md b/security.md
index cd5dad1f445..839409cc93d 100644
--- a/security.md
+++ b/security.md
@@ -3,15 +3,12 @@ See also [code conventions](code-conventions.md); there are a few guidelines
about security of added code there.
## Reporting security issues
-Security issues may be reported to core team members privately e.g. on Discord.
-Note that this applies *only* to security issues; everything else should still
-be posted to issue tracker.
+Security issues may be reported via the GitHub private vulnerability reporting feature [here](https://github.com/SkriptLang/Skript/security/advisories/new).
+Note that this applies *only* to security issues; everything else should still be posted to issue tracker.
-Publicly posting security issues is also allowed, because not everyone has or
-wants a Discord account. We may add other channels for private reports in
-future.
+Please avoid publicly posting or discussing security issues that don't have a fix available yet.
## Team guidelines
Everyone with push access must use two-factor authentication for their Github
accounts. Should their account still be compromised, other team members should
-be immediately notified via Discord.
\ No newline at end of file
+be immediately notified via Discord.
diff --git a/settings.gradle b/settings.gradle
index 051b410bf2e..78b185aca4c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1,6 @@
+
+plugins {
+ id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
+}
+
rootProject.name = 'Skript'
diff --git a/skript-aliases b/skript-aliases
index e99be898254..490bbeadf6e 160000
--- a/skript-aliases
+++ b/skript-aliases
@@ -1 +1 @@
-Subproject commit e99be898254965b0207992f66a3289ab6744106e
+Subproject commit 490bbeadf6e44e26dd436acfd191dae5b740ebe6
diff --git a/src/main/java/ch/njol/skript/ScriptLoader.java b/src/main/java/ch/njol/skript/ScriptLoader.java
index fdca5b339ce..3fa8c855c32 100644
--- a/src/main/java/ch/njol/skript/ScriptLoader.java
+++ b/src/main/java/ch/njol/skript/ScriptLoader.java
@@ -23,21 +23,18 @@
import ch.njol.skript.config.SectionNode;
import ch.njol.skript.config.SimpleNode;
import ch.njol.skript.events.bukkit.PreScriptLoadEvent;
-import ch.njol.skript.log.SkriptLogger;
-import org.skriptlang.skript.lang.script.Script;
import ch.njol.skript.lang.Section;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.Statement;
import ch.njol.skript.lang.TriggerItem;
import ch.njol.skript.lang.TriggerSection;
import ch.njol.skript.lang.parser.ParserInstance;
-import org.skriptlang.skript.lang.structure.Structure;
-import ch.njol.skript.lang.util.ContextlessEvent;
import ch.njol.skript.log.CountingLogHandler;
import ch.njol.skript.log.LogEntry;
import ch.njol.skript.log.RetainingLogHandler;
+import ch.njol.skript.log.SkriptLogger;
import ch.njol.skript.sections.SecLoop;
-import ch.njol.skript.structures.StructOptions;
+import ch.njol.skript.structures.StructOptions.OptionsData;
import ch.njol.skript.util.ExceptionUtils;
import ch.njol.skript.util.SkriptColor;
import ch.njol.skript.util.Task;
@@ -47,10 +44,11 @@
import ch.njol.util.NonNullPair;
import ch.njol.util.OpenCloseable;
import ch.njol.util.StringUtils;
-import ch.njol.util.coll.CollectionUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;
+import org.skriptlang.skript.lang.script.Script;
+import org.skriptlang.skript.lang.structure.Structure;
import java.io.File;
import java.io.FileFilter;
@@ -60,7 +58,6 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@@ -467,7 +464,7 @@ public static CompletableFuture loadScripts(File file, OpenCloseable
* @param openCloseable An {@link OpenCloseable} that will be called before and after
* each individual script load (see {@link #makeFuture(Supplier, OpenCloseable)}).
*/
- public static CompletableFuture loadScripts(Collection files, OpenCloseable openCloseable) {
+ public static CompletableFuture loadScripts(Set files, OpenCloseable openCloseable) {
return loadScripts(files.stream()
.sorted()
.map(ScriptLoader::loadStructures)
@@ -493,7 +490,7 @@ private static CompletableFuture loadScripts(List configs, O
ScriptInfo scriptInfo = new ScriptInfo();
- List