commit 82192a48028afa1c7cbda8c6ce5e1ea1a9a43688 Author: ChockyPowder Date: Sun Sep 20 01:56:07 2026 +0100 Initial commit diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..6dd9aa6 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,91 @@ +# 📌 Pull Request + +## Description + + + +## Related Issues / Discussions + + + +- Fixes # +- Related to # + +## Motivation & Context + + + +## Type of Change + +Please tick all that apply: + +- [ ] 🐛 Bug fix (non-breaking change that fixes an issue) +- [ ] ⚡ Performance improvement +- [ ] 🧩 New feature (non-breaking) +- [ ] 🔧 Refactor / cleanup (no functional changes) +- [ ] 🔥 Crash / exploit fix +- [ ] 📚 Documentation update +- [ ] ❗ Breaking change (may affect plugins or server behavior) + +## Testing Performed + + + +- [ ] Compiled successfully with `mvn clean package` +- [ ] Tested on a Beta 1.7.3 server +- [ ] Existing functionality verified +- [ ] Edge cases considered + +**Test details:** +```text +Example: +- Local server with multiple players +- Testing on production environment on RetroMC +- Tested login, chunk loading, plugins, and shutdown +``` + +## Logs / Screenshots (if applicable) + + + +```(Optional)``` + +## Compatibility Considerations + + + +- [ ] No known compatibility impact +- [ ] Potential plugin impact (described below) +- [ ] Network / protocol (Netcode) behavior changed +- [ ] Configuration change required + + +## Compatibility Notes + + + +## Checklist + +Please confirm the following: +- [ ] No unnecessary formatting or whitespace-only changes +- [ ] Changes are compatible with Minecraft Beta 1.7.3 +- [ ] No dependencies have been added without discussion with the RetroMC team + +## Additional Notes + + + + +## Thanks for contributing to Project Poseidon! diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml new file mode 100644 index 0000000..9ab253c --- /dev/null +++ b/.github/workflows/build-and-test.yaml @@ -0,0 +1,101 @@ +name: build-and-test +on: + pull_request: + types: + - opened + - synchronize + - reopened + push: + branches: + - master + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + # Step 1: Checkout the repository + - name: Checkout + uses: actions/checkout@v4 + + # Step 2: Set up JDK 1.8 + - name: Set up JDK 1.8 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: 8 + + # Step 3: Get the version from pom.xml + - name: Get the version from pom.xml + id: get_version + run: echo "PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV + + # Step 4: Generate custom release version + - name: Generate Release Version + id: release_version + run: | + DATE=$(date +'%y%m%d-%H%M') + SHA=$(echo $GITHUB_SHA | cut -c1-7) + RELEASE_VERSION="${PROJECT_VERSION}-${DATE}-${SHA}" + echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV + + # Step 5: Create version.properties file + - name: Create version.properties file + run: | + mkdir -p src/main/resources + + # Application Information + APP_NAME=$(mvn help:evaluate -Dexpression=project.name -q -DforceStdout) + + # Core Metadata + echo "version=${{ env.RELEASE_VERSION }}" >> src/main/resources/version.properties + echo "build_timestamp=$(date --utc +'%Y-%m-%dT%H:%M:%SZ')" >> src/main/resources/version.properties + echo "git_branch=${{ github.ref_name }}" >> src/main/resources/version.properties + echo "git_commit=${GITHUB_SHA}" >> src/main/resources/version.properties + + echo "app_name=${APP_NAME}" >> src/main/resources/version.properties + echo "release_version=${{ env.RELEASE_VERSION }}" >> src/main/resources/version.properties + echo "maven_version=${{ env.PROJECT_VERSION }}" >> src/main/resources/version.properties + + # Build Type + if [[ "${{ github.ref }}" == "refs/heads/master" || "${{ github.ref }}" == "refs/heads/main" ]]; then + BUILD_TYPE="production" + elif [[ "${{ github.event_name }}" == "pull_request" ]]; then + BUILD_TYPE="pull_request" + else + BUILD_TYPE="development" + fi + echo "build_type=${BUILD_TYPE}" >> src/main/resources/version.properties + + # CI/CD Metadata + echo "workflow_name=${{ github.workflow }}" >> src/main/resources/version.properties + echo "workflow_run_id=${{ github.run_id }}" >> src/main/resources/version.properties + echo "workflow_run_number=${{ github.run_number }}" >> src/main/resources/version.properties + + # Team or Author Information + echo "build_author=${{ github.actor }}" >> src/main/resources/version.properties + + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.1 + + # Step 6: Build application + - name: Build Application + shell: bash + run: | + mvn clean install + + # Step 7: Run Tests + - name: Run Tests + shell: bash + run: | + mvn test + + # Step 8: Upload artifact + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ github.event.repository.name }}-artifact + path: target/*.jar diff --git a/.github/workflows/java21-buld-test.yaml b/.github/workflows/java21-buld-test.yaml new file mode 100644 index 0000000..28ae58f --- /dev/null +++ b/.github/workflows/java21-buld-test.yaml @@ -0,0 +1,39 @@ +name: Java-Compatibility +on: + pull_request: + types: + - opened + - synchronize + - reopened + push: + branches: + - master + - main + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + # Java 8 is tested as a part of the build-and-test workflow + java-version: ['17', '21' ] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Java ${{ matrix.java-version }} + uses: actions/setup-java@v2 + with: + java-version: ${{ matrix.java-version }} + distribution: temurin + java-package: jdk + + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.1 + + - name: Build application + shell: bash + run: | + mvn clean install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b70bf9d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,112 @@ +name: Release Workflow + +on: + push: + branches: + - main + - master + +permissions: + contents: write + +jobs: + build-and-release: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up JDK 8 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "8" + cache: maven + + - name: Get Maven project version + id: get_version + run: echo "PROJECT_VERSION=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version)" >> "$GITHUB_ENV" + + - name: Fail if snapshot version + run: | + if [[ "$PROJECT_VERSION" == *"-SNAPSHOT"* ]]; then + echo "Snapshot versions are not releasable: $PROJECT_VERSION" + exit 1 + fi + + - name: Generate Release Version + run: | + DATE=$(date +'%y%m%d-%H%M') + SHA=$(echo "$GITHUB_SHA" | cut -c1-7) + RELEASE_VERSION="${PROJECT_VERSION}-${DATE}-${SHA}" + echo "RELEASE_VERSION=$RELEASE_VERSION" >> "$GITHUB_ENV" + echo "Release version: $RELEASE_VERSION" + + - name: Set Maven version to Release Version (no commit) + run: | + mvn -B versions:set -DnewVersion="${RELEASE_VERSION}" -DgenerateBackupPoms=false + + - name: Create version.properties + run: | + mkdir -p src/main/resources + + APP_NAME=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.name) + + { + echo "version=${RELEASE_VERSION}" + echo "build_timestamp=$(date --utc +'%Y-%m-%dT%H:%M:%SZ')" + echo "git_branch=${GITHUB_REF_NAME}" + echo "git_commit=${GITHUB_SHA}" + echo "app_name=${APP_NAME}" + echo "release_version=${RELEASE_VERSION}" + echo "maven_version=${RELEASE_VERSION}" + + if [[ "$GITHUB_REF" == "refs/heads/master" || "$GITHUB_REF" == "refs/heads/main" ]]; then + BUILD_TYPE="production" + else + BUILD_TYPE="development" + fi + echo "build_type=${BUILD_TYPE}" + + echo "workflow_name=${GITHUB_WORKFLOW}" + echo "workflow_run_id=${GITHUB_RUN_ID}" + echo "workflow_run_number=${GITHUB_RUN_NUMBER}" + echo "build_author=${GITHUB_ACTOR}" + } > src/main/resources/version.properties + + - name: Write Maven settings.xml for Nexus auth + run: | + mkdir -p ~/.m2 + cat > ~/.m2/settings.xml << 'EOF' + + + + johnymuffin-nexus + ${env.NEXUS_USERNAME} + ${env.NEXUS_PASSWORD} + + + + EOF + env: + NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} + + - name: Build & Deploy to Nexus + run: mvn -B -DskipTests clean deploy + env: + NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ env.RELEASE_VERSION }} + name: ${{ env.RELEASE_VERSION }} + files: | + target/*.jar + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47e6fdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,237 @@ + +# Created by https://www.gitignore.io/api/java,intellij,intellij+all,intellij+iml +# Edit at https://www.gitignore.io/?templates=java,intellij,intellij+all,intellij+iml + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### Intellij+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Intellij+iml ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### Intellij+iml Patch ### +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# End of https://www.gitignore.io/api/java,intellij,intellij+all,intellij+iml +/bin/ + +# Eclipse project files (Hopefully I don't mess everything up now -Saghetti) +.project +.classpath +.settings/ + +# Remvoe server stuff from path +/server/ + +# Maven target files +/target + +# Don't need dependecy reduced pom +dependency-reduced-pom.xml \ No newline at end of file diff --git a/LICENCE.txt b/LICENCE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENCE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9aea528 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# Project-Poseidon +![](/img/banner.png) +## What's Project Poseidon? +**A CraftBukkit CB1060 fork for Beta 1.7.3 fixing bugs and adding basic features.
** + +If your looking for Project Poseidon support on pre-1.7.3 versions, please check out [Project Poseidon Uberbukkit](https://github.com/Moresteck/Project-Poseidon-Uberbukkit) developed by Moresteck which supports earlier versions.
+ +Discord: https://discord.gg/FwKg676 + +## Features +This is a non-exhaustive list of features that Project Poseidon includes: + +- **UUID Support:** Settings to enable UUID-based inventories alongside methods for plugins to transition to UUID-based systems similar to modern Minecraft server implementations. +- **Poseidon Watchdog Implementation:** An automatic utility for detecting server hangs, ending the server process, and providing diagnostics to fix the underlying issues. +- **Packet Events:** Adds packet send and receive events for advanced plugin development without needing Spout or to use Reflections that are incompatible with modern Java versions. +- **Inventory Block Duplication Fixes:** Includes fixes for chest, furnace, inventory block duplication, and Minecart duplication issues. +- **Cross-World Duplication Fix:** Fixes a cross-world duplication glitch. +- **Duplication Glitch Fix:** Fix a bug with the Bukkit chunk cache which allowed users to duplicate and get unobtainable items. +- **Server Crash Fix:** Addresses multiple server crash issues. +- **Connection Pauses:** A powerful feature allowing developers to retrieve information asynchronously before a player connects. +- **Event Handlers:** Modern event handlers backported to facilitating easier coding, plugin backporting, and early release plugin support. +- **Vanish API Backport:** Backports the modern vanish API for easy vanish plugin creation and fixes issues with hacking players seeing vanished players. +- **Logging Enhancements:** Adds an option for daily log file creation and logs player commands to the console, with exceptions for Authme, XAuth, and similar plugins. +- **TPS API and Command:** Adds a TPS command and API for plugins to access historical TPS data. +- **Server Shutdown Improvements:** Enhances server shutdown procedures to ensure world/player data and plugin data are properly saved. +- **Release2Beta Support:** Added support for Release2Beta, including IP Forwarding. +- **Tree Growth Blockage Settings:** Allows server owners to block tree growth from replacing certain blocks to prevent griefing. +- **TCP NoDelay Option:** Improves netcode performance for compatible clients. +- **Ragequit/Ragejoin Fixes:** Prevents ragequit and ragejoin connection/chat spam. +- **Plugin Hiding:** Allows plugins to be hidden from the server list via an attribute in `plugin.yml`. +- **Improve Console Debug:** Make multiple common errors less verbose in the console. +- **Event Handling Improvements:** Ensures primed TNT fires the correct event and backports the explosion event from modern Bukkit. +- **Spawn Location Options:** Provides options to disable spawn location randomization and teleportation to the highest safe block on join. +- **Configurable Mob Spawner Area Limit:** Allows server owners to set a mob-cap for mob spawners to prevent mob farms from causing extreme lag. + + + +## Want to use Project Poseidon on your server? +Please read the following article before changing over to Project Poseidon: https://github.com/RhysB/Project-Poseidon/wiki/Implementing-Project-Poseidon-In-Production + +# Download +You can download the latest builds at the [GitHub Releases](https://github.com/retromcorg/Project-Poseidon/releases/). + +Historical builds can be found on the [Glass Launcher Jenkins](https://jenkins.glass-launcher.net/job/Project-Poseidon/). + +Please note, download the artifact (JAR) without original in the name, eg. `project-poseidon-1.1.8.jar`. + +## Maven Repository & Plugin Development + +### Maven Repository +Project Poseidon releases are published to the Legacy Minecraft Maven repository: + +- **Repository:** https://repository.johnymuffin.com/ +- **Browse Poseidon artifacts:** + https://repository.johnymuffin.com/#browse/browse:maven-releases:com%2Flegacyminecraft%2Fposeidon%2Fposeidon-craftbukkit + +This repository can be used to depend on Poseidon artifacts directly in your build tooling (e.g. Maven or Gradle) when developing plugins. + +### Plugin Development Examples +Examples demonstrating how to develop plugins for Poseidon using **Maven** and **GitHub Actions** can be found here: + +- **Poseidon Plugin Template:** + https://github.com/retromcorg/Poseidon-Plugin-Template + +The template includes: +- A preconfigured Maven project +- GitHub Actions CI configuration +- Correct repository and dependency setup for Poseidon plugin development +- Example code including player listeners and a config system + + +## Licensing +CraftBukkit and Bukkit are licensed under GNU General Public License v3.0
+Any future commits to this repository will remain under the same GNU General Public License v3.0
+Libraries in the compiled .jar files distrusted may contain their own licenses.
+This project contains decompiled code that is copyrighted by Mojang AB typically under the `net.minecraft.server` package.
+ +## How To Setup - IntelliJ IDEA + +1. Clone this project using Git or a desktop client. +2. Open IntelliJ and create a new project in the same directory as the Project Poseidon folder. + +## Compiling + +Compiling is done via maven. To compile a JAR, cd into the Project Poseidon directory and run the following command: + +``` +mvn clean package +``` + +You should now have a runnable JAR inside the /target folder! + +## Regarding the DMCA of CraftBukkit in 2014 +The contributor Wolverness who first contributed on CraftBukkit in February 2012 issued a DMCA against CraftBukkit and other major forks of CraftBukkit. +This project is based on the following commits: + +* CraftBukkit: [54bcd1c1f36691a714234e5ca2f30a20b3ad2816](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/54bcd1c1f36691a714234e5ca2f30a20b3ad2816) (SpigotMC) +* Bukkit: [3524fde5ffc387ef9e39f6ee7dae83ff4dbf8229](https://github.com/Bukkit/Bukkit/commit/3524fde5ffc387ef9e39f6ee7dae83ff4dbf8229) (GitHub) + +The Bukkit and CraftBukkit commits that Project Poseidon is based on are before Wolverness started contributing. + +If you were a contributor before these commits please feel free to contact me or open an issue asking for this repository to be taken down. + +## MC-DEV +We include files from the mc-dev GitHub repository. This code is automatically generated using minecraft_server.jar and sourced from the Bukkit repositories. +* MC-DEV: [1a792ed860ebe2c6d4c40c52f3bc7b9e0789ca23](https://github.com/Bukkit/mc-dev/commit/1a792ed860ebe2c6d4c40c52f3bc7b9e0789ca23) + +If Mojang Studios or someone on their behalf wants to have this repository removed due to including copyrighted Minecraft sources like bukkit/mc-dev, please contact me or make an issue. + +## How to setup ModLoaderMP support (NOT WORKING) +Please read the following: https://github.com/RhysB/Project-Poseidon/wiki/Adding-ModLoaderMP diff --git a/img/banner.png b/img/banner.png new file mode 100644 index 0000000..931f6e7 Binary files /dev/null and b/img/banner.png differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2dff7f2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,253 @@ + + 4.0.0 + + com.legacyminecraft.poseidon + poseidon-craftbukkit + 1.1.12 + + jar + + Project Poseidon + + UTF-8 + unknown + + + scm:git:git://github.com/Bukkit/CraftBukkit.git + scm:git:ssh://git@github.com/Bukkit/CraftBukkit.git + https://github.com/Bukkit/CraftBukkit + + + + bukkit-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots + + + + + + + jline + JLine Project Repository + http://jline.sourceforge.net/m2repo + + + + johnymuffin-nexus-releases + https://repository.johnymuffin.com/repository/maven-public/ + + true + + + false + + + + + johnymuffin-nexus-snapshots + https://repository.johnymuffin.com/repository/maven-snapshots/ + + false + + + true + + + + + + + johnymuffin-nexus + https://repository.johnymuffin.com/repository/maven-releases/ + + + + johnymuffin-nexus + https://repository.johnymuffin.com/repository/maven-snapshots/ + + + + + + + + + + + + + + org.bukkit + bukkit + 0.0.1-POSEIDON + jar + compile + + + net.sf.jopt-simple + jopt-simple + 6.0-alpha-3 + + + jline + jline + 0.9.93 + jar + compile + + + org.xerial + sqlite-jdbc + 3.7.2 + jar + compile + + + mysql + mysql-connector-java + 5.1.14 + jar + compile + + + + modloader + ModLoaderMP-B1.7.3 + 1.0 + system + ${project.basedir}/libs/ModLoaderMP.jar + + + + + org.avaje + ebean + 2.7.3 + jar + provided + + + org.yaml + snakeyaml + 2.0 + jar + provided + + + com.google.guava + guava-collections + r03 + jar + provided + + + org.jetbrains + annotations + 20.0.0 + + + + + com.google.guava + guava + 32.0.0-jre + jar + compile + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + com.google.code.gson + gson + 2.9.0 + + + + + + clean install + + + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + org.bukkit.craftbukkit.Main + Project-Posiden + RhysB + Bukkit + ${api.version} + Bukkit Team + true + + + + net/bukkit/ + + true + + + + com/bukkit/ + + true + + + + org/bukkit/ + + true + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + junit:junit + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + + diff --git a/resources/META-INF/MANIFEST.MF b/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..a77e8c3 --- /dev/null +++ b/resources/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Created-By: 1.6.0 +Specification-Title: Bukkit +Main-Class: org.bukkit.craftbukkit.Main +Specification-Version: unknown +Specification-Vendor: Bukkit Team +Implementation-Version: git-Bukkit-0.0.0-980-g4ed23b1-b1060jnks +Implementation-Vendor: Bukkit Team +Sealed: true +Implementation-Title: CraftBukkit + +Name: net/bukkit/ +Sealed: true + +Name: com/bukkit/ +Sealed: true + +Name: org/bukkit/ +Sealed: true diff --git a/resources/achievement/map.txt b/resources/achievement/map.txt new file mode 100644 index 0000000..aaf280a --- /dev/null +++ b/resources/achievement/map.txt @@ -0,0 +1,446 @@ +1000,43ddd8b48469d9a8c011718aa846facb +1001,aaed8c669f583cf35300f7c5d5396fce +1002,d517ae73160fd8576d7687ead1c1a973 +1003,ac37df168bae3c69a24d7fd5bae913c7 +1004,6d2591e94464b8327afadbdba44978d +1100,8b1df73e012e2ae34cd2d84a72a7898b +2000,c9ee0d494e0524c86a577cf684f5816d +2001,cd7a2836ea0b77b23a6131222f5be354 +2002,381aeedb2c5c5a7a9a01333e0eebc839 +2003,229048d1bb9e928831734cb2e5000286 +2004,b2c088c3c6928bfe29684a75ae1b127c +2005,1ce3491a1021a5aed07c687e3f6133e6 +2006,6c3d114caffd8160f7d56fc8757419a +2007,bcb501cfac8f7e73b455563bddbcb417 +2008,e1aa93d7bba48898a32810c43c6ff5c3 +2010,d0818779df1b967cc2f8ffc3ada631ec +2011,ecf0dbe93240e84edf6bd263645e634f +2020,b4a67353e11c3039ad755a3e96b4a046 +2021,1bb21f7731a5b3ffc6a1e2b586dae3f5 +2022,e58162e284df8fe339f05626eb46d835 +2023,739948643f5f6f685aea81c42883a480 +2024,799b0d35362a9574d3226c2d762b53c6 +2025,5ec18fbb462516a1e1a3427e0595a7d6 +16908544,12512904b67d2091dd516dc8eeb0cfa0 +16908545,a5c35cc01a263f91419d3e8e981708f1 +16908546,f6bdebf227e42c204066cede8cb5928c +16908547,9c44e6d3ab80afa2bb52fe3499559d5e +16908548,2e1799ddfdab14417c2a8e24d8c0c731 +16908549,3f4169a181feb5d2532efc6aa91f2ee5 +16908550,895725d3432cbf374b1cce4f7db28e9 +16908551,12892864f18d30521b6f4a6c45b65ece +16908552,146f6c3458adde8e0bca04d976275f85 +16908553,7c40dbd9451129b4762f3ab04ce7ffb9 +16908554,56d763eeb6a0107c2146d7dccd686d2a +16908555,9a4fff004ae419711c2a876b57cba69f +16908556,170ff67dd90d8d3d8dae393037da5e9b +16908557,3e65d657af8611cb3578cd8713419d4c +16908558,f3cb95383f698c4e9721b5aaa5fac3a7 +16908559,65bd006dc163a186f2dbb127f8ec0b27 +16908560,8c6479d786f9117e04910153a4f47d86 +16908561,75a25bd69f36250789d914ac01da34c1 +16908562,87a28b2bf2fad838af72ce00e2fb1937 +16908563,249ff32d605c5ba0a07694ff4fbbf15a +16908564,ba3b355eb9134bcd7522a1fc203c4c58 +16908565,321e1cb3657d2aca73fb9a8083d9c3bf +16908566,adb182051fab2c2269df89b4f75e505e +16908567,3d9ae8982f01fb6a6c56cffbe2fa074e +16908568,1efffb054b2c864f5ebe180ae46891c3 +16908569,25c73629d0b6b46690d222cecf331ba2 +16908570,6a46694c996e5721b14c9da1f00fe62c +16908571,5efc1c291eef23fe33f5209388b8cc33 +16908572,f71fc7deef6835c8efc305a00f1e8b8f +16908573,15484a373254c6024d90edf3b7a82947 +16908574,8253f1aaa2205dcaf828903cfce46e4 +16908575,ab778410d1fb2c0e55fec0c7d764b17c +16908576,19ad61c04ff3ae082955f72fc8771866 +16908577,b5d3eeff40086643a03f034b5345504d +16908578,3d647bf5562e743263cbd90be36b6a1c +16908579,5a9d2fb7050009785421257d5ef24416 +16908580,909b03e2d2eeee2e868b5aaf446e81ea +16908581,e603a4cbfdfcbf4d0bfe25efb753b424 +16908582,e355f481f99220e50e4b2b2eb45dcc56 +16908583,73a25e59c2d18ae77db02928b0a70e3 +16908584,8f81a2fb647f817422a299829994de7b +16908585,128e9978380ee9ef981d2e12d008255e +16908586,fd1453f3e2a3125e7d16cfe6fd2d4722 +16908587,8e27b6f750bec22333a5d4108ce1e094 +16908588,b2169f6190bdf95236037bed2301712b +16908589,536e6340e5328075ede672428d94d921 +16908590,cb9eede8b783b4a5d7ff7529e3fb1f44 +16908591,267d51d891c3c32b3a02577d38f4e242 +16908592,3f31e8ab260f02acca218c720fafc7b8 +16908593,552869a63aa3151e79e875596f31e505 +16908594,c5b0399e7fc64f0561a82063773e1282 +16908595,cfd61cdbf22133caeca528da9b53474e +16908596,8d3802169313f270d5adcda790170ca2 +16908597,a82c4f31d6d3f5bef9aa3062945c02d6 +16908598,85eca649072752e9ffafdefa1287470f +16908599,98ffd259abbe2e4794c00716a9d2da7 +16908600,263f8fab89ae0f9d695a74512443070b +16908601,b4ae28e8babe7bd09b2a392780565dbe +16908602,dfd84b5b35231267a47891cc8c8f48ba +16908603,f6990bbd57862a238aaf68b0c2f4c998 +16908604,9dca837e109ae977a89ed64dd17fab10 +16908605,ebdb407fd6e4d5c450f73173487c3162 +16908606,fdf869946d814f4f2aeebe269db06e31 +16908607,f9ea1fa393862a86e79ffade6a2662e7 +16908608,60491b4f5956534afd5959e7c2411cda +16908609,b78fc6d8b8b8ecb1266eb9c04c5129b +16908610,add241f6dcfe6af3f096a45b96fb04e1 +16908611,38760b28c0d26204b1e0383ca318947a +16908612,d3d8076b8b7a911b7cbbf5099f8ffd48 +16908613,fc78be6fb5735b715325ac499990550e +16908614,a7504fcd85d6696a8880f32b97b34a60 +16908615,f0821b6fdc8ebbf8a6fcb37c75086b1d +16908616,88b0e1b842fc88f0cbc5f38e95d68417 +16908617,d977f8453c349a44baa7e05c3dd81cb8 +16908618,26184c3c1edfa7623d5620433c0ff36 +16908619,8edbf7f3996852add4fcb18008cb722f +16908620,39e5881696ed1141fb934593dd6bab70 +16908621,1e0d787240ea16af6edbbdb1ab372fe7 +16908622,af6ec83a0b072b4abd4194d8d43f7f02 +16908623,658b5f77ff892a455a7fce5dc93268ac +16908624,6474336f089d541c9cec4a1df0c3b6cf +16908625,72cfc6fe503df207d53119aa7d5b84b4 +16908626,3070c2283ca5fd0fe00f7880a4bcdf18 +16908627,340cef5b043dceb7073ede0be69d700d +16908628,24dda1839a72d6707ed1932f6f32bd8e +16908629,1c50c7d94cec18710417d513708094d1 +16908630,2b1f11fed636bf7892650b9adc9b8e94 +16908631,afd9ba61c39fa742a840fe6ab2cfb490 +16908632,b709157ffabe225e820218b020508173 +16908633,3e9f7b867952f7b2df48e156402d558 +16908634,ab9f22a1fbc265d19a4dd7f84f3a4585 +16908635,c89cf9510108d63d7d181b3f7c546094 +16908636,c7af3251ce44f2dafb2c192d817e9c52 +16908637,796f607d214012447b7c552673f95b4a +16908638,ea796bd83dd7689d322085c74d0957a7 +16908639,ce2f6f842d68418baad5fc2ecefcb879 +16908640,6b3016429a5f814f3cccaff484a46831 +16908641,7dea9bdb69c9c5965609eab99af9f9d9 +16908642,3add5c50b3427182fcb7dd04fe953945 +16908643,4175965cd5cee134d43038ac54858b0f +16908644,feae27a32b6cc95860ec46da6d37c4b0 +16908645,5898813ee0b2785afc9dad2524f56162 +16910544,adb04e128238341b88a18532f3448d13 +16910545,8e274d3a14b5cb87cbce019d0a3b9a23 +16974080,cfed396d9f54d3c04bc390a004916c52 +16974081,64f1b3409c0937114f77f9933a4e2b82 +16974082,5a6e9dc254405a6cb066472172fa09b1 +16974083,b23adf8b24d9a42637977c3322f02b75 +16974091,df1b76bca1e6a035d3e22e7c01f67bc6 +16974092,4bb3d702d36739ba62041c0c936cbfb6 +16974093,d02062bdb07f81100381ef87e6fc2922 +16974094,1a0d208f9f489b37b800c6eeaaa752c9 +16974095,34ee6807c2040168606740d0e3f46e30 +16974096,9b8bb8517841df03f1a894b238251068 +16974097,bb0b43349ffa6aa13b5d84ca70d25eb3 +16974098,b3b647da85fe51c6da997e28b66cb4c3 +16974099,d33c3d7d3fbc6880e0e03ce573644b1e +16974100,17d45fba9866349c133608e9d42e4ac9 +16974101,74205e9529729bd0ef51c3d544c1e372 +16974102,edf620106dc10c10a3357436a306400d +16974103,74b3a17953dca5a0cb9bb8c47b241eca +16974107,1938aff98985ef5e79c7003868c1e91 +16974108,14b782f5d9afda571ce6c8bad868e2bd +16974109,cb124718b4ecfb29a900e1e617c79544 +16974110,ae3c73a1546a058da74d4b8a588b59f2 +16974114,cbdefe9bd14088ad45141843474d2bb0 +16974115,641938697f84f6e7b59ebc08edc4648b +16974116,74ccb1de521aa54c65ffcb906ffd1d3b +16974117,fffed44e7bb844ad6c69f7eb4540cff3 +16974118,536b2d3a4009eed61300bf5f0af7419e +16974122,8a8ea889723fc0f8de50c53339819871 +16974123,768b65f8e24b1e042b75cf6f576cfcd1 +16974124,a4b5522486920acfc2ed97e105c7831 +16974125,6e9b513f3c219f4276556070b36a0339 +16974126,942450301cd8068c9a14352c1cecc2d0 +16974127,c98e2b8eb252d75a2a1f90144596ada4 +16974128,7b13a95332dac62ad73cddf33d3bba0f +16974129,1951adc5a346867490626a854788b9ad +16974130,b75636944eeba77a4ce3f254460e0d49 +16974131,bb5bc2285c0a2e24548533f59af76788 +16974132,929561410b14786db52aa89b675a9759 +16974133,6b07bd2605f311d8134a8170ba49fd73 +16974134,2f97923d891e3e8c1967d53f7734ff55 +16974135,dea0b11c8760d28eafbe76e25df7d301 +16974136,586e309c00ba6f3c2ada595b742bef23 +16974137,29e48d74dc5062eb900d376196fd4f23 +16974138,fa79e8b641b225166b17ea86a9ecb174 +16974139,7a66328b6b976337ff5bde5c7edccaa5 +16974140,95559b402657cf222a87248d1e6ce0f5 +16974141,52843420526ced65d57513afad342515 +16974170,56690bacbebf8107b83e80528f40740 +16908289,83cfae9a11032a88e08c95b7fcef84cc +16908291,39a4ea3b5ddf7f89b41faf675f7bfc0f +16908292,64ec21dc8495fb180cc94f59f873efb8 +16908293,fda16e9858404b9545649ba21a828a6a +16908294,a57157213ffc25d269ea46e45984eae0 +16908295,90f2ac6ac3005ad4cabcd248831f2205 +16908296,4adafcbbef5ace168ca03e173af10452 +16908298,bb2e0425d8b489fc856cab2c0828f2ff +16908300,76b80613789c553593097956002a392b +16908301,23bd5cc4fb97d25e432604be0958320d +16908302,7b129f5775b2d4997681338012130cad +16908303,4935425ac3ef59e71bca7c4c8bf7e2ea +16908304,564d5c2df622b99692929bedbcd7f4b1 +16908305,e06bb538b6b224ce1376b47804ee2bbb +16908306,f13b4a0fa66e65ed33dcbd7ead08ac46 +16908307,29710a54739e35ae0d34919fca091640 +16908308,8693b46ac89dd595f8e3efd4437e6e90 +16908309,3ebf10825c7d8f2e17deae70b37d1fbd +16908310,354d414b2a1f29494a80b3acedb72ae2 +16908311,de662954670ec00899809b916abe6c60 +16908312,831dd7a79cd7e5f3cad86690c6724902 +16908313,265f19645487a858e4f53b9706cdff03 +16908314,2ad06f9f7e24f920fb067e2f2cc7869c +16908315,99f3286cc36b9a4393b3e967878b01d4 +16908316,4fbc91a39f7f4814f8f79ba425e4f30a +16908318,ccb82be2278587dd637ac763a1087c7 +16908323,8e8a2f6a87c3701e76650680e7b2f6e6 +16908325,fcd992a9a44518d5de6bd09c409ea7de +16908326,e41e706456c10963824e032484992946 +16908327,662301d3344073cc69887a27a8c42f24 +16908329,313738e052612f868d55f47940080288 +16908330,79474b10f860f09be4e9183ad5f1c7b4 +16908332,60a3062d151151a2ff229a02d3221337 +16908333,833c8c420ce04aa18b9912ff05e5ced2 +16908334,6e0f4183ad7abbb63c5b6a1ead24214a +16908335,477292deea02d72acc1087b2425c570a +16908336,82cf44076f1a94ed31f3172433a80ef6 +16908337,84f64a9f8523d35a1cf8319f580dd578 +16908338,b6365376050089a025a1ed1d85a85dba +16908339,4e989db8b445f22b61bd4d30daee1a05 +16908340,50ec890e85029d44ea96bfa31d8ed16a +16908341,b4f23438454d39a742546dafd5d3cfc6 +16908342,5414035b686e0fb0a1ce0d535d0a0f82 +16908343,72d6218e86d3787422fa6b03f30ccaf3 +16908344,ddfe42c53aae03dd94c2d3163869ddc0 +16908345,b8b09ac7af1bb81e28715a3e0f0eeb17 +16908346,c53d28ac584d8053ec438f692a58cd1a +16908347,243cf7fb2bf36e60e3a25cde83b33a5e +16908349,2837ae3dabc00c4c5515bafa34a302dc +16908351,4973e12438ce4c870f6ba1c158873c43 +16908352,37678301896aa95cc358bcd73308232c +16908353,31c5e38768bda9a8a7cd1bbca7c9226d +16908354,5ff1e27f9ef25fcf0a3c51b0551f7fd2 +16908355,60a060ee3e51167f4d87cf6d923f9ca7 +16908356,b24aa4a609b3483b795c4f3bf89116b7 +16908357,7a17a96ff758cd4ff8c0ffd070230cc7 +16908358,c14586711c04239a174c192d24b8ce20 +16908359,1f0abe2925128be5191932a1cc4a3019 +16908360,a9c8343cf444aa7686d9dd2b40e90a47 +16908361,94a02b3ef18bb35970105bf276001fe0 +16908363,bfa45b4169d1944debabc84b04880837 +16908365,a3d0bb31ba7c30209129e4366e072b05 +16908366,de6d35451526c85c7c5907a0adcbeff7 +16908367,4a0d45a9aedaa06eb574f88f580c265b +16908368,56ab2510d3cb4787bdcfa9680aa7e757 +16908369,feef935305ae32e1972d3b017a4eb +16908370,41b270e7ecb39d0b81d1b60f32c3943 +16908371,b159339fc55e60000efee4c55d0e1d1c +16908372,74ca5387c7d373fc88e65e0623d5991f +16908373,8b8ae20ea681d47cd899f74f75bde08d +16908374,5cb926f4743f6ccdb4988c8b35dc97dd +16908375,947a02e037fe9d31c8eb4c4a22dba58c +16908376,2c2a7e8a269a770cc4afbe695e662601 +16908377,9a992e19651652de8b4f5ce07d1d2af0 +16908378,3e37efadc720d972ddc30ccae606ab00 +16908380,77b1802a2504a685bf8ff34a1f9de6c3 +16908381,45c0dbda39dca97dc634a6e89f037716 +16908383,ca404ded18b83fd872a5810c8a44517d +16843027,ecc0eb0ba51e2c14aaa006e168eacc8c +16842753,f6282e18f6f87e4cf68970579aac7219 +16843026,6f3d105b3e6d1624af4ce68b2a55362d +16843025,aa1c8e137823bf5245f0d27c980796e7 +16843024,ed65803a11251872c6cf659381d0aaaa +16843031,fa2f9de197813d8e32d78bd184603161 +16842757,1a13db89ae6fdbb152856edbe3688d95 +16843030,46bd8fadf2f12988d808e69dcfc138cb +16843029,bf398d8ec9fef1d04c67fbf474fda790 +16843028,69ee29bc3bd715b3203d888ca2a88cc0 +16843035,2f79ed9030fe0339dec2eb43f56fa369 +16843034,e2f097a36cdf87a1b211d27eb31dea32 +16843033,c02e9379a6624b40fef669494a7e7183 +16843032,af44f7fe9a4366c67479a44b24ae80b +16843038,501ead1cb03222808aa09b376c9d5cac +16843037,a2d01853631a9b52006ad32497ddc865 +16843036,6e381ac09bfc75ef7f71e02f3b99f279 +16843010,bcfe734d49949142a5073766188213dc +16843011,88ea7e11c57b09139afe92169c443e20 +16843008,91f14375672f1b2003202ec7682771cb +16843009,f5007e4886946d1eb603979a35726d69 +16843014,b0bde3daab8a1cc6354cd86c65db90e2 +16842772,b59c880de07e668eaba0888fc4de229a +16843015,7184233667abf34d2ee3eea20fb9f82b +16842775,bcc06ff4c56de9b4a1557d3c47ec1783 +16842774,6f2eab110a33c15cb17238708244db4d +16843013,3fe45d065187550d481cc745780c29c2 +16843018,7bddb0161d99059f0a6c1c09d0b35b34 +16842777,fdc779803765398f0c782a1fd55a9d86 +16842776,6b6c09ee89a933288c37f55d2187eddd +16843019,87545673867c5cf2f97ea6cc3e0d3595 +16843016,e2288c9f60d09d5f2882175abf161bd +16842779,9667a31366f5dcf740d64b775402c64 +16843017,e3108d8ee8530e50d7b425de217a4585 +16843022,847f1b6f38ebf442a1d34cac0fd6080e +16843023,5d01d19f8441e4d5dd5c41266f480ffc +16842780,b02509b360e6f14eac4fb03f55c11fed +16843020,90e2ab194dab9f482eca64c651ea41e9 +16843021,58d3e73bd29c14b6ec97d4187cee5500 +16843057,bf533b7d78ccc350cfd2f41a8e1f0822 +16842787,e49146643faf3308ca7246d82fc5b2bb +16843056,d8e023c15aa80df2445c782c6b2179da +16843059,c649596d99d96be696332cb08b4a33f2 +16843058,d129fce211dfb56e80195a11f39ab1e9 +16843061,441d86175b74884ef3f672066ae52c90 +16843060,cf6d7dfef99b200a4551cd65467fb9fc +16843063,f50f8b7fafde6d640ced3ec4d797f807 +16843062,d22de0ebc290280b2699b5cb77568fcb +16842794,d347d92a886b9d445d7d60b090a5bcda +16843065,a393477443f20a1a8a511c390024f963 +16843064,e6f28eea0ebbad0d18d23ea3c15f2102 +16843067,d6efe6a63f529d675417c2092546e144 +16842793,d5ac3bcc56cbc370ae3b172dd6ed5df4 +16843066,935aa84de286e8bced6a127b69347997 +16842798,377a21bcb39dcfcb4a0902a7555a984f +16843069,63cc6da6165cc068740827890b4460ed +16843068,6dda3129884399b67b935bb4e51ad34f +16842799,d4831a785c1c65ad2054bb1232babf0c +16842796,48be99a37d3a885d38657a50d6f77365 +16842797,8da03c2f611c7f0654aa71096832b5c +16842802,9b2a96570a99f6677e299d8215b1eecd +16843042,322d7c02f205806126f1529564ab3cd0 +16843043,660acf0ca76261ec49deb7a7bd072f8c +16843044,d8dd28acc9e4431ff8eb481c1d8d9832 +16842806,919bc6715eddf74c0517372ead95cdcb +16843045,72ae59db2ef5c472f671b31f1c6f07ce +16842805,9e359ce06b5603c820bd749592beb4a7 +16843046,cee09c2303e44dfbbaadbf167cdc503c +16842810,8ecd9ec7607c958cdf2e252f516fe3d8 +16843049,47171b2af8bb14c3816f52f79579b46d +16842809,fef5bbbc588422579bf3de8a49c73e18 +16843050,6b29998dbe690122afdf6da71e905009 +16843051,5f9f017aa89719c7a282aa222c65baf +16843052,216a61701714cb3f04e23a74a1336864 +16843053,e146704e3fe30e6821352ceb3b090184 +16842813,899942760d5a83d94cf58a536be6171e +16843054,5aa0a467c7451f88f9c6056e8c7427cc +16843055,6881fc74a0574433e9e0f05f7cae53f7 +16843095,50f6c2ffdc69bea12cd7b58c69824be1 +16842821,42b4814e4e61191b61a8d3f7c6041938 +16843094,356c3f0d5b88d0e2077d85168eac6306 +16842822,d69011621d777519c5ab6a68da8959 +16843092,d84a39f3d30a72b13640e3afb7ea2018 +16843091,37603e187bd7ad9dceccb8ef2b6b5335 +16842817,bad6f1072232c28353aabf42142cbd26 +16842818,bd0c4079c99e529e55abef5ac44dcdf8 +16843088,5e5d08b1780bfd69747216c24b7aee92 +16842819,ae608e1ca5ca083163d92974d7c66b06 +16843103,d4d1b946336039e515c3e4a392694223 +16842828,6a15bcf38bcf78021f9416ac395cac85 +16843102,603020acbbdc6e8765c2e2cd589f7933 +16842829,41cce73f9ce59993afa3517becd4bd3c +16842824,2368ffe803beb1d06772e96eeffd9cc9 +16843099,c373e78822d440c926edf7f1b700d4c5 +16843098,503a4fb49cbfebe1fb71ef185c8ced56 +16843097,4e72dc4d35b34147ce69d691aa2937e3 +16842837,4c903ddf3b9cd49a952a3889fc2c5573 +16842836,a304f875b846d65498366479fbf34568 +16843076,1b11a34d5c6cee280c727938ee96054b +16843077,ff170af78a0a674445f16e24394546c0 +16843074,ba8bd10757ab9a4446f024952bf3f1e3 +16843075,b34ec8f0f5f92acf230925c89eacec65 +16842832,3b10180dc99ab99568b51010d89c655c +16843072,d752bd5dd907feec915d036d76707ee5 +16843073,168e43895b105169862fa2e3c205529b +16842834,58efc828918aa006d5af09e32fe7799b +16843085,b30c099494e63d26f755d58ba109136a +16842841,2c471142bddf9a982a48e0ecb52cbb8 +16843082,5574b9699d71e02f3efb48f3712da8bf +16843080,4945e39d1260ff273c49d39dfc58c2a8 +16842843,bfc9dce4c1ccef959c57360fb9f70205 +16843108,4e225dd49c0231b617a15ded1ba6cb0a +16843109,35715377a038019c56925b2e661cfdab +16843105,3b91182484dc677a0bf27263e612d818 +16843106,affab7221afa03df4b7306b9ce50be7f +16843107,e3710bc197d17e0dc78ae3f607c46048 +16777217,9012132a1d0f770eca67e62a68247137 +16777219,58fc65723143afeb33f742c17e028c94 +16777220,1d5e2088f7137e304366873dd829ca98 +16777221,66a18fa3f554756edc12bf1a08586bc8 +16777222,4007295f7bdae0b78a6e47a9d64521 +16777228,c154160ce7b52d4bdc220fc954edf796 +16777229,2400808c6f442f2663b6869e4930c879 +16777230,7ae3b31e8e0f2f22f50fbf224e1fe4f7 +16777231,fe5698e183b10037e38f979a411489b8 +16777232,aeae00c7b4a95ff05423c1629bf3ad7e +16777233,72153ea3d60930cebf4c0d37fac89102 +16777235,f517ab768fbb35e275440b74b6631bfc +16777236,623df9298630687873579ea16bb97e7b +16777237,6984cb9e6a322728be736860b97b971a +16777238,6947378f4e2abb24b47e2b943945b16f +16777239,55a585682bf0569a60a71a66f031ca2 +16777240,f653295b0c48244dc2aa68fc5b94fa29 +16777241,c213fb7ee968403b24ff6ede98686add +16777243,afd641da6f3834b319b761ba6d72ff74 +16777244,8d822c710a221b8a407b2def97885470 +16777246,9c99187cc6fd9c958417b4736772e4d3 +16777251,6418210d69669c4a602148ed42ab2ecd +16777253,afe51ea56dc8c831f9b0b5ae02bac702 +16777254,95812c1d4021558b6a7f62521228c52a +16777255,3a1252acb6fe968751d2b61d57557e09 +16777257,fd7caeeb5d16756028f19ba016ed1970 +16777258,6339b8043c05d19c6b15135eade95f94 +16777260,aa1ed939a8b275df9dc5474bc0477a33 +16777261,b631dcf219d3add3560f243ff6cceb75 +16777262,91eca0c33ac53fb155feb15db48c43de +16777263,b681c19d7812c281b4b2feabb88697f4 +16777264,a2b07ae4f37a65fe1f5992826b578b02 +16777265,af5255a4dcb486e2ab11669fd3de8441 +16777266,8a4b2b706f219e52a261e342b47a3964 +16777269,921cb54cfb47ca9eca0edcf8e660e3cd +16777270,b79b3a522d1e2f865eb1e9aeb63dc66a +16777272,36e1c1dd8cbb267488e1669811319e7e +16777273,c84a7d710228024c2e100a79a2c30e55 +16777274,a1674e3020689bae5680f29f937e5424 +16777277,46b34dd723f7efeb38f670925ee3824f +16777281,da71e3e4f9a25c6621d2f0b40ffd1c72 +16777282,388109bb9b9b49c1f5bb604abee91671 +16777283,eb6912fd84b2d57ed3433acb3f85d3e6 +16777285,619967351702f1d570d4d0195bbbcc1e +16777286,ebff74d54387fb154d5b467e01d92b64 +16777288,f8154dd7c9c1d397dd64eeb6569d7d34 +16777289,971cc6f827398c6c4755b310c6795672 +16777291,bb952ff9523f248ddaae56317e91a509 +16777293,e5c24577cf35a31bd217d206b88a7499 +16777294,f4c170867c75982e604358da611b26e3 +16777295,922200512d058ecc0ef19a0efcdb51bf +16777296,39283c3dbafb10b2a732f9d6ef3e08b6 +16777297,3603ae881c41c957a89aaa30990c0040 +16777298,fbf9e47600457d091060b0f877458a83 +16777300,2b0d53bafa91c68bf59b5863354bd7ae +16777301,50b99fabae858e971eb02ed5146fd63a +16777302,7a32eac396b4cf3930ba9ca7b5d8dbae +16777303,115f1e956219026bb9cca0bcafb2b11b +16777304,afb2f032a96d859ca5f24d8ff129bd64 +16777305,372b3a0fd7c09f64f3cfcab89f03a9a0 +16777306,e4b6233ac91337dcc3940e309d21c3c +16777311,d290638555ce76ce3053c70fdacf7d55 +5242880,8099ff561e194072c9086dea38757a89 +5242881,90b3d9a90a8cf3e21527fc8fe3b43c49 +5242882,c9806dd45be8ebed3e4ab94f66e65212 +5242883,f382ded5f9a4299e3879dea4f7fe1c50 +5242884,27af08a994f76a2a08ec8671d14fdcc2 +5242885,9969ce4355ae7338470461f48f4e5ef5 +5242886,39208e0b0f070629cad494da5fb95f0d +5242887,678e63329d3d813f22e0f15006a93768 +5242888,694ffe9efa49193780d4b757115c9064 +5242889,9080a51ccefd23f9924bae9a854e7b49 +5242890,5f1d51ccd1b4adf141707907233f8379 +5242891,73df45f45e0b7484ef51441ad0e50604 +5242892,c9e52234c475354483dc3e9e6386af61 +5242893,3c3ee1df989ecf5de70a5673acfa33b8 +5242894,468cc8b546e1586406b78ad733976f5f +5242895,e546a7afaaa6c6729e3b062fc4ace4ae diff --git a/resources/font.txt b/resources/font.txt new file mode 100644 index 0000000..59c1d31 --- /dev/null +++ b/resources/font.txt @@ -0,0 +1,10 @@ +# This file NEEDS to be in UTF-8 format! + !"#$%&'()*+,-./ +0123456789:;<=>? +@ABCDEFGHIJKLMNO +PQRSTUVWXYZ[\]^_ +'abcdefghijklmno +pqrstuvwxyz{|}~⌂ +ÇüéâäàåçêëèïîìÄÅ +ÉæÆôöòûùÿÖÜø£Ø×ƒ +áíóúñѪº¿®¬½¼¡«» \ No newline at end of file diff --git a/resources/lang/en_US.lang b/resources/lang/en_US.lang new file mode 100644 index 0000000..704f1c4 --- /dev/null +++ b/resources/lang/en_US.lang @@ -0,0 +1,579 @@ + +gui.done=Done +gui.cancel=Cancel +gui.toMenu=Back to title screen +gui.up=Up +gui.down=Down +gui.yes=Yes +gui.no=No + +menu.singleplayer=Singleplayer +menu.multiplayer=Multiplayer +menu.mods=Mods and Texture Packs +menu.options=Options... +menu.quit=Quit Game + +selectWorld.title=Select World +selectWorld.empty=empty +selectWorld.world=World +selectWorld.select=Play Selected World +selectWorld.create=Create New World +selectWorld.createDemo=Play New Demo World +selectWorld.delete=Delete +selectWorld.rename=Rename +selectWorld.deleteQuestion=Are you sure you want to delete this world? +selectWorld.deleteWarning=will be lost forever! (A long time!) +selectWorld.deleteButton=Delete +selectWorld.renameButton=Rename +selectWorld.renameTitle=Rename World +selectWorld.conversion=Must be converted! +selectWorld.newWorld=New World +selectWorld.enterName=World Name +selectWorld.resultFolder=Will be saved in: +selectWorld.enterSeed=Seed for the World Generator +selectWorld.seedInfo=Leave blank for a random seed + +multiplayer.title=Play Multiplayer +multiplayer.connect=Connect +multiplayer.info1=Minecraft Multiplayer is currently not finished, but there +multiplayer.info2=is some buggy early testing going on. +multiplayer.ipinfo=Enter the IP of a server to connect to it: + +multiplayer.downloadingTerrain=Downloading terrain + +multiplayer.stopSleeping=Leave Bed + +demo.day.1=This demo will last five game days, do your best! +demo.day.2=Day Two +demo.day.3=Day Three +demo.day.4=Day Four +demo.day.5=This is your last day! +demo.day.warning=Your time is almost up! +demo.day.6=You have passed your fifth day, use F2 to save a screenshot of your creation +demo.reminder=The demo time has expired, buy the game to continue or start a new world! +demo.help.movement=Use %1$s, %2$s, %3$s, %4$s and the mouse to move around +demo.help.jump=Jump by pressing %1$s +demo.help.inventory=Use %1$s to open your inventory + +connect.connecting=Connecting to the server... +connect.authorizing=Logging in... +connect.failed=Failed to connect to the server + +disconnect.genericReason=%s +disconnect.disconnected=Disconnected by Server +disconnect.lost=Connection Lost +disconnect.kicked=Was kicked from the game +disconnect.timeout=Timed out +disconnect.closed=Connection closed +disconnect.loginFailed=Failed to login +disconnect.loginFailedInfo=Failed to login: %s +disconnect.quitting=Quitting +disconnect.endOfStream=End of stream +disconnect.overflow=Buffer overflow + +options.off=OFF +options.on=ON +options.title=Options +options.controls=Controls... +options.video=Video Settings... +options.videoTitle=Video Settings +options.music=Music +options.sound=Sound +options.invertMouse=Invert Mouse +options.sensitivity=Sensitivity +options.sensitivity.min=*yawn* +options.sensitivity.max=HYPERSPEED!!! +options.renderDistance=Render Distance +options.renderDistance.tiny=Tiny +options.renderDistance.short=Short +options.renderDistance.normal=Normal +options.renderDistance.far=Far +options.viewBobbing=View Bobbing +options.ao=Smooth Lighting +options.anaglyph=3D Anaglyph +options.framerateLimit=Performance +options.difficulty=Difficulty +options.difficulty.peaceful=Peaceful +options.difficulty.easy=Easy +options.difficulty.normal=Normal +options.difficulty.hard=Hard +options.graphics=Graphics +options.graphics.fancy=Fancy +options.graphics.fast=Fast +options.guiScale=GUI Scale +options.guiScale.auto=Auto +options.guiScale.small=Small +options.guiScale.normal=Normal +options.guiScale.large=Large +options.advancedOpengl=Advanced OpenGL + +performance.max=Max FPS +performance.balanced=Balanced +performance.powersaver=Power saver + +controls.title=Controls + +key.forward=Forward +key.left=Left +key.back=Back +key.right=Right +key.jump=Jump +key.inventory=Inventory +key.drop=Drop +key.chat=Chat +key.fog=Toggle Fog +key.sneak=Sneak +key.playerlist=List players + +texturePack.openFolder=Open texture pack folder +texturePack.title=Select Texture Pack +texturePack.folderInfo=(Place texture pack files here) + +tile.stone.name=Stone +tile.stone.desc= +tile.grass.name=Grass +tile.grass.desc= +tile.dirt.name=Dirt +tile.dirt.desc= +tile.stonebrick.name=Cobblestone +tile.stonebrick.desc= +tile.wood.name=Wooden Planks +tile.wood.desc= +tile.sapling.name=Sapling +tile.sapling.desc= +tile.bedrock.name=Bedrock +tile.bedrock.desc= +tile.water.name=Water +tile.water.desc= +tile.lava.name=Lava +tile.lava.desc= +tile.sand.name=Sand +tile.sand.desc= +tile.sandStone.name=Sandstone +tile.sand.desc= +tile.gravel.name=Gravel +tile.gravel.desc= +tile.oreGold.name=Gold Ore +tile.oreGold.desc= +tile.oreIron.name=Iron Ore +tile.oreIron.desc= +tile.oreCoal.name=Coal Ore +tile.oreCoal.desc= +tile.log.name=Wood +tile.log.desc= +tile.leaves.name=Leaves +tile.leaves.desc= +tile.sponge.name=Sponge +tile.sponge.desc= +tile.glass.name=Glass +tile.glass.desc= +tile.cloth.name=Wool +tile.cloth.desc= +tile.flower.name=Flower +tile.flower.desc= +tile.rose.name=Rose +tile.rose.desc= +tile.mushroom.name=Mushroom +tile.mushroom.desc= +tile.blockGold.name=Block of Gold +tile.blockGold.desc= +tile.blockIron.name=Block of Iron +tile.blockIron.desc= +tile.stoneSlab.stone.name=Stone Slab +tile.stoneSlab.stone.desc= +tile.stoneSlab.sand.name=Sandstone Slab +tile.stoneSlab.sand.desc= +tile.stoneSlab.wood.name=Wooden Slab +tile.stoneSlab.wood.desc= +tile.stoneSlab.cobble.name=Stone Slab +tile.stoneSlab.cobble.desc= +tile.brick.name=Bricks +tile.brick.desc= +tile.tnt.name=TNT +tile.tnt.desc= +tile.bookshelf.name=Bookshelf +tile.bookshelf.desc= +tile.stoneMoss.name=Moss Stone +tile.stoneMoss.desc= +tile.obsidian.name=Obsidian +tile.obsidian.desc= +tile.torch.name=Torch +tile.torch.desc= +tile.fire.name=Fire +tile.fire.desc= +tile.mobSpawner.name=Monster Spawner +tile.mobSpawner.desc= +tile.stairsWood.name=Wooden Stairs +tile.stairsWood.desc= +tile.chest.name=Chest +tile.chest.desc= +tile.redstoneDust.name=Redstone Dust +tile.redstoneDust.desc= +tile.oreDiamond.name=Diamond Ore +tile.oreDiamond.desc= +tile.blockDiamond.name=Block of Diamond +tile.blockDiamond.desc= +tile.workbench.name=Crafting Table +tile.workbench.desc= +tile.crops.name=Crops +tile.crops.desc= +tile.farmland.name=Farmland +tile.farmland.desc= +tile.furnace.name=Furnace +tile.furnace.desc= +tile.sign.name=Sign +tile.sign.desc= +tile.doorWood.name=Wooden Door +tile.doorWood.desc= +tile.ladder.name=Ladder +tile.ladder.desc= +tile.rail.name=Rail +tile.rail.desc= +tile.goldenRail.name=Powered Rail +tile.goldenRail.desc= +tile.detectorRail.name=Detector Rail +tile.detectorRail.desc= +tile.stairsStone.name=Stone Stairs +tile.stairsStone.desc= +tile.lever.name=Lever +tile.lever.desc= +tile.pressurePlate.name=Pressure Plate +tile.pressurePlate.desc= +tile.doorIron.name=Iron Door +tile.doorIron.desc= +tile.oreRedstone.name=Redstone Ore +tile.oreRedstone.desc= +tile.notGate.name=Redstone Torch +tile.notGate.desc= +tile.button.name=Button +tile.button.desc= +tile.snow.name=Snow +tile.snow.desc= +tile.ice.name=Ice +tile.ice.desc= +tile.cactus.name=Cactus +tile.cactus.desc= +tile.clay.name=Clay +tile.clay.desc= +tile.reeds.name=Sugar cane +tile.reeds.desc= +tile.jukebox.name=Jukebox +tile.jukebox.desc= +tile.fence.name=Fence +tile.fence.desc= +tile.pumpkin.name=Pumpkin +tile.pumpkin.desc= +tile.litpumpkin.name=Jack 'o' Lantern +tile.litpumpkin.desc= +tile.hellrock.name=Netherrack +tile.hellrock.desc= +tile.hellsand.name=Soul Sand +tile.hellsand.desc= +tile.lightgem.name=Glowstone +tile.lightgem.desc= +tile.portal.name=Portal +tile.portal.desc= +tile.cloth.black.name=Black Wool +tile.cloth.black.desc= +tile.cloth.red.name=Red Wool +tile.cloth.red.desc= +tile.cloth.green.name=Green Wool +tile.cloth.green.desc= +tile.cloth.brown.name=Brown Wool +tile.cloth.brown.desc= +tile.cloth.blue.name=Blue Wool +tile.cloth.blue.desc= +tile.cloth.purple.name=Purple Wool +tile.cloth.purple.desc= +tile.cloth.cyan.name=Cyan Wool +tile.cloth.cyan.desc= +tile.cloth.silver.name=Light Gray Wool +tile.cloth.silver.desc= +tile.cloth.gray.name=Gray Wool +tile.cloth.gray.desc= +tile.cloth.pink.name=Pink Wool +tile.cloth.pink.desc= +tile.cloth.lime.name=Lime Wool +tile.cloth.lime.desc= +tile.cloth.yellow.name=Yellow Wool +tile.cloth.yellow.desc= +tile.cloth.lightBlue.name=Light Blue Wool +tile.cloth.lightBlue.desc= +tile.cloth.magenta.name=Magenta Wool +tile.cloth.magenta.desc= +tile.cloth.orange.name=Orange Wool +tile.cloth.orange.desc= +tile.cloth.white.name=Wool +tile.cloth.white.desc= +tile.oreLapis.name=Lapis Lazuli Ore +tile.oreLapis.desc= +tile.blockLapis.name=Lapis Lazuli Block +tile.blockLapis.desc= +tile.dispenser.name=Dispenser +tile.dispenser.desc= +tile.musicBlock.name=Note Block +tile.musicBlock.desc= +tile.cake.name=Cake +tile.cake.desc= +tile.bed.name=Bed +tile.bed.desc= +tile.bed.occupied=This bed is occupied +tile.bed.noSleep=You can only sleep at night +tile.bed.notValid=Your home bed was missing or obstructed +tile.lockedchest.name=Locked chest +tile.lockedchest.desc= +tile.trapdoor.name=Trapdoor +tile.trapdoor.desc= +tile.web.name=Cobweb +tile.web.desc= +tile.stonebricksmooth.name=Stone Bricks +tile.stonebricksmooth.desc= +tile.pistonBase.name=Piston +tile.pistonBase.desc= +tile.pistonStickyBase.name=Sticky Piston +tile.pistonStickyBase.desc= + +item.shovelIron.name=Iron Shovel +item.shovelIron.desc= +item.pickaxeIron.name=Iron Pickaxe +item.pickaxeIron.desc= +item.hatchetIron.name=Iron Axe +item.hatchetIron.desc= +item.flintAndSteel.name=Flint and Steel +item.flintAndSteel.desc= +item.apple.name=Apple +item.apple.desc= +item.cookie.name=Cookie +item.cookie.desc= +item.bow.name=Bow +item.bow.desc= +item.arrow.name=Arrow +item.arrow.desc= +item.coal.name=Coal +item.coal.desc= +item.charcoal.name=Charcoal +item.charcoal.desc= +item.emerald.name=Diamond +item.emerald.desc= +item.ingotIron.name=Iron Ingot +item.ingotIron.desc= +item.ingotGold.name=Gold Ingot +item.ingotGold.desc= +item.swordIron.name=Iron Sword +item.swordIron.desc= +item.swordWood.name=Wooden Sword +item.swordWood.desc= +item.shovelWood.name=Wooden Shovel +item.shovelWood.desc= +item.pickaxeWood.name=Wooden Pickaxe +item.pickaxeWood.desc= +item.hatchetWood.name=Wooden Axe +item.hatchetWood.desc= +item.swordStone.name=Stone Sword +item.swordStone.desc= +item.shovelStone.name=Stone Shovel +item.shovelStone.desc= +item.pickaxeStone.name=Stone Pickaxe +item.pickaxeStone.desc= +item.hatchetStone.name=Stone Axe +item.hatchetStone.desc= +item.swordDiamond.name=Diamond Sword +item.swordDiamond.desc= +item.shovelDiamond.name=Diamond Shovel +item.shovelDiamond.desc= +item.pickaxeDiamond.name=Diamond Pickaxe +item.pickaxeDiamond.desc= +item.hatchetDiamond.name=Diamond Axe +item.hatchetDiamond.desc= +item.stick.name=Stick +item.stick.desc= +item.bowl.name=Bowl +item.bowl.desc= +item.mushroomStew.name=Mushroom Stew +item.mushroomStew.desc= +item.swordGold.name=Golden Sword +item.swordGold.desc= +item.shovelGold.name=Golden Shovel +item.shovelGold.desc= +item.pickaxeGold.name=Golden Pickaxe +item.pickaxeGold.desc= +item.hatchetGold.name=Golden Axe +item.hatchetGold.desc= +item.string.name=String +item.string.desc= +item.feather.name=Feather +item.feather.desc= +item.sulphur.name=Gunpowder +item.sulphur.desc= +item.hoeWood.name=Wooden Hoe +item.hoeWood.desc= +item.hoeStone.name=Stone Hoe +item.hoeStone.desc= +item.hoeIron.name=Iron Hoe +item.hoeIron.desc= +item.hoeDiamond.name=Diamond Hoe +item.hoeDiamond.desc= +item.hoeGold.name=Golden Hoe +item.hoeGold.desc= +item.seeds.name=Seeds +item.seeds.desc= +item.wheat.name=Wheat +item.wheat.desc= +item.bread.name=Bread +item.bread.desc= +item.helmetCloth.name=Leather Cap +item.helmetCloth.desc= +item.chestplateCloth.name=Leather Tunic +item.chestplateCloth.desc= +item.leggingsCloth.name=Leather Pants +item.leggingsCloth.desc= +item.bootsCloth.name=Leather Boots +item.bootsCloth.desc= +item.helmetChain.name=Chain Helmet +item.helmetChain.desc= +item.chestplateChain.name=Chain Chestplate +item.chestplateChain.desc= +item.leggingsChain.name=Chain Leggings +item.leggingsChain.desc= +item.bootsChain.name=Chain Boots +item.bootsChain.desc= +item.helmetIron.name=Iron Helmet +item.helmetIron.desc= +item.chestplateIron.name=Iron Chestplate +item.chestplateIron.desc= +item.leggingsIron.name=Iron Leggings +item.leggingsIron.desc= +item.bootsIron.name=Iron Boots +item.bootsIron.desc= +item.helmetDiamond.name=Diamond Helmet +item.helmetDiamond.desc= +item.chestplateDiamond.name=Diamond Chestplate +item.chestplateDiamond.desc= +item.leggingsDiamond.name=Diamond Leggings +item.leggingsDiamond.desc= +item.bootsDiamond.name=Diamond Boots +item.bootsDiamond.desc= +item.helmetGold.name=Golden Helmet +item.helmetGold.desc= +item.chestplateGold.name=Golden Chestplate +item.chestplateGold.desc= +item.leggingsGold.name=Golden Leggings +item.leggingsGold.desc= +item.bootsGold.name=Golden boots +item.bootsGold.desc= +item.flint.name=Flint +item.flint.desc= +item.porkchopRaw.name=Raw Porkchop +item.porkchopRaw.desc= +item.porkchopCooked.name=Cooked Porkchop +item.porkchopCooked.desc= +item.painting.name=Painting +item.painting.desc= +item.appleGold.name=Golden Apple +item.appleGold.desc= +item.sign.name=Sign +item.sign.desc= +item.doorWood.name=Wooden Door +item.doorWood.desc= +item.bucket.name=Bucket +item.bucket.desc= +item.bucketWater.name=Water Bucket +item.bucketWater.desc= +item.bucketLava.name=Lava bucket +item.bucketLava.desc= +item.minecart.name=Minecart +item.minecart.desc= +item.saddle.name=Saddle +item.saddle.desc= +item.doorIron.name=Iron Door +item.doorIron.desc= +item.redstone.name=Redstone +item.redstone.desc= +item.snowball.name=Snowball +item.snowball.desc= +item.boat.name=Boat +item.boat.desc= +item.leather.name=Leather +item.leather.desc= +item.milk.name=Milk +item.milk.desc= +item.brick.name=Brick +item.brick.desc= +item.clay.name=Clay +item.clay.desc= +item.reeds.name=Sugar Canes +item.reeds.desc= +item.paper.name=Paper +item.paper.desc= +item.book.name=Book +item.book.desc= +item.slimeball.name=Slimeball +item.slimeball.desc= +item.minecartChest.name=Minecart with Chest +item.minecartChest.desc= +item.minecartFurnace.name=Minecart with Furnace +item.minecartFurnace.desc= +item.egg.name=Egg +item.egg.desc= +item.compass.name=Compass +item.compass.desc= +item.fishingRod.name=Fishing Rod +item.fishingRod.desc= +item.clock.name=Clock +item.clock.desc= +item.yellowDust.name=Glowstone Dust +item.yellowDust.desc= +item.fishRaw.name=Raw Fish +item.fishRaw.desc= +item.fishCooked.name=Cooked Fish +item.fishCooked.desc= +item.record.name=Music Disc +item.record.desc= +item.bone.name=Bone +item.bone.desc= +item.dyePowder.black.name=Ink Sac +item.dyePowder.black.desc= +item.dyePowder.red.name=Rose Red +item.dyePowder.red.desc= +item.dyePowder.green.name=Cactus Green +item.dyePowder.green.desc= +item.dyePowder.brown.name=Cocoa Beans +item.dyePowder.brown.desc= +item.dyePowder.blue.name=Lapis Lazuli +item.dyePowder.blue.desc= +item.dyePowder.purple.name=Purple Dye +item.dyePowder.purple.desc= +item.dyePowder.cyan.name=Cyan Dye +item.dyePowder.cyan.desc= +item.dyePowder.silver.name=Light Gray Dye +item.dyePowder.silver.desc= +item.dyePowder.gray.name=Gray Dye +item.dyePowder.gray.desc= +item.dyePowder.pink.name=Pink Dye +item.dyePowder.pink.desc= +item.dyePowder.lime.name=Lime Dye +item.dyePowder.lime.desc= +item.dyePowder.yellow.name=Dandelion Yellow +item.dyePowder.yellow.desc= +item.dyePowder.lightBlue.name=Light Blue Dye +item.dyePowder.lightBlue.desc= +item.dyePowder.magenta.name=Magenta Dye +item.dyePowder.magenta.desc= +item.dyePowder.orange.name=Orange Dye +item.dyePowder.orange.desc= +item.dyePowder.white.name=Bone Meal +item.dyePowder.white.desc= +item.sugar.name=Sugar +item.sugar.desc= +item.cake.name=Cake +item.cake.desc= +item.bed.name=Bed +item.bed.desc= +item.diode.name=Redstone Repeater +item.diode.desc= +item.map.name=Map +item.map.desc= +item.leaves.name=Leaves +item.leaves.desc= +item.shears.name=Shears +item.shears.desc= diff --git a/resources/lang/stats_US.lang b/resources/lang/stats_US.lang new file mode 100644 index 0000000..caba23a --- /dev/null +++ b/resources/lang/stats_US.lang @@ -0,0 +1,81 @@ +gui.achievements=Achievements +gui.stats=Statistics + +stat.generalButton=General +stat.blocksButton=Blocks +stat.itemsButton=Items + +stat.used=Times Used +stat.mined=Times Mined +stat.depleted=Times Depleted +stat.crafted=Times Crafted + +stat.startGame=Times played +stat.createWorld=Worlds played +stat.loadWorld=Saves loaded +stat.joinMultiplayer=Multiplayer joins +stat.leaveGame=Games quit + +stat.playOneMinute=Minutes Played + +stat.walkOneCm=Distance Walked +stat.fallOneCm=Distance Fallen +stat.swimOneCm=Distance Swum +stat.flyOneCm=Distance Flown +stat.climbOneCm=Distance Climbed +stat.diveOneCm=Distance Dove +stat.minecartOneCm=Distance by Minecart +stat.boatOneCm=Distance by Boat +stat.pigOneCm=Distance by Pig +stat.jump=Jumps +stat.drop=Items Dropped + +stat.damageDealt=Damage Dealt +stat.damageTaken=Damage Taken +stat.deaths=Number of Deaths +stat.mobKills=Mob Kills +stat.playerKills=Player Kills +stat.fishCaught=Fish Caught + +stat.mineBlock=%1$s Mined +stat.craftItem=%1$s Crafted +stat.useItem=%1$s Used +stat.breakItem=%1$s Depleted + +achievement.get=Achievement get! + +achievement.taken=Taken! + +achievement.requires=Requires '%1$s' +achievement.openInventory=Taking Inventory +achievement.openInventory.desc=Press '%1$s' to open your inventory. +achievement.mineWood=Getting Wood +achievement.mineWood.desc=Attack a tree until a block of wood pops out +achievement.buildWorkBench=Benchmarking +achievement.buildWorkBench.desc=Craft a workbench with four blocks of planks +achievement.buildPickaxe=Time to Mine! +achievement.buildPickaxe.desc=Use planks and sticks to make a pickaxe +achievement.buildFurnace=Hot Topic +achievement.buildFurnace.desc=Construct a furnace out of eight stone blocks +achievement.acquireIron=Acquire Hardware +achievement.acquireIron.desc=Smelt an iron ingot +achievement.buildHoe=Time to Farm! +achievement.buildHoe.desc=Use planks and sticks to make a hoe +achievement.makeBread=Bake Bread +achievement.makeBread.desc=Turn wheat into bread +achievement.bakeCake=The Lie +achievement.bakeCake.desc=Wheat, sugar, milk and eggs! +achievement.buildBetterPickaxe=Getting an Upgrade +achievement.buildBetterPickaxe.desc=Construct a better pickaxe +achievement.cookFish=Delicious Fish +achievement.cookFish.desc=Catch and cook fish! +achievement.onARail=On A Rail +achievement.onARail.desc=Travel by minecart at least 1 km from where you started +achievement.buildSword=Time to Strike! +achievement.buildSword.desc=Use planks and sticks to make a sword +achievement.killEnemy=Monster Hunter +achievement.killEnemy.desc=Attack and destroy a monster +achievement.killCow=Cow Tipper +achievement.killCow.desc=Harvest some leather +achievement.flyPig=When Pigs Fly +achievement.flyPig.desc=Fly a pig off a cliff diff --git a/resources/null b/resources/null new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/com/legacyminecraft/poseidon/PluginLoadPlanner.java b/src/main/java/com/legacyminecraft/poseidon/PluginLoadPlanner.java new file mode 100644 index 0000000..5bf900f --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/PluginLoadPlanner.java @@ -0,0 +1,285 @@ +package com.legacyminecraft.poseidon; + +import org.bukkit.Server; +import org.bukkit.plugin.InvalidDescriptionException; +import org.bukkit.plugin.InvalidPluginException; +import org.bukkit.plugin.PluginDescriptionFile; +import org.yaml.snakeyaml.error.YAMLException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class PluginLoadPlanner { + private final Server server; + private final Set fileFilters; + private final File updateDirectory; + + public PluginLoadPlanner(Server server, Set fileFilters, File updateDirectory) { + this.server = server; + this.fileFilters = fileFilters; + this.updateDirectory = updateDirectory; + } + + // Generate a load order for plugins in a given directory based on dependencies. + public List plan(File directory, File[] files) { + if (files == null || files.length == 0) { + return Collections.emptyList(); + } + + // Normalize filesystem enumeration so plugin order is not platform-dependent. + // Issue identified by RobertWesner + Arrays.sort(files, (left, right) -> left.getName().compareToIgnoreCase(right.getName())); + + // Index plugin metadata up front so dependency decisions can be made before any plugin code runs. + LinkedHashMap candidates = new LinkedHashMap<>(); + + // Loop through files in the directory and parse plugin descriptions, skipping duplicates and invalid plugins. + //TODO: We should figure out how we want to handle dupe plugins in Poseidon in the future. No reason exists for them and they just cause hard to trobleshoot issues + for (File file : files) { + PluginCandidate candidate = createCandidate(file); + if (candidate == null) { + continue; + } + + PluginCandidate existing = candidates.get(candidate.name); + if (existing != null) { + server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': duplicate plugin name '" + candidate.name + "' also found in '" + existing.file.getPath() + "'"); + continue; + } + + candidates.put(candidate.name, candidate); + } + + List plan = new ArrayList<>(); + + + // Create a deterministic load order + Set loadedNames = new LinkedHashSet<>(); + LinkedHashSet remaining = new LinkedHashSet<>(candidates.values()); + + // Iterate until no plugins remain or no progress can be made due to missing or circular dependencies. + while (!remaining.isEmpty()) { + List ready = new ArrayList<>(); + + // First try to satisfy both hard dependencies + for (PluginCandidate candidate : remaining) { + if (hasMissingHardDependencies(candidate, candidates)) { + continue; + } + + // Prefer loading after both hard and present soft dependencies when the graph allows it. + if (dependenciesLoaded(candidate.getHardDependencies(), loadedNames) + && dependenciesLoaded(candidate.getPresentSoftDependencies(candidates), loadedNames)) { + ready.add(candidate); + } + } + + // If no plugin can satisfy every soft dependency, fall back to hard-dependency order. + boolean relaxedSoftDependencies = false; + if (ready.isEmpty()) { + for (PluginCandidate candidate : remaining) { + if (hasMissingHardDependencies(candidate, candidates)) { + continue; + } + + // This preserves startup progress when soft dependencies form cycles or long chains. + if (dependenciesLoaded(candidate.getHardDependencies(), loadedNames)) { + ready.add(candidate); + } + } + relaxedSoftDependencies = !ready.isEmpty(); + } + + if (ready.isEmpty()) { + // Anything left here either references a missing hard dependency or is part of a cycle. + break; + } + + // Sort deterministically to ensure a stable load order + Collections.sort(ready, (left, right) -> { + int loadOrder = left.description.getLoad().compareTo(right.description.getLoad()); + if (loadOrder != 0) { + return loadOrder; + } + + int nameOrder = left.name.compareToIgnoreCase(right.name); + if (nameOrder != 0) { + return nameOrder; + } + + return left.file.getName().compareToIgnoreCase(right.file.getName()); + }); + + for (PluginCandidate candidate : ready) { + // Tell the legacy loader to ignore soft dependencies only when the planner already relaxed them. + boolean ignoreSoftDependencies = relaxedSoftDependencies || candidate.hasMissingSoftDependencies(candidates); + plan.add(new PlannedPlugin(candidate.file, candidate.name, ignoreSoftDependencies)); + loadedNames.add(candidate.name); + remaining.remove(candidate); + } + } + + // Print errors + for (PluginCandidate candidate : remaining) { + // If the candidate has missing hard dependencies, report them. Otherwise, report a circular or unresolved dependency chain. + if (hasMissingHardDependencies(candidate, candidates)) { + for (String dependency : candidate.getMissingHardDependencies(candidates)) { + server.getLogger().log(Level.SEVERE, "Could not load '" + candidate.file.getPath() + "' in folder '" + directory.getPath() + "': Unknown dependency " + dependency); + } + } else { + server.getLogger().log(Level.SEVERE, "Could not load '" + candidate.file.getPath() + "' in folder '" + directory.getPath() + "': circular or unresolved dependency chain"); + } + } + + return plan; + } + + private PluginCandidate createCandidate(File file) { + PluginDescriptionFile description; + + try { + description = getPluginDescription(file); + } catch (InvalidPluginException | InvalidDescriptionException ex) { + server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "'.", ex); + return null; + } + + if (description == null) { + // Non-plugin files in the directory are ignored by the registered file filters. + return null; + } + + return new PluginCandidate(file, description); + } + + private PluginDescriptionFile getPluginDescription(File file) throws InvalidPluginException, InvalidDescriptionException { + // Read plugin.yml first so ordering can be computed without instantiating plugin classes. + File descriptionSource = getEffectivePluginFile(file); // If plugin has an update, read description from the update file instead as it might have new dependencies. + + for (Pattern filter : fileFilters) { + Matcher match = filter.matcher(descriptionSource.getName()); + if (!match.find()) { + continue; + } + + try (JarFile jar = new JarFile(descriptionSource)) { + JarEntry entry = jar.getJarEntry("plugin.yml"); + + if (entry == null) { + throw new InvalidPluginException(new IOException("Jar does not contain plugin.yml")); + } + + try (InputStream stream = jar.getInputStream(entry)) { + return new PluginDescriptionFile(stream); + } + } catch (IOException ex) { + throw new InvalidPluginException(ex); + } catch (YAMLException ex) { + throw new InvalidPluginException(ex); + } + } + + return null; + } + + private File getEffectivePluginFile(File file) { + if (updateDirectory == null || !updateDirectory.isDirectory()) { + return file; + } + + File updateFile = new File(updateDirectory, file.getName()); + if (updateFile.isFile()) { + // Return the update file instead for processing + return updateFile; + } + + return file; + } + + private boolean hasMissingHardDependencies(PluginCandidate candidate, Map candidates) { + return !candidate.getMissingHardDependencies(candidates).isEmpty(); + } + + private boolean dependenciesLoaded(Collection dependencies, Set loadedNames) { + for (String dependency : dependencies) { + if (!loadedNames.contains(dependency)) { + return false; + } + } + + return true; + } + + public static final class PlannedPlugin { + public final File file; + public final String name; + public final boolean ignoreSoftDependencies; + + PlannedPlugin(File file, String name, boolean ignoreSoftDependencies) { + this.file = file; + this.name = name; + this.ignoreSoftDependencies = ignoreSoftDependencies; + } + } + + private static final class PluginCandidate { + private final File file; + private final PluginDescriptionFile description; + private final String name; + private final List hardDependencies; + private final List softDependencies; + + private PluginCandidate(File file, PluginDescriptionFile description) { + this.file = file; + this.description = description; + this.name = description.getName(); + this.hardDependencies = copyDependencies(description.getDepend()); + this.softDependencies = copyDependencies(description.getSoftDepend()); + } + + private List getHardDependencies() { + return hardDependencies; + } + + private List getMissingHardDependencies(Map candidates) { + List missing = new ArrayList<>(); + for (String dependency : hardDependencies) { + if (!candidates.containsKey(dependency)) { + missing.add(dependency); + } + } + return missing; + } + + private List getPresentSoftDependencies(Map candidates) { + List present = new ArrayList<>(); + for (String dependency : softDependencies) { + if (candidates.containsKey(dependency)) { + present.add(dependency); + } + } + return present; + } + + private boolean hasMissingSoftDependencies(Map candidates) { + // Missing soft dependencies should not block load, but present ones still influence ordering. + return getPresentSoftDependencies(candidates).size() != softDependencies.size(); + } + + @SuppressWarnings("unchecked") + private static List copyDependencies(Object dependencies) { + if (dependencies == null) { + return Collections.emptyList(); + } + + return new ArrayList<>((Collection) dependencies); + } + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/Poseidon.java b/src/main/java/com/legacyminecraft/poseidon/Poseidon.java new file mode 100644 index 0000000..5887a8c --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/Poseidon.java @@ -0,0 +1,35 @@ +package com.legacyminecraft.poseidon; + +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.craftbukkit.CraftServer; + +import java.util.LinkedList; + +public final class Poseidon { + private static PoseidonServer server; + + /** + * Returns a list of the server's TPS (Ticks Per Second) records for performance monitoring. + * The list contains Double values indicating the TPS at each second, ordered from most recent to oldest. + * + * @return LinkedList of TPS records. + */ + public static LinkedList getTpsRecords() { + return ((CraftServer) Bukkit.getServer()).getServer().getTpsRecords(); + } + + public static PoseidonServer getServer() { + return server; + } + + public static void setServer(PoseidonServer server) { + if (Poseidon.server != null) { + throw new UnsupportedOperationException("Cannot redefine singleton Server"); + } + + Poseidon.server = server; + } + + +} diff --git a/src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java b/src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java new file mode 100644 index 0000000..0e81018 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java @@ -0,0 +1,395 @@ +package com.legacyminecraft.poseidon; + +import org.bukkit.util.config.Configuration; + +import java.io.File; +import java.util.Arrays; +import java.util.UUID; +import java.util.regex.Pattern; + +public class PoseidonConfig extends Configuration { + private static PoseidonConfig singleton; + private final int configVersion = 5; + private Integer[] treeBlacklistIDs; + + public Integer[] getTreeBlacklistIDs() { + return treeBlacklistIDs; + } + + private PoseidonConfig() { + super(new File("poseidon.yml")); + this.reload(); + } + + public void reload() { + this.load(); + this.write(); + this.validation(); + this.save(); + } + + public void resetConfig() { + // Delete all the config options + for (String key : this.getKeys()) { + this.removeProperty(key); + } + // Reload the config + this.write(); + } + + private void validation() { + //Confirm settings.uuid-fetcher.method.value is either POST or GET + if (!this.getConfigString("settings.uuid-fetcher.method.value").equalsIgnoreCase("POST") && !this.getConfigString("settings.uuid-fetcher.method.value").equalsIgnoreCase("GET")) { + System.out.println("[Poseidon] Config: settings.uuid-fetcher.method.value is not POST or GET. Changing to POST."); + this.setProperty("settings.uuid-fetcher.method.value", "POST"); + } + } + + private void write() { + if (this.getString("config-version") == null || Integer.valueOf(this.getString("config-version")) < configVersion) { + System.out.println("[Poseidon] Converting from config version " + (this.getString("config-version") == null ? "0" : this.getString("config-version")) + " to " + configVersion); + convertToNewConfig(); + this.setProperty("config-version", configVersion); + } + //Main + generateConfigOption("config-version", configVersion); + //Setting +// generateConfigOption("settings.allow-graceful-uuids", true); + generateConfigOption("settings.delete-duplicate-uuids", false); + generateConfigOption("settings.save-playerdata-by-uuid", true); + // Log management and rotation + generateConfigOption("settings.per-day-log-file.info", "This setting causes the server to create a new log file each day. This is useful for log rotation and log file management."); + generateConfigOption("settings.per-day-log-file.enabled", false); + generateConfigOption("settings.per-day-log-file.latest-log.info", "This setting causes the server to create a latest.log similar to modern Minecraft servers. This can be useful for certain control panels and log file management."); + generateConfigOption("settings.per-day-log-file.latest-log.enabled", true); + + //generateConfigOption("settings.fetch-uuids-from", "https://api.mojang.com/profiles/minecraft"); + + // UUID Fetcher Settings + generateConfigOption("settings.uuid-fetcher.post.info", "This setting allows you to change the URL that the server fetches UUIDs from. This is useful if you have a custom UUID server or a proxy server that fetches UUIDs."); + generateConfigOption("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname"); + + generateConfigOption("settings.uuid-fetcher.get.info", "This setting allows you to change the URL that the server fetches UUIDs from. This is useful if you have a custom UUID server or a proxy server that fetches UUIDs."); + generateConfigOption("settings.uuid-fetcher.get.value", "https://api.minecraftservices.com/minecraft/profile/lookup/name/{username}"); + generateConfigOption("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled", true); + generateConfigOption("settings.uuid-fetcher.get.enforce-case-sensitivity.info", "The Mojang API is case-insensitive by default meaning usernames with different casing will return the same UUID. This setting checks the case of the username to prevent this issue. If the name is invalid, the player will be kicked."); + + + generateConfigOption("settings.uuid-fetcher.method.value", "POST"); + generateConfigOption("settings.uuid-fetcher.method.info", "This setting allows for POST or GET method for fetching UUIDs. This is useful if you have a custom UUID server, Mojang API is down, or a proxy server that fetches UUIDs."); + + generateConfigOption("settings.uuid-fetcher.allow-graceful-uuids.value", true); + generateConfigOption("settings.uuid-fetcher.allow-graceful-uuids.info", "This setting means offline UUIDs are generated for players who don't have a Mojang UUID. This is useful for cracked or semi-cracked servers."); + + generateConfigOption("settings.uuid-fetcher.always-use-graceful-uuids.enabled", false); + generateConfigOption("settings.uuid-fetcher.always-use-graceful-uuids.info", "Will always use offline UUIDs. Useful if you need the server to run completely offline."); + + // Setting to automatically add a . prefix to cracked account usernames + generateConfigOption("settings.cracked-username-prefix.enabled", false); + generateConfigOption("settings.cracked-username-prefix.info", "This setting automatically adds a . prefix to cracked account usernames to prevent username conflicts with premium accounts."); + + generateConfigOption("settings.remove-join-leave-debug", true); + generateConfigOption("settings.enable-tpc-nodelay", false); + + //generateConfigOption("settings.use-get-for-uuids.enabled", true); + //generateConfigOption("settings.use-get-for-uuids.info", "This setting causes the server to use the GET method for Username to UUID conversion. This is useful incase the POST method goes offline."); + + //generateConfigOption("settings.use-get-for-uuids.case-sensitive.enabled", true); + //generateConfigOption("settings.use-get-for-uuids.case-sensitive.info", "This setting will verify sensitivity of the username as the GET method is case-insensitive."); + + generateConfigOption("settings.faster-packets.enabled", true); + generateConfigOption("settings.faster-packets.info", "This setting increases the speed of packets, a fix from newer Minecraft versions."); + + generateConfigOption("settings.fix-drowning-push-down.enabled", true); + generateConfigOption("settings.fix-drowning-push-down.info", "This setting fixes taking drowning damage pushing you down."); + + generateConfigOption("settings.player-knockback-fix.enabled", true); + generateConfigOption("settings.player-knockback-fix.info", "This setting fixes reduced knockback for certain players on the server."); + + //Watchdog + //generateConfigOption("settings.enable-watchdog", true); + generateConfigOption("settings.watchdog.info", "Watchdog is a automatic hang detection system which can print stacktraces and kill the server automatically after a predefined interval."); + generateConfigOption("settings.watchdog.enable", true); + generateConfigOption("settings.watchdog.timeout.value", 120); + generateConfigOption("settings.watchdog.timeout.info", "The number of seconds to kill the server process after no ticks occurring."); + generateConfigOption("settings.watchdog.debug-timeout.enabled", false); + generateConfigOption("settings.watchdog.debug-timeout.value", 30); + generateConfigOption("settings.watchdog.debug-timeout.info", "debug-timeout can be used to print a stack trace at a lower interval then the main timeout allowing admins to locate blocking tasks that cause hangs over a certain duration. Only enable this if you have experienced temporary hangs/server freezes."); + + // Performance Monitoring + generateConfigOption("settings.performance-monitoring.listener-reporting.info", "This setting will cause the server to record listener execution times."); + generateConfigOption("settings.performance-monitoring.listener-reporting.enabled", true); + generateConfigOption("settings.performance-monitoring.listener-reporting.print-statistics-on-shutdown.info", "Prints the listener statistics to the console on server shutdown."); + generateConfigOption("settings.performance-monitoring.listener-reporting.print-statistics-on-shutdown.enabled", false); + generateConfigOption("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.info", "Print to console when a listener takes longer than the specified time in milliseconds. It isn't recommended to set this any lower then 10ms to prevent console spam."); + generateConfigOption("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.enabled", true); + generateConfigOption("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.value", 100); // Default to two Minecraft tick + + generateConfigOption("settings.performance-monitoring.task-reporting.info", "This setting will cause the server to record synchronous task execution times."); + generateConfigOption("settings.performance-monitoring.task-reporting.enabled", true); + generateConfigOption("settings.performance-monitoring.task-reporting.print-statistics-on-shutdown.info", "Prints the task statistics to the console on server shutdown."); + generateConfigOption("settings.performance-monitoring.task-reporting.print-statistics-on-shutdown.enabled", false); + generateConfigOption("settings.performance-monitoring.task-reporting.print-on-slow-tasks.info", "Print to console when a task takes longer than the specified time in milliseconds. It isn't recommended to set this any lower then 10ms to prevent console spam."); + generateConfigOption("settings.performance-monitoring.task-reporting.print-on-slow-tasks.enabled", true); + generateConfigOption("settings.performance-monitoring.task-reporting.print-on-slow-tasks.value", 100); // Default to two Minecraft tick + + //Packet Events + generateConfigOption("settings.packet-events.enabled", false); + generateConfigOption("settings.packet-events.info", "This setting causes the server to fire a Bukkit event for each packet received and sent to a player once they have finished the initial login process. This only needs to be enabled if you have a plugin that uses this specific feature."); +// generateConfigOption("settings.bukkit-event.disabled-plugin-unregister.value", true); +// generateConfigOption("settings.bukkit-event.disabled-plugin-unregister.info", "This setting will automatically unregister listeners from disabled plugins. This is useful if you have a plugin that can get disabled at runtime and you want to prevent errors to the disabled plugin."); + generateConfigOption("settings.packet-spam-detection.enabled", true); + generateConfigOption("settings.packet-spam-detection.info", "This setting causes the server to detect and kick malicious players who send too many packets in a short period of time. This is useful to prevent players from sending too many packets to the server to cause lag."); + generateConfigOption("settings.packet-spam-detection.threshold", 10000); + + //Statistics + generateConfigOption("settings.statistics.key", UUID.randomUUID().toString()); + generateConfigOption("settings.statistics.enabled", true); + + //World Settings + generateConfigOption("world-settings.optimized-explosions", false); + generateConfigOption("world-settings.send-explosion-velocity", true); + generateConfigOption("world-settings.randomize-spawn", true); + generateConfigOption("world-settings.teleport-to-highest-safe-block", true); + generateConfigOption("world-settings.use-modern-fence-bounding-boxes", false); + //TODO: Actually implement the tree growth functionality stuff + generateConfigOption("world.settings.block-tree-growth.enabled", true); + generateConfigOption("world.settings.block-tree-growth.list", "54,63,68"); + generateConfigOption("world.settings.block-tree-growth.info", "This setting allows for server owners to easily block trees growing from automatically destroying certain blocks. The list must be a string with numerical item ids separated by commas."); + generateConfigOption("world.settings.block-pistons-pushing-furnaces.info", "This workaround prevents pistons from pushing furnaces which prevents a malicious server crash."); + generateConfigOption("world.settings.block-pistons-pushing-furnaces.enabled", true); + generateConfigOption("world.settings.pistons.transmutation-fix.enabled", true); + generateConfigOption("world.settings.pistons.transmutation-fix.info", "This setting fixes block transmutation exploits."); + generateConfigOption("world.settings.pistons.sand-gravel-duping-fix.enabled", true); + generateConfigOption("world.settings.pistons.sand-gravel-duping-fix.info", "This setting fixes sand/gravel duplication exploits."); + generateConfigOption("world.settings.pistons.other-fixes.enabled", true); + generateConfigOption("world.settings.pistons.other-fixes.info", "This setting fixes various other piston exploits like creating illegal pistons, breaking bedrock and duplicating redstone torches."); + generateConfigOption("world.settings.skeleton-shooting-sound-fix.info", "This setting fixes the sound of skeletons and players shooting not playing on clients."); + generateConfigOption("world.settings.skeleton-shooting-sound-fix.enabled", true); + generateConfigOption("world.settings.speed-hack-check.enable", true); + generateConfigOption("world.settings.speed-hack-check.teleport", true); + generateConfigOption("world.settings.speed-hack-check.distance", 100.0D); + generateConfigOption("world.settings.speed-hack-check.info", "This setting allows you to configure the automatic speedhack detection."); + generateConfigOption("world.settings.flowing-lava-fix.enabled", true); + generateConfigOption("world.settings.flowing-lava-fix.info", "This setting fixes flowing lava not disappearing when the source block is removed."); + //Mob Spawner Area Limit (8 chunks) + generateConfigOption("world.settings.mob-spawner-area-limit.enable", true); + generateConfigOption("world.settings.mob-spawner-area-limit.limit", 150); + generateConfigOption("world.settings.mob-spawner-area-limit.chunk-radius", 8); + generateConfigOption("world.settings.mob-spawner-area-limit.info", + "This setting controls the maximum number of entities of a mob spawner type that can exist within the defined chunk radius around a mob spawner. If the number of entities exceeds this limit, the spawner will stop spawning additional entities of that type. This is useful to stop the extreme lag that can be caused by mob spawners."); + + + //generateConfigOption("world-settings.eject-from-vehicle-on-teleport.enabled", true); + //generateConfigOption("world-settings.eject-from-vehicle-on-teleport.info", "Eject the player from a boat or minecart before teleporting them preventing cross world coordinate exploits."); + + //Release2Beta Settings + generateConfigOption("settings.release2beta.enable-ip-pass-through", false); + generateConfigOption("settings.release2beta.proxy-ip", "127.0.0.1"); + + //BungeeCord + generateConfigOption("settings.bungeecord.bungee-mode.enable", false); + generateConfigOption("settings.bungeecord.bungee-mode.kick-message", "You must connect through BungeeCord to join this server!"); + generateConfigOption("settings.bungeecord.bungee-mode.info", "Only allows connections via BungeeCord to join. Includes optional custom kick message for players not using BungeeCord."); + + //Modded Jar Support + generateConfigOption("settings.support.modloader.enable", false); + generateConfigOption("settings.support.modloader.info", "EXPERIMENTAL support for ModloaderMP."); + + //Offline Username Check + generateConfigOption("settings.check-username-validity.enabled", true); + generateConfigOption("settings.check-username-validity.info", "If enabled, verifies the validity of a usernames of cracked players."); + generateConfigOption("settings.check-username-validity.regex", "[a-zA-Z0-9_.]*"); + generateConfigOption("settings.check-username-validity.max-length", 16); + generateConfigOption("settings.check-username-validity.min-length", 3); + generateConfigOption("emergency.debug.regenerate-corrupt-chunks.enable", false); + generateConfigOption("emergency.debug.regenerate-corrupt-chunks.info", "This setting allows you to automatically regenerate corrupt chunks. This is useful after a ungraceful shutdown while a file is being written to or out of memory exception."); + + generateConfigOption("settings.update-checker.enabled", true); + generateConfigOption("settings.update-checker.info", "This setting allows you to disable the update checker. This is useful if you have a custom build of Poseidon or don't want to be notified of updates."); + generateConfigOption("settings.update-checker.notify-staff.enabled", true); + generateConfigOption("settings.update-checker.notify-staff.info", "This setting notifies operators and players with the permission poseidon.update when a new version of Poseidon is available on join."); + generateConfigOption("settings.update-checker.notify-if-up-to-date.enabled", false); + generateConfigOption("settings.update-checker.notify-if-up-to-date.info", "This setting controls if the update checker will print a message in console if the server is up to date."); + generateConfigOption("settings.update-checker.interval.ticks", 20 * 60 * 60); + generateConfigOption("settings.update-checker.interval.info", "Controls how often the update checker will query the latest Poseidon version"); + + //Messages + generateConfigOption("message.kick.banned", "You are banned from this server!"); + generateConfigOption("message.kick.ip-banned", "Your IP address is banned from this server!"); + generateConfigOption("message.kick.not-whitelisted", "You are not white-listed on this server!"); + generateConfigOption("message.kick.full", "The server is full!"); + generateConfigOption("message.kick.shutdown", "\u00A7cServer is shutting down, please rejoin later."); + generateConfigOption("message.kick.already-online", "\u00A7cA player with your username or uuid is already online, try reconnecting in a minute."); + generateConfigOption("message.player.join", "\u00A7e%player% joined the game."); + generateConfigOption("message.player.leave", "\u00A7e%player% left the game."); + generateConfigOption("message.update.available", "\u00A7dA newer version of Poseidon is available: %newversion%"); + + //Optional Poseidon Commands + generateConfigOption("command.info", "This section allows you to enable or disable optional Poseidon commands. This is useful if you have a plugin that conflicts with a Poseidon command."); + generateConfigOption("command.tps.info", "Enables the /tps command to show the server's TPS for various intervals."); + generateConfigOption("command.tps.enabled", true); + + //UberBukkit + generateConfigOption("fix.optimize-sponges.enabled", true); + generateConfigOption("fix.optimize-sponges.info", "Optimizes sponges by removing unnecessary block updates. This can also prevent some block duplication methods."); + + //Tree Leave Destroy Blacklist + if (Boolean.valueOf(String.valueOf(getConfigOption("world.settings.block-tree-growth.enabled", true)))) { + if (String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().isEmpty()) { + //Empty Blacklist + } else { + String[] rawBlacklist = String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().split(","); + int blackListCount = 0; + for (String stringID : rawBlacklist) { + if (Pattern.compile("-?[0-9]+").matcher(stringID).matches()) { + blackListCount = blackListCount + 1; + } else { + System.out.println("The ID " + stringID + " for leaf decay blocker has been detected as invalid, and won't be used."); + } + } + //Loop a second time to get correct array length. I know this is horrible code, but it works and only runs on server startup. + treeBlacklistIDs = new Integer[blackListCount]; + int i = 0; + for (String stringID : rawBlacklist) { + if (Pattern.compile("-?[0-9]+").matcher(stringID).matches()) { + treeBlacklistIDs[i] = Integer.valueOf(stringID); + i = i + 1; + } + } + System.out.println("Leaf blocks can't replace the following block IDs: " + Arrays.toString(treeBlacklistIDs)); + } + } else { + treeBlacklistIDs = new Integer[0]; + } + } + + + private void generateConfigOption(String key, Object defaultValue) { + if (this.getProperty(key) == null) { + this.setProperty(key, defaultValue); + } + final Object value = this.getProperty(key); + this.removeProperty(key); + this.setProperty(key, value); + } + + //Getters Start + public Object getConfigOption(String key) { + return this.getProperty(key); + } + + public Object getConfigOption(String key, Object defaultValue) { + Object value = getConfigOption(key); + if (value == null) { + value = defaultValue; + } + return value; + + } + + public String getConfigString(String key) { + return String.valueOf(getConfigOption(key)); + } + + public Integer getConfigInteger(String key) { + return Integer.valueOf(getConfigString(key)); + } + + public Long getConfigLong(String key) { + return Long.valueOf(getConfigString(key)); + } + + public Double getConfigDouble(String key) { + return Double.valueOf(getConfigString(key)); + } + + public Boolean getConfigBoolean(String key) { + return Boolean.valueOf(getConfigString(key)); + } + + public Boolean getConfigBoolean(String key, Boolean defaultValue) { + Boolean value = getConfigBoolean(key); + if (value == null) { + System.out.println("[Poseidon] Config: " + key + " does not exist. Using default value: " + defaultValue); + System.out.println("[Poseidon] Config: This is likely the result of an error. Please report this to the developer."); + value = defaultValue; + } + return value; + } + + //Getters End + + private void convertToNewConfig() { + // 1- 2/3 Conversion + convertToNewAddress("settings.statistics.enabled", "settings.enable-statistics"); + convertToNewAddress("settings.allow-graceful-uuids", "allowGracefulUUID"); + convertToNewAddress("settings.save-playerdata-by-uuid", "savePlayerdataByUUID"); + convertToNewAddress("settings.watchdog.enable", "settings.enable-watchdog"); + // 3-4 Conversion + + // Don't automatically enable the latest log file for servers that have the per-day-logfile setting enabled as this is a change in behavior + if (this.getString("settings.per-day-logfile") != null && this.getConfigBoolean("settings.per-day-logfile")) { + this.setProperty("settings.per-day-log-file.latest-log.enabled", false); + } + convertToNewAddress("settings.per-day-log-file.enabled", "settings.per-day-logfile"); + + // 4-5 Conversion + convertToNewAddress("settings.uuid-fetcher.post.value", "settings.fetch-uuids-from"); + if (this.getString("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname").equals("https://api.mojang.com/profiles/minecraft")) { + System.out.println("[Poseidon] Config: settings.fetch-uuids-from is set to the default value (" + this.getString("settings.uuid-fetcher.post.value") + "). Changing to the new default value (https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname)"); + this.setProperty("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname"); + } + + boolean usePost = !this.getConfigBoolean("settings.use-get-for-uuids.enabled", false); // Is the server currently using POST? + if (usePost) { + this.setProperty("settings.uuid-fetcher.method.value", "POST"); + } else { + this.setProperty("settings.uuid-fetcher.method.value", "GET"); + } + + removeDeprecatedConfig("settings.use-get-for-uuids.enabled", "settings.use-get-for-uuids.info"); + + convertToNewAddress("settings.uuid-fetcher.allow-graceful-uuids.value", "settings.allow-graceful-uuids"); + convertToNewAddress("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled", "settings.use-get-for-uuids.case-sensitive.enabled"); + removeDeprecatedConfig("settings.use-get-for-uuids.case-sensitive.info"); + } + + //Allow any number of string arguments to be passed to this method + private boolean removeDeprecatedConfig(String... keys) { + boolean removed = false; + for (String key : keys) { + if (this.getString(key) != null) { + System.out.println("[Poseidon] Config: " + key + " is deprecated. Removing."); + this.removeProperty(key); + removed = true; + } + } + return removed; + } + + private boolean convertToNewAddress(String newKey, String oldKey) { + if (this.getString(newKey) != null) { + return false; + } + if (this.getString(oldKey) == null) { + System.out.println("[Poseidon] Config: " + oldKey + " does not exist. Skipping conversion."); + return false; + } + System.out.println("[Poseidon] Converting Config: " + oldKey + " to " + newKey); + Object value = this.getProperty(oldKey); + this.setProperty(newKey, value); + this.removeProperty(oldKey); + return true; + + } + + + public synchronized static PoseidonConfig getInstance() { + if (PoseidonConfig.singleton == null) { + PoseidonConfig.singleton = new PoseidonConfig(); + } + return PoseidonConfig.singleton; + } + +} diff --git a/src/main/java/com/legacyminecraft/poseidon/PoseidonPlugin.java b/src/main/java/com/legacyminecraft/poseidon/PoseidonPlugin.java new file mode 100644 index 0000000..2de1b90 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/PoseidonPlugin.java @@ -0,0 +1,91 @@ +package com.legacyminecraft.poseidon; + +import com.avaje.ebean.EbeanServer; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginLoader; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.util.config.Configuration; + +import java.io.File; + +public class PoseidonPlugin implements Plugin { + + + + + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + return false; + } + + @Override + public File getDataFolder() { + return null; + } + + @Override + public PluginDescriptionFile getDescription() { + return null; + } + + @Override + public Configuration getConfiguration() { + return null; + } + + @Override + public PluginLoader getPluginLoader() { + return null; + } + + @Override + public Server getServer() { + return null; + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public void onDisable() { + + } + + @Override + public void onLoad() { + + } + + @Override + public void onEnable() { + + } + + @Override + public boolean isNaggable() { + return false; + } + + @Override + public void setNaggable(boolean canNag) { + + } + + @Override + public EbeanServer getDatabase() { + return null; + } + + @Override + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { + return null; + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/PoseidonServer.java b/src/main/java/com/legacyminecraft/poseidon/PoseidonServer.java new file mode 100644 index 0000000..7be9f1b --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/PoseidonServer.java @@ -0,0 +1,247 @@ +package com.legacyminecraft.poseidon; + +import com.legacyminecraft.poseidon.utility.PerformanceStatistic; +import com.legacyminecraft.poseidon.utility.PoseidonVersionChecker; +import com.legacyminecraft.poseidon.watchdog.WatchDogThread; +import com.projectposeidon.johnymuffin.UUIDManager; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.NetServerHandler; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; + +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.logging.Logger; + +public final class PoseidonServer { + private final MinecraftServer server; + private final CraftServer craftServer; + + private final List hiddenCommands = new ArrayList<>(); + private final Properties versionProperties = new Properties(); + + private boolean serverInitialized = false; + + private PoseidonVersionChecker poseidonVersionChecker; + private WatchDogThread watchDogThread; + + private Map listenerPerformance = new HashMap(); + + private Map taskPerformance = new HashMap(); + + private PoseidonConfig config; + + public PoseidonServer(MinecraftServer server, CraftServer craftServer) { + this.server = server; + this.craftServer = craftServer; + this.config = PoseidonConfig.getInstance(); + + loadVersionProperties(); + + addHiddenCommands(Arrays.asList("login", "l", "register", "reg", "unregister", "changepassword", "changepw")); + } + + private void loadVersionProperties() { + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("version.properties")) { + if (inputStream != null) { + versionProperties.load(inputStream); + } + } catch (IOException e) { + getLogger().warning("Failed to load version.properties: " + e.getMessage()); + } + } + + public void initializeServer() { + if (serverInitialized) { + throw new UnsupportedOperationException("Server already initialized"); + } + + getLogger().info("[Poseidon] Starting Project Poseidon Modules!"); + + PoseidonConfig.getInstance(); + UUIDManager.getInstance(); + + initializeUpdateChecker(); + + //Start Watchdog + watchDogThread = new WatchDogThread(Thread.currentThread()); + if (PoseidonConfig.getInstance().getBoolean("settings.watchdog.enable", true)) { + getLogger().info("[Poseidon] Starting Watchdog to detect any server hangs!"); + watchDogThread.start(); + watchDogThread.tickUpdate(); + } + + serverInitialized = true; + getLogger().info("[Poseidon] Finished loading Project Poseidon Modules!"); + } + + private void initializeUpdateChecker() { + if (!PoseidonConfig.getInstance().getConfigBoolean("settings.update-checker.enabled", true)) { + getLogger().info("[Poseidon] Version checker disabled. The server will not check for updates."); + return; + } + + String releaseVersion = getReleaseVersion(); + + if (releaseVersion == null) { + getLogger().warning("[Poseidon] Version checker is disabled as no version.properties file was found."); + return; + } + + if (!getBuildType().equalsIgnoreCase("production")) { + getLogger().warning("[Poseidon] Version checker is disabled as this is a " + getBuildType() + " build. The updater will only check for updates on production builds."); + return; + } + + poseidonVersionChecker = new PoseidonVersionChecker(craftServer, releaseVersion); + + getLogger().info("[Poseidon] Version checker enabled. The server will check for updates every hour."); + // Run the version checker in a separate thread every hour + Bukkit.getScheduler().scheduleAsyncRepeatingTask(new PoseidonPlugin(), new Runnable() { + @Override + public void run() { + poseidonVersionChecker.fetchLatestVersion(); + } + }, 0, PoseidonConfig.getInstance().getConfigLong("settings.update-checker.interval.ticks")); + } + + public void shutdownServer() { + if (!serverInitialized) { +// throw new UnsupportedOperationException("Server not initialized"); + return; + } + + getLogger().info("[Poseidon] Stopping Project Poseidon Modules!"); + + UUIDManager.getInstance().saveJsonArray(); + + if (watchDogThread != null) { + getLogger().info("[Poseidon] Stopping Watchdog!"); + watchDogThread.interrupt(); + } + + serverInitialized = false; + getLogger().info("[Poseidon] Finished unloading Project Poseidon Modules!"); + } + + public Logger getLogger() { + return MinecraftServer.log; + } + + public String getAppName() { + return versionProperties.getProperty("app_name", "Unknown"); + } + + public String getReleaseVersion() { + return versionProperties.getProperty("release_version", "Unknown"); + } + + public String getMavenVersion() { + return versionProperties.getProperty("maven_version", "Unknown"); + } + + public String getBuildTimestamp() { + return versionProperties.getProperty("build_timestamp", "Unknown"); + } + + public String getGitCommit() { + return versionProperties.getProperty("git_commit", "Unknown"); + } + + public String getBuildType() { + return versionProperties.getProperty("build_type", "Unknown"); + } + + public boolean isUpdateAvailable() { + return poseidonVersionChecker != null && poseidonVersionChecker.isUpdateAvailable(); + } + + public String getNewestVersion() { + return poseidonVersionChecker == null ? "Unknown" : poseidonVersionChecker.getLatestVersion(); + } + + public WatchDogThread getWatchDogThread() { + return watchDogThread; + } + + /** + * Returns the current hide state of the command from param (Hide from console) + * + * @param cmdName Command name + * @return True if the command from param is hidden and false otherwise + */ + public boolean isCommandHidden(String cmdName) { + return hiddenCommands.contains(cmdName.toLowerCase()); + } + + /** + * Hides the command from param from being logged to server console + * + * @param cmd Command name + */ + public void addHiddenCommand(String cmd) { + cmd = cmd.toLowerCase(); + + if (hiddenCommands.contains(cmd)) { + Logger.getLogger(NetServerHandler.class.getName()).warning("List of Hidden commands already contains " + cmd); + return; + } + + hiddenCommands.add(cmd); + } + + /** + * Hides the commands from param from being logged to server console + * + * @param commands List of command names + */ + public void addHiddenCommands(List commands) { + for (String cmd : commands) { + addHiddenCommand(cmd); + } + } + + public Map getListenerPerformance() { + return listenerPerformance; + } + + public Map getTaskPerformance() { + return taskPerformance; + } + + // Generic method to sort any performance map + public Map getSortedPerformance(Map unsortedMap) { + return unsortedMap.entrySet() + .stream() + .sorted(Map.Entry.comparingByValue( + Comparator.comparingLong(PerformanceStatistic::getAverageExecutionTime).reversed() + )) + .collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (e1, e2) -> e1, // if same key, keep the first + LinkedHashMap::new + )); + } + + // Specific method to get sorted listener performance + public Map getSortedListenerPerformance() { + return getSortedPerformance(getListenerPerformance()); + } + + // Specific method to get sorted task performance + public Map getSortedTaskPerformance() { + return getSortedPerformance(getTaskPerformance()); + } + + public PoseidonConfig getConfig() { + return config; + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/PoseidonStatisticsAgent.java b/src/main/java/com/legacyminecraft/poseidon/PoseidonStatisticsAgent.java new file mode 100644 index 0000000..275048b --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/PoseidonStatisticsAgent.java @@ -0,0 +1,104 @@ +package com.legacyminecraft.poseidon; + +import net.minecraft.server.MinecraftServer; +import org.bukkit.craftbukkit.CraftServer; +import org.json.simple.JSONObject; + +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Random; + +public class PoseidonStatisticsAgent { + //Default details + private int protocolID = 1; + public final String postTo = "https://poseidon.johnymuffin.com/statistics.php"; + //Unique Details + private String uniqueID; + private final String sessionID; + private final String version; + private final String branch; + private final Long startTime; + private Object syncLock = new Object(); + + public PoseidonStatisticsAgent(MinecraftServer server, CraftServer craftServer) { + //This really shouldn't be needed, but it runs once, whats the harm? + synchronized (syncLock) { + this.startTime = (System.currentTimeMillis() / 1000L); + this.uniqueID = PoseidonConfig.getInstance().getString("settings.statistics.key"); + //Create temp value + Random rnd = new Random(); + this.sessionID = String.valueOf(100000 + rnd.nextInt(900000)); + this.version = craftServer.getPoseidonVersion(); + this.branch = craftServer.getPoseidonReleaseType(); + } + + PoseidonStatisticsSender poseidonStatisticsSender = new PoseidonStatisticsSender(); + poseidonStatisticsSender.start(); + + } + + public JSONObject getPing() { + synchronized (syncLock) { + JSONObject ping = new JSONObject(); + ping.put("protocol", protocolID); + ping.put("uniqueID", uniqueID); + ping.put("sessionID", sessionID); + ping.put("version", version); + ping.put("branch", branch); + int uptime = (int) ((System.currentTimeMillis() / 1000L) - startTime); + ping.put("uptime", uptime); + return ping; + } + } + + public class PoseidonStatisticsSender extends Thread { + public volatile boolean errored = false; + + public void run() { + while (true && !this.isInterrupted()) { + HttpURLConnection connection = null; + try { + System.out.println("Submitting Project Poseidon Statistics."); + final JSONObject ping = getPing(); + URL url = new URL(postTo); + //Create Connection + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + //Write Body + OutputStream stream = connection.getOutputStream(); + stream.write(ping.toJSONString().getBytes()); + stream.flush(); + stream.close(); + //Get Response + String response = String.valueOf(new InputStreamReader(connection.getInputStream())); + connection.disconnect(); + errored = false; + } catch (Exception exception) { + if (!errored) { + System.out.println("Failed to submit statistics for Project Poseidon. " + exception + " : " + exception.getMessage() + "."); + } + errored = true; + } finally { + if (connection != null) { + connection.disconnect(); + connection = null; + } + try { + Thread.sleep(300000L); + } catch (InterruptedException exception) { + System.out.println("Project Poseidon statistics thread has been closed."); + break; + } + } + } + } + + } + +} diff --git a/src/main/java/com/legacyminecraft/poseidon/commands/PoseidonCommand.java b/src/main/java/com/legacyminecraft/poseidon/commands/PoseidonCommand.java new file mode 100644 index 0000000..e62950d --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/commands/PoseidonCommand.java @@ -0,0 +1,105 @@ +package com.legacyminecraft.poseidon.commands; + +import com.legacyminecraft.poseidon.Poseidon; +import com.projectposeidon.api.PoseidonUUID; +import com.projectposeidon.api.UUIDType; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Properties; +import java.util.UUID; + +public class PoseidonCommand extends Command { + + private final Properties versionProperties = new Properties(); + + public PoseidonCommand(String name) { + super(name); + this.description = "Show data regarding the server's version of Project Poseidon"; + this.usageMessage = "/poseidon"; + this.setAliases(Arrays.asList("projectposeidon")); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + + if (args.length >= 1 && args[0].equalsIgnoreCase("resolve")) { + String[] subArgs = Arrays.copyOfRange(args, 1, args.length); + ResolveCommand resolver = new ResolveCommand("resolve"); + return resolver.execute(sender, "resolve", subArgs); + } + + if (args.length == 0) { + String appName = Poseidon.getServer().getAppName(); + String releaseVersion = Poseidon.getServer().getReleaseVersion(); + String mavenVersion = Poseidon.getServer().getMavenVersion(); + String buildTimestamp = Poseidon.getServer().getBuildTimestamp(); + String gitCommit = Poseidon.getServer().getGitCommit(); + String buildType = Poseidon.getServer().getBuildType(); + + // Shorten the git commit hash to 7 characters + if (gitCommit.length() > 7) { + gitCommit = gitCommit.substring(0, 7); + } + + if ("Unknown".equals(releaseVersion)) { + sender.sendMessage(ChatColor.RED + "Warning: version.properties not found. This is a local or unconfigured build."); + } else { + sender.sendMessage(ChatColor.GRAY + "This server is running " + ChatColor.AQUA + appName + ChatColor.GRAY + ":"); + sender.sendMessage(ChatColor.GRAY + " - Version: " + ChatColor.YELLOW + releaseVersion); + sender.sendMessage(ChatColor.GRAY + " - Built at: " + ChatColor.YELLOW + buildTimestamp); + sender.sendMessage(ChatColor.GRAY + " - Git SHA: " + ChatColor.YELLOW + gitCommit); + + if ("production".equalsIgnoreCase(buildType)) { + sender.sendMessage(ChatColor.GREEN + "This is a release build."); + } else if ("pull_request".equalsIgnoreCase(buildType)) { + sender.sendMessage(ChatColor.BLUE + "This is a pull request build."); + } else { + sender.sendMessage(ChatColor.GRAY + "This is a development build."); + } + } + } else if (args.length == 1) { + if (args[0].equalsIgnoreCase("uuid")) { + sender.sendMessage(ChatColor.GRAY + "Please specify a user /poseidon uuid (username)"); + } else { + sender.sendMessage(ChatColor.GRAY + "Unknown sub command."); + } + } else { + if (!args[0].equalsIgnoreCase("uuid")) { + sender.sendMessage(ChatColor.GRAY + "Unknown sub command."); + } else { + UUID uuid = PoseidonUUID.getPlayerUUIDFromCache(args[1], true); + if (uuid == null) { + uuid = PoseidonUUID.getPlayerUUIDFromCache(args[1], false); + } + + if (uuid == null) { + sender.sendMessage(ChatColor.GRAY + "Unable to locate the UUID of the player called: " + ChatColor.WHITE + args[1] + ChatColor.GRAY + ". Please remember usernames are cap sensitive"); + } else { + + String latestUsername = PoseidonUUID.getPlayerUsernameFromUUID(uuid); + + sender.sendMessage(ChatColor.GRAY + "Username: " + latestUsername); + sender.sendMessage(ChatColor.GRAY + "UUID: " + uuid.toString()); + UUIDType uuidType = PoseidonUUID.getPlayerUUIDCacheStatus(args[1]); + if (uuidType.equals(UUIDType.ONLINE)) { + sender.sendMessage(ChatColor.GRAY + "UUID Type: " + ChatColor.GREEN + "Online"); + } else if (uuidType.equals(UUIDType.OFFLINE)) { + sender.sendMessage(ChatColor.GRAY + "UUID Type: " + ChatColor.RED + "Offline"); + } else { + sender.sendMessage(ChatColor.GRAY + "UUID Type: " + ChatColor.DARK_RED + "UNKNOWN"); + } + } + } + } + + return true; + + } + +} diff --git a/src/main/java/com/legacyminecraft/poseidon/commands/ResolveCommand.java b/src/main/java/com/legacyminecraft/poseidon/commands/ResolveCommand.java new file mode 100644 index 0000000..09aa4a2 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/commands/ResolveCommand.java @@ -0,0 +1,137 @@ +package com.legacyminecraft.poseidon.commands; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Field; +import java.util.Map; + +public class ResolveCommand extends Command { + + public ResolveCommand(String name) { + super(name); + this.description = "Find out what plugin a command belongs to"; + this.usageMessage = "/poseidon resolve "; + this.setPermission("poseidon.command.resolve"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + if (args.length == 0) { + sender.sendMessage(ChatColor.RED + "Usage: /poseidon resolve "); + return true; + } + + String targetCommand = args[0].toLowerCase(); + if (targetCommand.startsWith("/")) { + targetCommand = targetCommand.substring(1); + } + + // Try to find the command in the server's command map + Command cmd = Bukkit.getServer().getPluginCommand(targetCommand); + + if (cmd != null && cmd instanceof PluginCommand) { + displayPluginCommand(sender, (PluginCommand) cmd, targetCommand); + return true; + } + + // If not found as PluginCommand, search through all known commands + try { + SimpleCommandMap commandMap = getCommandMap(); + + if (commandMap == null) { + sender.sendMessage(ChatColor.RED + "Unable to access command map."); + return true; + } + + Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands"); + knownCommandsField.setAccessible(true); + + @SuppressWarnings("unchecked") + Map knownCommands = (Map) knownCommandsField.get(commandMap); + + for (Map.Entry entry : knownCommands.entrySet()) { + if (entry.getKey().equalsIgnoreCase(targetCommand) || + entry.getValue().getName().equalsIgnoreCase(targetCommand)) { + + Command foundCmd = entry.getValue(); + + if (foundCmd instanceof PluginCommand) { + displayPluginCommand(sender, (PluginCommand) foundCmd, targetCommand); + return true; + } else { + displayServerCommand(sender, foundCmd, targetCommand); + return true; + } + } + } + } catch (Exception e) { + sender.sendMessage(ChatColor.RED + "Error while searching for command: " + e.getMessage()); + return true; + } + sender.sendMessage(ChatColor.RED + "Command '" + targetCommand + "' not found."); + sender.sendMessage(ChatColor.YELLOW + "Note: The command might not be registered or might be case-sensitive."); + return true; + } + + private void displayPluginCommand(CommandSender sender, PluginCommand pluginCmd, String targetCommand) { + Plugin plugin = pluginCmd.getPlugin(); + + sender.sendMessage(ChatColor.GREEN + "Command: " + ChatColor.WHITE + "/" + targetCommand); + sender.sendMessage(ChatColor.GREEN + "Plugin: " + ChatColor.WHITE + plugin.getDescription().getName()); + sender.sendMessage(ChatColor.GREEN + "Author: " + ChatColor.WHITE + plugin.getDescription().getAuthors()); + sender.sendMessage(ChatColor.GREEN + "Version: " + ChatColor.WHITE + plugin.getDescription().getVersion()); + + if (pluginCmd.getAliases() != null && !pluginCmd.getAliases().isEmpty()) { + sender.sendMessage(ChatColor.GREEN + "Aliases: " + ChatColor.WHITE + + String.join(", ", pluginCmd.getAliases())); + } + + if (pluginCmd.getDescription() != null && !pluginCmd.getDescription().isEmpty()) { + sender.sendMessage(ChatColor.GREEN + "Description: " + ChatColor.WHITE + + pluginCmd.getDescription()); + } + } + + private void displayServerCommand(CommandSender sender, Command cmd, String targetCommand) { + sender.sendMessage(ChatColor.GREEN + "Command: " + ChatColor.WHITE + "/" + targetCommand); + sender.sendMessage(ChatColor.AQUA + "Source: " + ChatColor.WHITE + "Server (Poseidon/Bukkit)"); + + if (!cmd.getAliases().isEmpty()) { + sender.sendMessage(ChatColor.GREEN + "Aliases: " + ChatColor.WHITE + + String.join(", ", cmd.getAliases())); + } + + if (cmd.getDescription() != null && !cmd.getDescription().isEmpty()) { + sender.sendMessage(ChatColor.GREEN + "Description: " + ChatColor.WHITE + + cmd.getDescription()); + } + + if (cmd.getPermission() != null && !cmd.getPermission().isEmpty()) { + sender.sendMessage(ChatColor.GREEN + "Permission: " + ChatColor.WHITE + + cmd.getPermission()); + } + } + + @SuppressWarnings("CatchMayIgnoreException") + private SimpleCommandMap getCommandMap() { + try { + if (Bukkit.getServer() instanceof CraftServer) { + CraftServer craftServer = (CraftServer) Bukkit.getServer(); + Field commandMapField = CraftServer.class.getDeclaredField("commandMap"); + commandMapField.setAccessible(true); + return (SimpleCommandMap) commandMapField.get(craftServer); + } + } catch (Exception e) { + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/legacyminecraft/poseidon/commands/TPSCommand.java b/src/main/java/com/legacyminecraft/poseidon/commands/TPSCommand.java new file mode 100644 index 0000000..a085f06 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/commands/TPSCommand.java @@ -0,0 +1,75 @@ +package com.legacyminecraft.poseidon.commands; + +import com.legacyminecraft.poseidon.Poseidon; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.defaults.VanillaCommand; + +import java.util.LinkedList; +import java.util.LinkedHashMap; +import java.util.Map; + +public class TPSCommand extends Command { + + private final LinkedHashMap intervals = new LinkedHashMap<>(); + + public TPSCommand(String name) { + super(name); + this.description = "Shows the server's TPS for various intervals"; + this.usageMessage = "/tps"; + this.setPermission("poseidon.command.tps"); + + // Define the intervals for TPS calculation + intervals.put("5s", 5); + intervals.put("30s", 30); + intervals.put("1m", 60); + intervals.put("5m", 300); + intervals.put("10m", 600); + intervals.put("15m", 900); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + LinkedList tpsRecords = Poseidon.getTpsRecords(); + StringBuilder message = new StringBuilder("§bServer TPS: "); + + // Calculate and format TPS for each interval dynamically + for (Map.Entry entry : intervals.entrySet()) { + double averageTps = calculateAverage(tpsRecords, entry.getValue()); + message.append(formatTps(averageTps)).append(" (").append(entry.getKey()).append("), "); + } + + // Remove the trailing comma and space + if (message.length() > 0) { + message.setLength(message.length() - 2); + } + + sender.sendMessage(message.toString()); + return true; + } + + private double calculateAverage(LinkedList records, int seconds) { + int size = Math.min(records.size(), seconds); + if (size == 0) return 20.0; + + double total = 0; + for (int i = 0; i < size; i++) { + total += records.get(i); + } + return total / size; + } + + private String formatTps(double tps) { + String colorCode; + if (tps >= 19) { + colorCode = "§a"; + } else if (tps >= 15) { + colorCode = "§e"; + } else { + colorCode = "§c"; + } + return colorCode + String.format("%.2f", tps); + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/event/PlayerDeathEvent.java b/src/main/java/com/legacyminecraft/poseidon/event/PlayerDeathEvent.java new file mode 100644 index 0000000..81fa080 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/event/PlayerDeathEvent.java @@ -0,0 +1,54 @@ +package com.legacyminecraft.poseidon.event; + +import org.bukkit.entity.Entity; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class PlayerDeathEvent extends EntityDeathEvent { + private String deathMessage = ""; + private boolean keepInventory = false; + + public PlayerDeathEvent(Entity what, List drops) { + super(what, drops); + } + + /** + * Set the death message that will appear to everyone on the server. + * + * @param deathMessage Message to appear to other players on the server. + */ + public void setDeathMessage(String deathMessage) { + this.deathMessage = deathMessage; + } + + /** + * Get the death message that will appear to everyone on the server. + * + * @return Message to appear to other players on the server. + */ + public String getDeathMessage() { + return deathMessage; + } + + /** + * Sets if the Player keeps inventory on death. + * + * @param keepInventory True to keep the inventory + */ + public void setKeepInventory(boolean keepInventory) { + this.keepInventory = keepInventory; + } + + /** + * Gets if the Player keeps inventory on death. + * + * @return True if the player keeps inventory on death + */ + public boolean getKeepInventory() { + return keepInventory; + } + + +} diff --git a/src/main/java/com/legacyminecraft/poseidon/event/PlayerPacketEvent.java b/src/main/java/com/legacyminecraft/poseidon/event/PlayerPacketEvent.java new file mode 100644 index 0000000..80f5917 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/event/PlayerPacketEvent.java @@ -0,0 +1,46 @@ +package com.legacyminecraft.poseidon.event; + +import net.minecraft.server.Packet; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerPacketEvent extends Event implements Cancellable { + private boolean cancel; + private Packet packet; + private String username; + + public PlayerPacketEvent(Type type, String username, Packet packet) { + super(type); + this.cancel = false; + this.packet = packet; + this.username = username; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + public int getPacketID() { + return packet.b(); + } + + public Packet getPacket() { + return packet; + } + + public void setPacket(Packet packet) { + this.packet = packet; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + public String getUsername() { + return username; + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/event/PlayerReceivePacketEvent.java b/src/main/java/com/legacyminecraft/poseidon/event/PlayerReceivePacketEvent.java new file mode 100644 index 0000000..ad79539 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/event/PlayerReceivePacketEvent.java @@ -0,0 +1,9 @@ +package com.legacyminecraft.poseidon.event; + +import net.minecraft.server.Packet; + +public class PlayerReceivePacketEvent extends PlayerPacketEvent { + public PlayerReceivePacketEvent(String username, Packet packet) { + super(Type.PLAYER_RECEIVE_PACKET, username, packet); + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/event/PlayerSendPacketEvent.java b/src/main/java/com/legacyminecraft/poseidon/event/PlayerSendPacketEvent.java new file mode 100644 index 0000000..b75c3c8 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/event/PlayerSendPacketEvent.java @@ -0,0 +1,10 @@ +package com.legacyminecraft.poseidon.event; + +import net.minecraft.server.Packet; + +public class PlayerSendPacketEvent extends PlayerPacketEvent { + + public PlayerSendPacketEvent(String username, Packet packet) { + super(Type.PLAYER_SEND_PACKET, username, packet); + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/event/PoseidonCustomListener.java b/src/main/java/com/legacyminecraft/poseidon/event/PoseidonCustomListener.java new file mode 100644 index 0000000..94c088a --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/event/PoseidonCustomListener.java @@ -0,0 +1,6 @@ +package com.legacyminecraft.poseidon.event; + +import org.bukkit.event.Listener; + +public interface PoseidonCustomListener extends Listener { +} diff --git a/src/main/java/com/legacyminecraft/poseidon/packets/ArtificialPacket53BlockChange.java b/src/main/java/com/legacyminecraft/poseidon/packets/ArtificialPacket53BlockChange.java new file mode 100644 index 0000000..becb632 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/packets/ArtificialPacket53BlockChange.java @@ -0,0 +1,64 @@ +package com.legacyminecraft.poseidon.packets; + +import net.minecraft.server.NetHandler; +import net.minecraft.server.Packet; +import net.minecraft.server.World; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class ArtificialPacket53BlockChange extends Packet { + + public int a; + public int b; + public int c; + public int material; + public int data; + + public ArtificialPacket53BlockChange() { + this.k = true; + } + + public ArtificialPacket53BlockChange(int i, int j, int k, World world) { + this.k = true; + this.a = i; + this.b = j; + this.c = k; + this.material = world.getTypeId(i, j, k); + this.data = world.getData(i, j, k); + } + + public ArtificialPacket53BlockChange(int i, int j, int k, int materialType, int data) { + this.k = true; + this.a = i; + this.b = j; + this.c = k; + this.material = materialType; + this.data = data; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.read(); + this.c = datainputstream.readInt(); + this.material = datainputstream.read(); + this.data = datainputstream.read(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.write(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.write(this.material); + dataoutputstream.write(this.data); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 11; + } +} \ No newline at end of file diff --git a/src/main/java/com/legacyminecraft/poseidon/util/GetUUIDFetcher.java b/src/main/java/com/legacyminecraft/poseidon/util/GetUUIDFetcher.java new file mode 100644 index 0000000..1113afb --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/GetUUIDFetcher.java @@ -0,0 +1,128 @@ +package com.legacyminecraft.poseidon.util; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.*; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.UUID; +import java.util.regex.Pattern; + +import static com.projectposeidon.johnymuffin.UUIDManager.generateOfflineUUID; + +public class GetUUIDFetcher { + + public static class UUIDAndUsernameResult { + private UUIDResult uuidResult; + private String returnedUsername; + + public UUIDAndUsernameResult(UUIDResult uuidResult, String returnedUsername) { + this.uuidResult = uuidResult; + this.returnedUsername = returnedUsername; + } + + public UUIDResult getUuidResult() { + return uuidResult; + } + + public String getReturnedUsername() { + return returnedUsername; + } + } + + + public static UUIDAndUsernameResult getUUID(String username) { + try { + String url = PoseidonConfig.getInstance().getString("settings.uuid-fetcher.get.value", "https://api.minecraftservices.com/minecraft/profile/lookup/name/{username}"); + url = url.replace("{username}", encode(username)); + + JSONObject jsonObject = readJsonFromUrl(url); + UUIDResult uuidResult; + String returnedUsername = null; + + if (!jsonObject.containsKey("id")) { + uuidResult = new UUIDResult(generateOfflineUUID(username), UUIDResult.ReturnType.OFFLINE); + } else { + UUID uuid = toUUIDWithDashes(String.valueOf(jsonObject.get("id"))); + if (uuid == null) { + uuidResult = new UUIDResult(null, UUIDResult.ReturnType.API_OFFLINE); + } else { + returnedUsername = String.valueOf(jsonObject.get("name")); + uuidResult = new UUIDResult(uuid, UUIDResult.ReturnType.ONLINE); + } + } + + return new UUIDAndUsernameResult(uuidResult, returnedUsername); + + } catch (Exception exception) { + UUIDResult uuidResult = null; + if (exception == null || exception instanceof FileNotFoundException || exception.getMessage() == null) { + // This is a hacky solution to tell if the API is offline, or the user is cracked. + uuidResult = new UUIDResult(generateOfflineUUID(username), UUIDResult.ReturnType.OFFLINE); + } else { + uuidResult = new UUIDResult(null, UUIDResult.ReturnType.API_OFFLINE); + uuidResult.setException(exception); + } + return new UUIDAndUsernameResult(uuidResult, null); + } + } + + + public static String encode(String string) { + try { + return URLEncoder.encode(string, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return string; + } + } + + public static UUID toUUIDWithDashes(String uuid) { + return UUID.fromString(uuid.replaceFirst("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5")); + } + + public static boolean verifyJSONArguments(JSONObject jsonObject, String... arguments) { + for (String s : arguments) { + if (!jsonObject.containsKey(s)) return false; + } + return true; + } + + public static boolean isURL(String url) { + try { + new URL(url); + return true; + } catch (Exception e) { + return false; + } + } + + public static boolean validUUID(String uuid) { + return Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$").matcher(uuid).matches(); + } + + private static String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } + + private static JSONObject readJsonFromUrl(String url) throws IOException, ParseException { + InputStream is = new URL(url).openStream(); + try { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + JSONParser jsp = new JSONParser(); + JSONObject json = (JSONObject) jsp.parse(jsonText); + return json; + } finally { + is.close(); + } + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/util/HTTPResponse.java b/src/main/java/com/legacyminecraft/poseidon/util/HTTPResponse.java new file mode 100644 index 0000000..17880a6 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/HTTPResponse.java @@ -0,0 +1,23 @@ +package com.legacyminecraft.poseidon.util; + +public class HTTPResponse +{ + private String response; + private int responseCode; + + public HTTPResponse(String response, int responseCode) + { + this.response = response; + this.responseCode = responseCode; + } + + public String getResponse() + { + return response; + } + + public int getResponseCode() + { + return responseCode; + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/util/Release2Beta.java b/src/main/java/com/legacyminecraft/poseidon/util/Release2Beta.java new file mode 100644 index 0000000..d4d4ac0 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/Release2Beta.java @@ -0,0 +1,53 @@ +package com.legacyminecraft.poseidon.util; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +public class Release2Beta { + + public static long serializeAddress(SocketAddress address) { + String str = address.toString(); + String[] parts = str.split(":"); + + String realAddress = parts[0].substring(1); // remove '/' + return ipToLong(realAddress); + } + + public static InetSocketAddress deserializeAddress(long spoofedAddress) { + String realAddress = longToIp(spoofedAddress); + return new InetSocketAddress(realAddress, 0); + } + + //Credit: https://mkyong.com/java/java-convert-ip-address-to-decimal-number/ + public static long ipToLong(String ipAddress) { + // ipAddressInArray[0] = 192 + String[] ipAddressInArray = ipAddress.split("\\."); + + long result = 0; + for (int i = 0; i < ipAddressInArray.length; i++) { + + int power = 3 - i; + int ip = Integer.parseInt(ipAddressInArray[i]); + + // 1. 192 * 256^3 + // 2. 168 * 256^2 + // 3. 1 * 256^1 + // 4. 2 * 256^0 + result += ip * Math.pow(256, power); + + } + + return result; + + } + + //Credit: https://mkyong.com/java/java-convert-ip-address-to-decimal-number/ + private static String longToIp(long i) { + + return ((i >> 24) & 0xFF) + + "." + ((i >> 16) & 0xFF) + + "." + ((i >> 8) & 0xFF) + + "." + (i & 0xFF); + + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/util/ServerLogRotator.java b/src/main/java/com/legacyminecraft/poseidon/util/ServerLogRotator.java new file mode 100644 index 0000000..a293549 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/ServerLogRotator.java @@ -0,0 +1,150 @@ +package com.legacyminecraft.poseidon.util; + +import org.bukkit.Bukkit; +import com.legacyminecraft.poseidon.PoseidonPlugin; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import java.util.logging.*; + +public class ServerLogRotator { + private final String latestLogFileName; + private final Logger logger; + + public ServerLogRotator(String latestLogFileName) { + this.latestLogFileName = latestLogFileName; + this.logger = Logger.getLogger("Minecraft"); + } + + /** + * Checks if the date in the log line is today's date + * @param date The date in the log line. Format: "yyyy-MM-dd" + * @return True if the date in the log line is today's date, false otherwise + */ + private boolean isToday(String date) { + String[] dateParts = date.split("-"); + LocalDateTime logLineDateTime = LocalDateTime.of(Integer.parseInt(dateParts[0]), Integer.parseInt(dateParts[1]), Integer.parseInt(dateParts[2]), 0, 0, 0); + LocalDateTime now = LocalDateTime.now(); + return logLineDateTime.getYear() == now.getYear() && logLineDateTime.getMonthValue() == now.getMonthValue() && logLineDateTime.getDayOfMonth() == now.getDayOfMonth(); + } + + /** + * Archives a log line to a log file with the same date as the date in the log line + * @param parts The log line to archive to a log file haven been split already e.g. ["2024-03-20", "13:02:27", "[INFO]", "This is a log message..."] + */ + private void archiveLine(String[] parts) { + + try { + + String date = parts[0]; + String time = parts[1]; + String logLevel = parts[2]; + String message = String.join(" ", Arrays.copyOfRange(parts, 3, parts.length)); + // check if a log file with this information already exists + File logFile = new File("." + File.separator + "logs" + File.separator + date + ".log"); + if (!logFile.exists()) { + logFile.createNewFile(); + } + // append the log line to the log file with the same date as the date in the log line + FileWriter fileWriter = new FileWriter(logFile, true); + PrintWriter writer = new PrintWriter(fileWriter); + writer.println(date + " " + time + " " + logLevel + " " + message); + writer.close(); + + // catch any exceptions that occur during the process, and log them. IOExceptions are possible when calling createNewFile() + } catch (IOException e) { + logger.log(Level.SEVERE, "[Poseidon] Failed to create new log file!"); + logger.log(Level.SEVERE, e.toString()); + } + } + + /** + * Builds historical logs from the latest.log file. Logs from today's date are kept in the latest.log file, while logs from previous dates are archived to log files with the same date as the date in the log line. + * Note that if latest.log contains logs from multiple days, the logs will be split by date and archived to the appropriate log files. + */ + private void buildHistoricalLogsFromLatestLogFile() { + + logger.log(Level.INFO, "[Poseidon] Building logs from latest.log..."); + + try { + // open latest log file + File latestLog = new File("." + File.separator + "logs" + File.separator + this.latestLogFileName + ".log"); + if (!latestLog.exists()) { + logger.log(Level.INFO, "[Poseidon] No logs to build from latest.log!"); + return; + } + + // split the contents of the latest log file by line (and strip the newline character) + String content = new String(Files.readAllBytes(latestLog.toPath())); + String[] lines = content.split("\n"); + // create a StringBuilder to store today's logs (to write back to latest.log after archiving the rest of the logs) + StringBuilder todayLogs = new StringBuilder(); + + for (String line : lines) { + + String[] splitLine = line.split(" "); + if (splitLine.length < 3) { // all lines will start with a date, time, and log level e.g. "2024-03-20 13:02:27 [INFO]" + continue; + } + + // make sure the first index is a date + if (!splitLine[0].matches("\\d{4}-\\d{2}-\\d{2}")) { + continue; + } + + // if the log line is of today's date, do not archive it (ignore times) + if (isToday(splitLine[0])) { + todayLogs.append(line).append("\n"); + continue; + } + + // archive the log line to a log file with the same date as the date in the log line + archiveLine(splitLine); + + } + + // clear latest.log and write back today's logs from the StringBuilder + FileWriter fileWriter = new FileWriter(latestLog); + PrintWriter writer = new PrintWriter(fileWriter); + writer.print(todayLogs); + writer.close(); + + logger.log(Level.INFO, "[Poseidon] Logs built from latest.log!"); + + // catch any exceptions that occur during the process, and log them + } catch (Exception e) { + logger.log(Level.SEVERE, "[Poseidon] Failed to build logs from latest.log!"); + logger.log(Level.SEVERE, e.toString()); + } + } + + public void start() { + // Calculate the initial delay and period for the log rotation task + ZonedDateTime now = ZonedDateTime.now(); + ZonedDateTime nextRun = now.withHour(0).withMinute(0).withSecond(0).withNano(0); + if(now.compareTo(nextRun) > 0) + nextRun = nextRun.plusDays(1); + Duration duration = Duration.between(now, nextRun); + long initialDelay = duration.getSeconds(); + long period = TimeUnit.DAYS.toSeconds(1); + + // do log rotation immediately upon startup to ensure that logs are archived correctly. + buildHistoricalLogsFromLatestLogFile(); + + // Schedule the log rotation task to run every day at midnight offset by one second to avoid missing logs + logger.log(Level.INFO, "[Poseidon] Log rotation task scheduled for run in " + initialDelay + " seconds, and then every " + period + " seconds."); + logger.log(Level.INFO, "[Poseidon] If latest.log contains logs from earlier, not previously archived dates, they will be archived to the appropriate log files " + + "upon first run of the log rotation task. If log files already exist for these dates, the logs will be appended to the existing log files!"); + Bukkit.getScheduler().scheduleAsyncRepeatingTask(new PoseidonPlugin(), this::buildHistoricalLogsFromLatestLogFile, (initialDelay + 1) * 20, period * 20); + } +} + diff --git a/src/main/java/com/legacyminecraft/poseidon/util/SessionAPI.java b/src/main/java/com/legacyminecraft/poseidon/util/SessionAPI.java new file mode 100644 index 0000000..ddc08b1 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/SessionAPI.java @@ -0,0 +1,75 @@ +package com.legacyminecraft.poseidon.util; + +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * A wrapper class for the Minecraft session API + * + * TODO maybe make the HTTP requests asynchronous? idk if it really matters + * + * @author moderator_man + */ +public class SessionAPI +{ + public static final String SESSION_BASE = "http://session.minecraft.net/game/"; + + public static boolean hasJoined(String username, String serverId) + { + HTTPResponse response = httpGetRequest(SESSION_BASE + String.format("checkserver.jsp?user=%s&serverId=%s", username, serverId)); + if (response.getResponse() != "YES") + return false; + return true; + } + + public static void hasJoined(String username, String serverId, String ip, SessionRequestRunnable callback) + { + try + { + boolean checkIP = ip == "127.0.0.1" || ip == "localhost"; + StringBuilder sb = new StringBuilder(); + sb.append(System.getProperty("minecraft.api.session.host", "https://sessionserver.mojang.com") + "/session/minecraft/hasJoined"); + sb.append("?username=" + username); + sb.append("&serverId=" + serverId); + if (checkIP) + sb.append("&ip=" + ip); + String requestUrl = sb.toString(); + + HTTPResponse response = httpGetRequest(requestUrl); + JSONObject obj = (JSONObject) new JSONParser().parse(response.getResponse()); + String res_username = (obj.containsKey("name") ? (String) obj.get("name") : "nousername"); + String res_uuid = (obj.containsKey("id") ? (String) obj.get("id") : "nouuid"); + String res_ip = (obj.containsKey("ip") ? (String) obj.get("ip") : "noip"); + callback.callback(response.getResponseCode(), res_username, res_uuid, res_ip); + } catch (Exception ex) { + System.out.println(String.format("Failed to authenticate session for '%s': %s", username, ex.getMessage())); + // TODO: if debug, print the stack trace + } + } + + private static HTTPResponse httpGetRequest(String url) + { + try + { + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "Project-Poseidon/0"); + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuffer response = new StringBuffer(); + while ((inputLine = in.readLine()) != null) + response.append(inputLine); + in.close(); + return new HTTPResponse(response.toString(), con.getResponseCode()); + } catch (Exception ex) { + ex.printStackTrace(); + return new HTTPResponse("", -1); + } + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/util/SessionRequestRunnable.java b/src/main/java/com/legacyminecraft/poseidon/util/SessionRequestRunnable.java new file mode 100644 index 0000000..5f14071 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/SessionRequestRunnable.java @@ -0,0 +1,6 @@ +package com.legacyminecraft.poseidon.util; + +public interface SessionRequestRunnable +{ + public void callback(int responseCode, String username, String uuid, String ip); +} diff --git a/src/main/java/com/legacyminecraft/poseidon/util/UUIDFetcher.java b/src/main/java/com/legacyminecraft/poseidon/util/UUIDFetcher.java new file mode 100644 index 0000000..4239f52 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/UUIDFetcher.java @@ -0,0 +1,97 @@ +package com.legacyminecraft.poseidon.util; + +import com.google.common.collect.ImmutableList; +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.Callable; + +public class UUIDFetcher implements Callable> { + private static final double PROFILES_PER_REQUEST = 100; + private static final String PROFILE_URL = PoseidonConfig.getInstance().getString("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname"); + private final JSONParser jsonParser = new JSONParser(); + private final List names; + private final boolean rateLimiting; + + public UUIDFetcher(List names, boolean rateLimiting) { + this.names = ImmutableList.copyOf(names); + this.rateLimiting = rateLimiting; + } + + public UUIDFetcher(List names) { + this(names, true); + } + + public Map call() throws Exception { + Map uuidMap = new HashMap(); + int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST); + for (int i = 0; i < requests; i++) { + HttpURLConnection connection = createConnection(); + String body = JSONArray.toJSONString(names.subList(i * 100, Math.min((i + 1) * 100, names.size()))); + writeBody(connection, body); + JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream())); + for (Object profile : array) { + JSONObject jsonProfile = (JSONObject) profile; + String id = (String) jsonProfile.get("id"); + String name = (String) jsonProfile.get("name"); + UUID uuid = UUIDFetcher.getUUID(id); + uuidMap.put(name, uuid); + } + if (rateLimiting && i != requests - 1) { + Thread.sleep(100L); + } + } + return uuidMap; + } + + private static void writeBody(HttpURLConnection connection, String body) throws Exception { + OutputStream stream = connection.getOutputStream(); + stream.write(body.getBytes()); + stream.flush(); + stream.close(); + } + + private static HttpURLConnection createConnection() throws Exception { + URL url = new URL(PROFILE_URL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + return connection; + } + + private static UUID getUUID(String id) { + return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +id.substring(20, 32)); + } + + public static byte[] toBytes(UUID uuid) { + ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); + byteBuffer.putLong(uuid.getMostSignificantBits()); + byteBuffer.putLong(uuid.getLeastSignificantBits()); + return byteBuffer.array(); + } + + public static UUID fromBytes(byte[] array) { + if (array.length != 16) { + throw new IllegalArgumentException("Illegal byte array length: " + array.length); + } + ByteBuffer byteBuffer = ByteBuffer.wrap(array); + long mostSignificant = byteBuffer.getLong(); + long leastSignificant = byteBuffer.getLong(); + return new UUID(mostSignificant, leastSignificant); + } + + public static UUID getUUIDOf(String name) throws Exception { + return new UUIDFetcher(Arrays.asList(name)).call().get(name); + } +} \ No newline at end of file diff --git a/src/main/java/com/legacyminecraft/poseidon/util/UUIDResult.java b/src/main/java/com/legacyminecraft/poseidon/util/UUIDResult.java new file mode 100644 index 0000000..ab88987 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/util/UUIDResult.java @@ -0,0 +1,37 @@ +package com.legacyminecraft.poseidon.util; + +import java.util.UUID; + +public class UUIDResult { + private final UUID uuid; + private final ReturnType returnType; + private Exception exception; + + public UUIDResult(UUID uuid, ReturnType returnType) { + this.uuid = uuid; + this.returnType = returnType; + } + + public UUID getUuid() { + return uuid; + } + + public ReturnType getReturnType() { + return returnType; + } + + public Exception getException() { + return exception; + } + + public void setException(Exception exception) { + this.exception = exception; + } + + + public enum ReturnType { + ONLINE, + OFFLINE, + API_OFFLINE + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/utility/PerformanceStatistic.java b/src/main/java/com/legacyminecraft/poseidon/utility/PerformanceStatistic.java new file mode 100644 index 0000000..8b345f5 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/utility/PerformanceStatistic.java @@ -0,0 +1,50 @@ +package com.legacyminecraft.poseidon.utility; + +public class PerformanceStatistic { + private long minTime = Long.MAX_VALUE; + private long maxTime = 0; + private long totalTime = 0; + private long count = 0; + + // Update the stats with a new execution time + public void update(long duration) { + if (duration < minTime) { + minTime = duration; + } + if (duration > maxTime) { + maxTime = duration; + } + totalTime += duration; + count++; + } + + // Retrieve the average execution time + long getAverageTime() { + return count > 0 ? totalTime / count : 0; + } + + // Print the statistics for this listener + public String printStats() { + return String.format("Called: %d times, Min: %dms, Avg: %dms, Max: %dms", count, minTime, getAverageTime(), maxTime); + } + + public long getEventCount() { + return count; + } + + public long getTotalExecutionTime() { + return totalTime; + } + + public long getAverageExecutionTime() { + return getAverageTime(); + } + + public long getMinExecutionTime() { + return minTime; + } + + public long getMaxExecutionTime() { + return maxTime; + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/utility/PoseidonVersionChecker.java b/src/main/java/com/legacyminecraft/poseidon/utility/PoseidonVersionChecker.java new file mode 100644 index 0000000..2d5a5d1 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/utility/PoseidonVersionChecker.java @@ -0,0 +1,96 @@ +package com.legacyminecraft.poseidon.utility; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.craftbukkit.CraftServer; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; + +public class PoseidonVersionChecker { + + private static final String GITHUB_API_URL = "https://api.github.com/repos/retromcorg/Project-Poseidon/releases/latest"; + private static final String releaseUrl = "https://github.com/retromcorg/Project-Poseidon/releases"; + private final String currentVersion; + private volatile String latestVersion; + private CraftServer server; + + public PoseidonVersionChecker(CraftServer server, String currentVersion) { + this.currentVersion = currentVersion; + this.latestVersion = currentVersion; // Assume the latest version is the current version until checked + this.server = server; + } + + /** + * Checks if a new version is available. + * + * @return true if a newer version is available, false otherwise. + */ + public synchronized boolean isUpdateAvailable() { + return latestVersion != null && !currentVersion.equalsIgnoreCase(latestVersion); + } + + /** + * Fetches the latest release version from GitHub API. + * + * @return the latest version as a String or null if fetching fails. + */ + public void fetchLatestVersion() { + HttpURLConnection connection = null; + try { + URL url = new URL(GITHUB_API_URL); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Accept", "application/json"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + + int responseCode = connection.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK) { + server.getLogger().log(Level.WARNING, "[Poseidon] Failed to check GitHub for latest version. HTTP Response Code: " + responseCode); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder response = new StringBuilder(); + String line; + + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + JSONParser parser = new JSONParser(); + JSONObject json = (JSONObject) parser.parse(response.toString()); + + this.latestVersion = (String) json.get("tag_name"); + + if (isUpdateAvailable()) { + server.getLogger().log(Level.INFO, "[Poseidon] A new version is available: " + latestVersion); + server.getLogger().log(Level.INFO, "[Poseidon] You are currently running version: " + currentVersion); + server.getLogger().log(Level.INFO, "[Poseidon] Download the latest version here: " + releaseUrl); + } else { + if (PoseidonConfig.getInstance().getConfigBoolean("settings.update-checker.notify-if-up-to-date.enabled")) + server.getLogger().log(Level.INFO, "[Poseidon] You are running the latest version (" + currentVersion + ") of Project Poseidon."); + } + } catch (Exception e) { + server.getLogger().log(Level.WARNING, "[Poseidon] Failed to check GitHub for latest version.", e); + } finally { + if (connection != null) { + connection.disconnect(); + } + } + } + + public String getCurrentVersion() { + return currentVersion; + } + + public String getLatestVersion() { + return latestVersion; + } +} diff --git a/src/main/java/com/legacyminecraft/poseidon/uuid/ThreadUUIDFetcher.java b/src/main/java/com/legacyminecraft/poseidon/uuid/ThreadUUIDFetcher.java new file mode 100644 index 0000000..df164c9 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/uuid/ThreadUUIDFetcher.java @@ -0,0 +1,117 @@ +package com.legacyminecraft.poseidon.uuid; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.util.GetUUIDFetcher; +import com.legacyminecraft.poseidon.util.UUIDResult; +import com.projectposeidon.johnymuffin.LoginProcessHandler; +import net.minecraft.server.Packet1Login; +import org.bukkit.ChatColor; + +import java.util.UUID; + +import static com.legacyminecraft.poseidon.util.UUIDFetcher.getUUIDOf; +import static com.projectposeidon.johnymuffin.UUIDManager.generateOfflineUUID; + +public class ThreadUUIDFetcher extends Thread { + + final Packet1Login loginPacket; + // final NetLoginHandler netLoginHandler; + final LoginProcessHandler loginProcessHandler; + final boolean useGetMethod; + + public ThreadUUIDFetcher(Packet1Login packet1Login, LoginProcessHandler loginProcessHandler, boolean useGetMethod) { +// this.netLoginHandler = netloginhandler; // The login handler + this.loginProcessHandler = loginProcessHandler; + this.loginPacket = packet1Login; // The login packet + this.useGetMethod = useGetMethod; + + } + + public void run() { + if (PoseidonConfig.getInstance().getBoolean("settings.uuid-fetcher.always-use-graceful-uuids.enabled", false)) { + System.out.println("[Poseidon] Skipping UUID fetching since always-use-graceful-uuids is enabled, " + loginPacket.name + " will use offline UUID."); + UUID offlineUUID = generateOfflineUUID(loginPacket.name); + loginProcessHandler.userUUIDReceived(offlineUUID, false); + return; + } else if (useGetMethod) { + getMethod(); + } else { + postMethod(); + } + + } + + public void getMethod() { + UUIDResult uuidResult; + GetUUIDFetcher.UUIDAndUsernameResult uuidAndUsernameResult = GetUUIDFetcher.getUUID(loginPacket.name); + uuidResult = uuidAndUsernameResult.getUuidResult(); + + if (uuidResult.getReturnType().equals(UUIDResult.ReturnType.ONLINE) && uuidAndUsernameResult.getReturnedUsername().equals(loginPacket.name)) { + System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " using GET - " + uuidResult.getUuid().toString()); + loginProcessHandler.userUUIDReceived(uuidResult.getUuid(), true); + return; + } else if (uuidResult.getReturnType().equals(UUIDResult.ReturnType.ONLINE)) { + if(PoseidonConfig.getInstance().getConfigBoolean("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled")) { + System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " using GET - " + uuidResult.getUuid().toString() + " however, the username returned was " + uuidAndUsernameResult.getReturnedUsername() + ". The user has been kicked as the server is configured to use case sensitive usernames"); + loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, that username has invalid casing"); + return; + } else { + System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " - " + uuidResult.getUuid().toString()); + loginProcessHandler.userUUIDReceived(uuidResult.getUuid(), true); + return; + } + } else if (uuidResult.getReturnType().equals(UUIDResult.ReturnType.OFFLINE)) { + if ((boolean) PoseidonConfig.getInstance().getProperty("settings.uuid-fetcher.allow-graceful-uuids.value")) { + System.out.println("[Poseidon] " + loginPacket.name + " does not have a Mojang UUID associated with their name"); + UUID offlineUUID = uuidResult.getUuid(); + loginProcessHandler.userUUIDReceived(offlineUUID, false); + System.out.println("[Poseidon] Using Offline Based UUID for " + loginPacket.name + " - " + offlineUUID); + } else { + System.out.println("[Poseidon] " + loginPacket.name + " does not have a UUID with Mojang. Player has been kicked as graceful UUID is disabled"); + loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we only support premium accounts"); + } + return; + } + System.out.println("[Poseidon] Failed to fetch UUID for " + loginPacket.name + " using GET method from Mojang."); + System.out.println("[Poseidon] Mojang's API may be offline, your internet connection may be down, or something else may be wrong."); + + uuidResult.getException().printStackTrace(); + loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we can't connect to Mojang currently, please try again later"); + + } + + + public void postMethod() { + UUID uuid; + try { + uuid = getUUIDOf(loginPacket.name); + if (uuid == null) { + if (PoseidonConfig.getInstance().getConfigBoolean("settings.uuid-fetcher.allow-graceful-uuids.value", true)) { + System.out.println("[Poseidon] " + loginPacket.name + " does not have a Mojang UUID associated with their name"); + UUID offlineUUID = generateOfflineUUID(loginPacket.name); + loginProcessHandler.userUUIDReceived(offlineUUID, false); + System.out.println("[Poseidon] Using Offline Based UUID for " + loginPacket.name + " - " + offlineUUID); + } else { + System.out.println("[Poseidon] " + loginPacket.name + " does not have a UUID with Mojang. Player has been kicked as graceful UUID is disabled"); + loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we only support premium accounts"); + } + } else { + System.out.println("[Poseidon] Fetched UUID from Mojang for " + loginPacket.name + " using POST - " + uuid.toString()); + loginProcessHandler.userUUIDReceived(uuid, true); + } + } catch (Exception e) { + System.out.println("[Poseidon] Mojang failed contact for user " + loginPacket.name + ":"); + + System.out.println("[Poseidon] If this issue persists, please utilize the GET method. Mojang's API frequently has issues with POST requests."); + System.out.println("[Poseidon] You can do this by changing settings.uuid-fetcher.method.value to GET in the config"); + + e.printStackTrace(); + loginProcessHandler.cancelLoginProcess(ChatColor.RED + "Sorry, we can't connect to Mojang currently, please try again later"); + } + + } + + +} + + diff --git a/src/main/java/com/legacyminecraft/poseidon/watchdog/WatchDogThread.java b/src/main/java/com/legacyminecraft/poseidon/watchdog/WatchDogThread.java new file mode 100644 index 0000000..5b29f76 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/watchdog/WatchDogThread.java @@ -0,0 +1,72 @@ +package com.legacyminecraft.poseidon.watchdog; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; + +public class WatchDogThread extends Thread { + private int count = 0; + private Long lastTick = System.currentTimeMillis() / 1000L; + private volatile AtomicBoolean tickOccurred = new AtomicBoolean(true); + private Thread serverThread; + private final int killTimeout; + //Debug Timeout + private final boolean debugTimeoutEnabled; + private final int debugTimeout; + private boolean printedDebug; + + public WatchDogThread(Thread thread) { + this.serverThread = thread; + this.killTimeout = PoseidonConfig.getInstance().getConfigInteger("settings.watchdog.timeout.value"); + + this.debugTimeoutEnabled = PoseidonConfig.getInstance().getConfigBoolean("settings.watchdog.debug-timeout.enabled"); + this.debugTimeout = PoseidonConfig.getInstance().getConfigInteger("settings.watchdog.debug-timeout.value"); + } + + public void run() { + boolean running = true; + while (true && !this.isInterrupted() && running) { + try { + if (tickOccurred.get()) { + lastTick = System.currentTimeMillis() / 1000L; + tickOccurred.set(false); + printedDebug = false; //Set back tp false so if server hangs again debug is printed. + } else { + //Server timout check + if ((lastTick + killTimeout) < (System.currentTimeMillis() / 1000L)) { + System.out.println("[Poseidon-Watchdog] Server has hanged. Killing the process as a result of the watchdog timeout being exceeded."); + System.out.println("--------------------[Stacktrace For Developers]--------------------"); + Arrays.asList(serverThread.getStackTrace()).forEach(System.out::println); + System.out.println("-------------------------------------------------------------------"); + Runtime.getRuntime().halt(0); + + } else { + System.out.println("[Poseidon-Watchdog] A server tick hasn't occurred in " + ((int) ((System.currentTimeMillis() / 1000L) - lastTick)) + " seconds."); + //Server debug timeout + if((lastTick + debugTimeout) < (System.currentTimeMillis() / 1000L) && debugTimeoutEnabled && !printedDebug) { + System.out.println("[Poseidon-Watchdog] Server hang detected. Printing debug as debug timeout has been exceeded."); + System.out.println("--------------------[Stacktrace For Developers]--------------------"); + Arrays.asList(serverThread.getStackTrace()).forEach(System.out::println); + System.out.println("-------------------------------------------------------------------"); + printedDebug = true; //This variable prevents debug from printing multiple times during a single tick. + } + } + } + Thread.sleep(3000L); + } catch (InterruptedException e) { + System.out.println("[Poseidon-Watchdog] The watchdog has been interrupted."); +// e.printStackTrace(); + running = false; + } + } + } + + public void tickUpdate() { + tickOccurred.set(true); + } + + public boolean isHangDetected() { + return tickOccurred.get(); + } +} diff --git a/src/main/java/com/projectposeidon/ConnectionType.java b/src/main/java/com/projectposeidon/ConnectionType.java new file mode 100644 index 0000000..4f76152 --- /dev/null +++ b/src/main/java/com/projectposeidon/ConnectionType.java @@ -0,0 +1,11 @@ +package com.projectposeidon; + +public enum ConnectionType { + NORMAL, + RELEASE2BETA, + RELEASE2BETA_ONLINE_MODE_IP_FORWARDING, + RELEASE2BETA_OFFLINE_MODE_IP_FORWARDING, + BUNGEECORD, + BUNGEECORD_OFFLINE_MODE_IP_FORWARDING, + BUNGEECORD_ONLINE_MODE_IP_FORWARDING, +} diff --git a/src/main/java/com/projectposeidon/README b/src/main/java/com/projectposeidon/README new file mode 100644 index 0000000..9203681 --- /dev/null +++ b/src/main/java/com/projectposeidon/README @@ -0,0 +1,2 @@ +We will no longer store classes under the name of the developer who created it. Current legacy stuff may stay in its current position tho. +All new classes must be created under com.legacyminecraft.poseidon \ No newline at end of file diff --git a/src/main/java/com/projectposeidon/api/PoseidonUUID.java b/src/main/java/com/projectposeidon/api/PoseidonUUID.java new file mode 100644 index 0000000..78dab4e --- /dev/null +++ b/src/main/java/com/projectposeidon/api/PoseidonUUID.java @@ -0,0 +1,71 @@ +package com.projectposeidon.api; + +import com.projectposeidon.johnymuffin.UUIDManager; + +import java.util.UUID; + +public final class PoseidonUUID { + + private PoseidonUUID() { + + } + + /** + * @param username Username of a player who has connected + * @return A Mojang UUID if known, otherwise null + */ + public static UUID getPlayerMojangUUID(String username) { + return UUIDManager.getInstance().getUUIDFromUsername(username, true); + } + + /** + * @param username Username of a player who has connected + * @return A Mojang UUID if known, otherwise a offline uuid + */ + public static UUID getPlayerGracefulUUID(String username) { + return UUIDManager.getInstance().getUUIDGraceful(username); + } + + /** + * Get a UUID of a player IF they have joined before. + * + * @param username Username of a player who has connected + * @param onlineUUID Search for online or offline UUIDs? + * @return Returns a UUID if known in cache, otherwise null + */ + public static UUID getPlayerUUIDFromCache(String username, boolean onlineUUID) { + return UUIDManager.getInstance().getUUIDFromUsername(username, onlineUUID); + } + + /** + * @param username Username of a player + * @return A offline UUID for a player + */ + public static UUID getPlayerOfflineUUID(String username) { + return UUIDManager.generateOfflineUUID(username); + } + + /** + * @param username Username of a player + * @return A UUIDType enum. + */ + public static UUIDType getPlayerUUIDCacheStatus(String username) { + if (getPlayerUUIDFromCache(username, true) != null) { + return UUIDType.ONLINE; + } + if (getPlayerUUIDFromCache(username, false) != null) { + return UUIDType.OFFLINE; + } + return UUIDType.UNKNOWN; + } + + /** + * @param uuid UUID for a player + * @return A corresponding username if known, otherwise null + */ + public static String getPlayerUsernameFromUUID(UUID uuid) { + return UUIDManager.getInstance().getUsernameFromUUID(uuid); + } + + +} diff --git a/src/main/java/com/projectposeidon/api/UUIDType.java b/src/main/java/com/projectposeidon/api/UUIDType.java new file mode 100644 index 0000000..7682b82 --- /dev/null +++ b/src/main/java/com/projectposeidon/api/UUIDType.java @@ -0,0 +1,9 @@ +package com.projectposeidon.api; + +public enum UUIDType { + //I was not sure about the coding conventions regarding capitalization. I have followed the ALL caps example in the Java Docs: https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html + ONLINE, + OFFLINE, + UNKNOWN + +} diff --git a/src/main/java/com/projectposeidon/johnymuffin/ConnectionPause.java b/src/main/java/com/projectposeidon/johnymuffin/ConnectionPause.java new file mode 100644 index 0000000..008ce8e --- /dev/null +++ b/src/main/java/com/projectposeidon/johnymuffin/ConnectionPause.java @@ -0,0 +1,72 @@ +package com.projectposeidon.johnymuffin; + +public class ConnectionPause { + private String pluginName; + private String connectionPauseName; + private LoginProcessHandler loginProcessHandler; + private long creationTime; + + private long completionTime; + private boolean active; + + public ConnectionPause(String PluginName, String connectionPauseName, LoginProcessHandler loginProcessHandler) { + this.pluginName = PluginName; + this.connectionPauseName = connectionPauseName; + this.loginProcessHandler = loginProcessHandler; + this.creationTime = System.currentTimeMillis(); + this.active = true; + } + + /** + * This method is still undecided, please don't use it in production. + */ + public void removeConnectionPause() { + loginProcessHandler.removeConnectionPause(this); + } + + public String getPluginName() { + return this.pluginName; + } + + public String getConnectionPauseName() { + return this.connectionPauseName; + } + + + public long getCreationTime() { + return creationTime; + } + + public boolean isActive() { + return active; + } + + /** + * This method is for Poseidon, not plugin use. DON'T TOUCH THIS IF YOU DON'T KNOW WHAT YOU ARE DOING. + */ + public void setActive(boolean active) { + if(!active) + this.completionTime = System.currentTimeMillis(); + this.active = active; + } + + public int getRunningTime() { + int running; + if (active) { + running = (int) (System.currentTimeMillis() - creationTime); + } else { + running = (int) (completionTime - creationTime); + } + running = running / 1000; + return running; + } + + + public LoginProcessHandler getLoginProcessHandler() { + return loginProcessHandler; + } + + public long getCompletionTime() { + return completionTime; + } +} diff --git a/src/main/java/com/projectposeidon/johnymuffin/LoginProcessHandler.java b/src/main/java/com/projectposeidon/johnymuffin/LoginProcessHandler.java new file mode 100644 index 0000000..ae591af --- /dev/null +++ b/src/main/java/com/projectposeidon/johnymuffin/LoginProcessHandler.java @@ -0,0 +1,381 @@ +package com.projectposeidon.johnymuffin; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.PoseidonPlugin; +import com.legacyminecraft.poseidon.uuid.ThreadUUIDFetcher; +import net.minecraft.server.NetLoginHandler; +import net.minecraft.server.Packet1Login; +import net.minecraft.server.ThreadLoginVerifier; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerConnectionInitializationEvent; +import org.bukkit.event.player.PlayerPreLoginEvent; +import org.bukkit.plugin.Plugin; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.UUID; + +public class LoginProcessHandler { + + private NetLoginHandler netLoginHandler; + private final Packet1Login packet1Login; + private CraftServer server; + private boolean onlineMode; + private boolean loginCancelled = false; + private LoginProcessHandler loginProcessHandler; + private boolean loginSuccessful = false; + private long startTime; + + private HashSet connectionPauses = new HashSet(); + + private final String msgKickAlreadyOnline; + + public LoginProcessHandler(NetLoginHandler netloginhandler, Packet1Login packet1login, CraftServer server, boolean onlineMode) { + this.loginProcessHandler = this; + this.netLoginHandler = netloginhandler; + this.packet1Login = packet1login; + this.server = server; + this.onlineMode = onlineMode; + + this.msgKickAlreadyOnline = PoseidonConfig.getInstance().getConfigString("message.kick.already-online"); + + processAuthentication(); + + long connectionStartTime = System.currentTimeMillis() / 1000L; + runLoginTimer(connectionStartTime); + + } + + private void runLoginTimer(long connectionStartTime) { + Bukkit.getScheduler().scheduleAsyncDelayedTask(new PoseidonPlugin(), () -> { + int currentRunningTime = (int) (System.currentTimeMillis() / 1000L - connectionStartTime); + if (!loginSuccessful && !loginCancelled) { + //This if statement shouldn't be needed, but this is here just in case a players login fails but the appropriate variables aren't changed + System.out.println("[Poseidon] The login process for " + packet1Login.name + " is still running. It has been running for " + currentRunningTime + " seconds. The following plugins are still currently pausing the login process: " + getConnectionPauseNames(true)); + + //Cancel the login process if it has been running for more than 20 seconds. + if (currentRunningTime >= 20) { + cancelLoginProcess("Login Process Handler Timeout"); + System.out.println("[Poseidon] LoginProcessHandler for user " + packet1Login.name + " has failed to respond after 20 seconds. And future calls to this class will result in error"); + System.out.println("[Poseidon] Plugin Pauses: " + getConnectionPauseNames(true)); + } + + if (currentRunningTime < 60) { + runLoginTimer(connectionStartTime); + } + } + }, 20 * 5); + } + + private void processAuthentication() { + PlayerConnectionInitializationEvent event = new PlayerConnectionInitializationEvent(this.packet1Login.name, this.netLoginHandler.getSocket().getInetAddress(), loginProcessHandler); + this.server.getPluginManager().callEvent(event); + if (loginCancelled) { + return; + } + + if (onlineMode) { + //Server is running online mode + verifyMojangSession(); + } else { + //Server is not running online mode + getUserUUID(); + } + } + + private void getUserUUID() { + //UUID uuid = UUIDManager.getInstance().getUUIDFromUsername(packet1Login.name, true); + long unixTime = (System.currentTimeMillis() / 1000L); + UUID uuid = UUIDManager.getInstance().getUUIDFromUsername(packet1Login.name, true, unixTime); + if (uuid == null) { + boolean useGetMethod = PoseidonConfig.getInstance().getString("settings.uuid-fetcher.method.value", "POST").equalsIgnoreCase("GET"); + (new ThreadUUIDFetcher(packet1Login, this, useGetMethod)).start(); + } else { + System.out.println("[Poseidon] Fetched UUID from Cache for " + packet1Login.name + " - " + uuid.toString()); + connectPlayer(uuid); + } + + + } + + public synchronized void userUUIDReceived(UUID uuid, boolean onlineMode) { + if (!onlineMode) { + if (Boolean.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.enabled", true))) && !isUsernameValid()) { + //Username is invalid, and is a cracked user + return; + } + } + + // Connect the player based on their mode + if(onlineMode) { + // Handle saving the UUID for online mode user here + long unixTime = (System.currentTimeMillis() / 1000L) + 1382400; + UUIDManager.getInstance().receivedUUID(packet1Login.name, uuid, unixTime, onlineMode); + + connectPlayerPremium(uuid); + } else { + // Handle saving the UUID for cracked user inside connectPlayerCracked method as it may need to be modified + + connectPlayerCracked(uuid); + } + + } + + public void connectPlayerPremium(UUID uuid) { + connectPlayer(uuid); + } + + public void connectPlayerCracked(UUID uuid) { + // Append . to the start of the username if not already present and generate offline UUID based on that + + String username = this.packet1Login.name; + + if (Boolean.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.enabled", true))) && !isUsernameValid()) { + //Username is invalid, and is a cracked user + return; + } + + boolean prefixDot = PoseidonConfig.getInstance().getConfigBoolean("settings.cracked-username-prefix.enabled", false); + + if(prefixDot) { + if (!username.startsWith(".")) { + System.out.println("[Poseidon] Adding . prefix to cracked user " + username + "'s username"); + username = "." + username; + } + + // Rename the player to have the . prefix + this.packet1Login.name = username; + netLoginHandler.updateUsername(username); + } + + UUID offlineUUID = UUIDManager.generateOfflineUUID(username); + // Add new UUID entry for cracked user + long expiresOn = (System.currentTimeMillis() / 1000L) + 1382400; + UUIDManager.getInstance().receivedUUID(username, offlineUUID, expiresOn, false); + + connectPlayer(offlineUUID); + } + + //This function is only run if the user is cracked + public boolean isUsernameValid() { + String username = this.packet1Login.name; + + // Ensure the username length is valid + int minimumLength = Integer.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.min-length", 3))); + int maximumLength = Integer.valueOf(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.max-length", 16))); + + if (username.length() < minimumLength) { + cancelLoginProcess("Sorry, your username is too short. The minimum length is: " + minimumLength); + return false; + } + + // Remove the . prefix for validation if it exists and the server is configured to use it. + boolean prefixDot = PoseidonConfig.getInstance().getConfigBoolean("settings.cracked-username-prefix.enabled", false); + boolean dotAdded = false; + if(prefixDot) { + if (username.startsWith(".")) { + username = username.substring(1); + dotAdded = true; + } + } + + if (username.length() > maximumLength) { + cancelLoginProcess("Sorry, your username is too long. The maximum length is: " + (dotAdded ? (maximumLength - 1) : maximumLength)); // Adjust max length if dot was automatically added + return false; + } + + if (username.isEmpty()) { + cancelLoginProcess("Sorry, you don't have a username, messing with MC?????"); + return false; + } + + String regex = String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.check-username-validity.regex", "[a-zA-Z0-9_?]*")); + + if (!username.matches(regex)) { + cancelLoginProcess("Sorry, your username is invalid, allowed characters: " + regex); + return false; + } + + return true; + } + + + private void verifyMojangSession() { + if (!loginSuccessful & !loginCancelled) { + (new ThreadLoginVerifier(this, netLoginHandler, this.packet1Login, this.server)).start(); // CraftBukkit + } + } + + public synchronized void userMojangSessionVerified() { + if (!loginSuccessful & !loginCancelled) { + getUserUUID(); + } + } + + private void connectPlayer(UUID uuid) { + String username = packet1Login.name; + //Check if a player with the same UUID or Username is already online which is mainly an issue in Offline Mode servers. + for (Player p : server.getOnlinePlayers()) { + if (p.getName().equalsIgnoreCase(username) || p.getUniqueId().equals(uuid)) { + cancelLoginProcess(this.msgKickAlreadyOnline); + System.out.println("[Poseidon] User " + username + " has been blocked from connecting as they share a username or UUID with a user who is already online called " + p.getName() + + "\nMost likely the user has changed their UUID or the server is running in offline mode and someone has attempted to connect with their name"); + } + } + + + if (!loginSuccessful && !loginCancelled) { + + //Bukkit Login Event Start + if (this.netLoginHandler.getSocket() == null) { + return; + } + + + PlayerPreLoginEvent event = new PlayerPreLoginEvent(this.packet1Login.name, ((InetSocketAddress) netLoginHandler.networkManager.getSocketAddress()).getAddress(), loginProcessHandler); + this.server.getPluginManager().callEvent(event); + if (event.getResult() != PlayerPreLoginEvent.Result.ALLOWED) { + cancelLoginProcess(event.getKickMessage()); + return; + } + //Bukkit Login Event End + if (isPlayerConnectionPaused()) { + startTime = System.currentTimeMillis() / 1000L; + } else { + loginSuccessful = true; + NetLoginHandler.a(netLoginHandler, packet1Login); + } + } + } + + /** + * Cancel a players login before join or login events + */ + public void cancelLoginProcess(String s) { + if (!loginCancelled && !loginSuccessful) { + loginCancelled = true; + netLoginHandler.disconnect(s); + } + } + + /** + * Set a pause for your plugin + * Connection pauses are for fetching data for a player before they MIGHT be allowed to join + * + * @param plugin Instance of plugin + * @param connectionPauseName Name of connection pause (Ensure no duplicates) + * @return ConnectionPause Object, used to remove a connection pause + */ + public ConnectionPause addConnectionInterrupt(Plugin plugin, String connectionPauseName) { + final ConnectionPause connectionPause = new ConnectionPause(plugin.getDescription().getName(), connectionPauseName, loginProcessHandler); + connectionPauses.add(connectionPause); + return connectionPause; + } + + @Deprecated + public void removeConnectionPause(ConnectionPause connectionPause) { + removeConnectionInterrupt(connectionPause); + } + + /** + * Remove a connection pause + * + * @param connectionPause ConnectionPause object + */ + public void removeConnectionInterrupt(ConnectionPause connectionPause) { + //Check if the connection pause is registered and active + if (!connectionPauses.contains(connectionPause)) { + System.out.println("[Poseidon] A plugin has tried to remove a connection pause from the player " + packet1Login.name + " called " + connectionPause.getConnectionPauseName() + + " from the plugin " + connectionPause.getPluginName() + ". Please contact the plugin author and get them to check their logic as this is a duplicate remove, or a pause for another player."); + return; + } + //Handle the completion of the pause + connectionPause.setActive(false); + //If there are no more pauses, connect the player + if (!isPlayerConnectionPaused()) { + long endTime = System.currentTimeMillis() / 1000L; + int timeTaken = (int) (endTime - startTime); + + //If a pause has cancelled the login, don't connect the player + if (loginCancelled) { + System.out.println("[Poseidon] Player " + loginProcessHandler.packet1Login.name + " was not allowed to join after being on hold for " + timeTaken + " seconds by the following plugins: " + getConnectionPauseNames(false)); + return; + } + + this.setLoginSuccessful(true); + System.out.println("[Poseidon] Player " + loginProcessHandler.packet1Login.name + " has been allowed to join after being on hold for " + timeTaken + " seconds by the following plugins: " + getConnectionPauseNames(false)); + NetLoginHandler.a(netLoginHandler, packet1Login); + } + } + + + public ConnectionPause[] getActiveConnectionPauses() { + HashSet activePauses = new HashSet<>(); + for (ConnectionPause connectionPause : connectionPauses) { + if (connectionPause.isActive()) { + activePauses.add(connectionPause); + } + } + return activePauses.toArray(new ConnectionPause[activePauses.size()]); + } + + public String getConnectionPauseNames(boolean activeOnly) { + + StringBuilder pauseNames = new StringBuilder(); + for (ConnectionPause connectionPause : connectionPauses) { + String pluginName = connectionPause.getPluginName(); + String pauseName = connectionPause.getConnectionPauseName(); + boolean isActive = connectionPause.isActive(); + int time = connectionPause.getRunningTime(); + if (activeOnly) { + if (connectionPause.isActive()) { + pauseNames.append(pluginName).append(":").append(pauseName).append(":").append(isActive ? "Running" : "Complete").append(":").append(time).append("-Seconds, "); + } + } else { + pauseNames.append(pluginName).append(":").append(pauseName).append(":").append(isActive ? "Running" : "Complete").append(":").append(time).append("-Seconds, "); + } + } + return pauseNames.toString(); + } + + + private ConnectionPause legacyConnectionPause; + + /** + * Set a pause for your plugin + * Connection pauses are for fetching data for a player before they MIGHT be allowed to join + */ + @Deprecated + public void addConnectionPause(Plugin plugin) throws Exception { + System.out.println("[Poseidon] " + plugin.getDescription().getName() + " is using the deprecated connection pause system which will be removed in the future. Contact the plugin author to get an updated version."); + legacyConnectionPause = addConnectionInterrupt(plugin, "Legacy-Connection-Pause"); + } + + /** + * Remove a pause for your plugin + */ + @Deprecated + public void removeConnectionPause(Plugin plugin) { + if (legacyConnectionPause != null) { + removeConnectionInterrupt(legacyConnectionPause); + return; + } + System.out.println("[Poseidon] " + plugin.getDescription().getName() + " Attempted to remove a legacy (deprecated) connection pause that was never added. Please contact the plugin author and get them to check their logic and update to the new connection pause system."); + } + + /** + * See if the players connection currently paused + */ + public boolean isPlayerConnectionPaused() { + return getActiveConnectionPauses().length > 0; + } + + + private void setLoginSuccessful(boolean loginSuccessful) { + this.loginSuccessful = loginSuccessful; + } +} diff --git a/src/main/java/com/projectposeidon/johnymuffin/UUIDManager.java b/src/main/java/com/projectposeidon/johnymuffin/UUIDManager.java new file mode 100644 index 0000000..5fbbd4f --- /dev/null +++ b/src/main/java/com/projectposeidon/johnymuffin/UUIDManager.java @@ -0,0 +1,200 @@ +package com.projectposeidon.johnymuffin; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.legacyminecraft.poseidon.PoseidonConfig; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class UUIDManager { + private static UUIDManager singleton; + private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + private final File cacheFile = new File("uuidcache.json"); + + private final Map> usernameCache = new ConcurrentHashMap<>(); + private final Map> uuidCache = new ConcurrentHashMap<>(); + + private List uuidCacheList; + + private UUIDManager() { + if (!cacheFile.exists()) { + try (FileWriter writer = new FileWriter(cacheFile)) { + System.out.println("[Poseidon] Generating uuidcache.json for Project Poseidon"); + uuidCacheList = new ArrayList<>(); + gson.toJson(uuidCacheList, writer); + } catch (IOException e) { + e.printStackTrace(); + } + } + + try (FileReader reader = new FileReader(cacheFile)) { + System.out.println("[Poseidon] Reading uuidcache.json for Project Poseidon"); + Type listType = new TypeToken>() {}.getType(); + uuidCacheList = gson.fromJson(reader, listType); + if (uuidCacheList == null) uuidCacheList = new ArrayList<>(); + } catch (Exception e) { + System.out.println("[Poseidon] UUID cache corrupt or unreadable, resetting: " + e); + uuidCacheList = new ArrayList<>(); + saveJsonArray(); + } + + rebuildCaches(); + } + + public static UUIDManager getInstance() { + if (singleton == null) { + singleton = new UUIDManager(); + } + return singleton; + } + + + private void rebuildCaches() { + usernameCache.clear(); + uuidCache.clear(); + + for (UUIDEntry entry : uuidCacheList) { + usernameCache.computeIfAbsent(entry.name.toLowerCase(), k -> new ArrayList<>()).add(entry); + uuidCache.computeIfAbsent(entry.uuid, k -> new ArrayList<>()).add(entry); + } + } + + private void addToCaches(UUIDEntry entry) { + usernameCache.computeIfAbsent(entry.name.toLowerCase(), k -> new ArrayList<>()).add(entry); + uuidCache.computeIfAbsent(entry.uuid, k -> new ArrayList<>()).add(entry); + } + + private void removeFromCaches(UUIDEntry entry) { + List userEntries = usernameCache.get(entry.name.toLowerCase()); + if (userEntries != null) userEntries.remove(entry); + List uuidEntries = uuidCache.get(entry.uuid); + if (uuidEntries != null) uuidEntries.remove(entry); + } + + public static UUID generateOfflineUUID(String username) { + // TODO: Update to modern system: UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)); + return UUID.nameUUIDFromBytes(username.getBytes()); + } + + public UUID getUUIDGraceful(String username) { + UUID uuid = getUUIDFromUsername(username, true); + return uuid != null ? uuid : generateOfflineUUID(username); + } + + public void saveJsonArray() { + try (FileWriter writer = new FileWriter(cacheFile)) { + gson.toJson(uuidCacheList, writer); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void receivedUUID(String username, UUID uuid, Long expiry, boolean online) { + // Check existing entry + List entries = usernameCache.getOrDefault(username.toLowerCase(), Collections.emptyList()); + for (UUIDEntry entry : entries) { + if (entry.uuid.equals(uuid) && entry.onlineUUID == online) { + entry.expiresOn = expiry; + return; + } + } + + removeInstancesOfUsername(username); + removeInstancesOfUUID(uuid); + + UUIDEntry newEntry = new UUIDEntry(username, uuid, expiry, online); + uuidCacheList.add(newEntry); + addToCaches(newEntry); + } + + + public UUID getUUIDFromUsername(String username) { + List entries = usernameCache.get(username.toLowerCase()); + if (entries != null && !entries.isEmpty()) { + return entries.get(0).uuid; + } + return null; + } + + public UUID getUUIDFromUsername(String username, boolean online) { + List entries = usernameCache.get(username.toLowerCase()); + if (entries != null) { + for (UUIDEntry entry : entries) { + if (entry.onlineUUID == online) { + return entry.uuid; + } + } + } + return null; + } + + public UUID getUUIDFromUsername(String username, boolean online, long afterUnix) { + List entries = usernameCache.get(username.toLowerCase()); + if (entries != null) { + for (UUIDEntry entry : entries) { + if (entry.onlineUUID == online && entry.expiresOn > afterUnix) { + return entry.uuid; + } + } + } + return null; + } + + public String getUsernameFromUUID(UUID uuid) { + List entries = uuidCache.get(uuid); + if (entries == null || entries.isEmpty()) return null; + + UUIDEntry newest = entries.get(0); + for (UUIDEntry entry : entries) { + if (entry.expiresOn > newest.expiresOn) { + newest = entry; + } + } + return newest.name; + } + + private void removeInstancesOfUsername(String username) { + List entries = usernameCache.get(username.toLowerCase()); + if (entries != null) { + for (UUIDEntry entry : new ArrayList<>(entries)) { + uuidCacheList.remove(entry); + removeFromCaches(entry); + } + } + } + + private void removeInstancesOfUUID(UUID uuid) { + List entries = uuidCache.get(uuid); + if (entries == null) return; + + for (UUIDEntry entry : new ArrayList<>(entries)) { + if ((boolean) PoseidonConfig.getInstance().getConfigOption("settings.delete-duplicate-uuids")) { + uuidCacheList.remove(entry); + removeFromCaches(entry); + } else { + entry.expiresOn = 1L; // mark as outdated + } + } + } + + protected class UUIDEntry { + public String name; + public UUID uuid; + public long expiresOn; + public boolean onlineUUID; + + public UUIDEntry(String name, UUID uuid, long expiresOn, boolean onlineUUID) { + this.name = name; + this.uuid = uuid; + this.expiresOn = expiresOn; + this.onlineUUID = onlineUUID; + } + } +} diff --git a/src/main/java/net/minecraft/server/Achievement.java b/src/main/java/net/minecraft/server/Achievement.java new file mode 100644 index 0000000..f196bf7 --- /dev/null +++ b/src/main/java/net/minecraft/server/Achievement.java @@ -0,0 +1,60 @@ +package net.minecraft.server; + +public class Achievement extends Statistic { + + public final int a; + public final int b; + public final Achievement c; + private final String l; + public final ItemStack d; + private boolean m; + + public Achievement(int i, String s, int j, int k, Item item, Achievement achievement) { + this(i, s, j, k, new ItemStack(item), achievement); + } + + public Achievement(int i, String s, int j, int k, Block block, Achievement achievement) { + this(i, s, j, k, new ItemStack(block), achievement); + } + + public Achievement(int i, String s, int j, int k, ItemStack itemstack, Achievement achievement) { + super(5242880 + i, StatisticCollector.a("achievement." + s)); + this.d = itemstack; + this.l = StatisticCollector.a("achievement." + s + ".desc"); + this.a = j; + this.b = k; + if (j < AchievementList.a) { + AchievementList.a = j; + } + + if (k < AchievementList.b) { + AchievementList.b = k; + } + + if (j > AchievementList.c) { + AchievementList.c = j; + } + + if (k > AchievementList.d) { + AchievementList.d = k; + } + + this.c = achievement; + } + + public Achievement a() { + this.g = true; + return this; + } + + public Achievement b() { + this.m = true; + return this; + } + + public Achievement c() { + super.d(); + AchievementList.e.add(this); + return this; + } +} diff --git a/src/main/java/net/minecraft/server/AchievementList.java b/src/main/java/net/minecraft/server/AchievementList.java new file mode 100644 index 0000000..f6b4a89 --- /dev/null +++ b/src/main/java/net/minecraft/server/AchievementList.java @@ -0,0 +1,37 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +public class AchievementList { + + public static int a; + public static int b; + public static int c; + public static int d; + public static List e = new ArrayList(); + public static Achievement f = (new Achievement(0, "openInventory", 0, 0, Item.BOOK, (Achievement) null)).a().c(); + public static Achievement g = (new Achievement(1, "mineWood", 2, 1, Block.LOG, f)).c(); + public static Achievement h = (new Achievement(2, "buildWorkBench", 4, -1, Block.WORKBENCH, g)).c(); + public static Achievement i = (new Achievement(3, "buildPickaxe", 4, 2, Item.WOOD_PICKAXE, h)).c(); + public static Achievement j = (new Achievement(4, "buildFurnace", 3, 4, Block.BURNING_FURNACE, i)).c(); + public static Achievement k = (new Achievement(5, "acquireIron", 1, 4, Item.IRON_INGOT, j)).c(); + public static Achievement l = (new Achievement(6, "buildHoe", 2, -3, Item.WOOD_HOE, h)).c(); + public static Achievement m = (new Achievement(7, "makeBread", -1, -3, Item.BREAD, l)).c(); + public static Achievement n = (new Achievement(8, "bakeCake", 0, -5, Item.CAKE, l)).c(); + public static Achievement o = (new Achievement(9, "buildBetterPickaxe", 6, 2, Item.STONE_PICKAXE, i)).c(); + public static Achievement p = (new Achievement(10, "cookFish", 2, 6, Item.COOKED_FISH, j)).c(); + public static Achievement q = (new Achievement(11, "onARail", 2, 3, Block.RAILS, k)).b().c(); + public static Achievement r = (new Achievement(12, "buildSword", 6, -1, Item.WOOD_SWORD, h)).c(); + public static Achievement s = (new Achievement(13, "killEnemy", 8, -1, Item.BONE, r)).c(); + public static Achievement t = (new Achievement(14, "killCow", 7, -3, Item.LEATHER, r)).c(); + public static Achievement u = (new Achievement(15, "flyPig", 8, -4, Item.SADDLE, t)).b().c(); + + public AchievementList() {} + + public static void a() {} + + static { + System.out.println(e.size() + " achievements"); + } +} diff --git a/src/main/java/net/minecraft/server/AchievementMap.java b/src/main/java/net/minecraft/server/AchievementMap.java new file mode 100644 index 0000000..ab48b19 --- /dev/null +++ b/src/main/java/net/minecraft/server/AchievementMap.java @@ -0,0 +1,35 @@ +package net.minecraft.server; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; + +public class AchievementMap { + + public static AchievementMap a = new AchievementMap(); + private Map b = new HashMap(); + + private AchievementMap() { + try { + BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(AchievementMap.class.getResourceAsStream("/achievement/map.txt"))); + + String s; + + while ((s = bufferedreader.readLine()) != null) { + String[] astring = s.split(","); + int i = Integer.parseInt(astring[0]); + + this.b.put(Integer.valueOf(i), astring[1]); + } + + bufferedreader.close(); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public static String a(int i) { + return (String) a.b.get(Integer.valueOf(i)); + } +} diff --git a/src/main/java/net/minecraft/server/AxisAlignedBB.java b/src/main/java/net/minecraft/server/AxisAlignedBB.java new file mode 100644 index 0000000..1a95cdf --- /dev/null +++ b/src/main/java/net/minecraft/server/AxisAlignedBB.java @@ -0,0 +1,334 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +public class AxisAlignedBB { + + private static List g = new ArrayList(); + private static int h = 0; + public double a; + public double b; + public double c; + public double d; + public double e; + public double f; + + public static AxisAlignedBB a(double d0, double d1, double d2, double d3, double d4, double d5) { + return new AxisAlignedBB(d0, d1, d2, d3, d4, d5); + } + + public static void a() { + h = 0; + } + + public static AxisAlignedBB b(double d0, double d1, double d2, double d3, double d4, double d5) { + if (h >= g.size()) { + g.add(a(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D)); + } + + return ((AxisAlignedBB) g.get(h++)).c(d0, d1, d2, d3, d4, d5); + } + + private AxisAlignedBB(double d0, double d1, double d2, double d3, double d4, double d5) { + this.a = d0; + this.b = d1; + this.c = d2; + this.d = d3; + this.e = d4; + this.f = d5; + } + + public AxisAlignedBB c(double d0, double d1, double d2, double d3, double d4, double d5) { + this.a = d0; + this.b = d1; + this.c = d2; + this.d = d3; + this.e = d4; + this.f = d5; + return this; + } + + public AxisAlignedBB a(double d0, double d1, double d2) { + double d3 = this.a; + double d4 = this.b; + double d5 = this.c; + double d6 = this.d; + double d7 = this.e; + double d8 = this.f; + + if (d0 < 0.0D) { + d3 += d0; + } + + if (d0 > 0.0D) { + d6 += d0; + } + + if (d1 < 0.0D) { + d4 += d1; + } + + if (d1 > 0.0D) { + d7 += d1; + } + + if (d2 < 0.0D) { + d5 += d2; + } + + if (d2 > 0.0D) { + d8 += d2; + } + + return b(d3, d4, d5, d6, d7, d8); + } + + public AxisAlignedBB b(double d0, double d1, double d2) { + double d3 = this.a - d0; + double d4 = this.b - d1; + double d5 = this.c - d2; + double d6 = this.d + d0; + double d7 = this.e + d1; + double d8 = this.f + d2; + + return b(d3, d4, d5, d6, d7, d8); + } + + public AxisAlignedBB c(double d0, double d1, double d2) { + return b(this.a + d0, this.b + d1, this.c + d2, this.d + d0, this.e + d1, this.f + d2); + } + + public double a(AxisAlignedBB axisalignedbb, double d0) { + if (axisalignedbb.e > this.b && axisalignedbb.b < this.e) { + if (axisalignedbb.f > this.c && axisalignedbb.c < this.f) { + double d1; + + if (d0 > 0.0D && axisalignedbb.d <= this.a) { + d1 = this.a - axisalignedbb.d; + if (d1 < d0) { + d0 = d1; + } + } + + if (d0 < 0.0D && axisalignedbb.a >= this.d) { + d1 = this.d - axisalignedbb.a; + if (d1 > d0) { + d0 = d1; + } + } + + return d0; + } else { + return d0; + } + } else { + return d0; + } + } + + public double b(AxisAlignedBB axisalignedbb, double d0) { + if (axisalignedbb.d > this.a && axisalignedbb.a < this.d) { + if (axisalignedbb.f > this.c && axisalignedbb.c < this.f) { + double d1; + + if (d0 > 0.0D && axisalignedbb.e <= this.b) { + d1 = this.b - axisalignedbb.e; + if (d1 < d0) { + d0 = d1; + } + } + + if (d0 < 0.0D && axisalignedbb.b >= this.e) { + d1 = this.e - axisalignedbb.b; + if (d1 > d0) { + d0 = d1; + } + } + + return d0; + } else { + return d0; + } + } else { + return d0; + } + } + + public double c(AxisAlignedBB axisalignedbb, double d0) { + if (axisalignedbb.d > this.a && axisalignedbb.a < this.d) { + if (axisalignedbb.e > this.b && axisalignedbb.b < this.e) { + double d1; + + if (d0 > 0.0D && axisalignedbb.f <= this.c) { + d1 = this.c - axisalignedbb.f; + if (d1 < d0) { + d0 = d1; + } + } + + if (d0 < 0.0D && axisalignedbb.c >= this.f) { + d1 = this.f - axisalignedbb.c; + if (d1 > d0) { + d0 = d1; + } + } + + return d0; + } else { + return d0; + } + } else { + return d0; + } + } + + public boolean a(AxisAlignedBB axisalignedbb) { + return axisalignedbb.d > this.a && axisalignedbb.a < this.d ? (axisalignedbb.e > this.b && axisalignedbb.b < this.e ? axisalignedbb.f > this.c && axisalignedbb.c < this.f : false) : false; + } + + public AxisAlignedBB d(double d0, double d1, double d2) { + this.a += d0; + this.b += d1; + this.c += d2; + this.d += d0; + this.e += d1; + this.f += d2; + return this; + } + + public boolean a(Vec3D vec3d) { + return vec3d.a > this.a && vec3d.a < this.d ? (vec3d.b > this.b && vec3d.b < this.e ? vec3d.c > this.c && vec3d.c < this.f : false) : false; + } + + public AxisAlignedBB shrink(double d0, double d1, double d2) { + double d3 = this.a + d0; + double d4 = this.b + d1; + double d5 = this.c + d2; + double d6 = this.d - d0; + double d7 = this.e - d1; + double d8 = this.f - d2; + + return b(d3, d4, d5, d6, d7, d8); + } + + public AxisAlignedBB clone() { + return b(this.a, this.b, this.c, this.d, this.e, this.f); + } + + public MovingObjectPosition a(Vec3D vec3d, Vec3D vec3d1) { + Vec3D vec3d2 = vec3d.a(vec3d1, this.a); + Vec3D vec3d3 = vec3d.a(vec3d1, this.d); + Vec3D vec3d4 = vec3d.b(vec3d1, this.b); + Vec3D vec3d5 = vec3d.b(vec3d1, this.e); + Vec3D vec3d6 = vec3d.c(vec3d1, this.c); + Vec3D vec3d7 = vec3d.c(vec3d1, this.f); + + if (!this.b(vec3d2)) { + vec3d2 = null; + } + + if (!this.b(vec3d3)) { + vec3d3 = null; + } + + if (!this.c(vec3d4)) { + vec3d4 = null; + } + + if (!this.c(vec3d5)) { + vec3d5 = null; + } + + if (!this.d(vec3d6)) { + vec3d6 = null; + } + + if (!this.d(vec3d7)) { + vec3d7 = null; + } + + Vec3D vec3d8 = null; + + if (vec3d2 != null && (vec3d8 == null || vec3d.b(vec3d2) < vec3d.b(vec3d8))) { + vec3d8 = vec3d2; + } + + if (vec3d3 != null && (vec3d8 == null || vec3d.b(vec3d3) < vec3d.b(vec3d8))) { + vec3d8 = vec3d3; + } + + if (vec3d4 != null && (vec3d8 == null || vec3d.b(vec3d4) < vec3d.b(vec3d8))) { + vec3d8 = vec3d4; + } + + if (vec3d5 != null && (vec3d8 == null || vec3d.b(vec3d5) < vec3d.b(vec3d8))) { + vec3d8 = vec3d5; + } + + if (vec3d6 != null && (vec3d8 == null || vec3d.b(vec3d6) < vec3d.b(vec3d8))) { + vec3d8 = vec3d6; + } + + if (vec3d7 != null && (vec3d8 == null || vec3d.b(vec3d7) < vec3d.b(vec3d8))) { + vec3d8 = vec3d7; + } + + if (vec3d8 == null) { + return null; + } else { + byte b0 = -1; + + if (vec3d8 == vec3d2) { + b0 = 4; + } + + if (vec3d8 == vec3d3) { + b0 = 5; + } + + if (vec3d8 == vec3d4) { + b0 = 0; + } + + if (vec3d8 == vec3d5) { + b0 = 1; + } + + if (vec3d8 == vec3d6) { + b0 = 2; + } + + if (vec3d8 == vec3d7) { + b0 = 3; + } + + return new MovingObjectPosition(0, 0, 0, b0, vec3d8); + } + } + + private boolean b(Vec3D vec3d) { + return vec3d == null ? false : vec3d.b >= this.b && vec3d.b <= this.e && vec3d.c >= this.c && vec3d.c <= this.f; + } + + private boolean c(Vec3D vec3d) { + return vec3d == null ? false : vec3d.a >= this.a && vec3d.a <= this.d && vec3d.c >= this.c && vec3d.c <= this.f; + } + + private boolean d(Vec3D vec3d) { + return vec3d == null ? false : vec3d.a >= this.a && vec3d.a <= this.d && vec3d.b >= this.b && vec3d.b <= this.e; + } + + public void b(AxisAlignedBB axisalignedbb) { + this.a = axisalignedbb.a; + this.b = axisalignedbb.b; + this.c = axisalignedbb.c; + this.d = axisalignedbb.d; + this.e = axisalignedbb.e; + this.f = axisalignedbb.f; + } + + public String toString() { + return "box[" + this.a + ", " + this.b + ", " + this.c + " -> " + this.d + ", " + this.e + ", " + this.f + "]"; + } +} diff --git a/src/main/java/net/minecraft/server/BedBlockTextures.java b/src/main/java/net/minecraft/server/BedBlockTextures.java new file mode 100644 index 0000000..156e2e3 --- /dev/null +++ b/src/main/java/net/minecraft/server/BedBlockTextures.java @@ -0,0 +1,10 @@ +package net.minecraft.server; + +public class BedBlockTextures { + + public static final int[] a = new int[] { 3, 4, 2, 5}; + public static final int[] b = new int[] { 2, 3, 0, 1}; + public static final int[][] c = new int[][] { { 1, 0, 3, 2, 5, 4}, { 1, 0, 5, 4, 2, 3}, { 1, 0, 2, 3, 4, 5}, { 1, 0, 4, 5, 3, 2}}; + + public BedBlockTextures() {} +} diff --git a/src/main/java/net/minecraft/server/BiomeBase.java b/src/main/java/net/minecraft/server/BiomeBase.java new file mode 100644 index 0000000..687e4e7 --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeBase.java @@ -0,0 +1,121 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class BiomeBase { + + public static final BiomeBase RAINFOREST = (new BiomeRainforest()).b(588342).a("Rainforest").a(2094168); + public static final BiomeBase SWAMPLAND = (new BiomeSwamp()).b(522674).a("Swampland").a(9154376); + public static final BiomeBase SEASONAL_FOREST = (new BiomeBase()).b(10215459).a("Seasonal Forest"); + public static final BiomeBase FOREST = (new BiomeForest()).b(353825).a("Forest").a(5159473); + public static final BiomeBase SAVANNA = (new BiomeDesert()).b(14278691).a("Savanna"); + public static final BiomeBase SHRUBLAND = (new BiomeBase()).b(10595616).a("Shrubland"); + public static final BiomeBase TAIGA = (new BiomeTaiga()).b(3060051).a("Taiga").b().a(8107825); + public static final BiomeBase DESERT = (new BiomeDesert()).b(16421912).a("Desert").e(); + public static final BiomeBase PLAINS = (new BiomeDesert()).b(16767248).a("Plains"); + public static final BiomeBase ICE_DESERT = (new BiomeDesert()).b(16772499).a("Ice Desert").b().e().a(12899129); + public static final BiomeBase TUNDRA = (new BiomeBase()).b(5762041).a("Tundra").b().a(12899129); + public static final BiomeBase HELL = (new BiomeHell()).b(16711680).a("Hell").e(); + public static final BiomeBase SKY = (new BiomeSky()).b(8421631).a("Sky").e(); + public String n; + public int o; + public byte p; + public byte q; + public int r; + protected List s; + protected List t; + protected List u; + private boolean v; + private boolean w; + private static BiomeBase[] x = new BiomeBase[4096]; + + protected BiomeBase() { + this.p = (byte) Block.GRASS.id; + this.q = (byte) Block.DIRT.id; + this.r = 5169201; + this.s = new ArrayList(); + this.t = new ArrayList(); + this.u = new ArrayList(); + this.w = true; + this.s.add(new BiomeMeta(EntitySpider.class, 10)); + this.s.add(new BiomeMeta(EntityZombie.class, 10)); + this.s.add(new BiomeMeta(EntitySkeleton.class, 10)); + this.s.add(new BiomeMeta(EntityCreeper.class, 10)); + this.s.add(new BiomeMeta(EntitySlime.class, 10)); + this.t.add(new BiomeMeta(EntitySheep.class, 12)); + this.t.add(new BiomeMeta(EntityPig.class, 10)); + this.t.add(new BiomeMeta(EntityChicken.class, 10)); + this.t.add(new BiomeMeta(EntityCow.class, 8)); + this.u.add(new BiomeMeta(EntitySquid.class, 10)); + } + + private BiomeBase e() { + this.w = false; + return this; + } + + public static void a() { + for (int i = 0; i < 64; ++i) { + for (int j = 0; j < 64; ++j) { + x[i + j * 64] = a((float) i / 63.0F, (float) j / 63.0F); + } + } + + DESERT.p = DESERT.q = (byte) Block.SAND.id; + ICE_DESERT.p = ICE_DESERT.q = (byte) Block.SAND.id; + } + + public WorldGenerator a(Random random) { + return (WorldGenerator) (random.nextInt(10) == 0 ? new WorldGenBigTree() : new WorldGenTrees()); + } + + protected BiomeBase b() { + this.v = true; + return this; + } + + protected BiomeBase a(String s) { + this.n = s; + return this; + } + + protected BiomeBase a(int i) { + this.r = i; + return this; + } + + protected BiomeBase b(int i) { + this.o = i; + return this; + } + + public static BiomeBase a(double d0, double d1) { + int i = (int) (d0 * 63.0D); + int j = (int) (d1 * 63.0D); + + return x[i + j * 64]; + } + + public static BiomeBase a(float f, float f1) { + f1 *= f; + return f < 0.1F ? TUNDRA : (f1 < 0.2F ? (f < 0.5F ? TUNDRA : (f < 0.95F ? SAVANNA : DESERT)) : (f1 > 0.5F && f < 0.7F ? SWAMPLAND : (f < 0.5F ? TAIGA : (f < 0.97F ? (f1 < 0.35F ? SHRUBLAND : FOREST) : (f1 < 0.45F ? PLAINS : (f1 < 0.9F ? SEASONAL_FOREST : RAINFOREST)))))); + } + + public List a(EnumCreatureType enumcreaturetype) { + return enumcreaturetype == EnumCreatureType.MONSTER ? this.s : (enumcreaturetype == EnumCreatureType.CREATURE ? this.t : (enumcreaturetype == EnumCreatureType.WATER_CREATURE ? this.u : null)); + } + + public boolean c() { + return this.v; + } + + public boolean d() { + return this.v ? false : this.w; + } + + static { + a(); + } +} diff --git a/src/main/java/net/minecraft/server/BiomeDesert.java b/src/main/java/net/minecraft/server/BiomeDesert.java new file mode 100644 index 0000000..e4815a6 --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeDesert.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +public class BiomeDesert extends BiomeBase { + + public BiomeDesert() {} +} diff --git a/src/main/java/net/minecraft/server/BiomeForest.java b/src/main/java/net/minecraft/server/BiomeForest.java new file mode 100644 index 0000000..48005be --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeForest.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BiomeForest extends BiomeBase { + + public BiomeForest() { + this.t.add(new BiomeMeta(EntityWolf.class, 2)); + } + + public WorldGenerator a(Random random) { + return (WorldGenerator) (random.nextInt(5) == 0 ? new WorldGenForest() : (random.nextInt(3) == 0 ? new WorldGenBigTree() : new WorldGenTrees())); + } +} diff --git a/src/main/java/net/minecraft/server/BiomeHell.java b/src/main/java/net/minecraft/server/BiomeHell.java new file mode 100644 index 0000000..08ee915 --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeHell.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +public class BiomeHell extends BiomeBase { + + public BiomeHell() { + this.s.clear(); + this.t.clear(); + this.u.clear(); + this.s.add(new BiomeMeta(EntityGhast.class, 10)); + this.s.add(new BiomeMeta(EntityPigZombie.class, 10)); + } +} diff --git a/src/main/java/net/minecraft/server/BiomeMeta.java b/src/main/java/net/minecraft/server/BiomeMeta.java new file mode 100644 index 0000000..3e32b12 --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeMeta.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +public class BiomeMeta { + + public Class a; + public int b; + + public BiomeMeta(Class oclass, int i) { + this.a = oclass; + this.b = i; + } +} diff --git a/src/main/java/net/minecraft/server/BiomeRainforest.java b/src/main/java/net/minecraft/server/BiomeRainforest.java new file mode 100644 index 0000000..5bdae2c --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeRainforest.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BiomeRainforest extends BiomeBase { + + public BiomeRainforest() {} + + public WorldGenerator a(Random random) { + return (WorldGenerator) (random.nextInt(3) == 0 ? new WorldGenBigTree() : new WorldGenTrees()); + } +} diff --git a/src/main/java/net/minecraft/server/BiomeSky.java b/src/main/java/net/minecraft/server/BiomeSky.java new file mode 100644 index 0000000..f920305 --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeSky.java @@ -0,0 +1,11 @@ +package net.minecraft.server; + +public class BiomeSky extends BiomeBase { + + public BiomeSky() { + this.s.clear(); + this.t.clear(); + this.u.clear(); + this.t.add(new BiomeMeta(EntityChicken.class, 10)); + } +} diff --git a/src/main/java/net/minecraft/server/BiomeSwamp.java b/src/main/java/net/minecraft/server/BiomeSwamp.java new file mode 100644 index 0000000..44c2a9b --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeSwamp.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +public class BiomeSwamp extends BiomeBase { + + public BiomeSwamp() {} +} diff --git a/src/main/java/net/minecraft/server/BiomeTaiga.java b/src/main/java/net/minecraft/server/BiomeTaiga.java new file mode 100644 index 0000000..45a53b0 --- /dev/null +++ b/src/main/java/net/minecraft/server/BiomeTaiga.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BiomeTaiga extends BiomeBase { + + public BiomeTaiga() { + this.t.add(new BiomeMeta(EntityWolf.class, 2)); + } + + public WorldGenerator a(Random random) { + return (WorldGenerator) (random.nextInt(3) == 0 ? new WorldGenTaiga1() : new WorldGenTaiga2()); + } +} diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java new file mode 100644 index 0000000..80d873a --- /dev/null +++ b/src/main/java/net/minecraft/server/Block.java @@ -0,0 +1,555 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class Block { + + public static final StepSound d = new StepSound("stone", 1.0F, 1.0F); + public static final StepSound e = new StepSound("wood", 1.0F, 1.0F); + public static final StepSound f = new StepSound("gravel", 1.0F, 1.0F); + public static final StepSound g = new StepSound("grass", 1.0F, 1.0F); + public static final StepSound h = new StepSound("stone", 1.0F, 1.0F); + public static final StepSound i = new StepSound("stone", 1.0F, 1.5F); + public static final StepSound j = new StepSoundStone("stone", 1.0F, 1.0F); + public static final StepSound k = new StepSound("cloth", 1.0F, 1.0F); + public static final StepSound l = new StepSoundSand("sand", 1.0F, 1.0F); + public static final Block[] byId = new Block[256]; + public static final boolean[] n = new boolean[256]; + public static final boolean[] o = new boolean[256]; + public static final boolean[] isTileEntity = new boolean[256]; + public static final int[] q = new int[256]; + public static final boolean[] r = new boolean[256]; + public static final int[] s = new int[256]; + public static final boolean[] t = new boolean[256]; + public static final Block STONE = (new BlockStone(1, 1)).c(1.5F).b(10.0F).a(h).a("stone"); + public static final BlockGrass GRASS = (BlockGrass) (new BlockGrass(2)).c(0.6F).a(g).a("grass"); + public static final Block DIRT = (new BlockDirt(3, 2)).c(0.5F).a(f).a("dirt"); + public static final Block COBBLESTONE = (new Block(4, 16, Material.STONE)).c(2.0F).b(10.0F).a(h).a("stonebrick"); + public static final Block WOOD = (new Block(5, 4, Material.WOOD)).c(2.0F).b(5.0F).a(e).a("wood").g(); + public static final Block SAPLING = (new BlockSapling(6, 15)).c(0.0F).a(g).a("sapling").g(); + public static final Block BEDROCK = (new Block(7, 17, Material.STONE)).i().b(6000000.0F).a(h).a("bedrock").n(); + public static final Block WATER = (new BlockFlowing(8, Material.WATER)).c(100.0F).f(3).a("water").n().g(); + public static final Block STATIONARY_WATER = (new BlockStationary(9, Material.WATER)).c(100.0F).f(3).a("water").n().g(); + public static final Block LAVA = (new BlockFlowing(10, Material.LAVA)).c(0.0F).a(1.0F).f(255).a("lava").n().g(); + public static final Block STATIONARY_LAVA = (new BlockStationary(11, Material.LAVA)).c(100.0F).a(1.0F).f(255).a("lava").n().g(); + public static final Block SAND = (new BlockSand(12, 18)).c(0.5F).a(l).a("sand"); + public static final Block GRAVEL = (new BlockGravel(13, 19)).c(0.6F).a(f).a("gravel"); + public static final Block GOLD_ORE = (new BlockOre(14, 32)).c(3.0F).b(5.0F).a(h).a("oreGold"); + public static final Block IRON_ORE = (new BlockOre(15, 33)).c(3.0F).b(5.0F).a(h).a("oreIron"); + public static final Block COAL_ORE = (new BlockOre(16, 34)).c(3.0F).b(5.0F).a(h).a("oreCoal"); + public static final Block LOG = (new BlockLog(17)).c(2.0F).a(e).a("log").g(); + public static final BlockLeaves LEAVES = (BlockLeaves) (new BlockLeaves(18, 52)).c(0.2F).f(1).a(g).a("leaves").n().g(); + public static final Block SPONGE = (new BlockSponge(19)).c(0.6F).a(g).a("sponge"); + public static final Block GLASS = (new BlockGlass(20, 49, Material.SHATTERABLE, false)).c(0.3F).a(j).a("glass"); + public static final Block LAPIS_ORE = (new BlockOre(21, 160)).c(3.0F).b(5.0F).a(h).a("oreLapis"); + public static final Block LAPIS_BLOCK = (new Block(22, 144, Material.STONE)).c(3.0F).b(5.0F).a(h).a("blockLapis"); + public static final Block DISPENSER = (new BlockDispenser(23)).c(3.5F).a(h).a("dispenser").g(); + public static final Block SANDSTONE = (new BlockSandStone(24)).a(h).c(0.8F).a("sandStone"); + public static final Block NOTE_BLOCK = (new BlockNote(25)).c(0.8F).a("musicBlock").g(); + public static final Block BED = (new BlockBed(26)).c(0.2F).a("bed").n().g(); + public static final Block GOLDEN_RAIL = (new BlockMinecartTrack(27, 179, true)).c(0.7F).a(i).a("goldenRail").g(); + public static final Block DETECTOR_RAIL = (new BlockMinecartDetector(28, 195)).c(0.7F).a(i).a("detectorRail").g(); + public static final Block PISTON_STICKY = (new BlockPiston(29, 106, true)).a("pistonStickyBase").g(); + public static final Block WEB = (new BlockWeb(30, 11)).f(1).c(4.0F).a("web"); + public static final BlockLongGrass LONG_GRASS = (BlockLongGrass) (new BlockLongGrass(31, 39)).c(0.0F).a(g).a("tallgrass"); + public static final BlockDeadBush DEAD_BUSH = (BlockDeadBush) (new BlockDeadBush(32, 55)).c(0.0F).a(g).a("deadbush"); + public static final Block PISTON = (new BlockPiston(33, 107, false)).a("pistonBase").g(); + public static final BlockPistonExtension PISTON_EXTENSION = (BlockPistonExtension) (new BlockPistonExtension(34, 107)).g(); + public static final Block WOOL = (new BlockCloth()).c(0.8F).a(k).a("cloth").g(); + public static final BlockPistonMoving PISTON_MOVING = new BlockPistonMoving(36); + public static final BlockFlower YELLOW_FLOWER = (BlockFlower) (new BlockFlower(37, 13)).c(0.0F).a(g).a("flower"); + public static final BlockFlower RED_ROSE = (BlockFlower) (new BlockFlower(38, 12)).c(0.0F).a(g).a("rose"); + public static final BlockFlower BROWN_MUSHROOM = (BlockFlower) (new BlockMushroom(39, 29)).c(0.0F).a(g).a(0.125F).a("mushroom"); + public static final BlockFlower RED_MUSHROOM = (BlockFlower) (new BlockMushroom(40, 28)).c(0.0F).a(g).a("mushroom"); + public static final Block GOLD_BLOCK = (new BlockOreBlock(41, 23)).c(3.0F).b(10.0F).a(i).a("blockGold"); + public static final Block IRON_BLOCK = (new BlockOreBlock(42, 22)).c(5.0F).b(10.0F).a(i).a("blockIron"); + public static final Block DOUBLE_STEP = (new BlockStep(43, true)).c(2.0F).b(10.0F).a(h).a("stoneSlab"); + public static final Block STEP = (new BlockStep(44, false)).c(2.0F).b(10.0F).a(h).a("stoneSlab"); + public static final Block BRICK = (new Block(45, 7, Material.STONE)).c(2.0F).b(10.0F).a(h).a("brick"); + public static final Block TNT = (new BlockTNT(46, 8)).c(0.0F).a(g).a("tnt"); + public static final Block BOOKSHELF = (new BlockBookshelf(47, 35)).c(1.5F).a(e).a("bookshelf"); + public static final Block MOSSY_COBBLESTONE = (new Block(48, 36, Material.STONE)).c(2.0F).b(10.0F).a(h).a("stoneMoss"); + public static final Block OBSIDIAN = (new BlockObsidian(49, 37)).c(10.0F).b(2000.0F).a(h).a("obsidian"); + public static final Block TORCH = (new BlockTorch(50, 80)).c(0.0F).a(0.9375F).a(e).a("torch").g(); + public static final BlockFire FIRE = (BlockFire) (new BlockFire(51, 31)).c(0.0F).a(1.0F).a(e).a("fire").n().g(); + public static final Block MOB_SPAWNER = (new BlockMobSpawner(52, 65)).c(5.0F).a(i).a("mobSpawner").n(); + public static final Block WOOD_STAIRS = (new BlockStairs(53, WOOD)).a("stairsWood").g(); + public static final Block CHEST = (new BlockChest(54)).c(2.5F).a(e).a("chest").g(); + public static final Block REDSTONE_WIRE = (new BlockRedstoneWire(55, 164)).c(0.0F).a(d).a("redstoneDust").n().g(); + public static final Block DIAMOND_ORE = (new BlockOre(56, 50)).c(3.0F).b(5.0F).a(h).a("oreDiamond"); + public static final Block DIAMOND_BLOCK = (new BlockOreBlock(57, 24)).c(5.0F).b(10.0F).a(i).a("blockDiamond"); + public static final Block WORKBENCH = (new BlockWorkbench(58)).c(2.5F).a(e).a("workbench"); + public static final Block CROPS = (new BlockCrops(59, 88)).c(0.0F).a(g).a("crops").n().g(); + public static final Block SOIL = (new BlockSoil(60)).c(0.6F).a(f).a("farmland"); + public static final Block FURNACE = (new BlockFurnace(61, false)).c(3.5F).a(h).a("furnace").g(); + public static final Block BURNING_FURNACE = (new BlockFurnace(62, true)).c(3.5F).a(h).a(0.875F).a("furnace").g(); + public static final Block SIGN_POST = (new BlockSign(63, TileEntitySign.class, true)).c(1.0F).a(e).a("sign").n().g(); + public static final Block WOODEN_DOOR = (new BlockDoor(64, Material.WOOD)).c(3.0F).a(e).a("doorWood").n().g(); + public static final Block LADDER = (new BlockLadder(65, 83)).c(0.4F).a(e).a("ladder").g(); + public static final Block RAILS = (new BlockMinecartTrack(66, 128, false)).c(0.7F).a(i).a("rail").g(); + public static final Block COBBLESTONE_STAIRS = (new BlockStairs(67, COBBLESTONE)).a("stairsStone").g(); + public static final Block WALL_SIGN = (new BlockSign(68, TileEntitySign.class, false)).c(1.0F).a(e).a("sign").n().g(); + public static final Block LEVER = (new BlockLever(69, 96)).c(0.5F).a(e).a("lever").g(); + public static final Block STONE_PLATE = (new BlockPressurePlate(70, STONE.textureId, EnumMobType.MOBS, Material.STONE)).c(0.5F).a(h).a("pressurePlate").g(); + public static final Block IRON_DOOR_BLOCK = (new BlockDoor(71, Material.ORE)).c(5.0F).a(i).a("doorIron").n().g(); + public static final Block WOOD_PLATE = (new BlockPressurePlate(72, WOOD.textureId, EnumMobType.EVERYTHING, Material.WOOD)).c(0.5F).a(e).a("pressurePlate").g(); + public static final Block REDSTONE_ORE = (new BlockRedstoneOre(73, 51, false)).c(3.0F).b(5.0F).a(h).a("oreRedstone").g(); + public static final Block GLOWING_REDSTONE_ORE = (new BlockRedstoneOre(74, 51, true)).a(0.625F).c(3.0F).b(5.0F).a(h).a("oreRedstone").g(); + public static final Block REDSTONE_TORCH_OFF = (new BlockRedstoneTorch(75, 115, false)).c(0.0F).a(e).a("notGate").g(); + public static final Block REDSTONE_TORCH_ON = (new BlockRedstoneTorch(76, 99, true)).c(0.0F).a(0.5F).a(e).a("notGate").g(); + public static final Block STONE_BUTTON = (new BlockButton(77, STONE.textureId)).c(0.5F).a(h).a("button").g(); + public static final Block SNOW = (new BlockSnow(78, 66)).c(0.1F).a(k).a("snow"); + public static final Block ICE = (new BlockIce(79, 67)).c(0.5F).f(3).a(j).a("ice"); + public static final Block SNOW_BLOCK = (new BlockSnowBlock(80, 66)).c(0.2F).a(k).a("snow"); + public static final Block CACTUS = (new BlockCactus(81, 70)).c(0.4F).a(k).a("cactus"); + public static final Block CLAY = (new BlockClay(82, 72)).c(0.6F).a(f).a("clay"); + public static final Block SUGAR_CANE_BLOCK = (new BlockReed(83, 73)).c(0.0F).a(g).a("reeds").n(); + public static final Block JUKEBOX = (new BlockJukeBox(84, 74)).c(2.0F).b(10.0F).a(h).a("jukebox").g(); + public static final Block FENCE = (new BlockFence(85, 4)).c(2.0F).b(5.0F).a(e).a("fence").g(); + public static final Block PUMPKIN = (new BlockPumpkin(86, 102, false)).c(1.0F).a(e).a("pumpkin").g(); + public static final Block NETHERRACK = (new BlockBloodStone(87, 103)).c(0.4F).a(h).a("hellrock"); + public static final Block SOUL_SAND = (new BlockSlowSand(88, 104)).c(0.5F).a(l).a("hellsand"); + public static final Block GLOWSTONE = (new BlockLightStone(89, 105, Material.STONE)).c(0.3F).a(j).a(1.0F).a("lightgem"); + public static final BlockPortal PORTAL = (BlockPortal) (new BlockPortal(90, 14)).c(-1.0F).a(j).a(0.75F).a("portal"); + public static final Block JACK_O_LANTERN = (new BlockPumpkin(91, 102, true)).c(1.0F).a(e).a(1.0F).a("litpumpkin").g(); + public static final Block CAKE_BLOCK = (new BlockCake(92, 121)).c(0.5F).a(k).a("cake").n().g(); + public static final Block DIODE_OFF = (new BlockDiode(93, false)).c(0.0F).a(e).a("diode").n().g(); + public static final Block DIODE_ON = (new BlockDiode(94, true)).c(0.0F).a(0.625F).a(e).a("diode").n().g(); + public static final Block LOCKED_CHEST = (new BlockLockedChest(95)).c(0.0F).a(1.0F).a(e).a("lockedchest").a(true).g(); + public static final Block TRAP_DOOR = (new BlockTrapdoor(96, Material.WOOD)).c(3.0F).a(e).a("trapdoor").n().g(); + public static final List leafDecayBlacklist = Arrays.asList(PoseidonConfig.getInstance().getTreeBlacklistIDs()); + public int textureId; + public final int id; + protected float strength; + protected float durability; + protected boolean bq; + protected boolean br; + public double minX; + public double minY; + public double minZ; + public double maxX; + public double maxY; + public double maxZ; + public StepSound stepSound; + public float bz; + public final Material material; + public float frictionFactor; + private String name; + + protected Block(int i, Material material) { + this.bq = true; + this.br = true; + this.stepSound = d; + this.bz = 1.0F; + this.frictionFactor = 0.6F; + if (byId[i] != null) { + throw new IllegalArgumentException("Slot " + i + " is already occupied by " + byId[i] + " when adding " + this); + } else { + this.material = material; + byId[i] = this; + this.id = i; + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + o[i] = this.a(); + q[i] = this.a() ? 255 : 0; + r[i] = !material.blocksLight(); + isTileEntity[i] = false; + } + } + + protected Block g() { + t[this.id] = true; + return this; + } + + protected void h() { + } + + protected Block(int i, int j, Material material) { + this(i, material); + this.textureId = j; + } + + protected Block a(StepSound stepsound) { + this.stepSound = stepsound; + return this; + } + + protected Block f(int i) { + q[this.id] = i; + return this; + } + + protected Block a(float f) { + s[this.id] = (int) (15.0F * f); + return this; + } + + protected Block b(float f) { + this.durability = f * 3.0F; + return this; + } + + public boolean b() { + return true; + } + + protected Block c(float f) { + this.strength = f; + if (this.durability < f * 5.0F) { + this.durability = f * 5.0F; + } + + return this; + } + + protected Block i() { + this.c(-1.0F); + return this; + } + + public float j() { + return this.strength; + } + + protected Block a(boolean flag) { + n[this.id] = flag; + return this; + } + + public void a(float f, float f1, float f2, float f3, float f4, float f5) { + this.minX = (double) f; + this.minY = (double) f1; + this.minZ = (double) f2; + this.maxX = (double) f3; + this.maxY = (double) f4; + this.maxZ = (double) f5; + } + + public boolean b(IBlockAccess iblockaccess, int i, int j, int k, int l) { + return iblockaccess.getMaterial(i, j, k).isBuildable(); + } + + public int a(int i, int j) { + return this.a(i); + } + + public int a(int i) { + return this.textureId; + } + + public void a(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist) { + AxisAlignedBB axisalignedbb1 = this.e(world, i, j, k); + + if (axisalignedbb1 != null && axisalignedbb.a(axisalignedbb1)) { + arraylist.add(axisalignedbb1); + } + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return AxisAlignedBB.b((double) i + this.minX, (double) j + this.minY, (double) k + this.minZ, (double) i + this.maxX, (double) j + this.maxY, (double) k + this.maxZ); + } + + public boolean a() { + return true; + } + + public boolean a(int i, boolean flag) { + return this.k_(); + } + + public boolean k_() { + return true; + } + + public void a(World world, int i, int j, int k, Random random) { + } + + public void postBreak(World world, int i, int j, int k, int l) { + } + + public void doPhysics(World world, int i, int j, int k, int l) { + } + + public int c() { + return 10; + } + + public void c(World world, int i, int j, int k) { + } + + public void remove(World world, int i, int j, int k) { + } + + public int a(Random random) { + return 1; + } + + public int a(int i, Random random) { + return this.id; + } + + public float getDamage(EntityHuman entityhuman) { + return this.strength < 0.0F ? 0.0F : (!entityhuman.b(this) ? 1.0F / this.strength / 100.0F : entityhuman.a(this) / this.strength / 30.0F); + } + + public final void g(World world, int i, int j, int k, int l) { + this.dropNaturally(world, i, j, k, l, 1.0F); + } + + public void dropNaturally(World world, int i, int j, int k, int l, float f) { + if (!world.isStatic) { + int i1 = this.a(world.random); + + for (int j1 = 0; j1 < i1; ++j1) { + // CraftBukkit - <= to < to allow for plugins to completely disable block drops from explosions + if (world.random.nextFloat() < f) { + int k1 = this.a(l, world.random); + + if (k1 > 0) { + this.a(world, i, j, k, new ItemStack(k1, 1, this.a_(l))); + } + } + } + } + } + + protected void a(World world, int i, int j, int k, ItemStack itemstack) { + if (!world.isStatic) { + float f = 0.7F; + double d0 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + double d1 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + double d2 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + EntityItem entityitem = new EntityItem(world, (double) i + d0, (double) j + d1, (double) k + d2, itemstack); + + entityitem.pickupDelay = 10; + world.addEntity(entityitem); + } + } + + protected int a_(int i) { + return 0; + } + + public float a(Entity entity) { + return this.durability / 5.0F; + } + + public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) { + this.a(world, i, j, k); + vec3d = vec3d.add((double) (-i), (double) (-j), (double) (-k)); + vec3d1 = vec3d1.add((double) (-i), (double) (-j), (double) (-k)); + Vec3D vec3d2 = vec3d.a(vec3d1, this.minX); + Vec3D vec3d3 = vec3d.a(vec3d1, this.maxX); + Vec3D vec3d4 = vec3d.b(vec3d1, this.minY); + Vec3D vec3d5 = vec3d.b(vec3d1, this.maxY); + Vec3D vec3d6 = vec3d.c(vec3d1, this.minZ); + Vec3D vec3d7 = vec3d.c(vec3d1, this.maxZ); + + if (!this.a(vec3d2)) { + vec3d2 = null; + } + + if (!this.a(vec3d3)) { + vec3d3 = null; + } + + if (!this.b(vec3d4)) { + vec3d4 = null; + } + + if (!this.b(vec3d5)) { + vec3d5 = null; + } + + if (!this.c(vec3d6)) { + vec3d6 = null; + } + + if (!this.c(vec3d7)) { + vec3d7 = null; + } + + Vec3D vec3d8 = null; + + if (vec3d2 != null && (vec3d8 == null || vec3d.a(vec3d2) < vec3d.a(vec3d8))) { + vec3d8 = vec3d2; + } + + if (vec3d3 != null && (vec3d8 == null || vec3d.a(vec3d3) < vec3d.a(vec3d8))) { + vec3d8 = vec3d3; + } + + if (vec3d4 != null && (vec3d8 == null || vec3d.a(vec3d4) < vec3d.a(vec3d8))) { + vec3d8 = vec3d4; + } + + if (vec3d5 != null && (vec3d8 == null || vec3d.a(vec3d5) < vec3d.a(vec3d8))) { + vec3d8 = vec3d5; + } + + if (vec3d6 != null && (vec3d8 == null || vec3d.a(vec3d6) < vec3d.a(vec3d8))) { + vec3d8 = vec3d6; + } + + if (vec3d7 != null && (vec3d8 == null || vec3d.a(vec3d7) < vec3d.a(vec3d8))) { + vec3d8 = vec3d7; + } + + if (vec3d8 == null) { + return null; + } else { + byte b0 = -1; + + if (vec3d8 == vec3d2) { + b0 = 4; + } + + if (vec3d8 == vec3d3) { + b0 = 5; + } + + if (vec3d8 == vec3d4) { + b0 = 0; + } + + if (vec3d8 == vec3d5) { + b0 = 1; + } + + if (vec3d8 == vec3d6) { + b0 = 2; + } + + if (vec3d8 == vec3d7) { + b0 = 3; + } + + return new MovingObjectPosition(i, j, k, b0, vec3d8.add((double) i, (double) j, (double) k)); + } + } + + private boolean a(Vec3D vec3d) { + return vec3d == null ? false : vec3d.b >= this.minY && vec3d.b <= this.maxY && vec3d.c >= this.minZ && vec3d.c <= this.maxZ; + } + + private boolean b(Vec3D vec3d) { + return vec3d == null ? false : vec3d.a >= this.minX && vec3d.a <= this.maxX && vec3d.c >= this.minZ && vec3d.c <= this.maxZ; + } + + private boolean c(Vec3D vec3d) { + return vec3d == null ? false : vec3d.a >= this.minX && vec3d.a <= this.maxX && vec3d.b >= this.minY && vec3d.b <= this.maxY; + } + + public void d(World world, int i, int j, int k) { + } + + public boolean canPlace(World world, int i, int j, int k, int l) { + return this.canPlace(world, i, j, k); + } + + public boolean canPlace(World world, int i, int j, int k) { + int l = world.getTypeId(i, j, k); + + return l == 0 || byId[l].material.isReplacable(); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + return false; + } + + public void b(World world, int i, int j, int k, Entity entity) { + } + + public void postPlace(World world, int i, int j, int k, int l) { + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + } + + public void a(World world, int i, int j, int k, Entity entity, Vec3D vec3d) { + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + return false; + } + + public boolean isPowerSource() { + return false; + } + + public void a(World world, int i, int j, int k, Entity entity) { + } + + public boolean d(World world, int i, int j, int k, int l) { + return false; + } + + public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) { + entityhuman.a(StatisticList.C[this.id], 1); + this.g(world, i, j, k, l); + } + + public boolean f(World world, int i, int j, int k) { + return true; + } + + public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) { + } + + public Block a(String s) { + this.name = "tile." + s; + return this; + } + + public String k() { + return StatisticCollector.a(this.l() + ".name"); + } + + public String l() { + return this.name; + } + + public void a(World world, int i, int j, int k, int l, int i1) { + } + + public boolean m() { + return this.br; + } + + protected Block n() { + this.br = false; + return this; + } + + public int e() { + return this.material.j(); + } + + static { + Item.byId[WOOL.id] = (new ItemCloth(WOOL.id - 256)).a("cloth"); + Item.byId[LOG.id] = (new ItemLog(LOG.id - 256)).a("log"); + Item.byId[STEP.id] = (new ItemStep(STEP.id - 256)).a("stoneSlab"); + Item.byId[SAPLING.id] = (new ItemSapling(SAPLING.id - 256)).a("sapling"); + Item.byId[LEAVES.id] = (new ItemLeaves(LEAVES.id - 256)).a("leaves"); + Item.byId[PISTON.id] = new ItemPiston(PISTON.id - 256); + Item.byId[PISTON_STICKY.id] = new ItemPiston(PISTON_STICKY.id - 256); + + for (int i = 0; i < 256; ++i) { + if (byId[i] != null && Item.byId[i] == null) { + Item.byId[i] = new ItemBlock(i - 256); + byId[i].h(); + } + } + + r[0] = true; + StatisticList.b(); + } +} diff --git a/src/main/java/net/minecraft/server/BlockBed.java b/src/main/java/net/minecraft/server/BlockBed.java new file mode 100644 index 0000000..236e4bf --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockBed.java @@ -0,0 +1,201 @@ +package net.minecraft.server; + +import org.bukkit.event.entity.EntityDamageEvent; + +import java.util.Iterator; +import java.util.Random; + +public class BlockBed extends Block { + + public static final int[][] a = new int[][] { { 0, 1}, { -1, 0}, { 0, -1}, { 1, 0}}; + + public BlockBed(int i) { + super(i, 134, Material.CLOTH); + this.o(); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (world.isStatic) { + return true; + } else { + int l = world.getData(i, j, k); + + if (!d(l)) { + int i1 = c(l); + + i += a[i1][0]; + k += a[i1][1]; + if (world.getTypeId(i, j, k) != this.id) { + return true; + } + + l = world.getData(i, j, k); + } + + if (!world.worldProvider.d()) { + double d0 = (double) i + 0.5D; + double d1 = (double) j + 0.5D; + double d2 = (double) k + 0.5D; + + world.setTypeId(i, j, k, 0); + int j1 = c(l); + + i += a[j1][0]; + k += a[j1][1]; + if (world.getTypeId(i, j, k) == this.id) { + world.setTypeId(i, j, k, 0); + d0 = (d0 + (double) i + 0.5D) / 2.0D; + d1 = (d1 + (double) j + 0.5D) / 2.0D; + d2 = (d2 + (double) k + 0.5D) / 2.0D; + } + + world.createExplosion((Entity) null, (double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), 5.0F, true, EntityDamageEvent.DamageCause.BED_EXPLOSION); //Project poseidon + return true; + } else { + if (e(l)) { + EntityHuman entityhuman1 = null; + Iterator iterator = world.players.iterator(); + + while (iterator.hasNext()) { + EntityHuman entityhuman2 = (EntityHuman) iterator.next(); + + if (entityhuman2.isSleeping()) { + ChunkCoordinates chunkcoordinates = entityhuman2.A; + + if (chunkcoordinates.x == i && chunkcoordinates.y == j && chunkcoordinates.z == k) { + entityhuman1 = entityhuman2; + } + } + } + + if (entityhuman1 != null) { + entityhuman.a("tile.bed.occupied"); + return true; + } + + a(world, i, j, k, false); + } + + EnumBedError enumbederror = entityhuman.a(i, j, k); + + if (enumbederror == EnumBedError.OK) { + a(world, i, j, k, true); + return true; + } else { + if (enumbederror == EnumBedError.NOT_POSSIBLE_NOW) { + entityhuman.a("tile.bed.noSleep"); + } + + return true; + } + } + } + } + + public int a(int i, int j) { + if (i == 0) { + return Block.WOOD.textureId; + } else { + int k = c(j); + int l = BedBlockTextures.c[k][i]; + + return d(j) ? (l == 2 ? this.textureId + 2 + 16 : (l != 5 && l != 4 ? this.textureId + 1 : this.textureId + 1 + 16)) : (l == 3 ? this.textureId - 1 + 16 : (l != 5 && l != 4 ? this.textureId : this.textureId + 16)); + } + } + + public boolean b() { + return false; + } + + public boolean a() { + return false; + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + this.o(); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + int j1 = c(i1); + + if (d(i1)) { + if (world.getTypeId(i - a[j1][0], j, k - a[j1][1]) != this.id) { + world.setTypeId(i, j, k, 0); + } + } else if (world.getTypeId(i + a[j1][0], j, k + a[j1][1]) != this.id) { + world.setTypeId(i, j, k, 0); + if (!world.isStatic) { + this.g(world, i, j, k, i1); + } + } + } + + public int a(int i, Random random) { + return d(i) ? 0 : Item.BED.id; + } + + private void o() { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.5625F, 1.0F); + } + + public static int c(int i) { + return i & 3; + } + + public static boolean d(int i) { + return (i & 8) != 0; + } + + public static boolean e(int i) { + return (i & 4) != 0; + } + + public static void a(World world, int i, int j, int k, boolean flag) { + int l = world.getData(i, j, k); + + if (flag) { + l |= 4; + } else { + l &= -5; + } + + world.setData(i, j, k, l); + } + + public static ChunkCoordinates f(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + int j1 = c(i1); + + for (int k1 = 0; k1 <= 1; ++k1) { + int l1 = i - a[j1][0] * k1 - 1; + int i2 = k - a[j1][1] * k1 - 1; + int j2 = l1 + 2; + int k2 = i2 + 2; + + for (int l2 = l1; l2 <= j2; ++l2) { + for (int i3 = i2; i3 <= k2; ++i3) { + if (world.e(l2, j - 1, i3) && world.isEmpty(l2, j, i3) && world.isEmpty(l2, j + 1, i3)) { + if (l <= 0) { + return new ChunkCoordinates(l2, j, i3); + } + + --l; + } + } + } + } + + return null; + } + + public void dropNaturally(World world, int i, int j, int k, int l, float f) { + if (!d(l)) { + super.dropNaturally(world, i, j, k, l, f); + } + } + + public int e() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/BlockBloodStone.java b/src/main/java/net/minecraft/server/BlockBloodStone.java new file mode 100644 index 0000000..884e279 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockBloodStone.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +public class BlockBloodStone extends Block { + + public BlockBloodStone(int i, int j) { + super(i, j, Material.STONE); + } + + // CraftBukkit start + public void doPhysics(World world, int i, int j, int k, int l) { + if (net.minecraft.server.Block.byId[l] != null && net.minecraft.server.Block.byId[l].isPowerSource()) { + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + int power = block.getBlockPower(); + + BlockRedstoneEvent event = new BlockRedstoneEvent(block, power, power); + world.getServer().getPluginManager().callEvent(event); + } + } + // CraftBukkit end +} diff --git a/src/main/java/net/minecraft/server/BlockBookshelf.java b/src/main/java/net/minecraft/server/BlockBookshelf.java new file mode 100644 index 0000000..ce70e2b --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockBookshelf.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockBookshelf extends Block { + + public BlockBookshelf(int i, int j) { + super(i, j, Material.WOOD); + } + + public int a(int i) { + return i <= 1 ? 4 : this.textureId; + } + + public int a(Random random) { + return 0; + } +} diff --git a/src/main/java/net/minecraft/server/BlockBreakable.java b/src/main/java/net/minecraft/server/BlockBreakable.java new file mode 100644 index 0000000..d5b2a6e --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockBreakable.java @@ -0,0 +1,15 @@ +package net.minecraft.server; + +public class BlockBreakable extends Block { + + private boolean a; + + protected BlockBreakable(int i, int j, Material material, boolean flag) { + super(i, j, material); + this.a = flag; + } + + public boolean a() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/BlockButton.java b/src/main/java/net/minecraft/server/BlockButton.java new file mode 100644 index 0000000..0b7292f --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockButton.java @@ -0,0 +1,248 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +import java.util.Random; + +public class BlockButton extends Block { + + protected BlockButton(int i, int j) { + super(i, j, Material.ORIENTABLE); + this.a(true); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public int c() { + return 20; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k, int l) { + return l == 2 && world.e(i, j, k + 1) ? true : (l == 3 && world.e(i, j, k - 1) ? true : (l == 4 && world.e(i + 1, j, k) ? true : l == 5 && world.e(i - 1, j, k))); + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i - 1, j, k) ? true : (world.e(i + 1, j, k) ? true : (world.e(i, j, k - 1) ? true : world.e(i, j, k + 1))); + } + + public void postPlace(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + int j1 = i1 & 8; + + i1 &= 7; + if (l == 2 && world.e(i, j, k + 1)) { + i1 = 4; + } else if (l == 3 && world.e(i, j, k - 1)) { + i1 = 3; + } else if (l == 4 && world.e(i + 1, j, k)) { + i1 = 2; + } else if (l == 5 && world.e(i - 1, j, k)) { + i1 = 1; + } else { + i1 = this.g(world, i, j, k); + } + + world.setData(i, j, k, i1 + j1); + } + + private int g(World world, int i, int j, int k) { + return world.e(i - 1, j, k) ? 1 : (world.e(i + 1, j, k) ? 2 : (world.e(i, j, k - 1) ? 3 : (world.e(i, j, k + 1) ? 4 : 1))); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (this.h(world, i, j, k)) { + int i1 = world.getData(i, j, k) & 7; + boolean flag = false; + + if (!world.e(i - 1, j, k) && i1 == 1) { + flag = true; + } + + if (!world.e(i + 1, j, k) && i1 == 2) { + flag = true; + } + + if (!world.e(i, j, k - 1) && i1 == 3) { + flag = true; + } + + if (!world.e(i, j, k + 1) && i1 == 4) { + flag = true; + } + + if (flag) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + } + + private boolean h(World world, int i, int j, int k) { + if (!this.canPlace(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + return false; + } else { + return true; + } + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getData(i, j, k); + int i1 = l & 7; + boolean flag = (l & 8) > 0; + float f = 0.375F; + float f1 = 0.625F; + float f2 = 0.1875F; + float f3 = 0.125F; + + if (flag) { + f3 = 0.0625F; + } + + if (i1 == 1) { + this.a(0.0F, f, 0.5F - f2, f3, f1, 0.5F + f2); + } else if (i1 == 2) { + this.a(1.0F - f3, f, 0.5F - f2, 1.0F, f1, 0.5F + f2); + } else if (i1 == 3) { + this.a(0.5F - f2, f, 0.0F, 0.5F + f2, f1, f3); + } else if (i1 == 4) { + this.a(0.5F - f2, f, 1.0F - f3, 0.5F + f2, f1, 1.0F); + } + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + this.interact(world, i, j, k, entityhuman); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + int l = world.getData(i, j, k); + int i1 = l & 7; + int j1 = 8 - (l & 8); + + if (j1 == 0) { + return true; + } else { + // CraftBukkit start + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + int old = (j1 != 8) ? 1 : 0; + int current = (j1 == 8) ? 1 : 0; + + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, old, current); + world.getServer().getPluginManager().callEvent(eventRedstone); + + if ((eventRedstone.getNewCurrent() > 0) != (j1 == 8)) { + return true; + } + // CraftBukkit end + + world.setData(i, j, k, i1 + j1); + world.b(i, j, k, i, j, k); + world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "random.click", 0.3F, 0.6F); + world.applyPhysics(i, j, k, this.id); + if (i1 == 1) { + world.applyPhysics(i - 1, j, k, this.id); + } else if (i1 == 2) { + world.applyPhysics(i + 1, j, k, this.id); + } else if (i1 == 3) { + world.applyPhysics(i, j, k - 1, this.id); + } else if (i1 == 4) { + world.applyPhysics(i, j, k + 1, this.id); + } else { + world.applyPhysics(i, j - 1, k, this.id); + } + + world.c(i, j, k, this.id, this.c()); + return true; + } + } + + public void remove(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + + if ((l & 8) > 0) { + world.applyPhysics(i, j, k, this.id); + int i1 = l & 7; + + if (i1 == 1) { + world.applyPhysics(i - 1, j, k, this.id); + } else if (i1 == 2) { + world.applyPhysics(i + 1, j, k, this.id); + } else if (i1 == 3) { + world.applyPhysics(i, j, k - 1, this.id); + } else if (i1 == 4) { + world.applyPhysics(i, j, k + 1, this.id); + } else { + world.applyPhysics(i, j - 1, k, this.id); + } + } + + super.remove(world, i, j, k); + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + return (iblockaccess.getData(i, j, k) & 8) > 0; + } + + public boolean d(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + + if ((i1 & 8) == 0) { + return false; + } else { + int j1 = i1 & 7; + + return j1 == 5 && l == 1 ? true : (j1 == 4 && l == 2 ? true : (j1 == 3 && l == 3 ? true : (j1 == 2 && l == 4 ? true : j1 == 1 && l == 5))); + } + } + + public boolean isPowerSource() { + return true; + } + + public void a(World world, int i, int j, int k, Random random) { + if (!world.isStatic) { + int l = world.getData(i, j, k); + + if ((l & 8) != 0) { + // CraftBukkit start + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, 1, 0); + world.getServer().getPluginManager().callEvent(eventRedstone); + + if (eventRedstone.getNewCurrent() > 0) return; + // CraftBukkit end + + world.setData(i, j, k, l & 7); + world.applyPhysics(i, j, k, this.id); + int i1 = l & 7; + + if (i1 == 1) { + world.applyPhysics(i - 1, j, k, this.id); + } else if (i1 == 2) { + world.applyPhysics(i + 1, j, k, this.id); + } else if (i1 == 3) { + world.applyPhysics(i, j, k - 1, this.id); + } else if (i1 == 4) { + world.applyPhysics(i, j, k + 1, this.id); + } else { + world.applyPhysics(i, j - 1, k, this.id); + } + + world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "random.click", 0.3F, 0.5F); + world.b(i, j, k, i, j, k); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockCactus.java b/src/main/java/net/minecraft/server/BlockCactus.java new file mode 100644 index 0000000..fddda50 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockCactus.java @@ -0,0 +1,103 @@ +package net.minecraft.server; + +// CraftBukkit start + +import org.bukkit.event.entity.EntityDamageByBlockEvent; +import org.bukkit.event.entity.EntityDamageEvent; + +import java.util.Random; + +// CraftBukkit end + +public class BlockCactus extends Block { + + protected BlockCactus(int i, int j) { + super(i, j, Material.CACTUS); + this.a(true); + } + + public void a(World world, int i, int j, int k, Random random) { + if (world.isEmpty(i, j + 1, k)) { + int l; + + for (l = 1; world.getTypeId(i, j - l, k) == this.id; ++l) { + ; + } + + if (l < 3) { + int i1 = world.getData(i, j, k); + + if (i1 == 15) { + world.setTypeId(i, j + 1, k, this.id); + world.setData(i, j, k, 0); + } else { + world.setData(i, j, k, i1 + 1); + } + } + } + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + float f = 0.0625F; + + return AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) ((float) (j + 1) - f), (double) ((float) (k + 1) - f)); + } + + public int a(int i) { + return i == 1 ? this.textureId - 1 : (i == 0 ? this.textureId + 1 : this.textureId); + } + + public boolean b() { + return false; + } + + public boolean a() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k) { + return !super.canPlace(world, i, j, k) ? false : this.f(world, i, j, k); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!this.f(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + + public boolean f(World world, int i, int j, int k) { + if (world.getMaterial(i - 1, j, k).isBuildable()) { + return false; + } else if (world.getMaterial(i + 1, j, k).isBuildable()) { + return false; + } else if (world.getMaterial(i, j, k - 1).isBuildable()) { + return false; + } else if (world.getMaterial(i, j, k + 1).isBuildable()) { + return false; + } else { + int l = world.getTypeId(i, j - 1, k); + + return l == Block.CACTUS.id || l == Block.SAND.id; + } + } + + public void a(World world, int i, int j, int k, Entity entity) { + // CraftBukkit start - ENTITY_DAMAGEBY_BLOCK event + if (entity instanceof EntityLiving) { + org.bukkit.block.Block damager = world.getWorld().getBlockAt(i, j, k); + org.bukkit.entity.Entity damagee = (entity == null) ? null : entity.getBukkitEntity(); + + EntityDamageByBlockEvent event = new EntityDamageByBlockEvent(damager, damagee, EntityDamageEvent.DamageCause.CONTACT, 1); + world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + entity.damageEntity((Entity) null, event.getDamage()); + } + return; + } + // CraftBukkit end + + entity.damageEntity((Entity) null, 1); + } +} diff --git a/src/main/java/net/minecraft/server/BlockCake.java b/src/main/java/net/minecraft/server/BlockCake.java new file mode 100644 index 0000000..7705fbd --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockCake.java @@ -0,0 +1,91 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockCake extends Block { + + protected BlockCake(int i, int j) { + super(i, j, Material.CAKE); + this.a(true); + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getData(i, j, k); + float f = 0.0625F; + float f1 = (float) (1 + l * 2) / 16.0F; + float f2 = 0.5F; + + this.a(f1, 0.0F, f, 1.0F - f, f2, 1.0F - f); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + float f = 0.0625F; + float f1 = (float) (1 + l * 2) / 16.0F; + float f2 = 0.5F; + + return AxisAlignedBB.b((double) ((float) i + f1), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) ((float) j + f2 - f), (double) ((float) (k + 1) - f)); + } + + public int a(int i, int j) { + return i == 1 ? this.textureId : (i == 0 ? this.textureId + 3 : (j > 0 && i == 4 ? this.textureId + 2 : this.textureId + 1)); + } + + public int a(int i) { + return i == 1 ? this.textureId : (i == 0 ? this.textureId + 3 : this.textureId + 1); + } + + public boolean b() { + return false; + } + + public boolean a() { + return false; + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + this.c(world, i, j, k, entityhuman); + return true; + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + this.c(world, i, j, k, entityhuman); + } + + private void c(World world, int i, int j, int k, EntityHuman entityhuman) { + if (entityhuman.health < 20) { + entityhuman.b(3); + int l = world.getData(i, j, k) + 1; + + if (l >= 6) { + world.setTypeId(i, j, k, 0); + } else { + world.setData(i, j, k, l); + world.i(i, j, k); + } + } + } + + public boolean canPlace(World world, int i, int j, int k) { + return !super.canPlace(world, i, j, k) ? false : this.f(world, i, j, k); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!this.f(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + + public boolean f(World world, int i, int j, int k) { + return world.getMaterial(i, j - 1, k).isBuildable(); + } + + public int a(Random random) { + return 0; + } + + public int a(int i, Random random) { + return 0; + } +} diff --git a/src/main/java/net/minecraft/server/BlockChest.java b/src/main/java/net/minecraft/server/BlockChest.java new file mode 100644 index 0000000..be79eb2 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockChest.java @@ -0,0 +1,120 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockChest extends BlockContainer { + + private Random a = new Random(); + + protected BlockChest(int i) { + super(i, Material.WOOD); + this.textureId = 26; + } + + public int a(int i) { + return i == 1 ? this.textureId - 1 : (i == 0 ? this.textureId - 1 : (i == 3 ? this.textureId + 1 : this.textureId)); + } + + public boolean canPlace(World world, int i, int j, int k) { + int l = 0; + + if (world.getTypeId(i - 1, j, k) == this.id) { + ++l; + } + + if (world.getTypeId(i + 1, j, k) == this.id) { + ++l; + } + + if (world.getTypeId(i, j, k - 1) == this.id) { + ++l; + } + + if (world.getTypeId(i, j, k + 1) == this.id) { + ++l; + } + + return l > 1 ? false : (this.g(world, i - 1, j, k) ? false : (this.g(world, i + 1, j, k) ? false : (this.g(world, i, j, k - 1) ? false : !this.g(world, i, j, k + 1)))); + } + + private boolean g(World world, int i, int j, int k) { + return world.getTypeId(i, j, k) != this.id ? false : (world.getTypeId(i - 1, j, k) == this.id ? true : (world.getTypeId(i + 1, j, k) == this.id ? true : (world.getTypeId(i, j, k - 1) == this.id ? true : world.getTypeId(i, j, k + 1) == this.id))); + } + + public void remove(World world, int i, int j, int k) { + TileEntityChest tileentitychest = (TileEntityChest) world.getTileEntity(i, j, k); + + for (int l = 0; l < tileentitychest.getSize(); ++l) { + ItemStack itemstack = tileentitychest.getItem(l); + + if (itemstack != null) { + float f = this.a.nextFloat() * 0.8F + 0.1F; + float f1 = this.a.nextFloat() * 0.8F + 0.1F; + float f2 = this.a.nextFloat() * 0.8F + 0.1F; + + while (itemstack.count > 0) { + int i1 = this.a.nextInt(21) + 10; + + if (i1 > itemstack.count) { + i1 = itemstack.count; + } + + itemstack.count -= i1; + EntityItem entityitem = new EntityItem(world, (double) ((float) i + f), (double) ((float) j + f1), (double) ((float) k + f2), new ItemStack(itemstack.id, i1, itemstack.getData())); + float f3 = 0.05F; + + entityitem.motX = (double) ((float) this.a.nextGaussian() * f3); + entityitem.motY = (double) ((float) this.a.nextGaussian() * f3 + 0.2F); + entityitem.motZ = (double) ((float) this.a.nextGaussian() * f3); + world.addEntity(entityitem); + } + tileentitychest.setItem(l, null); + } + } + + super.remove(world, i, j, k); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + Object object = (TileEntityChest) world.getTileEntity(i, j, k); + + if (world.e(i, j + 1, k)) { + return true; + } else if (world.getTypeId(i - 1, j, k) == this.id && world.e(i - 1, j + 1, k)) { + return true; + } else if (world.getTypeId(i + 1, j, k) == this.id && world.e(i + 1, j + 1, k)) { + return true; + } else if (world.getTypeId(i, j, k - 1) == this.id && world.e(i, j + 1, k - 1)) { + return true; + } else if (world.getTypeId(i, j, k + 1) == this.id && world.e(i, j + 1, k + 1)) { + return true; + } else { + if (world.getTypeId(i - 1, j, k) == this.id) { + object = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(i - 1, j, k), (IInventory) object); + } + + if (world.getTypeId(i + 1, j, k) == this.id) { + object = new InventoryLargeChest("Large chest", (IInventory) object, (TileEntityChest) world.getTileEntity(i + 1, j, k)); + } + + if (world.getTypeId(i, j, k - 1) == this.id) { + object = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(i, j, k - 1), (IInventory) object); + } + + if (world.getTypeId(i, j, k + 1) == this.id) { + object = new InventoryLargeChest("Large chest", (IInventory) object, (TileEntityChest) world.getTileEntity(i, j, k + 1)); + } + + if (world.isStatic) { + return true; + } else { + entityhuman.a((IInventory) object); + return true; + } + } + } + + protected TileEntity a_() { + return new TileEntityChest(); + } +} diff --git a/src/main/java/net/minecraft/server/BlockClay.java b/src/main/java/net/minecraft/server/BlockClay.java new file mode 100644 index 0000000..c0c1581 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockClay.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockClay extends Block { + + public BlockClay(int i, int j) { + super(i, j, Material.CLAY); + } + + public int a(int i, Random random) { + return Item.CLAY_BALL.id; + } + + public int a(Random random) { + return 4; + } +} diff --git a/src/main/java/net/minecraft/server/BlockCloth.java b/src/main/java/net/minecraft/server/BlockCloth.java new file mode 100644 index 0000000..c51c3b4 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockCloth.java @@ -0,0 +1,29 @@ +package net.minecraft.server; + +public class BlockCloth extends Block { + + public BlockCloth() { + super(35, 64, Material.CLOTH); + } + + public int a(int i, int j) { + if (j == 0) { + return this.textureId; + } else { + j = ~(j & 15); + return 113 + ((j & 8) >> 3) + (j & 7) * 16; + } + } + + protected int a_(int i) { + return i; + } + + public static int c(int i) { + return ~i & 15; + } + + public static int d(int i) { + return ~i & 15; + } +} diff --git a/src/main/java/net/minecraft/server/BlockContainer.java b/src/main/java/net/minecraft/server/BlockContainer.java new file mode 100644 index 0000000..e8dd7ed --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockContainer.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +public abstract class BlockContainer extends Block { + + protected BlockContainer(int i, Material material) { + super(i, material); + isTileEntity[i] = true; + } + + protected BlockContainer(int i, int j, Material material) { + super(i, j, material); + isTileEntity[i] = true; + } + + public void c(World world, int i, int j, int k) { + super.c(world, i, j, k); + world.setTileEntity(i, j, k, this.a_()); + } + + public void remove(World world, int i, int j, int k) { + super.remove(world, i, j, k); + world.o(i, j, k); + } + + protected abstract TileEntity a_(); +} diff --git a/src/main/java/net/minecraft/server/BlockCrops.java b/src/main/java/net/minecraft/server/BlockCrops.java new file mode 100644 index 0000000..0025bc3 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockCrops.java @@ -0,0 +1,114 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockCrops extends BlockFlower { + + protected BlockCrops(int i, int j) { + super(i, j); + this.textureId = j; + this.a(true); + float f = 0.5F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.25F, 0.5F + f); + } + + protected boolean c(int i) { + return i == Block.SOIL.id; + } + + public void a(World world, int i, int j, int k, Random random) { + super.a(world, i, j, k, random); + if (world.getLightLevel(i, j + 1, k) >= 9) { + int l = world.getData(i, j, k); + + if (l < 7) { + float f = this.h(world, i, j, k); + + if (random.nextInt((int) (100.0F / f)) == 0) { + ++l; + world.setData(i, j, k, l); + } + } + } + } + + public void d_(World world, int i, int j, int k) { + world.setData(i, j, k, 7); + } + + private float h(World world, int i, int j, int k) { + float f = 1.0F; + int l = world.getTypeId(i, j, k - 1); + int i1 = world.getTypeId(i, j, k + 1); + int j1 = world.getTypeId(i - 1, j, k); + int k1 = world.getTypeId(i + 1, j, k); + int l1 = world.getTypeId(i - 1, j, k - 1); + int i2 = world.getTypeId(i + 1, j, k - 1); + int j2 = world.getTypeId(i + 1, j, k + 1); + int k2 = world.getTypeId(i - 1, j, k + 1); + boolean flag = j1 == this.id || k1 == this.id; + boolean flag1 = l == this.id || i1 == this.id; + boolean flag2 = l1 == this.id || i2 == this.id || j2 == this.id || k2 == this.id; + + for (int l2 = i - 1; l2 <= i + 1; ++l2) { + for (int i3 = k - 1; i3 <= k + 1; ++i3) { + int j3 = world.getTypeId(l2, j - 1, i3); + float f1 = 0.0F; + + if (j3 == Block.SOIL.id) { + f1 = 1.0F; + if (world.getData(l2, j - 1, i3) > 0) { + f1 = 3.0F; + } + } + + if (l2 != i || i3 != k) { + f1 /= 4.0F; + } + + f += f1; + } + } + + if (flag2 || flag && flag1) { + f /= 2.0F; + } + + return f; + } + + public int a(int i, int j) { + if (j < 0) { + j = 7; + } + + return this.textureId + j; + } + + public void dropNaturally(World world, int i, int j, int k, int l, float f) { + super.dropNaturally(world, i, j, k, l, f); + if (!world.isStatic) { + for (int i1 = 0; i1 < 3; ++i1) { + if (world.random.nextInt(15) <= l) { + float f1 = 0.7F; + float f2 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F; + float f3 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F; + float f4 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F; + EntityItem entityitem = new EntityItem(world, (double) ((float) i + f2), (double) ((float) j + f3), (double) ((float) k + f4), new ItemStack(Item.SEEDS)); + + entityitem.pickupDelay = 10; + world.addEntity(entityitem); + } + } + } + } + + public int a(int i, Random random) { + return i == 7 ? Item.WHEAT.id : -1; + } + + public int a(Random random) { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/BlockDeadBush.java b/src/main/java/net/minecraft/server/BlockDeadBush.java new file mode 100644 index 0000000..5786b34 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockDeadBush.java @@ -0,0 +1,25 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockDeadBush extends BlockFlower { + + protected BlockDeadBush(int i, int j) { + super(i, j); + float f = 0.4F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.8F, 0.5F + f); + } + + protected boolean c(int i) { + return i == Block.SAND.id; + } + + public int a(int i, int j) { + return this.textureId; + } + + public int a(int i, Random random) { + return -1; + } +} diff --git a/src/main/java/net/minecraft/server/BlockDiode.java b/src/main/java/net/minecraft/server/BlockDiode.java new file mode 100644 index 0000000..c213f50 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockDiode.java @@ -0,0 +1,145 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockDiode extends Block { + + public static final double[] a = new double[] { -0.0625D, 0.0625D, 0.1875D, 0.3125D}; + private static final int[] b = new int[] { 1, 2, 3, 4}; + private final boolean c; + + protected BlockDiode(int i, boolean flag) { + super(i, 6, Material.ORIENTABLE); + this.c = flag; + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); + } + + public boolean b() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k) { + return !world.e(i, j - 1, k) ? false : super.canPlace(world, i, j, k); + } + + public boolean f(World world, int i, int j, int k) { + return !world.e(i, j - 1, k) ? false : super.f(world, i, j, k); + } + + public void a(World world, int i, int j, int k, Random random) { + int l = world.getData(i, j, k); + boolean flag = this.f(world, i, j, k, l); + + if (this.c && !flag) { + world.setTypeIdAndData(i, j, k, Block.DIODE_OFF.id, l); + } else if (!this.c) { + world.setTypeIdAndData(i, j, k, Block.DIODE_ON.id, l); + if (!flag) { + int i1 = (l & 12) >> 2; + + world.c(i, j, k, Block.DIODE_ON.id, b[i1] * 2); + } + } + } + + public int a(int i, int j) { + return i == 0 ? (this.c ? 99 : 115) : (i == 1 ? (this.c ? 147 : 131) : 5); + } + + public int a(int i) { + return this.a(i, 0); + } + + public boolean d(World world, int i, int j, int k, int l) { + return this.a(world, i, j, k, l); + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + if (!this.c) { + return false; + } else { + int i1 = iblockaccess.getData(i, j, k) & 3; + + return i1 == 0 && l == 3 ? true : (i1 == 1 && l == 4 ? true : (i1 == 2 && l == 2 ? true : i1 == 3 && l == 5)); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!this.f(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } else { + int i1 = world.getData(i, j, k); + boolean flag = this.f(world, i, j, k, i1); + int j1 = (i1 & 12) >> 2; + + if (this.c && !flag) { + world.c(i, j, k, this.id, b[j1] * 2); + } else if (!this.c && flag) { + world.c(i, j, k, this.id, b[j1] * 2); + } + } + } + + private boolean f(World world, int i, int j, int k, int l) { + int i1 = l & 3; + + switch (i1) { + case 0: + return world.isBlockFaceIndirectlyPowered(i, j, k + 1, 3) || world.getTypeId(i, j, k + 1) == Block.REDSTONE_WIRE.id && world.getData(i, j, k + 1) > 0; + + case 1: + return world.isBlockFaceIndirectlyPowered(i - 1, j, k, 4) || world.getTypeId(i - 1, j, k) == Block.REDSTONE_WIRE.id && world.getData(i - 1, j, k) > 0; + + case 2: + return world.isBlockFaceIndirectlyPowered(i, j, k - 1, 2) || world.getTypeId(i, j, k - 1) == Block.REDSTONE_WIRE.id && world.getData(i, j, k - 1) > 0; + + case 3: + return world.isBlockFaceIndirectlyPowered(i + 1, j, k, 5) || world.getTypeId(i + 1, j, k) == Block.REDSTONE_WIRE.id && world.getData(i + 1, j, k) > 0; + + default: + return false; + } + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + int l = world.getData(i, j, k); + int i1 = (l & 12) >> 2; + + i1 = i1 + 1 << 2 & 12; + world.setData(i, j, k, i1 | l & 3); + return true; + } + + public boolean isPowerSource() { + return false; + } + + public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) { + int l = ((MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4; + + world.setData(i, j, k, l); + boolean flag = this.f(world, i, j, k, l); + + if (flag) { + world.c(i, j, k, this.id, 1); + } + } + + public void c(World world, int i, int j, int k) { + world.applyPhysics(i + 1, j, k, this.id); + world.applyPhysics(i - 1, j, k, this.id); + world.applyPhysics(i, j, k + 1, this.id); + world.applyPhysics(i, j, k - 1, this.id); + world.applyPhysics(i, j - 1, k, this.id); + world.applyPhysics(i, j + 1, k, this.id); + } + + public boolean a() { + return false; + } + + public int a(int i, Random random) { + return Item.DIODE.id; + } +} diff --git a/src/main/java/net/minecraft/server/BlockDirt.java b/src/main/java/net/minecraft/server/BlockDirt.java new file mode 100644 index 0000000..2f33ac7 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockDirt.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +public class BlockDirt extends Block { + + protected BlockDirt(int i, int j) { + super(i, j, Material.EARTH); + } +} diff --git a/src/main/java/net/minecraft/server/BlockDispenser.java b/src/main/java/net/minecraft/server/BlockDispenser.java new file mode 100644 index 0000000..9cb7613 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockDispenser.java @@ -0,0 +1,249 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.event.block.BlockDispenseEvent; +import org.bukkit.util.Vector; + +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class BlockDispenser extends BlockContainer { + + private Random a = new Random(); + + protected BlockDispenser(int i) { + super(i, Material.STONE); + this.textureId = 45; + } + + public int c() { + return 4; + } + + public int a(int i, Random random) { + return Block.DISPENSER.id; + } + + public void c(World world, int i, int j, int k) { + super.c(world, i, j, k); + this.g(world, i, j, k); + } + + private void g(World world, int i, int j, int k) { + if (!world.isStatic) { + int l = world.getTypeId(i, j, k - 1); + int i1 = world.getTypeId(i, j, k + 1); + int j1 = world.getTypeId(i - 1, j, k); + int k1 = world.getTypeId(i + 1, j, k); + byte b0 = 3; + + if (Block.o[l] && !Block.o[i1]) { + b0 = 3; + } + + if (Block.o[i1] && !Block.o[l]) { + b0 = 2; + } + + if (Block.o[j1] && !Block.o[k1]) { + b0 = 5; + } + + if (Block.o[k1] && !Block.o[j1]) { + b0 = 4; + } + + world.setData(i, j, k, b0); + } + } + + public int a(int i) { + return i == 1 ? this.textureId + 17 : (i == 0 ? this.textureId + 17 : (i == 3 ? this.textureId + 1 : this.textureId)); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (world.isStatic) { + return true; + } else { + TileEntityDispenser tileentitydispenser = (TileEntityDispenser) world.getTileEntity(i, j, k); + + entityhuman.a(tileentitydispenser); + return true; + } + } + + // CraftBukkit - private -> public + public void dispense(World world, int i, int j, int k, Random random) { + int l = world.getData(i, j, k); + byte b0 = 0; + byte b1 = 0; + + if (l == 3) { + b1 = 1; + } else if (l == 2) { + b1 = -1; + } else if (l == 5) { + b0 = 1; + } else { + b0 = -1; + } + + TileEntityDispenser tileentitydispenser = (TileEntityDispenser) world.getTileEntity(i, j, k); + // CraftBukkit start + int dispenseSlot = tileentitydispenser.findDispenseSlot(); + ItemStack itemstack = null; + if (dispenseSlot > -1) { + itemstack = tileentitydispenser.getContents()[dispenseSlot]; + + // Copy item stack, because we want it to have 1 item + itemstack = new ItemStack(itemstack.id, 1, itemstack.damage); + } + // CraftBukkit end + + double d0 = (double) i + (double) b0 * 0.6D + 0.5D; + double d1 = (double) j + 0.5D; + double d2 = (double) k + (double) b1 * 0.6D + 0.5D; + + if (itemstack == null) { + world.e(1001, i, j, k, 0); + } else { + // CraftBukkit start + double d3 = random.nextDouble() * 0.1D + 0.2D; + double motX = (double) b0 * d3; + double motY = 0.20000000298023224D; + double motZ = (double) b1 * d3; + motX += random.nextGaussian() * 0.007499999832361937D * 6.0D; + motY += random.nextGaussian() * 0.007499999832361937D * 6.0D; + motZ += random.nextGaussian() * 0.007499999832361937D * 6.0D; + + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack).clone(); + + BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new Vector(motX, motY, motZ)); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + // Actually remove the item + tileentitydispenser.splitStack(dispenseSlot, 1); + + motX = event.getVelocity().getX(); + motY = event.getVelocity().getY(); + motZ = event.getVelocity().getZ(); + + itemstack = new ItemStack(event.getItem().getTypeId(), event.getItem().getAmount(), event.getItem().getDurability()); + // CraftBukkit end + + if (itemstack.id == Item.ARROW.id) { + EntityArrow entityarrow = new EntityArrow(world, d0, d1, d2); + + entityarrow.a((double) b0, 0.10000000149011612D, (double) b1, 1.1F, 6.0F); + entityarrow.fromPlayer = true; + world.addEntity(entityarrow); + world.e(1002, i, j, k, 0); + } else if (itemstack.id == Item.EGG.id) { + EntityEgg entityegg = new EntityEgg(world, d0, d1, d2); + + entityegg.a((double) b0, 0.10000000149011612D, (double) b1, 1.1F, 6.0F); + world.addEntity(entityegg); + world.e(1002, i, j, k, 0); + } else if (itemstack.id == Item.SNOW_BALL.id) { + EntitySnowball entitysnowball = new EntitySnowball(world, d0, d1, d2); + + entitysnowball.a((double) b0, 0.10000000149011612D, (double) b1, 1.1F, 6.0F); + world.addEntity(entitysnowball); + world.e(1002, i, j, k, 0); + } else { + EntityItem entityitem = new EntityItem(world, d0, d1 - 0.3D, d2, itemstack); + // CraftBukkit start + // double d3 = random.nextDouble() * 0.1D + 0.2D; // Moved up + entityitem.motX = motX; + entityitem.motY = motY; + entityitem.motZ = motZ; + // CraftBukkit end + world.addEntity(entityitem); + world.e(1000, i, j, k, 0); + } + + world.e(2000, i, j, k, b0 + 1 + (b1 + 1) * 3); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (l > 0 && Block.byId[l].isPowerSource()) { + boolean flag = world.isBlockIndirectlyPowered(i, j, k) || world.isBlockIndirectlyPowered(i, j + 1, k); + + if (flag) { + world.c(i, j, k, this.id, this.c()); + } + } + } + + public void a(World world, int i, int j, int k, Random random) { + if (world.isBlockIndirectlyPowered(i, j, k) || world.isBlockIndirectlyPowered(i, j + 1, k)) { + this.dispense(world, i, j, k, random); + } + } + + protected TileEntity a_() { + return new TileEntityDispenser(); + } + + public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) { + int l = MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3; + + if (l == 0) { + world.setData(i, j, k, 2); + } + + if (l == 1) { + world.setData(i, j, k, 5); + } + + if (l == 2) { + world.setData(i, j, k, 3); + } + + if (l == 3) { + world.setData(i, j, k, 4); + } + } + + public void remove(World world, int i, int j, int k) { + TileEntityDispenser tileentitydispenser = (TileEntityDispenser) world.getTileEntity(i, j, k); + + for (int l = 0; l < tileentitydispenser.getSize(); ++l) { + ItemStack itemstack = tileentitydispenser.getItem(l); + + if (itemstack != null) { + float f = this.a.nextFloat() * 0.8F + 0.1F; + float f1 = this.a.nextFloat() * 0.8F + 0.1F; + float f2 = this.a.nextFloat() * 0.8F + 0.1F; + + while (itemstack.count > 0) { + int i1 = this.a.nextInt(21) + 10; + + if (i1 > itemstack.count) { + i1 = itemstack.count; + } + + itemstack.count -= i1; + EntityItem entityitem = new EntityItem(world, (double) ((float) i + f), (double) ((float) j + f1), (double) ((float) k + f2), new ItemStack(itemstack.id, i1, itemstack.getData())); + float f3 = 0.05F; + + entityitem.motX = (double) ((float) this.a.nextGaussian() * f3); + entityitem.motY = (double) ((float) this.a.nextGaussian() * f3 + 0.2F); + entityitem.motZ = (double) ((float) this.a.nextGaussian() * f3); + world.addEntity(entityitem); + } + tileentitydispenser.setItem(l, null); + } + } + + super.remove(world, i, j, k); + } +} diff --git a/src/main/java/net/minecraft/server/BlockDoor.java b/src/main/java/net/minecraft/server/BlockDoor.java new file mode 100644 index 0000000..6e06050 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockDoor.java @@ -0,0 +1,211 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +import java.util.Random; + +public class BlockDoor extends Block { + + protected BlockDoor(int i, Material material) { + super(i, material); + this.textureId = 97; + if (material == Material.ORE) { + ++this.textureId; + } + + float f = 0.5F; + float f1 = 1.0F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f); + } + + public int a(int i, int j) { + if (i != 0 && i != 1) { + int k = this.d(j); + + if ((k == 0 || k == 2) ^ i <= 3) { + return this.textureId; + } else { + int l = k / 2 + (i & 1 ^ k); + + l += (j & 4) / 4; + int i1 = this.textureId - (j & 8) * 2; + + if ((l & 1) != 0) { + i1 = -i1; + } + + return i1; + } + } else { + return this.textureId; + } + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + this.a(world, i, j, k); + return super.e(world, i, j, k); + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + this.c(this.d(iblockaccess.getData(i, j, k))); + } + + public void c(int i) { + float f = 0.1875F; + + this.a(0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F); + if (i == 0) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); + } + + if (i == 1) { + this.a(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + + if (i == 2) { + this.a(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); + } + + if (i == 3) { + this.a(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); + } + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + this.interact(world, i, j, k, entityhuman); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (this.material == Material.ORE) { + return true; + } else { + int l = world.getData(i, j, k); + + if ((l & 8) != 0) { + if (world.getTypeId(i, j - 1, k) == this.id) { + this.interact(world, i, j - 1, k, entityhuman); + } + + return true; + } else { + if (world.getTypeId(i, j + 1, k) == this.id) { + world.setData(i, j + 1, k, (l ^ 4) + 8); + } + + world.setData(i, j, k, l ^ 4); + world.b(i, j - 1, k, i, j, k); + world.a(entityhuman, 1003, i, j, k, 0); + return true; + } + } + } + + public void setDoor(World world, int i, int j, int k, boolean flag) { + int l = world.getData(i, j, k); + + if ((l & 8) != 0) { + if (world.getTypeId(i, j - 1, k) == this.id) { + this.setDoor(world, i, j - 1, k, flag); + } + } else { + boolean flag1 = (world.getData(i, j, k) & 4) > 0; + + if (flag1 != flag) { + if (world.getTypeId(i, j + 1, k) == this.id) { + world.setData(i, j + 1, k, (l ^ 4) + 8); + } + + world.setData(i, j, k, l ^ 4); + world.b(i, j - 1, k, i, j, k); + world.a((EntityHuman) null, 1003, i, j, k, 0); + } + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + + if ((i1 & 8) != 0) { + if (world.getTypeId(i, j - 1, k) != this.id) { + world.setTypeId(i, j, k, 0); + } + + if (l > 0 && Block.byId[l].isPowerSource()) { + this.doPhysics(world, i, j - 1, k, l); + } + } else { + boolean flag = false; + + if (world.getTypeId(i, j + 1, k) != this.id) { + world.setTypeId(i, j, k, 0); + flag = true; + } + + if (!world.e(i, j - 1, k)) { + world.setTypeId(i, j, k, 0); + flag = true; + if (world.getTypeId(i, j + 1, k) == this.id) { + world.setTypeId(i, j + 1, k, 0); + } + } + + if (flag) { + if (!world.isStatic) { + this.g(world, i, j, k, i1); + } + } else if (l > 0 && Block.byId[l].isPowerSource()) { + // CraftBukkit start + org.bukkit.World bworld = world.getWorld(); + org.bukkit.block.Block block = bworld.getBlockAt(i, j, k); + org.bukkit.block.Block blockTop = bworld.getBlockAt(i, j + 1, k); + + int power = block.getBlockPower(); + int powerTop = blockTop.getBlockPower(); + if (powerTop > power) power = powerTop; + int oldPower = (world.getData(i, j, k) & 4) > 0 ? 15 : 0; + + if (oldPower == 0 ^ power == 0) { + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, oldPower, power); + world.getServer().getPluginManager().callEvent(eventRedstone); + + this.setDoor(world, i, j, k, eventRedstone.getNewCurrent() > 0); + } + // CraftBukkit end + } + } + } + + public int a(int i, Random random) { + return (i & 8) != 0 ? 0 : (this.material == Material.ORE ? Item.IRON_DOOR.id : Item.WOOD_DOOR.id); + } + + public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) { + this.a(world, i, j, k); + return super.a(world, i, j, k, vec3d, vec3d1); + } + + public int d(int i) { + return (i & 4) == 0 ? i - 1 & 3 : i & 3; + } + + public boolean canPlace(World world, int i, int j, int k) { + return j >= 127 ? false : world.e(i, j - 1, k) && super.canPlace(world, i, j, k) && super.canPlace(world, i, j + 1, k); + } + + public static boolean e(int i) { + return (i & 4) != 0; + } + + public int e() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/BlockFence.java b/src/main/java/net/minecraft/server/BlockFence.java new file mode 100644 index 0000000..6a10b7e --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockFence.java @@ -0,0 +1,70 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +public class BlockFence extends Block { + private boolean modernFencingBounding = false; + + public BlockFence(int i, int j) { + super(i, j, Material.WOOD); + modernFencingBounding = (boolean) PoseidonConfig.getInstance().getConfigOption("world-settings.use-modern-fence-bounding-boxes", false); + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.getTypeId(i, j - 1, k) == this.id ? true : (!world.getMaterial(i, j - 1, k).isBuildable() ? false : super.canPlace(world, i, j, k)); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + if(!modernFencingBounding) { + return AxisAlignedBB.b((double) i, (double) j, (double) k, (double) (i + 1), (double) ((float) j + 1.5F), (double) (k + 1)); + } + + boolean flag = this.b(world, i, j, k - 1); + boolean flag1 = this.b(world, i, j, k + 1); + boolean flag2 = this.b(world, i - 1, j, k); + boolean flag3 = this.b(world, i + 1, j, k); + float f = 0.375F; + float f1 = 0.625F; + float f2 = 0.375F; + float f3 = 0.625F; + + if (flag) { + f2 = 0.0F; + } + + if (flag1) { + f3 = 1.0F; + } + + if (flag2) { + f = 0.0F; + } + + if (flag3) { + f1 = 1.0F; + } + + return AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f2), (double) ((float) i + f1), (double) ((float) j + 1.5F), (double) ((float) k + f3)); + } + + public boolean b(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getTypeId(i, j, k); + + if (l != this.id) { + Block block = Block.byId[l]; + + return block != null && block.material.h() && block.b() ? block.material != Material.PUMPKIN : false; + } else { + return true; + } + } + + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/BlockFire.java b/src/main/java/net/minecraft/server/BlockFire.java new file mode 100644 index 0000000..f1ecd67 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockFire.java @@ -0,0 +1,242 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; +import org.bukkit.event.block.BlockSpreadEvent; +import org.bukkit.material.MaterialData; + +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class BlockFire extends Block { + + private int[] a = new int[256]; + private int[] b = new int[256]; + + protected BlockFire(int i, int j) { + super(i, j, Material.FIRE); + this.a(true); + } + + public void h() { + this.a(Block.WOOD.id, 5, 20); + this.a(Block.FENCE.id, 5, 20); + this.a(Block.WOOD_STAIRS.id, 5, 20); + this.a(Block.LOG.id, 5, 5); + this.a(Block.LEAVES.id, 30, 60); + this.a(Block.BOOKSHELF.id, 30, 20); + this.a(Block.TNT.id, 15, 100); + this.a(Block.LONG_GRASS.id, 60, 100); + this.a(Block.WOOL.id, 30, 60); + } + + private void a(int i, int j, int k) { + this.a[i] = j; + this.b[i] = k; + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public int a(Random random) { + return 0; + } + + public int c() { + return 40; + } + + public void a(World world, int i, int j, int k, Random random) { + boolean flag = world.getTypeId(i, j - 1, k) == Block.NETHERRACK.id; + + if (!this.canPlace(world, i, j, k)) { + world.setTypeId(i, j, k, 0); + } + + if (!flag && world.v() && (world.s(i, j, k) || world.s(i - 1, j, k) || world.s(i + 1, j, k) || world.s(i, j, k - 1) || world.s(i, j, k + 1))) { + world.setTypeId(i, j, k, 0); + } else { + int l = world.getData(i, j, k); + + if (l < 15) { + world.setRawData(i, j, k, l + random.nextInt(3) / 2); + } + + world.c(i, j, k, this.id, this.c()); + if (!flag && !this.g(world, i, j, k)) { + if (!world.e(i, j - 1, k) || l > 3) { + world.setTypeId(i, j, k, 0); + } + } else if (!flag && !this.b(world, i, j - 1, k) && l == 15 && random.nextInt(4) == 0) { + world.setTypeId(i, j, k, 0); + } else { + this.a(world, i + 1, j, k, 300, random, l); + this.a(world, i - 1, j, k, 300, random, l); + this.a(world, i, j - 1, k, 250, random, l); + this.a(world, i, j + 1, k, 250, random, l); + this.a(world, i, j, k - 1, 300, random, l); + this.a(world, i, j, k + 1, 300, random, l); + + // CraftBukkit start - Call to stop spread of fire. + org.bukkit.Server server = world.getServer(); + org.bukkit.World bworld = world.getWorld(); + + IgniteCause igniteCause = BlockIgniteEvent.IgniteCause.SPREAD; + org.bukkit.block.Block fromBlock = bworld.getBlockAt(i, j, k); + // CraftBukkit end + + for (int i1 = i - 1; i1 <= i + 1; ++i1) { + for (int j1 = k - 1; j1 <= k + 1; ++j1) { + for (int k1 = j - 1; k1 <= j + 4; ++k1) { + if (i1 != i || k1 != j || j1 != k) { + int l1 = 100; + + if (k1 > j + 1) { + l1 += (k1 - (j + 1)) * 100; + } + + int i2 = this.h(world, i1, k1, j1); + + if (i2 > 0) { + int j2 = (i2 + 40) / (l + 30); + + if (j2 > 0 && random.nextInt(l1) <= j2 && (!world.v() || !world.s(i1, k1, j1)) && !world.s(i1 - 1, k1, k) && !world.s(i1 + 1, k1, j1) && !world.s(i1, k1, j1 - 1) && !world.s(i1, k1, j1 + 1)) { + int k2 = l + random.nextInt(5) / 4; + + if (k2 > 15) { + k2 = 15; + } + // CraftBukkit start - Call to stop spread of fire. + org.bukkit.block.Block block = bworld.getBlockAt(i1, k1, j1); + + if (block.getTypeId() != Block.FIRE.id) { + BlockIgniteEvent event = new BlockIgniteEvent(block, igniteCause, null); + server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + continue; + } + + org.bukkit.block.BlockState blockState = bworld.getBlockAt(i1, k1, j1).getState(); + blockState.setTypeId(this.id); + blockState.setData(new MaterialData(this.id, (byte) k2)); + + BlockSpreadEvent spreadEvent = new BlockSpreadEvent(blockState.getBlock(), fromBlock, blockState); + server.getPluginManager().callEvent(spreadEvent); + + if (!spreadEvent.isCancelled()) { + blockState.update(true); + } + } + // CraftBukkit end + } + } + } + } + } + } + } + } + } + + private void a(World world, int i, int j, int k, int l, Random random, int i1) { + int j1 = this.b[world.getTypeId(i, j, k)]; + + if (random.nextInt(l) < j1) { + boolean flag = world.getTypeId(i, j, k) == Block.TNT.id; + // CraftBukkit start + org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(i, j, k); + + BlockBurnEvent event = new BlockBurnEvent(theBlock); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end + + if (random.nextInt(i1 + 10) < 5 && !world.s(i, j, k)) { + int k1 = i1 + random.nextInt(5) / 4; + + if (k1 > 15) { + k1 = 15; + } + + world.setTypeIdAndData(i, j, k, this.id, k1); + } else { + world.setTypeId(i, j, k, 0); + } + + if (flag) { + Block.TNT.postBreak(world, i, j, k, 1); + } + } + } + + private boolean g(World world, int i, int j, int k) { + return this.b(world, i + 1, j, k) ? true : (this.b(world, i - 1, j, k) ? true : (this.b(world, i, j - 1, k) ? true : (this.b(world, i, j + 1, k) ? true : (this.b(world, i, j, k - 1) ? true : this.b(world, i, j, k + 1))))); + } + + private int h(World world, int i, int j, int k) { + byte b0 = 0; + + if (!world.isEmpty(i, j, k)) { + return 0; + } else { + int l = this.f(world, i + 1, j, k, b0); + + l = this.f(world, i - 1, j, k, l); + l = this.f(world, i, j - 1, k, l); + l = this.f(world, i, j + 1, k, l); + l = this.f(world, i, j, k - 1, l); + l = this.f(world, i, j, k + 1, l); + return l; + } + } + + public boolean k_() { + return false; + } + + public boolean b(IBlockAccess iblockaccess, int i, int j, int k) { + return this.a[iblockaccess.getTypeId(i, j, k)] > 0; + } + + public int f(World world, int i, int j, int k, int l) { + int i1 = this.a[world.getTypeId(i, j, k)]; + + return i1 > l ? i1 : l; + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i, j - 1, k) || this.g(world, i, j, k); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!world.e(i, j - 1, k) && !this.g(world, i, j, k)) { + world.setTypeId(i, j, k, 0); + } + } + + public void c(World world, int i, int j, int k) { + if (world.getTypeId(i, j - 1, k) != Block.OBSIDIAN.id || !Block.PORTAL.a_(world, i, j, k)) { + if (!world.e(i, j - 1, k) && !this.g(world, i, j, k)) { + world.setTypeId(i, j, k, 0); + } else { + world.c(i, j, k, this.id, this.c()); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockFlower.java b/src/main/java/net/minecraft/server/BlockFlower.java new file mode 100644 index 0000000..eaa0819 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockFlower.java @@ -0,0 +1,55 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockFlower extends Block { + + protected BlockFlower(int i, int j) { + super(i, Material.PLANT); + this.textureId = j; + this.a(true); + float f = 0.2F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f * 3.0F, 0.5F + f); + } + + public boolean canPlace(World world, int i, int j, int k) { + return super.canPlace(world, i, j, k) && this.c(world.getTypeId(i, j - 1, k)); + } + + protected boolean c(int i) { + return i == Block.GRASS.id || i == Block.DIRT.id || i == Block.SOIL.id; + } + + public void doPhysics(World world, int i, int j, int k, int l) { + super.doPhysics(world, i, j, k, l); + this.g(world, i, j, k); + } + + public void a(World world, int i, int j, int k, Random random) { + this.g(world, i, j, k); + } + + protected final void g(World world, int i, int j, int k) { + if (!this.f(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + + public boolean f(World world, int i, int j, int k) { + return (world.k(i, j, k) >= 8 || world.isChunkLoaded(i, j, k)) && this.c(world.getTypeId(i, j - 1, k)); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/BlockFlowing.java b/src/main/java/net/minecraft/server/BlockFlowing.java new file mode 100644 index 0000000..ba7ece8 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockFlowing.java @@ -0,0 +1,308 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.block.BlockFace; +import org.bukkit.event.block.BlockFromToEvent; + +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class BlockFlowing extends BlockFluids { + + int a = 0; + boolean[] b = new boolean[4]; + int[] c = new int[4]; + + protected BlockFlowing(int i, Material material) { + super(i, material); + } + + private void i(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + + world.setRawTypeIdAndData(i, j, k, this.id + 1, l); + world.b(i, j, k, i, j, k); + world.notify(i, j, k); + } + + public void a(World world, int i, int j, int k, Random random) { + // CraftBukkit start + org.bukkit.World bworld = world.getWorld(); + org.bukkit.Server server = world.getServer(); + org.bukkit.block.Block source = bworld == null ? null : bworld.getBlockAt(i, j, k); + // CraftBukkit end + + int l = this.g(world, i, j, k); + byte b0 = 1; + + if (this.material == Material.LAVA && !world.worldProvider.d) { + b0 = 2; + } + + boolean flag = true; + int i1; + + if (l > 0) { + byte b1 = -100; + + this.a = 0; + int j1 = this.f(world, i - 1, j, k, b1); + + j1 = this.f(world, i + 1, j, k, j1); + j1 = this.f(world, i, j, k - 1, j1); + j1 = this.f(world, i, j, k + 1, j1); + i1 = j1 + b0; + if (i1 >= 8 || j1 < 0) { + i1 = -1; + } + + if (this.g(world, i, j + 1, k) >= 0) { + int k1 = this.g(world, i, j + 1, k); + + if (k1 >= 8) { + i1 = k1; + } else { + i1 = k1 + 8; + } + } + + if (this.a >= 2 && this.material == Material.WATER) { + if (world.getMaterial(i, j - 1, k).isBuildable()) { + i1 = 0; + } else if (world.getMaterial(i, j - 1, k) == this.material && world.getData(i, j, k) == 0) { + i1 = 0; + } + } + + if (this.material == Material.LAVA && l < 8 && i1 < 8 && i1 > l && random.nextInt(4) != 0) { + // Poseidon start - Fix flowing lava not disappearing + boolean fixFlowingLava = PoseidonConfig.getInstance().getConfigBoolean("world.settings.flowing-lava-fix.enabled", true); + if (!fixFlowingLava) { + i1 = l; + } + // Poseidon end + flag = false; + } + + if (i1 != l) { + l = i1; + if (i1 < 0) { + world.setTypeId(i, j, k, 0); + } else { + world.setData(i, j, k, i1); + world.c(i, j, k, this.id, this.c()); + world.applyPhysics(i, j, k, this.id); + } + } else if (flag) { + this.i(world, i, j, k); + } + } else { + this.i(world, i, j, k); + } + + if (this.l(world, i, j - 1, k)) { + // CraftBukkit start - send "down" to the server + BlockFromToEvent event = new BlockFromToEvent(source, BlockFace.DOWN); + if (server != null) { + server.getPluginManager().callEvent(event); + } + + if (!event.isCancelled()) { + if (l >= 8) { + world.setTypeIdAndData(i, j - 1, k, this.id, l); + } else { + world.setTypeIdAndData(i, j - 1, k, this.id, l + 8); + } + } + // CraftBukkit end + } else if (l >= 0 && (l == 0 || this.k(world, i, j - 1, k))) { + boolean[] aboolean = this.j(world, i, j, k); + + i1 = l + b0; + if (l >= 8) { + i1 = 1; + } + + if (i1 >= 8) { + return; + } + + // CraftBukkit start - all four cardinal directions. Do not change the order! + BlockFace[] faces = new BlockFace[] { BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST }; + int index = 0; + + for (BlockFace currentFace: faces) { + if (aboolean[index]) { + BlockFromToEvent event = new BlockFromToEvent(source, currentFace); + + if (server != null) { + server.getPluginManager().callEvent(event); + } + + if (!event.isCancelled()) { + this.flow(world, i + currentFace.getModX(), j, k + currentFace.getModZ(), i1); + } + } + index++; + } + // CraftBukkit end + } + } + + private void flow(World world, int i, int j, int k, int l) { + if (this.l(world, i, j, k)) { + int i1 = world.getTypeId(i, j, k); + + if (i1 > 0) { + if (this.material == Material.LAVA) { + this.h(world, i, j, k); + } else { + Block.byId[i1].g(world, i, j, k, world.getData(i, j, k)); + } + } + + world.setTypeIdAndData(i, j, k, this.id, l); + } + } + + private int b(World world, int i, int j, int k, int l, int i1) { + int j1 = 1000; + + for (int k1 = 0; k1 < 4; ++k1) { + if ((k1 != 0 || i1 != 1) && (k1 != 1 || i1 != 0) && (k1 != 2 || i1 != 3) && (k1 != 3 || i1 != 2)) { + int l1 = i; + int i2 = k; + + if (k1 == 0) { + l1 = i - 1; + } + + if (k1 == 1) { + ++l1; + } + + if (k1 == 2) { + i2 = k - 1; + } + + if (k1 == 3) { + ++i2; + } + + if (!this.k(world, l1, j, i2) && (world.getMaterial(l1, j, i2) != this.material || world.getData(l1, j, i2) != 0)) { + if (!this.k(world, l1, j - 1, i2)) { + return l; + } + + if (l < 4) { + int j2 = this.b(world, l1, j, i2, l + 1, k1); + + if (j2 < j1) { + j1 = j2; + } + } + } + } + } + + return j1; + } + + private boolean[] j(World world, int i, int j, int k) { + int l; + int i1; + + for (l = 0; l < 4; ++l) { + this.c[l] = 1000; + i1 = i; + int j1 = k; + + if (l == 0) { + i1 = i - 1; + } + + if (l == 1) { + ++i1; + } + + if (l == 2) { + j1 = k - 1; + } + + if (l == 3) { + ++j1; + } + + if (!this.k(world, i1, j, j1) && (world.getMaterial(i1, j, j1) != this.material || world.getData(i1, j, j1) != 0)) { + if (!this.k(world, i1, j - 1, j1)) { + this.c[l] = 0; + } else { + this.c[l] = this.b(world, i1, j, j1, 1, l); + } + } + } + + l = this.c[0]; + + for (i1 = 1; i1 < 4; ++i1) { + if (this.c[i1] < l) { + l = this.c[i1]; + } + } + + for (i1 = 0; i1 < 4; ++i1) { + this.b[i1] = this.c[i1] == l; + } + + return this.b; + } + + private boolean k(World world, int i, int j, int k) { + int l = world.getTypeId(i, j, k); + + if (l != Block.WOODEN_DOOR.id && l != Block.IRON_DOOR_BLOCK.id && l != Block.SIGN_POST.id && l != Block.LADDER.id && l != Block.SUGAR_CANE_BLOCK.id) { + if (l == 0) { + return false; + } else { + Material material = Block.byId[l].material; + + return material.isSolid(); + } + } else { + return true; + } + } + + protected int f(World world, int i, int j, int k, int l) { + int i1 = this.g(world, i, j, k); + + if (i1 < 0) { + return l; + } else { + if (i1 == 0) { + ++this.a; + } + + if (i1 >= 8) { + i1 = 0; + } + + return l >= 0 && i1 >= l ? l : i1; + } + } + + private boolean l(World world, int i, int j, int k) { + Material material = world.getMaterial(i, j, k); + + return material == this.material ? false : (material == Material.LAVA ? false : !this.k(world, i, j, k)); + } + + public void c(World world, int i, int j, int k) { + super.c(world, i, j, k); + if (world.getTypeId(i, j, k) == this.id) { + world.c(i, j, k, this.id, this.c()); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockFluids.java b/src/main/java/net/minecraft/server/BlockFluids.java new file mode 100644 index 0000000..0670b90 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockFluids.java @@ -0,0 +1,234 @@ +package net.minecraft.server; + +import java.util.Random; + +public abstract class BlockFluids extends Block { + + protected BlockFluids(int i, Material material) { + super(i, (material == Material.LAVA ? 14 : 12) * 16 + 13, material); + float f = 0.0F; + float f1 = 0.0F; + + this.a(0.0F + f1, 0.0F + f, 0.0F + f1, 1.0F + f1, 1.0F + f, 1.0F + f1); + this.a(true); + } + + public static float c(int i) { + if (i >= 8) { + i = 0; + } + + float f = (float) (i + 1) / 9.0F; + + return f; + } + + public int a(int i) { + return i != 0 && i != 1 ? this.textureId + 1 : this.textureId; + } + + protected int g(World world, int i, int j, int k) { + return world.getMaterial(i, j, k) != this.material ? -1 : world.getData(i, j, k); + } + + protected int b(IBlockAccess iblockaccess, int i, int j, int k) { + if (iblockaccess.getMaterial(i, j, k) != this.material) { + return -1; + } else { + int l = iblockaccess.getData(i, j, k); + + if (l >= 8) { + l = 0; + } + + return l; + } + } + + public boolean b() { + return false; + } + + public boolean a() { + return false; + } + + public boolean a(int i, boolean flag) { + return flag && i == 0; + } + + public boolean b(IBlockAccess iblockaccess, int i, int j, int k, int l) { + Material material = iblockaccess.getMaterial(i, j, k); + + return material == this.material ? false : (material == Material.ICE ? false : (l == 1 ? true : super.b(iblockaccess, i, j, k, l))); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public int a(int i, Random random) { + return 0; + } + + public int a(Random random) { + return 0; + } + + private Vec3D c(IBlockAccess iblockaccess, int i, int j, int k) { + Vec3D vec3d = Vec3D.create(0.0D, 0.0D, 0.0D); + int l = this.b(iblockaccess, i, j, k); + + for (int i1 = 0; i1 < 4; ++i1) { + int j1 = i; + int k1 = k; + + if (i1 == 0) { + j1 = i - 1; + } + + if (i1 == 1) { + k1 = k - 1; + } + + if (i1 == 2) { + ++j1; + } + + if (i1 == 3) { + ++k1; + } + + int l1 = this.b(iblockaccess, j1, j, k1); + int i2; + + if (l1 < 0) { + if (!iblockaccess.getMaterial(j1, j, k1).isSolid()) { + l1 = this.b(iblockaccess, j1, j - 1, k1); + if (l1 >= 0) { + i2 = l1 - (l - 8); + vec3d = vec3d.add((double) ((j1 - i) * i2), (double) ((j - j) * i2), (double) ((k1 - k) * i2)); + } + } + } else if (l1 >= 0) { + i2 = l1 - l; + vec3d = vec3d.add((double) ((j1 - i) * i2), (double) ((j - j) * i2), (double) ((k1 - k) * i2)); + } + } + + if (iblockaccess.getData(i, j, k) >= 8) { + boolean flag = false; + + if (flag || this.b(iblockaccess, i, j, k - 1, 2)) { + flag = true; + } + + if (flag || this.b(iblockaccess, i, j, k + 1, 3)) { + flag = true; + } + + if (flag || this.b(iblockaccess, i - 1, j, k, 4)) { + flag = true; + } + + if (flag || this.b(iblockaccess, i + 1, j, k, 5)) { + flag = true; + } + + if (flag || this.b(iblockaccess, i, j + 1, k - 1, 2)) { + flag = true; + } + + if (flag || this.b(iblockaccess, i, j + 1, k + 1, 3)) { + flag = true; + } + + if (flag || this.b(iblockaccess, i - 1, j + 1, k, 4)) { + flag = true; + } + + if (flag || this.b(iblockaccess, i + 1, j + 1, k, 5)) { + flag = true; + } + + if (flag) { + vec3d = vec3d.b().add(0.0D, -6.0D, 0.0D); + } + } + + vec3d = vec3d.b(); + return vec3d; + } + + public void a(World world, int i, int j, int k, Entity entity, Vec3D vec3d) { + Vec3D vec3d1 = this.c((IBlockAccess) world, i, j, k); + + vec3d.a += vec3d1.a; + vec3d.b += vec3d1.b; + vec3d.c += vec3d1.c; + } + + public int c() { + return this.material == Material.WATER ? 5 : (this.material == Material.LAVA ? 30 : 0); + } + + public void a(World world, int i, int j, int k, Random random) { + super.a(world, i, j, k, random); + } + + public void c(World world, int i, int j, int k) { + this.i(world, i, j, k); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + this.i(world, i, j, k); + } + + private void i(World world, int i, int j, int k) { + if (world.getTypeId(i, j, k) == this.id) { + if (this.material == Material.LAVA) { + boolean flag = false; + + if (flag || world.getMaterial(i, j, k - 1) == Material.WATER) { + flag = true; + } + + if (flag || world.getMaterial(i, j, k + 1) == Material.WATER) { + flag = true; + } + + if (flag || world.getMaterial(i - 1, j, k) == Material.WATER) { + flag = true; + } + + if (flag || world.getMaterial(i + 1, j, k) == Material.WATER) { + flag = true; + } + + if (flag || world.getMaterial(i, j + 1, k) == Material.WATER) { + flag = true; + } + + if (flag) { + int l = world.getData(i, j, k); + + if (l == 0) { + world.setTypeId(i, j, k, Block.OBSIDIAN.id); + } else if (l <= 4) { + world.setTypeId(i, j, k, Block.COBBLESTONE.id); + } + + this.h(world, i, j, k); + } + } + } + } + + protected void h(World world, int i, int j, int k) { + world.makeSound((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), "random.fizz", 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); + + for (int l = 0; l < 8; ++l) { + world.a("largesmoke", (double) i + Math.random(), (double) j + 1.2D, (double) k + Math.random(), 0.0D, 0.0D, 0.0D); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockFurnace.java b/src/main/java/net/minecraft/server/BlockFurnace.java new file mode 100644 index 0000000..5c306e5 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockFurnace.java @@ -0,0 +1,147 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockFurnace extends BlockContainer { + + private Random a = new Random(); + private final boolean b; + private static boolean c = false; + + protected BlockFurnace(int i, boolean flag) { + super(i, Material.STONE); + this.b = flag; + this.textureId = 45; + } + + public int a(int i, Random random) { + return Block.FURNACE.id; + } + + public void c(World world, int i, int j, int k) { + super.c(world, i, j, k); + this.g(world, i, j, k); + } + + private void g(World world, int i, int j, int k) { + if (!world.isStatic) { + int l = world.getTypeId(i, j, k - 1); + int i1 = world.getTypeId(i, j, k + 1); + int j1 = world.getTypeId(i - 1, j, k); + int k1 = world.getTypeId(i + 1, j, k); + byte b0 = 3; + + if (Block.o[l] && !Block.o[i1]) { + b0 = 3; + } + + if (Block.o[i1] && !Block.o[l]) { + b0 = 2; + } + + if (Block.o[j1] && !Block.o[k1]) { + b0 = 5; + } + + if (Block.o[k1] && !Block.o[j1]) { + b0 = 4; + } + + world.setData(i, j, k, b0); + } + } + + public int a(int i) { + return i == 1 ? this.textureId + 17 : (i == 0 ? this.textureId + 17 : (i == 3 ? this.textureId - 1 : this.textureId)); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (world.isStatic) { + return true; + } else { + TileEntityFurnace tileentityfurnace = (TileEntityFurnace) world.getTileEntity(i, j, k); + + entityhuman.a(tileentityfurnace); + return true; + } + } + + public static void a(boolean flag, World world, int i, int j, int k) { + int l = world.getData(i, j, k); + TileEntity tileentity = world.getTileEntity(i, j, k); + if (tileentity == null) return; // CraftBukkit + + c = true; + if (flag) { + world.setTypeId(i, j, k, Block.BURNING_FURNACE.id); + } else { + world.setTypeId(i, j, k, Block.FURNACE.id); + } + + c = false; + world.setData(i, j, k, l); + tileentity.j(); + world.setTileEntity(i, j, k, tileentity); + } + + protected TileEntity a_() { + return new TileEntityFurnace(); + } + + public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) { + int l = MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3; + + if (l == 0) { + world.setData(i, j, k, 2); + } + + if (l == 1) { + world.setData(i, j, k, 5); + } + + if (l == 2) { + world.setData(i, j, k, 3); + } + + if (l == 3) { + world.setData(i, j, k, 4); + } + } + + public void remove(World world, int i, int j, int k) { + if (!c) { + TileEntityFurnace tileentityfurnace = (TileEntityFurnace) world.getTileEntity(i, j, k); + + if (tileentityfurnace == null) return; // CraftBukkit + for (int l = 0; l < tileentityfurnace.getSize(); ++l) { + ItemStack itemstack = tileentityfurnace.getItem(l); + + if (itemstack != null) { + float f = this.a.nextFloat() * 0.8F + 0.1F; + float f1 = this.a.nextFloat() * 0.8F + 0.1F; + float f2 = this.a.nextFloat() * 0.8F + 0.1F; + + while (itemstack.count > 0) { + int i1 = this.a.nextInt(21) + 10; + + if (i1 > itemstack.count) { + i1 = itemstack.count; + } + + itemstack.count -= i1; + EntityItem entityitem = new EntityItem(world, (double) ((float) i + f), (double) ((float) j + f1), (double) ((float) k + f2), new ItemStack(itemstack.id, i1, itemstack.getData())); + float f3 = 0.05F; + + entityitem.motX = (double) ((float) this.a.nextGaussian() * f3); + entityitem.motY = (double) ((float) this.a.nextGaussian() * f3 + 0.2F); + entityitem.motZ = (double) ((float) this.a.nextGaussian() * f3); + world.addEntity(entityitem); + } + tileentityfurnace.setItem(l, null); + } + } + } + + super.remove(world, i, j, k); + } +} diff --git a/src/main/java/net/minecraft/server/BlockGlass.java b/src/main/java/net/minecraft/server/BlockGlass.java new file mode 100644 index 0000000..35d1887 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockGlass.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockGlass extends BlockBreakable { + + public BlockGlass(int i, int j, Material material, boolean flag) { + super(i, j, material, flag); + } + + public int a(Random random) { + return 0; + } +} diff --git a/src/main/java/net/minecraft/server/BlockGrass.java b/src/main/java/net/minecraft/server/BlockGrass.java new file mode 100644 index 0000000..9a93d61 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockGrass.java @@ -0,0 +1,64 @@ +package net.minecraft.server; + +import java.util.Random; + +// CraftBukkit start +import org.bukkit.event.block.BlockSpreadEvent; +import org.bukkit.event.block.BlockFadeEvent; +//CraftBukkit end + +public class BlockGrass extends Block { + + protected BlockGrass(int i) { + super(i, Material.GRASS); + this.textureId = 3; + this.a(true); + } + + public void a(World world, int i, int j, int k, Random random) { + if (!world.isStatic) { + if (world.getLightLevel(i, j + 1, k) < 4 && Block.q[world.getTypeId(i, j + 1, k)] > 2) { + if (random.nextInt(4) != 0) { + return; + } + + // CraftBukkit start + org.bukkit.World bworld = world.getWorld(); + org.bukkit.block.BlockState blockState = bworld.getBlockAt(i, j, k).getState(); + blockState.setTypeId(Block.DIRT.id); + + BlockFadeEvent event = new BlockFadeEvent(blockState.getBlock(), blockState); + world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + blockState.update(true); + } + // CraftBukkit end + } else if (world.getLightLevel(i, j + 1, k) >= 9) { + int l = i + random.nextInt(3) - 1; + int i1 = j + random.nextInt(5) - 3; + int j1 = k + random.nextInt(3) - 1; + int k1 = world.getTypeId(l, i1 + 1, j1); + + if (world.getTypeId(l, i1, j1) == Block.DIRT.id && world.getLightLevel(l, i1 + 1, j1) >= 4 && Block.q[k1] <= 2) { + // CraftBukkit start + org.bukkit.World bworld = world.getWorld(); + org.bukkit.block.BlockState blockState = bworld.getBlockAt(l, i1, j1).getState(); + blockState.setTypeId(this.id); + + BlockSpreadEvent event = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(i, j, k), blockState); + world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + blockState.update(true); + } + // CraftBukkit end + } + } + } + } + + public int a(int i, Random random) { + return Block.DIRT.a(0, random); + } +} diff --git a/src/main/java/net/minecraft/server/BlockGravel.java b/src/main/java/net/minecraft/server/BlockGravel.java new file mode 100644 index 0000000..a180226 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockGravel.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockGravel extends BlockSand { + + public BlockGravel(int i, int j) { + super(i, j); + } + + public int a(int i, Random random) { + return random.nextInt(10) == 0 ? Item.FLINT.id : this.id; + } +} diff --git a/src/main/java/net/minecraft/server/BlockIce.java b/src/main/java/net/minecraft/server/BlockIce.java new file mode 100644 index 0000000..f6555dd --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockIce.java @@ -0,0 +1,44 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.event.CraftEventFactory; + +import java.util.Random; + +public class BlockIce extends BlockBreakable { + + public BlockIce(int i, int j) { + super(i, j, Material.ICE, false); + this.frictionFactor = 0.98F; + this.a(true); + } + + public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) { + super.a(world, entityhuman, i, j, k, l); + Material material = world.getMaterial(i, j - 1, k); + + if (material.isSolid() || material.isLiquid()) { + world.setTypeId(i, j, k, Block.WATER.id); + } + } + + public int a(Random random) { + return 0; + } + + public void a(World world, int i, int j, int k, Random random) { + if (world.a(EnumSkyBlock.BLOCK, i, j, k) > 11 - Block.q[this.id]) { + // CraftBukkit start + if (CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(i, j, k), Block.STATIONARY_WATER.id).isCancelled()) { + return; + } + // CraftBukkit end + + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, Block.STATIONARY_WATER.id); + } + } + + public int e() { + return 0; + } +} diff --git a/src/main/java/net/minecraft/server/BlockJukeBox.java b/src/main/java/net/minecraft/server/BlockJukeBox.java new file mode 100644 index 0000000..67f857a --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockJukeBox.java @@ -0,0 +1,70 @@ +package net.minecraft.server; + +public class BlockJukeBox extends BlockContainer { + + protected BlockJukeBox(int i, int j) { + super(i, j, Material.WOOD); + } + + public int a(int i) { + return this.textureId + (i == 1 ? 1 : 0); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (world.getData(i, j, k) == 0) { + return false; + } else { + this.b_(world, i, j, k); + return true; + } + } + + public void f(World world, int i, int j, int k, int l) { + if (!world.isStatic) { + TileEntityRecordPlayer tileentityrecordplayer = (TileEntityRecordPlayer) world.getTileEntity(i, j, k); + + tileentityrecordplayer.a = l; + tileentityrecordplayer.update(); + world.setData(i, j, k, 1); + } + } + + public void b_(World world, int i, int j, int k) { + if (!world.isStatic) { + TileEntityRecordPlayer tileentityrecordplayer = (TileEntityRecordPlayer) world.getTileEntity(i, j, k); + if (tileentityrecordplayer == null) return; // CraftBukkit + int l = tileentityrecordplayer.a; + + if (l != 0) { + world.e(1005, i, j, k, 0); + world.a((String) null, i, j, k); + tileentityrecordplayer.a = 0; + tileentityrecordplayer.update(); + world.setData(i, j, k, 0); + float f = 0.7F; + double d0 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + double d1 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.2D + 0.6D; + double d2 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + EntityItem entityitem = new EntityItem(world, (double) i + d0, (double) j + d1, (double) k + d2, new ItemStack(l, 1, 0)); + + entityitem.pickupDelay = 10; + world.addEntity(entityitem); + } + } + } + + public void remove(World world, int i, int j, int k) { + this.b_(world, i, j, k); + super.remove(world, i, j, k); + } + + public void dropNaturally(World world, int i, int j, int k, int l, float f) { + if (!world.isStatic) { + super.dropNaturally(world, i, j, k, l, f); + } + } + + protected TileEntity a_() { + return new TileEntityRecordPlayer(); + } +} diff --git a/src/main/java/net/minecraft/server/BlockLadder.java b/src/main/java/net/minecraft/server/BlockLadder.java new file mode 100644 index 0000000..cea5732 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLadder.java @@ -0,0 +1,99 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockLadder extends Block { + + protected BlockLadder(int i, int j) { + super(i, j, Material.ORIENTABLE); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + float f = 0.125F; + + if (l == 2) { + this.a(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); + } + + if (l == 3) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); + } + + if (l == 4) { + this.a(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + + if (l == 5) { + this.a(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); + } + + return super.e(world, i, j, k); + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i - 1, j, k) ? true : (world.e(i + 1, j, k) ? true : (world.e(i, j, k - 1) ? true : world.e(i, j, k + 1))); + } + + public void postPlace(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + + if ((i1 == 0 || l == 2) && world.e(i, j, k + 1)) { + i1 = 2; + } + + if ((i1 == 0 || l == 3) && world.e(i, j, k - 1)) { + i1 = 3; + } + + if ((i1 == 0 || l == 4) && world.e(i + 1, j, k)) { + i1 = 4; + } + + if ((i1 == 0 || l == 5) && world.e(i - 1, j, k)) { + i1 = 5; + } + + world.setData(i, j, k, i1); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + boolean flag = false; + + if (i1 == 2 && world.e(i, j, k + 1)) { + flag = true; + } + + if (i1 == 3 && world.e(i, j, k - 1)) { + flag = true; + } + + if (i1 == 4 && world.e(i + 1, j, k)) { + flag = true; + } + + if (i1 == 5 && world.e(i - 1, j, k)) { + flag = true; + } + + if (!flag) { + this.g(world, i, j, k, i1); + world.setTypeId(i, j, k, 0); + } + + super.doPhysics(world, i, j, k, l); + } + + public int a(Random random) { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/BlockLeaves.java b/src/main/java/net/minecraft/server/BlockLeaves.java new file mode 100644 index 0000000..d8456e7 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLeaves.java @@ -0,0 +1,165 @@ +package net.minecraft.server; + +import org.bukkit.event.block.LeavesDecayEvent; + +import java.util.Random; + +public class BlockLeaves extends BlockLeavesBase { + + private int c; + int[] a; + + protected BlockLeaves(int i, int j) { + super(i, j, Material.LEAVES, false); + this.c = j; + this.a(true); + } + + public void remove(World world, int i, int j, int k) { + byte b0 = 1; + int l = b0 + 1; + + if (world.a(i - l, j - l, k - l, i + l, j + l, k + l)) { + for (int i1 = -b0; i1 <= b0; ++i1) { + for (int j1 = -b0; j1 <= b0; ++j1) { + for (int k1 = -b0; k1 <= b0; ++k1) { + int l1 = world.getTypeId(i + i1, j + j1, k + k1); + + if (l1 == Block.LEAVES.id) { + int i2 = world.getData(i + i1, j + j1, k + k1); + + world.setRawData(i + i1, j + j1, k + k1, i2 | 8); + } + } + } + } + } + } + + public void a(World world, int i, int j, int k, Random random) { + if (!world.isStatic) { + int l = world.getData(i, j, k); + + if ((l & 8) != 0) { + byte b0 = 4; + int i1 = b0 + 1; + byte b1 = 32; + int j1 = b1 * b1; + int k1 = b1 / 2; + + if (this.a == null) { + this.a = new int[b1 * b1 * b1]; + } + + int l1; + + if (world.a(i - i1, j - i1, k - i1, i + i1, j + i1, k + i1)) { + int i2; + int j2; + int k2; + + for (l1 = -b0; l1 <= b0; ++l1) { + for (i2 = -b0; i2 <= b0; ++i2) { + for (j2 = -b0; j2 <= b0; ++j2) { + k2 = world.getTypeId(i + l1, j + i2, k + j2); + if (k2 == Block.LOG.id) { + this.a[(l1 + k1) * j1 + (i2 + k1) * b1 + j2 + k1] = 0; + } else if (k2 == Block.LEAVES.id) { + this.a[(l1 + k1) * j1 + (i2 + k1) * b1 + j2 + k1] = -2; + } else { + this.a[(l1 + k1) * j1 + (i2 + k1) * b1 + j2 + k1] = -1; + } + } + } + } + + for (l1 = 1; l1 <= 4; ++l1) { + for (i2 = -b0; i2 <= b0; ++i2) { + for (j2 = -b0; j2 <= b0; ++j2) { + for (k2 = -b0; k2 <= b0; ++k2) { + if (this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + k2 + k1] == l1 - 1) { + if (this.a[(i2 + k1 - 1) * j1 + (j2 + k1) * b1 + k2 + k1] == -2) { + this.a[(i2 + k1 - 1) * j1 + (j2 + k1) * b1 + k2 + k1] = l1; + } + + if (this.a[(i2 + k1 + 1) * j1 + (j2 + k1) * b1 + k2 + k1] == -2) { + this.a[(i2 + k1 + 1) * j1 + (j2 + k1) * b1 + k2 + k1] = l1; + } + + if (this.a[(i2 + k1) * j1 + (j2 + k1 - 1) * b1 + k2 + k1] == -2) { + this.a[(i2 + k1) * j1 + (j2 + k1 - 1) * b1 + k2 + k1] = l1; + } + + if (this.a[(i2 + k1) * j1 + (j2 + k1 + 1) * b1 + k2 + k1] == -2) { + this.a[(i2 + k1) * j1 + (j2 + k1 + 1) * b1 + k2 + k1] = l1; + } + + if (this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + (k2 + k1 - 1)] == -2) { + this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + (k2 + k1 - 1)] = l1; + } + + if (this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + k2 + k1 + 1] == -2) { + this.a[(i2 + k1) * j1 + (j2 + k1) * b1 + k2 + k1 + 1] = l1; + } + } + } + } + } + } + } + + l1 = this.a[k1 * j1 + k1 * b1 + k1]; + if (l1 >= 0) { + world.setRawData(i, j, k, l & -9); + } else { + this.g(world, i, j, k); + } + } + } + } + + private void g(World world, int i, int j, int k) { + // CraftBukkit start + LeavesDecayEvent event = new LeavesDecayEvent(world.getWorld().getBlockAt(i, j, k)); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) return; + // CraftBukkit end + + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + + public int a(Random random) { + return random.nextInt(20) == 0 ? 1 : 0; + } + + public int a(int i, Random random) { + return Block.SAPLING.id; + } + + public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) { + if (!world.isStatic && entityhuman.G() != null && entityhuman.G().id == Item.SHEARS.id) { + entityhuman.a(StatisticList.C[this.id], 1); + this.a(world, i, j, k, new ItemStack(Block.LEAVES.id, 1, l & 3)); + } else { + super.a(world, entityhuman, i, j, k, l); + } + } + + protected int a_(int i) { + return i & 3; + } + + public boolean a() { + return !this.b; + } + + public int a(int i, int j) { + return (j & 3) == 1 ? this.textureId + 80 : this.textureId; + } + + public void b(World world, int i, int j, int k, Entity entity) { + super.b(world, i, j, k, entity); + } +} diff --git a/src/main/java/net/minecraft/server/BlockLeavesBase.java b/src/main/java/net/minecraft/server/BlockLeavesBase.java new file mode 100644 index 0000000..692862d --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLeavesBase.java @@ -0,0 +1,15 @@ +package net.minecraft.server; + +public class BlockLeavesBase extends Block { + + protected boolean b; + + protected BlockLeavesBase(int i, int j, Material material, boolean flag) { + super(i, j, material); + this.b = flag; + } + + public boolean a() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/BlockLever.java b/src/main/java/net/minecraft/server/BlockLever.java new file mode 100644 index 0000000..76a0560 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLever.java @@ -0,0 +1,216 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +public class BlockLever extends Block { + + protected BlockLever(int i, int j) { + super(i, j, Material.ORIENTABLE); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k, int l) { + return l == 1 && world.e(i, j - 1, k) ? true : (l == 2 && world.e(i, j, k + 1) ? true : (l == 3 && world.e(i, j, k - 1) ? true : (l == 4 && world.e(i + 1, j, k) ? true : l == 5 && world.e(i - 1, j, k)))); + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i - 1, j, k) ? true : (world.e(i + 1, j, k) ? true : (world.e(i, j, k - 1) ? true : (world.e(i, j, k + 1) ? true : world.e(i, j - 1, k)))); + } + + public void postPlace(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + int j1 = i1 & 8; + + i1 &= 7; + i1 = -1; + if (l == 1 && world.e(i, j - 1, k)) { + i1 = 5 + world.random.nextInt(2); + } + + if (l == 2 && world.e(i, j, k + 1)) { + i1 = 4; + } + + if (l == 3 && world.e(i, j, k - 1)) { + i1 = 3; + } + + if (l == 4 && world.e(i + 1, j, k)) { + i1 = 2; + } + + if (l == 5 && world.e(i - 1, j, k)) { + i1 = 1; + } + + if (i1 == -1) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } else { + world.setData(i, j, k, i1 + j1); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (this.g(world, i, j, k)) { + int i1 = world.getData(i, j, k) & 7; + boolean flag = false; + + if (!world.e(i - 1, j, k) && i1 == 1) { + flag = true; + } + + if (!world.e(i + 1, j, k) && i1 == 2) { + flag = true; + } + + if (!world.e(i, j, k - 1) && i1 == 3) { + flag = true; + } + + if (!world.e(i, j, k + 1) && i1 == 4) { + flag = true; + } + + if (!world.e(i, j - 1, k) && i1 == 5) { + flag = true; + } + + if (!world.e(i, j - 1, k) && i1 == 6) { + flag = true; + } + + if (flag) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + } + + private boolean g(World world, int i, int j, int k) { + if (!this.canPlace(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + return false; + } else { + return true; + } + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getData(i, j, k) & 7; + float f = 0.1875F; + + if (l == 1) { + this.a(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f); + } else if (l == 2) { + this.a(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f); + } else if (l == 3) { + this.a(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F); + } else if (l == 4) { + this.a(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F); + } else { + f = 0.25F; + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.6F, 0.5F + f); + } + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + this.interact(world, i, j, k, entityhuman); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (world.isStatic) { + return true; + } else { + int l = world.getData(i, j, k); + int i1 = l & 7; + int j1 = 8 - (l & 8); + + // CraftBukkit start - Interact Lever + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + int old = (j1 != 8) ? 1 : 0; + int current = (j1 == 8) ? 1 : 0; + + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, old, current); + world.getServer().getPluginManager().callEvent(eventRedstone); + + if ((eventRedstone.getNewCurrent() > 0) != (j1 == 8)) { + return true; + } + // CraftBukkit end + + world.setData(i, j, k, i1 + j1); + world.b(i, j, k, i, j, k); + world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "random.click", 0.3F, j1 > 0 ? 0.6F : 0.5F); + world.applyPhysics(i, j, k, this.id); + if (i1 == 1) { + world.applyPhysics(i - 1, j, k, this.id); + } else if (i1 == 2) { + world.applyPhysics(i + 1, j, k, this.id); + } else if (i1 == 3) { + world.applyPhysics(i, j, k - 1, this.id); + } else if (i1 == 4) { + world.applyPhysics(i, j, k + 1, this.id); + } else { + world.applyPhysics(i, j - 1, k, this.id); + } + + return true; + } + } + + public void remove(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + + if ((l & 8) > 0) { + world.applyPhysics(i, j, k, this.id); + int i1 = l & 7; + + if (i1 == 1) { + world.applyPhysics(i - 1, j, k, this.id); + } else if (i1 == 2) { + world.applyPhysics(i + 1, j, k, this.id); + } else if (i1 == 3) { + world.applyPhysics(i, j, k - 1, this.id); + } else if (i1 == 4) { + world.applyPhysics(i, j, k + 1, this.id); + } else { + world.applyPhysics(i, j - 1, k, this.id); + } + } + + super.remove(world, i, j, k); + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + return (iblockaccess.getData(i, j, k) & 8) > 0; + } + + public boolean d(World world, int i, int j, int k, int l) { + int i1 = world.getData(i, j, k); + + if ((i1 & 8) == 0) { + return false; + } else { + int j1 = i1 & 7; + + return j1 == 6 && l == 1 ? true : (j1 == 5 && l == 1 ? true : (j1 == 4 && l == 2 ? true : (j1 == 3 && l == 3 ? true : (j1 == 2 && l == 4 ? true : j1 == 1 && l == 5)))); + } + } + + public boolean isPowerSource() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/BlockLightStone.java b/src/main/java/net/minecraft/server/BlockLightStone.java new file mode 100644 index 0000000..6d142e9 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLightStone.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockLightStone extends Block { + + public BlockLightStone(int i, int j, Material material) { + super(i, j, material); + } + + public int a(Random random) { + return 2 + random.nextInt(3); + } + + public int a(int i, Random random) { + return Item.GLOWSTONE_DUST.id; + } +} diff --git a/src/main/java/net/minecraft/server/BlockLockedChest.java b/src/main/java/net/minecraft/server/BlockLockedChest.java new file mode 100644 index 0000000..da04f70 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLockedChest.java @@ -0,0 +1,23 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockLockedChest extends Block { + + protected BlockLockedChest(int i) { + super(i, Material.WOOD); + this.textureId = 26; + } + + public int a(int i) { + return i == 1 ? this.textureId - 1 : (i == 0 ? this.textureId - 1 : (i == 3 ? this.textureId + 1 : this.textureId)); + } + + public boolean canPlace(World world, int i, int j, int k) { + return true; + } + + public void a(World world, int i, int j, int k, Random random) { + world.setTypeId(i, j, k, 0); + } +} diff --git a/src/main/java/net/minecraft/server/BlockLog.java b/src/main/java/net/minecraft/server/BlockLog.java new file mode 100644 index 0000000..68baaba --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLog.java @@ -0,0 +1,54 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockLog extends Block { + + protected BlockLog(int i) { + super(i, Material.WOOD); + this.textureId = 20; + } + + public int a(Random random) { + return 1; + } + + public int a(int i, Random random) { + return Block.LOG.id; + } + + public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) { + super.a(world, entityhuman, i, j, k, l); + } + + public void remove(World world, int i, int j, int k) { + byte b0 = 4; + int l = b0 + 1; + + if (world.a(i - l, j - l, k - l, i + l, j + l, k + l)) { + for (int i1 = -b0; i1 <= b0; ++i1) { + for (int j1 = -b0; j1 <= b0; ++j1) { + for (int k1 = -b0; k1 <= b0; ++k1) { + int l1 = world.getTypeId(i + i1, j + j1, k + k1); + + if (l1 == Block.LEAVES.id) { + int i2 = world.getData(i + i1, j + j1, k + k1); + + if ((i2 & 8) == 0) { + world.setRawData(i + i1, j + j1, k + k1, i2 | 8); + } + } + } + } + } + } + } + + public int a(int i, int j) { + return i == 1 ? 21 : (i == 0 ? 21 : (j == 1 ? 116 : (j == 2 ? 117 : 20))); + } + + protected int a_(int i) { + return i; + } +} diff --git a/src/main/java/net/minecraft/server/BlockLongGrass.java b/src/main/java/net/minecraft/server/BlockLongGrass.java new file mode 100644 index 0000000..9e01676 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockLongGrass.java @@ -0,0 +1,21 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockLongGrass extends BlockFlower { + + protected BlockLongGrass(int i, int j) { + super(i, j); + float f = 0.4F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.8F, 0.5F + f); + } + + public int a(int i, int j) { + return j == 1 ? this.textureId : (j == 2 ? this.textureId + 16 + 1 : (j == 0 ? this.textureId + 16 : this.textureId)); + } + + public int a(int i, Random random) { + return random.nextInt(8) == 0 ? Item.SEEDS.id : -1; + } +} diff --git a/src/main/java/net/minecraft/server/BlockMinecartDetector.java b/src/main/java/net/minecraft/server/BlockMinecartDetector.java new file mode 100644 index 0000000..d180dc3 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockMinecartDetector.java @@ -0,0 +1,90 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +import java.util.List; +import java.util.Random; + +public class BlockMinecartDetector extends BlockMinecartTrack { + + public BlockMinecartDetector(int i, int j) { + super(i, j, true); + this.a(true); + } + + public int c() { + return 20; + } + + public boolean isPowerSource() { + return true; + } + + public void a(World world, int i, int j, int k, Entity entity) { + if (!world.isStatic) { + int l = world.getData(i, j, k); + + if ((l & 8) == 0) { + this.f(world, i, j, k, l); + } + } + } + + public void a(World world, int i, int j, int k, Random random) { + if (!world.isStatic) { + int l = world.getData(i, j, k); + + if ((l & 8) != 0) { + this.f(world, i, j, k, l); + } + } + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + return (iblockaccess.getData(i, j, k) & 8) != 0; + } + + public boolean d(World world, int i, int j, int k, int l) { + return (world.getData(i, j, k) & 8) == 0 ? false : l == 1; + } + + private void f(World world, int i, int j, int k, int l) { + boolean flag = (l & 8) != 0; + boolean flag1 = false; + float f = 0.125F; + List list = world.a(EntityMinecart.class, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f))); + + if (list.size() > 0) { + flag1 = true; + } + + // CraftBukkit start + if (flag != flag1) { + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, flag ? 1 : 0, flag1 ? 1 : 0); + world.getServer().getPluginManager().callEvent(eventRedstone); + + flag1 = eventRedstone.getNewCurrent() > 0; + } + // CraftBukkit end + + if (flag1 && !flag) { + world.setData(i, j, k, l | 8); + world.applyPhysics(i, j, k, this.id); + world.applyPhysics(i, j - 1, k, this.id); + world.b(i, j, k, i, j, k); + } + + if (!flag1 && flag) { + world.setData(i, j, k, l & 7); + world.applyPhysics(i, j, k, this.id); + world.applyPhysics(i, j - 1, k, this.id); + world.b(i, j, k, i, j, k); + } + + if (flag1) { + world.c(i, j, k, this.id, this.c()); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockMinecartTrack.java b/src/main/java/net/minecraft/server/BlockMinecartTrack.java new file mode 100644 index 0000000..48d78fa --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockMinecartTrack.java @@ -0,0 +1,258 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockMinecartTrack extends Block { + + private final boolean a; + + public static final boolean g(World world, int i, int j, int k) { + int l = world.getTypeId(i, j, k); + + return l == Block.RAILS.id || l == Block.GOLDEN_RAIL.id || l == Block.DETECTOR_RAIL.id; + } + + public static final boolean c(int i) { + return i == Block.RAILS.id || i == Block.GOLDEN_RAIL.id || i == Block.DETECTOR_RAIL.id; + } + + protected BlockMinecartTrack(int i, int j, boolean flag) { + super(i, j, Material.ORIENTABLE); + this.a = flag; + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); + } + + public boolean f() { + return this.a; + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean a() { + return false; + } + + public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) { + this.a(world, i, j, k); + return super.a(world, i, j, k, vec3d, vec3d1); + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getData(i, j, k); + + if (l >= 2 && l <= 5) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F); + } else { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); + } + } + + public int a(int i, int j) { + if (this.a) { + if (this.id == Block.GOLDEN_RAIL.id && (j & 8) == 0) { + return this.textureId - 16; + } + } else if (j >= 6) { + return this.textureId - 16; + } + + return this.textureId; + } + + public boolean b() { + return false; + } + + public int a(Random random) { + return 1; + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i, j - 1, k); + } + + public void c(World world, int i, int j, int k) { + if (!world.isStatic) { + this.a(world, i, j, k, true); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!world.isStatic) { + int i1 = world.getData(i, j, k); + int j1 = i1; + + if (this.a) { + j1 = i1 & 7; + } + + boolean flag = false; + + if (!world.e(i, j - 1, k)) { + flag = true; + } + + if (j1 == 2 && !world.e(i + 1, j, k)) { + flag = true; + } + + if (j1 == 3 && !world.e(i - 1, j, k)) { + flag = true; + } + + if (j1 == 4 && !world.e(i, j, k - 1)) { + flag = true; + } + + if (j1 == 5 && !world.e(i, j, k + 1)) { + flag = true; + } + + if (flag) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } else if (this.id == Block.GOLDEN_RAIL.id) { + boolean flag1 = world.isBlockIndirectlyPowered(i, j, k) || world.isBlockIndirectlyPowered(i, j + 1, k); + + flag1 = flag1 || this.a(world, i, j, k, i1, true, 0) || this.a(world, i, j, k, i1, false, 0); + boolean flag2 = false; + + if (flag1 && (i1 & 8) == 0) { + world.setData(i, j, k, j1 | 8); + flag2 = true; + } else if (!flag1 && (i1 & 8) != 0) { + world.setData(i, j, k, j1); + flag2 = true; + } + + if (flag2) { + world.applyPhysics(i, j - 1, k, this.id); + if (j1 == 2 || j1 == 3 || j1 == 4 || j1 == 5) { + world.applyPhysics(i, j + 1, k, this.id); + } + } + } else if (l > 0 && Block.byId[l].isPowerSource() && !this.a && MinecartTrackLogic.a(new MinecartTrackLogic(this, world, i, j, k)) == 3) { + this.a(world, i, j, k, false); + } + } + } + + private void a(World world, int i, int j, int k, boolean flag) { + if (!world.isStatic) { + (new MinecartTrackLogic(this, world, i, j, k)).a(world.isBlockIndirectlyPowered(i, j, k), flag); + } + } + + private boolean a(World world, int i, int j, int k, int l, boolean flag, int i1) { + if (i1 >= 8) { + return false; + } else { + int j1 = l & 7; + boolean flag1 = true; + + switch (j1) { + case 0: + if (flag) { + ++k; + } else { + --k; + } + break; + + case 1: + if (flag) { + --i; + } else { + ++i; + } + break; + + case 2: + if (flag) { + --i; + } else { + ++i; + ++j; + flag1 = false; + } + + j1 = 1; + break; + + case 3: + if (flag) { + --i; + ++j; + flag1 = false; + } else { + ++i; + } + + j1 = 1; + break; + + case 4: + if (flag) { + ++k; + } else { + --k; + ++j; + flag1 = false; + } + + j1 = 0; + break; + + case 5: + if (flag) { + ++k; + ++j; + flag1 = false; + } else { + --k; + } + + j1 = 0; + } + + return this.a(world, i, j, k, flag, i1, j1) ? true : flag1 && this.a(world, i, j - 1, k, flag, i1, j1); + } + } + + private boolean a(World world, int i, int j, int k, boolean flag, int l, int i1) { + int j1 = world.getTypeId(i, j, k); + + if (j1 == Block.GOLDEN_RAIL.id) { + int k1 = world.getData(i, j, k); + int l1 = k1 & 7; + + if (i1 == 1 && (l1 == 0 || l1 == 4 || l1 == 5)) { + return false; + } + + if (i1 == 0 && (l1 == 1 || l1 == 2 || l1 == 3)) { + return false; + } + + if ((k1 & 8) != 0) { + if (!world.isBlockIndirectlyPowered(i, j, k) && !world.isBlockIndirectlyPowered(i, j + 1, k)) { + return this.a(world, i, j, k, k1, flag, l + 1); + } + + return true; + } + } + + return false; + } + + public int e() { + return 0; + } + + static boolean a(BlockMinecartTrack blockminecarttrack) { + return blockminecarttrack.a; + } +} diff --git a/src/main/java/net/minecraft/server/BlockMobSpawner.java b/src/main/java/net/minecraft/server/BlockMobSpawner.java new file mode 100644 index 0000000..975f0c2 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockMobSpawner.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockMobSpawner extends BlockContainer { + + protected BlockMobSpawner(int i, int j) { + super(i, j, Material.STONE); + } + + protected TileEntity a_() { + return new TileEntityMobSpawner(); + } + + public int a(int i, Random random) { + return 0; + } + + public int a(Random random) { + return 0; + } + + public boolean a() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/BlockMushroom.java b/src/main/java/net/minecraft/server/BlockMushroom.java new file mode 100644 index 0000000..43ef81e --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockMushroom.java @@ -0,0 +1,52 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockSpreadEvent; + +import java.util.Random; + +public class BlockMushroom extends BlockFlower { + + protected BlockMushroom(int i, int j) { + super(i, j); + float f = 0.2F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f * 2.0F, 0.5F + f); + this.a(true); + } + + public void a(World world, int i, int j, int k, Random random) { + if (random.nextInt(100) == 0) { + int l = i + random.nextInt(3) - 1; + int i1 = j + random.nextInt(2) - random.nextInt(2); + int j1 = k + random.nextInt(3) - 1; + + if (world.isEmpty(l, i1, j1) && this.f(world, l, i1, j1)) { + int k1 = i + (random.nextInt(3) - 1); + + k1 = k + (random.nextInt(3) - 1); + if (world.isEmpty(l, i1, j1) && this.f(world, l, i1, j1)) { + // CraftBukkit start + org.bukkit.World bworld = world.getWorld(); + org.bukkit.block.BlockState blockState = bworld.getBlockAt(l, i1, j1).getState(); + blockState.setTypeId(this.id); + + BlockSpreadEvent event = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(i, j, k), blockState); + world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + blockState.update(true); + } + // CraftBukkit end + } + } + } + } + + protected boolean c(int i) { + return Block.o[i]; + } + + public boolean f(World world, int i, int j, int k) { + return j >= 0 && j < 128 ? world.k(i, j, k) < 13 && this.c(world.getTypeId(i, j - 1, k)) : false; + } +} diff --git a/src/main/java/net/minecraft/server/BlockNote.java b/src/main/java/net/minecraft/server/BlockNote.java new file mode 100644 index 0000000..a41f86a --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockNote.java @@ -0,0 +1,75 @@ +package net.minecraft.server; + +public class BlockNote extends BlockContainer { + + public BlockNote(int i) { + super(i, 74, Material.WOOD); + } + + public int a(int i) { + return this.textureId; + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (l > 0 && Block.byId[l].isPowerSource()) { + boolean flag = world.isBlockPowered(i, j, k); + TileEntityNote tileentitynote = (TileEntityNote) world.getTileEntity(i, j, k); + + if (tileentitynote.b != flag) { + if (flag) { + tileentitynote.play(world, i, j, k); + } + + tileentitynote.b = flag; + } + } + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (world.isStatic) { + return true; + } else { + TileEntityNote tileentitynote = (TileEntityNote) world.getTileEntity(i, j, k); + + tileentitynote.a(); + tileentitynote.play(world, i, j, k); + return true; + } + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + if (!world.isStatic) { + TileEntityNote tileentitynote = (TileEntityNote) world.getTileEntity(i, j, k); + + tileentitynote.play(world, i, j, k); + } + } + + protected TileEntity a_() { + return new TileEntityNote(); + } + + public void a(World world, int i, int j, int k, int l, int i1) { + float f = (float) Math.pow(2.0D, (double) (i1 - 12) / 12.0D); + String s = "harp"; + + if (l == 1) { + s = "bd"; + } + + if (l == 2) { + s = "snare"; + } + + if (l == 3) { + s = "hat"; + } + + if (l == 4) { + s = "bassattack"; + } + + world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "note." + s, 3.0F, f); + world.a("note", (double) i + 0.5D, (double) j + 1.2D, (double) k + 0.5D, (double) i1 / 24.0D, 0.0D, 0.0D); + } +} diff --git a/src/main/java/net/minecraft/server/BlockObsidian.java b/src/main/java/net/minecraft/server/BlockObsidian.java new file mode 100644 index 0000000..c2d9223 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockObsidian.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockObsidian extends BlockStone { + + public BlockObsidian(int i, int j) { + super(i, j); + } + + public int a(Random random) { + return 1; + } + + public int a(int i, Random random) { + return Block.OBSIDIAN.id; + } +} diff --git a/src/main/java/net/minecraft/server/BlockOre.java b/src/main/java/net/minecraft/server/BlockOre.java new file mode 100644 index 0000000..3ecf3e8 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockOre.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockOre extends Block { + + public BlockOre(int i, int j) { + super(i, j, Material.STONE); + } + + public int a(int i, Random random) { + return this.id == Block.COAL_ORE.id ? Item.COAL.id : (this.id == Block.DIAMOND_ORE.id ? Item.DIAMOND.id : (this.id == Block.LAPIS_ORE.id ? Item.INK_SACK.id : this.id)); + } + + public int a(Random random) { + return this.id == Block.LAPIS_ORE.id ? 4 + random.nextInt(5) : 1; + } + + protected int a_(int i) { + return this.id == Block.LAPIS_ORE.id ? 4 : 0; + } +} diff --git a/src/main/java/net/minecraft/server/BlockOreBlock.java b/src/main/java/net/minecraft/server/BlockOreBlock.java new file mode 100644 index 0000000..4b24687 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockOreBlock.java @@ -0,0 +1,13 @@ +package net.minecraft.server; + +public class BlockOreBlock extends Block { + + public BlockOreBlock(int i, int j) { + super(i, Material.ORE); + this.textureId = j; + } + + public int a(int i) { + return this.textureId; + } +} diff --git a/src/main/java/net/minecraft/server/BlockPiston.java b/src/main/java/net/minecraft/server/BlockPiston.java new file mode 100644 index 0000000..c5aa818 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockPiston.java @@ -0,0 +1,374 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; + +import java.util.ArrayList; + +// CraftBukkit start +// CraftBukkit end + +public class BlockPiston extends Block { + + private boolean a; + private boolean b; + + public BlockPiston(int i, int j, boolean flag) { + super(i, j, Material.PISTON); + this.a = flag; + this.a(h); + this.c(0.5F); + } + + public int a(int i, int j) { + int k = c(j); + + return k > 5 ? this.textureId : (i == k ? (!d(j) && this.minX <= 0.0D && this.minY <= 0.0D && this.minZ <= 0.0D && this.maxX >= 1.0D && this.maxY >= 1.0D && this.maxZ >= 1.0D ? this.textureId : 110) : (i == PistonBlockTextures.a[k] ? 109 : 108)); + } + + public boolean a() { + return false; + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + return false; + } + + public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) { + int l = c(world, i, j, k, (EntityHuman) entityliving); + + world.setData(i, j, k, l); + if (!world.isStatic) { + this.g(world, i, j, k); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!world.isStatic && !this.b) { + this.g(world, i, j, k); + } + } + + public void c(World world, int i, int j, int k) { + if (!world.isStatic && world.getTileEntity(i, j, k) == null) { + this.g(world, i, j, k); + } + } + + private void g(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + int i1 = c(l); + boolean flag = this.f(world, i, j, k, i1); + + if (l != 7) { + if (flag && !d(l)) { + // CraftBukkit start + int length; + try { + length = h(world, i, j, k, i1); + } catch (RuntimeException exception) { + System.out.println("[Poseidon] A piston crash attempt occurred at " + i + " " + j + " " + k + " in " + world.getWorld().getName()); + return; + } + if (length >= 0) { + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + + BlockPistonExtendEvent event = new BlockPistonExtendEvent(block, length); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end + + world.setRawData(i, j, k, i1 | 8); + world.playNote(i, j, k, 0, i1); + } + } else if (!flag && d(l)) { + // CraftBukkit start + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + + BlockPistonRetractEvent event = new BlockPistonRetractEvent(block); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end + + world.setRawData(i, j, k, i1); + world.playNote(i, j, k, 1, i1); + } + } + } + + private boolean f(World world, int i, int j, int k, int l) { + return l != 0 && world.isBlockFaceIndirectlyPowered(i, j - 1, k, 0) ? true : (l != 1 && world.isBlockFaceIndirectlyPowered(i, j + 1, k, 1) ? true : (l != 2 && world.isBlockFaceIndirectlyPowered(i, j, k - 1, 2) ? true : (l != 3 && world.isBlockFaceIndirectlyPowered(i, j, k + 1, 3) ? true : (l != 5 && world.isBlockFaceIndirectlyPowered(i + 1, j, k, 5) ? true : (l != 4 && world.isBlockFaceIndirectlyPowered(i - 1, j, k, 4) ? true : (world.isBlockFaceIndirectlyPowered(i, j, k, 0) ? true : (world.isBlockFaceIndirectlyPowered(i, j + 2, k, 1) ? true : (world.isBlockFaceIndirectlyPowered(i, j + 1, k - 1, 2) ? true : (world.isBlockFaceIndirectlyPowered(i, j + 1, k + 1, 3) ? true : (world.isBlockFaceIndirectlyPowered(i - 1, j + 1, k, 4) ? true : world.isBlockFaceIndirectlyPowered(i + 1, j + 1, k, 5))))))))))); + } + + public void a(World world, int i, int j, int k, int l, int i1) { + this.b = true; + if (l == 0) { + if (this.i(world, i, j, k, i1)) { + world.setData(i, j, k, i1 | 8); + world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "tile.piston.out", 0.5F, world.random.nextFloat() * 0.25F + 0.6F); + } + } else if (l == 1) { + TileEntity tileentity = world.getTileEntity(i + PistonBlockTextures.b[i1], j + PistonBlockTextures.c[i1], k + PistonBlockTextures.d[i1]); + + if (tileentity != null && tileentity instanceof TileEntityPiston) { + ((TileEntityPiston) tileentity).k(); + } + + world.setRawTypeIdAndData(i, j, k, Block.PISTON_MOVING.id, i1); + world.setTileEntity(i, j, k, BlockPistonMoving.a(this.id, i1, i1, false, true)); + if (this.a) { + int j1 = i + PistonBlockTextures.b[i1] * 2; + int k1 = j + PistonBlockTextures.c[i1] * 2; + int l1 = k + PistonBlockTextures.d[i1] * 2; + int i2 = world.getTypeId(j1, k1, l1); + int j2 = world.getData(j1, k1, l1); + boolean flag = false; + + if (i2 == Block.PISTON_MOVING.id) { + TileEntity tileentity1 = world.getTileEntity(j1, k1, l1); + + if (tileentity1 != null && tileentity1 instanceof TileEntityPiston) { + TileEntityPiston tileentitypiston = (TileEntityPiston) tileentity1; + + if (tileentitypiston.d() == i1 && tileentitypiston.c()) { + tileentitypiston.k(); + i2 = tileentitypiston.a(); + j2 = tileentitypiston.e(); + flag = true; + } + } + } + + if (!flag && i2 > 0 && a(i2, world, j1, k1, l1, false) && (Block.byId[i2].e() == 0 || i2 == Block.PISTON.id || i2 == Block.PISTON_STICKY.id)) { + this.b = false; + world.setTypeId(j1, k1, l1, 0); + this.b = true; + i += PistonBlockTextures.b[i1]; + j += PistonBlockTextures.c[i1]; + k += PistonBlockTextures.d[i1]; + world.setRawTypeIdAndData(i, j, k, Block.PISTON_MOVING.id, j2); + world.setTileEntity(i, j, k, BlockPistonMoving.a(i2, j2, i1, false, false)); + } else if (!flag) { + this.b = false; + world.setTypeId(i + PistonBlockTextures.b[i1], j + PistonBlockTextures.c[i1], k + PistonBlockTextures.d[i1], 0); + this.b = true; + } + } else { + this.b = false; + world.setTypeId(i + PistonBlockTextures.b[i1], j + PistonBlockTextures.c[i1], k + PistonBlockTextures.d[i1], 0); + this.b = true; + } + + world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "tile.piston.in", 0.5F, world.random.nextFloat() * 0.15F + 0.6F); + } + + this.b = false; + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getData(i, j, k); + + if (d(l)) { + switch (c(l)) { + case 0: + this.a(0.0F, 0.25F, 0.0F, 1.0F, 1.0F, 1.0F); + break; + + case 1: + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.75F, 1.0F); + break; + + case 2: + this.a(0.0F, 0.0F, 0.25F, 1.0F, 1.0F, 1.0F); + break; + + case 3: + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.75F); + break; + + case 4: + this.a(0.25F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + break; + + case 5: + this.a(0.0F, 0.0F, 0.0F, 0.75F, 1.0F, 1.0F); + } + } else { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + } + + public void a(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + } + + public boolean b() { + return false; + } + + public static int c(int i) { + return i & 7; + } + + public static boolean d(int i) { + return (i & 8) != 0; + } + + private static int c(World world, int i, int j, int k, EntityHuman entityhuman) { + if (MathHelper.abs((float) entityhuman.locX - (float) i) < 2.0F && MathHelper.abs((float) entityhuman.locZ - (float) k) < 2.0F) { + double d0 = entityhuman.locY + 1.82D - (double) entityhuman.height; + + if (d0 - (double) j > 2.0D) { + return 1; + } + + if ((double) j - d0 > 0.0D) { + return 0; + } + } + + int l = MathHelper.floor((double) (entityhuman.yaw * 4.0F / 360.0F) + 0.5D) & 3; + + return l == 0 ? 2 : (l == 1 ? 5 : (l == 2 ? 3 : (l == 3 ? 4 : 0))); + } + + private static boolean a(int i, World world, int j, int k, int l, boolean flag) { + if (i == Block.OBSIDIAN.id) { + return false; + } else if ((i == Block.FURNACE.id || i == Block.BURNING_FURNACE.id) && PoseidonConfig.getInstance().getBoolean("world.settings.block-pistons-pushing-furnaces.enabled", true)) { +// System.out.println("Blocking a piston from being pushed."); + return false; + } else { + if (i != Block.PISTON.id && i != Block.PISTON_STICKY.id) { + if (Block.byId[i].j() == -1.0F) { + return false; + } + + if (Block.byId[i].e() == 2) { + return false; + } + + if (!flag && Block.byId[i].e() == 1) { + return false; + } + } else if (d(world.getData(j, k, l))) { + return false; + } + + TileEntity tileentity = world.getTileEntity(j, k, l); + + return tileentity == null; + } + } + + // CraftBukkkit boolean -> int + private static int h(World world, int i, int j, int k, int l) { + int i1 = i + PistonBlockTextures.b[l]; + int j1 = j + PistonBlockTextures.c[l]; + int k1 = k + PistonBlockTextures.d[l]; + int l1 = 0; + + while (true) { + if (l1 < 13) { + if (j1 <= 0 || j1 >= 127) { + return -1; // CraftBukkit + } + + int i2 = world.getTypeId(i1, j1, k1); + + if (i2 != 0) { + if (!a(i2, world, i1, j1, k1, true)) { + return -1; // CraftBukkit + } + + if (Block.byId[i2].e() != 1) { + if (l1 == 12) { + return -1; // CraftBukkit + } + + i1 += PistonBlockTextures.b[l]; + j1 += PistonBlockTextures.c[l]; + k1 += PistonBlockTextures.d[l]; + ++l1; + continue; + } + } + } + + return l1; // CraftBukkit + } + } + + private boolean i(World world, int i, int j, int k, int l) { + int i1 = i + PistonBlockTextures.b[l]; + int j1 = j + PistonBlockTextures.c[l]; + int k1 = k + PistonBlockTextures.d[l]; + int l1 = 0; + + while (true) { + int i2; + + if (l1 < 13) { + if (j1 <= 0 || j1 >= 127) { + return false; + } + + i2 = world.getTypeId(i1, j1, k1); + if (i2 != 0) { + if (!a(i2, world, i1, j1, k1, true)) { + return false; + } + + if (Block.byId[i2].e() != 1) { + if (l1 == 12) { + return false; + } + + i1 += PistonBlockTextures.b[l]; + j1 += PistonBlockTextures.c[l]; + k1 += PistonBlockTextures.d[l]; + ++l1; + continue; + } + + Block.byId[i2].g(world, i1, j1, k1, world.getData(i1, j1, k1)); + if (PoseidonConfig.getInstance().getConfigBoolean("world.settings.pistons.other-fixes.enabled", true)) { + world.setRawTypeId(i1, j1, k1, 0); + } else { + world.setTypeId(i1, j1, k1, 0); + } + } + } + + while (i1 != i || j1 != j || k1 != k) { + l1 = i1 - PistonBlockTextures.b[l]; + i2 = j1 - PistonBlockTextures.c[l]; + int j2 = k1 - PistonBlockTextures.d[l]; + int k2 = world.getTypeId(l1, i2, j2); + int l2 = world.getData(l1, i2, j2); + + if (k2 == this.id && l1 == i && i2 == j && j2 == k) { + world.setRawTypeIdAndData(i1, j1, k1, Block.PISTON_MOVING.id, l | (this.a ? 8 : 0)); + world.setTileEntity(i1, j1, k1, BlockPistonMoving.a(Block.PISTON_EXTENSION.id, l | (this.a ? 8 : 0), l, true, false)); + } else { + world.setRawTypeIdAndData(i1, j1, k1, Block.PISTON_MOVING.id, l2); + world.setTileEntity(i1, j1, k1, BlockPistonMoving.a(k2, l2, l, true, false)); + } + + i1 = l1; + j1 = i2; + k1 = j2; + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockPistonExtension.java b/src/main/java/net/minecraft/server/BlockPistonExtension.java new file mode 100644 index 0000000..04f9ba3 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockPistonExtension.java @@ -0,0 +1,155 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.Random; + +public class BlockPistonExtension extends Block { + + private int a = -1; + + public BlockPistonExtension(int i, int j) { + super(i, j, Material.PISTON); + this.a(h); + this.c(0.5F); + } + + public void remove(World world, int i, int j, int k) { + super.remove(world, i, j, k); + int l = world.getData(i, j, k); + if (l < 0 || l == 6 || l == 7 || l > 13) return; // CraftBukkit - fixed a piston AIOOBE issue. + int i1 = PistonBlockTextures.a[b(l)]; + + i += PistonBlockTextures.b[i1]; + j += PistonBlockTextures.c[i1]; + k += PistonBlockTextures.d[i1]; + int j1 = world.getTypeId(i, j, k); + + if (j1 == Block.PISTON.id || j1 == Block.PISTON_STICKY.id) { + l = world.getData(i, j, k); + if (BlockPiston.d(l)) { + Block.byId[j1].g(world, i, j, k, l); + world.setTypeId(i, j, k, 0); + } + } + } + + public int a(int i, int j) { + int k = b(j); + + return i == k ? (this.a >= 0 ? this.a : ((j & 8) != 0 ? this.textureId - 1 : this.textureId)) : (i == PistonBlockTextures.a[k] ? 107 : 108); + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k) { + return false; + } + + public boolean canPlace(World world, int i, int j, int k, int l) { + return false; + } + + public int a(Random random) { + return 0; + } + + public void a(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist) { + int l = world.getData(i, j, k); + + switch (b(l)) { + case 0: + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.25F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.375F, 0.25F, 0.375F, 0.625F, 1.0F, 0.625F); + super.a(world, i, j, k, axisalignedbb, arraylist); + break; + + case 1: + this.a(0.0F, 0.75F, 0.0F, 1.0F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.375F, 0.0F, 0.375F, 0.625F, 0.75F, 0.625F); + super.a(world, i, j, k, axisalignedbb, arraylist); + break; + + case 2: + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.25F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.25F, 0.375F, 0.25F, 0.75F, 0.625F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + break; + + case 3: + this.a(0.0F, 0.0F, 0.75F, 1.0F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.25F, 0.375F, 0.0F, 0.75F, 0.625F, 0.75F); + super.a(world, i, j, k, axisalignedbb, arraylist); + break; + + case 4: + this.a(0.0F, 0.0F, 0.0F, 0.25F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.375F, 0.25F, 0.25F, 0.625F, 0.75F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + break; + + case 5: + this.a(0.75F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.0F, 0.375F, 0.25F, 0.75F, 0.625F, 0.75F); + super.a(world, i, j, k, axisalignedbb, arraylist); + } + + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getData(i, j, k); + + switch (b(l)) { + case 0: + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.25F, 1.0F); + break; + + case 1: + this.a(0.0F, 0.75F, 0.0F, 1.0F, 1.0F, 1.0F); + break; + + case 2: + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.25F); + break; + + case 3: + this.a(0.0F, 0.0F, 0.75F, 1.0F, 1.0F, 1.0F); + break; + + case 4: + this.a(0.0F, 0.0F, 0.0F, 0.25F, 1.0F, 1.0F); + break; + + case 5: + this.a(0.75F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + int i1 = b(world.getData(i, j, k)); + if (i1 > 5 || i1 < 0) return; // CraftBukkit - fixed a piston AIOOBE issue. + int j1 = world.getTypeId(i - PistonBlockTextures.b[i1], j - PistonBlockTextures.c[i1], k - PistonBlockTextures.d[i1]); + + if (j1 != Block.PISTON.id && j1 != Block.PISTON_STICKY.id) { + world.setTypeId(i, j, k, 0); + } else { + Block.byId[j1].doPhysics(world, i - PistonBlockTextures.b[i1], j - PistonBlockTextures.c[i1], k - PistonBlockTextures.d[i1], l); + } + } + + public static int b(int i) { + return i & 7; + } +} diff --git a/src/main/java/net/minecraft/server/BlockPistonMoving.java b/src/main/java/net/minecraft/server/BlockPistonMoving.java new file mode 100644 index 0000000..03d9ca2 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockPistonMoving.java @@ -0,0 +1,146 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockPistonMoving extends BlockContainer { + + public BlockPistonMoving(int i) { + super(i, Material.PISTON); + this.c(-1.0F); + } + + protected TileEntity a_() { + return null; + } + + public void c(World world, int i, int j, int k) {} + + public void remove(World world, int i, int j, int k) { + TileEntity tileentity = world.getTileEntity(i, j, k); + + if (tileentity != null && tileentity instanceof TileEntityPiston) { + ((TileEntityPiston) tileentity).k(); + } else { + super.remove(world, i, j, k); + } + } + + public boolean canPlace(World world, int i, int j, int k) { + return false; + } + + public boolean canPlace(World world, int i, int j, int k, int l) { + return false; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (!world.isStatic && world.getTileEntity(i, j, k) == null) { + world.setTypeId(i, j, k, 0); + return true; + } else { + return false; + } + } + + public int a(int i, Random random) { + return 0; + } + + public void dropNaturally(World world, int i, int j, int k, int l, float f) { + if (!world.isStatic) { + TileEntityPiston tileentitypiston = this.b(world, i, j, k); + + if (tileentitypiston != null) { + Block.byId[tileentitypiston.a()].g(world, i, j, k, tileentitypiston.e()); + } + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!world.isStatic && world.getTileEntity(i, j, k) == null) { + ; + } + } + + public static TileEntity a(int i, int j, int k, boolean flag, boolean flag1) { + return new TileEntityPiston(i, j, k, flag, flag1); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + TileEntityPiston tileentitypiston = this.b(world, i, j, k); + + if (tileentitypiston == null) { + return null; + } else { + float f = tileentitypiston.a(0.0F); + + if (tileentitypiston.c()) { + f = 1.0F - f; + } + + return this.a(world, i, j, k, tileentitypiston.a(), f, tileentitypiston.d()); + } + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + TileEntityPiston tileentitypiston = this.b(iblockaccess, i, j, k); + + if (tileentitypiston != null) { + Block block = Block.byId[tileentitypiston.a()]; + + if (block == null || block == this) { + return; + } + + block.a(iblockaccess, i, j, k); + float f = tileentitypiston.a(0.0F); + + if (tileentitypiston.c()) { + f = 1.0F - f; + } + + int l = tileentitypiston.d(); + + this.minX = block.minX - (double) ((float) PistonBlockTextures.b[l] * f); + this.minY = block.minY - (double) ((float) PistonBlockTextures.c[l] * f); + this.minZ = block.minZ - (double) ((float) PistonBlockTextures.d[l] * f); + this.maxX = block.maxX - (double) ((float) PistonBlockTextures.b[l] * f); + this.maxY = block.maxY - (double) ((float) PistonBlockTextures.c[l] * f); + this.maxZ = block.maxZ - (double) ((float) PistonBlockTextures.d[l] * f); + } + } + + public AxisAlignedBB a(World world, int i, int j, int k, int l, float f, int i1) { + if (l != 0 && l != this.id) { + AxisAlignedBB axisalignedbb = Block.byId[l].e(world, i, j, k); + + if (axisalignedbb == null) { + return null; + } else { + axisalignedbb.a -= (double) ((float) PistonBlockTextures.b[i1] * f); + axisalignedbb.d -= (double) ((float) PistonBlockTextures.b[i1] * f); + axisalignedbb.b -= (double) ((float) PistonBlockTextures.c[i1] * f); + axisalignedbb.e -= (double) ((float) PistonBlockTextures.c[i1] * f); + axisalignedbb.c -= (double) ((float) PistonBlockTextures.d[i1] * f); + axisalignedbb.f -= (double) ((float) PistonBlockTextures.d[i1] * f); + return axisalignedbb; + } + } else { + return null; + } + } + + private TileEntityPiston b(IBlockAccess iblockaccess, int i, int j, int k) { + TileEntity tileentity = iblockaccess.getTileEntity(i, j, k); + + return tileentity != null && tileentity instanceof TileEntityPiston ? (TileEntityPiston) tileentity : null; + } +} diff --git a/src/main/java/net/minecraft/server/BlockPortal.java b/src/main/java/net/minecraft/server/BlockPortal.java new file mode 100644 index 0000000..93045dc --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockPortal.java @@ -0,0 +1,173 @@ +package net.minecraft.server; + +import org.bukkit.event.entity.EntityPortalEnterEvent; +import org.bukkit.event.world.PortalCreateEvent; + +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class BlockPortal extends BlockBreakable { + + public BlockPortal(int i, int j) { + super(i, j, Material.PORTAL, false); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + float f; + float f1; + + if (iblockaccess.getTypeId(i - 1, j, k) != this.id && iblockaccess.getTypeId(i + 1, j, k) != this.id) { + f = 0.125F; + f1 = 0.5F; + this.a(0.5F - f, 0.0F, 0.5F - f1, 0.5F + f, 1.0F, 0.5F + f1); + } else { + f = 0.5F; + f1 = 0.125F; + this.a(0.5F - f, 0.0F, 0.5F - f1, 0.5F + f, 1.0F, 0.5F + f1); + } + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean a_(World world, int i, int j, int k) { + byte b0 = 0; + byte b1 = 0; + + if (world.getTypeId(i - 1, j, k) == Block.OBSIDIAN.id || world.getTypeId(i + 1, j, k) == Block.OBSIDIAN.id) { + b0 = 1; + } + + if (world.getTypeId(i, j, k - 1) == Block.OBSIDIAN.id || world.getTypeId(i, j, k + 1) == Block.OBSIDIAN.id) { + b1 = 1; + } + + if (b0 == b1) { + return false; + } else { + // CraftBukkit start + java.util.Collection blocks = new java.util.HashSet(); + org.bukkit.World bworld = world.getWorld(); + // CraftBukkit end + + if (world.getTypeId(i - b0, j, k - b1) == 0) { + i -= b0; + k -= b1; + } + + int l; + int i1; + + for (l = -1; l <= 2; ++l) { + for (i1 = -1; i1 <= 3; ++i1) { + boolean flag = l == -1 || l == 2 || i1 == -1 || i1 == 3; + + if (l != -1 && l != 2 || i1 != -1 && i1 != 3) { + int j1 = world.getTypeId(i + b0 * l, j + i1, k + b1 * l); + + if (flag) { + if (j1 != Block.OBSIDIAN.id) { + return false; + } else { + blocks.add(bworld.getBlockAt(i + b0 * l, j + i1, k + b1 * l)); // CraftBukkit + } + } else if (j1 != 0 && j1 != Block.FIRE.id) { + return false; + } + } + } + } + + // CraftBukkit start + for (l = 0; l < 2; ++l) { + for (i1 = 0; i1 < 3; ++i1) { + blocks.add(bworld.getBlockAt(i + b0 * l, j + i1, k + b1 * l)); + } + } + + PortalCreateEvent event = new PortalCreateEvent(blocks, bworld); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return false; + } + // CraftBukkit end + + world.suppressPhysics = true; + + for (l = 0; l < 2; ++l) { + for (i1 = 0; i1 < 3; ++i1) { + world.setTypeId(i + b0 * l, j + i1, k + b1 * l, Block.PORTAL.id); + } + } + + world.suppressPhysics = false; + return true; + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + byte b0 = 0; + byte b1 = 1; + + if (world.getTypeId(i - 1, j, k) == this.id || world.getTypeId(i + 1, j, k) == this.id) { + b0 = 1; + b1 = 0; + } + + int i1; + + for (i1 = j; world.getTypeId(i, i1 - 1, k) == this.id; --i1) { + ; + } + + if (world.getTypeId(i, i1 - 1, k) != Block.OBSIDIAN.id) { + world.setTypeId(i, j, k, 0); + } else { + int j1; + + for (j1 = 1; j1 < 4 && world.getTypeId(i, i1 + j1, k) == this.id; ++j1) { + ; + } + + if (j1 == 3 && world.getTypeId(i, i1 + j1, k) == Block.OBSIDIAN.id) { + boolean flag = world.getTypeId(i - 1, j, k) == this.id || world.getTypeId(i + 1, j, k) == this.id; + boolean flag1 = world.getTypeId(i, j, k - 1) == this.id || world.getTypeId(i, j, k + 1) == this.id; + + if (flag && flag1) { + world.setTypeId(i, j, k, 0); + } else if ((world.getTypeId(i + b0, j, k + b1) != Block.OBSIDIAN.id || world.getTypeId(i - b0, j, k - b1) != this.id) && (world.getTypeId(i - b0, j, k - b1) != Block.OBSIDIAN.id || world.getTypeId(i + b0, j, k + b1) != this.id)) { + world.setTypeId(i, j, k, 0); + } + } else { + world.setTypeId(i, j, k, 0); + } + } + } + + public int a(Random random) { + return 0; + } + + public void a(World world, int i, int j, int k, Entity entity) { + if (entity.vehicle == null && entity.passenger == null) { + // CraftBukkit start - Entity in portal + EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), i, j, k)); + world.getServer().getPluginManager().callEvent(event); + // CraftBukkit end + + entity.P(); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockPressurePlate.java b/src/main/java/net/minecraft/server/BlockPressurePlate.java new file mode 100644 index 0000000..3dade98 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockPressurePlate.java @@ -0,0 +1,189 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockRedstoneEvent; +import org.bukkit.event.entity.EntityInteractEvent; + +import java.util.List; +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class BlockPressurePlate extends Block { + + private EnumMobType a; + + protected BlockPressurePlate(int i, int j, EnumMobType enummobtype, Material material) { + super(i, j, material); + this.a = enummobtype; + this.a(true); + float f = 0.0625F; + + this.a(f, 0.0F, f, 1.0F - f, 0.03125F, 1.0F - f); + } + + public int c() { + return 20; + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i, j - 1, k); + } + + public void c(World world, int i, int j, int k) {} + + public void doPhysics(World world, int i, int j, int k, int l) { + boolean flag = false; + + if (!world.e(i, j - 1, k)) { + flag = true; + } + + if (flag) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + + public void a(World world, int i, int j, int k, Random random) { + if (!world.isStatic) { + if (world.getData(i, j, k) != 0) { + this.g(world, i, j, k); + } + } + } + + public void a(World world, int i, int j, int k, Entity entity) { + if (!world.isStatic) { + if (world.getData(i, j, k) != 1) { + this.g(world, i, j, k); + } + } + } + + private void g(World world, int i, int j, int k) { + boolean flag = world.getData(i, j, k) == 1; + boolean flag1 = false; + float f = 0.125F; + List list = null; + + if (this.a == EnumMobType.EVERYTHING) { + list = world.b((Entity) null, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f))); + } + + if (this.a == EnumMobType.MOBS) { + list = world.a(EntityLiving.class, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f))); + } + + if (this.a == EnumMobType.PLAYERS) { + list = world.a(EntityHuman.class, AxisAlignedBB.b((double) ((float) i + f), (double) j, (double) ((float) k + f), (double) ((float) (i + 1) - f), (double) j + 0.25D, (double) ((float) (k + 1) - f))); + } + + if (list.size() > 0) { + flag1 = true; + } + + // CraftBukkit start - Interact Pressure Plate + org.bukkit.World bworld = world.getWorld(); + org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); + + if (flag != flag1) { + if (flag1) { + for (Object object: list) { + if (object != null) { + org.bukkit.event.Cancellable cancellable; + + if (object instanceof EntityHuman) { + cancellable = CraftEventFactory.callPlayerInteractEvent((EntityHuman) object, org.bukkit.event.block.Action.PHYSICAL, i, j, k, -1, null); + } else if (object instanceof Entity) { + cancellable = new EntityInteractEvent(((Entity) object).getBukkitEntity(), bworld.getBlockAt(i, j, k)); + manager.callEvent((EntityInteractEvent) cancellable); + } else { + continue; + } + if (cancellable.isCancelled()) { + return; + } + } + } + } + + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bworld.getBlockAt(i, j, k), flag ? 1 : 0, flag1 ? 1 : 0); + manager.callEvent(eventRedstone); + + flag1 = eventRedstone.getNewCurrent() > 0; + } + // CraftBukkit end + + if (flag1 && !flag) { + world.setData(i, j, k, 1); + world.applyPhysics(i, j, k, this.id); + world.applyPhysics(i, j - 1, k, this.id); + world.b(i, j, k, i, j, k); + world.makeSound((double) i + 0.5D, (double) j + 0.1D, (double) k + 0.5D, "random.click", 0.3F, 0.6F); + } + + if (!flag1 && flag) { + world.setData(i, j, k, 0); + world.applyPhysics(i, j, k, this.id); + world.applyPhysics(i, j - 1, k, this.id); + world.b(i, j, k, i, j, k); + world.makeSound((double) i + 0.5D, (double) j + 0.1D, (double) k + 0.5D, "random.click", 0.3F, 0.5F); + } + + if (flag1) { + world.c(i, j, k, this.id, this.c()); + } + } + + public void remove(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + + if (l > 0) { + world.applyPhysics(i, j, k, this.id); + world.applyPhysics(i, j - 1, k, this.id); + } + + super.remove(world, i, j, k); + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + boolean flag = iblockaccess.getData(i, j, k) == 1; + float f = 0.0625F; + + if (flag) { + this.a(f, 0.0F, f, 1.0F - f, 0.03125F, 1.0F - f); + } else { + this.a(f, 0.0F, f, 1.0F - f, 0.0625F, 1.0F - f); + } + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + return iblockaccess.getData(i, j, k) > 0; + } + + public boolean d(World world, int i, int j, int k, int l) { + return world.getData(i, j, k) == 0 ? false : l == 1; + } + + public boolean isPowerSource() { + return true; + } + + public int e() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/BlockPumpkin.java b/src/main/java/net/minecraft/server/BlockPumpkin.java new file mode 100644 index 0000000..9ebe235 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockPumpkin.java @@ -0,0 +1,63 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +public class BlockPumpkin extends Block { + + private boolean a; + + protected BlockPumpkin(int i, int j, boolean flag) { + super(i, Material.PUMPKIN); + this.textureId = j; + this.a(true); + this.a = flag; + } + + public int a(int i, int j) { + if (i == 1) { + return this.textureId; + } else if (i == 0) { + return this.textureId; + } else { + int k = this.textureId + 1 + 16; + + if (this.a) { + ++k; + } + + return j == 2 && i == 2 ? k : (j == 3 && i == 5 ? k : (j == 0 && i == 3 ? k : (j == 1 && i == 4 ? k : this.textureId + 16))); + } + } + + public int a(int i) { + return i == 1 ? this.textureId : (i == 0 ? this.textureId : (i == 3 ? this.textureId + 1 + 16 : this.textureId + 16)); + } + + public void c(World world, int i, int j, int k) { + super.c(world, i, j, k); + } + + public boolean canPlace(World world, int i, int j, int k) { + int l = world.getTypeId(i, j, k); + + return (l == 0 || Block.byId[l].material.isReplacable()) && world.e(i, j - 1, k); + } + + public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) { + int l = MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 2.5D) & 3; + + world.setData(i, j, k, l); + } + + // CraftBukkit start + public void doPhysics(World world, int i, int j, int k, int l) { + if (net.minecraft.server.Block.byId[l] != null && net.minecraft.server.Block.byId[l].isPowerSource()) { + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + int power = block.getBlockPower(); + + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, power, power); + world.getServer().getPluginManager().callEvent(eventRedstone); + } + } + // CraftBukkit end +} diff --git a/src/main/java/net/minecraft/server/BlockRedstoneOre.java b/src/main/java/net/minecraft/server/BlockRedstoneOre.java new file mode 100644 index 0000000..c927bb9 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockRedstoneOre.java @@ -0,0 +1,96 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockRedstoneOre extends Block { + + private boolean a; + + public BlockRedstoneOre(int i, int j, boolean flag) { + super(i, j, Material.STONE); + if (flag) { + this.a(true); + } + + this.a = flag; + } + + public int c() { + return 30; + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + this.g(world, i, j, k); + super.b(world, i, j, k, entityhuman); + } + + public void b(World world, int i, int j, int k, Entity entity) { + this.g(world, i, j, k); + super.b(world, i, j, k, entity); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + this.g(world, i, j, k); + return super.interact(world, i, j, k, entityhuman); + } + + private void g(World world, int i, int j, int k) { + this.h(world, i, j, k); + if (this.id == Block.REDSTONE_ORE.id) { + world.setTypeId(i, j, k, Block.GLOWING_REDSTONE_ORE.id); + } + } + + public void a(World world, int i, int j, int k, Random random) { + if (this.id == Block.GLOWING_REDSTONE_ORE.id) { + world.setTypeId(i, j, k, Block.REDSTONE_ORE.id); + } + } + + public int a(int i, Random random) { + return Item.REDSTONE.id; + } + + public int a(Random random) { + return 4 + random.nextInt(2); + } + + private void h(World world, int i, int j, int k) { + Random random = world.random; + double d0 = 0.0625D; + + for (int l = 0; l < 6; ++l) { + double d1 = (double) ((float) i + random.nextFloat()); + double d2 = (double) ((float) j + random.nextFloat()); + double d3 = (double) ((float) k + random.nextFloat()); + + if (l == 0 && !world.p(i, j + 1, k)) { + d2 = (double) (j + 1) + d0; + } + + if (l == 1 && !world.p(i, j - 1, k)) { + d2 = (double) (j + 0) - d0; + } + + if (l == 2 && !world.p(i, j, k + 1)) { + d3 = (double) (k + 1) + d0; + } + + if (l == 3 && !world.p(i, j, k - 1)) { + d3 = (double) (k + 0) - d0; + } + + if (l == 4 && !world.p(i + 1, j, k)) { + d1 = (double) (i + 1) + d0; + } + + if (l == 5 && !world.p(i - 1, j, k)) { + d1 = (double) (i + 0) - d0; + } + + if (d1 < (double) i || d1 > (double) (i + 1) || d2 < 0.0D || d2 > (double) (j + 1) || d3 < (double) k || d3 > (double) (k + 1)) { + world.a("reddust", d1, d2, d3, 0.0D, 0.0D, 0.0D); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java new file mode 100644 index 0000000..ce9cff2 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java @@ -0,0 +1,162 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class BlockRedstoneTorch extends BlockTorch { + + private boolean isOn = false; + private static List b = new ArrayList(); + + public int a(int i, int j) { + return i == 1 ? Block.REDSTONE_WIRE.a(i, j) : super.a(i, j); + } + + private boolean a(World world, int i, int j, int k, boolean flag) { + if (flag) { + b.add(new RedstoneUpdateInfo(i, j, k, world.getTime())); + } + + int l = 0; + + for (int i1 = 0; i1 < b.size(); ++i1) { + RedstoneUpdateInfo redstoneupdateinfo = (RedstoneUpdateInfo) b.get(i1); + + if (redstoneupdateinfo.a == i && redstoneupdateinfo.b == j && redstoneupdateinfo.c == k) { + ++l; + if (l >= 8) { + return true; + } + } + } + + return false; + } + + protected BlockRedstoneTorch(int i, int j, boolean flag) { + super(i, j); + this.isOn = flag; + this.a(true); + } + + public int c() { + return 2; + } + + public void c(World world, int i, int j, int k) { + if (world.getData(i, j, k) == 0) { + super.c(world, i, j, k); + } + + if (this.isOn) { + world.applyPhysics(i, j - 1, k, this.id); + world.applyPhysics(i, j + 1, k, this.id); + world.applyPhysics(i - 1, j, k, this.id); + world.applyPhysics(i + 1, j, k, this.id); + world.applyPhysics(i, j, k - 1, this.id); + world.applyPhysics(i, j, k + 1, this.id); + } + } + + public void remove(World world, int i, int j, int k) { + if (this.isOn) { + world.applyPhysics(i, j - 1, k, this.id); + world.applyPhysics(i, j + 1, k, this.id); + world.applyPhysics(i - 1, j, k, this.id); + world.applyPhysics(i + 1, j, k, this.id); + world.applyPhysics(i, j, k - 1, this.id); + world.applyPhysics(i, j, k + 1, this.id); + } + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + if (!this.isOn) { + return false; + } else { + int i1 = iblockaccess.getData(i, j, k); + + return i1 == 5 && l == 1 ? false : (i1 == 3 && l == 3 ? false : (i1 == 4 && l == 2 ? false : (i1 == 1 && l == 5 ? false : i1 != 2 || l != 4))); + } + } + + private boolean g(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + + return l == 5 && world.isBlockFaceIndirectlyPowered(i, j - 1, k, 0) ? true : (l == 3 && world.isBlockFaceIndirectlyPowered(i, j, k - 1, 2) ? true : (l == 4 && world.isBlockFaceIndirectlyPowered(i, j, k + 1, 3) ? true : (l == 1 && world.isBlockFaceIndirectlyPowered(i - 1, j, k, 4) ? true : l == 2 && world.isBlockFaceIndirectlyPowered(i + 1, j, k, 5)))); + } + + public void a(World world, int i, int j, int k, Random random) { + boolean flag = this.g(world, i, j, k); + + while (b.size() > 0 && world.getTime() - ((RedstoneUpdateInfo) b.get(0)).d > 100L) { + b.remove(0); + } + + // CraftBukkit start + org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + int oldCurrent = this.isOn ? 15 : 0; + + BlockRedstoneEvent event = new BlockRedstoneEvent(block, oldCurrent, oldCurrent); + // CraftBukkit end + + if (this.isOn) { + if (flag) { + // CraftBukkit start + if (oldCurrent != 0) { + event.setNewCurrent(0); + manager.callEvent(event); + if (event.getNewCurrent() != 0) { + return; + } + } + // CraftBukkit end + + world.setTypeIdAndData(i, j, k, Block.REDSTONE_TORCH_OFF.id, world.getData(i, j, k)); + if (this.a(world, i, j, k, true)) { + world.makeSound((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), "random.fizz", 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); + + for (int l = 0; l < 5; ++l) { + double d0 = (double) i + random.nextDouble() * 0.6D + 0.2D; + double d1 = (double) j + random.nextDouble() * 0.6D + 0.2D; + double d2 = (double) k + random.nextDouble() * 0.6D + 0.2D; + + world.a("smoke", d0, d1, d2, 0.0D, 0.0D, 0.0D); + } + } + } + } else if (!flag && !this.a(world, i, j, k, false)) { + // CraftBukkit start + if (oldCurrent != 15) { + event.setNewCurrent(15); + manager.callEvent(event); + if (event.getNewCurrent() != 15) { + return; + } + } + // CraftBukkit end + + world.setTypeIdAndData(i, j, k, Block.REDSTONE_TORCH_ON.id, world.getData(i, j, k)); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + super.doPhysics(world, i, j, k, l); + world.c(i, j, k, this.id, this.c()); + } + + public boolean d(World world, int i, int j, int k, int l) { + return l == 0 ? this.a(world, i, j, k, l) : false; + } + + public int a(int i, Random random) { + return Block.REDSTONE_TORCH_ON.id; + } + + public boolean isPowerSource() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/BlockRedstoneWire.java b/src/main/java/net/minecraft/server/BlockRedstoneWire.java new file mode 100644 index 0000000..78ab814 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockRedstoneWire.java @@ -0,0 +1,357 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +public class BlockRedstoneWire extends Block { + + private boolean a = true; + private Set b = new HashSet(); + + public BlockRedstoneWire(int i, int j) { + super(i, j, Material.ORIENTABLE); + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F); + } + + public int a(int i, int j) { + return this.textureId; + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i, j - 1, k); + } + + private void g(World world, int i, int j, int k) { + this.a(world, i, j, k, i, j, k); + ArrayList arraylist = new ArrayList(this.b); + + this.b.clear(); + + for (int l = 0; l < arraylist.size(); ++l) { + ChunkPosition chunkposition = (ChunkPosition) arraylist.get(l); + + world.applyPhysics(chunkposition.x, chunkposition.y, chunkposition.z, this.id); + } + } + + private void a(World world, int i, int j, int k, int l, int i1, int j1) { + int k1 = world.getData(i, j, k); + int l1 = 0; + + this.a = false; + boolean flag = world.isBlockIndirectlyPowered(i, j, k); + + this.a = true; + int i2; + int j2; + int k2; + + if (flag) { + l1 = 15; + } else { + for (i2 = 0; i2 < 4; ++i2) { + j2 = i; + k2 = k; + if (i2 == 0) { + j2 = i - 1; + } + + if (i2 == 1) { + ++j2; + } + + if (i2 == 2) { + k2 = k - 1; + } + + if (i2 == 3) { + ++k2; + } + + if (j2 != l || j != i1 || k2 != j1) { + l1 = this.getPower(world, j2, j, k2, l1); + } + + if (world.e(j2, j, k2) && !world.e(i, j + 1, k)) { + if (j2 != l || j + 1 != i1 || k2 != j1) { + l1 = this.getPower(world, j2, j + 1, k2, l1); + } + } else if (!world.e(j2, j, k2) && (j2 != l || j - 1 != i1 || k2 != j1)) { + l1 = this.getPower(world, j2, j - 1, k2, l1); + } + } + + if (l1 > 0) { + --l1; + } else { + l1 = 0; + } + } + + // CraftBukkit start + if (k1 != l1) { + BlockRedstoneEvent event = new BlockRedstoneEvent(world.getWorld().getBlockAt(i, j, k), k1, l1); + world.getServer().getPluginManager().callEvent(event); + + l1 = event.getNewCurrent(); + } + // CraftBukkit end + + if (k1 != l1) { + world.suppressPhysics = true; + world.setData(i, j, k, l1); + world.b(i, j, k, i, j, k); + world.suppressPhysics = false; + + for (i2 = 0; i2 < 4; ++i2) { + j2 = i; + k2 = k; + int l2 = j - 1; + + if (i2 == 0) { + j2 = i - 1; + } + + if (i2 == 1) { + ++j2; + } + + if (i2 == 2) { + k2 = k - 1; + } + + if (i2 == 3) { + ++k2; + } + + if (world.e(j2, j, k2)) { + l2 += 2; + } + + boolean flag1 = false; + int i3 = this.getPower(world, j2, j, k2, -1); + + l1 = world.getData(i, j, k); + if (l1 > 0) { + --l1; + } + + if (i3 >= 0 && i3 != l1) { + this.a(world, j2, j, k2, i, j, k); + } + + i3 = this.getPower(world, j2, l2, k2, -1); + l1 = world.getData(i, j, k); + if (l1 > 0) { + --l1; + } + + if (i3 >= 0 && i3 != l1) { + this.a(world, j2, l2, k2, i, j, k); + } + } + + if (k1 == 0 || l1 == 0) { + this.b.add(new ChunkPosition(i, j, k)); + this.b.add(new ChunkPosition(i - 1, j, k)); + this.b.add(new ChunkPosition(i + 1, j, k)); + this.b.add(new ChunkPosition(i, j - 1, k)); + this.b.add(new ChunkPosition(i, j + 1, k)); + this.b.add(new ChunkPosition(i, j, k - 1)); + this.b.add(new ChunkPosition(i, j, k + 1)); + } + } + } + + private void h(World world, int i, int j, int k) { + if (world.getTypeId(i, j, k) == this.id) { + world.applyPhysics(i, j, k, this.id); + world.applyPhysics(i - 1, j, k, this.id); + world.applyPhysics(i + 1, j, k, this.id); + world.applyPhysics(i, j, k - 1, this.id); + world.applyPhysics(i, j, k + 1, this.id); + world.applyPhysics(i, j - 1, k, this.id); + world.applyPhysics(i, j + 1, k, this.id); + } + } + + public void c(World world, int i, int j, int k) { + super.c(world, i, j, k); + if (!world.isStatic) { + this.g(world, i, j, k); + world.applyPhysics(i, j + 1, k, this.id); + world.applyPhysics(i, j - 1, k, this.id); + this.h(world, i - 1, j, k); + this.h(world, i + 1, j, k); + this.h(world, i, j, k - 1); + this.h(world, i, j, k + 1); + if (world.e(i - 1, j, k)) { + this.h(world, i - 1, j + 1, k); + } else { + this.h(world, i - 1, j - 1, k); + } + + if (world.e(i + 1, j, k)) { + this.h(world, i + 1, j + 1, k); + } else { + this.h(world, i + 1, j - 1, k); + } + + if (world.e(i, j, k - 1)) { + this.h(world, i, j + 1, k - 1); + } else { + this.h(world, i, j - 1, k - 1); + } + + if (world.e(i, j, k + 1)) { + this.h(world, i, j + 1, k + 1); + } else { + this.h(world, i, j - 1, k + 1); + } + } + } + + public void remove(World world, int i, int j, int k) { + super.remove(world, i, j, k); + if (!world.isStatic) { + world.applyPhysics(i, j + 1, k, this.id); + world.applyPhysics(i, j - 1, k, this.id); + this.g(world, i, j, k); + this.h(world, i - 1, j, k); + this.h(world, i + 1, j, k); + this.h(world, i, j, k - 1); + this.h(world, i, j, k + 1); + if (world.e(i - 1, j, k)) { + this.h(world, i - 1, j + 1, k); + } else { + this.h(world, i - 1, j - 1, k); + } + + if (world.e(i + 1, j, k)) { + this.h(world, i + 1, j + 1, k); + } else { + this.h(world, i + 1, j - 1, k); + } + + if (world.e(i, j, k - 1)) { + this.h(world, i, j + 1, k - 1); + } else { + this.h(world, i, j - 1, k - 1); + } + + if (world.e(i, j, k + 1)) { + this.h(world, i, j + 1, k + 1); + } else { + this.h(world, i, j - 1, k + 1); + } + } + } + + // CraftBukkit - private -> public + public int getPower(World world, int i, int j, int k, int l) { + if (world.getTypeId(i, j, k) != this.id) { + return l; + } else { + int i1 = world.getData(i, j, k); + + return i1 > l ? i1 : l; + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!world.isStatic) { + int i1 = world.getData(i, j, k); + boolean flag = this.canPlace(world, i, j, k); + + if (!flag) { + this.g(world, i, j, k, i1); + world.setTypeId(i, j, k, 0); + } else { + this.g(world, i, j, k); + } + + super.doPhysics(world, i, j, k, l); + } + } + + public int a(int i, Random random) { + return Item.REDSTONE.id; + } + + public boolean d(World world, int i, int j, int k, int l) { + return !this.a ? false : this.a(world, i, j, k, l); + } + + public boolean a(IBlockAccess iblockaccess, int i, int j, int k, int l) { + if (!this.a) { + return false; + } else if (iblockaccess.getData(i, j, k) == 0) { + return false; + } else if (l == 1) { + return true; + } else { + boolean flag = c(iblockaccess, i - 1, j, k, 1) || !iblockaccess.e(i - 1, j, k) && c(iblockaccess, i - 1, j - 1, k, -1); + boolean flag1 = c(iblockaccess, i + 1, j, k, 3) || !iblockaccess.e(i + 1, j, k) && c(iblockaccess, i + 1, j - 1, k, -1); + boolean flag2 = c(iblockaccess, i, j, k - 1, 2) || !iblockaccess.e(i, j, k - 1) && c(iblockaccess, i, j - 1, k - 1, -1); + boolean flag3 = c(iblockaccess, i, j, k + 1, 0) || !iblockaccess.e(i, j, k + 1) && c(iblockaccess, i, j - 1, k + 1, -1); + + if (!iblockaccess.e(i, j + 1, k)) { + if (iblockaccess.e(i - 1, j, k) && c(iblockaccess, i - 1, j + 1, k, -1)) { + flag = true; + } + + if (iblockaccess.e(i + 1, j, k) && c(iblockaccess, i + 1, j + 1, k, -1)) { + flag1 = true; + } + + if (iblockaccess.e(i, j, k - 1) && c(iblockaccess, i, j + 1, k - 1, -1)) { + flag2 = true; + } + + if (iblockaccess.e(i, j, k + 1) && c(iblockaccess, i, j + 1, k + 1, -1)) { + flag3 = true; + } + } + + return !flag2 && !flag1 && !flag && !flag3 && l >= 2 && l <= 5 ? true : (l == 2 && flag2 && !flag && !flag1 ? true : (l == 3 && flag3 && !flag && !flag1 ? true : (l == 4 && flag && !flag2 && !flag3 ? true : l == 5 && flag1 && !flag2 && !flag3))); + } + } + + public boolean isPowerSource() { + return this.a; + } + + public static boolean c(IBlockAccess iblockaccess, int i, int j, int k, int l) { + int i1 = iblockaccess.getTypeId(i, j, k); + + if (i1 == Block.REDSTONE_WIRE.id) { + return true; + } else if (i1 == 0) { + return false; + } else if (Block.byId[i1].isPowerSource()) { + return true; + } else if (i1 != Block.DIODE_OFF.id && i1 != Block.DIODE_ON.id) { + return false; + } else { + int j1 = iblockaccess.getData(i, j, k); + + return l == BedBlockTextures.b[j1 & 3]; + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockReed.java b/src/main/java/net/minecraft/server/BlockReed.java new file mode 100644 index 0000000..da8735d --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockReed.java @@ -0,0 +1,73 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockReed extends Block { + + protected BlockReed(int i, int j) { + super(i, Material.PLANT); + this.textureId = j; + float f = 0.375F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 1.0F, 0.5F + f); + this.a(true); + } + + public void a(World world, int i, int j, int k, Random random) { + if (world.isEmpty(i, j + 1, k)) { + int l; + + for (l = 1; world.getTypeId(i, j - l, k) == this.id; ++l) { + ; + } + + if (l < 3) { + int i1 = world.getData(i, j, k); + + if (i1 == 15) { + world.setTypeId(i, j + 1, k, this.id); + world.setData(i, j, k, 0); + } else { + world.setData(i, j, k, i1 + 1); + } + } + } + } + + public boolean canPlace(World world, int i, int j, int k) { + int l = world.getTypeId(i, j - 1, k); + + return l == this.id ? true : (l != Block.GRASS.id && l != Block.DIRT.id ? false : (world.getMaterial(i - 1, j - 1, k) == Material.WATER ? true : (world.getMaterial(i + 1, j - 1, k) == Material.WATER ? true : (world.getMaterial(i, j - 1, k - 1) == Material.WATER ? true : world.getMaterial(i, j - 1, k + 1) == Material.WATER)))); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + this.g(world, i, j, k); + } + + protected final void g(World world, int i, int j, int k) { + if (!this.f(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + + public boolean f(World world, int i, int j, int k) { + return this.canPlace(world, i, j, k); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public int a(int i, Random random) { + return Item.SUGAR_CANE.id; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/BlockRegister.java b/src/main/java/net/minecraft/server/BlockRegister.java new file mode 100644 index 0000000..7959712 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockRegister.java @@ -0,0 +1,30 @@ +package net.minecraft.server; + +public class BlockRegister { + + private static byte[] a = new byte[256]; + + public BlockRegister() {} + + public static void a(byte[] abyte) { + for (int i = 0; i < abyte.length; ++i) { + abyte[i] = a[abyte[i] & 255]; + } + } + + static { + try { + for (int i = 0; i < 256; ++i) { + byte b0 = (byte) i; + + if (b0 != 0 && Block.byId[b0 & 255] == null) { + b0 = 0; + } + + a[i] = b0; + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockSand.java b/src/main/java/net/minecraft/server/BlockSand.java new file mode 100644 index 0000000..d653228 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSand.java @@ -0,0 +1,69 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +import java.util.Random; + +public class BlockSand extends Block { + + public static boolean instaFall = false; + + public BlockSand(int i, int j) { + super(i, j, Material.SAND); + } + + public void c(World world, int i, int j, int k) { + world.c(i, j, k, this.id, this.c()); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + world.c(i, j, k, this.id, this.c()); + } + + public void a(World world, int i, int j, int k, Random random) { + this.g(world, i, j, k); + } + + private void g(World world, int i, int j, int k) { + if (c_(world, i, j - 1, k) && j >= 0) { + byte b0 = 32; + + if (!instaFall && world.a(i - b0, j - b0, k - b0, i + b0, j + b0, k + b0)) { + if (PoseidonConfig.getInstance().getConfigBoolean("world.settings.pistons.sand-gravel-duping-fix.enabled", true)) { + world.setTypeId(i, j, k, 0); + } + EntityFallingSand entityfallingsand = new EntityFallingSand(world, i + 0.5D, j + 0.5D, k + 0.5D, this.id); + + world.addEntity(entityfallingsand); + } else { + world.setTypeId(i, j, k, 0); + + while (c_(world, i, j - 1, k) && j > 0) { + --j; + } + + if (j > 0) { + world.setTypeId(i, j, k, this.id); + } + } + } + } + + public int c() { + return 3; + } + + public static boolean c_(World world, int i, int j, int k) { + int l = world.getTypeId(i, j, k); + + if (l == 0) { + return true; + } else if (l == Block.FIRE.id) { + return true; + } else { + Material material = Block.byId[l].material; + + return material == Material.WATER ? true : material == Material.LAVA; + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockSandStone.java b/src/main/java/net/minecraft/server/BlockSandStone.java new file mode 100644 index 0000000..a8dba06 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSandStone.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +public class BlockSandStone extends Block { + + public BlockSandStone(int i) { + super(i, 192, Material.STONE); + } + + public int a(int i) { + return i == 1 ? this.textureId - 16 : (i == 0 ? this.textureId + 16 : this.textureId); + } +} diff --git a/src/main/java/net/minecraft/server/BlockSapling.java b/src/main/java/net/minecraft/server/BlockSapling.java new file mode 100644 index 0000000..c85e6a3 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSapling.java @@ -0,0 +1,86 @@ +package net.minecraft.server; + +import org.bukkit.BlockChangeDelegate; + +import java.util.Random; + +public class BlockSapling extends BlockFlower { + + protected BlockSapling(int i, int j) { + super(i, j); + float f = 0.4F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f * 2.0F, 0.5F + f); + } + + public void a(World world, int i, int j, int k, Random random) { + if (!world.isStatic) { + super.a(world, i, j, k, random); + if (world.getLightLevel(i, j + 1, k) >= 9 && random.nextInt(30) == 0) { + int l = world.getData(i, j, k); + + if ((l & 8) == 0) { + world.setData(i, j, k, l | 8); + } else { + this.b(world, i, j, k, random); + } + } + } + } + + public int a(int i, int j) { + j &= 3; + return j == 1 ? 63 : (j == 2 ? 79 : super.a(i, j)); + } + + public void b(World world, int i, int j, int k, Random random) { + int l = world.getData(i, j, k) & 3; + + world.setRawTypeId(i, j, k, 0); + + // CraftBukkit start - fixes client updates on recently grown trees + boolean grownTree; + BlockChangeWithNotify delegate = new BlockChangeWithNotify(world); + + if (l == 1) { + grownTree = new WorldGenTaiga2().generate(delegate, random, i, j, k); + } else if (l == 2) { + grownTree = new WorldGenForest().generate(delegate, random, i, j, k); + } else { + if (random.nextInt(10) == 0) { + grownTree = new WorldGenBigTree().generate(delegate, random, i, j, k); + } else { + grownTree = new WorldGenTrees().generate(delegate, random, i, j, k); + } + } + + if (!grownTree) { + world.setRawTypeIdAndData(i, j, k, this.id, l); + } + // CraftBukkit end + } + + protected int a_(int i) { + return i & 3; + } + + // CraftBukkit start + private class BlockChangeWithNotify implements BlockChangeDelegate { + World world; + + BlockChangeWithNotify(World world) { this.world = world; } + + public boolean setRawTypeId(int x, int y, int z, int type) { + return this.world.setTypeId(x, y, z, type); + } + + public boolean setRawTypeIdAndData(int x, int y, int z, int type, int data) { + return this.world.setTypeIdAndData(x, y, z, type, data); + } + + public int getTypeId(int x, int y, int z) { + return this.world.getTypeId(x, y, z); + } + } + // CraftBukkit end +} diff --git a/src/main/java/net/minecraft/server/BlockSign.java b/src/main/java/net/minecraft/server/BlockSign.java new file mode 100644 index 0000000..a785d17 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSign.java @@ -0,0 +1,120 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +import java.util.Random; + +public class BlockSign extends BlockContainer { + + private Class a; + private boolean b; + + protected BlockSign(int i, Class oclass, boolean flag) { + super(i, Material.WOOD); + this.b = flag; + this.textureId = 4; + this.a = oclass; + float f = 0.25F; + float f1 = 1.0F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + if (!this.b) { + int l = iblockaccess.getData(i, j, k); + float f = 0.28125F; + float f1 = 0.78125F; + float f2 = 0.0F; + float f3 = 1.0F; + float f4 = 0.125F; + + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + if (l == 2) { + this.a(f2, f, 1.0F - f4, f3, f1, 1.0F); + } + + if (l == 3) { + this.a(f2, f, 0.0F, f3, f1, f4); + } + + if (l == 4) { + this.a(1.0F - f4, f, f2, 1.0F, f1, f3); + } + + if (l == 5) { + this.a(0.0F, f, f2, f4, f1, f3); + } + } + } + + public boolean b() { + return false; + } + + public boolean a() { + return false; + } + + protected TileEntity a_() { + try { + return (TileEntity) this.a.newInstance(); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + } + + public int a(int i, Random random) { + return Item.SIGN.id; + } + + public void doPhysics(World world, int i, int j, int k, int l) { + boolean flag = false; + + if (this.b) { + if (!world.getMaterial(i, j - 1, k).isBuildable()) { + flag = true; + } + } else { + int i1 = world.getData(i, j, k); + + flag = true; + if (i1 == 2 && world.getMaterial(i, j, k + 1).isBuildable()) { + flag = false; + } + + if (i1 == 3 && world.getMaterial(i, j, k - 1).isBuildable()) { + flag = false; + } + + if (i1 == 4 && world.getMaterial(i + 1, j, k).isBuildable()) { + flag = false; + } + + if (i1 == 5 && world.getMaterial(i - 1, j, k).isBuildable()) { + flag = false; + } + } + + if (flag) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + + super.doPhysics(world, i, j, k, l); + + // CraftBukkit start + if (net.minecraft.server.Block.byId[l] != null && net.minecraft.server.Block.byId[l].isPowerSource()) { + org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); + int power = block.getBlockPower(); + + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, power, power); + world.getServer().getPluginManager().callEvent(eventRedstone); + } + // CraftBukkit end + } +} diff --git a/src/main/java/net/minecraft/server/BlockSlowSand.java b/src/main/java/net/minecraft/server/BlockSlowSand.java new file mode 100644 index 0000000..5737276 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSlowSand.java @@ -0,0 +1,19 @@ +package net.minecraft.server; + +public class BlockSlowSand extends Block { + + public BlockSlowSand(int i, int j) { + super(i, j, Material.SAND); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + float f = 0.125F; + + return AxisAlignedBB.b((double) i, (double) j, (double) k, (double) (i + 1), (double) ((float) (j + 1) - f), (double) (k + 1)); + } + + public void a(World world, int i, int j, int k, Entity entity) { + entity.motX *= 0.4D; + entity.motZ *= 0.4D; + } +} diff --git a/src/main/java/net/minecraft/server/BlockSnow.java b/src/main/java/net/minecraft/server/BlockSnow.java new file mode 100644 index 0000000..8692b10 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSnow.java @@ -0,0 +1,90 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.event.CraftEventFactory; + +import java.util.Random; + +public class BlockSnow extends Block { + + protected BlockSnow(int i, int j) { + super(i, j, Material.SNOW_LAYER); + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); + this.a(true); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + int l = world.getData(i, j, k) & 7; + + return l >= 3 ? AxisAlignedBB.b((double) i + this.minX, (double) j + this.minY, (double) k + this.minZ, (double) i + this.maxX, (double) ((float) j + 0.5F), (double) k + this.maxZ) : null; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + int l = iblockaccess.getData(i, j, k) & 7; + float f = (float) (2 * (1 + l)) / 16.0F; + + this.a(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F); + } + + public boolean canPlace(World world, int i, int j, int k) { + int l = world.getTypeId(i, j - 1, k); + + return l != 0 && Block.byId[l].a() ? world.getMaterial(i, j - 1, k).isSolid() : false; + } + + public void doPhysics(World world, int i, int j, int k, int l) { + this.g(world, i, j, k); + } + + private boolean g(World world, int i, int j, int k) { + if (!this.canPlace(world, i, j, k)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + return false; + } else { + return true; + } + } + + public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) { + int i1 = Item.SNOW_BALL.id; + float f = 0.7F; + double d0 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + double d1 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + double d2 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D; + EntityItem entityitem = new EntityItem(world, (double) i + d0, (double) j + d1, (double) k + d2, new ItemStack(i1, 1, 0)); + + entityitem.pickupDelay = 10; + world.addEntity(entityitem); + world.setTypeId(i, j, k, 0); + entityhuman.a(StatisticList.C[this.id], 1); + } + + public int a(int i, Random random) { + return Item.SNOW_BALL.id; + } + + public int a(Random random) { + return 0; + } + + public void a(World world, int i, int j, int k, Random random) { + if (world.a(EnumSkyBlock.BLOCK, i, j, k) > 11) { + // CraftBukkit start + if (CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(i, j, k), 0).isCancelled()) { + return; + } + // CraftBukkit end + + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockSnowBlock.java b/src/main/java/net/minecraft/server/BlockSnowBlock.java new file mode 100644 index 0000000..60c586e --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSnowBlock.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockSnowBlock extends Block { + + protected BlockSnowBlock(int i, int j) { + super(i, j, Material.SNOW_BLOCK); + this.a(true); + } + + public int a(int i, Random random) { + return Item.SNOW_BALL.id; + } + + public int a(Random random) { + return 4; + } + + public void a(World world, int i, int j, int k, Random random) { + if (world.a(EnumSkyBlock.BLOCK, i, j, k) > 11) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockSoil.java b/src/main/java/net/minecraft/server/BlockSoil.java new file mode 100644 index 0000000..fef69e9 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSoil.java @@ -0,0 +1,113 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.entity.EntityInteractEvent; + +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class BlockSoil extends Block { + + protected BlockSoil(int i) { + super(i, Material.EARTH); + this.textureId = 87; + this.a(true); + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.9375F, 1.0F); + this.f(255); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return AxisAlignedBB.b((double) (i + 0), (double) (j + 0), (double) (k + 0), (double) (i + 1), (double) (j + 1), (double) (k + 1)); + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public int a(int i, int j) { + return i == 1 && j > 0 ? this.textureId - 1 : (i == 1 ? this.textureId : 2); + } + + public void a(World world, int i, int j, int k, Random random) { + if (random.nextInt(5) == 0) { + if (!this.h(world, i, j, k) && !world.s(i, j + 1, k)) { + int l = world.getData(i, j, k); + + if (l > 0) { + world.setData(i, j, k, l - 1); + } else if (!this.g(world, i, j, k)) { + world.setTypeId(i, j, k, Block.DIRT.id); + } + } else { + world.setData(i, j, k, 7); + } + } + } + + public void b(World world, int i, int j, int k, Entity entity) { + if (world.random.nextInt(4) == 0) { + // CraftBukkit start - Interact Soil + org.bukkit.event.Cancellable cancellable; + if (entity instanceof EntityHuman) { + cancellable = CraftEventFactory.callPlayerInteractEvent((EntityHuman) entity, org.bukkit.event.block.Action.PHYSICAL, i, j, k, -1, null); + } else { + cancellable = new EntityInteractEvent(entity.getBukkitEntity(), world.getWorld().getBlockAt(i, j, k)); + world.getServer().getPluginManager().callEvent((EntityInteractEvent) cancellable); + } + + if (cancellable.isCancelled()) { + return; + } + // CraftBukkit end + + world.setTypeId(i, j, k, Block.DIRT.id); + } + } + + private boolean g(World world, int i, int j, int k) { + byte b0 = 0; + + for (int l = i - b0; l <= i + b0; ++l) { + for (int i1 = k - b0; i1 <= k + b0; ++i1) { + if (world.getTypeId(l, j + 1, i1) == Block.CROPS.id) { + return true; + } + } + } + + return false; + } + + private boolean h(World world, int i, int j, int k) { + for (int l = i - 4; l <= i + 4; ++l) { + for (int i1 = j; i1 <= j + 1; ++i1) { + for (int j1 = k - 4; j1 <= k + 4; ++j1) { + if (world.getMaterial(l, i1, j1) == Material.WATER) { + return true; + } + } + } + } + + return false; + } + + public void doPhysics(World world, int i, int j, int k, int l) { + super.doPhysics(world, i, j, k, l); + Material material = world.getMaterial(i, j + 1, k); + + if (material.isBuildable()) { + world.setTypeId(i, j, k, Block.DIRT.id); + } + } + + public int a(int i, Random random) { + return Block.DIRT.a(0, random); + } +} diff --git a/src/main/java/net/minecraft/server/BlockSponge.java b/src/main/java/net/minecraft/server/BlockSponge.java new file mode 100644 index 0000000..7402c5b --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockSponge.java @@ -0,0 +1,42 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +public class BlockSponge extends Block { + protected BlockSponge(int i) { + super(i, Material.SPONGE); + this.textureId = 48; + } + + public void remove(World world, int i, int j, int k) { + byte radius = 2; + + if (PoseidonConfig.getInstance().getConfigBoolean("fix.optimize-sponges.enabled", true)) { + this.optimizedRemove(world, i, j, k, radius); + return; + } + + for (int x = i - radius; x <= i + radius; ++x) { + for (int y = j - radius; y <= j + radius; ++y) { + for (int z = k - radius; z <= k + radius; ++z) { + world.applyPhysics(x, y, z, world.getTypeId(x, y, z)); + } + } + } + } + + private void optimizedRemove(World world, int i, int j, int k, byte radius) { + for (int x = i - radius; x <= i + radius; ++x) { + for (int y = j - radius; y <= j + radius; ++y) { + if (y > 127 || y < 0) continue; + + for (int z = k - radius; z <= k + radius; ++z) { + int type = world.getTypeId(x, y, z); + if ((type != Block.WATER.id && type != Block.STATIONARY_WATER.id)) continue; + + world.applyPhysics(x, y, z, type); + } + } + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockStairs.java b/src/main/java/net/minecraft/server/BlockStairs.java new file mode 100644 index 0000000..67ca33c --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockStairs.java @@ -0,0 +1,159 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.Random; + +public class BlockStairs extends Block { + + private Block a; + + protected BlockStairs(int i, Block block) { + super(i, block.textureId, block.material); + this.a = block; + this.c(block.strength); + this.b(block.durability / 3.0F); + this.a(block.stepSound); + this.f(255); + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return super.e(world, i, j, k); + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public void a(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist) { + int l = world.getData(i, j, k); + + if (l == 0) { + this.a(0.0F, 0.0F, 0.0F, 0.5F, 0.5F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + } else if (l == 1) { + this.a(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.5F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + } else if (l == 2) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 0.5F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + } else if (l == 3) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F); + super.a(world, i, j, k, axisalignedbb, arraylist); + this.a(0.0F, 0.0F, 0.5F, 1.0F, 0.5F, 1.0F); + super.a(world, i, j, k, axisalignedbb, arraylist); + } + + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + this.a.b(world, i, j, k, entityhuman); + } + + public void postBreak(World world, int i, int j, int k, int l) { + this.a.postBreak(world, i, j, k, l); + } + + public float a(Entity entity) { + return this.a.a(entity); + } + + public int a(int i, Random random) { + return this.a.a(i, random); + } + + public int a(Random random) { + return this.a.a(random); + } + + public int a(int i, int j) { + return this.a.a(i, j); + } + + public int a(int i) { + return this.a.a(i); + } + + public int c() { + return this.a.c(); + } + + public void a(World world, int i, int j, int k, Entity entity, Vec3D vec3d) { + this.a.a(world, i, j, k, entity, vec3d); + } + + public boolean k_() { + return this.a.k_(); + } + + public boolean a(int i, boolean flag) { + return this.a.a(i, flag); + } + + public boolean canPlace(World world, int i, int j, int k) { + return this.a.canPlace(world, i, j, k); + } + + public void c(World world, int i, int j, int k) { + this.doPhysics(world, i, j, k, 0); + this.a.c(world, i, j, k); + } + + public void remove(World world, int i, int j, int k) { + this.a.remove(world, i, j, k); + } + + public void dropNaturally(World world, int i, int j, int k, int l, float f) { + this.a.dropNaturally(world, i, j, k, l, f); + } + + public void b(World world, int i, int j, int k, Entity entity) { + this.a.b(world, i, j, k, entity); + } + + public void a(World world, int i, int j, int k, Random random) { + this.a.a(world, i, j, k, random); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + return this.a.interact(world, i, j, k, entityhuman); + } + + public void d(World world, int i, int j, int k) { + this.a.d(world, i, j, k); + } + + public void postPlace(World world, int i, int j, int k, EntityLiving entityliving) { + int l = MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3; + + if (l == 0) { + world.setData(i, j, k, 2); + } + + if (l == 1) { + world.setData(i, j, k, 1); + } + + if (l == 2) { + world.setData(i, j, k, 3); + } + + if (l == 3) { + world.setData(i, j, k, 0); + } + } +} diff --git a/src/main/java/net/minecraft/server/BlockStationary.java b/src/main/java/net/minecraft/server/BlockStationary.java new file mode 100644 index 0000000..0399136 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockStationary.java @@ -0,0 +1,77 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockIgniteEvent; + +import java.util.Random; + +public class BlockStationary extends BlockFluids { + + protected BlockStationary(int i, Material material) { + super(i, material); + this.a(false); + if (material == Material.LAVA) { + this.a(true); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + super.doPhysics(world, i, j, k, l); + if (world.getTypeId(i, j, k) == this.id) { + this.i(world, i, j, k); + } + } + + private void i(World world, int i, int j, int k) { + int l = world.getData(i, j, k); + + world.suppressPhysics = true; + world.setRawTypeIdAndData(i, j, k, this.id - 1, l); + world.b(i, j, k, i, j, k); + world.c(i, j, k, this.id - 1, this.c()); + world.suppressPhysics = false; + } + + public void a(World world, int i, int j, int k, Random random) { + if (this.material == Material.LAVA) { + int l = random.nextInt(3); + + // CraftBukkit start - prevent lava putting something on fire. + org.bukkit.World bworld = world.getWorld(); + BlockIgniteEvent.IgniteCause igniteCause = BlockIgniteEvent.IgniteCause.LAVA; + // CraftBukkit end + + for (int i1 = 0; i1 < l; ++i1) { + i += random.nextInt(3) - 1; + ++j; + k += random.nextInt(3) - 1; + int j1 = world.getTypeId(i, j, k); + + if (j1 == 0) { + if (this.j(world, i - 1, j, k) || this.j(world, i + 1, j, k) || this.j(world, i, j, k - 1) || this.j(world, i, j, k + 1) || this.j(world, i, j - 1, k) || this.j(world, i, j + 1, k)) { + // CraftBukkit start - prevent lava putting something on fire. + org.bukkit.block.Block block = bworld.getBlockAt(i, j, k); + + if (block.getTypeId() != Block.FIRE.id) { + BlockIgniteEvent event = new BlockIgniteEvent(block, igniteCause, null); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + continue; + } + } + // CraftBukkit end + + world.setTypeId(i, j, k, Block.FIRE.id); + return; + } + } else if (Block.byId[j1].material.isSolid()) { + return; + } + } + } + } + + private boolean j(World world, int i, int j, int k) { + return world.getMaterial(i, j, k).isBurnable(); + } +} diff --git a/src/main/java/net/minecraft/server/BlockStep.java b/src/main/java/net/minecraft/server/BlockStep.java new file mode 100644 index 0000000..63762d4 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockStep.java @@ -0,0 +1,64 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockStep extends Block { + + public static final String[] a = new String[] { "stone", "sand", "wood", "cobble"}; + private boolean b; + + public BlockStep(int i, boolean flag) { + super(i, 6, Material.STONE); + this.b = flag; + if (!flag) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F); + } + + this.f(255); + } + + public int a(int i, int j) { + return j == 0 ? (i <= 1 ? 6 : 5) : (j == 1 ? (i == 0 ? 208 : (i == 1 ? 176 : 192)) : (j == 2 ? 4 : (j == 3 ? 16 : 6))); + } + + public int a(int i) { + return this.a(i, 0); + } + + public boolean a() { + return this.b; + } + + public void c(World world, int i, int j, int k) { + if (this != Block.STEP) { + super.c(world, i, j, k); + } + + int l = world.getTypeId(i, j - 1, k); + int i1 = world.getData(i, j, k); + int j1 = world.getData(i, j - 1, k); + + if (i1 == j1) { + if (l == STEP.id) { + world.setTypeId(i, j, k, 0); + world.setTypeIdAndData(i, j - 1, k, Block.DOUBLE_STEP.id, i1); + } + } + } + + public int a(int i, Random random) { + return Block.STEP.id; + } + + public int a(Random random) { + return this.b ? 2 : 1; + } + + protected int a_(int i) { + return i; + } + + public boolean b() { + return this.b; + } +} diff --git a/src/main/java/net/minecraft/server/BlockStone.java b/src/main/java/net/minecraft/server/BlockStone.java new file mode 100644 index 0000000..b473e2e --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockStone.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockStone extends Block { + + public BlockStone(int i, int j) { + super(i, j, Material.STONE); + } + + public int a(int i, Random random) { + return Block.COBBLESTONE.id; + } +} diff --git a/src/main/java/net/minecraft/server/BlockTNT.java b/src/main/java/net/minecraft/server/BlockTNT.java new file mode 100644 index 0000000..c386a59 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockTNT.java @@ -0,0 +1,65 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockTNT extends Block { + + public BlockTNT(int i, int j) { + super(i, j, Material.TNT); + } + + public int a(int i) { + return i == 0 ? this.textureId + 2 : (i == 1 ? this.textureId + 1 : this.textureId); + } + + public void c(World world, int i, int j, int k) { + super.c(world, i, j, k); + if (world.isBlockIndirectlyPowered(i, j, k)) { + this.postBreak(world, i, j, k, 1); + world.setTypeId(i, j, k, 0); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (l > 0 && Block.byId[l].isPowerSource() && world.isBlockIndirectlyPowered(i, j, k)) { + this.postBreak(world, i, j, k, 1); + world.setTypeId(i, j, k, 0); + } + } + + public int a(Random random) { + return 0; + } + + public void d(World world, int i, int j, int k) { + EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F)); + + entitytntprimed.fuseTicks = world.random.nextInt(entitytntprimed.fuseTicks / 4) + entitytntprimed.fuseTicks / 8; + world.addEntity(entitytntprimed); + } + + public void postBreak(World world, int i, int j, int k, int l) { + if (!world.isStatic) { + if ((l & 1) == 0) { + this.a(world, i, j, k, new ItemStack(Block.TNT.id, 1, 0)); + } else { + EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F)); + + world.addEntity(entitytntprimed); + world.makeSound(entitytntprimed, "random.fuse", 1.0F, 1.0F); + } + } + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + if (entityhuman.G() != null && entityhuman.G().id == Item.FLINT_AND_STEEL.id) { + world.setRawData(i, j, k, 1); + } + + super.b(world, i, j, k, entityhuman); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + return super.interact(world, i, j, k, entityhuman); + } +} diff --git a/src/main/java/net/minecraft/server/BlockTorch.java b/src/main/java/net/minecraft/server/BlockTorch.java new file mode 100644 index 0000000..68b513e --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockTorch.java @@ -0,0 +1,145 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +import java.util.Random; + +public class BlockTorch extends Block { + + protected BlockTorch(int i, int j) { + super(i, j, Material.ORIENTABLE); + this.a(true); + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + private boolean g(World world, int i, int j, int k) { + return world.e(i, j, k) || world.getTypeId(i, j, k) == Block.FENCE.id; + } + + public boolean canPlace(World world, int i, int j, int k) { + return world.e(i - 1, j, k) ? true : (world.e(i + 1, j, k) ? true : (world.e(i, j, k - 1) ? true : (world.e(i, j, k + 1) ? true : this.g(world, i, j - 1, k)))); + } + + public void postPlace(World world, int i, int j, int k, int l) { + if (PoseidonConfig.getInstance().getConfigBoolean("world.settings.pistons.transmutation-fix.enabled", true) && world.getTypeId(i, j, k) != this.id) return; + int i1 = world.getData(i, j, k); + + if (l == 1 && this.g(world, i, j - 1, k)) { + i1 = 5; + } + + if (l == 2 && world.e(i, j, k + 1)) { + i1 = 4; + } + + if (l == 3 && world.e(i, j, k - 1)) { + i1 = 3; + } + + if (l == 4 && world.e(i + 1, j, k)) { + i1 = 2; + } + + if (l == 5 && world.e(i - 1, j, k)) { + i1 = 1; + } + + world.setData(i, j, k, i1); + } + + public void a(World world, int i, int j, int k, Random random) { + super.a(world, i, j, k, random); + if (world.getData(i, j, k) == 0) { + this.c(world, i, j, k); + } + } + + public void c(World world, int i, int j, int k) { + if (world.e(i - 1, j, k)) { + world.setData(i, j, k, 1); + } else if (world.e(i + 1, j, k)) { + world.setData(i, j, k, 2); + } else if (world.e(i, j, k - 1)) { + world.setData(i, j, k, 3); + } else if (world.e(i, j, k + 1)) { + world.setData(i, j, k, 4); + } else if (this.g(world, i, j - 1, k)) { + world.setData(i, j, k, 5); + } + + this.h(world, i, j, k); + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (this.h(world, i, j, k)) { + int i1 = world.getData(i, j, k); + boolean flag = false; + + if (!world.e(i - 1, j, k) && i1 == 1) { + flag = true; + } + + if (!world.e(i + 1, j, k) && i1 == 2) { + flag = true; + } + + if (!world.e(i, j, k - 1) && i1 == 3) { + flag = true; + } + + if (!world.e(i, j, k + 1) && i1 == 4) { + flag = true; + } + + if (!this.g(world, i, j - 1, k) && i1 == 5) { + flag = true; + } + + if (flag) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + } + } + } + + private boolean h(World world, int i, int j, int k) { + if (!this.canPlace(world, i, j, k) && (!PoseidonConfig.getInstance().getConfigBoolean("world.settings.pistons.other-fixes.enabled") || world.getTypeId(i, j, k) == this.id)) { + this.g(world, i, j, k, world.getData(i, j, k)); + world.setTypeId(i, j, k, 0); + return false; + } else { + return true; + } + } + + public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) { + int l = world.getData(i, j, k) & 7; + float f = 0.15F; + + if (l == 1) { + this.a(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f); + } else if (l == 2) { + this.a(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f); + } else if (l == 3) { + this.a(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F); + } else if (l == 4) { + this.a(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F); + } else { + f = 0.1F; + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.6F, 0.5F + f); + } + + return super.a(world, i, j, k, vec3d, vec3d1); + } +} diff --git a/src/main/java/net/minecraft/server/BlockTrapdoor.java b/src/main/java/net/minecraft/server/BlockTrapdoor.java new file mode 100644 index 0000000..a3c7c83 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockTrapdoor.java @@ -0,0 +1,189 @@ +package net.minecraft.server; + +import org.bukkit.event.block.BlockRedstoneEvent; + +public class BlockTrapdoor extends Block { + + protected BlockTrapdoor(int i, Material material) { + super(i, material); + this.textureId = 84; + if (material == Material.ORE) { + ++this.textureId; + } + + float f = 0.5F; + float f1 = 1.0F; + + this.a(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f); + } + + public boolean a() { + return false; + } + + public boolean b() { + return false; + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + this.a(world, i, j, k); + return super.e(world, i, j, k); + } + + public void a(IBlockAccess iblockaccess, int i, int j, int k) { + this.c(iblockaccess.getData(i, j, k)); + } + + public void c(int i) { + float f = 0.1875F; + + this.a(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F); + if (d(i)) { + if ((i & 3) == 0) { + this.a(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); + } + + if ((i & 3) == 1) { + this.a(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); + } + + if ((i & 3) == 2) { + this.a(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + + if ((i & 3) == 3) { + this.a(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); + } + } + } + + public void b(World world, int i, int j, int k, EntityHuman entityhuman) { + this.interact(world, i, j, k, entityhuman); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (this.material == Material.ORE) { + return true; + } else { + int l = world.getData(i, j, k); + + world.setData(i, j, k, l ^ 4); + world.a(entityhuman, 1003, i, j, k, 0); + return true; + } + } + + public void a(World world, int i, int j, int k, boolean flag) { + int l = world.getData(i, j, k); + boolean flag1 = (l & 4) > 0; + + if (flag1 != flag) { + world.setData(i, j, k, l ^ 4); + world.a((EntityHuman) null, 1003, i, j, k, 0); + } + } + + public void doPhysics(World world, int i, int j, int k, int l) { + if (!world.isStatic) { + int i1 = world.getData(i, j, k); + int j1 = i; + int k1 = k; + + if ((i1 & 3) == 0) { + k1 = k + 1; + } + + if ((i1 & 3) == 1) { + --k1; + } + + if ((i1 & 3) == 2) { + j1 = i + 1; + } + + if ((i1 & 3) == 3) { + --j1; + } + + if (!world.e(j1, j, k1)) { + world.setTypeId(i, j, k, 0); + this.g(world, i, j, k, i1); + } + + // CraftBukkit start + if (l > 0 && Block.byId[l] != null && Block.byId[l].isPowerSource()) { + org.bukkit.World bworld = world.getWorld(); + org.bukkit.block.Block block = bworld.getBlockAt(i, j, k); + + int power = block.getBlockPower(); + int oldPower = (world.getData(i, j, k) & 4) > 0 ? 15 : 0; + + if (oldPower == 0 ^ power == 0) { + BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, oldPower, power); + world.getServer().getPluginManager().callEvent(eventRedstone); + + this.a(world, i, j, k, eventRedstone.getNewCurrent() > 0); + } + // CraftBukkit end + } + } + } + + public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) { + this.a(world, i, j, k); + return super.a(world, i, j, k, vec3d, vec3d1); + } + + public void postPlace(World world, int i, int j, int k, int l) { + byte b0 = 0; + + if (l == 2) { + b0 = 0; + } + + if (l == 3) { + b0 = 1; + } + + if (l == 4) { + b0 = 2; + } + + if (l == 5) { + b0 = 3; + } + + world.setData(i, j, k, b0); + doPhysics(world, i, j, k, Block.REDSTONE_WIRE.id); // CraftBukkit + } + + public boolean canPlace(World world, int i, int j, int k, int l) { + if (l == 0) { + return false; + } else if (l == 1) { + return false; + } else { + if (l == 2) { + ++k; + } + + if (l == 3) { + --k; + } + + if (l == 4) { + ++i; + } + + if (l == 5) { + --i; + } + + return world.e(i, j, k); + } + } + + public static boolean d(int i) { + return (i & 4) != 0; + } +} diff --git a/src/main/java/net/minecraft/server/BlockWeb.java b/src/main/java/net/minecraft/server/BlockWeb.java new file mode 100644 index 0000000..c41e032 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockWeb.java @@ -0,0 +1,30 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BlockWeb extends Block { + + public BlockWeb(int i, int j) { + super(i, j, Material.WEB); + } + + public void a(World world, int i, int j, int k, Entity entity) { + entity.bf = true; + } + + public boolean a() { + return false; + } + + public AxisAlignedBB e(World world, int i, int j, int k) { + return null; + } + + public boolean b() { + return false; + } + + public int a(int i, Random random) { + return Item.STRING.id; + } +} diff --git a/src/main/java/net/minecraft/server/BlockWorkbench.java b/src/main/java/net/minecraft/server/BlockWorkbench.java new file mode 100644 index 0000000..ec1f288 --- /dev/null +++ b/src/main/java/net/minecraft/server/BlockWorkbench.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +public class BlockWorkbench extends Block { + + protected BlockWorkbench(int i) { + super(i, Material.WOOD); + this.textureId = 59; + } + + public int a(int i) { + return i == 1 ? this.textureId - 16 : (i == 0 ? Block.WOOD.a(0) : (i != 2 && i != 4 ? this.textureId : this.textureId + 1)); + } + + public boolean interact(World world, int i, int j, int k, EntityHuman entityhuman) { + if (world.isStatic) { + return true; + } else { + entityhuman.b(i, j, k); + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java new file mode 100644 index 0000000..8f095d4 --- /dev/null +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -0,0 +1,650 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +import java.util.*; + +public class Chunk { + + public static boolean a; + public byte[] b; + public boolean c; + public World world; + public NibbleArray e; + public NibbleArray f; + public NibbleArray g; + public byte[] heightMap; + public int i; + public final int x; + public final int z; + public Map tileEntities; + public List[] entitySlices; + public boolean done; + public boolean o; + public boolean p; + public boolean q; + public long r; + + public Chunk(World world, int i, int j) { + this.tileEntities = new HashMap(); + this.entitySlices = new List[8]; + this.done = false; + this.o = false; + this.q = false; + this.r = 0L; + this.world = world; + this.x = i; + this.z = j; + this.heightMap = new byte[256]; + + for (int k = 0; k < this.entitySlices.length; ++k) { + this.entitySlices[k] = new ArrayList(); + } + + // CraftBukkit start + org.bukkit.craftbukkit.CraftWorld cworld = this.world.getWorld(); + this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); + } + + public org.bukkit.Chunk bukkitChunk; + // CraftBukkit end + + public Chunk(World world, byte[] abyte, int i, int j) { + this(world, i, j); + this.b = abyte; + this.e = new NibbleArray(abyte.length); + this.f = new NibbleArray(abyte.length); + this.g = new NibbleArray(abyte.length); + } + + public boolean a(int i, int j) { + return i == this.x && j == this.z; + } + + public int b(int i, int j) { + return this.heightMap[j << 4 | i] & 255; + } + + public void a() {} + + public void initLighting() { + int i = 127; + + int j; + int k; + + for (j = 0; j < 16; ++j) { + for (k = 0; k < 16; ++k) { + int l = 127; + + int i1; + + for (i1 = j << 11 | k << 7; l > 0 && Block.q[this.b[i1 + l - 1] & 255] == 0; --l) { + ; + } + + this.heightMap[k << 4 | j] = (byte) l; + if (l < i) { + i = l; + } + + if (!this.world.worldProvider.e) { + int j1 = 15; + int k1 = 127; + + do { + j1 -= Block.q[this.b[i1 + k1] & 255]; + if (j1 > 0) { + this.f.a(j, k1, k, j1); + } + + --k1; + } while (k1 > 0 && j1 > 0); + } + } + } + + this.i = i; + + for (j = 0; j < 16; ++j) { + for (k = 0; k < 16; ++k) { + this.c(j, k); + } + } + + this.o = true; + } + + public void loadNOP() {} + + private void c(int i, int j) { + int k = this.b(i, j); + int l = this.x * 16 + i; + int i1 = this.z * 16 + j; + + this.f(l - 1, i1, k); + this.f(l + 1, i1, k); + this.f(l, i1 - 1, k); + this.f(l, i1 + 1, k); + } + + private void f(int i, int j, int k) { + int l = this.world.getHighestBlockYAt(i, j); + + if (l > k) { + this.world.a(EnumSkyBlock.SKY, i, k, j, i, l, j); + this.o = true; + } else if (l < k) { + this.world.a(EnumSkyBlock.SKY, i, l, j, i, k, j); + this.o = true; + } + } + + private void g(int i, int j, int k) { + int l = this.heightMap[k << 4 | i] & 255; + int i1 = l; + + if (j > l) { + i1 = j; + } + + for (int j1 = i << 11 | k << 7; i1 > 0 && Block.q[this.b[j1 + i1 - 1] & 255] == 0; --i1) { + ; + } + + if (i1 != l) { + this.world.g(i, k, i1, l); + this.heightMap[k << 4 | i] = (byte) i1; + int k1; + int l1; + int i2; + + if (i1 < this.i) { + this.i = i1; + } else { + k1 = 127; + + for (l1 = 0; l1 < 16; ++l1) { + for (i2 = 0; i2 < 16; ++i2) { + if ((this.heightMap[i2 << 4 | l1] & 255) < k1) { + k1 = this.heightMap[i2 << 4 | l1] & 255; + } + } + } + + this.i = k1; + } + + k1 = this.x * 16 + i; + l1 = this.z * 16 + k; + if (i1 < l) { + for (i2 = i1; i2 < l; ++i2) { + this.f.a(i, i2, k, 15); + } + } else { + this.world.a(EnumSkyBlock.SKY, k1, l, l1, k1, i1, l1); + + for (i2 = l; i2 < i1; ++i2) { + this.f.a(i, i2, k, 0); + } + } + + i2 = 15; + + int j2; + + for (j2 = i1; i1 > 0 && i2 > 0; this.f.a(i, i1, k, i2)) { + --i1; + int k2 = Block.q[this.getTypeId(i, i1, k)]; + + if (k2 == 0) { + k2 = 1; + } + + i2 -= k2; + if (i2 < 0) { + i2 = 0; + } + } + + while (i1 > 0 && Block.q[this.getTypeId(i, i1 - 1, k)] == 0) { + --i1; + } + + if (i1 != j2) { + this.world.a(EnumSkyBlock.SKY, k1 - 1, i1, l1 - 1, k1 + 1, j2, l1 + 1); + } + + this.o = true; + } + } + + public int getTypeId(int i, int j, int k) { + return this.b[i << 11 | k << 7 | j] & 255; + } + + public boolean a(int i, int j, int k, int l, int i1) { + byte b0 = (byte) l; + int j1 = this.heightMap[k << 4 | i] & 255; + int k1 = this.b[i << 11 | k << 7 | j] & 255; + + if (k1 == l && this.e.a(i, j, k) == i1) { + return false; + } else { + int l1 = this.x * 16 + i; + int i2 = this.z * 16 + k; + + this.b[i << 11 | k << 7 | j] = (byte) (b0 & 255); + if (PoseidonConfig.getInstance().getConfigBoolean("world.settings.pistons.transmutation-fix.enabled", true)) { + this.e.a(i, j, k, i1); + if (k1 != 0 && !this.world.isStatic) { + Block.byId[k1].remove(this.world, l1, j, i2); + } + } else { + if (k1 != 0 && !this.world.isStatic) { + Block.byId[k1].remove(this.world, l1, j, i2); + } + this.e.a(i, j, k, i1); + } + + if (!this.world.worldProvider.e) { + if (Block.q[b0 & 255] != 0) { + if (j >= j1) { + this.g(i, j + 1, k); + } + } else if (j == j1 - 1) { + this.g(i, j, k); + } + + this.world.a(EnumSkyBlock.SKY, l1, j, i2, l1, j, i2); + } + + this.world.a(EnumSkyBlock.BLOCK, l1, j, i2, l1, j, i2); + this.c(i, k); + if (l != 0) { + Block.byId[l].c(this.world, l1, j, i2); + } + + this.o = true; + return true; + } + } + + public boolean a(int i, int j, int k, int l) { + byte b0 = (byte) l; + int i1 = this.heightMap[k << 4 | i] & 255; + int j1 = this.b[i << 11 | k << 7 | j] & 255; + + if (j1 == l) { + return false; + } else { + int k1 = this.x * 16 + i; + int l1 = this.z * 16 + k; + + this.b[i << 11 | k << 7 | j] = (byte) (b0 & 255); + if (j1 != 0) { + Block.byId[j1].remove(this.world, k1, j, l1); + } + + this.e.a(i, j, k, 0); + if (Block.q[b0 & 255] != 0) { + if (j >= i1) { + this.g(i, j + 1, k); + } + } else if (j == i1 - 1) { + this.g(i, j, k); + } + + this.world.a(EnumSkyBlock.SKY, k1, j, l1, k1, j, l1); + this.world.a(EnumSkyBlock.BLOCK, k1, j, l1, k1, j, l1); + this.c(i, k); + if (l != 0 && !this.world.isStatic) { + Block.byId[l].c(this.world, k1, j, l1); + } + + this.o = true; + return true; + } + } + + public int getData(int i, int j, int k) { + return this.e.a(i, j, k); + } + + public void b(int i, int j, int k, int l) { + this.o = true; + this.e.a(i, j, k, l); + } + + public int a(EnumSkyBlock enumskyblock, int i, int j, int k) { + return enumskyblock == EnumSkyBlock.SKY ? this.f.a(i, j, k) : (enumskyblock == EnumSkyBlock.BLOCK ? this.g.a(i, j, k) : 0); + } + + public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l) { + this.o = true; + if (enumskyblock == EnumSkyBlock.SKY) { + this.f.a(i, j, k, l); + } else { + if (enumskyblock != EnumSkyBlock.BLOCK) { + return; + } + + this.g.a(i, j, k, l); + } + } + + public int c(int i, int j, int k, int l) { + int i1 = this.f.a(i, j, k); + + if (i1 > 0) { + a = true; + } + + i1 -= l; + int j1 = this.g.a(i, j, k); + + if (j1 > i1) { + i1 = j1; + } + + return i1; + } + + public void a(Entity entity) { + this.q = true; + int i = MathHelper.floor(entity.locX / 16.0D); + int j = MathHelper.floor(entity.locZ / 16.0D); + + if (i != this.x || j != this.z) { + System.out.println("Wrong location! " + entity); + // Thread.dumpStack(); // CraftBukkit + // CraftBukkit + System.out.println("" + entity.locX + "," + entity.locZ + "(" + i + "," + j + ") vs " + this.x + "," + this.z); + } + + int k = MathHelper.floor(entity.locY / 16.0D); + + if (k < 0) { + k = 0; + } + + if (k >= this.entitySlices.length) { + k = this.entitySlices.length - 1; + } + + entity.bG = true; + entity.bH = this.x; + entity.bI = k; + entity.bJ = this.z; + this.entitySlices[k].add(entity); + } + + public void b(Entity entity) { + this.a(entity, entity.bI); + } + + public void a(Entity entity, int i) { + if (i < 0) { + i = 0; + } + + if (i >= this.entitySlices.length) { + i = this.entitySlices.length - 1; + } + + this.entitySlices[i].remove(entity); + } + + public boolean c(int i, int j, int k) { + return j >= (this.heightMap[k << 4 | i] & 255); + } + + public TileEntity d(int i, int j, int k) { + ChunkPosition chunkposition = new ChunkPosition(i, j, k); + TileEntity tileentity = (TileEntity) this.tileEntities.get(chunkposition); + + if (tileentity == null) { + int l = this.getTypeId(i, j, k); + + if (!Block.isTileEntity[l]) { + return null; + } + + BlockContainer blockcontainer = (BlockContainer) Block.byId[l]; + + blockcontainer.c(this.world, this.x * 16 + i, j, this.z * 16 + k); + tileentity = (TileEntity) this.tileEntities.get(chunkposition); + } + + if (tileentity != null && tileentity.g()) { + this.tileEntities.remove(chunkposition); + return null; + } else { + return tileentity; + } + } + + public void a(TileEntity tileentity) { + int i = tileentity.x - this.x * 16; + int j = tileentity.y; + int k = tileentity.z - this.z * 16; + + this.placeTileEntity(i, j, k, tileentity); + if (this.c) { + this.world.c.add(tileentity); + } + } + + public void placeTileEntity(int i, int j, int k, TileEntity tileentity) { + ChunkPosition chunkposition = new ChunkPosition(i, j, k); + + tileentity.world = this.world; + tileentity.x = this.x * 16 + i; + tileentity.y = j; + tileentity.z = this.z * 16 + k; + if (this.getTypeId(i, j, k) != 0 && Block.byId[this.getTypeId(i, j, k)] instanceof BlockContainer) { + tileentity.j(); + this.tileEntities.put(chunkposition, tileentity); + // Poseidon start - Backport of 0021-Remove-invalid-mob-spawner-tile-entities.patch from PaperSpigot + } else if (tileentity instanceof TileEntityMobSpawner && !(Block.byId[this.getTypeId(i, j, k)] instanceof BlockMobSpawner)) { + this.tileEntities.remove(chunkposition); + // Poseidon end + } else { + System.out.println("Attempted to place a tile entity where there was no entity tile!"); + } + } + + public void e(int i, int j, int k) { + ChunkPosition chunkposition = new ChunkPosition(i, j, k); + + if (this.c) { + TileEntity tileentity = (TileEntity) this.tileEntities.remove(chunkposition); + + if (tileentity != null) { + tileentity.h(); + } + } + } + + public void addEntities() { + this.c = true; + this.world.a(this.tileEntities.values()); + + for (int i = 0; i < this.entitySlices.length; ++i) { + this.world.a(this.entitySlices[i]); + } + } + + public void removeEntities() { + this.c = false; + Iterator iterator = this.tileEntities.values().iterator(); + + while (iterator.hasNext()) { + TileEntity tileentity = (TileEntity) iterator.next(); + + world.markForRemoval(tileentity); // Craftbukkit + } + + for (int i = 0; i < this.entitySlices.length; ++i) { + // CraftBukkit start + java.util.Iterator iter = this.entitySlices[i].iterator(); + while (iter.hasNext()) { + Entity entity = (Entity) iter.next(); + int cx = org.bukkit.Location.locToBlock(entity.locX) >> 4; + int cz = org.bukkit.Location.locToBlock(entity.locZ) >> 4; + + // Do not pass along players, as doing so can get them stuck outside of time. + // (which for example disables inventory icon updates and prevents block breaking) + if (entity instanceof EntityPlayer && (cx != this.x || cz != this.z)) { + iter.remove(); + } + } + // CraftBukkit end + + this.world.b(this.entitySlices[i]); + } + } + + public void f() { + this.o = true; + } + + public void a(Entity entity, AxisAlignedBB axisalignedbb, List list) { + int i = MathHelper.floor((axisalignedbb.b - 2.0D) / 16.0D); + int j = MathHelper.floor((axisalignedbb.e + 2.0D) / 16.0D); + + if (i < 0) { + i = 0; + } + + if (j >= this.entitySlices.length) { + j = this.entitySlices.length - 1; + } + + for (int k = i; k <= j; ++k) { + List list1 = this.entitySlices[k]; + + for (int l = 0; l < list1.size(); ++l) { + Entity entity1 = (Entity) list1.get(l); + + if (entity1 != entity && entity1.boundingBox.a(axisalignedbb)) { + list.add(entity1); + } + } + } + } + + public void a(Class oclass, AxisAlignedBB axisalignedbb, List list) { + int i = MathHelper.floor((axisalignedbb.b - 2.0D) / 16.0D); + int j = MathHelper.floor((axisalignedbb.e + 2.0D) / 16.0D); + + if (i < 0) { + i = 0; + } + + if (j >= this.entitySlices.length) { + j = this.entitySlices.length - 1; + } + + for (int k = i; k <= j; ++k) { + List list1 = this.entitySlices[k]; + + for (int l = 0; l < list1.size(); ++l) { + Entity entity = (Entity) list1.get(l); + + if (oclass.isAssignableFrom(entity.getClass()) && entity.boundingBox.a(axisalignedbb)) { + list.add(entity); + } + } + } + } + + public boolean a(boolean flag) { + if (this.p) { + return false; + } else { + if (flag) { + if (this.q && this.world.getTime() != this.r) { + return true; + } + } else if (this.q && this.world.getTime() >= this.r + 600L) { + return true; + } + + return this.o; + } + } + + public int getData(byte[] abyte, int i, int j, int k, int l, int i1, int j1, int k1) { + int l1 = l - i; + int i2 = i1 - j; + int j2 = j1 - k; + + if (l1 * i2 * j2 == this.b.length) { + System.arraycopy(this.b, 0, abyte, k1, this.b.length); + k1 += this.b.length; + System.arraycopy(this.e.a, 0, abyte, k1, this.e.a.length); + k1 += this.e.a.length; + System.arraycopy(this.g.a, 0, abyte, k1, this.g.a.length); + k1 += this.g.a.length; + System.arraycopy(this.f.a, 0, abyte, k1, this.f.a.length); + k1 += this.f.a.length; + return k1; + } else { + int k2; + int l2; + int i3; + int j3; + + for (k2 = i; k2 < l; ++k2) { + for (l2 = k; l2 < j1; ++l2) { + i3 = k2 << 11 | l2 << 7 | j; + j3 = i1 - j; + System.arraycopy(this.b, i3, abyte, k1, j3); + k1 += j3; + } + } + + for (k2 = i; k2 < l; ++k2) { + for (l2 = k; l2 < j1; ++l2) { + i3 = (k2 << 11 | l2 << 7 | j) >> 1; + j3 = (i1 - j) / 2; + System.arraycopy(this.e.a, i3, abyte, k1, j3); + k1 += j3; + } + } + + for (k2 = i; k2 < l; ++k2) { + for (l2 = k; l2 < j1; ++l2) { + i3 = (k2 << 11 | l2 << 7 | j) >> 1; + j3 = (i1 - j) / 2; + System.arraycopy(this.g.a, i3, abyte, k1, j3); + k1 += j3; + } + } + + for (k2 = i; k2 < l; ++k2) { + for (l2 = k; l2 < j1; ++l2) { + i3 = (k2 << 11 | l2 << 7 | j) >> 1; + j3 = (i1 - j) / 2; + System.arraycopy(this.f.a, i3, abyte, k1, j3); + k1 += j3; + } + } + + return k1; + } + } + + public Random a(long i) { + return new Random(this.world.getSeed() + (long) (this.x * this.x * 4987142) + (long) (this.x * 5947611) + (long) (this.z * this.z) * 4392871L + (long) (this.z * 389711) ^ i); + } + + public boolean isEmpty() { + return false; + } + + public void h() { + BlockRegister.a(this.b); + } +} diff --git a/src/main/java/net/minecraft/server/ChunkBuffer.java b/src/main/java/net/minecraft/server/ChunkBuffer.java new file mode 100644 index 0000000..a6a0be9 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkBuffer.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +import java.io.ByteArrayOutputStream; + +class ChunkBuffer extends ByteArrayOutputStream { + + private int b; + private int c; + + final RegionFile a; + + public ChunkBuffer(RegionFile regionfile, int i, int j) { + super(8096); + this.a = regionfile; + this.b = i; + this.c = j; + } + + public void close() { + this.a.a(this.b, this.c, this.buf, this.count); + } +} diff --git a/src/main/java/net/minecraft/server/ChunkCache.java b/src/main/java/net/minecraft/server/ChunkCache.java new file mode 100644 index 0000000..fbac7b3 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkCache.java @@ -0,0 +1,76 @@ +package net.minecraft.server; + +public class ChunkCache implements IBlockAccess { + + private int a; + private int b; + private Chunk[][] c; + private World d; + + public ChunkCache(World world, int i, int j, int k, int l, int i1, int j1) { + this.d = world; + this.a = i >> 4; + this.b = k >> 4; + int k1 = l >> 4; + int l1 = j1 >> 4; + + this.c = new Chunk[k1 - this.a + 1][l1 - this.b + 1]; + + for (int i2 = this.a; i2 <= k1; ++i2) { + for (int j2 = this.b; j2 <= l1; ++j2) { + this.c[i2 - this.a][j2 - this.b] = world.getChunkAt(i2, j2); + } + } + } + + public int getTypeId(int i, int j, int k) { + if (j < 0) { + return 0; + } else if (j >= 128) { + return 0; + } else { + int l = (i >> 4) - this.a; + int i1 = (k >> 4) - this.b; + + if (l >= 0 && l < this.c.length && i1 >= 0 && i1 < this.c[l].length) { + Chunk chunk = this.c[l][i1]; + + return chunk == null ? 0 : chunk.getTypeId(i & 15, j, k & 15); + } else { + return 0; + } + } + } + + public TileEntity getTileEntity(int i, int j, int k) { + int l = (i >> 4) - this.a; + int i1 = (k >> 4) - this.b; + + return this.c[l][i1].d(i & 15, j, k & 15); + } + + public int getData(int i, int j, int k) { + if (j < 0) { + return 0; + } else if (j >= 128) { + return 0; + } else { + int l = (i >> 4) - this.a; + int i1 = (k >> 4) - this.b; + + return this.c[l][i1].getData(i & 15, j, k & 15); + } + } + + public Material getMaterial(int i, int j, int k) { + int l = this.getTypeId(i, j, k); + + return l == 0 ? Material.AIR : Block.byId[l].material; + } + + public boolean e(int i, int j, int k) { + Block block = Block.byId[this.getTypeId(i, j, k)]; + + return block == null ? false : block.material.isSolid() && block.b(); + } +} diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java new file mode 100644 index 0000000..f3a2e80 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +public class ChunkCoordIntPair { + + public final int x; + public final int z; + + public ChunkCoordIntPair(int i, int j) { + this.x = i; + this.z = j; + } + + public static int a(int i, int j) { + return (i < 0 ? Integer.MIN_VALUE : 0) | (i & 32767) << 16 | (j < 0 ? '\u8000' : 0) | j & 32767; + } + + public int hashCode() { + return a(this.x, this.z); + } + + public boolean equals(Object object) { + ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) object; + + return chunkcoordintpair.x == this.x && chunkcoordintpair.z == this.z; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkCoordinates.java b/src/main/java/net/minecraft/server/ChunkCoordinates.java new file mode 100644 index 0000000..f672347 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkCoordinates.java @@ -0,0 +1,49 @@ +package net.minecraft.server; + +public class ChunkCoordinates implements Comparable { + + public int x; + public int y; + public int z; + + public ChunkCoordinates() {} + + public ChunkCoordinates(int i, int j, int k) { + this.x = i; + this.y = j; + this.z = k; + } + + public ChunkCoordinates(ChunkCoordinates chunkcoordinates) { + this.x = chunkcoordinates.x; + this.y = chunkcoordinates.y; + this.z = chunkcoordinates.z; + } + + public boolean equals(Object object) { + if (!(object instanceof ChunkCoordinates)) { + return false; + } else { + ChunkCoordinates chunkcoordinates = (ChunkCoordinates) object; + + return this.x == chunkcoordinates.x && this.y == chunkcoordinates.y && this.z == chunkcoordinates.z; + } + } + + public int hashCode() { + return this.x + this.z << 8 + this.y << 16; + } + + public int compareTo(Object o) { + ChunkCoordinates chunkcoordinates = (ChunkCoordinates) o; + return this.y == chunkcoordinates.y ? (this.z == chunkcoordinates.z ? this.x - chunkcoordinates.x : this.z - chunkcoordinates.z) : this.y - chunkcoordinates.y; + } + + public double a(int i, int j, int k) { + int l = this.x - i; + int i1 = this.y - j; + int j1 = this.z - k; + + return Math.sqrt((double) (l * l + i1 * i1 + j1 * j1)); + } +} diff --git a/src/main/java/net/minecraft/server/ChunkFile.java b/src/main/java/net/minecraft/server/ChunkFile.java new file mode 100644 index 0000000..95a17c5 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkFile.java @@ -0,0 +1,51 @@ +package net.minecraft.server; + +import java.io.File; +import java.util.regex.Matcher; + +class ChunkFile implements Comparable { + + private final File a; + private final int b; + private final int c; + + public ChunkFile(File file1) { + this.a = file1; + Matcher matcher = ChunkFilenameFilter.a.matcher(file1.getName()); + + if (matcher.matches()) { + this.b = Integer.parseInt(matcher.group(1), 36); + this.c = Integer.parseInt(matcher.group(2), 36); + } else { + this.b = 0; + this.c = 0; + } + } + + public int compareTo(Object o) { + ChunkFile chunkfile = (ChunkFile) o; + int i = this.b >> 5; + int j = chunkfile.b >> 5; + + if (i == j) { + int k = this.c >> 5; + int l = chunkfile.c >> 5; + + return k - l; + } else { + return i - j; + } + } + + public File a() { + return this.a; + } + + public int b() { + return this.b; + } + + public int c() { + return this.c; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkFileFilter.java b/src/main/java/net/minecraft/server/ChunkFileFilter.java new file mode 100644 index 0000000..987195d --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkFileFilter.java @@ -0,0 +1,27 @@ +package net.minecraft.server; + +import java.io.File; +import java.io.FileFilter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class ChunkFileFilter implements FileFilter { + + public static final Pattern a = Pattern.compile("[0-9a-z]|([0-9a-z][0-9a-z])"); + + private ChunkFileFilter() {} + + public boolean accept(File file1) { + if (file1.isDirectory()) { + Matcher matcher = a.matcher(file1.getName()); + + return matcher.matches(); + } else { + return false; + } + } + + ChunkFileFilter(EmptyClass2 emptyclass2) { + this(); + } +} diff --git a/src/main/java/net/minecraft/server/ChunkFilenameFilter.java b/src/main/java/net/minecraft/server/ChunkFilenameFilter.java new file mode 100644 index 0000000..320fda3 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkFilenameFilter.java @@ -0,0 +1,23 @@ +package net.minecraft.server; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class ChunkFilenameFilter implements FilenameFilter { + + public static final Pattern a = Pattern.compile("c\\.(-?[0-9a-z]+)\\.(-?[0-9a-z]+)\\.dat"); + + private ChunkFilenameFilter() {} + + public boolean accept(File file1, String s) { + Matcher matcher = a.matcher(s); + + return matcher.matches(); + } + + ChunkFilenameFilter(EmptyClass2 emptyclass2) { + this(); + } +} diff --git a/src/main/java/net/minecraft/server/ChunkLoader.java b/src/main/java/net/minecraft/server/ChunkLoader.java new file mode 100644 index 0000000..acb3518 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkLoader.java @@ -0,0 +1,221 @@ +package net.minecraft.server; + +import java.io.*; +import java.util.Iterator; + +public class ChunkLoader implements IChunkLoader { + + private File a; + private boolean b; + + public ChunkLoader(File file1, boolean flag) { + this.a = file1; + this.b = flag; + } + + private File a(int i, int j) { + String s = "c." + Integer.toString(i, 36) + "." + Integer.toString(j, 36) + ".dat"; + String s1 = Integer.toString(i & 63, 36); + String s2 = Integer.toString(j & 63, 36); + File file1 = new File(this.a, s1); + + if (!file1.exists()) { + if (!this.b) { + return null; + } + + file1.mkdir(); + } + + file1 = new File(file1, s2); + if (!file1.exists()) { + if (!this.b) { + return null; + } + + file1.mkdir(); + } + + file1 = new File(file1, s); + return !file1.exists() && !this.b ? null : file1; + } + + public Chunk a(World world, int i, int j) { + File file1 = this.a(i, j); + + if (file1 != null && file1.exists()) { + try { + FileInputStream fileinputstream = new FileInputStream(file1); + NBTTagCompound nbttagcompound = CompressedStreamTools.a((InputStream) fileinputstream); + + if (!nbttagcompound.hasKey("Level")) { + System.out.println("Chunk file at " + i + "," + j + " is missing level data, skipping"); + return null; + } + + if (!nbttagcompound.k("Level").hasKey("Blocks")) { + System.out.println("Chunk file at " + i + "," + j + " is missing block data, skipping"); + return null; + } + + Chunk chunk = a(world, nbttagcompound.k("Level")); + + if (!chunk.a(i, j)) { + System.out.println("Chunk file at " + i + "," + j + " is in the wrong location; relocating. (Expected " + i + ", " + j + ", got " + chunk.x + ", " + chunk.z + ")"); + nbttagcompound.a("xPos", i); + nbttagcompound.a("zPos", j); + chunk = a(world, nbttagcompound.k("Level")); + } + + chunk.h(); + return chunk; + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + return null; + } + + public void a(World world, Chunk chunk) { + world.k(); + File file1 = this.a(chunk.x, chunk.z); + + if (file1.exists()) { + WorldData worlddata = world.q(); + + worlddata.b(worlddata.g() - file1.length()); + } + + try { + File file2 = new File(this.a, "tmp_chunk.dat"); + FileOutputStream fileoutputstream = new FileOutputStream(file2); + NBTTagCompound nbttagcompound = new NBTTagCompound(); + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound.a("Level", (NBTBase) nbttagcompound1); + a(chunk, world, nbttagcompound1); + CompressedStreamTools.a(nbttagcompound, (OutputStream) fileoutputstream); + fileoutputstream.close(); + if (file1.exists()) { + file1.delete(); + } + + file2.renameTo(file1); + WorldData worlddata1 = world.q(); + + worlddata1.b(worlddata1.g() + file1.length()); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public static void a(Chunk chunk, World world, NBTTagCompound nbttagcompound) { + world.k(); + nbttagcompound.a("xPos", chunk.x); + nbttagcompound.a("zPos", chunk.z); + nbttagcompound.setLong("LastUpdate", world.getTime()); + nbttagcompound.a("Blocks", chunk.b); + nbttagcompound.a("Data", chunk.e.a); + nbttagcompound.a("SkyLight", chunk.f.a); + nbttagcompound.a("BlockLight", chunk.g.a); + nbttagcompound.a("HeightMap", chunk.heightMap); + nbttagcompound.a("TerrainPopulated", chunk.done); + chunk.q = false; + NBTTagList nbttaglist = new NBTTagList(); + + Iterator iterator; + NBTTagCompound nbttagcompound1; + + for (int i = 0; i < chunk.entitySlices.length; ++i) { + iterator = chunk.entitySlices[i].iterator(); + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); + + chunk.q = true; + nbttagcompound1 = new NBTTagCompound(); + if (entity.c(nbttagcompound1)) { + nbttaglist.a((NBTBase) nbttagcompound1); + } + } + } + + nbttagcompound.a("Entities", (NBTBase) nbttaglist); + NBTTagList nbttaglist1 = new NBTTagList(); + + iterator = chunk.tileEntities.values().iterator(); + + while (iterator.hasNext()) { + TileEntity tileentity = (TileEntity) iterator.next(); + + nbttagcompound1 = new NBTTagCompound(); + tileentity.b(nbttagcompound1); + nbttaglist1.a((NBTBase) nbttagcompound1); + } + + nbttagcompound.a("TileEntities", (NBTBase) nbttaglist1); + } + + public static Chunk a(World world, NBTTagCompound nbttagcompound) { + int i = nbttagcompound.e("xPos"); + int j = nbttagcompound.e("zPos"); + Chunk chunk = new Chunk(world, i, j); + + chunk.b = nbttagcompound.j("Blocks"); + chunk.e = new NibbleArray(nbttagcompound.j("Data")); + chunk.f = new NibbleArray(nbttagcompound.j("SkyLight")); + chunk.g = new NibbleArray(nbttagcompound.j("BlockLight")); + chunk.heightMap = nbttagcompound.j("HeightMap"); + chunk.done = nbttagcompound.m("TerrainPopulated"); + if (!chunk.e.a()) { + chunk.e = new NibbleArray(chunk.b.length); + } + + if (chunk.heightMap == null || !chunk.f.a()) { + chunk.heightMap = new byte[256]; + chunk.f = new NibbleArray(chunk.b.length); + chunk.initLighting(); + } + + if (!chunk.g.a()) { + chunk.g = new NibbleArray(chunk.b.length); + chunk.a(); + } + + NBTTagList nbttaglist = nbttagcompound.l("Entities"); + + if (nbttaglist != null) { + for (int k = 0; k < nbttaglist.c(); ++k) { + NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttaglist.a(k); + Entity entity = EntityTypes.a(nbttagcompound1, world); + + chunk.q = true; + if (entity != null) { + chunk.a(entity); + } + } + } + + NBTTagList nbttaglist1 = nbttagcompound.l("TileEntities"); + + if (nbttaglist1 != null) { + for (int l = 0; l < nbttaglist1.c(); ++l) { + NBTTagCompound nbttagcompound2 = (NBTTagCompound) nbttaglist1.a(l); + TileEntity tileentity = TileEntity.c(nbttagcompound2); + + if (tileentity != null) { + chunk.a(tileentity); + } + } + } + + return chunk; + } + + public void a() {} + + public void b() {} + + public void b(World world, Chunk chunk) {} +} diff --git a/src/main/java/net/minecraft/server/ChunkPosition.java b/src/main/java/net/minecraft/server/ChunkPosition.java new file mode 100644 index 0000000..1fe13bb --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkPosition.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +public class ChunkPosition { + + public final int x; + public final int y; + public final int z; + + public ChunkPosition(int i, int j, int k) { + this.x = i; + this.y = j; + this.z = k; + } + + public boolean equals(Object object) { + if (!(object instanceof ChunkPosition)) { + return false; + } else { + ChunkPosition chunkposition = (ChunkPosition) object; + + return chunkposition.x == this.x && chunkposition.y == this.y && chunkposition.z == this.z; + } + } + + public int hashCode() { + return this.x * 8976890 + this.y * 981131 + this.z; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderGenerate.java b/src/main/java/net/minecraft/server/ChunkProviderGenerate.java new file mode 100644 index 0000000..0775e92 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkProviderGenerate.java @@ -0,0 +1,642 @@ +package net.minecraft.server; + +import java.util.Random; + +public class ChunkProviderGenerate implements IChunkProvider { + + private Random j; + private NoiseGeneratorOctaves k; + private NoiseGeneratorOctaves l; + private NoiseGeneratorOctaves m; + private NoiseGeneratorOctaves n; + private NoiseGeneratorOctaves o; + public NoiseGeneratorOctaves a; + public NoiseGeneratorOctaves b; + public NoiseGeneratorOctaves c; + private World p; + private double[] q; + private double[] r = new double[256]; + private double[] s = new double[256]; + private double[] t = new double[256]; + private MapGenBase u = new MapGenCaves(); + private BiomeBase[] v; + double[] d; + double[] e; + double[] f; + double[] g; + double[] h; + int[][] i = new int[32][32]; + private double[] w; + + public ChunkProviderGenerate(World world, long i) { + this.p = world; + this.j = new Random(i); + this.k = new NoiseGeneratorOctaves(this.j, 16); + this.l = new NoiseGeneratorOctaves(this.j, 16); + this.m = new NoiseGeneratorOctaves(this.j, 8); + this.n = new NoiseGeneratorOctaves(this.j, 4); + this.o = new NoiseGeneratorOctaves(this.j, 4); + this.a = new NoiseGeneratorOctaves(this.j, 10); + this.b = new NoiseGeneratorOctaves(this.j, 16); + this.c = new NoiseGeneratorOctaves(this.j, 8); + } + + public void a(int i, int j, byte[] abyte, BiomeBase[] abiomebase, double[] adouble) { + byte b0 = 4; + byte b1 = 64; + int k = b0 + 1; + byte b2 = 17; + int l = b0 + 1; + + this.q = this.a(this.q, i * b0, 0, j * b0, k, b2, l); + + for (int i1 = 0; i1 < b0; ++i1) { + for (int j1 = 0; j1 < b0; ++j1) { + for (int k1 = 0; k1 < 16; ++k1) { + double d0 = 0.125D; + double d1 = this.q[((i1 + 0) * l + j1 + 0) * b2 + k1 + 0]; + double d2 = this.q[((i1 + 0) * l + j1 + 1) * b2 + k1 + 0]; + double d3 = this.q[((i1 + 1) * l + j1 + 0) * b2 + k1 + 0]; + double d4 = this.q[((i1 + 1) * l + j1 + 1) * b2 + k1 + 0]; + double d5 = (this.q[((i1 + 0) * l + j1 + 0) * b2 + k1 + 1] - d1) * d0; + double d6 = (this.q[((i1 + 0) * l + j1 + 1) * b2 + k1 + 1] - d2) * d0; + double d7 = (this.q[((i1 + 1) * l + j1 + 0) * b2 + k1 + 1] - d3) * d0; + double d8 = (this.q[((i1 + 1) * l + j1 + 1) * b2 + k1 + 1] - d4) * d0; + + for (int l1 = 0; l1 < 8; ++l1) { + double d9 = 0.25D; + double d10 = d1; + double d11 = d2; + double d12 = (d3 - d1) * d9; + double d13 = (d4 - d2) * d9; + + for (int i2 = 0; i2 < 4; ++i2) { + int j2 = i2 + i1 * 4 << 11 | 0 + j1 * 4 << 7 | k1 * 8 + l1; + short short1 = 128; + double d14 = 0.25D; + double d15 = d10; + double d16 = (d11 - d10) * d14; + + for (int k2 = 0; k2 < 4; ++k2) { + double d17 = adouble[(i1 * 4 + i2) * 16 + j1 * 4 + k2]; + int l2 = 0; + + if (k1 * 8 + l1 < b1) { + if (d17 < 0.5D && k1 * 8 + l1 >= b1 - 1) { + l2 = Block.ICE.id; + } else { + l2 = Block.STATIONARY_WATER.id; + } + } + + if (d15 > 0.0D) { + l2 = Block.STONE.id; + } + + abyte[j2] = (byte) l2; + j2 += short1; + d15 += d16; + } + + d10 += d12; + d11 += d13; + } + + d1 += d5; + d2 += d6; + d3 += d7; + d4 += d8; + } + } + } + } + } + + public void a(int i, int j, byte[] abyte, BiomeBase[] abiomebase) { + byte b0 = 64; + double d0 = 0.03125D; + + this.r = this.n.a(this.r, (double) (i * 16), (double) (j * 16), 0.0D, 16, 16, 1, d0, d0, 1.0D); + this.s = this.n.a(this.s, (double) (i * 16), 109.0134D, (double) (j * 16), 16, 1, 16, d0, 1.0D, d0); + this.t = this.o.a(this.t, (double) (i * 16), (double) (j * 16), 0.0D, 16, 16, 1, d0 * 2.0D, d0 * 2.0D, d0 * 2.0D); + + for (int k = 0; k < 16; ++k) { + for (int l = 0; l < 16; ++l) { + BiomeBase biomebase = abiomebase[k + l * 16]; + boolean flag = this.r[k + l * 16] + this.j.nextDouble() * 0.2D > 0.0D; + boolean flag1 = this.s[k + l * 16] + this.j.nextDouble() * 0.2D > 3.0D; + int i1 = (int) (this.t[k + l * 16] / 3.0D + 3.0D + this.j.nextDouble() * 0.25D); + int j1 = -1; + byte b1 = biomebase.p; + byte b2 = biomebase.q; + + for (int k1 = 127; k1 >= 0; --k1) { + int l1 = (l * 16 + k) * 128 + k1; + + if (k1 <= 0 + this.j.nextInt(5)) { + abyte[l1] = (byte) Block.BEDROCK.id; + } else { + byte b3 = abyte[l1]; + + if (b3 == 0) { + j1 = -1; + } else if (b3 == Block.STONE.id) { + if (j1 == -1) { + if (i1 <= 0) { + b1 = 0; + b2 = (byte) Block.STONE.id; + } else if (k1 >= b0 - 4 && k1 <= b0 + 1) { + b1 = biomebase.p; + b2 = biomebase.q; + if (flag1) { + b1 = 0; + } + + if (flag1) { + b2 = (byte) Block.GRAVEL.id; + } + + if (flag) { + b1 = (byte) Block.SAND.id; + } + + if (flag) { + b2 = (byte) Block.SAND.id; + } + } + + if (k1 < b0 && b1 == 0) { + b1 = (byte) Block.STATIONARY_WATER.id; + } + + j1 = i1; + if (k1 >= b0 - 1) { + abyte[l1] = b1; + } else { + abyte[l1] = b2; + } + } else if (j1 > 0) { + --j1; + abyte[l1] = b2; + if (j1 == 0 && b2 == Block.SAND.id) { + j1 = this.j.nextInt(4); + b2 = (byte) Block.SANDSTONE.id; + } + } + } + } + } + } + } + } + + public Chunk getChunkAt(int i, int j) { + return this.getOrCreateChunk(i, j); + } + + public Chunk getOrCreateChunk(int i, int j) { + this.j.setSeed((long) i * 341873128712L + (long) j * 132897987541L); + byte[] abyte = new byte['\u8000']; + Chunk chunk = new Chunk(this.p, abyte, i, j); + + this.v = this.p.getWorldChunkManager().a(this.v, i * 16, j * 16, 16, 16); + double[] adouble = this.p.getWorldChunkManager().temperature; + + this.a(i, j, abyte, this.v, adouble); + this.a(i, j, abyte, this.v); + this.u.a(this, this.p, i, j, abyte); + chunk.initLighting(); + return chunk; + } + + private double[] a(double[] adouble, int i, int j, int k, int l, int i1, int j1) { + if (adouble == null) { + adouble = new double[l * i1 * j1]; + } + + double d0 = 684.412D; + double d1 = 684.412D; + double[] adouble1 = this.p.getWorldChunkManager().temperature; + double[] adouble2 = this.p.getWorldChunkManager().rain; + + this.g = this.a.a(this.g, i, k, l, j1, 1.121D, 1.121D, 0.5D); + this.h = this.b.a(this.h, i, k, l, j1, 200.0D, 200.0D, 0.5D); + this.d = this.m.a(this.d, (double) i, (double) j, (double) k, l, i1, j1, d0 / 80.0D, d1 / 160.0D, d0 / 80.0D); + this.e = this.k.a(this.e, (double) i, (double) j, (double) k, l, i1, j1, d0, d1, d0); + this.f = this.l.a(this.f, (double) i, (double) j, (double) k, l, i1, j1, d0, d1, d0); + int k1 = 0; + int l1 = 0; + int i2 = 16 / l; + + for (int j2 = 0; j2 < l; ++j2) { + int k2 = j2 * i2 + i2 / 2; + + for (int l2 = 0; l2 < j1; ++l2) { + int i3 = l2 * i2 + i2 / 2; + double d2 = adouble1[k2 * 16 + i3]; + double d3 = adouble2[k2 * 16 + i3] * d2; + double d4 = 1.0D - d3; + + d4 *= d4; + d4 *= d4; + d4 = 1.0D - d4; + double d5 = (this.g[l1] + 256.0D) / 512.0D; + + d5 *= d4; + if (d5 > 1.0D) { + d5 = 1.0D; + } + + double d6 = this.h[l1] / 8000.0D; + + if (d6 < 0.0D) { + d6 = -d6 * 0.3D; + } + + d6 = d6 * 3.0D - 2.0D; + if (d6 < 0.0D) { + d6 /= 2.0D; + if (d6 < -1.0D) { + d6 = -1.0D; + } + + d6 /= 1.4D; + d6 /= 2.0D; + d5 = 0.0D; + } else { + if (d6 > 1.0D) { + d6 = 1.0D; + } + + d6 /= 8.0D; + } + + if (d5 < 0.0D) { + d5 = 0.0D; + } + + d5 += 0.5D; + d6 = d6 * (double) i1 / 16.0D; + double d7 = (double) i1 / 2.0D + d6 * 4.0D; + + ++l1; + + for (int j3 = 0; j3 < i1; ++j3) { + double d8 = 0.0D; + double d9 = ((double) j3 - d7) * 12.0D / d5; + + if (d9 < 0.0D) { + d9 *= 4.0D; + } + + double d10 = this.e[k1] / 512.0D; + double d11 = this.f[k1] / 512.0D; + double d12 = (this.d[k1] / 10.0D + 1.0D) / 2.0D; + + if (d12 < 0.0D) { + d8 = d10; + } else if (d12 > 1.0D) { + d8 = d11; + } else { + d8 = d10 + (d11 - d10) * d12; + } + + d8 -= d9; + if (j3 > i1 - 4) { + double d13 = (double) ((float) (j3 - (i1 - 4)) / 3.0F); + + d8 = d8 * (1.0D - d13) + -10.0D * d13; + } + + adouble[k1] = d8; + ++k1; + } + } + } + + return adouble; + } + + public boolean isChunkLoaded(int i, int j) { + return true; + } + + public void getChunkAt(IChunkProvider ichunkprovider, int i, int j) { + BlockSand.instaFall = true; + int k = i * 16; + int l = j * 16; + BiomeBase biomebase = this.p.getWorldChunkManager().getBiome(k + 16, l + 16); + + this.j.setSeed(this.p.getSeed()); + long i1 = this.j.nextLong() / 2L * 2L + 1L; + long j1 = this.j.nextLong() / 2L * 2L + 1L; + + this.j.setSeed((long) i * i1 + (long) j * j1 ^ this.p.getSeed()); + double d0 = 0.25D; + int k1; + int l1; + int i2; + + if (this.j.nextInt(4) == 0) { + k1 = k + this.j.nextInt(16) + 8; + l1 = this.j.nextInt(128); + i2 = l + this.j.nextInt(16) + 8; + (new WorldGenLakes(Block.STATIONARY_WATER.id)).a(this.p, this.j, k1, l1, i2); + } + + if (this.j.nextInt(8) == 0) { + k1 = k + this.j.nextInt(16) + 8; + l1 = this.j.nextInt(this.j.nextInt(120) + 8); + i2 = l + this.j.nextInt(16) + 8; + if (l1 < 64 || this.j.nextInt(10) == 0) { + (new WorldGenLakes(Block.STATIONARY_LAVA.id)).a(this.p, this.j, k1, l1, i2); + } + } + + int j2; + + for (k1 = 0; k1 < 8; ++k1) { + l1 = k + this.j.nextInt(16) + 8; + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16) + 8; + (new WorldGenDungeons()).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 10; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenClay(32)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 20; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.DIRT.id, 32)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 10; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.GRAVEL.id, 32)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 20; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.COAL_ORE.id, 16)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 20; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(64); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.IRON_ORE.id, 8)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 2; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(32); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.GOLD_ORE.id, 8)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 8; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(16); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.REDSTONE_ORE.id, 7)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 1; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(16); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.DIAMOND_ORE.id, 7)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 1; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(16) + this.j.nextInt(16); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.LAPIS_ORE.id, 6)).a(this.p, this.j, l1, i2, j2); + } + + d0 = 0.5D; + k1 = (int) ((this.c.a((double) k * d0, (double) l * d0) / 8.0D + this.j.nextDouble() * 4.0D + 4.0D) / 3.0D); + l1 = 0; + if (this.j.nextInt(10) == 0) { + ++l1; + } + + if (biomebase == BiomeBase.FOREST) { + l1 += k1 + 5; + } + + if (biomebase == BiomeBase.RAINFOREST) { + l1 += k1 + 5; + } + + if (biomebase == BiomeBase.SEASONAL_FOREST) { + l1 += k1 + 2; + } + + if (biomebase == BiomeBase.TAIGA) { + l1 += k1 + 5; + } + + if (biomebase == BiomeBase.DESERT) { + l1 -= 20; + } + + if (biomebase == BiomeBase.TUNDRA) { + l1 -= 20; + } + + if (biomebase == BiomeBase.PLAINS) { + l1 -= 20; + } + + int k2; + + for (i2 = 0; i2 < l1; ++i2) { + j2 = k + this.j.nextInt(16) + 8; + k2 = l + this.j.nextInt(16) + 8; + WorldGenerator worldgenerator = biomebase.a(this.j); + + worldgenerator.a(1.0D, 1.0D, 1.0D); + worldgenerator.a(this.p, this.j, j2, this.p.getHighestBlockYAt(j2, k2), k2); + } + + byte b0 = 0; + + if (biomebase == BiomeBase.FOREST) { + b0 = 2; + } + + if (biomebase == BiomeBase.SEASONAL_FOREST) { + b0 = 4; + } + + if (biomebase == BiomeBase.TAIGA) { + b0 = 2; + } + + if (biomebase == BiomeBase.PLAINS) { + b0 = 3; + } + + int l2; + int i3; + + for (j2 = 0; j2 < b0; ++j2) { + k2 = k + this.j.nextInt(16) + 8; + i3 = this.j.nextInt(128); + l2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.YELLOW_FLOWER.id)).a(this.p, this.j, k2, i3, l2); + } + + byte b1 = 0; + + if (biomebase == BiomeBase.FOREST) { + b1 = 2; + } + + if (biomebase == BiomeBase.RAINFOREST) { + b1 = 10; + } + + if (biomebase == BiomeBase.SEASONAL_FOREST) { + b1 = 2; + } + + if (biomebase == BiomeBase.TAIGA) { + b1 = 1; + } + + if (biomebase == BiomeBase.PLAINS) { + b1 = 10; + } + + int j3; + int k3; + + for (k2 = 0; k2 < b1; ++k2) { + byte b2 = 1; + + if (biomebase == BiomeBase.RAINFOREST && this.j.nextInt(3) != 0) { + b2 = 2; + } + + l2 = k + this.j.nextInt(16) + 8; + k3 = this.j.nextInt(128); + j3 = l + this.j.nextInt(16) + 8; + (new WorldGenGrass(Block.LONG_GRASS.id, b2)).a(this.p, this.j, l2, k3, j3); + } + + b1 = 0; + if (biomebase == BiomeBase.DESERT) { + b1 = 2; + } + + for (k2 = 0; k2 < b1; ++k2) { + i3 = k + this.j.nextInt(16) + 8; + l2 = this.j.nextInt(128); + k3 = l + this.j.nextInt(16) + 8; + (new WorldGenDeadBush(Block.DEAD_BUSH.id)).a(this.p, this.j, i3, l2, k3); + } + + if (this.j.nextInt(2) == 0) { + k2 = k + this.j.nextInt(16) + 8; + i3 = this.j.nextInt(128); + l2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.RED_ROSE.id)).a(this.p, this.j, k2, i3, l2); + } + + if (this.j.nextInt(4) == 0) { + k2 = k + this.j.nextInt(16) + 8; + i3 = this.j.nextInt(128); + l2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.BROWN_MUSHROOM.id)).a(this.p, this.j, k2, i3, l2); + } + + if (this.j.nextInt(8) == 0) { + k2 = k + this.j.nextInt(16) + 8; + i3 = this.j.nextInt(128); + l2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.RED_MUSHROOM.id)).a(this.p, this.j, k2, i3, l2); + } + + for (k2 = 0; k2 < 10; ++k2) { + i3 = k + this.j.nextInt(16) + 8; + l2 = this.j.nextInt(128); + k3 = l + this.j.nextInt(16) + 8; + (new WorldGenReed()).a(this.p, this.j, i3, l2, k3); + } + + if (this.j.nextInt(32) == 0) { + k2 = k + this.j.nextInt(16) + 8; + i3 = this.j.nextInt(128); + l2 = l + this.j.nextInt(16) + 8; + (new WorldGenPumpkin()).a(this.p, this.j, k2, i3, l2); + } + + k2 = 0; + if (biomebase == BiomeBase.DESERT) { + k2 += 10; + } + + for (i3 = 0; i3 < k2; ++i3) { + l2 = k + this.j.nextInt(16) + 8; + k3 = this.j.nextInt(128); + j3 = l + this.j.nextInt(16) + 8; + (new WorldGenCactus()).a(this.p, this.j, l2, k3, j3); + } + + for (i3 = 0; i3 < 50; ++i3) { + l2 = k + this.j.nextInt(16) + 8; + k3 = this.j.nextInt(this.j.nextInt(120) + 8); + j3 = l + this.j.nextInt(16) + 8; + (new WorldGenLiquids(Block.WATER.id)).a(this.p, this.j, l2, k3, j3); + } + + for (i3 = 0; i3 < 20; ++i3) { + l2 = k + this.j.nextInt(16) + 8; + k3 = this.j.nextInt(this.j.nextInt(this.j.nextInt(112) + 8) + 8); + j3 = l + this.j.nextInt(16) + 8; + (new WorldGenLiquids(Block.LAVA.id)).a(this.p, this.j, l2, k3, j3); + } + + this.w = this.p.getWorldChunkManager().a(this.w, k + 8, l + 8, 16, 16); + + for (i3 = k + 8; i3 < k + 8 + 16; ++i3) { + for (l2 = l + 8; l2 < l + 8 + 16; ++l2) { + k3 = i3 - (k + 8); + j3 = l2 - (l + 8); + int l3 = this.p.e(i3, l2); + double d1 = this.w[k3 * 16 + j3] - (double) (l3 - 64) / 64.0D * 0.3D; + + if (d1 < 0.5D && l3 > 0 && l3 < 128 && this.p.isEmpty(i3, l3, l2) && this.p.getMaterial(i3, l3 - 1, l2).isSolid() && this.p.getMaterial(i3, l3 - 1, l2) != Material.ICE) { + this.p.setTypeId(i3, l3, l2, Block.SNOW.id); + } + } + } + + BlockSand.instaFall = false; + } + + public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) { + return true; + } + + public boolean unloadChunks() { + return false; + } + + public boolean canSave() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderHell.java b/src/main/java/net/minecraft/server/ChunkProviderHell.java new file mode 100644 index 0000000..e9b5f1a --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkProviderHell.java @@ -0,0 +1,387 @@ +package net.minecraft.server; + +import java.util.Random; + +public class ChunkProviderHell implements IChunkProvider { + + private Random h; + private NoiseGeneratorOctaves i; + private NoiseGeneratorOctaves j; + private NoiseGeneratorOctaves k; + private NoiseGeneratorOctaves l; + private NoiseGeneratorOctaves m; + public NoiseGeneratorOctaves a; + public NoiseGeneratorOctaves b; + private World n; + private double[] o; + private double[] p = new double[256]; + private double[] q = new double[256]; + private double[] r = new double[256]; + private MapGenBase s = new MapGenCavesHell(); + double[] c; + double[] d; + double[] e; + double[] f; + double[] g; + + public ChunkProviderHell(World world, long i) { + this.n = world; + this.h = new Random(i); + this.i = new NoiseGeneratorOctaves(this.h, 16); + this.j = new NoiseGeneratorOctaves(this.h, 16); + this.k = new NoiseGeneratorOctaves(this.h, 8); + this.l = new NoiseGeneratorOctaves(this.h, 4); + this.m = new NoiseGeneratorOctaves(this.h, 4); + this.a = new NoiseGeneratorOctaves(this.h, 10); + this.b = new NoiseGeneratorOctaves(this.h, 16); + } + + public void a(int i, int j, byte[] abyte) { + byte b0 = 4; + byte b1 = 32; + int k = b0 + 1; + byte b2 = 17; + int l = b0 + 1; + + this.o = this.a(this.o, i * b0, 0, j * b0, k, b2, l); + + for (int i1 = 0; i1 < b0; ++i1) { + for (int j1 = 0; j1 < b0; ++j1) { + for (int k1 = 0; k1 < 16; ++k1) { + double d0 = 0.125D; + double d1 = this.o[((i1 + 0) * l + j1 + 0) * b2 + k1 + 0]; + double d2 = this.o[((i1 + 0) * l + j1 + 1) * b2 + k1 + 0]; + double d3 = this.o[((i1 + 1) * l + j1 + 0) * b2 + k1 + 0]; + double d4 = this.o[((i1 + 1) * l + j1 + 1) * b2 + k1 + 0]; + double d5 = (this.o[((i1 + 0) * l + j1 + 0) * b2 + k1 + 1] - d1) * d0; + double d6 = (this.o[((i1 + 0) * l + j1 + 1) * b2 + k1 + 1] - d2) * d0; + double d7 = (this.o[((i1 + 1) * l + j1 + 0) * b2 + k1 + 1] - d3) * d0; + double d8 = (this.o[((i1 + 1) * l + j1 + 1) * b2 + k1 + 1] - d4) * d0; + + for (int l1 = 0; l1 < 8; ++l1) { + double d9 = 0.25D; + double d10 = d1; + double d11 = d2; + double d12 = (d3 - d1) * d9; + double d13 = (d4 - d2) * d9; + + for (int i2 = 0; i2 < 4; ++i2) { + int j2 = i2 + i1 * 4 << 11 | 0 + j1 * 4 << 7 | k1 * 8 + l1; + short short1 = 128; + double d14 = 0.25D; + double d15 = d10; + double d16 = (d11 - d10) * d14; + + for (int k2 = 0; k2 < 4; ++k2) { + int l2 = 0; + + if (k1 * 8 + l1 < b1) { + l2 = Block.STATIONARY_LAVA.id; + } + + if (d15 > 0.0D) { + l2 = Block.NETHERRACK.id; + } + + abyte[j2] = (byte) l2; + j2 += short1; + d15 += d16; + } + + d10 += d12; + d11 += d13; + } + + d1 += d5; + d2 += d6; + d3 += d7; + d4 += d8; + } + } + } + } + } + + public void b(int i, int j, byte[] abyte) { + byte b0 = 64; + double d0 = 0.03125D; + + this.p = this.l.a(this.p, (double) (i * 16), (double) (j * 16), 0.0D, 16, 16, 1, d0, d0, 1.0D); + this.q = this.l.a(this.q, (double) (i * 16), 109.0134D, (double) (j * 16), 16, 1, 16, d0, 1.0D, d0); + this.r = this.m.a(this.r, (double) (i * 16), (double) (j * 16), 0.0D, 16, 16, 1, d0 * 2.0D, d0 * 2.0D, d0 * 2.0D); + + for (int k = 0; k < 16; ++k) { + for (int l = 0; l < 16; ++l) { + boolean flag = this.p[k + l * 16] + this.h.nextDouble() * 0.2D > 0.0D; + boolean flag1 = this.q[k + l * 16] + this.h.nextDouble() * 0.2D > 0.0D; + int i1 = (int) (this.r[k + l * 16] / 3.0D + 3.0D + this.h.nextDouble() * 0.25D); + int j1 = -1; + byte b1 = (byte) Block.NETHERRACK.id; + byte b2 = (byte) Block.NETHERRACK.id; + + for (int k1 = 127; k1 >= 0; --k1) { + int l1 = (l * 16 + k) * 128 + k1; + + if (k1 >= 127 - this.h.nextInt(5)) { + abyte[l1] = (byte) Block.BEDROCK.id; + } else if (k1 <= 0 + this.h.nextInt(5)) { + abyte[l1] = (byte) Block.BEDROCK.id; + } else { + byte b3 = abyte[l1]; + + if (b3 == 0) { + j1 = -1; + } else if (b3 == Block.NETHERRACK.id) { + if (j1 == -1) { + if (i1 <= 0) { + b1 = 0; + b2 = (byte) Block.NETHERRACK.id; + } else if (k1 >= b0 - 4 && k1 <= b0 + 1) { + b1 = (byte) Block.NETHERRACK.id; + b2 = (byte) Block.NETHERRACK.id; + if (flag1) { + b1 = (byte) Block.GRAVEL.id; + } + + if (flag1) { + b2 = (byte) Block.NETHERRACK.id; + } + + if (flag) { + b1 = (byte) Block.SOUL_SAND.id; + } + + if (flag) { + b2 = (byte) Block.SOUL_SAND.id; + } + } + + if (k1 < b0 && b1 == 0) { + b1 = (byte) Block.STATIONARY_LAVA.id; + } + + j1 = i1; + if (k1 >= b0 - 1) { + abyte[l1] = b1; + } else { + abyte[l1] = b2; + } + } else if (j1 > 0) { + --j1; + abyte[l1] = b2; + } + } + } + } + } + } + } + + public Chunk getChunkAt(int i, int j) { + return this.getOrCreateChunk(i, j); + } + + public Chunk getOrCreateChunk(int i, int j) { + this.h.setSeed((long) i * 341873128712L + (long) j * 132897987541L); + byte[] abyte = new byte['\u8000']; + + this.a(i, j, abyte); + this.b(i, j, abyte); + this.s.a(this, this.n, i, j, abyte); + Chunk chunk = new Chunk(this.n, abyte, i, j); + + return chunk; + } + + private double[] a(double[] adouble, int i, int j, int k, int l, int i1, int j1) { + if (adouble == null) { + adouble = new double[l * i1 * j1]; + } + + double d0 = 684.412D; + double d1 = 2053.236D; + + this.f = this.a.a(this.f, (double) i, (double) j, (double) k, l, 1, j1, 1.0D, 0.0D, 1.0D); + this.g = this.b.a(this.g, (double) i, (double) j, (double) k, l, 1, j1, 100.0D, 0.0D, 100.0D); + this.c = this.k.a(this.c, (double) i, (double) j, (double) k, l, i1, j1, d0 / 80.0D, d1 / 60.0D, d0 / 80.0D); + this.d = this.i.a(this.d, (double) i, (double) j, (double) k, l, i1, j1, d0, d1, d0); + this.e = this.j.a(this.e, (double) i, (double) j, (double) k, l, i1, j1, d0, d1, d0); + int k1 = 0; + int l1 = 0; + double[] adouble1 = new double[i1]; + + int i2; + + for (i2 = 0; i2 < i1; ++i2) { + adouble1[i2] = Math.cos((double) i2 * 3.141592653589793D * 6.0D / (double) i1) * 2.0D; + double d2 = (double) i2; + + if (i2 > i1 / 2) { + d2 = (double) (i1 - 1 - i2); + } + + if (d2 < 4.0D) { + d2 = 4.0D - d2; + adouble1[i2] -= d2 * d2 * d2 * 10.0D; + } + } + + for (i2 = 0; i2 < l; ++i2) { + for (int j2 = 0; j2 < j1; ++j2) { + double d3 = (this.f[l1] + 256.0D) / 512.0D; + + if (d3 > 1.0D) { + d3 = 1.0D; + } + + double d4 = 0.0D; + double d5 = this.g[l1] / 8000.0D; + + if (d5 < 0.0D) { + d5 = -d5; + } + + d5 = d5 * 3.0D - 3.0D; + if (d5 < 0.0D) { + d5 /= 2.0D; + if (d5 < -1.0D) { + d5 = -1.0D; + } + + d5 /= 1.4D; + d5 /= 2.0D; + d3 = 0.0D; + } else { + if (d5 > 1.0D) { + d5 = 1.0D; + } + + d5 /= 6.0D; + } + + d3 += 0.5D; + d5 = d5 * (double) i1 / 16.0D; + ++l1; + + for (int k2 = 0; k2 < i1; ++k2) { + double d6 = 0.0D; + double d7 = adouble1[k2]; + double d8 = this.d[k1] / 512.0D; + double d9 = this.e[k1] / 512.0D; + double d10 = (this.c[k1] / 10.0D + 1.0D) / 2.0D; + + if (d10 < 0.0D) { + d6 = d8; + } else if (d10 > 1.0D) { + d6 = d9; + } else { + d6 = d8 + (d9 - d8) * d10; + } + + d6 -= d7; + double d11; + + if (k2 > i1 - 4) { + d11 = (double) ((float) (k2 - (i1 - 4)) / 3.0F); + d6 = d6 * (1.0D - d11) + -10.0D * d11; + } + + if ((double) k2 < d4) { + d11 = (d4 - (double) k2) / 4.0D; + if (d11 < 0.0D) { + d11 = 0.0D; + } + + if (d11 > 1.0D) { + d11 = 1.0D; + } + + d6 = d6 * (1.0D - d11) + -10.0D * d11; + } + + adouble[k1] = d6; + ++k1; + } + } + } + + return adouble; + } + + public boolean isChunkLoaded(int i, int j) { + return true; + } + + public void getChunkAt(IChunkProvider ichunkprovider, int i, int j) { + BlockSand.instaFall = true; + int k = i * 16; + int l = j * 16; + + int i1; + int j1; + int k1; + int l1; + + for (i1 = 0; i1 < 8; ++i1) { + j1 = k + this.h.nextInt(16) + 8; + k1 = this.h.nextInt(120) + 4; + l1 = l + this.h.nextInt(16) + 8; + (new WorldGenHellLava(Block.LAVA.id)).a(this.n, this.h, j1, k1, l1); + } + + i1 = this.h.nextInt(this.h.nextInt(10) + 1) + 1; + + int i2; + + for (j1 = 0; j1 < i1; ++j1) { + k1 = k + this.h.nextInt(16) + 8; + l1 = this.h.nextInt(120) + 4; + i2 = l + this.h.nextInt(16) + 8; + (new WorldGenFire()).a(this.n, this.h, k1, l1, i2); + } + + i1 = this.h.nextInt(this.h.nextInt(10) + 1); + + for (j1 = 0; j1 < i1; ++j1) { + k1 = k + this.h.nextInt(16) + 8; + l1 = this.h.nextInt(120) + 4; + i2 = l + this.h.nextInt(16) + 8; + (new WorldGenLightStone2()).a(this.n, this.h, k1, l1, i2); + } + + for (j1 = 0; j1 < 10; ++j1) { + k1 = k + this.h.nextInt(16) + 8; + l1 = this.h.nextInt(128); + i2 = l + this.h.nextInt(16) + 8; + (new WorldGenLightStone1()).a(this.n, this.h, k1, l1, i2); + } + + if (this.h.nextInt(1) == 0) { + j1 = k + this.h.nextInt(16) + 8; + k1 = this.h.nextInt(128); + l1 = l + this.h.nextInt(16) + 8; + (new WorldGenFlowers(Block.BROWN_MUSHROOM.id)).a(this.n, this.h, j1, k1, l1); + } + + if (this.h.nextInt(1) == 0) { + j1 = k + this.h.nextInt(16) + 8; + k1 = this.h.nextInt(128); + l1 = l + this.h.nextInt(16) + 8; + (new WorldGenFlowers(Block.RED_MUSHROOM.id)).a(this.n, this.h, j1, k1, l1); + } + + BlockSand.instaFall = false; + } + + public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) { + return true; + } + + public boolean unloadChunks() { + return false; + } + + public boolean canSave() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderLoadOrGenerate.java b/src/main/java/net/minecraft/server/ChunkProviderLoadOrGenerate.java new file mode 100644 index 0000000..1a59ad5 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkProviderLoadOrGenerate.java @@ -0,0 +1,183 @@ +package net.minecraft.server; + +import java.util.*; + +public class ChunkProviderLoadOrGenerate implements IChunkProvider { + + private Set a = new HashSet(); + private Chunk b; + private IChunkProvider c; + private IChunkLoader d; + private Map e = new HashMap(); + private List f = new ArrayList(); + private World g; + + public ChunkProviderLoadOrGenerate(World world, IChunkLoader ichunkloader, IChunkProvider ichunkprovider) { + this.b = new EmptyChunk(world, new byte['\u8000'], 0, 0); + this.g = world; + this.d = ichunkloader; + this.c = ichunkprovider; + } + + public boolean isChunkLoaded(int i, int j) { + return this.e.containsKey(Integer.valueOf(ChunkCoordIntPair.a(i, j))); + } + + public Chunk getChunkAt(int i, int j) { + int k = ChunkCoordIntPair.a(i, j); + + this.a.remove(Integer.valueOf(k)); + Chunk chunk = (Chunk) this.e.get(Integer.valueOf(k)); + + if (chunk == null) { + chunk = this.d(i, j); + if (chunk == null) { + if (this.c == null) { + chunk = this.b; + } else { + chunk = this.c.getOrCreateChunk(i, j); + } + } + + this.e.put(Integer.valueOf(k), chunk); + this.f.add(chunk); + if (chunk != null) { + chunk.loadNOP(); + chunk.addEntities(); + } + + if (!chunk.done && this.isChunkLoaded(i + 1, j + 1) && this.isChunkLoaded(i, j + 1) && this.isChunkLoaded(i + 1, j)) { + this.getChunkAt(this, i, j); + } + + if (this.isChunkLoaded(i - 1, j) && !this.getOrCreateChunk(i - 1, j).done && this.isChunkLoaded(i - 1, j + 1) && this.isChunkLoaded(i, j + 1) && this.isChunkLoaded(i - 1, j)) { + this.getChunkAt(this, i - 1, j); + } + + if (this.isChunkLoaded(i, j - 1) && !this.getOrCreateChunk(i, j - 1).done && this.isChunkLoaded(i + 1, j - 1) && this.isChunkLoaded(i, j - 1) && this.isChunkLoaded(i + 1, j)) { + this.getChunkAt(this, i, j - 1); + } + + if (this.isChunkLoaded(i - 1, j - 1) && !this.getOrCreateChunk(i - 1, j - 1).done && this.isChunkLoaded(i - 1, j - 1) && this.isChunkLoaded(i, j - 1) && this.isChunkLoaded(i - 1, j)) { + this.getChunkAt(this, i - 1, j - 1); + } + } + + return chunk; + } + + public Chunk getOrCreateChunk(int i, int j) { + Chunk chunk = (Chunk) this.e.get(Integer.valueOf(ChunkCoordIntPair.a(i, j))); + + return chunk == null ? this.getChunkAt(i, j) : chunk; + } + + private Chunk d(int i, int j) { + if (this.d == null) { + return null; + } else { + try { + Chunk chunk = this.d.a(this.g, i, j); + + if (chunk != null) { + chunk.r = this.g.getTime(); + } + + return chunk; + } catch (Exception exception) { + exception.printStackTrace(); + return null; + } + } + } + + private void a(Chunk chunk) { + if (this.d != null) { + try { + this.d.b(this.g, chunk); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + } + + private void b(Chunk chunk) { + if (this.d != null) { + try { + chunk.r = this.g.getTime(); + this.d.a(this.g, chunk); + } catch (Exception ioexception) { + ioexception.printStackTrace(); + } + } + } + + public void getChunkAt(IChunkProvider ichunkprovider, int i, int j) { + Chunk chunk = this.getOrCreateChunk(i, j); + + if (!chunk.done) { + chunk.done = true; + if (this.c != null) { + this.c.getChunkAt(ichunkprovider, i, j); + chunk.f(); + } + } + } + + public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) { + int i = 0; + + for (int j = 0; j < this.f.size(); ++j) { + Chunk chunk = (Chunk) this.f.get(j); + + if (flag && !chunk.p) { + this.a(chunk); + } + + if (chunk.a(flag)) { + this.b(chunk); + chunk.o = false; + ++i; + if (i == 24 && !flag) { + return false; + } + } + } + + if (flag) { + if (this.d == null) { + return true; + } + + this.d.b(); + } + + return true; + } + + public boolean unloadChunks() { + for (int i = 0; i < 100; ++i) { + if (!this.a.isEmpty()) { + Integer integer = (Integer) this.a.iterator().next(); + Chunk chunk = (Chunk) this.e.get(integer); + + chunk.removeEntities(); + this.b(chunk); + this.a(chunk); + this.a.remove(integer); + this.e.remove(integer); + this.f.remove(chunk); + } + } + + if (this.d != null) { + this.d.a(); + } + + return this.c.unloadChunks(); + } + + public boolean canSave() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java new file mode 100644 index 0000000..b8fcbd0 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -0,0 +1,280 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.util.LongHashset; +import org.bukkit.craftbukkit.util.LongHashtable; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.ChunkPopulateEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.generator.BlockPopulator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class ChunkProviderServer implements IChunkProvider { + + // CraftBukkit start + public LongHashset unloadQueue = new LongHashset(); + public Chunk emptyChunk; + public IChunkProvider chunkProvider; // CraftBukkit + private IChunkLoader e; + public boolean forceChunkLoad = false; + public LongHashtable chunks = new LongHashtable(); + public List chunkList = new ArrayList(); + public WorldServer world; + // CraftBukkit end + + public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, IChunkProvider ichunkprovider) { + this.emptyChunk = new EmptyChunk(worldserver, new byte['\u8000'], 0, 0); + this.world = worldserver; + this.e = ichunkloader; + this.chunkProvider = ichunkprovider; + } + + public boolean isChunkLoaded(int i, int j) { + return this.chunks.containsKey(i, j); // CraftBukkit + } + + public void queueUnload(int i, int j) { + ChunkCoordinates chunkcoordinates = this.world.getSpawn(); + int k = i * 16 + 8 - chunkcoordinates.x; + int l = j * 16 + 8 - chunkcoordinates.z; + short short1 = 128; + + if (k < -short1 || k > short1 || l < -short1 || l > short1 || !(this.world.keepSpawnInMemory)) { // CraftBukkit - added 'this.world.keepSpawnInMemory' + this.unloadQueue.add(i, j); // CraftBukkit + } + } + + public Chunk getChunkAt(int i, int j) { + // CraftBukkit start + this.unloadQueue.remove(i, j); + Chunk chunk = (Chunk) this.chunks.get(i, j); + boolean newChunk = false; + // CraftBukkit end + + if (chunk == null) { + chunk = this.loadChunk(i, j); + if (chunk == null) { + if (this.chunkProvider == null) { + chunk = this.emptyChunk; + } else { + chunk = this.chunkProvider.getOrCreateChunk(i, j); + } + newChunk = true; // CraftBukkit + } + + this.chunks.put(i, j, chunk); // CraftBukkit + this.chunkList.add(chunk); + if (chunk != null) { + chunk.loadNOP(); + chunk.addEntities(); + } + + // CraftBukkit start + org.bukkit.Server server = this.world.getServer(); + if (server != null) { + /* + * If it's a new world, the first few chunks are generated inside + * the World constructor. We can't reliably alter that, so we have + * no way of creating a CraftWorld/CraftServer at that point. + */ + server.getPluginManager().callEvent(new ChunkLoadEvent(chunk.bukkitChunk, newChunk)); + } + // CraftBukkit end + + if (!chunk.done && this.isChunkLoaded(i + 1, j + 1) && this.isChunkLoaded(i, j + 1) && this.isChunkLoaded(i + 1, j)) { + this.getChunkAt(this, i, j); + } + + if (this.isChunkLoaded(i - 1, j) && !this.getOrCreateChunk(i - 1, j).done && this.isChunkLoaded(i - 1, j + 1) && this.isChunkLoaded(i, j + 1) && this.isChunkLoaded(i - 1, j)) { + this.getChunkAt(this, i - 1, j); + } + + if (this.isChunkLoaded(i, j - 1) && !this.getOrCreateChunk(i, j - 1).done && this.isChunkLoaded(i + 1, j - 1) && this.isChunkLoaded(i, j - 1) && this.isChunkLoaded(i + 1, j)) { + this.getChunkAt(this, i, j - 1); + } + + if (this.isChunkLoaded(i - 1, j - 1) && !this.getOrCreateChunk(i - 1, j - 1).done && this.isChunkLoaded(i - 1, j - 1) && this.isChunkLoaded(i, j - 1) && this.isChunkLoaded(i - 1, j)) { + this.getChunkAt(this, i - 1, j - 1); + } + } + + return chunk; + } + + public Chunk getOrCreateChunk(int i, int j) { + // CraftBukkit start + Chunk chunk = (Chunk) this.chunks.get(i, j); + + //Poseidon chunk regenerate + try { + chunk = chunk == null ? (!this.world.isLoading && !this.forceChunkLoad ? this.emptyChunk : this.getChunkAt(i, j)) : chunk; + } catch (Exception e) { + //Poseidon chunk regenerate + if (PoseidonConfig.getInstance().getConfigBoolean("emergency.debug.regenerate-corrupt-chunks.enable")) { + System.out.println("Poseidon ran into a critical error when attempting to load a chunk (" + i + "," + j + "+. Regenerating chunk..."); + chunk = this.emptyChunk; + } else { + System.out.println("Poseidon ran into a critical error when attempting to load a chunk (" + i + "," + j + "+. The server will now likely hang. Enabling \"emergency.debug.regenerate-corrupt-chunks.enable\" in the Poseidon.yml may help."); + e.printStackTrace(); + } + e.printStackTrace(); + } + + + if (chunk == this.emptyChunk) return chunk; + if (i != chunk.x || j != chunk.z) { + MinecraftServer.log.info("Chunk (" + chunk.x + ", " + chunk.z + ") stored at (" + i + ", " + j + ")"); + MinecraftServer.log.info(chunk.getClass().getName()); + Throwable ex = new Throwable(); + ex.fillInStackTrace(); + ex.printStackTrace(); + } + return chunk; + // CraftBukkit end + } + + public Chunk loadChunk(int i, int j) { // CraftBukkit - private -> public + if (this.e == null) { + return null; + } else { + try { + Chunk chunk = this.e.a(this.world, i, j); + + if (chunk != null) { + chunk.r = this.world.getTime(); + } + + return chunk; + } catch (Exception exception) { + exception.printStackTrace(); + return null; + } + } + } + + public void saveChunkNOP(Chunk chunk) { // CraftBukkit - private -> public + if (this.e != null) { + try { + this.e.b(this.world, chunk); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + } + + public void saveChunk(Chunk chunk) { // CraftBukkit - private -> public + if (this.e != null) { + try { + chunk.r = this.world.getTime(); + this.e.a(this.world, chunk); + } catch (Exception ioexception) { // CraftBukkit - IOException -> Exception + ioexception.printStackTrace(); + } + } + } + + public void getChunkAt(IChunkProvider ichunkprovider, int i, int j) { + Chunk chunk = this.getOrCreateChunk(i, j); + + if (!chunk.done) { + chunk.done = true; + if (this.chunkProvider != null) { + this.chunkProvider.getChunkAt(ichunkprovider, i, j); + + // CraftBukkit start + BlockSand.instaFall = true; + Random random = new Random(); + random.setSeed(world.getSeed()); + long xRand = random.nextLong() / 2L * 2L + 1L; + long zRand = random.nextLong() / 2L * 2L + 1L; + random.setSeed((long) i * xRand + (long) j * zRand ^ world.getSeed()); + + org.bukkit.World world = this.world.getWorld(); + if (world != null) { + for (BlockPopulator populator : world.getPopulators()) { + populator.populate(world, random, chunk.bukkitChunk); + } + } + BlockSand.instaFall = false; + this.world.getServer().getPluginManager().callEvent(new ChunkPopulateEvent(chunk.bukkitChunk)); + // CraftBukkit end + + chunk.f(); + } + } + } + + public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) { + int i = 0; + + for (int j = 0; j < this.chunkList.size(); ++j) { + Chunk chunk = (Chunk) this.chunkList.get(j); + + if (flag && !chunk.p) { + this.saveChunkNOP(chunk); + } + + if (chunk.a(flag)) { + this.saveChunk(chunk); + chunk.o = false; + ++i; + if (i == 24 && !flag) { + return false; + } + } + } + + if (flag) { + if (this.e == null) { + return true; + } + + this.e.b(); + } + + return true; + } + + public boolean unloadChunks() { + if (!this.world.canSave) { + // CraftBukkit start + org.bukkit.Server server = this.world.getServer(); + for (int i = 0; i < 50 && !this.unloadQueue.isEmpty(); i++) { + long chunkcoordinates = this.unloadQueue.popFirst(); + Chunk chunk = this.chunks.get(chunkcoordinates); + if (chunk == null) continue; + + ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); + server.getPluginManager().callEvent(event); + if (!event.isCancelled()) { +// this.world.getWorld().preserveChunk((CraftChunk) chunk.bukkitChunk); + + chunk.removeEntities(); + this.saveChunk(chunk); + this.saveChunkNOP(chunk); + // this.unloadQueue.remove(integer); + this.chunks.remove(chunkcoordinates); // CraftBukkit + this.chunkList.remove(chunk); + } + } + // CraftBukkit end + + if (this.e != null) { + this.e.a(); + } + } + + return this.chunkProvider.unloadChunks(); + } + + public boolean canSave() { + return !this.world.canSave; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderSky.java b/src/main/java/net/minecraft/server/ChunkProviderSky.java new file mode 100644 index 0000000..aec3bc0 --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkProviderSky.java @@ -0,0 +1,532 @@ +package net.minecraft.server; + +import java.util.Random; + +public class ChunkProviderSky implements IChunkProvider { + + private Random j; + private NoiseGeneratorOctaves k; + private NoiseGeneratorOctaves l; + private NoiseGeneratorOctaves m; + private NoiseGeneratorOctaves n; + private NoiseGeneratorOctaves o; + public NoiseGeneratorOctaves a; + public NoiseGeneratorOctaves b; + public NoiseGeneratorOctaves c; + private World p; + private double[] q; + private double[] r = new double[256]; + private double[] s = new double[256]; + private double[] t = new double[256]; + private MapGenBase u = new MapGenCaves(); + private BiomeBase[] v; + double[] d; + double[] e; + double[] f; + double[] g; + double[] h; + int[][] i = new int[32][32]; + private double[] w; + + public ChunkProviderSky(World world, long i) { + this.p = world; + this.j = new Random(i); + this.k = new NoiseGeneratorOctaves(this.j, 16); + this.l = new NoiseGeneratorOctaves(this.j, 16); + this.m = new NoiseGeneratorOctaves(this.j, 8); + this.n = new NoiseGeneratorOctaves(this.j, 4); + this.o = new NoiseGeneratorOctaves(this.j, 4); + this.a = new NoiseGeneratorOctaves(this.j, 10); + this.b = new NoiseGeneratorOctaves(this.j, 16); + this.c = new NoiseGeneratorOctaves(this.j, 8); + } + + public void a(int i, int j, byte[] abyte, BiomeBase[] abiomebase, double[] adouble) { + byte b0 = 2; + int k = b0 + 1; + byte b1 = 33; + int l = b0 + 1; + + this.q = this.a(this.q, i * b0, 0, j * b0, k, b1, l); + + for (int i1 = 0; i1 < b0; ++i1) { + for (int j1 = 0; j1 < b0; ++j1) { + for (int k1 = 0; k1 < 32; ++k1) { + double d0 = 0.25D; + double d1 = this.q[((i1 + 0) * l + j1 + 0) * b1 + k1 + 0]; + double d2 = this.q[((i1 + 0) * l + j1 + 1) * b1 + k1 + 0]; + double d3 = this.q[((i1 + 1) * l + j1 + 0) * b1 + k1 + 0]; + double d4 = this.q[((i1 + 1) * l + j1 + 1) * b1 + k1 + 0]; + double d5 = (this.q[((i1 + 0) * l + j1 + 0) * b1 + k1 + 1] - d1) * d0; + double d6 = (this.q[((i1 + 0) * l + j1 + 1) * b1 + k1 + 1] - d2) * d0; + double d7 = (this.q[((i1 + 1) * l + j1 + 0) * b1 + k1 + 1] - d3) * d0; + double d8 = (this.q[((i1 + 1) * l + j1 + 1) * b1 + k1 + 1] - d4) * d0; + + for (int l1 = 0; l1 < 4; ++l1) { + double d9 = 0.125D; + double d10 = d1; + double d11 = d2; + double d12 = (d3 - d1) * d9; + double d13 = (d4 - d2) * d9; + + for (int i2 = 0; i2 < 8; ++i2) { + int j2 = i2 + i1 * 8 << 11 | 0 + j1 * 8 << 7 | k1 * 4 + l1; + short short1 = 128; + double d14 = 0.125D; + double d15 = d10; + double d16 = (d11 - d10) * d14; + + for (int k2 = 0; k2 < 8; ++k2) { + int l2 = 0; + + if (d15 > 0.0D) { + l2 = Block.STONE.id; + } + + abyte[j2] = (byte) l2; + j2 += short1; + d15 += d16; + } + + d10 += d12; + d11 += d13; + } + + d1 += d5; + d2 += d6; + d3 += d7; + d4 += d8; + } + } + } + } + } + + public void a(int i, int j, byte[] abyte, BiomeBase[] abiomebase) { + double d0 = 0.03125D; + + this.r = this.n.a(this.r, (double) (i * 16), (double) (j * 16), 0.0D, 16, 16, 1, d0, d0, 1.0D); + this.s = this.n.a(this.s, (double) (i * 16), 109.0134D, (double) (j * 16), 16, 1, 16, d0, 1.0D, d0); + this.t = this.o.a(this.t, (double) (i * 16), (double) (j * 16), 0.0D, 16, 16, 1, d0 * 2.0D, d0 * 2.0D, d0 * 2.0D); + + for (int k = 0; k < 16; ++k) { + for (int l = 0; l < 16; ++l) { + BiomeBase biomebase = abiomebase[k + l * 16]; + int i1 = (int) (this.t[k + l * 16] / 3.0D + 3.0D + this.j.nextDouble() * 0.25D); + int j1 = -1; + byte b0 = biomebase.p; + byte b1 = biomebase.q; + + for (int k1 = 127; k1 >= 0; --k1) { + int l1 = (l * 16 + k) * 128 + k1; + byte b2 = abyte[l1]; + + if (b2 == 0) { + j1 = -1; + } else if (b2 == Block.STONE.id) { + if (j1 == -1) { + if (i1 <= 0) { + b0 = 0; + b1 = (byte) Block.STONE.id; + } + + j1 = i1; + if (k1 >= 0) { + abyte[l1] = b0; + } else { + abyte[l1] = b1; + } + } else if (j1 > 0) { + --j1; + abyte[l1] = b1; + if (j1 == 0 && b1 == Block.SAND.id) { + j1 = this.j.nextInt(4); + b1 = (byte) Block.SANDSTONE.id; + } + } + } + } + } + } + } + + public Chunk getChunkAt(int i, int j) { + return this.getOrCreateChunk(i, j); + } + + public Chunk getOrCreateChunk(int i, int j) { + this.j.setSeed((long) i * 341873128712L + (long) j * 132897987541L); + byte[] abyte = new byte['\u8000']; + Chunk chunk = new Chunk(this.p, abyte, i, j); + + this.v = this.p.getWorldChunkManager().a(this.v, i * 16, j * 16, 16, 16); + double[] adouble = this.p.getWorldChunkManager().temperature; + + this.a(i, j, abyte, this.v, adouble); + this.a(i, j, abyte, this.v); + this.u.a(this, this.p, i, j, abyte); + chunk.initLighting(); + return chunk; + } + + private double[] a(double[] adouble, int i, int j, int k, int l, int i1, int j1) { + if (adouble == null) { + adouble = new double[l * i1 * j1]; + } + + double d0 = 684.412D; + double d1 = 684.412D; + double[] adouble1 = this.p.getWorldChunkManager().temperature; + double[] adouble2 = this.p.getWorldChunkManager().rain; + + this.g = this.a.a(this.g, i, k, l, j1, 1.121D, 1.121D, 0.5D); + this.h = this.b.a(this.h, i, k, l, j1, 200.0D, 200.0D, 0.5D); + d0 *= 2.0D; + this.d = this.m.a(this.d, (double) i, (double) j, (double) k, l, i1, j1, d0 / 80.0D, d1 / 160.0D, d0 / 80.0D); + this.e = this.k.a(this.e, (double) i, (double) j, (double) k, l, i1, j1, d0, d1, d0); + this.f = this.l.a(this.f, (double) i, (double) j, (double) k, l, i1, j1, d0, d1, d0); + int k1 = 0; + int l1 = 0; + int i2 = 16 / l; + + for (int j2 = 0; j2 < l; ++j2) { + int k2 = j2 * i2 + i2 / 2; + + for (int l2 = 0; l2 < j1; ++l2) { + int i3 = l2 * i2 + i2 / 2; + double d2 = adouble1[k2 * 16 + i3]; + double d3 = adouble2[k2 * 16 + i3] * d2; + double d4 = 1.0D - d3; + + d4 *= d4; + d4 *= d4; + d4 = 1.0D - d4; + double d5 = (this.g[l1] + 256.0D) / 512.0D; + + d5 *= d4; + if (d5 > 1.0D) { + d5 = 1.0D; + } + + double d6 = this.h[l1] / 8000.0D; + + if (d6 < 0.0D) { + d6 = -d6 * 0.3D; + } + + d6 = d6 * 3.0D - 2.0D; + if (d6 > 1.0D) { + d6 = 1.0D; + } + + d6 /= 8.0D; + d6 = 0.0D; + if (d5 < 0.0D) { + d5 = 0.0D; + } + + d5 += 0.5D; + d6 = d6 * (double) i1 / 16.0D; + ++l1; + double d7 = (double) i1 / 2.0D; + + for (int j3 = 0; j3 < i1; ++j3) { + double d8 = 0.0D; + double d9 = ((double) j3 - d7) * 8.0D / d5; + + if (d9 < 0.0D) { + d9 *= -1.0D; + } + + double d10 = this.e[k1] / 512.0D; + double d11 = this.f[k1] / 512.0D; + double d12 = (this.d[k1] / 10.0D + 1.0D) / 2.0D; + + if (d12 < 0.0D) { + d8 = d10; + } else if (d12 > 1.0D) { + d8 = d11; + } else { + d8 = d10 + (d11 - d10) * d12; + } + + d8 -= 8.0D; + byte b0 = 32; + double d13; + + if (j3 > i1 - b0) { + d13 = (double) ((float) (j3 - (i1 - b0)) / ((float) b0 - 1.0F)); + d8 = d8 * (1.0D - d13) + -30.0D * d13; + } + + b0 = 8; + if (j3 < b0) { + d13 = (double) ((float) (b0 - j3) / ((float) b0 - 1.0F)); + d8 = d8 * (1.0D - d13) + -30.0D * d13; + } + + adouble[k1] = d8; + ++k1; + } + } + } + + return adouble; + } + + public boolean isChunkLoaded(int i, int j) { + return true; + } + + public void getChunkAt(IChunkProvider ichunkprovider, int i, int j) { + BlockSand.instaFall = true; + int k = i * 16; + int l = j * 16; + BiomeBase biomebase = this.p.getWorldChunkManager().getBiome(k + 16, l + 16); + + this.j.setSeed(this.p.getSeed()); + long i1 = this.j.nextLong() / 2L * 2L + 1L; + long j1 = this.j.nextLong() / 2L * 2L + 1L; + + this.j.setSeed((long) i * i1 + (long) j * j1 ^ this.p.getSeed()); + double d0 = 0.25D; + int k1; + int l1; + int i2; + + if (this.j.nextInt(4) == 0) { + k1 = k + this.j.nextInt(16) + 8; + l1 = this.j.nextInt(128); + i2 = l + this.j.nextInt(16) + 8; + (new WorldGenLakes(Block.STATIONARY_WATER.id)).a(this.p, this.j, k1, l1, i2); + } + + if (this.j.nextInt(8) == 0) { + k1 = k + this.j.nextInt(16) + 8; + l1 = this.j.nextInt(this.j.nextInt(120) + 8); + i2 = l + this.j.nextInt(16) + 8; + if (l1 < 64 || this.j.nextInt(10) == 0) { + (new WorldGenLakes(Block.STATIONARY_LAVA.id)).a(this.p, this.j, k1, l1, i2); + } + } + + int j2; + + for (k1 = 0; k1 < 8; ++k1) { + l1 = k + this.j.nextInt(16) + 8; + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16) + 8; + (new WorldGenDungeons()).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 10; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenClay(32)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 20; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.DIRT.id, 32)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 10; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.GRAVEL.id, 32)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 20; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(128); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.COAL_ORE.id, 16)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 20; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(64); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.IRON_ORE.id, 8)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 2; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(32); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.GOLD_ORE.id, 8)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 8; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(16); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.REDSTONE_ORE.id, 7)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 1; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(16); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.DIAMOND_ORE.id, 7)).a(this.p, this.j, l1, i2, j2); + } + + for (k1 = 0; k1 < 1; ++k1) { + l1 = k + this.j.nextInt(16); + i2 = this.j.nextInt(16) + this.j.nextInt(16); + j2 = l + this.j.nextInt(16); + (new WorldGenMinable(Block.LAPIS_ORE.id, 6)).a(this.p, this.j, l1, i2, j2); + } + + d0 = 0.5D; + k1 = (int) ((this.c.a((double) k * d0, (double) l * d0) / 8.0D + this.j.nextDouble() * 4.0D + 4.0D) / 3.0D); + l1 = 0; + if (this.j.nextInt(10) == 0) { + ++l1; + } + + if (biomebase == BiomeBase.FOREST) { + l1 += k1 + 5; + } + + if (biomebase == BiomeBase.RAINFOREST) { + l1 += k1 + 5; + } + + if (biomebase == BiomeBase.SEASONAL_FOREST) { + l1 += k1 + 2; + } + + if (biomebase == BiomeBase.TAIGA) { + l1 += k1 + 5; + } + + if (biomebase == BiomeBase.DESERT) { + l1 -= 20; + } + + if (biomebase == BiomeBase.TUNDRA) { + l1 -= 20; + } + + if (biomebase == BiomeBase.PLAINS) { + l1 -= 20; + } + + int k2; + + for (i2 = 0; i2 < l1; ++i2) { + j2 = k + this.j.nextInt(16) + 8; + k2 = l + this.j.nextInt(16) + 8; + WorldGenerator worldgenerator = biomebase.a(this.j); + + worldgenerator.a(1.0D, 1.0D, 1.0D); + worldgenerator.a(this.p, this.j, j2, this.p.getHighestBlockYAt(j2, k2), k2); + } + + int l2; + + for (i2 = 0; i2 < 2; ++i2) { + j2 = k + this.j.nextInt(16) + 8; + k2 = this.j.nextInt(128); + l2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.YELLOW_FLOWER.id)).a(this.p, this.j, j2, k2, l2); + } + + if (this.j.nextInt(2) == 0) { + i2 = k + this.j.nextInt(16) + 8; + j2 = this.j.nextInt(128); + k2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.RED_ROSE.id)).a(this.p, this.j, i2, j2, k2); + } + + if (this.j.nextInt(4) == 0) { + i2 = k + this.j.nextInt(16) + 8; + j2 = this.j.nextInt(128); + k2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.BROWN_MUSHROOM.id)).a(this.p, this.j, i2, j2, k2); + } + + if (this.j.nextInt(8) == 0) { + i2 = k + this.j.nextInt(16) + 8; + j2 = this.j.nextInt(128); + k2 = l + this.j.nextInt(16) + 8; + (new WorldGenFlowers(Block.RED_MUSHROOM.id)).a(this.p, this.j, i2, j2, k2); + } + + for (i2 = 0; i2 < 10; ++i2) { + j2 = k + this.j.nextInt(16) + 8; + k2 = this.j.nextInt(128); + l2 = l + this.j.nextInt(16) + 8; + (new WorldGenReed()).a(this.p, this.j, j2, k2, l2); + } + + if (this.j.nextInt(32) == 0) { + i2 = k + this.j.nextInt(16) + 8; + j2 = this.j.nextInt(128); + k2 = l + this.j.nextInt(16) + 8; + (new WorldGenPumpkin()).a(this.p, this.j, i2, j2, k2); + } + + i2 = 0; + if (biomebase == BiomeBase.DESERT) { + i2 += 10; + } + + int i3; + + for (j2 = 0; j2 < i2; ++j2) { + k2 = k + this.j.nextInt(16) + 8; + l2 = this.j.nextInt(128); + i3 = l + this.j.nextInt(16) + 8; + (new WorldGenCactus()).a(this.p, this.j, k2, l2, i3); + } + + for (j2 = 0; j2 < 50; ++j2) { + k2 = k + this.j.nextInt(16) + 8; + l2 = this.j.nextInt(this.j.nextInt(120) + 8); + i3 = l + this.j.nextInt(16) + 8; + (new WorldGenLiquids(Block.WATER.id)).a(this.p, this.j, k2, l2, i3); + } + + for (j2 = 0; j2 < 20; ++j2) { + k2 = k + this.j.nextInt(16) + 8; + l2 = this.j.nextInt(this.j.nextInt(this.j.nextInt(112) + 8) + 8); + i3 = l + this.j.nextInt(16) + 8; + (new WorldGenLiquids(Block.LAVA.id)).a(this.p, this.j, k2, l2, i3); + } + + this.w = this.p.getWorldChunkManager().a(this.w, k + 8, l + 8, 16, 16); + + for (j2 = k + 8; j2 < k + 8 + 16; ++j2) { + for (k2 = l + 8; k2 < l + 8 + 16; ++k2) { + l2 = j2 - (k + 8); + i3 = k2 - (l + 8); + int j3 = this.p.e(j2, k2); + double d1 = this.w[l2 * 16 + i3] - (double) (j3 - 64) / 64.0D * 0.3D; + + if (d1 < 0.5D && j3 > 0 && j3 < 128 && this.p.isEmpty(j2, j3, k2) && this.p.getMaterial(j2, j3 - 1, k2).isSolid() && this.p.getMaterial(j2, j3 - 1, k2) != Material.ICE) { + this.p.setTypeId(j2, j3, k2, Block.SNOW.id); + } + } + } + + BlockSand.instaFall = false; + } + + public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) { + return true; + } + + public boolean unloadChunks() { + return false; + } + + public boolean canSave() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java new file mode 100644 index 0000000..086e33d --- /dev/null +++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java @@ -0,0 +1,68 @@ +package net.minecraft.server; + +import java.io.*; + +public class ChunkRegionLoader implements IChunkLoader { + + private final File a; + + public ChunkRegionLoader(File file1) { + this.a = file1; + } + + public Chunk a(World world, int i, int j) throws IOException { + DataInputStream datainputstream = RegionFileCache.c(this.a, i, j); + + if (datainputstream != null) { + NBTTagCompound nbttagcompound = CompressedStreamTools.a((DataInput) datainputstream); + + if (!nbttagcompound.hasKey("Level")) { + System.out.println("Chunk file at " + i + "," + j + " is missing level data, skipping"); + return null; + } else if (!nbttagcompound.k("Level").hasKey("Blocks")) { + System.out.println("Chunk file at " + i + "," + j + " is missing block data, skipping"); + return null; + } else { + Chunk chunk = ChunkLoader.a(world, nbttagcompound.k("Level")); + + if (!chunk.a(i, j)) { + System.out.println("Chunk file at " + i + "," + j + " is in the wrong location; relocating. (Expected " + i + ", " + j + ", got " + chunk.x + ", " + chunk.z + ")"); + nbttagcompound.a("xPos", i); + nbttagcompound.a("zPos", j); + chunk = ChunkLoader.a(world, nbttagcompound.k("Level")); + } + + chunk.h(); + return chunk; + } + } else { + return null; + } + } + + public void a(World world, Chunk chunk) { + world.k(); + + try { + DataOutputStream dataoutputstream = RegionFileCache.d(this.a, chunk.x, chunk.z); + NBTTagCompound nbttagcompound = new NBTTagCompound(); + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound.a("Level", (NBTBase) nbttagcompound1); + ChunkLoader.a(chunk, world, nbttagcompound1); + CompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream); + dataoutputstream.close(); + WorldData worlddata = world.q(); + + worlddata.b(worlddata.g() + (long) RegionFileCache.b(this.a, chunk.x, chunk.z)); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public void b(World world, Chunk chunk) {} + + public void a() {} + + public void b() {} +} diff --git a/src/main/java/net/minecraft/server/CompressedStreamTools.java b/src/main/java/net/minecraft/server/CompressedStreamTools.java new file mode 100644 index 0000000..2dd70d8 --- /dev/null +++ b/src/main/java/net/minecraft/server/CompressedStreamTools.java @@ -0,0 +1,48 @@ +package net.minecraft.server; + +import java.io.*; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +public class CompressedStreamTools { + + public CompressedStreamTools() {} + + public static NBTTagCompound a(InputStream inputstream) throws IOException { + DataInputStream datainputstream = new DataInputStream(new GZIPInputStream(inputstream)); + + NBTTagCompound nbttagcompound; + + try { + nbttagcompound = a((DataInput) datainputstream); + } finally { + datainputstream.close(); + } + + return nbttagcompound; + } + + public static void a(NBTTagCompound nbttagcompound, OutputStream outputstream) throws IOException { + DataOutputStream dataoutputstream = new DataOutputStream(new GZIPOutputStream(outputstream)); + + try { + a(nbttagcompound, (DataOutput) dataoutputstream); + } finally { + dataoutputstream.close(); + } + } + + public static NBTTagCompound a(DataInput datainput) throws IOException { + NBTBase nbtbase = NBTBase.b(datainput); + + if (nbtbase instanceof NBTTagCompound) { + return (NBTTagCompound) nbtbase; + } else { + throw new IOException("Root tag must be a named compound tag"); + } + } + + public static void a(NBTTagCompound nbttagcompound, DataOutput dataoutput) throws IOException { + NBTBase.a(nbttagcompound, dataoutput); + } +} diff --git a/src/main/java/net/minecraft/server/ConsoleCommandHandler.java b/src/main/java/net/minecraft/server/ConsoleCommandHandler.java new file mode 100644 index 0000000..e5b735b --- /dev/null +++ b/src/main/java/net/minecraft/server/ConsoleCommandHandler.java @@ -0,0 +1,418 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.command.ServerCommandListener; +import org.bukkit.craftbukkit.entity.CraftPlayer; + +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Logger; + +// CraftBukkit start +// CraftBukkit end + +public class ConsoleCommandHandler { + + private static Logger a = Logger.getLogger("Minecraft"); + private MinecraftServer server; + private ICommandListener listener; // CraftBukkit + + public ConsoleCommandHandler(MinecraftServer minecraftserver) { + this.server = minecraftserver; + } + + // Craftbukkit start + private boolean hasPermission(ICommandListener listener, String perm) { + if (listener instanceof ServerCommandListener) { + ServerCommandListener serv = (ServerCommandListener)listener; + return serv.getSender().hasPermission(perm); + } else if (listener instanceof NetServerHandler) { + NetServerHandler net = (NetServerHandler)listener; + return net.getPlayer().hasPermission(perm); + } else if ((listener instanceof ServerGUI) || (listener instanceof MinecraftServer)) { + return server.console.hasPermission(perm); + } + + return false; + } + + private boolean checkPermission(ICommandListener listener, String command) { + if (hasPermission(listener, "bukkit.command." + command)) { + return true; + } else { + listener.sendMessage("I'm sorry, Dave, but I cannot let you do that."); + return false; + } + } + // Craftbukkit end + + public boolean handle(ServerCommand servercommand) { // CraftBukkit - returns boolean + String s = servercommand.command; + ICommandListener icommandlistener = servercommand.b; + String s1 = icommandlistener.getName(); + this.listener = icommandlistener; // CraftBukkit + ServerConfigurationManager serverconfigurationmanager = this.server.serverConfigurationManager; + + if (!s.toLowerCase().startsWith("help") && !s.toLowerCase().startsWith("?")) { + if (s.toLowerCase().startsWith("list")) { + if (!checkPermission(listener, "list")) return true; // Craftbukkit + icommandlistener.sendMessage("Connected players: " + serverconfigurationmanager.c()); + } else if (s.toLowerCase().startsWith("stop")) { + if (!checkPermission(listener, "stop")) return true; // Craftbukkit + this.print(s1, "Stopping the server.."); + this.server.a(); + } else { + int i; + WorldServer worldserver; + + if (s.toLowerCase().startsWith("save-all")) { + if (!checkPermission(listener, "save.perform")) return true; // Craftbukkit + this.print(s1, "Forcing save.."); + if (serverconfigurationmanager != null) { + serverconfigurationmanager.savePlayers(); + } + + // CraftBukkit start + for (i = 0; i < this.server.worlds.size(); ++i) { + worldserver = this.server.worlds.get(i); + boolean save = worldserver.canSave; + worldserver.canSave = false; + worldserver.save(true, (IProgressUpdate) null); + worldserver.canSave = save; + } + // CraftBukkit end + + this.print(s1, "Save complete."); + } else if (s.toLowerCase().startsWith("save-off")) { + if (!checkPermission(listener, "save.disable")) return true; // Craftbukkit + this.print(s1, "Disabling level saving.."); + + for (i = 0; i < this.server.worlds.size(); ++i) { // CraftBukkit + worldserver = this.server.worlds.get(i); // CraftBukkit + worldserver.canSave = true; + } + } else if (s.toLowerCase().startsWith("save-on")) { + if (!checkPermission(listener, "save.enable")) return true; // Craftbukkit + this.print(s1, "Enabling level saving.."); + + for (i = 0; i < this.server.worlds.size(); ++i) { // CraftBukkit + worldserver = this.server.worlds.get(i); // CraftBukkit + worldserver.canSave = false; + } + } else { + String s2; + + if (s.toLowerCase().startsWith("op ")) { + if (!checkPermission(listener, "op.give")) return true; // Craftbukkit + s2 = s.substring(s.indexOf(" ")).trim(); + serverconfigurationmanager.e(s2); + this.print(s1, "Opping " + s2); + serverconfigurationmanager.a(s2, "\u00A7eYou are now op!"); + } else if (s.toLowerCase().startsWith("deop ")) { + if (!checkPermission(listener, "op.take")) return true; // Craftbukkit + s2 = s.substring(s.indexOf(" ")).trim(); + serverconfigurationmanager.f(s2); + serverconfigurationmanager.a(s2, "\u00A7eYou are no longer op!"); + this.print(s1, "De-opping " + s2); + } else if (s.toLowerCase().startsWith("ban-ip ")) { + if (!checkPermission(listener, "ban.ip")) return true; // Craftbukkit + s2 = s.substring(s.indexOf(" ")).trim(); + serverconfigurationmanager.c(s2); + this.print(s1, "Banning ip " + s2); + } else if (s.toLowerCase().startsWith("pardon-ip ")) { + if (!checkPermission(listener, "unban.ip")) return true; // Craftbukkit + s2 = s.substring(s.indexOf(" ")).trim(); + serverconfigurationmanager.d(s2); + this.print(s1, "Pardoning ip " + s2); + } else { + EntityPlayer entityplayer; + + if (s.toLowerCase().startsWith("ban ")) { + if (!checkPermission(listener, "ban.player")) return true; // Craftbukkit + s2 = s.substring(s.indexOf(" ")).trim(); + serverconfigurationmanager.a(s2); + this.print(s1, "Banning " + s2); + entityplayer = serverconfigurationmanager.i(s2); + if (entityplayer != null) { + entityplayer.netServerHandler.disconnect("Banned by admin"); + } + } else if (s.toLowerCase().startsWith("pardon ")) { + if (!checkPermission(listener, "unban.player")) return true; // Craftbukkit + s2 = s.substring(s.indexOf(" ")).trim(); + serverconfigurationmanager.b(s2); + this.print(s1, "Pardoning " + s2); + } else { + int j; + + if (s.toLowerCase().startsWith("kick ")) { + if (!checkPermission(listener, "kick")) return true; // Craftbukkit + // CraftBukkit start - Add kick message compatibility + String[] parts = s.split(" "); + s2 = parts.length >= 2 ? parts[1] : ""; + // CraftBukkit end + entityplayer = null; + + for (j = 0; j < serverconfigurationmanager.players.size(); ++j) { + EntityPlayer entityplayer1 = (EntityPlayer) serverconfigurationmanager.players.get(j); + + if (entityplayer1.name.equalsIgnoreCase(s2)) { + entityplayer = entityplayer1; + } + } + + if (entityplayer != null) { + entityplayer.netServerHandler.disconnect("Kicked by admin"); + this.print(s1, "Kicking " + entityplayer.name); + } else { + icommandlistener.sendMessage("Can\'t find user " + s2 + ". No kick."); + } + } else { + EntityPlayer entityplayer2; + String[] astring; + + if (s.toLowerCase().startsWith("tp ")) { + if (!checkPermission(listener, "teleport")) return true; // Craftbukkit + astring = s.split(" "); + if (astring.length == 3) { + entityplayer = serverconfigurationmanager.i(astring[1]); + entityplayer2 = serverconfigurationmanager.i(astring[2]); + if (entityplayer == null) { + icommandlistener.sendMessage("Can\'t find user " + astring[1] + ". No tp."); + } else if (entityplayer2 == null) { + icommandlistener.sendMessage("Can\'t find user " + astring[2] + ". No tp."); + } else if (entityplayer.dimension != entityplayer2.dimension) { + icommandlistener.sendMessage("User " + astring[1] + " and " + astring[2] + " are in different dimensions. No tp."); + } else { + entityplayer.netServerHandler.a(entityplayer2.locX, entityplayer2.locY, entityplayer2.locZ, entityplayer2.yaw, entityplayer2.pitch); + this.print(s1, "Teleporting " + astring[1] + " to " + astring[2] + "."); + } + } else { + icommandlistener.sendMessage("Syntax error, please provice a source and a target."); + } + } else { + String s3; + int k; + + if (s.toLowerCase().startsWith("give ")) { + if (!checkPermission(listener, "give")) return true; // Craftbukkit + astring = s.split(" "); + if (astring.length != 3 && astring.length != 4) { + return true; // CraftBukkit + } + + s3 = astring[1]; + entityplayer2 = serverconfigurationmanager.i(s3); + if (entityplayer2 != null) { + try { + k = Integer.parseInt(astring[2]); + if (Item.byId[k] != null) { + this.print(s1, "Giving " + entityplayer2.name + " some " + k); + int l = 1; + + if (astring.length > 3) { + l = this.a(astring[3], 1); + } + + if (l < 1) { + l = 1; + } + + if (l > 64) { + l = 64; + } + + entityplayer2.b(new ItemStack(k, l, 0)); + } else { + icommandlistener.sendMessage("There\'s no item with id " + k); + } + } catch (NumberFormatException numberformatexception) { + icommandlistener.sendMessage("There\'s no item with id " + astring[2]); + } + } else { + icommandlistener.sendMessage("Can\'t find user " + s3); + } + } else if (s.toLowerCase().startsWith("time ")) { + astring = s.split(" "); + if (astring.length != 3) { + return true; // CraftBukkit + } + + s3 = astring[1]; + + try { + j = Integer.parseInt(astring[2]); + WorldServer worldserver1; + + if ("add".equalsIgnoreCase(s3)) { + if (!checkPermission(listener, "time.add")) return true; // Craftbukkit + for (k = 0; k < this.server.worlds.size(); ++k) { // CraftBukkit + worldserver1 = this.server.worlds.get(k); // CraftBukkit + worldserver1.setTimeAndFixTicklists(worldserver1.getTime() + (long) j); + } + + this.print(s1, "Added " + j + " to time"); + } else if ("set".equalsIgnoreCase(s3)) { + if (!checkPermission(listener, "time.set")) return true; // Craftbukkit + for (k = 0; k < this.server.worlds.size(); ++k) { // CraftBukkit + worldserver1 = this.server.worlds.get(k); // CraftBukkit + worldserver1.setTimeAndFixTicklists((long) j); + } + + this.print(s1, "Set time to " + j); + } else { + icommandlistener.sendMessage("Unknown method, use either \"add\" or \"set\""); + } + } catch (NumberFormatException numberformatexception1) { + icommandlistener.sendMessage("Unable to convert time value, " + astring[2]); + } + } else if (s.toLowerCase().startsWith("say ")) { + if (!checkPermission(listener, "say")) return true; // Craftbukkit + s = s.substring(s.indexOf(" ")).trim(); + a.info("[" + s1 + "] " + s); + serverconfigurationmanager.sendAll(new Packet3Chat("\u00A7d[Server] " + s)); + } else if (s.toLowerCase().startsWith("tell ")) { + if (!checkPermission(listener, "tell")) return true; // Craftbukkit + astring = s.split(" "); + if (astring.length >= 3) { + s = s.substring(s.indexOf(" ")).trim(); + s = s.substring(s.indexOf(" ")).trim(); + a.info("[" + s1 + "->" + astring[1] + "] " + s); + s = "\u00A77" + s1 + " whispers " + s; + a.info(s); + if (!serverconfigurationmanager.a(astring[1], (Packet) (new Packet3Chat(s)))) { + icommandlistener.sendMessage("There\'s no player by that name online."); + } + } + } else if (s.toLowerCase().startsWith("whitelist ")) { + this.a(s1, s, icommandlistener); + } else { + icommandlistener.sendMessage("Unknown console command. Type \"help\" for help."); // CraftBukkit + return false; // CraftBukkit + } + } + } + } + } + } + } + } else { + if (!checkPermission(listener, "help")) return true; // Craftbukkit + this.a(icommandlistener); + } + + return true; // CraftBukkit + } + + private void a(String s, String s1, ICommandListener icommandlistener) { + String[] astring = s1.split(" "); + this.listener = icommandlistener; // CraftBukkit + + if (astring.length >= 2) { + String s2 = astring[1].toLowerCase(); + + if ("on".equals(s2)) { + if (!checkPermission(listener, "whitelist.enable")) return; // Craftbukkit + this.print(s, "Turned on white-listing"); + this.server.propertyManager.b("white-list", true); + } else if ("off".equals(s2)) { + if (!checkPermission(listener, "whitelist.disable")) return; // Craftbukkit + this.print(s, "Turned off white-listing"); + this.server.propertyManager.b("white-list", false); + } else if ("list".equals(s2)) { + if (!checkPermission(listener, "whitelist.list")) return; // Craftbukkit + Set set = this.server.serverConfigurationManager.e(); + String s3 = ""; + + String s4; + + for (Iterator iterator = set.iterator(); iterator.hasNext(); s3 = s3 + s4 + " ") { + s4 = (String) iterator.next(); + } + + icommandlistener.sendMessage("White-listed players: " + s3); + } else { + String s5; + + if ("add".equals(s2) && astring.length == 3) { + if (!checkPermission(listener, "whitelist.add")) return; // Craftbukkit + s5 = astring[2].toLowerCase(); + this.server.serverConfigurationManager.k(s5); + this.print(s, "Added " + s5 + " to white-list"); + } else if ("remove".equals(s2) && astring.length == 3) { + if (!checkPermission(listener, "whitelist.remove")) return; // Craftbukkit + s5 = astring[2].toLowerCase(); + this.server.serverConfigurationManager.l(s5); + this.print(s, "Removed " + s5 + " from white-list"); + } else if ("reload".equals(s2)) { + if (!checkPermission(listener, "whitelist.reload")) return; // Craftbukkit + this.server.serverConfigurationManager.f(); + this.print(s, "Reloaded white-list from file"); + } + } + } + } + + private void a(ICommandListener icommandlistener) { + icommandlistener.sendMessage("To run the server without a gui, start it like this:"); + icommandlistener.sendMessage(" java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui"); + icommandlistener.sendMessage("Console commands:"); + icommandlistener.sendMessage(" help or ? shows this message"); + icommandlistener.sendMessage(" kick removes a player from the server"); + icommandlistener.sendMessage(" ban bans a player from the server"); + icommandlistener.sendMessage(" pardon pardons a banned player so that they can connect again"); + icommandlistener.sendMessage(" ban-ip bans an IP address from the server"); + icommandlistener.sendMessage(" pardon-ip pardons a banned IP address so that they can connect again"); + icommandlistener.sendMessage(" op turns a player into an op"); + icommandlistener.sendMessage(" deop removes op status from a player"); + icommandlistener.sendMessage(" tp moves one player to the same location as another player"); + icommandlistener.sendMessage(" give [num] gives a player a resource"); + icommandlistener.sendMessage(" tell sends a private message to a player"); + icommandlistener.sendMessage(" stop gracefully stops the server"); + icommandlistener.sendMessage(" save-all forces a server-wide level save"); + icommandlistener.sendMessage(" save-off disables terrain saving (useful for backup scripts)"); + icommandlistener.sendMessage(" save-on re-enables terrain saving"); + icommandlistener.sendMessage(" list lists all currently connected players"); + icommandlistener.sendMessage(" say broadcasts a message to all players"); + icommandlistener.sendMessage(" time adds to or sets the world time (0-24000)"); + } + + private void print(String s, String s1) { + String s2 = s + ": " + s1; + + // CraftBukkit start + this.listener.sendMessage(s1); + this.informOps("\u00A77(" + s2 + ")"); + if (this.listener instanceof MinecraftServer) { + return; // Already logged so don't call a.info() + } + // CraftBukkit end + a.info(s2); + } + + // CraftBukkit start + private void informOps(String msg) { + Packet3Chat packet3chat = new Packet3Chat(msg); + EntityPlayer sender = null; + if (this.listener instanceof ServerCommandListener) { + org.bukkit.command.CommandSender commandSender = ((ServerCommandListener) this.listener).getSender(); + if (commandSender instanceof CraftPlayer) { + sender = ((CraftPlayer) commandSender).getHandle(); + } + } + java.util.List players = this.server.serverConfigurationManager.players; + for (int i = 0; i < players.size(); ++i) { + EntityPlayer entityPlayer = (EntityPlayer) players.get(i); + if (sender != entityPlayer && this.server.serverConfigurationManager.isOp(entityPlayer.name)) { + entityPlayer.netServerHandler.sendPacket(packet3chat); + } + } + } + // CraftBukkit end + + private int a(String s, int i) { + try { + return Integer.parseInt(s); + } catch (NumberFormatException numberformatexception) { + return i; + } + } +} diff --git a/src/main/java/net/minecraft/server/ConsoleLogFormatter.java b/src/main/java/net/minecraft/server/ConsoleLogFormatter.java new file mode 100644 index 0000000..e2f8793 --- /dev/null +++ b/src/main/java/net/minecraft/server/ConsoleLogFormatter.java @@ -0,0 +1,51 @@ +package net.minecraft.server; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.SimpleDateFormat; +import java.util.logging.Formatter; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +final class ConsoleLogFormatter extends Formatter { + + private SimpleDateFormat a = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + ConsoleLogFormatter() {} + + public String format(LogRecord logrecord) { + StringBuilder stringbuilder = new StringBuilder(); + + stringbuilder.append(this.a.format(Long.valueOf(logrecord.getMillis()))); + Level level = logrecord.getLevel(); + + if (level == Level.FINEST) { + stringbuilder.append(" [FINEST] "); + } else if (level == Level.FINER) { + stringbuilder.append(" [FINER] "); + } else if (level == Level.FINE) { + stringbuilder.append(" [FINE] "); + } else if (level == Level.INFO) { + stringbuilder.append(" [INFO] "); + } else if (level == Level.WARNING) { + stringbuilder.append(" [WARNING] "); + } else if (level == Level.SEVERE) { + stringbuilder.append(" [SEVERE] "); + } else if (level == Level.SEVERE) { + stringbuilder.append(" [" + level.getLocalizedName() + "] "); + } + + stringbuilder.append(logrecord.getMessage()); + stringbuilder.append('\n'); + Throwable throwable = logrecord.getThrown(); + + if (throwable != null) { + StringWriter stringwriter = new StringWriter(); + + throwable.printStackTrace(new PrintWriter(stringwriter)); + stringbuilder.append(stringwriter.toString()); + } + + return stringbuilder.toString(); + } +} diff --git a/src/main/java/net/minecraft/server/ConsoleLogManager.java b/src/main/java/net/minecraft/server/ConsoleLogManager.java new file mode 100644 index 0000000..3129a74 --- /dev/null +++ b/src/main/java/net/minecraft/server/ConsoleLogManager.java @@ -0,0 +1,79 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.craftbukkit.util.ShortConsoleLogFormatter; +import org.bukkit.craftbukkit.util.TerminalConsoleHandler; + +import java.io.File; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.logging.*; + +// CraftBukkit start +// CraftBukkit end + +public class ConsoleLogManager { + + public static Logger a = Logger.getLogger("Minecraft"); + public static Logger global = Logger.getLogger(""); // CraftBukkit + + public ConsoleLogManager() { + } + + // CraftBukkit - change of method signature! + public static void init(MinecraftServer server) { + ConsoleLogFormatter consolelogformatter = new ConsoleLogFormatter(); + + a.setUseParentHandlers(false); + // CraftBukkit start + ConsoleHandler consolehandler = new TerminalConsoleHandler(server.reader); + + for (Handler handler : global.getHandlers()) { + global.removeHandler(handler); + } + + consolehandler.setFormatter(new ShortConsoleLogFormatter(server)); + global.addHandler(consolehandler); + // CraftBukkit end + + a.addHandler(consolehandler); + + try { + //Project Poseidon Start + FileHandler filehandler; + if ((boolean) PoseidonConfig.getInstance().getConfigOption("settings.per-day-log-file.enabled")) { + //If latest log file is enabled, create a new log file for each day + if ((boolean) PoseidonConfig.getInstance().getConfigOption("settings.per-day-log-file.latest-log.enabled")) { + String latestLogFileName = "latest"; + File log = new File("." + File.separator + "logs" + File.separator); + log.getParentFile().mkdirs(); + log.mkdirs(); + filehandler = new FileHandler("." + File.separator + "logs" + File.separator + latestLogFileName + ".log", true); + } else { + //If latest log file is disabled, create a new log file for each day with the date as the file name + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String logfile = LocalDate.now().format(formatter); + File log = new File("." + File.separator + "logs" + File.separator); + log.getParentFile().mkdirs(); + log.mkdirs(); + filehandler = new FileHandler("." + File.separator + "logs" + File.separator + logfile + ".log", true); + } + } else { + // CraftBukkit start + String pattern = (String) server.options.valueOf("log-pattern"); + int limit = ((Integer) server.options.valueOf("log-limit")).intValue(); + int count = ((Integer) server.options.valueOf("log-count")).intValue(); + boolean append = ((Boolean) server.options.valueOf("log-append")).booleanValue(); + filehandler = new FileHandler(pattern, limit, count, append); + // CraftBukkit start + } + //Project Poseidon End + + filehandler.setFormatter(consolelogformatter); + a.addHandler(filehandler); + global.addHandler(filehandler); // CraftBukkit + } catch (Exception exception) { + a.log(Level.WARNING, "Failed to log to server.log", exception); + } + } +} diff --git a/src/main/java/net/minecraft/server/Container.java b/src/main/java/net/minecraft/server/Container.java new file mode 100644 index 0000000..bb99614 --- /dev/null +++ b/src/main/java/net/minecraft/server/Container.java @@ -0,0 +1,285 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public abstract class Container { + + public List d = new ArrayList(); + public List e = new ArrayList(); + public int windowId = 0; + private short a = 0; + protected List listeners = new ArrayList(); + private Set b = new HashSet(); + + public Container() {} + + protected void a(Slot slot) { + slot.a = this.e.size(); + this.e.add(slot); + this.d.add(null); + } + + public void a(ICrafting icrafting) { + if (this.listeners.contains(icrafting)) { + throw new IllegalArgumentException("Listener already listening"); + } else { + this.listeners.add(icrafting); + icrafting.a(this, this.b()); + this.a(); + } + } + + public List b() { + ArrayList arraylist = new ArrayList(); + + for (int i = 0; i < this.e.size(); ++i) { + arraylist.add(((Slot) this.e.get(i)).getItem()); + } + + return arraylist; + } + + public void a() { + for (int i = 0; i < this.e.size(); ++i) { + ItemStack itemstack = ((Slot) this.e.get(i)).getItem(); + ItemStack itemstack1 = (ItemStack) this.d.get(i); + + if (!ItemStack.equals(itemstack1, itemstack)) { + itemstack1 = itemstack == null ? null : itemstack.cloneItemStack(); + this.d.set(i, itemstack1); + + for (int j = 0; j < this.listeners.size(); ++j) { + ((ICrafting) this.listeners.get(j)).a(this, i, itemstack1); + } + } + } + } + + public Slot a(IInventory iinventory, int i) { + for (int j = 0; j < this.e.size(); ++j) { + Slot slot = (Slot) this.e.get(j); + + if (slot.a(iinventory, i)) { + return slot; + } + } + + return null; + } + + public Slot b(int i) { + return (Slot) this.e.get(i); + } + + public ItemStack a(int i) { + Slot slot = (Slot) this.e.get(i); + + return slot != null ? slot.getItem() : null; + } + + public ItemStack a(int i, int j, boolean flag, EntityHuman entityhuman) { + ItemStack itemstack = null; + + if (j == 0 || j == 1) { + InventoryPlayer inventoryplayer = entityhuman.inventory; + + if (i == -999) { + if (inventoryplayer.j() != null && i == -999) { + if (j == 0) { + entityhuman.b(inventoryplayer.j()); + inventoryplayer.b((ItemStack) null); + } + + if (j == 1) { + entityhuman.b(inventoryplayer.j().a(1)); + if (inventoryplayer.j().count == 0) { + inventoryplayer.b((ItemStack) null); + } + } + } + } else { + int k; + + if (flag) { + ItemStack itemstack1 = this.a(i); + + if (itemstack1 != null) { + int l = itemstack1.count; + + itemstack = itemstack1.cloneItemStack(); + Slot slot = (Slot) this.e.get(i); + + if (slot != null && slot.getItem() != null) { + k = slot.getItem().count; + if (k < l) { + this.a(i, j, flag, entityhuman); + } + } + } + } else { + Slot slot1 = (Slot) this.e.get(i); + + if (slot1 != null) { + slot1.c(); + ItemStack itemstack2 = slot1.getItem(); + ItemStack itemstack3 = inventoryplayer.j(); + + if (itemstack2 != null) { + itemstack = itemstack2.cloneItemStack(); + } + + if (itemstack2 == null) { + if (itemstack3 != null && slot1.isAllowed(itemstack3)) { + k = j == 0 ? itemstack3.count : 1; + if (k > slot1.d()) { + k = slot1.d(); + } + + slot1.c(itemstack3.a(k)); + if (itemstack3.count == 0) { + inventoryplayer.b((ItemStack) null); + } + } + } else if (itemstack3 == null) { + k = j == 0 ? itemstack2.count : (itemstack2.count + 1) / 2; + ItemStack itemstack4 = slot1.a(k); + + inventoryplayer.b(itemstack4); + if (itemstack2.count == 0) { + slot1.c((ItemStack) null); + } + + slot1.a(inventoryplayer.j()); + } else if (slot1.isAllowed(itemstack3)) { + if (itemstack2.id == itemstack3.id && (!itemstack2.usesData() || itemstack2.getData() == itemstack3.getData())) { + k = j == 0 ? itemstack3.count : 1; + if (k > slot1.d() - itemstack2.count) { + k = slot1.d() - itemstack2.count; + } + + if (k > itemstack3.getMaxStackSize() - itemstack2.count) { + k = itemstack3.getMaxStackSize() - itemstack2.count; + } + + itemstack3.a(k); + if (itemstack3.count == 0) { + inventoryplayer.b((ItemStack) null); + } + + itemstack2.count += k; + } else if (itemstack3.count <= slot1.d()) { + slot1.c(itemstack3); + inventoryplayer.b(itemstack2); + } + } else if (itemstack2.id == itemstack3.id && itemstack3.getMaxStackSize() > 1 && (!itemstack2.usesData() || itemstack2.getData() == itemstack3.getData())) { + k = itemstack2.count; + if (k > 0 && k + itemstack3.count <= itemstack3.getMaxStackSize()) { + itemstack3.count += k; + itemstack2.a(k); + if (itemstack2.count == 0) { + slot1.c((ItemStack) null); + } + + slot1.a(inventoryplayer.j()); + } + } + } + } + } + } + + return itemstack; + } + + public void a(EntityHuman entityhuman) { + InventoryPlayer inventoryplayer = entityhuman.inventory; + + if (inventoryplayer.j() != null) { + entityhuman.b(inventoryplayer.j()); + inventoryplayer.b((ItemStack) null); + } + } + + public void a(IInventory iinventory) { + this.a(); + } + + public boolean c(EntityHuman entityhuman) { + return !this.b.contains(entityhuman); + } + + public void a(EntityHuman entityhuman, boolean flag) { + if (flag) { + this.b.remove(entityhuman); + } else { + this.b.add(entityhuman); + } + } + + public abstract boolean b(EntityHuman entityhuman); + + protected void a(ItemStack itemstack, int i, int j, boolean flag) { + int k = i; + + if (flag) { + k = j - 1; + } + + Slot slot; + ItemStack itemstack1; + + if (itemstack.isStackable()) { + while (itemstack.count > 0 && (!flag && k < j || flag && k >= i)) { + slot = (Slot) this.e.get(k); + itemstack1 = slot.getItem(); + if (itemstack1 != null && itemstack1.id == itemstack.id && (!itemstack.usesData() || itemstack.getData() == itemstack1.getData())) { + int l = itemstack1.count + itemstack.count; + + if (l <= itemstack.getMaxStackSize()) { + itemstack.count = 0; + itemstack1.count = l; + slot.c(); + } else if (itemstack1.count < itemstack.getMaxStackSize()) { + itemstack.count -= itemstack.getMaxStackSize() - itemstack1.count; + itemstack1.count = itemstack.getMaxStackSize(); + slot.c(); + } + } + + if (flag) { + --k; + } else { + ++k; + } + } + } + + if (itemstack.count > 0) { + if (flag) { + k = j - 1; + } else { + k = i; + } + + while (!flag && k < j || flag && k >= i) { + slot = (Slot) this.e.get(k); + itemstack1 = slot.getItem(); + if (itemstack1 == null) { + slot.c(itemstack.cloneItemStack()); + slot.c(); + itemstack.count = 0; + break; + } + + if (flag) { + --k; + } else { + ++k; + } + } + } + } +} diff --git a/src/main/java/net/minecraft/server/ContainerChest.java b/src/main/java/net/minecraft/server/ContainerChest.java new file mode 100644 index 0000000..383cd28 --- /dev/null +++ b/src/main/java/net/minecraft/server/ContainerChest.java @@ -0,0 +1,60 @@ +package net.minecraft.server; + +public class ContainerChest extends Container { + + private IInventory a; + private int b; + + public ContainerChest(IInventory iinventory, IInventory iinventory1) { + this.a = iinventory1; + this.b = iinventory1.getSize() / 9; + int i = (this.b - 4) * 18; + + int j; + int k; + + for (j = 0; j < this.b; ++j) { + for (k = 0; k < 9; ++k) { + this.a(new Slot(iinventory1, k + j * 9, 8 + k * 18, 18 + j * 18)); + } + } + + for (j = 0; j < 3; ++j) { + for (k = 0; k < 9; ++k) { + this.a(new Slot(iinventory, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i)); + } + } + + for (j = 0; j < 9; ++j) { + this.a(new Slot(iinventory, j, 8 + j * 18, 161 + i)); + } + } + + public boolean b(EntityHuman entityhuman) { + return this.a.a_(entityhuman); + } + + public ItemStack a(int i) { + ItemStack itemstack = null; + Slot slot = (Slot) this.e.get(i); + + if (slot != null && slot.b()) { + ItemStack itemstack1 = slot.getItem(); + + itemstack = itemstack1.cloneItemStack(); + if (i < this.b * 9) { + this.a(itemstack1, this.b * 9, this.e.size(), true); + } else { + this.a(itemstack1, 0, this.b * 9, false); + } + + if (itemstack1.count == 0) { + slot.c((ItemStack) null); + } else { + slot.c(); + } + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ContainerDispenser.java b/src/main/java/net/minecraft/server/ContainerDispenser.java new file mode 100644 index 0000000..ba20219 --- /dev/null +++ b/src/main/java/net/minecraft/server/ContainerDispenser.java @@ -0,0 +1,33 @@ +package net.minecraft.server; + +public class ContainerDispenser extends Container { + + private TileEntityDispenser a; + + public ContainerDispenser(IInventory iinventory, TileEntityDispenser tileentitydispenser) { + this.a = tileentitydispenser; + + int i; + int j; + + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + this.a(new Slot(tileentitydispenser, j + i * 3, 62 + j * 18, 17 + i * 18)); + } + } + + for (i = 0; i < 3; ++i) { + for (j = 0; j < 9; ++j) { + this.a(new Slot(iinventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + } + } + + for (i = 0; i < 9; ++i) { + this.a(new Slot(iinventory, i, 8 + i * 18, 142)); + } + } + + public boolean b(EntityHuman entityhuman) { + return this.a.a_(entityhuman); + } +} diff --git a/src/main/java/net/minecraft/server/ContainerFurnace.java b/src/main/java/net/minecraft/server/ContainerFurnace.java new file mode 100644 index 0000000..ca480db --- /dev/null +++ b/src/main/java/net/minecraft/server/ContainerFurnace.java @@ -0,0 +1,97 @@ +package net.minecraft.server; + +public class ContainerFurnace extends Container { + + private TileEntityFurnace a; + private int b = 0; + private int c = 0; + private int h = 0; + + public ContainerFurnace(InventoryPlayer inventoryplayer, TileEntityFurnace tileentityfurnace) { + this.a = tileentityfurnace; + this.a(new Slot(tileentityfurnace, 0, 56, 17)); + this.a(new Slot(tileentityfurnace, 1, 56, 53)); + this.a(new SlotResult2(inventoryplayer.d, tileentityfurnace, 2, 116, 35)); + + int i; + + for (i = 0; i < 3; ++i) { + for (int j = 0; j < 9; ++j) { + this.a(new Slot(inventoryplayer, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + } + } + + for (i = 0; i < 9; ++i) { + this.a(new Slot(inventoryplayer, i, 8 + i * 18, 142)); + } + } + + public void a(ICrafting icrafting) { + super.a(icrafting); + icrafting.a(this, 0, this.a.cookTime); + icrafting.a(this, 1, this.a.burnTime); + icrafting.a(this, 2, this.a.ticksForCurrentFuel); + } + + public void a() { + super.a(); + + for (int i = 0; i < this.listeners.size(); ++i) { + ICrafting icrafting = (ICrafting) this.listeners.get(i); + + if (this.b != this.a.cookTime) { + icrafting.a(this, 0, this.a.cookTime); + } + + if (this.c != this.a.burnTime) { + icrafting.a(this, 1, this.a.burnTime); + } + + if (this.h != this.a.ticksForCurrentFuel) { + icrafting.a(this, 2, this.a.ticksForCurrentFuel); + } + } + + this.b = this.a.cookTime; + this.c = this.a.burnTime; + this.h = this.a.ticksForCurrentFuel; + } + + public boolean b(EntityHuman entityhuman) { + return this.a.a_(entityhuman); + } + + public ItemStack a(int i) { + ItemStack itemstack = null; + Slot slot = (Slot) this.e.get(i); + + if (slot != null && slot.b()) { + ItemStack itemstack1 = slot.getItem(); + + itemstack = itemstack1.cloneItemStack(); + if (i == 2) { + this.a(itemstack1, 3, 39, true); + } else if (i >= 3 && i < 30) { + this.a(itemstack1, 30, 39, false); + } else if (i >= 30 && i < 39) { + this.a(itemstack1, 3, 30, false); + } else { + this.a(itemstack1, 3, 39, false); + } + + if (itemstack1.count == 0) { + slot.c((ItemStack) null); + } else { + slot.c(); + } + + if (itemstack1.count == itemstack.count) { + return null; + } + + slot.a(itemstack1); + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ContainerPlayer.java b/src/main/java/net/minecraft/server/ContainerPlayer.java new file mode 100644 index 0000000..9eed24c --- /dev/null +++ b/src/main/java/net/minecraft/server/ContainerPlayer.java @@ -0,0 +1,109 @@ +package net.minecraft.server; + +public class ContainerPlayer extends Container { + + public InventoryCrafting craftInventory; + public IInventory resultInventory; + public boolean c; + + public ContainerPlayer(InventoryPlayer inventoryplayer) { + this(inventoryplayer, true); + } + + public ContainerPlayer(InventoryPlayer inventoryplayer, boolean flag) { + this.craftInventory = new InventoryCrafting(this, 2, 2); + this.resultInventory = new InventoryCraftResult(); + this.c = false; + this.c = flag; + this.a((Slot) (new SlotResult(inventoryplayer.d, this.craftInventory, this.resultInventory, 0, 144, 36))); + + int i; + int j; + + for (i = 0; i < 2; ++i) { + for (j = 0; j < 2; ++j) { + this.a(new Slot(this.craftInventory, j + i * 2, 88 + j * 18, 26 + i * 18)); + } + } + + for (i = 0; i < 4; ++i) { + this.a((Slot) (new SlotArmor(this, inventoryplayer, inventoryplayer.getSize() - 1 - i, 8, 8 + i * 18, i))); + } + + for (i = 0; i < 3; ++i) { + for (j = 0; j < 9; ++j) { + this.a(new Slot(inventoryplayer, j + (i + 1) * 9, 8 + j * 18, 84 + i * 18)); + } + } + + for (i = 0; i < 9; ++i) { + this.a(new Slot(inventoryplayer, i, 8 + i * 18, 142)); + } + + this.a((IInventory) this.craftInventory); + } + + public void a(IInventory iinventory) { + // CraftBukkit start + ItemStack craftResult = CraftingManager.getInstance().craft(this.craftInventory); + this.resultInventory.setItem(0, craftResult); + if (super.listeners.size() < 1) { + return; + } + + EntityPlayer player = (EntityPlayer) super.listeners.get(0); // TODO: Is this _always_ correct? Seems like it. + player.netServerHandler.sendPacket(new Packet103SetSlot(player.activeContainer.windowId, 0, craftResult)); + // CraftBukkit end + } + + public void a(EntityHuman entityhuman) { + super.a(entityhuman); + + for (int i = 0; i < 4; ++i) { + ItemStack itemstack = this.craftInventory.getItem(i); + + if (itemstack != null) { + entityhuman.b(itemstack); + this.craftInventory.setItem(i, (ItemStack) null); + } + } + } + + public boolean b(EntityHuman entityhuman) { + return true; + } + + public ItemStack a(int i) { + ItemStack itemstack = null; + Slot slot = (Slot) this.e.get(i); + + if (slot != null && slot.b()) { + ItemStack itemstack1 = slot.getItem(); + + itemstack = itemstack1.cloneItemStack(); + if (i == 0) { + this.a(itemstack1, 9, 45, true); + } else if (i >= 9 && i < 36) { + this.a(itemstack1, 36, 45, false); + } else if (i >= 36 && i < 45) { + this.a(itemstack1, 9, 36, false); + } else { + this.a(itemstack1, 9, 45, false); + } + + if (itemstack1.count == 0) { + slot.c((ItemStack) null); + } else { + slot.c(); + } + + if (itemstack1.count == itemstack.count) { + return null; + } + + slot.a(itemstack1); + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ContainerWorkbench.java b/src/main/java/net/minecraft/server/ContainerWorkbench.java new file mode 100644 index 0000000..221cc76 --- /dev/null +++ b/src/main/java/net/minecraft/server/ContainerWorkbench.java @@ -0,0 +1,104 @@ +package net.minecraft.server; + +public class ContainerWorkbench extends Container { + + public InventoryCrafting craftInventory = new InventoryCrafting(this, 3, 3); + public IInventory resultInventory = new InventoryCraftResult(); + private World c; + private int h; + private int i; + private int j; + + public ContainerWorkbench(InventoryPlayer inventoryplayer, World world, int i, int j, int k) { + this.c = world; + this.h = i; + this.i = j; + this.j = k; + this.a((Slot) (new SlotResult(inventoryplayer.d, this.craftInventory, this.resultInventory, 0, 124, 35))); + + int l; + int i1; + + for (l = 0; l < 3; ++l) { + for (i1 = 0; i1 < 3; ++i1) { + this.a(new Slot(this.craftInventory, i1 + l * 3, 30 + i1 * 18, 17 + l * 18)); + } + } + + for (l = 0; l < 3; ++l) { + for (i1 = 0; i1 < 9; ++i1) { + this.a(new Slot(inventoryplayer, i1 + l * 9 + 9, 8 + i1 * 18, 84 + l * 18)); + } + } + + for (l = 0; l < 9; ++l) { + this.a(new Slot(inventoryplayer, l, 8 + l * 18, 142)); + } + + this.a((IInventory) this.craftInventory); + } + + public void a(IInventory iinventory) { + // CraftBukkit start + ItemStack craftResult = CraftingManager.getInstance().craft(this.craftInventory); + this.resultInventory.setItem(0, craftResult); + if (super.listeners.size() < 1) { + return; + } + + EntityPlayer player = (EntityPlayer) super.listeners.get(0); // TODO: Is this _always_ correct? Seems like it. + player.netServerHandler.sendPacket(new Packet103SetSlot(player.activeContainer.windowId, 0, craftResult)); + // CraftBukkit end + } + + public void a(EntityHuman entityhuman) { + super.a(entityhuman); + if (!this.c.isStatic) { + for (int i = 0; i < 9; ++i) { + ItemStack itemstack = this.craftInventory.getItem(i); + + if (itemstack != null) { + entityhuman.b(itemstack); + } + } + } + } + + public boolean b(EntityHuman entityhuman) { + return this.c.getTypeId(this.h, this.i, this.j) != Block.WORKBENCH.id ? false : entityhuman.e((double) this.h + 0.5D, (double) this.i + 0.5D, (double) this.j + 0.5D) <= 64.0D; + } + + public ItemStack a(int i) { + ItemStack itemstack = null; + Slot slot = (Slot) this.e.get(i); + + if (slot != null && slot.b()) { + ItemStack itemstack1 = slot.getItem(); + + itemstack = itemstack1.cloneItemStack(); + if (i == 0) { + this.a(itemstack1, 10, 46, true); + } else if (i >= 10 && i < 37) { + this.a(itemstack1, 37, 46, false); + } else if (i >= 37 && i < 46) { + this.a(itemstack1, 10, 37, false); + } else { + this.a(itemstack1, 10, 46, false); + } + + if (itemstack1.count == 0) { + slot.c((ItemStack) null); + } else { + slot.c(); + } + + if (itemstack1.count == itemstack.count) { + return null; + } + + slot.a(itemstack1); + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ConvertProgressUpdater.java b/src/main/java/net/minecraft/server/ConvertProgressUpdater.java new file mode 100644 index 0000000..6ee2043 --- /dev/null +++ b/src/main/java/net/minecraft/server/ConvertProgressUpdater.java @@ -0,0 +1,24 @@ +package net.minecraft.server; + +public class ConvertProgressUpdater implements IProgressUpdate { + + private long b; + + final MinecraftServer a; + + public ConvertProgressUpdater(MinecraftServer minecraftserver) { + this.a = minecraftserver; + this.b = System.currentTimeMillis(); + } + + public void a(String s) {} + + public void a(int i) { + if (System.currentTimeMillis() - this.b >= 1000L) { + this.b = System.currentTimeMillis(); + MinecraftServer.log.info("Converting... " + i + "%"); + } + } + + public void b(String s) {} +} diff --git a/src/main/java/net/minecraft/server/Convertable.java b/src/main/java/net/minecraft/server/Convertable.java new file mode 100644 index 0000000..9d96827 --- /dev/null +++ b/src/main/java/net/minecraft/server/Convertable.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +public interface Convertable { + + boolean isConvertable(String s); + + boolean convert(String s, IProgressUpdate iprogressupdate); +} diff --git a/src/main/java/net/minecraft/server/Counter.java b/src/main/java/net/minecraft/server/Counter.java new file mode 100644 index 0000000..cbfe88b --- /dev/null +++ b/src/main/java/net/minecraft/server/Counter.java @@ -0,0 +1,3 @@ +package net.minecraft.server; + +public interface Counter {} diff --git a/src/main/java/net/minecraft/server/CounterStatistic.java b/src/main/java/net/minecraft/server/CounterStatistic.java new file mode 100644 index 0000000..d09c17b --- /dev/null +++ b/src/main/java/net/minecraft/server/CounterStatistic.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +public class CounterStatistic extends Statistic { + + public CounterStatistic(int i, String s, Counter counter) { + super(i, s, counter); + } + + public CounterStatistic(int i, String s) { + super(i, s); + } + + public Statistic d() { + super.d(); + StatisticList.c.add(this); + return this; + } +} diff --git a/src/main/java/net/minecraft/server/CraftingManager.java b/src/main/java/net/minecraft/server/CraftingManager.java new file mode 100644 index 0000000..78ca3c4 --- /dev/null +++ b/src/main/java/net/minecraft/server/CraftingManager.java @@ -0,0 +1,183 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +public class CraftingManager { + + private static final CraftingManager a = new CraftingManager(); + private List b = new ArrayList(); + + public static final CraftingManager getInstance() { + return a; + } + + private CraftingManager() { + (new RecipesTools()).a(this); + (new RecipesWeapons()).a(this); + (new RecipeIngots()).a(this); + (new RecipesFood()).a(this); + (new RecipesCrafting()).a(this); + (new RecipesArmor()).a(this); + (new RecipesDyes()).a(this); + this.registerShapedRecipe(new ItemStack(Item.PAPER, 3), new Object[] { "###", Character.valueOf('#'), Item.SUGAR_CANE}); + this.registerShapedRecipe(new ItemStack(Item.BOOK, 1), new Object[] { "#", "#", "#", Character.valueOf('#'), Item.PAPER}); + this.registerShapedRecipe(new ItemStack(Block.FENCE, 2), new Object[] { "###", "###", Character.valueOf('#'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Block.JUKEBOX, 1), new Object[] { "###", "#X#", "###", Character.valueOf('#'), Block.WOOD, Character.valueOf('X'), Item.DIAMOND}); + this.registerShapedRecipe(new ItemStack(Block.NOTE_BLOCK, 1), new Object[] { "###", "#X#", "###", Character.valueOf('#'), Block.WOOD, Character.valueOf('X'), Item.REDSTONE}); + this.registerShapedRecipe(new ItemStack(Block.BOOKSHELF, 1), new Object[] { "###", "XXX", "###", Character.valueOf('#'), Block.WOOD, Character.valueOf('X'), Item.BOOK}); + this.registerShapedRecipe(new ItemStack(Block.SNOW_BLOCK, 1), new Object[] { "##", "##", Character.valueOf('#'), Item.SNOW_BALL}); + this.registerShapedRecipe(new ItemStack(Block.CLAY, 1), new Object[] { "##", "##", Character.valueOf('#'), Item.CLAY_BALL}); + this.registerShapedRecipe(new ItemStack(Block.BRICK, 1), new Object[] { "##", "##", Character.valueOf('#'), Item.CLAY_BRICK}); + this.registerShapedRecipe(new ItemStack(Block.GLOWSTONE, 1), new Object[] { "##", "##", Character.valueOf('#'), Item.GLOWSTONE_DUST}); + this.registerShapedRecipe(new ItemStack(Block.WOOL, 1), new Object[] { "##", "##", Character.valueOf('#'), Item.STRING}); + this.registerShapedRecipe(new ItemStack(Block.TNT, 1), new Object[] { "X#X", "#X#", "X#X", Character.valueOf('X'), Item.SULPHUR, Character.valueOf('#'), Block.SAND}); + this.registerShapedRecipe(new ItemStack(Block.STEP, 3, 3), new Object[] { "###", Character.valueOf('#'), Block.COBBLESTONE}); + this.registerShapedRecipe(new ItemStack(Block.STEP, 3, 0), new Object[] { "###", Character.valueOf('#'), Block.STONE}); + this.registerShapedRecipe(new ItemStack(Block.STEP, 3, 1), new Object[] { "###", Character.valueOf('#'), Block.SANDSTONE}); + this.registerShapedRecipe(new ItemStack(Block.STEP, 3, 2), new Object[] { "###", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Block.LADDER, 2), new Object[] { "# #", "###", "# #", Character.valueOf('#'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Item.WOOD_DOOR, 1), new Object[] { "##", "##", "##", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Block.TRAP_DOOR, 2), new Object[] { "###", "###", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Item.IRON_DOOR, 1), new Object[] { "##", "##", "##", Character.valueOf('#'), Item.IRON_INGOT}); + this.registerShapedRecipe(new ItemStack(Item.SIGN, 1), new Object[] { "###", "###", " X ", Character.valueOf('#'), Block.WOOD, Character.valueOf('X'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Item.CAKE, 1), new Object[] { "AAA", "BEB", "CCC", Character.valueOf('A'), Item.MILK_BUCKET, Character.valueOf('B'), Item.SUGAR, Character.valueOf('C'), Item.WHEAT, Character.valueOf('E'), Item.EGG}); + this.registerShapedRecipe(new ItemStack(Item.SUGAR, 1), new Object[] { "#", Character.valueOf('#'), Item.SUGAR_CANE}); + this.registerShapedRecipe(new ItemStack(Block.WOOD, 4), new Object[] { "#", Character.valueOf('#'), Block.LOG}); + this.registerShapedRecipe(new ItemStack(Item.STICK, 4), new Object[] { "#", "#", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Block.TORCH, 4), new Object[] { "X", "#", Character.valueOf('X'), Item.COAL, Character.valueOf('#'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Block.TORCH, 4), new Object[] { "X", "#", Character.valueOf('X'), new ItemStack(Item.COAL, 1, 1), Character.valueOf('#'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Item.BOWL, 4), new Object[] { "# #", " # ", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Block.RAILS, 16), new Object[] { "X X", "X#X", "X X", Character.valueOf('X'), Item.IRON_INGOT, Character.valueOf('#'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Block.GOLDEN_RAIL, 6), new Object[] { "X X", "X#X", "XRX", Character.valueOf('X'), Item.GOLD_INGOT, Character.valueOf('R'), Item.REDSTONE, Character.valueOf('#'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Block.DETECTOR_RAIL, 6), new Object[] { "X X", "X#X", "XRX", Character.valueOf('X'), Item.IRON_INGOT, Character.valueOf('R'), Item.REDSTONE, Character.valueOf('#'), Block.STONE_PLATE}); + this.registerShapedRecipe(new ItemStack(Item.MINECART, 1), new Object[] { "# #", "###", Character.valueOf('#'), Item.IRON_INGOT}); + this.registerShapedRecipe(new ItemStack(Block.JACK_O_LANTERN, 1), new Object[] { "A", "B", Character.valueOf('A'), Block.PUMPKIN, Character.valueOf('B'), Block.TORCH}); + this.registerShapedRecipe(new ItemStack(Item.STORAGE_MINECART, 1), new Object[] { "A", "B", Character.valueOf('A'), Block.CHEST, Character.valueOf('B'), Item.MINECART}); + this.registerShapedRecipe(new ItemStack(Item.POWERED_MINECART, 1), new Object[] { "A", "B", Character.valueOf('A'), Block.FURNACE, Character.valueOf('B'), Item.MINECART}); + this.registerShapedRecipe(new ItemStack(Item.BOAT, 1), new Object[] { "# #", "###", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Item.BUCKET, 1), new Object[] { "# #", " # ", Character.valueOf('#'), Item.IRON_INGOT}); + this.registerShapedRecipe(new ItemStack(Item.FLINT_AND_STEEL, 1), new Object[] { "A ", " B", Character.valueOf('A'), Item.IRON_INGOT, Character.valueOf('B'), Item.FLINT}); + this.registerShapedRecipe(new ItemStack(Item.BREAD, 1), new Object[] { "###", Character.valueOf('#'), Item.WHEAT}); + this.registerShapedRecipe(new ItemStack(Block.WOOD_STAIRS, 4), new Object[] { "# ", "## ", "###", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Item.FISHING_ROD, 1), new Object[] { " #", " #X", "# X", Character.valueOf('#'), Item.STICK, Character.valueOf('X'), Item.STRING}); + this.registerShapedRecipe(new ItemStack(Block.COBBLESTONE_STAIRS, 4), new Object[] { "# ", "## ", "###", Character.valueOf('#'), Block.COBBLESTONE}); + this.registerShapedRecipe(new ItemStack(Item.PAINTING, 1), new Object[] { "###", "#X#", "###", Character.valueOf('#'), Item.STICK, Character.valueOf('X'), Block.WOOL}); + this.registerShapedRecipe(new ItemStack(Item.GOLDEN_APPLE, 1), new Object[] { "###", "#X#", "###", Character.valueOf('#'), Block.GOLD_BLOCK, Character.valueOf('X'), Item.APPLE}); + this.registerShapedRecipe(new ItemStack(Block.LEVER, 1), new Object[] { "X", "#", Character.valueOf('#'), Block.COBBLESTONE, Character.valueOf('X'), Item.STICK}); + this.registerShapedRecipe(new ItemStack(Block.REDSTONE_TORCH_ON, 1), new Object[] { "X", "#", Character.valueOf('#'), Item.STICK, Character.valueOf('X'), Item.REDSTONE}); + this.registerShapedRecipe(new ItemStack(Item.DIODE, 1), new Object[] { "#X#", "III", Character.valueOf('#'), Block.REDSTONE_TORCH_ON, Character.valueOf('X'), Item.REDSTONE, Character.valueOf('I'), Block.STONE}); + this.registerShapedRecipe(new ItemStack(Item.WATCH, 1), new Object[] { " # ", "#X#", " # ", Character.valueOf('#'), Item.GOLD_INGOT, Character.valueOf('X'), Item.REDSTONE}); + this.registerShapedRecipe(new ItemStack(Item.COMPASS, 1), new Object[] { " # ", "#X#", " # ", Character.valueOf('#'), Item.IRON_INGOT, Character.valueOf('X'), Item.REDSTONE}); + this.registerShapedRecipe(new ItemStack(Item.MAP, 1), new Object[] { "###", "#X#", "###", Character.valueOf('#'), Item.PAPER, Character.valueOf('X'), Item.COMPASS}); + this.registerShapedRecipe(new ItemStack(Block.STONE_BUTTON, 1), new Object[] { "#", "#", Character.valueOf('#'), Block.STONE}); + this.registerShapedRecipe(new ItemStack(Block.STONE_PLATE, 1), new Object[] { "##", Character.valueOf('#'), Block.STONE}); + this.registerShapedRecipe(new ItemStack(Block.WOOD_PLATE, 1), new Object[] { "##", Character.valueOf('#'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Block.DISPENSER, 1), new Object[] { "###", "#X#", "#R#", Character.valueOf('#'), Block.COBBLESTONE, Character.valueOf('X'), Item.BOW, Character.valueOf('R'), Item.REDSTONE}); + this.registerShapedRecipe(new ItemStack(Block.PISTON, 1), new Object[] { "TTT", "#X#", "#R#", Character.valueOf('#'), Block.COBBLESTONE, Character.valueOf('X'), Item.IRON_INGOT, Character.valueOf('R'), Item.REDSTONE, Character.valueOf('T'), Block.WOOD}); + this.registerShapedRecipe(new ItemStack(Block.PISTON_STICKY, 1), new Object[] { "S", "P", Character.valueOf('S'), Item.SLIME_BALL, Character.valueOf('P'), Block.PISTON}); + this.registerShapedRecipe(new ItemStack(Item.BED, 1), new Object[] { "###", "XXX", Character.valueOf('#'), Block.WOOL, Character.valueOf('X'), Block.WOOD}); + Collections.sort(this.b, new RecipeSorter(this)); + System.out.println(this.b.size() + " recipes"); + } + + public void registerShapedRecipe(ItemStack itemstack, Object... aobject) { // CraftBukkit - default -> public + String s = ""; + int i = 0; + int j = 0; + int k = 0; + + if (aobject[i] instanceof String[]) { + String[] astring = (String[]) ((String[]) aobject[i++]); + + for (int l = 0; l < astring.length; ++l) { + String s1 = astring[l]; + + ++k; + j = s1.length(); + s = s + s1; + } + } else { + while (aobject[i] instanceof String) { + String s2 = (String) aobject[i++]; + + ++k; + j = s2.length(); + s = s + s2; + } + } + + HashMap hashmap; + + for (hashmap = new HashMap(); i < aobject.length; i += 2) { + Character character = (Character) aobject[i]; + ItemStack itemstack1 = null; + + if (aobject[i + 1] instanceof Item) { + itemstack1 = new ItemStack((Item) aobject[i + 1]); + } else if (aobject[i + 1] instanceof Block) { + itemstack1 = new ItemStack((Block) aobject[i + 1], 1, -1); + } else if (aobject[i + 1] instanceof ItemStack) { + itemstack1 = (ItemStack) aobject[i + 1]; + } + + hashmap.put(character, itemstack1); + } + + ItemStack[] aitemstack = new ItemStack[j * k]; + + for (int i1 = 0; i1 < j * k; ++i1) { + char c0 = s.charAt(i1); + + if (hashmap.containsKey(Character.valueOf(c0))) { + aitemstack[i1] = ((ItemStack) hashmap.get(Character.valueOf(c0))).cloneItemStack(); + } else { + aitemstack[i1] = null; + } + } + + this.b.add(new ShapedRecipes(j, k, aitemstack, itemstack)); + } + + public void registerShapelessRecipe(ItemStack itemstack, Object... aobject) { // CraftBukkit - default -> public + ArrayList arraylist = new ArrayList(); + Object[] aobject1 = aobject; + int i = aobject.length; + + for (int j = 0; j < i; ++j) { + Object object = aobject1[j]; + + if (object instanceof ItemStack) { + arraylist.add(((ItemStack) object).cloneItemStack()); + } else if (object instanceof Item) { + arraylist.add(new ItemStack((Item) object)); + } else { + if (!(object instanceof Block)) { + throw new RuntimeException("Invalid shapeless recipy!"); + } + + arraylist.add(new ItemStack((Block) object)); + } + } + + this.b.add(new ShapelessRecipes(itemstack, arraylist)); + } + + public ItemStack craft(InventoryCrafting inventorycrafting) { + for (int i = 0; i < this.b.size(); ++i) { + CraftingRecipe craftingrecipe = (CraftingRecipe) this.b.get(i); + + if (craftingrecipe.a(inventorycrafting)) { + return craftingrecipe.b(inventorycrafting); + } + } + + return null; + } + + public List b() { + return this.b; + } +} diff --git a/src/main/java/net/minecraft/server/CraftingRecipe.java b/src/main/java/net/minecraft/server/CraftingRecipe.java new file mode 100644 index 0000000..dee3749 --- /dev/null +++ b/src/main/java/net/minecraft/server/CraftingRecipe.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +public interface CraftingRecipe { + + boolean a(InventoryCrafting inventorycrafting); + + ItemStack b(InventoryCrafting inventorycrafting); + + int a(); + + ItemStack b(); +} diff --git a/src/main/java/net/minecraft/server/CraftingStatistic.java b/src/main/java/net/minecraft/server/CraftingStatistic.java new file mode 100644 index 0000000..82d776a --- /dev/null +++ b/src/main/java/net/minecraft/server/CraftingStatistic.java @@ -0,0 +1,11 @@ +package net.minecraft.server; + +public class CraftingStatistic extends Statistic { + + private final int a; + + public CraftingStatistic(int i, String s, int j) { + super(i, s); + this.a = j; + } +} diff --git a/src/main/java/net/minecraft/server/DataWatcher.java b/src/main/java/net/minecraft/server/DataWatcher.java new file mode 100644 index 0000000..36ae1b8 --- /dev/null +++ b/src/main/java/net/minecraft/server/DataWatcher.java @@ -0,0 +1,220 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.*; + +public class DataWatcher { + + private boolean d = true; + private static final HashMap a = new HashMap(); + private final Map b = new HashMap(); + private boolean c; + + public DataWatcher() {} + + public void a(int i, Object object) { + Integer integer = (Integer) a.get(object.getClass()); + + if (integer == null) { + throw new IllegalArgumentException("Unknown data type: " + object.getClass()); + } else if (i > 31) { + throw new IllegalArgumentException("Data value id is too big with " + i + "! (Max is " + 31 + ")"); + } else if (this.b.containsKey(Integer.valueOf(i))) { + throw new IllegalArgumentException("Duplicate id value for " + i + "!"); + } else { + WatchableObject watchableobject = new WatchableObject(integer.intValue(), i, object); + + this.b.put(Integer.valueOf(i), watchableobject); + this.d = false; + } + } + + public byte a(int i) { + return ((Byte) ((WatchableObject) this.b.get(Integer.valueOf(i))).b()).byteValue(); + } + + public int b(int i) { + return ((Integer) ((WatchableObject) this.b.get(Integer.valueOf(i))).b()).intValue(); + } + + public String c(int i) { + return (String) ((WatchableObject) this.b.get(Integer.valueOf(i))).b(); + } + + public void watch(int i, Object object) { + WatchableObject watchableobject = (WatchableObject) this.b.get(Integer.valueOf(i)); + + if (!object.equals(watchableobject.b())) { + watchableobject.a(object); + watchableobject.a(true); + this.c = true; + } + } + + public boolean a() { + return this.c; + } + + public static void a(List list, DataOutputStream dataoutputstream) throws IOException { + if (list != null) { + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { + WatchableObject watchableobject = (WatchableObject) iterator.next(); + + a(dataoutputstream, watchableobject); + } + } + + dataoutputstream.writeByte(127); + } + + public ArrayList b() { + ArrayList arraylist = null; + + if (this.c) { + Iterator iterator = this.b.values().iterator(); + + while (iterator.hasNext()) { + WatchableObject watchableobject = (WatchableObject) iterator.next(); + + if (watchableobject.d()) { + watchableobject.a(false); + if (arraylist == null) { + arraylist = new ArrayList(); + } + + arraylist.add(watchableobject); + } + } + } + + this.c = false; + return arraylist; + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + Iterator iterator = this.b.values().iterator(); + + while (iterator.hasNext()) { + WatchableObject watchableobject = (WatchableObject) iterator.next(); + + a(dataoutputstream, watchableobject); + } + + dataoutputstream.writeByte(127); + } + + private static void a(DataOutputStream dataoutputstream, WatchableObject watchableobject) throws IOException { + int i = (watchableobject.c() << 5 | watchableobject.a() & 31) & 255; + + dataoutputstream.writeByte(i); + switch (watchableobject.c()) { + case 0: + dataoutputstream.writeByte(((Byte) watchableobject.b()).byteValue()); + break; + + case 1: + dataoutputstream.writeShort(((Short) watchableobject.b()).shortValue()); + break; + + case 2: + dataoutputstream.writeInt(((Integer) watchableobject.b()).intValue()); + break; + + case 3: + dataoutputstream.writeFloat(((Float) watchableobject.b()).floatValue()); + break; + + case 4: + Packet.a((String) watchableobject.b(), dataoutputstream); + break; + + case 5: + ItemStack itemstack = (ItemStack) watchableobject.b(); + + dataoutputstream.writeShort(itemstack.getItem().id); + dataoutputstream.writeByte(itemstack.count); + dataoutputstream.writeShort(itemstack.getData()); + break; + + case 6: + ChunkCoordinates chunkcoordinates = (ChunkCoordinates) watchableobject.b(); + + dataoutputstream.writeInt(chunkcoordinates.x); + dataoutputstream.writeInt(chunkcoordinates.y); + dataoutputstream.writeInt(chunkcoordinates.z); + } + } + + public static List a(DataInputStream datainputstream) throws IOException { + ArrayList arraylist = null; + + for (byte b0 = datainputstream.readByte(); b0 != 127; b0 = datainputstream.readByte()) { + if (arraylist == null) { + arraylist = new ArrayList(); + } + + int i = (b0 & 224) >> 5; + int j = b0 & 31; + WatchableObject watchableobject = null; + + switch (i) { + case 0: + watchableobject = new WatchableObject(i, j, Byte.valueOf(datainputstream.readByte())); + break; + + case 1: + watchableobject = new WatchableObject(i, j, Short.valueOf(datainputstream.readShort())); + break; + + case 2: + watchableobject = new WatchableObject(i, j, Integer.valueOf(datainputstream.readInt())); + break; + + case 3: + watchableobject = new WatchableObject(i, j, Float.valueOf(datainputstream.readFloat())); + break; + + case 4: + watchableobject = new WatchableObject(i, j, Packet.a(datainputstream, 64)); + break; + + case 5: + short short1 = datainputstream.readShort(); + byte b1 = datainputstream.readByte(); + short short2 = datainputstream.readShort(); + + watchableobject = new WatchableObject(i, j, new ItemStack(short1, b1, short2)); + break; + + case 6: + int k = datainputstream.readInt(); + int l = datainputstream.readInt(); + int i1 = datainputstream.readInt(); + + watchableobject = new WatchableObject(i, j, new ChunkCoordinates(k, l, i1)); + } + + arraylist.add(watchableobject); + } + + return arraylist; + } + + public boolean getD() { + return this.d; + } + + static { + a.put(Byte.class, Integer.valueOf(0)); + a.put(Short.class, Integer.valueOf(1)); + a.put(Integer.class, Integer.valueOf(2)); + a.put(Float.class, Integer.valueOf(3)); + a.put(String.class, Integer.valueOf(4)); + a.put(ItemStack.class, Integer.valueOf(5)); + a.put(ChunkCoordinates.class, Integer.valueOf(6)); + } +} diff --git a/src/main/java/net/minecraft/server/DistancesCounter.java b/src/main/java/net/minecraft/server/DistancesCounter.java new file mode 100644 index 0000000..d92130e --- /dev/null +++ b/src/main/java/net/minecraft/server/DistancesCounter.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +final class DistancesCounter implements Counter { + + DistancesCounter() {} +} diff --git a/src/main/java/net/minecraft/server/EmptyChunk.java b/src/main/java/net/minecraft/server/EmptyChunk.java new file mode 100644 index 0000000..091eb0b --- /dev/null +++ b/src/main/java/net/minecraft/server/EmptyChunk.java @@ -0,0 +1,113 @@ +package net.minecraft.server; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class EmptyChunk extends Chunk { + + public EmptyChunk(World world, int i, int j) { + super(world, i, j); + this.p = true; + } + + public EmptyChunk(World world, byte[] abyte, int i, int j) { + super(world, abyte, i, j); + this.p = true; + } + + public boolean a(int i, int j) { + return i == this.x && j == this.z; + } + + public int b(int i, int j) { + return 0; + } + + public void a() {} + + public void initLighting() {} + + public void loadNOP() {} + + public int getTypeId(int i, int j, int k) { + return 0; + } + + public boolean a(int i, int j, int k, int l, int i1) { + return true; + } + + public boolean a(int i, int j, int k, int l) { + return true; + } + + public int getData(int i, int j, int k) { + return 0; + } + + public void b(int i, int j, int k, int l) {} + + public int a(EnumSkyBlock enumskyblock, int i, int j, int k) { + return 0; + } + + public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l) {} + + public int c(int i, int j, int k, int l) { + return 0; + } + + public void a(Entity entity) {} + + public void b(Entity entity) {} + + public void a(Entity entity, int i) {} + + public boolean c(int i, int j, int k) { + return false; + } + + public TileEntity d(int i, int j, int k) { + return null; + } + + public void a(TileEntity tileentity) {} + + public void placeTileEntity(int i, int j, int k, TileEntity tileentity) {} + + public void e(int i, int j, int k) {} + + public void addEntities() {} + + public void removeEntities() {} + + public void f() {} + + public void a(Entity entity, AxisAlignedBB axisalignedbb, List list) {} + + public void a(Class oclass, AxisAlignedBB axisalignedbb, List list) {} + + public boolean a(boolean flag) { + return false; + } + + public int getData(byte[] abyte, int i, int j, int k, int l, int i1, int j1, int k1) { + int l1 = l - i; + int i2 = i1 - j; + int j2 = j1 - k; + int k2 = l1 * i2 * j2; + int l2 = k2 + k2 / 2 * 3; + + Arrays.fill(abyte, k1, k1 + l2, (byte) 0); + return l2; + } + + public Random a(long i) { + return new Random(this.world.getSeed() + (long) (this.x * this.x * 4987142) + (long) (this.x * 5947611) + (long) (this.z * this.z) * 4392871L + (long) (this.z * 389711) ^ i); + } + + public boolean isEmpty() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/EmptyClass1.java b/src/main/java/net/minecraft/server/EmptyClass1.java new file mode 100644 index 0000000..1944517 --- /dev/null +++ b/src/main/java/net/minecraft/server/EmptyClass1.java @@ -0,0 +1,3 @@ +package net.minecraft.server; + +class EmptyClass1 {} diff --git a/src/main/java/net/minecraft/server/EmptyClass2.java b/src/main/java/net/minecraft/server/EmptyClass2.java new file mode 100644 index 0000000..19e2c96 --- /dev/null +++ b/src/main/java/net/minecraft/server/EmptyClass2.java @@ -0,0 +1,3 @@ +package net.minecraft.server; + +class EmptyClass2 {} diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java new file mode 100644 index 0000000..4794c63 --- /dev/null +++ b/src/main/java/net/minecraft/server/Entity.java @@ -0,0 +1,1354 @@ +package net.minecraft.server; + +import org.bukkit.Bukkit; +import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageByBlockEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; +import org.bukkit.event.vehicle.VehicleExitEvent; + +import java.util.List; +import java.util.Random; +import java.util.UUID; + +// CraftBukkit start +// CraftBukkit end + +public abstract class Entity { + + // Poseidon start - Backport of 0070-Use-a-Shared-Random-for-Entities.patch from PaperSpigot + public static Random SHARED_RANDOM = new Random() { + private boolean locked = false; + @Override + public synchronized void setSeed(long seed) { + if (locked) { + // Ignoring setSeed on Entity.SHARED_RANDOM + } else { + super.setSeed(seed); + locked = true; + } + } + }; + // Poseidon end + + private static int entityCount = 0; + public int id; + public double aH; + public boolean aI; + public Entity passenger; + public Entity vehicle; + public World world; + public double lastX; + public double lastY; + public double lastZ; + public double locX; + public double locY; + public double locZ; + public double motX; + public double motY; + public double motZ; + public float yaw; + public float pitch; + public float lastYaw; + public float lastPitch; + public final AxisAlignedBB boundingBox; + public boolean onGround; + public boolean positionChanged; + public boolean bc; + public boolean bd; + public boolean velocityChanged; + public boolean bf; + public boolean bg; + public boolean dead; + public float height; + public float length; + public float width; + public float bl; + public float bm; + public float fallDistance; // CraftBukkit - private -> public + private int b; + public double bo; + public double bp; + public double bq; + public float br; + public float bs; + public boolean bt; + public float bu; + protected Random random; + public int ticksLived; + public int maxFireTicks; + public int fireTicks; + public int maxAirTicks; // CraftBukkit - protected - >public + protected boolean bA; + public int noDamageTicks; + public int airTicks; + private boolean justCreated; + protected boolean fireProof; + protected DataWatcher datawatcher; + public float bF; + private double d; + private double e; + public boolean bG; + public int bH; + public int bI; + public int bJ; + public boolean bK; + public boolean airBorne; + public UUID uniqueId = UUID.randomUUID(); // CraftBukkit + + public Entity(World world) { + this.id = entityCount++; + this.aH = 1.0D; + this.aI = false; + this.boundingBox = AxisAlignedBB.a(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D); + this.onGround = false; + this.bd = false; + this.velocityChanged = false; + this.bg = true; + this.dead = false; + this.height = 0.0F; + this.length = 0.6F; + this.width = 1.8F; + this.bl = 0.0F; + this.bm = 0.0F; + this.fallDistance = 0.0F; + this.b = 1; + this.br = 0.0F; + this.bs = 0.0F; + this.bt = false; + this.bu = 0.0F; + this.random = SHARED_RANDOM; + this.ticksLived = 0; + this.maxFireTicks = 1; + this.fireTicks = 0; + this.maxAirTicks = 300; + this.bA = false; + this.noDamageTicks = 0; + this.airTicks = 300; + this.justCreated = true; + this.fireProof = false; + this.datawatcher = new DataWatcher(); + this.bF = 0.0F; + this.bG = false; + this.world = world; + this.setPosition(0.0D, 0.0D, 0.0D); + this.datawatcher.a(0, Byte.valueOf((byte) 0)); + this.b(); + } + + protected abstract void b(); + + public DataWatcher aa() { + return this.datawatcher; + } + + public boolean equals(Object object) { + return object instanceof Entity ? ((Entity) object).id == this.id : false; + } + + public int hashCode() { + return this.id; + } + + public void die() { + this.dead = true; + } + + protected void b(float f, float f1) { + this.length = f; + this.width = f1; + } + + protected void c(float f, float f1) { + // CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0. + if (Float.isNaN(f)) { + f = 0; + } + + if ((f == Float.POSITIVE_INFINITY) || (f == Float.NEGATIVE_INFINITY)) { + if (this instanceof EntityPlayer) { + System.err.println(((CraftPlayer) this.getBukkitEntity()).getName() + " was caught trying to crash the server with an invalid yaw"); + ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope"); + } + f = 0; + } + + // pitch was sometimes set to NaN, so we need to set it back to 0. + if (Float.isNaN(f1)) { + f1 = 0; + } + + if ((f1 == Float.POSITIVE_INFINITY) || (f1 == Float.NEGATIVE_INFINITY)) { + if (this instanceof EntityPlayer) { + System.err.println(((CraftPlayer) this.getBukkitEntity()).getName() + " was caught trying to crash the server with an invalid pitch"); + ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope"); + } + f1 = 0; + } + // CraftBukkit end + + this.yaw = f % 360.0F; + this.pitch = f1 % 360.0F; + } + + public void setPosition(double d0, double d1, double d2) { + this.locX = d0; + this.locY = d1; + this.locZ = d2; + float f = this.length / 2.0F; + float f1 = this.width; + + this.boundingBox.c(d0 - (double) f, d1 - (double) this.height + (double) this.br, d2 - (double) f, d0 + (double) f, d1 - (double) this.height + (double) this.br + (double) f1, d2 + (double) f); + } + + public void m_() { + this.R(); + } + + public void R() { + if (this.vehicle != null && this.vehicle.dead) { + this.vehicle = null; + } + + ++this.ticksLived; + this.bl = this.bm; + this.lastX = this.locX; + this.lastY = this.locY; + this.lastZ = this.locZ; + this.lastPitch = this.pitch; + this.lastYaw = this.yaw; + if (this.f_()) { + if (!this.bA && !this.justCreated) { + float f = MathHelper.a(this.motX * this.motX * 0.20000000298023224D + this.motY * this.motY + this.motZ * this.motZ * 0.20000000298023224D) * 0.2F; + + if (f > 1.0F) { + f = 1.0F; + } + + this.world.makeSound(this, "random.splash", f, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F); + float f1 = (float) MathHelper.floor(this.boundingBox.b); + + int i; + float f2; + float f3; + + for (i = 0; (float) i < 1.0F + this.length * 20.0F; ++i) { + f2 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + f3 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + this.world.a("bubble", this.locX + (double) f2, (double) (f1 + 1.0F), this.locZ + (double) f3, this.motX, this.motY - (double) (this.random.nextFloat() * 0.2F), this.motZ); + } + + for (i = 0; (float) i < 1.0F + this.length * 20.0F; ++i) { + f2 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + f3 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + this.world.a("splash", this.locX + (double) f2, (double) (f1 + 1.0F), this.locZ + (double) f3, this.motX, this.motY, this.motZ); + } + } + + this.fallDistance = 0.0F; + this.bA = true; + this.fireTicks = 0; + } else { + this.bA = false; + } + + if (this.world.isStatic) { + this.fireTicks = 0; + } else if (this.fireTicks > 0) { + if (this.fireProof) { + this.fireTicks -= 4; + if (this.fireTicks < 0) { + this.fireTicks = 0; + } + } else { + if (this.fireTicks % 20 == 0) { + // CraftBukkit start - TODO: this event spams! + if (this instanceof EntityLiving) { + EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.FIRE_TICK, 1); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.damageEntity((Entity) null, event.getDamage()); + } + } else { + this.damageEntity((Entity) null, 1); + } + // CraftBukkit end + } + + --this.fireTicks; + } + } + + if (this.ae()) { + this.ab(); + } + + if (this.locY < -64.0D) { + this.Y(); + } + + if (!this.world.isStatic) { + this.a(0, this.fireTicks > 0); + this.a(2, this.vehicle != null); + } + + this.justCreated = false; + } + + protected void ab() { + if (!this.fireProof) { + // CraftBukkit start - TODO: this event spams! + if (this instanceof EntityLiving) { + org.bukkit.Server server = this.world.getServer(); + + // TODO: shouldn't be sending null for the block. + org.bukkit.block.Block damager = null; // ((WorldServer) this.l).getWorld().getBlockAt(i, j, k); + org.bukkit.entity.Entity damagee = this.getBukkitEntity(); + + EntityDamageByBlockEvent event = new EntityDamageByBlockEvent(damager, damagee, EntityDamageEvent.DamageCause.LAVA, 4); + server.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.damageEntity((Entity) null, event.getDamage()); + } + + if (this.fireTicks <= 0) { + // not on fire yet + EntityCombustEvent combustEvent = new EntityCombustEvent(damagee); + server.getPluginManager().callEvent(combustEvent); + + if (!combustEvent.isCancelled()) { + this.fireTicks = 600; + } + } else { + // reset fire level back to max + this.fireTicks = 600; + } + return; + } + // CraftBukkit end + + this.damageEntity((Entity) null, 4); + this.fireTicks = 600; + } + } + + protected void Y() { + this.die(); + } + + public boolean d(double d0, double d1, double d2) { + AxisAlignedBB axisalignedbb = this.boundingBox.c(d0, d1, d2); + List list = this.world.getEntities(this, axisalignedbb); + + return list.size() > 0 ? false : !this.world.c(axisalignedbb); + } + + public void move(double d0, double d1, double d2) { + if (this.bt) { + this.boundingBox.d(d0, d1, d2); + this.locX = (this.boundingBox.a + this.boundingBox.d) / 2.0D; + this.locY = this.boundingBox.b + (double) this.height - (double) this.br; + this.locZ = (this.boundingBox.c + this.boundingBox.f) / 2.0D; + } else { + this.br *= 0.4F; + double d3 = this.locX; + double d4 = this.locZ; + + if (this.bf) { + this.bf = false; + d0 *= 0.25D; + d1 *= 0.05000000074505806D; + d2 *= 0.25D; + this.motX = 0.0D; + this.motY = 0.0D; + this.motZ = 0.0D; + } + + double d5 = d0; + double d6 = d1; + double d7 = d2; + AxisAlignedBB axisalignedbb = this.boundingBox.clone(); + boolean flag = this.onGround && this.isSneaking(); + + if (flag) { + double d8; + + for (d8 = 0.05D; d0 != 0.0D && this.world.getEntities(this, this.boundingBox.c(d0, -1.0D, 0.0D)).size() == 0; d5 = d0) { + if (d0 < d8 && d0 >= -d8) { + d0 = 0.0D; + } else if (d0 > 0.0D) { + d0 -= d8; + } else { + d0 += d8; + } + } + + for (; d2 != 0.0D && this.world.getEntities(this, this.boundingBox.c(0.0D, -1.0D, d2)).size() == 0; d7 = d2) { + if (d2 < d8 && d2 >= -d8) { + d2 = 0.0D; + } else if (d2 > 0.0D) { + d2 -= d8; + } else { + d2 += d8; + } + } + } + + List list = this.world.getEntities(this, this.boundingBox.a(d0, d1, d2)); + + for (int i = 0; i < list.size(); ++i) { + d1 = ((AxisAlignedBB) list.get(i)).b(this.boundingBox, d1); + } + + this.boundingBox.d(0.0D, d1, 0.0D); + if (!this.bg && d6 != d1) { + d2 = 0.0D; + d1 = 0.0D; + d0 = 0.0D; + } + + boolean flag1 = this.onGround || d6 != d1 && d6 < 0.0D; + + int j; + + for (j = 0; j < list.size(); ++j) { + d0 = ((AxisAlignedBB) list.get(j)).a(this.boundingBox, d0); + } + + this.boundingBox.d(d0, 0.0D, 0.0D); + if (!this.bg && d5 != d0) { + d2 = 0.0D; + d1 = 0.0D; + d0 = 0.0D; + } + + for (j = 0; j < list.size(); ++j) { + d2 = ((AxisAlignedBB) list.get(j)).c(this.boundingBox, d2); + } + + this.boundingBox.d(0.0D, 0.0D, d2); + if (!this.bg && d7 != d2) { + d2 = 0.0D; + d1 = 0.0D; + d0 = 0.0D; + } + + double d9; + double d10; + int k; + + if (this.bs > 0.0F && flag1 && (flag || this.br < 0.05F) && (d5 != d0 || d7 != d2)) { + d9 = d0; + d10 = d1; + double d11 = d2; + + d0 = d5; + d1 = (double) this.bs; + d2 = d7; + AxisAlignedBB axisalignedbb1 = this.boundingBox.clone(); + + this.boundingBox.b(axisalignedbb); + list = this.world.getEntities(this, this.boundingBox.a(d5, d1, d7)); + + for (k = 0; k < list.size(); ++k) { + d1 = ((AxisAlignedBB) list.get(k)).b(this.boundingBox, d1); + } + + this.boundingBox.d(0.0D, d1, 0.0D); + if (!this.bg && d6 != d1) { + d2 = 0.0D; + d1 = 0.0D; + d0 = 0.0D; + } + + for (k = 0; k < list.size(); ++k) { + d0 = ((AxisAlignedBB) list.get(k)).a(this.boundingBox, d0); + } + + this.boundingBox.d(d0, 0.0D, 0.0D); + if (!this.bg && d5 != d0) { + d2 = 0.0D; + d1 = 0.0D; + d0 = 0.0D; + } + + for (k = 0; k < list.size(); ++k) { + d2 = ((AxisAlignedBB) list.get(k)).c(this.boundingBox, d2); + } + + this.boundingBox.d(0.0D, 0.0D, d2); + if (!this.bg && d7 != d2) { + d2 = 0.0D; + d1 = 0.0D; + d0 = 0.0D; + } + + if (!this.bg && d6 != d1) { + d2 = 0.0D; + d1 = 0.0D; + d0 = 0.0D; + } else { + d1 = (double) (-this.bs); + + for (k = 0; k < list.size(); ++k) { + d1 = ((AxisAlignedBB) list.get(k)).b(this.boundingBox, d1); + } + + this.boundingBox.d(0.0D, d1, 0.0D); + } + + if (d9 * d9 + d11 * d11 >= d0 * d0 + d2 * d2) { + d0 = d9; + d1 = d10; + d2 = d11; + this.boundingBox.b(axisalignedbb1); + } else { + double d12 = this.boundingBox.b - (double) ((int) this.boundingBox.b); + + if (d12 > 0.0D) { + this.br = (float) ((double) this.br + d12 + 0.01D); + } + } + } + + this.locX = (this.boundingBox.a + this.boundingBox.d) / 2.0D; + this.locY = this.boundingBox.b + (double) this.height - (double) this.br; + this.locZ = (this.boundingBox.c + this.boundingBox.f) / 2.0D; + this.positionChanged = d5 != d0 || d7 != d2; + this.bc = d6 != d1; + this.onGround = d6 != d1 && d6 < 0.0D; + this.bd = this.positionChanged || this.bc; + this.a(d1, this.onGround); + if (d5 != d0) { + this.motX = 0.0D; + } + + if (d6 != d1) { + this.motY = 0.0D; + } + + if (d7 != d2) { + this.motZ = 0.0D; + } + + d9 = this.locX - d3; + d10 = this.locZ - d4; + int l; + int i1; + int j1; + + // CraftBukkit start + if ((this.positionChanged) && (this.getBukkitEntity() instanceof Vehicle)) { + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); + org.bukkit.block.Block block = this.world.getWorld().getBlockAt(MathHelper.floor(this.locX), MathHelper.floor(this.locY - 0.20000000298023224D - (double) this.height), MathHelper.floor(this.locZ)); + + if (d5 > d0) { + block = block.getRelative(BlockFace.SOUTH); + } else if (d5 < d0) { + block = block.getRelative(BlockFace.NORTH); + } else if (d7 > d2) { + block = block.getRelative(BlockFace.WEST); + } else if (d7 < d2) { + block = block.getRelative(BlockFace.EAST); + } + + VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, block); + this.world.getServer().getPluginManager().callEvent(event); + } + // CraftBukkit end + + if (this.n() && !flag && this.vehicle == null) { + this.bm = (float) ((double) this.bm + (double) MathHelper.a(d9 * d9 + d10 * d10) * 0.6D); + l = MathHelper.floor(this.locX); + i1 = MathHelper.floor(this.locY - 0.20000000298023224D - (double) this.height); + j1 = MathHelper.floor(this.locZ); + k = this.world.getTypeId(l, i1, j1); + if (this.world.getTypeId(l, i1 - 1, j1) == Block.FENCE.id) { + k = this.world.getTypeId(l, i1 - 1, j1); + } + + if (this.bm > (float) this.b && k > 0) { + ++this.b; + StepSound stepsound = Block.byId[k].stepSound; + + if (this.world.getTypeId(l, i1 + 1, j1) == Block.SNOW.id) { + stepsound = Block.SNOW.stepSound; + this.world.makeSound(this, stepsound.getName(), stepsound.getVolume1() * 0.15F, stepsound.getVolume2()); + } else if (!Block.byId[k].material.isLiquid()) { + this.world.makeSound(this, stepsound.getName(), stepsound.getVolume1() * 0.15F, stepsound.getVolume2()); + } + + Block.byId[k].b(this.world, l, i1, j1, this); + } + } + + l = MathHelper.floor(this.boundingBox.a + 0.0010D); + i1 = MathHelper.floor(this.boundingBox.b + 0.0010D); + j1 = MathHelper.floor(this.boundingBox.c + 0.0010D); + k = MathHelper.floor(this.boundingBox.d - 0.0010D); + int k1 = MathHelper.floor(this.boundingBox.e - 0.0010D); + int l1 = MathHelper.floor(this.boundingBox.f - 0.0010D); + + if (this.world.a(l, i1, j1, k, k1, l1)) { + for (int i2 = l; i2 <= k; ++i2) { + for (int j2 = i1; j2 <= k1; ++j2) { + for (int k2 = j1; k2 <= l1; ++k2) { + int l2 = this.world.getTypeId(i2, j2, k2); + + if (l2 > 0) { + Block.byId[l2].a(this.world, i2, j2, k2, this); + } + } + } + } + } + + boolean flag2 = this.ac(); + + if (this.world.d(this.boundingBox.shrink(0.0010D, 0.0010D, 0.0010D))) { + this.burn(1); + if (!flag2) { + ++this.fireTicks; + // CraftBukkit start - not on fire yet + if (this.fireTicks <= 0) { + EntityCombustEvent event = new EntityCombustEvent(this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.fireTicks = 300; + } + } else { + // CraftBukkit end - reset fire level back to max + this.fireTicks = 300; + } + } + } else if (this.fireTicks <= 0) { + this.fireTicks = -this.maxFireTicks; + } + + if (flag2 && this.fireTicks > 0) { + this.world.makeSound(this, "random.fizz", 0.7F, 1.6F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F); + this.fireTicks = -this.maxFireTicks; + } + } + } + + protected boolean n() { + return true; + } + + protected void a(double d0, boolean flag) { + if (flag) { + if (this.fallDistance > 0.0F) { + this.a(this.fallDistance); + this.fallDistance = 0.0F; + } + } else if (d0 < 0.0D) { + this.fallDistance = (float) ((double) this.fallDistance - d0); + } + } + + public AxisAlignedBB e_() { + return null; + } + + protected void burn(int i) { + if (!this.fireProof) { + // CraftBukkit start + if (this instanceof EntityLiving) { + EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.FIRE, i); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + i = event.getDamage(); + } + // CraftBukkit end + this.damageEntity((Entity) null, i); + } + } + + protected void a(float f) { + if (this.passenger != null) { + this.passenger.a(f); + } + } + + public boolean ac() { + return this.bA || this.world.s(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)); + } + + public boolean ad() { + return this.bA; + } + + public boolean f_() { + return this.world.a(this.boundingBox.b(0.0D, -0.4000000059604645D, 0.0D).shrink(0.0010D, 0.0010D, 0.0010D), Material.WATER, this); + } + + public boolean a(Material material) { + double d0 = this.locY + (double) this.t(); + int i = MathHelper.floor(this.locX); + int j = MathHelper.d((float) MathHelper.floor(d0)); + int k = MathHelper.floor(this.locZ); + int l = this.world.getTypeId(i, j, k); + + if (l != 0 && Block.byId[l].material == material) { + float f = BlockFluids.c(this.world.getData(i, j, k)) - 0.11111111F; + float f1 = (float) (j + 1) - f; + + return d0 < (double) f1; + } else { + return false; + } + } + + public float t() { + return 0.0F; + } + + public boolean ae() { + return this.world.a(this.boundingBox.b(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.LAVA); + } + + public void a(float f, float f1, float f2) { + float f3 = MathHelper.c(f * f + f1 * f1); + + if (f3 >= 0.01F) { + if (f3 < 1.0F) { + f3 = 1.0F; + } + + f3 = f2 / f3; + f *= f3; + f1 *= f3; + float f4 = MathHelper.sin(this.yaw * 3.1415927F / 180.0F); + float f5 = MathHelper.cos(this.yaw * 3.1415927F / 180.0F); + + this.motX += (double) (f * f5 - f1 * f4); + this.motZ += (double) (f1 * f5 + f * f4); + } + } + + public float c(float f) { + int i = MathHelper.floor(this.locX); + double d0 = (this.boundingBox.e - this.boundingBox.b) * 0.66D; + int j = MathHelper.floor(this.locY - (double) this.height + d0); + int k = MathHelper.floor(this.locZ); + + if (this.world.a(MathHelper.floor(this.boundingBox.a), MathHelper.floor(this.boundingBox.b), MathHelper.floor(this.boundingBox.c), MathHelper.floor(this.boundingBox.d), MathHelper.floor(this.boundingBox.e), MathHelper.floor(this.boundingBox.f))) { + float f1 = this.world.n(i, j, k); + + if (f1 < this.bF) { + f1 = this.bF; + } + + return f1; + } else { + return this.bF; + } + } + + public void spawnIn(World world) { + // CraftBukkit start + if (world == null) { + this.die(); + this.world = ((org.bukkit.craftbukkit.CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle(); + return; + } + // CraftBukkit end + this.world = world; + } + + public void setLocation(double d0, double d1, double d2, float f, float f1) { + this.lastX = this.locX = d0; + this.lastY = this.locY = d1; + this.lastZ = this.locZ = d2; + this.lastYaw = this.yaw = f; + this.lastPitch = this.pitch = f1; + this.br = 0.0F; + double d3 = (double) (this.lastYaw - f); + + if (d3 < -180.0D) { + this.lastYaw += 360.0F; + } + + if (d3 >= 180.0D) { + this.lastYaw -= 360.0F; + } + + this.setPosition(this.locX, this.locY, this.locZ); + this.c(f, f1); + } + + public void setPositionRotation(double d0, double d1, double d2, float f, float f1) { + this.bo = this.lastX = this.locX = d0; + this.bp = this.lastY = this.locY = d1 + (double) this.height; + this.bq = this.lastZ = this.locZ = d2; + this.yaw = f; + this.pitch = f1; + this.setPosition(this.locX, this.locY, this.locZ); + } + + public float f(Entity entity) { + float f = (float) (this.locX - entity.locX); + float f1 = (float) (this.locY - entity.locY); + float f2 = (float) (this.locZ - entity.locZ); + + return MathHelper.c(f * f + f1 * f1 + f2 * f2); + } + + public double e(double d0, double d1, double d2) { + double d3 = this.locX - d0; + double d4 = this.locY - d1; + double d5 = this.locZ - d2; + + return d3 * d3 + d4 * d4 + d5 * d5; + } + + public double f(double d0, double d1, double d2) { + double d3 = this.locX - d0; + double d4 = this.locY - d1; + double d5 = this.locZ - d2; + + return (double) MathHelper.a(d3 * d3 + d4 * d4 + d5 * d5); + } + + public double g(Entity entity) { + double d0 = this.locX - entity.locX; + double d1 = this.locY - entity.locY; + double d2 = this.locZ - entity.locZ; + + return d0 * d0 + d1 * d1 + d2 * d2; + } + + public void b(EntityHuman entityhuman) {} + + public void collide(Entity entity) { + if (entity.passenger != this && entity.vehicle != this) { + double d0 = entity.locX - this.locX; + double d1 = entity.locZ - this.locZ; + double d2 = MathHelper.a(d0, d1); + + if (d2 >= 0.009999999776482582D) { + d2 = (double) MathHelper.a(d2); + d0 /= d2; + d1 /= d2; + double d3 = 1.0D / d2; + + if (d3 > 1.0D) { + d3 = 1.0D; + } + + d0 *= d3; + d1 *= d3; + d0 *= 0.05000000074505806D; + d1 *= 0.05000000074505806D; + d0 *= (double) (1.0F - this.bu); + d1 *= (double) (1.0F - this.bu); + this.b(-d0, 0.0D, -d1); + entity.b(d0, 0.0D, d1); + } + } + } + + public void b(double d0, double d1, double d2) { + this.motX += d0; + this.motY += d1; + this.motZ += d2; + this.airBorne = true; + } + + protected void af() { + this.velocityChanged = true; + } + + public boolean damageEntity(Entity entity, int i) { + this.af(); + return false; + } + + public boolean l_() { + return false; + } + + public boolean d_() { + return false; + } + + public void c(Entity entity, int i) {} + + public boolean c(NBTTagCompound nbttagcompound) { + String s = this.ag(); + + if (!this.dead && s != null) { + nbttagcompound.setString("id", s); + this.d(nbttagcompound); + return true; + } else { + return false; + } + } + + public void d(NBTTagCompound nbttagcompound) { + nbttagcompound.a("Pos", (NBTBase) this.a(new double[] { this.locX, this.locY + (double) this.br, this.locZ})); + nbttagcompound.a("Motion", (NBTBase) this.a(new double[] { this.motX, this.motY, this.motZ})); + + // CraftBukkit start - checking for NaN pitch/yaw and resetting to zero + // TODO: make sure this is the best way to address this. + if (Float.isNaN(this.yaw)) { + this.yaw = 0; + } + + if (Float.isNaN(this.pitch)) { + this.pitch = 0; + } + // CraftBukkit end + + nbttagcompound.a("Rotation", (NBTBase) this.a(new float[] { this.yaw, this.pitch})); + nbttagcompound.a("FallDistance", this.fallDistance); + nbttagcompound.a("Fire", (short) this.fireTicks); + nbttagcompound.a("Air", (short) this.airTicks); + nbttagcompound.a("OnGround", this.onGround); + // CraftBukkit start + nbttagcompound.setLong("WorldUUIDLeast", this.world.getUUID().getLeastSignificantBits()); + nbttagcompound.setLong("WorldUUIDMost", this.world.getUUID().getMostSignificantBits()); + nbttagcompound.setLong("UUIDLeast", this.uniqueId.getLeastSignificantBits()); + nbttagcompound.setLong("UUIDMost", this.uniqueId.getMostSignificantBits()); + // CraftBukkit end + this.b(nbttagcompound); + } + + public void e(NBTTagCompound nbttagcompound) { + NBTTagList nbttaglist = nbttagcompound.l("Pos"); + NBTTagList nbttaglist1 = nbttagcompound.l("Motion"); + NBTTagList nbttaglist2 = nbttagcompound.l("Rotation"); + + this.motX = ((NBTTagDouble) nbttaglist1.a(0)).a; + this.motY = ((NBTTagDouble) nbttaglist1.a(1)).a; + this.motZ = ((NBTTagDouble) nbttaglist1.a(2)).a; + /* CraftBukkit start - moved section down + if (Math.abs(this.motX) > 10.0D) { + this.motX = 0.0D; + } + + if (Math.abs(this.motY) > 10.0D) { + this.motY = 0.0D; + } + + if (Math.abs(this.motZ) > 10.0D) { + this.motZ = 0.0D; + } + // CraftBukkit end */ + + this.lastX = this.bo = this.locX = ((NBTTagDouble) nbttaglist.a(0)).a; + this.lastY = this.bp = this.locY = ((NBTTagDouble) nbttaglist.a(1)).a; + this.lastZ = this.bq = this.locZ = ((NBTTagDouble) nbttaglist.a(2)).a; + this.lastYaw = this.yaw = ((NBTTagFloat) nbttaglist2.a(0)).a; + this.lastPitch = this.pitch = ((NBTTagFloat) nbttaglist2.a(1)).a; + this.fallDistance = nbttagcompound.g("FallDistance"); + this.fireTicks = nbttagcompound.d("Fire"); + this.airTicks = nbttagcompound.d("Air"); + this.onGround = nbttagcompound.m("OnGround"); + this.setPosition(this.locX, this.locY, this.locZ); + + // CraftBukkit start + long least = nbttagcompound.getLong("UUIDLeast"); + long most = nbttagcompound.getLong("UUIDMost"); + + if (least != 0L && most != 0L) { + this.uniqueId = new UUID(most, least); + } + // CraftBukkit end + + this.c(this.yaw, this.pitch); + this.a(nbttagcompound); + + // CraftBukkit start - Exempt Vehicles from notch's sanity check + if (!(this.getBukkitEntity() instanceof Vehicle)) { + if (Math.abs(this.motX) > 10.0D) { + this.motX = 0.0D; + } + + if (Math.abs(this.motY) > 10.0D) { + this.motY = 0.0D; + } + + if (Math.abs(this.motZ) > 10.0D) { + this.motZ = 0.0D; + } + } + // CraftBukkit end + + // CraftBukkit start - reset world + if (this instanceof EntityPlayer) { + org.bukkit.Server server = Bukkit.getServer(); + org.bukkit.World bworld = null; + + // TODO: Remove World related checks, replaced with WorldUID. + String worldName = nbttagcompound.getString("World"); + + if (nbttagcompound.hasKey("WorldUUIDMost") && nbttagcompound.hasKey("WorldUUIDLeast")) { + UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast")); + bworld = server.getWorld(uid); + } else { + bworld = server.getWorld(worldName); + } + if (bworld == null) { + EntityPlayer entityPlayer = (EntityPlayer) this; + bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(entityPlayer.dimension).getWorld(); + } + + this.spawnIn(bworld == null ? null : ((org.bukkit.craftbukkit.CraftWorld) bworld).getHandle()); + } + // CraftBukkit end + } + + protected final String ag() { + return EntityTypes.b(this); + } + + protected abstract void a(NBTTagCompound nbttagcompound); + + protected abstract void b(NBTTagCompound nbttagcompound); + + protected NBTTagList a(double... adouble) { + NBTTagList nbttaglist = new NBTTagList(); + double[] adouble1 = adouble; + int i = adouble.length; + + for (int j = 0; j < i; ++j) { + double d0 = adouble1[j]; + + nbttaglist.a((NBTBase) (new NBTTagDouble(d0))); + } + + return nbttaglist; + } + + protected NBTTagList a(float... afloat) { + NBTTagList nbttaglist = new NBTTagList(); + float[] afloat1 = afloat; + int i = afloat.length; + + for (int j = 0; j < i; ++j) { + float f = afloat1[j]; + + nbttaglist.a((NBTBase) (new NBTTagFloat(f))); + } + + return nbttaglist; + } + + public EntityItem b(int i, int j) { + return this.a(i, j, 0.0F); + } + + public EntityItem a(int i, int j, float f) { + return this.a(new ItemStack(i, j, 0), f); + } + + public EntityItem a(ItemStack itemstack, float f) { + EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY + (double) f, this.locZ, itemstack); + + entityitem.pickupDelay = 10; + this.world.addEntity(entityitem); + return entityitem; + } + + public boolean T() { + return !this.dead; + } + + public boolean K() { + for (int i = 0; i < 8; ++i) { + float f = ((float) ((i >> 0) % 2) - 0.5F) * this.length * 0.9F; + float f1 = ((float) ((i >> 1) % 2) - 0.5F) * 0.1F; + float f2 = ((float) ((i >> 2) % 2) - 0.5F) * this.length * 0.9F; + int j = MathHelper.floor(this.locX + (double) f); + int k = MathHelper.floor(this.locY + (double) this.t() + (double) f1); + int l = MathHelper.floor(this.locZ + (double) f2); + + if (this.world.e(j, k, l)) { + return true; + } + } + + return false; + } + + public boolean a(EntityHuman entityhuman) { + return false; + } + + public AxisAlignedBB a_(Entity entity) { + return null; + } + + public void E() { + if (this.vehicle.dead) { + this.vehicle = null; + } else { + this.motX = 0.0D; + this.motY = 0.0D; + this.motZ = 0.0D; + this.m_(); + if (this.vehicle != null) { + this.vehicle.f(); + this.e += (double) (this.vehicle.yaw - this.vehicle.lastYaw); + + for (this.d += (double) (this.vehicle.pitch - this.vehicle.lastPitch); this.e >= 180.0D; this.e -= 360.0D) { + ; + } + + while (this.e < -180.0D) { + this.e += 360.0D; + } + + while (this.d >= 180.0D) { + this.d -= 360.0D; + } + + while (this.d < -180.0D) { + this.d += 360.0D; + } + + double d0 = this.e * 0.5D; + double d1 = this.d * 0.5D; + float f = 10.0F; + + if (d0 > (double) f) { + d0 = (double) f; + } + + if (d0 < (double) (-f)) { + d0 = (double) (-f); + } + + if (d1 > (double) f) { + d1 = (double) f; + } + + if (d1 < (double) (-f)) { + d1 = (double) (-f); + } + + this.e -= d0; + this.d -= d1; + this.yaw = (float) ((double) this.yaw + d0); + this.pitch = (float) ((double) this.pitch + d1); + } + } + } + + public void f() { + this.passenger.setPosition(this.locX, this.locY + this.m() + this.passenger.I(), this.locZ); + } + + public double I() { + return (double) this.height; + } + + public double m() { + return (double) this.width * 0.75D; + } + + public void mount(Entity entity) { + // CraftBukkit start + this.setPassengerOf(entity); + } + + protected org.bukkit.entity.Entity bukkitEntity; + + public org.bukkit.entity.Entity getBukkitEntity() { + if (this.bukkitEntity == null) { + this.bukkitEntity = org.bukkit.craftbukkit.entity.CraftEntity.getEntity(this.world.getServer(), this); + } + return this.bukkitEntity; + } + + public void setPassengerOf(Entity entity) { + // b(null) doesn't really fly for overloaded methods, + // so this method is needed + + // CraftBukkit end + this.d = 0.0D; + this.e = 0.0D; + if (entity == null) { + if (this.vehicle != null) { + // CraftBukkit start + if ((this.getBukkitEntity() instanceof LivingEntity) && (this.vehicle.getBukkitEntity() instanceof Vehicle)) { + VehicleExitEvent event = new VehicleExitEvent((Vehicle) this.vehicle.getBukkitEntity(), (LivingEntity) this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + } + // CraftBukkit end + + this.setPositionRotation(this.vehicle.locX, this.vehicle.boundingBox.b + (double) this.vehicle.width, this.vehicle.locZ, this.yaw, this.pitch); + this.vehicle.passenger = null; + } + + this.vehicle = null; + } else if (this.vehicle == entity) { + // CraftBukkit start + if ((this.getBukkitEntity() instanceof LivingEntity) && (this.vehicle.getBukkitEntity() instanceof Vehicle)) { + VehicleExitEvent event = new VehicleExitEvent((Vehicle) this.vehicle.getBukkitEntity(), (LivingEntity) this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + } + // CraftBukkit end + + this.vehicle.passenger = null; + this.vehicle = null; + this.setPositionRotation(entity.locX, entity.boundingBox.b + (double) entity.width, entity.locZ, this.yaw, this.pitch); + } else { + if (this.vehicle != null) { + this.vehicle.passenger = null; + } + + if (entity.passenger != null) { + entity.passenger.vehicle = null; + } + + this.vehicle = entity; + entity.passenger = this; + } + } + + public Vec3D Z() { + return null; + } + + public void P() {} + + public ItemStack[] getEquipment() { + return null; + } + + public boolean isSneaking() { + return this.d(1); + } + + public void setSneak(boolean flag) { + this.a(1, flag); + } + + protected boolean d(int i) { + return (this.datawatcher.a(0) & 1 << i) != 0; + } + + protected void a(int i, boolean flag) { + byte b0 = this.datawatcher.a(0); + + if (flag) { + this.datawatcher.watch(0, Byte.valueOf((byte) (b0 | 1 << i))); + } else { + this.datawatcher.watch(0, Byte.valueOf((byte) (b0 & ~(1 << i)))); + } + } + + public void a(EntityWeatherStorm entityweatherstorm) { + // CraftBukkit start + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(entityweatherstorm.getBukkitEntity(), this.getBukkitEntity(), EntityDamageEvent.DamageCause.LIGHTNING, 5); + Bukkit.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + this.burn(event.getDamage()); + // CraftBukkit end + + ++this.fireTicks; + if (this.fireTicks == 0) { + this.fireTicks = 300; + } + } + + public void a(EntityLiving entityliving) {} + + protected boolean g(double d0, double d1, double d2) { + int i = MathHelper.floor(d0); + int j = MathHelper.floor(d1); + int k = MathHelper.floor(d2); + double d3 = d0 - (double) i; + double d4 = d1 - (double) j; + double d5 = d2 - (double) k; + + if (this.world.e(i, j, k)) { + boolean flag = !this.world.e(i - 1, j, k); + boolean flag1 = !this.world.e(i + 1, j, k); + boolean flag2 = !this.world.e(i, j - 1, k); + boolean flag3 = !this.world.e(i, j + 1, k); + boolean flag4 = !this.world.e(i, j, k - 1); + boolean flag5 = !this.world.e(i, j, k + 1); + byte b0 = -1; + double d6 = 9999.0D; + + if (flag && d3 < d6) { + d6 = d3; + b0 = 0; + } + + if (flag1 && 1.0D - d3 < d6) { + d6 = 1.0D - d3; + b0 = 1; + } + + if (flag2 && d4 < d6) { + d6 = d4; + b0 = 2; + } + + if (flag3 && 1.0D - d4 < d6) { + d6 = 1.0D - d4; + b0 = 3; + } + + if (flag4 && d5 < d6) { + d6 = d5; + b0 = 4; + } + + if (flag5 && 1.0D - d5 < d6) { + d6 = 1.0D - d5; + b0 = 5; + } + + float f = this.random.nextFloat() * 0.2F + 0.1F; + + if (b0 == 0) { + this.motX = (double) (-f); + } + + if (b0 == 1) { + this.motX = (double) f; + } + + if (b0 == 2) { + this.motY = (double) (-f); + } + + if (b0 == 3) { + this.motY = (double) f; + } + + if (b0 == 4) { + this.motZ = (double) (-f); + } + + if (b0 == 5) { + this.motZ = (double) f; + } + } + + return false; + } +} diff --git a/src/main/java/net/minecraft/server/EntityAnimal.java b/src/main/java/net/minecraft/server/EntityAnimal.java new file mode 100644 index 0000000..1d42583 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityAnimal.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +public abstract class EntityAnimal extends EntityCreature implements IAnimal { + + public EntityAnimal(World world) { + super(world); + } + + protected float a(int i, int j, int k) { + return this.world.getTypeId(i, j - 1, k) == Block.GRASS.id ? 10.0F : this.world.n(i, j, k) - 0.5F; + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + public boolean d() { + int i = MathHelper.floor(this.locX); + int j = MathHelper.floor(this.boundingBox.b); + int k = MathHelper.floor(this.locZ); + + return this.world.getTypeId(i, j - 1, k) == Block.GRASS.id && this.world.k(i, j, k) > 8 && super.d(); + } + + public int e() { + return 120; + } +} diff --git a/src/main/java/net/minecraft/server/EntityArrow.java b/src/main/java/net/minecraft/server/EntityArrow.java new file mode 100644 index 0000000..3795a93 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityArrow.java @@ -0,0 +1,317 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.entity.CraftLivingEntity; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityArrow extends Entity { + + private int d = -1; + private int e = -1; + private int f = -1; + private int g = 0; + private int h = 0; + private boolean inGround = false; + public boolean fromPlayer = false; + public int shake = 0; + public EntityLiving shooter; + private int j; + private int k = 0; + + public EntityArrow(World world) { + super(world); + this.b(0.5F, 0.5F); + } + + public EntityArrow(World world, double d0, double d1, double d2) { + super(world); + this.b(0.5F, 0.5F); + this.setPosition(d0, d1, d2); + this.height = 0.0F; + } + + public EntityArrow(World world, EntityLiving entityliving) { + super(world); + this.shooter = entityliving; + this.fromPlayer = entityliving instanceof EntityHuman; + this.b(0.5F, 0.5F); + this.setPositionRotation(entityliving.locX, entityliving.locY + (double) entityliving.t(), entityliving.locZ, entityliving.yaw, entityliving.pitch); + this.locX -= (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.locY -= 0.10000000149011612D; + this.locZ -= (double) (MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.setPosition(this.locX, this.locY, this.locZ); + this.height = 0.0F; + this.motX = (double) (-MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F)); + this.motZ = (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F)); + this.motY = (double) (-MathHelper.sin(this.pitch / 180.0F * 3.1415927F)); + this.a(this.motX, this.motY, this.motZ, 1.5F, 1.0F); + } + + protected void b() {} + + public void a(double d0, double d1, double d2, float f, float f1) { + float f2 = MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + + d0 /= (double) f2; + d1 /= (double) f2; + d2 /= (double) f2; + d0 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d1 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d2 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d0 *= (double) f; + d1 *= (double) f; + d2 *= (double) f; + this.motX = d0; + this.motY = d1; + this.motZ = d2; + float f3 = MathHelper.a(d0 * d0 + d2 * d2); + + this.lastYaw = this.yaw = (float) (Math.atan2(d0, d2) * 180.0D / 3.1415927410125732D); + this.lastPitch = this.pitch = (float) (Math.atan2(d1, (double) f3) * 180.0D / 3.1415927410125732D); + this.j = 0; + } + + public void m_() { + super.m_(); + if (this.lastPitch == 0.0F && this.lastYaw == 0.0F) { + float f = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + + this.lastYaw = this.yaw = (float) (Math.atan2(this.motX, this.motZ) * 180.0D / 3.1415927410125732D); + this.lastPitch = this.pitch = (float) (Math.atan2(this.motY, (double) f) * 180.0D / 3.1415927410125732D); + } + + int i = this.world.getTypeId(this.d, this.e, this.f); + + if (i > 0) { + Block.byId[i].a(this.world, this.d, this.e, this.f); + AxisAlignedBB axisalignedbb = Block.byId[i].e(this.world, this.d, this.e, this.f); + + if (axisalignedbb != null && axisalignedbb.a(Vec3D.create(this.locX, this.locY, this.locZ))) { + this.inGround = true; + } + } + + if (this.shake > 0) { + --this.shake; + } + + if (this.inGround) { + i = this.world.getTypeId(this.d, this.e, this.f); + int j = this.world.getData(this.d, this.e, this.f); + + if (i == this.g && j == this.h) { + ++this.j; + if (this.j == 1200) { + this.die(); + } + } else { + this.inGround = false; + this.motX *= (double) (this.random.nextFloat() * 0.2F); + this.motY *= (double) (this.random.nextFloat() * 0.2F); + this.motZ *= (double) (this.random.nextFloat() * 0.2F); + this.j = 0; + this.k = 0; + } + } else { + ++this.k; + Vec3D vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + Vec3D vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + MovingObjectPosition movingobjectposition = this.world.rayTrace(vec3d, vec3d1, false, true); + + vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + if (movingobjectposition != null) { + vec3d1 = Vec3D.create(movingobjectposition.f.a, movingobjectposition.f.b, movingobjectposition.f.c); + } + + Entity entity = null; + List list = this.world.b((Entity) this, this.boundingBox.a(this.motX, this.motY, this.motZ).b(1.0D, 1.0D, 1.0D)); + double d0 = 0.0D; + + float f1; + + for (int k = 0; k < list.size(); ++k) { + Entity entity1 = (Entity) list.get(k); + + if (entity1.l_() && (entity1 != this.shooter || this.k >= 5)) { + f1 = 0.3F; + AxisAlignedBB axisalignedbb1 = entity1.boundingBox.b((double) f1, (double) f1, (double) f1); + MovingObjectPosition movingobjectposition1 = axisalignedbb1.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { + double d1 = vec3d.a(movingobjectposition1.f); + + if (d1 < d0 || d0 == 0.0D) { + entity = entity1; + d0 = d1; + } + } + } + } + + if (entity != null) { + movingobjectposition = new MovingObjectPosition(entity); + } + + float f2; + + if (movingobjectposition != null) { + // CraftBukkit start + ProjectileHitEvent phe = new ProjectileHitEvent((Projectile) this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(phe); + // CraftBukkit end + if (movingobjectposition.entity != null) { + // CraftBukkit start + boolean stick; + if (entity instanceof EntityLiving) { + org.bukkit.Server server = this.world.getServer(); + + // TODO decide if we should create DamageCause.ARROW, DamageCause.PROJECTILE + // or leave as DamageCause.ENTITY_ATTACK + org.bukkit.entity.Entity damagee = movingobjectposition.entity.getBukkitEntity(); + Projectile projectile = (Projectile) this.getBukkitEntity(); + // TODO deal with arrows being fired from a non-entity + + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(projectile, damagee, EntityDamageEvent.DamageCause.PROJECTILE, 4); + server.getPluginManager().callEvent(event); + this.shooter = (projectile.getShooter() == null) ? null : ((CraftLivingEntity) projectile.getShooter()).getHandle(); + + if (event.isCancelled()) { + stick = !projectile.doesBounce(); + } else { + // this function returns if the arrow should stick in or not, i.e. !bounce + stick = movingobjectposition.entity.damageEntity(this, event.getDamage()); + } + } else { + stick = movingobjectposition.entity.damageEntity(this.shooter, 4); + } + if (stick) { + // CraftBukkit end + this.world.makeSound(this, "random.drr", 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); + this.die(); + } else { + this.motX *= -0.10000000149011612D; + this.motY *= -0.10000000149011612D; + this.motZ *= -0.10000000149011612D; + this.yaw += 180.0F; + this.lastYaw += 180.0F; + this.k = 0; + } + } else { + this.d = movingobjectposition.b; + this.e = movingobjectposition.c; + this.f = movingobjectposition.d; + this.g = this.world.getTypeId(this.d, this.e, this.f); + this.h = this.world.getData(this.d, this.e, this.f); + this.motX = (double) ((float) (movingobjectposition.f.a - this.locX)); + this.motY = (double) ((float) (movingobjectposition.f.b - this.locY)); + this.motZ = (double) ((float) (movingobjectposition.f.c - this.locZ)); + f2 = MathHelper.a(this.motX * this.motX + this.motY * this.motY + this.motZ * this.motZ); + this.locX -= this.motX / (double) f2 * 0.05000000074505806D; + this.locY -= this.motY / (double) f2 * 0.05000000074505806D; + this.locZ -= this.motZ / (double) f2 * 0.05000000074505806D; + this.world.makeSound(this, "random.drr", 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); + this.inGround = true; + this.shake = 7; + } + } + + this.locX += this.motX; + this.locY += this.motY; + this.locZ += this.motZ; + f2 = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + this.yaw = (float) (Math.atan2(this.motX, this.motZ) * 180.0D / 3.1415927410125732D); + + for (this.pitch = (float) (Math.atan2(this.motY, (double) f2) * 180.0D / 3.1415927410125732D); this.pitch - this.lastPitch < -180.0F; this.lastPitch -= 360.0F) { + ; + } + + while (this.pitch - this.lastPitch >= 180.0F) { + this.lastPitch += 360.0F; + } + + while (this.yaw - this.lastYaw < -180.0F) { + this.lastYaw -= 360.0F; + } + + while (this.yaw - this.lastYaw >= 180.0F) { + this.lastYaw += 360.0F; + } + + this.pitch = this.lastPitch + (this.pitch - this.lastPitch) * 0.2F; + this.yaw = this.lastYaw + (this.yaw - this.lastYaw) * 0.2F; + float f3 = 0.99F; + + f1 = 0.03F; + if (this.ad()) { + for (int l = 0; l < 4; ++l) { + float f4 = 0.25F; + + this.world.a("bubble", this.locX - this.motX * (double) f4, this.locY - this.motY * (double) f4, this.locZ - this.motZ * (double) f4, this.motX, this.motY, this.motZ); + } + + f3 = 0.8F; + } + + this.motX *= (double) f3; + this.motY *= (double) f3; + this.motZ *= (double) f3; + this.motY -= (double) f1; + this.setPosition(this.locX, this.locY, this.locZ); + } + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("xTile", (short) this.d); + nbttagcompound.a("yTile", (short) this.e); + nbttagcompound.a("zTile", (short) this.f); + nbttagcompound.a("inTile", (byte) this.g); + nbttagcompound.a("inData", (byte) this.h); + nbttagcompound.a("shake", (byte) this.shake); + nbttagcompound.a("inGround", (byte) (this.inGround ? 1 : 0)); + nbttagcompound.a("player", this.fromPlayer); + } + + public void a(NBTTagCompound nbttagcompound) { + this.d = nbttagcompound.d("xTile"); + this.e = nbttagcompound.d("yTile"); + this.f = nbttagcompound.d("zTile"); + this.g = nbttagcompound.c("inTile") & 255; + this.h = nbttagcompound.c("inData") & 255; + this.shake = nbttagcompound.c("shake") & 255; + this.inGround = nbttagcompound.c("inGround") == 1; + this.fromPlayer = nbttagcompound.m("player"); + } + + public void b(EntityHuman entityhuman) { + if (!this.world.isStatic) { + // CraftBukkit start + ItemStack itemstack = new ItemStack(Item.ARROW, 1); + if (this.inGround && this.fromPlayer && this.shake <= 0 && entityhuman.inventory.canHold(itemstack) > 0) { + net.minecraft.server.EntityItem item = new net.minecraft.server.EntityItem(this.world, this.locX, this.locY, this.locZ, itemstack); + + PlayerPickupItemEvent event = new PlayerPickupItemEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), new org.bukkit.craftbukkit.entity.CraftItem(this.world.getServer(), item), 0); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + } + // CraftBukkit end + + if (this.inGround && this.fromPlayer && this.shake <= 0 && entityhuman.inventory.pickup(new ItemStack(Item.ARROW, 1))) { + this.world.makeSound(this, "random.pop", 0.2F, ((this.random.nextFloat() - this.random.nextFloat()) * 0.7F + 1.0F) * 2.0F); + entityhuman.receive(this, 1); + this.die(); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityBoat.java b/src/main/java/net/minecraft/server/EntityBoat.java new file mode 100644 index 0000000..ab2d5cb --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityBoat.java @@ -0,0 +1,412 @@ +package net.minecraft.server; + +import org.bukkit.Location; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.vehicle.*; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityBoat extends Entity { + + public int damage; + public int b; + public int c; + private int d; + private double e; + private double f; + private double g; + private double h; + private double i; + + // CraftBukkit start + public double maxSpeed = 0.4D; + + @Override + public void collide(Entity entity) { + org.bukkit.entity.Entity hitEntity = (entity == null) ? null : entity.getBukkitEntity(); + + VehicleEntityCollisionEvent event = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), hitEntity); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + super.collide(entity); + } + // CraftBukkit end + + public EntityBoat(World world) { + super(world); + this.damage = 0; + this.b = 0; + this.c = 1; + this.aI = true; + this.b(1.5F, 0.6F); + this.height = this.width / 2.0F; + } + + protected boolean n() { + return false; + } + + protected void b() {} + + public AxisAlignedBB a_(Entity entity) { + return entity.boundingBox; + } + + public AxisAlignedBB e_() { + return this.boundingBox; + } + + public boolean d_() { + return true; + } + + public EntityBoat(World world, double d0, double d1, double d2) { + this(world); + this.setPosition(d0, d1 + (double) this.height, d2); + this.motX = 0.0D; + this.motY = 0.0D; + this.motZ = 0.0D; + this.lastX = d0; + this.lastY = d1; + this.lastZ = d2; + + this.world.getServer().getPluginManager().callEvent(new VehicleCreateEvent((Vehicle) this.getBukkitEntity())); // CraftBukkit + } + + public double m() { + return (double) this.width * 0.0D - 0.30000001192092896D; + } + + public boolean damageEntity(Entity entity, int i) { + if (!this.world.isStatic && !this.dead) { + // CraftBukkit start + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); + org.bukkit.entity.Entity attacker = (entity == null) ? null : entity.getBukkitEntity(); + + VehicleDamageEvent event = new VehicleDamageEvent(vehicle, attacker, i); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return true; + } + // i = event.getDamage(); // TODO Why don't we do this? + // CraftBukkit end + + this.c = -this.c; + this.b = 10; + this.damage += i * 10; + this.af(); + if (this.damage > 40) { + + // CraftBukkit start + VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, attacker); + this.world.getServer().getPluginManager().callEvent(destroyEvent); + + if (destroyEvent.isCancelled()) { + this.damage = 40; // Maximize damage so this doesn't get triggered again right away + return true; + } + // CraftBukkit end + + if (this.passenger != null) { + this.passenger.mount(this); + } + + int j; + + for (j = 0; j < 3; ++j) { + this.a(Block.WOOD.id, 1, 0.0F); + } + + for (j = 0; j < 2; ++j) { + this.a(Item.STICK.id, 1, 0.0F); + } + + this.die(); + } + + return true; + } else { + return true; + } + } + + public boolean l_() { + return !this.dead; + } + + public void m_() { + // CraftBukkit start + double prevX = this.locX; + double prevY = this.locY; + double prevZ = this.locZ; + float prevYaw = this.yaw; + float prevPitch = this.pitch; + // CraftBukkit end + + super.m_(); + if (this.b > 0) { + --this.b; + } + + if (this.damage > 0) { + --this.damage; + } + + this.lastX = this.locX; + this.lastY = this.locY; + this.lastZ = this.locZ; + byte b0 = 5; + double d0 = 0.0D; + + for (int i = 0; i < b0; ++i) { + double d1 = this.boundingBox.b + (this.boundingBox.e - this.boundingBox.b) * (double) (i + 0) / (double) b0 - 0.125D; + double d2 = this.boundingBox.b + (this.boundingBox.e - this.boundingBox.b) * (double) (i + 1) / (double) b0 - 0.125D; + AxisAlignedBB axisalignedbb = AxisAlignedBB.b(this.boundingBox.a, d1, this.boundingBox.c, this.boundingBox.d, d2, this.boundingBox.f); + + if (this.world.b(axisalignedbb, Material.WATER)) { + d0 += 1.0D / (double) b0; + } + } + + double d3; + double d4; + double d5; + double d6; + + if (this.world.isStatic) { + if (this.d > 0) { + d3 = this.locX + (this.e - this.locX) / (double) this.d; + d4 = this.locY + (this.f - this.locY) / (double) this.d; + d5 = this.locZ + (this.g - this.locZ) / (double) this.d; + + for (d6 = this.h - (double) this.yaw; d6 < -180.0D; d6 += 360.0D) { + ; + } + + while (d6 >= 180.0D) { + d6 -= 360.0D; + } + + this.yaw = (float) ((double) this.yaw + d6 / (double) this.d); + this.pitch = (float) ((double) this.pitch + (this.i - (double) this.pitch) / (double) this.d); + --this.d; + this.setPosition(d3, d4, d5); + this.c(this.yaw, this.pitch); + } else { + d3 = this.locX + this.motX; + d4 = this.locY + this.motY; + d5 = this.locZ + this.motZ; + this.setPosition(d3, d4, d5); + if (this.onGround) { + this.motX *= 0.5D; + this.motY *= 0.5D; + this.motZ *= 0.5D; + } + + this.motX *= 0.9900000095367432D; + this.motY *= 0.949999988079071D; + this.motZ *= 0.9900000095367432D; + } + } else { + if (d0 < 1.0D) { + d3 = d0 * 2.0D - 1.0D; + this.motY += 0.03999999910593033D * d3; + } else { + if (this.motY < 0.0D) { + this.motY /= 2.0D; + } + + this.motY += 0.007000000216066837D; + } + + if (this.passenger != null) { + this.motX += this.passenger.motX * 0.2D; + this.motZ += this.passenger.motZ * 0.2D; + } + + // CraftBukkit + d3 = this.maxSpeed; + if (this.motX < -d3) { + this.motX = -d3; + } + + if (this.motX > d3) { + this.motX = d3; + } + + if (this.motZ < -d3) { + this.motZ = -d3; + } + + if (this.motZ > d3) { + this.motZ = d3; + } + + if (this.onGround) { + this.motX *= 0.5D; + this.motY *= 0.5D; + this.motZ *= 0.5D; + } + + this.move(this.motX, this.motY, this.motZ); + d4 = Math.sqrt(this.motX * this.motX + this.motZ * this.motZ); + if (d4 > 0.15D) { + d5 = Math.cos((double) this.yaw * 3.141592653589793D / 180.0D); + d6 = Math.sin((double) this.yaw * 3.141592653589793D / 180.0D); + + for (int j = 0; (double) j < 1.0D + d4 * 60.0D; ++j) { + double d7 = (double) (this.random.nextFloat() * 2.0F - 1.0F); + double d8 = (double) (this.random.nextInt(2) * 2 - 1) * 0.7D; + double d9; + double d10; + + if (this.random.nextBoolean()) { + d9 = this.locX - d5 * d7 * 0.8D + d6 * d8; + d10 = this.locZ - d6 * d7 * 0.8D - d5 * d8; + this.world.a("splash", d9, this.locY - 0.125D, d10, this.motX, this.motY, this.motZ); + } else { + d9 = this.locX + d5 + d6 * d7 * 0.7D; + d10 = this.locZ + d6 - d5 * d7 * 0.7D; + this.world.a("splash", d9, this.locY - 0.125D, d10, this.motX, this.motY, this.motZ); + } + } + } + + if (this.positionChanged && d4 > 0.15D) { + if (!this.world.isStatic) { + this.die(); + + int k; + + for (k = 0; k < 3; ++k) { + this.a(Block.WOOD.id, 1, 0.0F); + } + + for (k = 0; k < 2; ++k) { + this.a(Item.STICK.id, 1, 0.0F); + } + } + } else { + this.motX *= 0.9900000095367432D; + this.motY *= 0.949999988079071D; + this.motZ *= 0.9900000095367432D; + } + + this.pitch = 0.0F; + d5 = (double) this.yaw; + d6 = this.lastX - this.locX; + double d11 = this.lastZ - this.locZ; + + if (d6 * d6 + d11 * d11 > 0.0010D) { + d5 = (double) ((float) (Math.atan2(d11, d6) * 180.0D / 3.141592653589793D)); + } + + double d12; + + for (d12 = d5 - (double) this.yaw; d12 >= 180.0D; d12 -= 360.0D) { + ; + } + + while (d12 < -180.0D) { + d12 += 360.0D; + } + + if (d12 > 20.0D) { + d12 = 20.0D; + } + + if (d12 < -20.0D) { + d12 = -20.0D; + } + + this.yaw = (float) ((double) this.yaw + d12); + this.c(this.yaw, this.pitch); + + // CraftBukkit start + org.bukkit.Server server = this.world.getServer(); + org.bukkit.World bworld = this.world.getWorld(); + + Location from = new Location(bworld, prevX, prevY, prevZ, prevYaw, prevPitch); + Location to = new Location(bworld, this.locX, this.locY, this.locZ, this.yaw, this.pitch); + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); + + server.getPluginManager().callEvent(new VehicleUpdateEvent(vehicle)); + + if (!from.equals(to)) { + VehicleMoveEvent event = new VehicleMoveEvent(vehicle, from, to); + server.getPluginManager().callEvent(event); + } + // CraftBukkit end + + List list = this.world.b((Entity) this, this.boundingBox.b(0.20000000298023224D, 0.0D, 0.20000000298023224D)); + int l; + + if (list != null && list.size() > 0) { + for (l = 0; l < list.size(); ++l) { + Entity entity = (Entity) list.get(l); + + if (entity != this.passenger && entity.d_() && entity instanceof EntityBoat) { + entity.collide(this); + } + } + } + + for (l = 0; l < 4; ++l) { + int i1 = MathHelper.floor(this.locX + ((double) (l % 2) - 0.5D) * 0.8D); + int j1 = MathHelper.floor(this.locY); + int k1 = MathHelper.floor(this.locZ + ((double) (l / 2) - 0.5D) * 0.8D); + + if (this.world.getTypeId(i1, j1, k1) == Block.SNOW.id) { + this.world.setTypeId(i1, j1, k1, 0); + } + } + + if (this.passenger != null && this.passenger.dead) { + this.passenger.vehicle = null; // CraftBukkit + this.passenger = null; + } + } + } + + public void f() { + if (this.passenger != null) { + double d0 = Math.cos((double) this.yaw * 3.141592653589793D / 180.0D) * 0.4D; + double d1 = Math.sin((double) this.yaw * 3.141592653589793D / 180.0D) * 0.4D; + + this.passenger.setPosition(this.locX + d0, this.locY + this.m() + this.passenger.I(), this.locZ + d1); + } + } + + protected void b(NBTTagCompound nbttagcompound) {} + + protected void a(NBTTagCompound nbttagcompound) {} + + public boolean a(EntityHuman entityhuman) { + if (this.passenger != null && this.passenger instanceof EntityHuman && this.passenger != entityhuman) { + return true; + } else { + if (!this.world.isStatic) { + // CraftBukkit start + VehicleEnterEvent event = new VehicleEnterEvent((Vehicle) this.getBukkitEntity(), entityhuman.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return true; + } + // CraftBukkit end + + entityhuman.mount(this); + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityChicken.java b/src/main/java/net/minecraft/server/EntityChicken.java new file mode 100644 index 0000000..6299463 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityChicken.java @@ -0,0 +1,76 @@ +package net.minecraft.server; + +public class EntityChicken extends EntityAnimal { + + public boolean a = false; + public float b = 0.0F; + public float c = 0.0F; + public float f; + public float g; + public float h = 1.0F; + public int i; + + public EntityChicken(World world) { + super(world); + this.texture = "/mob/chicken.png"; + this.b(0.3F, 0.4F); + this.health = 4; + this.i = this.random.nextInt(6000) + 6000; + } + + public void v() { + super.v(); + this.g = this.b; + this.f = this.c; + this.c = (float) ((double) this.c + (double) (this.onGround ? -1 : 4) * 0.3D); + if (this.c < 0.0F) { + this.c = 0.0F; + } + + if (this.c > 1.0F) { + this.c = 1.0F; + } + + if (!this.onGround && this.h < 1.0F) { + this.h = 1.0F; + } + + this.h = (float) ((double) this.h * 0.9D); + if (!this.onGround && this.motY < 0.0D) { + this.motY *= 0.6D; + } + + this.b += this.h * 2.0F; + if (!this.world.isStatic && --this.i <= 0) { + this.world.makeSound(this, "mob.chickenplop", 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + this.b(Item.EGG.id, 1); + this.i = this.random.nextInt(6000) + 6000; + } + } + + protected void a(float f) {} + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + protected String g() { + return "mob.chicken"; + } + + protected String h() { + return "mob.chickenhurt"; + } + + protected String i() { + return "mob.chickenhurt"; + } + + protected int j() { + return Item.FEATHER.id; + } +} diff --git a/src/main/java/net/minecraft/server/EntityCow.java b/src/main/java/net/minecraft/server/EntityCow.java new file mode 100644 index 0000000..3694ab7 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityCow.java @@ -0,0 +1,70 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.Location; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.event.player.PlayerBucketFillEvent; +// CraftBukkit end + +public class EntityCow extends EntityAnimal { + + public EntityCow(World world) { + super(world); + this.texture = "/mob/cow.png"; + this.b(0.9F, 1.3F); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + protected String g() { + return "mob.cow"; + } + + protected String h() { + return "mob.cowhurt"; + } + + protected String i() { + return "mob.cowhurt"; + } + + protected float k() { + return 0.4F; + } + + protected int j() { + return Item.LEATHER.id; + } + + public boolean a(EntityHuman entityhuman) { + ItemStack itemstack = entityhuman.inventory.getItemInHand(); + + if (itemstack != null && itemstack.id == Item.BUCKET.id) { + // CraftBukkit start - got milk? + Location loc = this.getBukkitEntity().getLocation(); + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), -1, itemstack, Item.MILK_BUCKET); + + if (event.isCancelled()) { + return false; + } + + CraftItemStack itemInHand = (CraftItemStack) event.getItemStack(); + byte data = itemInHand.getData() == null ? (byte) 0 : itemInHand.getData().getData(); + itemstack = new ItemStack(itemInHand.getTypeId(), itemInHand.getAmount(), data); + + entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, itemstack); + // CraftBukkit end + + return true; + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityCreature.java b/src/main/java/net/minecraft/server/EntityCreature.java new file mode 100644 index 0000000..30c595a --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityCreature.java @@ -0,0 +1,217 @@ +package net.minecraft.server; + +// CraftBukkit start + +import org.bukkit.craftbukkit.TrigMath; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.event.entity.EntityTargetEvent; +// CraftBukkit end + +public class EntityCreature extends EntityLiving { + + public PathEntity pathEntity; // CraftBukkit - public + public Entity target; // CraftBukkit - public + protected boolean e = false; + + public EntityCreature(World world) { + super(world); + } + + protected boolean w() { + return false; + } + + protected void c_() { + this.e = this.w(); + float f = 16.0F; + + if (this.target == null) { + // CraftBukkit start + Entity target = this.findTarget(); + if (target != null) { + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), target.getBukkitEntity(), EntityTargetEvent.TargetReason.CLOSEST_PLAYER); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + this.target = ((CraftEntity) event.getTarget()).getHandle(); + } + } + } + // CraftBukkit end + + if (this.target != null) { + this.pathEntity = this.world.findPath(this, this.target, f); + } + } else if (!this.target.T()) { + // CraftBukkit start + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), null, EntityTargetEvent.TargetReason.TARGET_DIED); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + this.target = ((CraftEntity) event.getTarget()).getHandle(); + } + } + // CraftBukkit end + } else { + float f1 = this.target.f(this); + + if (this.e(this.target)) { + this.a(this.target, f1); + } else { + this.b(this.target, f1); + } + } + + if (!this.e && this.target != null && (this.pathEntity == null || this.random.nextInt(20) == 0)) { + this.pathEntity = this.world.findPath(this, this.target, f); + } else if (!this.e && (this.pathEntity == null && this.random.nextInt(80) == 0 || this.random.nextInt(80) == 0)) { + this.B(); + } + + int i = MathHelper.floor(this.boundingBox.b + 0.5D); + boolean flag = this.ad(); + boolean flag1 = this.ae(); + + this.pitch = 0.0F; + if (this.pathEntity != null && this.random.nextInt(100) != 0) { + Vec3D vec3d = this.pathEntity.a(this); + double d0 = (double) (this.length * 2.0F); + + while (vec3d != null && vec3d.d(this.locX, vec3d.b, this.locZ) < d0 * d0) { + this.pathEntity.a(); + if (this.pathEntity.b()) { + vec3d = null; + this.pathEntity = null; + } else { + vec3d = this.pathEntity.a(this); + } + } + + this.aC = false; + if (vec3d != null) { + double d1 = vec3d.a - this.locX; + double d2 = vec3d.c - this.locZ; + double d3 = vec3d.b - (double) i; + // CraftBukkit - Math -> TrigMath + float f2 = (float) (TrigMath.atan2(d2, d1) * 180.0D / 3.1415927410125732D) - 90.0F; + float f3 = f2 - this.yaw; + + for (this.aA = this.aE; f3 < -180.0F; f3 += 360.0F) { + ; + } + + while (f3 >= 180.0F) { + f3 -= 360.0F; + } + + if (f3 > 30.0F) { + f3 = 30.0F; + } + + if (f3 < -30.0F) { + f3 = -30.0F; + } + + this.yaw += f3; + if (this.e && this.target != null) { + double d4 = this.target.locX - this.locX; + double d5 = this.target.locZ - this.locZ; + float f4 = this.yaw; + + this.yaw = (float) (Math.atan2(d5, d4) * 180.0D / 3.1415927410125732D) - 90.0F; + f3 = (f4 - this.yaw + 90.0F) * 3.1415927F / 180.0F; + this.az = -MathHelper.sin(f3) * this.aA * 1.0F; + this.aA = MathHelper.cos(f3) * this.aA * 1.0F; + } + + if (d3 > 0.0D) { + this.aC = true; + } + } + + if (this.target != null) { + this.a(this.target, 30.0F, 30.0F); + } + + if (this.positionChanged && !this.C()) { + this.aC = true; + } + + if (this.random.nextFloat() < 0.8F && (flag || flag1)) { + this.aC = true; + } + } else { + super.c_(); + this.pathEntity = null; + } + } + + protected void B() { + boolean flag = false; + int i = -1; + int j = -1; + int k = -1; + float f = -99999.0F; + + for (int l = 0; l < 10; ++l) { + int i1 = MathHelper.floor(this.locX + (double) this.random.nextInt(13) - 6.0D); + int j1 = MathHelper.floor(this.locY + (double) this.random.nextInt(7) - 3.0D); + int k1 = MathHelper.floor(this.locZ + (double) this.random.nextInt(13) - 6.0D); + float f1 = this.a(i1, j1, k1); + + if (f1 > f) { + f = f1; + i = i1; + j = j1; + k = k1; + flag = true; + } + } + + if (flag) { + this.pathEntity = this.world.a(this, i, j, k, 10.0F); + } + } + + protected void a(Entity entity, float f) {} + + protected void b(Entity entity, float f) {} + + protected float a(int i, int j, int k) { + return 0.0F; + } + + protected Entity findTarget() { + return null; + } + + public boolean d() { + int i = MathHelper.floor(this.locX); + int j = MathHelper.floor(this.boundingBox.b); + int k = MathHelper.floor(this.locZ); + + return super.d() && this.a(i, j, k) >= 0.0F; + } + + public boolean C() { + return this.pathEntity != null; + } + + public void setPathEntity(PathEntity pathentity) { + this.pathEntity = pathentity; + } + + public Entity F() { + return this.target; + } + + public void setTarget(Entity entity) { + this.target = entity; + } +} diff --git a/src/main/java/net/minecraft/server/EntityCreeper.java b/src/main/java/net/minecraft/server/EntityCreeper.java new file mode 100644 index 0000000..bda8be9 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityCreeper.java @@ -0,0 +1,172 @@ +package net.minecraft.server; + +// CraftBukkit start + +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.event.entity.CreeperPowerEvent; +import org.bukkit.event.entity.ExplosionPrimeEvent; +// CraftBukkit end + +public class EntityCreeper extends EntityMonster { + + int fuseTicks; + int b; + + public EntityCreeper(World world) { + super(world); + this.texture = "/mob/creeper.png"; + } + + protected void b() { + super.b(); + this.datawatcher.a(16, Byte.valueOf((byte) -1)); + this.datawatcher.a(17, Byte.valueOf((byte) 0)); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + if (this.datawatcher.a(17) == 1) { + nbttagcompound.a("powered", true); + } + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.datawatcher.watch(17, Byte.valueOf((byte) (nbttagcompound.m("powered") ? 1 : 0))); + } + + protected void b(Entity entity, float f) { + if (!this.world.isStatic) { + if (this.fuseTicks > 0) { + this.e(-1); + --this.fuseTicks; + if (this.fuseTicks < 0) { + this.fuseTicks = 0; + } + } + } + } + + public void m_() { + this.b = this.fuseTicks; + if (this.world.isStatic) { + int i = this.x(); + + if (i > 0 && this.fuseTicks == 0) { + this.world.makeSound(this, "random.fuse", 1.0F, 0.5F); + } + + this.fuseTicks += i; + if (this.fuseTicks < 0) { + this.fuseTicks = 0; + } + + if (this.fuseTicks >= 30) { + this.fuseTicks = 30; + } + } + + super.m_(); + if (this.target == null && this.fuseTicks > 0) { + this.e(-1); + --this.fuseTicks; + if (this.fuseTicks < 0) { + this.fuseTicks = 0; + } + } + } + + protected String h() { + return "mob.creeper"; + } + + protected String i() { + return "mob.creeperdeath"; + } + + public void die(Entity entity) { + super.die(entity); + if (entity instanceof EntityArrow) { + EntityLiving shooter = ((EntityArrow) entity).shooter; + if (shooter instanceof EntitySkeleton) { + this.b(Item.GOLD_RECORD.id + this.random.nextInt(2), 1); + } + } + } + + protected void a(Entity entity, float f) { + if (!this.world.isStatic) { + int i = this.x(); + + if ((i > 0 || f >= 3.0F) && (i <= 0 || f >= 7.0F)) { + this.e(-1); + --this.fuseTicks; + if (this.fuseTicks < 0) { + this.fuseTicks = 0; + } + } else { + if (this.fuseTicks == 0) { + this.world.makeSound(this, "random.fuse", 1.0F, 0.5F); + } + + this.e(1); + ++this.fuseTicks; + if (this.fuseTicks >= 30) { + // CraftBukkit start + float radius = this.isPowered() ? 6.0F : 3.0F; + + ExplosionPrimeEvent event = new ExplosionPrimeEvent(CraftEntity.getEntity(this.world.getServer(), this), radius, false); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire()); + this.die(); + } else { + this.fuseTicks = 0; + } + // CraftBukkit end + } + + this.e = true; + } + } + } + + public boolean isPowered() { + return this.datawatcher.a(17) == 1; + } + + protected int j() { + return Item.SULPHUR.id; + } + + private int x() { + return this.datawatcher.a(16); + } + + private void e(int i) { + this.datawatcher.watch(16, Byte.valueOf((byte) i)); + } + + public void a(EntityWeatherStorm entityweatherstorm) { + super.a(entityweatherstorm); + + // CraftBukkit start + CreeperPowerEvent event = new CreeperPowerEvent(this.getBukkitEntity(), entityweatherstorm.getBukkitEntity(), CreeperPowerEvent.PowerCause.LIGHTNING); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + this.setPowered(true); + } + + public void setPowered(boolean powered) { + if (!powered) { + this.datawatcher.watch(17, Byte.valueOf((byte) 0)); + } else + // CraftBukkit end + this.datawatcher.watch(17, Byte.valueOf((byte) 1)); + } +} diff --git a/src/main/java/net/minecraft/server/EntityEgg.java b/src/main/java/net/minecraft/server/EntityEgg.java new file mode 100644 index 0000000..6b0e033 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityEgg.java @@ -0,0 +1,343 @@ +package net.minecraft.server; + +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.player.PlayerEggThrowEvent; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityEgg extends Entity { + + private int b = -1; + private int c = -1; + private int d = -1; + private int e = 0; + private boolean f = false; + public int a = 0; + public EntityLiving thrower; // CraftBukkit - private -> public + private int h; + private int i = 0; + + public EntityEgg(World world) { + super(world); + this.b(0.25F, 0.25F); + } + + protected void b() {} + + public EntityEgg(World world, EntityLiving entityliving) { + super(world); + this.thrower = entityliving; + this.b(0.25F, 0.25F); + this.setPositionRotation(entityliving.locX, entityliving.locY + (double) entityliving.t(), entityliving.locZ, entityliving.yaw, entityliving.pitch); + this.locX -= (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.locY -= 0.10000000149011612D; + this.locZ -= (double) (MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.setPosition(this.locX, this.locY, this.locZ); + this.height = 0.0F; + float f = 0.4F; + + this.motX = (double) (-MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + this.motZ = (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + this.motY = (double) (-MathHelper.sin(this.pitch / 180.0F * 3.1415927F) * f); + this.a(this.motX, this.motY, this.motZ, 1.5F, 1.0F); + } + + public EntityEgg(World world, double d0, double d1, double d2) { + super(world); + this.h = 0; + this.b(0.25F, 0.25F); + this.setPosition(d0, d1, d2); + this.height = 0.0F; + } + + public void a(double d0, double d1, double d2, float f, float f1) { + float f2 = MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + + d0 /= (double) f2; + d1 /= (double) f2; + d2 /= (double) f2; + d0 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d1 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d2 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d0 *= (double) f; + d1 *= (double) f; + d2 *= (double) f; + this.motX = d0; + this.motY = d1; + this.motZ = d2; + float f3 = MathHelper.a(d0 * d0 + d2 * d2); + + this.lastYaw = this.yaw = (float) (Math.atan2(d0, d2) * 180.0D / 3.1415927410125732D); + this.lastPitch = this.pitch = (float) (Math.atan2(d1, (double) f3) * 180.0D / 3.1415927410125732D); + this.h = 0; + } + + public void m_() { + this.bo = this.locX; + this.bp = this.locY; + this.bq = this.locZ; + super.m_(); + if (this.a > 0) { + --this.a; + } + + if (this.f) { + int i = this.world.getTypeId(this.b, this.c, this.d); + + if (i == this.e) { + ++this.h; + if (this.h == 1200) { + this.die(); + } + + return; + } + + this.f = false; + this.motX *= (double) (this.random.nextFloat() * 0.2F); + this.motY *= (double) (this.random.nextFloat() * 0.2F); + this.motZ *= (double) (this.random.nextFloat() * 0.2F); + this.h = 0; + this.i = 0; + } else { + ++this.i; + } + + Vec3D vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + Vec3D vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + MovingObjectPosition movingobjectposition = this.world.a(vec3d, vec3d1); + + vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + if (movingobjectposition != null) { + vec3d1 = Vec3D.create(movingobjectposition.f.a, movingobjectposition.f.b, movingobjectposition.f.c); + } + + if (!this.world.isStatic) { + Entity entity = null; + List list = this.world.b((Entity) this, this.boundingBox.a(this.motX, this.motY, this.motZ).b(1.0D, 1.0D, 1.0D)); + double d0 = 0.0D; + + for (int j = 0; j < list.size(); ++j) { + Entity entity1 = (Entity) list.get(j); + + if (entity1.l_() && (entity1 != this.thrower || this.i >= 5)) { + float f = 0.3F; + AxisAlignedBB axisalignedbb = entity1.boundingBox.b((double) f, (double) f, (double) f); + MovingObjectPosition movingobjectposition1 = axisalignedbb.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { + double d1 = vec3d.a(movingobjectposition1.f); + + if (d1 < d0 || d0 == 0.0D) { + entity = entity1; + d0 = d1; + } + } + } + } + + if (entity != null) { + movingobjectposition = new MovingObjectPosition(entity); + } + } + + if (movingobjectposition != null) { + // CraftBukkit start + ProjectileHitEvent phe = new ProjectileHitEvent((Projectile) this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(phe); + + if (movingobjectposition.entity != null) { + boolean stick; + if (movingobjectposition.entity instanceof EntityLiving) { + org.bukkit.entity.Entity damagee = movingobjectposition.entity.getBukkitEntity(); + Projectile projectile = (Projectile) this.getBukkitEntity(); + + // TODO @see EntityArrow#162 + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(projectile, damagee, EntityDamageEvent.DamageCause.PROJECTILE, 0); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + stick = !projectile.doesBounce(); + } else { + // this function returns if the egg should stick in or not, i.e. !bounce + stick = movingobjectposition.entity.damageEntity(this, event.getDamage()); + } + } else { + stick = movingobjectposition.entity.damageEntity(this.thrower, 0); + } + + if (stick) { + ; // Original code does nothing *yet* + } + } + + boolean hatching = !this.world.isStatic && this.random.nextInt(8) == 0; + int numHatching = (this.random.nextInt(32) == 0) ? 4 : 1; + if (!hatching) { + numHatching = 0; + } + + CreatureType hatchingType = CreatureType.CHICKEN; + + if (this.thrower instanceof EntityPlayer) { + org.bukkit.entity.Player player = (this.thrower == null) ? null : (org.bukkit.entity.Player) this.thrower.getBukkitEntity(); + + PlayerEggThrowEvent event = new PlayerEggThrowEvent(player, (org.bukkit.entity.Egg) this.getBukkitEntity(), hatching, (byte) numHatching, hatchingType); + this.world.getServer().getPluginManager().callEvent(event); + + hatching = event.isHatching(); + numHatching = event.getNumHatches(); + hatchingType = event.getHatchType(); + } + + if (hatching) { + for (int k = 0; k < numHatching; k++) { + Entity entity = null; + switch (hatchingType) { + case CHICKEN: + entity = new EntityChicken(this.world); + break; + case COW: + entity = new EntityCow(this.world); + break; + case CREEPER: + entity = new EntityCreeper(this.world); + break; + case GHAST: + entity = new EntityGhast(this.world); + break; + case GIANT: + entity = new EntityGiantZombie(this.world); + break; + case PIG: + entity = new EntityPig(this.world); + break; + case PIG_ZOMBIE: + entity = new EntityPigZombie(this.world); + break; + case SHEEP: + entity = new EntitySheep(this.world); + break; + case SKELETON: + entity = new EntitySkeleton(this.world); + break; + case SPIDER: + entity = new EntitySpider(this.world); + break; + case ZOMBIE: + entity = new EntityZombie(this.world); + break; + case SQUID: + entity = new EntitySquid(this.world); + break; + case SLIME: + entity = new EntitySlime(this.world); + break; + case WOLF: + entity = new EntityWolf(this.world); + break; + case MONSTER: + entity = new EntityMonster(this.world); + break; + default: + entity = new EntityChicken(this.world); + break; + } + + // The world we're spawning in accepts this creature + boolean isAnimal = entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal; + if ((isAnimal && this.world.allowAnimals) || (!isAnimal && this.world.allowMonsters)) { + entity.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F); + this.world.addEntity(entity, SpawnReason.EGG); + } + // CraftBukkit end + } + } + + for (int l = 0; l < 8; ++l) { + this.world.a("snowballpoof", this.locX, this.locY, this.locZ, 0.0D, 0.0D, 0.0D); + } + + this.die(); + } + + this.locX += this.motX; + this.locY += this.motY; + this.locZ += this.motZ; + float f1 = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + + this.yaw = (float) (Math.atan2(this.motX, this.motZ) * 180.0D / 3.1415927410125732D); + + for (this.pitch = (float) (Math.atan2(this.motY, (double) f1) * 180.0D / 3.1415927410125732D); this.pitch - this.lastPitch < -180.0F; this.lastPitch -= 360.0F) { + ; + } + + while (this.pitch - this.lastPitch >= 180.0F) { + this.lastPitch += 360.0F; + } + + while (this.yaw - this.lastYaw < -180.0F) { + this.lastYaw -= 360.0F; + } + + while (this.yaw - this.lastYaw >= 180.0F) { + this.lastYaw += 360.0F; + } + + this.pitch = this.lastPitch + (this.pitch - this.lastPitch) * 0.2F; + this.yaw = this.lastYaw + (this.yaw - this.lastYaw) * 0.2F; + float f2 = 0.99F; + float f3 = 0.03F; + + if (this.ad()) { + for (int i1 = 0; i1 < 4; ++i1) { + float f4 = 0.25F; + + this.world.a("bubble", this.locX - this.motX * (double) f4, this.locY - this.motY * (double) f4, this.locZ - this.motZ * (double) f4, this.motX, this.motY, this.motZ); + } + + f2 = 0.8F; + } + + this.motX *= (double) f2; + this.motY *= (double) f2; + this.motZ *= (double) f2; + this.motY -= (double) f3; + this.setPosition(this.locX, this.locY, this.locZ); + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("xTile", (short) this.b); + nbttagcompound.a("yTile", (short) this.c); + nbttagcompound.a("zTile", (short) this.d); + nbttagcompound.a("inTile", (byte) this.e); + nbttagcompound.a("shake", (byte) this.a); + nbttagcompound.a("inGround", (byte) (this.f ? 1 : 0)); + } + + public void a(NBTTagCompound nbttagcompound) { + this.b = nbttagcompound.d("xTile"); + this.c = nbttagcompound.d("yTile"); + this.d = nbttagcompound.d("zTile"); + this.e = nbttagcompound.c("inTile") & 255; + this.a = nbttagcompound.c("shake") & 255; + this.f = nbttagcompound.c("inGround") == 1; + } + + public void b(EntityHuman entityhuman) { + if (this.f && this.thrower == entityhuman && this.a <= 0 && entityhuman.inventory.pickup(new ItemStack(Item.ARROW, 1))) { + this.world.makeSound(this, "random.pop", 0.2F, ((this.random.nextFloat() - this.random.nextFloat()) * 0.7F + 1.0F) * 2.0F); + entityhuman.receive(this, 1); + this.die(); + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityFallingSand.java b/src/main/java/net/minecraft/server/EntityFallingSand.java new file mode 100644 index 0000000..daea1c1 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityFallingSand.java @@ -0,0 +1,80 @@ +package net.minecraft.server; + +public class EntityFallingSand extends Entity { + + public int a; + public int b = 0; + + public EntityFallingSand(World world) { + super(world); + } + + public EntityFallingSand(World world, double d0, double d1, double d2, int i) { + super(world); + this.a = i; + this.aI = true; + this.b(0.98F, 0.98F); + this.height = this.width / 2.0F; + this.setPosition(d0, d1, d2); + this.motX = 0.0D; + this.motY = 0.0D; + this.motZ = 0.0D; + this.lastX = d0; + this.lastY = d1; + this.lastZ = d2; + } + + protected boolean n() { + return false; + } + + protected void b() {} + + public boolean l_() { + return !this.dead; + } + + public void m_() { + if (this.a == 0) { + this.die(); + } else { + this.lastX = this.locX; + this.lastY = this.locY; + this.lastZ = this.locZ; + ++this.b; + this.motY -= 0.03999999910593033D; + this.move(this.motX, this.motY, this.motZ); + this.motX *= 0.9800000190734863D; + this.motY *= 0.9800000190734863D; + this.motZ *= 0.9800000190734863D; + int i = MathHelper.floor(this.locX); + int j = MathHelper.floor(this.locY); + int k = MathHelper.floor(this.locZ); + + if (this.world.getTypeId(i, j, k) == this.a) { + this.world.setTypeId(i, j, k, 0); + } + + if (this.onGround) { + this.motX *= 0.699999988079071D; + this.motZ *= 0.699999988079071D; + this.motY *= -0.5D; + this.die(); + if ((!this.world.a(this.a, i, j, k, true, 1) || BlockSand.c_(this.world, i, j - 1, k) || !this.world.setTypeId(i, j, k, this.a)) && !this.world.isStatic) { + this.b(this.a, 1); + } + } else if (this.b > 100 && !this.world.isStatic) { + this.b(this.a, 1); + this.die(); + } + } + } + + protected void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("Tile", (byte) this.a); + } + + protected void a(NBTTagCompound nbttagcompound) { + this.a = nbttagcompound.c("Tile") & 255; + } +} diff --git a/src/main/java/net/minecraft/server/EntityFireball.java b/src/main/java/net/minecraft/server/EntityFireball.java new file mode 100644 index 0000000..6756aeb --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityFireball.java @@ -0,0 +1,265 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftLivingEntity; +import org.bukkit.entity.Explosive; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.ExplosionPrimeEvent; +import org.bukkit.event.entity.ProjectileHitEvent; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityFireball extends Entity { + + private int f = -1; + private int g = -1; + private int h = -1; + private int i = 0; + private boolean j = false; + public int a = 0; + public EntityLiving shooter; + private int k; + private int l = 0; + public double c; + public double d; + public double e; + + public float yield = 1; // CraftBukkit + public boolean isIncendiary = true; // CraftBukkit + + public EntityFireball(World world) { + super(world); + this.b(1.0F, 1.0F); + } + + protected void b() {} + + public EntityFireball(World world, EntityLiving entityliving, double d0, double d1, double d2) { + super(world); + this.shooter = entityliving; + this.b(1.0F, 1.0F); + this.setPositionRotation(entityliving.locX, entityliving.locY, entityliving.locZ, entityliving.yaw, entityliving.pitch); + this.setPosition(this.locX, this.locY, this.locZ); + this.height = 0.0F; + this.motX = this.motY = this.motZ = 0.0D; + // CraftBukkit start (added setDirection method) + this.setDirection(d0, d1, d2); + } + + public void setDirection(double d0, double d1, double d2) { + d0 += this.random.nextGaussian() * 0.4D; + d1 += this.random.nextGaussian() * 0.4D; + d2 += this.random.nextGaussian() * 0.4D; + double d3 = (double) MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + + this.c = d0 / d3 * 0.1D; + this.d = d1 / d3 * 0.1D; + this.e = d2 / d3 * 0.1D; + } + + public void m_() { + super.m_(); + this.fireTicks = 10; + if (this.a > 0) { + --this.a; + } + + if (this.j) { + int i = this.world.getTypeId(this.f, this.g, this.h); + + if (i == this.i) { + ++this.k; + if (this.k == 1200) { + this.die(); + } + + return; + } + + this.j = false; + this.motX *= (double) (this.random.nextFloat() * 0.2F); + this.motY *= (double) (this.random.nextFloat() * 0.2F); + this.motZ *= (double) (this.random.nextFloat() * 0.2F); + this.k = 0; + this.l = 0; + } else { + ++this.l; + } + + Vec3D vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + Vec3D vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + MovingObjectPosition movingobjectposition = this.world.a(vec3d, vec3d1); + + vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + if (movingobjectposition != null) { + vec3d1 = Vec3D.create(movingobjectposition.f.a, movingobjectposition.f.b, movingobjectposition.f.c); + } + + Entity entity = null; + List list = this.world.b((Entity) this, this.boundingBox.a(this.motX, this.motY, this.motZ).b(1.0D, 1.0D, 1.0D)); + double d0 = 0.0D; + + for (int j = 0; j < list.size(); ++j) { + Entity entity1 = (Entity) list.get(j); + + if (entity1.l_() && (entity1 != this.shooter || this.l >= 25)) { + float f = 0.3F; + AxisAlignedBB axisalignedbb = entity1.boundingBox.b((double) f, (double) f, (double) f); + MovingObjectPosition movingobjectposition1 = axisalignedbb.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { + double d1 = vec3d.a(movingobjectposition1.f); + + if (d1 < d0 || d0 == 0.0D) { + entity = entity1; + d0 = d1; + } + } + } + } + + if (entity != null) { + movingobjectposition = new MovingObjectPosition(entity); + } + + if (movingobjectposition != null) { + // CraftBukkit start + ProjectileHitEvent phe = new ProjectileHitEvent((Projectile) this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(phe); + // CraftBukkit end + if (!this.world.isStatic) { + // CraftBukkit start + if (movingobjectposition.entity != null) { + boolean stick; + if (movingobjectposition.entity instanceof EntityLiving) { + org.bukkit.entity.Entity damagee = movingobjectposition.entity.getBukkitEntity(); + Projectile projectile = (Projectile) this.getBukkitEntity(); + + // TODO @see EntityArrow#162 + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(projectile, damagee, EntityDamageEvent.DamageCause.PROJECTILE, 0); + this.world.getServer().getPluginManager().callEvent(event); + + this.shooter = (projectile.getShooter() == null) ? null : ((CraftLivingEntity) projectile.getShooter()).getHandle(); + + if (event.isCancelled()) { + stick = !projectile.doesBounce(); + } else { + // this function returns if the fireball should stick in or not, i.e. !bounce + stick = movingobjectposition.entity.damageEntity(this, event.getDamage()); + } + } else { + stick = movingobjectposition.entity.damageEntity(this.shooter, 0); + } + if (stick) { + ; + } + } + + ExplosionPrimeEvent event = new ExplosionPrimeEvent((Explosive) CraftEntity.getEntity(this.world.getServer(), this)); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + // give 'this' instead of (Entity) null so we know what causes the damage + this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire()); + } + // CraftBukkit end + } + + this.die(); + } + + this.locX += this.motX; + this.locY += this.motY; + this.locZ += this.motZ; + float f1 = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + + this.yaw = (float) (Math.atan2(this.motX, this.motZ) * 180.0D / 3.1415927410125732D); + + for (this.pitch = (float) (Math.atan2(this.motY, (double) f1) * 180.0D / 3.1415927410125732D); this.pitch - this.lastPitch < -180.0F; this.lastPitch -= 360.0F) { + ; + } + + while (this.pitch - this.lastPitch >= 180.0F) { + this.lastPitch += 360.0F; + } + + while (this.yaw - this.lastYaw < -180.0F) { + this.lastYaw -= 360.0F; + } + + while (this.yaw - this.lastYaw >= 180.0F) { + this.lastYaw += 360.0F; + } + + this.pitch = this.lastPitch + (this.pitch - this.lastPitch) * 0.2F; + this.yaw = this.lastYaw + (this.yaw - this.lastYaw) * 0.2F; + float f2 = 0.95F; + + if (this.ad()) { + for (int k = 0; k < 4; ++k) { + float f3 = 0.25F; + + this.world.a("bubble", this.locX - this.motX * (double) f3, this.locY - this.motY * (double) f3, this.locZ - this.motZ * (double) f3, this.motX, this.motY, this.motZ); + } + + f2 = 0.8F; + } + + this.motX += this.c; + this.motY += this.d; + this.motZ += this.e; + this.motX *= (double) f2; + this.motY *= (double) f2; + this.motZ *= (double) f2; + this.world.a("smoke", this.locX, this.locY + 0.5D, this.locZ, 0.0D, 0.0D, 0.0D); + this.setPosition(this.locX, this.locY, this.locZ); + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("xTile", (short) this.f); + nbttagcompound.a("yTile", (short) this.g); + nbttagcompound.a("zTile", (short) this.h); + nbttagcompound.a("inTile", (byte) this.i); + nbttagcompound.a("shake", (byte) this.a); + nbttagcompound.a("inGround", (byte) (this.j ? 1 : 0)); + } + + public void a(NBTTagCompound nbttagcompound) { + this.f = nbttagcompound.d("xTile"); + this.g = nbttagcompound.d("yTile"); + this.h = nbttagcompound.d("zTile"); + this.i = nbttagcompound.c("inTile") & 255; + this.a = nbttagcompound.c("shake") & 255; + this.j = nbttagcompound.c("inGround") == 1; + } + + public boolean l_() { + return true; + } + + public boolean damageEntity(Entity entity, int i) { + this.af(); + if (entity != null) { + Vec3D vec3d = entity.Z(); + + if (vec3d != null) { + this.motX = vec3d.a; + this.motY = vec3d.b; + this.motZ = vec3d.c; + this.c = this.motX * 0.1D; + this.d = this.motY * 0.1D; + this.e = this.motZ * 0.1D; + } + + return true; + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityFish.java b/src/main/java/net/minecraft/server/EntityFish.java new file mode 100644 index 0000000..291aaf8 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityFish.java @@ -0,0 +1,411 @@ +package net.minecraft.server; + +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerFishEvent; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityFish extends Entity { + + private int d = -1; + private int e = -1; + private int f = -1; + private int g = 0; + private boolean h = false; + public int a = 0; + public EntityHuman owner; + private int i; + private int j = 0; + private int k = 0; + public Entity c = null; + private int l; + private double m; + private double n; + private double o; + private double p; + private double q; + + public EntityFish(World world) { + super(world); + this.b(0.25F, 0.25F); + this.bK = true; + } + + public EntityFish(World world, EntityHuman entityhuman) { + super(world); + this.bK = true; + this.owner = entityhuman; + this.owner.hookedFish = this; + this.b(0.25F, 0.25F); + this.setPositionRotation(entityhuman.locX, entityhuman.locY + 1.62D - (double) entityhuman.height, entityhuman.locZ, entityhuman.yaw, entityhuman.pitch); + this.locX -= (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.locY -= 0.10000000149011612D; + this.locZ -= (double) (MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.setPosition(this.locX, this.locY, this.locZ); + this.height = 0.0F; + float f = 0.4F; + + this.motX = (double) (-MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + this.motZ = (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + this.motY = (double) (-MathHelper.sin(this.pitch / 180.0F * 3.1415927F) * f); + this.a(this.motX, this.motY, this.motZ, 1.5F, 1.0F); + } + + protected void b() {} + + public void a(double d0, double d1, double d2, float f, float f1) { + float f2 = MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + + d0 /= (double) f2; + d1 /= (double) f2; + d2 /= (double) f2; + d0 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d1 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d2 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d0 *= (double) f; + d1 *= (double) f; + d2 *= (double) f; + this.motX = d0; + this.motY = d1; + this.motZ = d2; + float f3 = MathHelper.a(d0 * d0 + d2 * d2); + + this.lastYaw = this.yaw = (float) (Math.atan2(d0, d2) * 180.0D / 3.1415927410125732D); + this.lastPitch = this.pitch = (float) (Math.atan2(d1, (double) f3) * 180.0D / 3.1415927410125732D); + this.i = 0; + } + + public void m_() { + super.m_(); + if (this.l > 0) { + double d0 = this.locX + (this.m - this.locX) / (double) this.l; + double d1 = this.locY + (this.n - this.locY) / (double) this.l; + double d2 = this.locZ + (this.o - this.locZ) / (double) this.l; + + double d3; + + for (d3 = this.p - (double) this.yaw; d3 < -180.0D; d3 += 360.0D) { + ; + } + + while (d3 >= 180.0D) { + d3 -= 360.0D; + } + + this.yaw = (float) ((double) this.yaw + d3 / (double) this.l); + this.pitch = (float) ((double) this.pitch + (this.q - (double) this.pitch) / (double) this.l); + --this.l; + this.setPosition(d0, d1, d2); + this.c(this.yaw, this.pitch); + } else { + if (!this.world.isStatic) { + ItemStack itemstack = this.owner.G(); + + if (this.owner.dead || !this.owner.T() || itemstack == null || itemstack.getItem() != Item.FISHING_ROD || this.g(this.owner) > 1024.0D) { + this.die(); + this.owner.hookedFish = null; + return; + } + + if (this.c != null) { + if (!this.c.dead) { + this.locX = this.c.locX; + this.locY = this.c.boundingBox.b + (double) this.c.width * 0.8D; + this.locZ = this.c.locZ; + return; + } + + this.c = null; + } + } + + if (this.a > 0) { + --this.a; + } + + if (this.h) { + int i = this.world.getTypeId(this.d, this.e, this.f); + + if (i == this.g) { + ++this.i; + if (this.i == 1200) { + this.die(); + } + + return; + } + + this.h = false; + this.motX *= (double) (this.random.nextFloat() * 0.2F); + this.motY *= (double) (this.random.nextFloat() * 0.2F); + this.motZ *= (double) (this.random.nextFloat() * 0.2F); + this.i = 0; + this.j = 0; + } else { + ++this.j; + } + + Vec3D vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + Vec3D vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + MovingObjectPosition movingobjectposition = this.world.a(vec3d, vec3d1); + + vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + if (movingobjectposition != null) { + vec3d1 = Vec3D.create(movingobjectposition.f.a, movingobjectposition.f.b, movingobjectposition.f.c); + } + + Entity entity = null; + List list = this.world.b((Entity) this, this.boundingBox.a(this.motX, this.motY, this.motZ).b(1.0D, 1.0D, 1.0D)); + double d4 = 0.0D; + + double d5; + + for (int j = 0; j < list.size(); ++j) { + Entity entity1 = (Entity) list.get(j); + + if (entity1.l_() && (entity1 != this.owner || this.j >= 5)) { + float f = 0.3F; + AxisAlignedBB axisalignedbb = entity1.boundingBox.b((double) f, (double) f, (double) f); + MovingObjectPosition movingobjectposition1 = axisalignedbb.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { + d5 = vec3d.a(movingobjectposition1.f); + if (d5 < d4 || d4 == 0.0D) { + entity = entity1; + d4 = d5; + } + } + } + } + + if (entity != null) { + movingobjectposition = new MovingObjectPosition(entity); + } + + if (movingobjectposition != null) { + if (movingobjectposition.entity != null) { + // CraftBukkit start + // TODO add EntityDamagedByProjectileEvent : fishing hook? + boolean stick; + if (movingobjectposition.entity instanceof EntityLiving) { + org.bukkit.entity.Entity damagee = movingobjectposition.entity.getBukkitEntity(); + Projectile projectile = (Projectile) this.getBukkitEntity(); + + // TODO @see EntityArrow#162 + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(projectile, damagee, EntityDamageEvent.DamageCause.PROJECTILE, 0); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + stick = !projectile.doesBounce(); + } else { + // this function returns if the fish should stick in or not, i.e. !bounce + stick = movingobjectposition.entity.damageEntity(this, event.getDamage()); + } + } else { + stick = movingobjectposition.entity.damageEntity(this.owner, 0); + } + if (!stick) { + // CraftBukkit end + this.c = movingobjectposition.entity; + } + } else { + this.h = true; + } + } + + if (!this.h) { + this.move(this.motX, this.motY, this.motZ); + float f1 = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + + this.yaw = (float) (Math.atan2(this.motX, this.motZ) * 180.0D / 3.1415927410125732D); + + for (this.pitch = (float) (Math.atan2(this.motY, (double) f1) * 180.0D / 3.1415927410125732D); this.pitch - this.lastPitch < -180.0F; this.lastPitch -= 360.0F) { + ; + } + + while (this.pitch - this.lastPitch >= 180.0F) { + this.lastPitch += 360.0F; + } + + while (this.yaw - this.lastYaw < -180.0F) { + this.lastYaw -= 360.0F; + } + + while (this.yaw - this.lastYaw >= 180.0F) { + this.lastYaw += 360.0F; + } + + this.pitch = this.lastPitch + (this.pitch - this.lastPitch) * 0.2F; + this.yaw = this.lastYaw + (this.yaw - this.lastYaw) * 0.2F; + float f2 = 0.92F; + + if (this.onGround || this.positionChanged) { + f2 = 0.5F; + } + + byte b0 = 5; + double d6 = 0.0D; + + for (int k = 0; k < b0; ++k) { + double d7 = this.boundingBox.b + (this.boundingBox.e - this.boundingBox.b) * (double) (k + 0) / (double) b0 - 0.125D + 0.125D; + double d8 = this.boundingBox.b + (this.boundingBox.e - this.boundingBox.b) * (double) (k + 1) / (double) b0 - 0.125D + 0.125D; + AxisAlignedBB axisalignedbb1 = AxisAlignedBB.b(this.boundingBox.a, d7, this.boundingBox.c, this.boundingBox.d, d8, this.boundingBox.f); + + if (this.world.b(axisalignedbb1, Material.WATER)) { + d6 += 1.0D / (double) b0; + } + } + + if (d6 > 0.0D) { + if (this.k > 0) { + --this.k; + } else { + short short1 = 500; + + if (this.world.s(MathHelper.floor(this.locX), MathHelper.floor(this.locY) + 1, MathHelper.floor(this.locZ))) { + short1 = 300; + } + + if (this.random.nextInt(short1) == 0) { + this.k = this.random.nextInt(30) + 10; + this.motY -= 0.20000000298023224D; + this.world.makeSound(this, "random.splash", 0.25F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F); + float f3 = (float) MathHelper.floor(this.boundingBox.b); + + float f4; + int l; + float f5; + + for (l = 0; (float) l < 1.0F + this.length * 20.0F; ++l) { + f5 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + f4 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + this.world.a("bubble", this.locX + (double) f5, (double) (f3 + 1.0F), this.locZ + (double) f4, this.motX, this.motY - (double) (this.random.nextFloat() * 0.2F), this.motZ); + } + + for (l = 0; (float) l < 1.0F + this.length * 20.0F; ++l) { + f5 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + f4 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length; + this.world.a("splash", this.locX + (double) f5, (double) (f3 + 1.0F), this.locZ + (double) f4, this.motX, this.motY, this.motZ); + } + } + } + } + + if (this.k > 0) { + this.motY -= (double) (this.random.nextFloat() * this.random.nextFloat() * this.random.nextFloat()) * 0.2D; + } + + d5 = d6 * 2.0D - 1.0D; + this.motY += 0.03999999910593033D * d5; + if (d6 > 0.0D) { + f2 = (float) ((double) f2 * 0.9D); + this.motY *= 0.8D; + } + + this.motX *= (double) f2; + this.motY *= (double) f2; + this.motZ *= (double) f2; + this.setPosition(this.locX, this.locY, this.locZ); + } + } + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("xTile", (short) this.d); + nbttagcompound.a("yTile", (short) this.e); + nbttagcompound.a("zTile", (short) this.f); + nbttagcompound.a("inTile", (byte) this.g); + nbttagcompound.a("shake", (byte) this.a); + nbttagcompound.a("inGround", (byte) (this.h ? 1 : 0)); + } + + public void a(NBTTagCompound nbttagcompound) { + this.d = nbttagcompound.d("xTile"); + this.e = nbttagcompound.d("yTile"); + this.f = nbttagcompound.d("zTile"); + this.g = nbttagcompound.c("inTile") & 255; + this.a = nbttagcompound.c("shake") & 255; + this.h = nbttagcompound.c("inGround") == 1; + } + + public int h() { + byte b0 = 0; + + if (this.c != null) { + // CraftBukkit start + PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) this.owner.getBukkitEntity(), this.c.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_ENTITY); + this.world.getServer().getPluginManager().callEvent(playerFishEvent); + + if (playerFishEvent.isCancelled()) { + this.die(); + this.owner.hookedFish = null; + return 0; + } + // CraftBukkit end + double d0 = this.owner.locX - this.locX; + double d1 = this.owner.locY - this.locY; + double d2 = this.owner.locZ - this.locZ; + double d3 = (double) MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + double d4 = 0.1D; + + this.c.motX += d0 * d4; + this.c.motY += d1 * d4 + (double) MathHelper.a(d3) * 0.08D; + this.c.motZ += d2 * d4; + b0 = 3; + } else if (this.k > 0) { + EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.RAW_FISH)); + // CraftBukkit start + PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) this.owner.getBukkitEntity(), entityitem.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH); + this.world.getServer().getPluginManager().callEvent(playerFishEvent); + + if (playerFishEvent.isCancelled()) { + this.die(); + this.owner.hookedFish = null; + return 0; + } + // CraftBukkit end + double d5 = this.owner.locX - this.locX; + double d6 = this.owner.locY - this.locY; + double d7 = this.owner.locZ - this.locZ; + double d8 = (double) MathHelper.a(d5 * d5 + d6 * d6 + d7 * d7); + double d9 = 0.1D; + + entityitem.motX = d5 * d9; + entityitem.motY = d6 * d9 + (double) MathHelper.a(d8) * 0.08D; + entityitem.motZ = d7 * d9; + this.world.addEntity(entityitem); + this.owner.a(StatisticList.B, 1); + b0 = 1; + } + + if (this.h) { + // CraftBukkit start + PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) this.owner.getBukkitEntity(), null, PlayerFishEvent.State.IN_GROUND); + this.world.getServer().getPluginManager().callEvent(playerFishEvent); + + if (playerFishEvent.isCancelled()) { + this.die(); + this.owner.hookedFish = null; + return 0; + } + // CraftBukkit end + b0 = 2; + } + + // CraftBukkit start + if (b0 == 0) { + PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) this.owner.getBukkitEntity(), null, PlayerFishEvent.State.FAILED_ATTEMPT); + this.world.getServer().getPluginManager().callEvent(playerFishEvent); + } + // CraftBukkit end + this.die(); + this.owner.hookedFish = null; + return b0; + } +} diff --git a/src/main/java/net/minecraft/server/EntityFlying.java b/src/main/java/net/minecraft/server/EntityFlying.java new file mode 100644 index 0000000..ecc90e5 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityFlying.java @@ -0,0 +1,71 @@ +package net.minecraft.server; + +public class EntityFlying extends EntityLiving { + + public EntityFlying(World world) { + super(world); + } + + protected void a(float f) {} + + public void a(float f, float f1) { + if (this.ad()) { + this.a(f, f1, 0.02F); + this.move(this.motX, this.motY, this.motZ); + this.motX *= 0.800000011920929D; + this.motY *= 0.800000011920929D; + this.motZ *= 0.800000011920929D; + } else if (this.ae()) { + this.a(f, f1, 0.02F); + this.move(this.motX, this.motY, this.motZ); + this.motX *= 0.5D; + this.motY *= 0.5D; + this.motZ *= 0.5D; + } else { + float f2 = 0.91F; + + if (this.onGround) { + f2 = 0.54600006F; + int i = this.world.getTypeId(MathHelper.floor(this.locX), MathHelper.floor(this.boundingBox.b) - 1, MathHelper.floor(this.locZ)); + + if (i > 0) { + f2 = Block.byId[i].frictionFactor * 0.91F; + } + } + + float f3 = 0.16277136F / (f2 * f2 * f2); + + this.a(f, f1, this.onGround ? 0.1F * f3 : 0.02F); + f2 = 0.91F; + if (this.onGround) { + f2 = 0.54600006F; + int j = this.world.getTypeId(MathHelper.floor(this.locX), MathHelper.floor(this.boundingBox.b) - 1, MathHelper.floor(this.locZ)); + + if (j > 0) { + f2 = Block.byId[j].frictionFactor * 0.91F; + } + } + + this.move(this.motX, this.motY, this.motZ); + this.motX *= (double) f2; + this.motY *= (double) f2; + this.motZ *= (double) f2; + } + + this.an = this.ao; + double d0 = this.locX - this.lastX; + double d1 = this.locZ - this.lastZ; + float f4 = MathHelper.a(d0 * d0 + d1 * d1) * 4.0F; + + if (f4 > 1.0F) { + f4 = 1.0F; + } + + this.ao += (f4 - this.ao) * 0.4F; + this.ap += this.ao; + } + + public boolean p() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/EntityGhast.java b/src/main/java/net/minecraft/server/EntityGhast.java new file mode 100644 index 0000000..46fc334 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityGhast.java @@ -0,0 +1,192 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.event.entity.EntityTargetEvent; +// CraftBukkit end + +public class EntityGhast extends EntityFlying implements IMonster { + + public int a = 0; + public double b; + public double c; + public double d; + private Entity target = null; + private int h = 0; + public int e = 0; + public int f = 0; + + public EntityGhast(World world) { + super(world); + this.texture = "/mob/ghast.png"; + this.b(4.0F, 4.0F); + this.fireProof = true; + } + + protected void b() { + super.b(); + this.datawatcher.a(16, Byte.valueOf((byte) 0)); + } + + public void m_() { + super.m_(); + byte b0 = this.datawatcher.a(16); + + this.texture = b0 == 1 ? "/mob/ghast_fire.png" : "/mob/ghast.png"; + } + + protected void c_() { + if (!this.world.isStatic && this.world.spawnMonsters == 0) { + this.die(); + } + + this.U(); + this.e = this.f; + double d0 = this.b - this.locX; + double d1 = this.c - this.locY; + double d2 = this.d - this.locZ; + double d3 = (double) MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + + if (d3 < 1.0D || d3 > 60.0D) { + this.b = this.locX + (double) ((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); + this.c = this.locY + (double) ((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); + this.d = this.locZ + (double) ((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); + } else if (this.a-- <= 0) { + this.a += this.random.nextInt(5) + 2; + if (this.a(this.b, this.c, this.d, d3)) { + this.motX += d0 / d3 * 0.1D; + this.motY += d1 / d3 * 0.1D; + this.motZ += d2 / d3 * 0.1D; + } else { + this.b = this.locX; + this.c = this.locY; + this.d = this.locZ; + } + } + + if (this.target != null && this.target.dead) { + // CraftBukkit start + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), null, EntityTargetEvent.TargetReason.TARGET_DIED); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + this.target = ((CraftEntity) event.getTarget()).getHandle(); + } + } + // CraftBukkit end + } + + if (this.target == null || this.h-- <= 0) { + // CraftBukkit start + Entity target = this.world.findNearbyPlayer(this, 100.0D); + if (target != null) { + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), target.getBukkitEntity(), EntityTargetEvent.TargetReason.CLOSEST_PLAYER); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + this.target = ((CraftEntity) event.getTarget()).getHandle(); + } + } + } + // CraftBukkit end + if (this.target != null) { + this.h = 20; + } + } + + double d4 = 64.0D; + + if (this.target != null && this.target.g(this) < d4 * d4) { + double d5 = this.target.locX - this.locX; + double d6 = this.target.boundingBox.b + (double) (this.target.width / 2.0F) - (this.locY + (double) (this.width / 2.0F)); + double d7 = this.target.locZ - this.locZ; + + this.K = this.yaw = -((float) Math.atan2(d5, d7)) * 180.0F / 3.1415927F; + if (this.e(this.target)) { + if (this.f == 10) { + this.world.makeSound(this, "mob.ghast.charge", this.k(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + } + + ++this.f; + if (this.f == 20) { + this.world.makeSound(this, "mob.ghast.fireball", this.k(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + EntityFireball entityfireball = new EntityFireball(this.world, this, d5, d6, d7); + double d8 = 4.0D; + Vec3D vec3d = this.b(1.0F); + + entityfireball.locX = this.locX + vec3d.a * d8; + entityfireball.locY = this.locY + (double) (this.width / 2.0F) + 0.5D; + entityfireball.locZ = this.locZ + vec3d.c * d8; + this.world.addEntity(entityfireball); + this.f = -40; + } + } else if (this.f > 0) { + --this.f; + } + } else { + this.K = this.yaw = -((float) Math.atan2(this.motX, this.motZ)) * 180.0F / 3.1415927F; + if (this.f > 0) { + --this.f; + } + } + + if (!this.world.isStatic) { + byte b0 = this.datawatcher.a(16); + byte b1 = (byte) (this.f > 10 ? 1 : 0); + + if (b0 != b1) { + this.datawatcher.watch(16, Byte.valueOf(b1)); + } + } + } + + private boolean a(double d0, double d1, double d2, double d3) { + double d4 = (this.b - this.locX) / d3; + double d5 = (this.c - this.locY) / d3; + double d6 = (this.d - this.locZ) / d3; + AxisAlignedBB axisalignedbb = this.boundingBox.clone(); + + for (int i = 1; (double) i < d3; ++i) { + axisalignedbb.d(d4, d5, d6); + if (this.world.getEntities(this, axisalignedbb).size() > 0) { + return false; + } + } + + return true; + } + + protected String g() { + return "mob.ghast.moan"; + } + + protected String h() { + return "mob.ghast.scream"; + } + + protected String i() { + return "mob.ghast.death"; + } + + protected int j() { + return Item.SULPHUR.id; + } + + protected float k() { + return 10.0F; + } + + public boolean d() { + return this.random.nextInt(20) == 0 && super.d() && this.world.spawnMonsters > 0; + } + + public int l() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/EntityGiantZombie.java b/src/main/java/net/minecraft/server/EntityGiantZombie.java new file mode 100644 index 0000000..2fc9917 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityGiantZombie.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +public class EntityGiantZombie extends EntityMonster { + + public EntityGiantZombie(World world) { + super(world); + this.texture = "/mob/zombie.png"; + this.aE = 0.5F; + this.damage = 50; + this.health *= 10; + this.height *= 6.0F; + this.b(this.length * 6.0F, this.width * 6.0F); + } + + protected float a(int i, int j, int k) { + return this.world.n(i, j, k) - 0.5F; + } +} diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java new file mode 100644 index 0000000..8be0096 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityHuman.java @@ -0,0 +1,920 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.craftbukkit.TrigMath; +import org.bukkit.craftbukkit.entity.CraftItem; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.player.PlayerBedEnterEvent; +import org.bukkit.event.player.PlayerBedLeaveEvent; +import org.bukkit.event.player.PlayerDropItemEvent; + +import java.util.Iterator; +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public abstract class EntityHuman extends EntityLiving { + + public InventoryPlayer inventory = new InventoryPlayer(this); + public Container defaultContainer; + public Container activeContainer; + public byte l = 0; + public int m = 0; + public float n; + public float o; + public boolean p = false; + public int q = 0; + public String name; + public int dimension; + public double t; + public double u; + public double v; + public double w; + public double x; + public double y; + // CraftBukkit start + public boolean sleeping; + public boolean fauxSleeping; + public String spawnWorld = ""; + // CraftBukkit end + public ChunkCoordinates A; + public int sleepTicks; // CraftBukkit - private -> public + public float B; + public float C; + private ChunkCoordinates b; + private ChunkCoordinates c; + public int D = 20; + protected boolean E = false; + public float F; + private int d = 0; + public EntityFish hookedFish = null; + + public EntityHuman(World world) { + super(world); + this.defaultContainer = new ContainerPlayer(this.inventory, !world.isStatic); + this.activeContainer = this.defaultContainer; + this.height = 1.62F; + ChunkCoordinates chunkcoordinates = world.getSpawn(); + float yaw = world.worldData.getYaw(); // Poseidon + float pitch = world.worldData.getPitch(); // Poseidon + + this.setPositionRotation((double) chunkcoordinates.x + 0.5D, (double) (chunkcoordinates.y + 1), (double) chunkcoordinates.z + 0.5D, yaw, pitch); + this.health = 20; + this.U = "humanoid"; + this.T = 180.0F; + this.maxFireTicks = 20; + this.texture = "/mob/char.png"; + } + + protected void b() { + super.b(); + this.datawatcher.a(16, Byte.valueOf((byte) 0)); + } + + public void m_() { + if (this.isSleeping()) { + ++this.sleepTicks; + if (this.sleepTicks > 100) { + this.sleepTicks = 100; + } + + if (!this.world.isStatic) { + if (!this.o()) { + this.a(true, true, false); + } else if (this.world.d()) { + this.a(false, true, true); + } + } + } else if (this.sleepTicks > 0) { + ++this.sleepTicks; + if (this.sleepTicks >= 110) { + this.sleepTicks = 0; + } + } + + super.m_(); + if (!this.world.isStatic && this.activeContainer != null && !this.activeContainer.b(this)) { + this.y(); + this.activeContainer = this.defaultContainer; + } + + this.t = this.w; + this.u = this.x; + this.v = this.y; + double d0 = this.locX - this.w; + double d1 = this.locY - this.x; + double d2 = this.locZ - this.y; + double d3 = 10.0D; + + if (d0 > d3) { + this.t = this.w = this.locX; + } + + if (d2 > d3) { + this.v = this.y = this.locZ; + } + + if (d1 > d3) { + this.u = this.x = this.locY; + } + + if (d0 < -d3) { + this.t = this.w = this.locX; + } + + if (d2 < -d3) { + this.v = this.y = this.locZ; + } + + if (d1 < -d3) { + this.u = this.x = this.locY; + } + + this.w += d0 * 0.25D; + this.y += d2 * 0.25D; + this.x += d1 * 0.25D; + this.a(StatisticList.k, 1); + if (this.vehicle == null) { + this.c = null; + } + } + + protected boolean D() { + return this.health <= 0 || this.isSleeping(); + } + + protected void y() { + this.activeContainer = this.defaultContainer; + } + + public void E() { + double d0 = this.locX; + double d1 = this.locY; + double d2 = this.locZ; + + super.E(); + this.n = this.o; + this.o = 0.0F; + this.i(this.locX - d0, this.locY - d1, this.locZ - d2); + } + + protected void c_() { + if (this.p) { + ++this.q; + if (this.q >= 8) { + this.q = 0; + this.p = false; + } + } else { + this.q = 0; + } + + this.aa = (float) this.q / 8.0F; + } + + public void v() { + // CraftBukkit - spawnMonsters -> allowMonsters + if (!this.world.allowMonsters && this.health < 20 && this.ticksLived % 20 * 12 == 0) { + this.b(1, RegainReason.REGEN); + } + + this.inventory.f(); + this.n = this.o; + super.v(); + float f = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + // CraftBukkit - Math -> TrigMath + float f1 = (float) TrigMath.atan(-this.motY * 0.20000000298023224D) * 15.0F; + + if (f > 0.1F) { + f = 0.1F; + } + + if (!this.onGround || this.health <= 0) { + f = 0.0F; + } + + if (this.onGround || this.health <= 0) { + f1 = 0.0F; + } + + this.o += (f - this.o) * 0.4F; + this.aj += (f1 - this.aj) * 0.8F; + if (this.health > 0) { + List list = this.world.b((Entity) this, this.boundingBox.b(1.0D, 0.0D, 1.0D)); + + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Entity entity = (Entity) list.get(i); + + if (!entity.dead) { + this.i(entity); + } + } + } + } + } + + private void i(Entity entity) { + entity.b(this); + } + + public void die(Entity entity) { + super.die(entity); + this.b(0.2F, 0.2F); + this.setPosition(this.locX, this.locY, this.locZ); + this.motY = 0.10000000149011612D; + if (this.name.equals("Notch")) { + this.a(new ItemStack(Item.APPLE, 1), true); + } + + this.inventory.h(); + if (entity != null) { + this.motX = (double) (-MathHelper.cos((this.af + this.yaw) * 3.1415927F / 180.0F) * 0.1F); + this.motZ = (double) (-MathHelper.sin((this.af + this.yaw) * 3.1415927F / 180.0F) * 0.1F); + } else { + this.motX = this.motZ = 0.0D; + } + + this.height = 0.1F; + this.a(StatisticList.y, 1); + } + + public void c(Entity entity, int i) { + this.m += i; + if (entity instanceof EntityHuman) { + this.a(StatisticList.A, 1); + } else { + this.a(StatisticList.z, 1); + } + } + + public void F() { + this.a(this.inventory.splitStack(this.inventory.itemInHandIndex, 1), false); + } + + public void b(ItemStack itemstack) { + this.a(itemstack, false); + } + + public void a(ItemStack itemstack, boolean flag) { + this.dropItemStack(itemstack, flag); + } + + public void dropItemStack(ItemStack itemstack, boolean randomDirection) { + if (itemstack != null) { + EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY - 0.30000001192092896D + (double) this.t(), this.locZ, itemstack); + + entityitem.pickupDelay = 40; + float f = 0.1F; + float f1; + + if (randomDirection) { + f1 = this.random.nextFloat() * 0.5F; + float f2 = this.random.nextFloat() * 3.1415927F * 2.0F; + + entityitem.motX = (double) (-MathHelper.sin(f2) * f1); + entityitem.motZ = (double) (MathHelper.cos(f2) * f1); + entityitem.motY = 0.20000000298023224D; + } else { + f = 0.3F; + entityitem.motX = (double) (-MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + entityitem.motZ = (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + entityitem.motY = (double) (-MathHelper.sin(this.pitch / 180.0F * 3.1415927F) * f + 0.1F); + f = 0.02F; + f1 = this.random.nextFloat() * 3.1415927F * 2.0F; + f *= this.random.nextFloat(); + entityitem.motX += Math.cos((double) f1) * (double) f; + entityitem.motY += (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F); + entityitem.motZ += Math.sin((double) f1) * (double) f; + } + + // CraftBukkit start + Player player = (Player) this.getBukkitEntity(); + CraftItem drop = new CraftItem(this.world.getServer(), entityitem); + + PlayerDropItemEvent event = new PlayerDropItemEvent(player, drop); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + player.getInventory().addItem(drop.getItemStack()); + return; + } + // CraftBukkit end + + this.a(entityitem); + this.a(StatisticList.v, 1); + } + } + + protected void a(EntityItem entityitem) { + this.world.addEntity(entityitem); + } + + public float a(Block block) { + float f = this.inventory.a(block); + + if (this.a(Material.WATER)) { + f /= 5.0F; + } + + if (!this.onGround) { + f /= 5.0F; + } + + return f; + } + + public boolean b(Block block) { + return this.inventory.b(block); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + NBTTagList nbttaglist = nbttagcompound.l("Inventory"); + + this.inventory.b(nbttaglist); + this.dimension = nbttagcompound.e("Dimension"); + this.sleeping = nbttagcompound.m("Sleeping"); + this.sleepTicks = nbttagcompound.d("SleepTimer"); + if (this.sleeping) { + this.A = new ChunkCoordinates(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)); + this.a(true, true, false); + } + + // CraftBukkit start + this.spawnWorld = nbttagcompound.getString("SpawnWorld"); + if (this.spawnWorld == "") { + this.spawnWorld = this.world.getServer().getWorlds().get(0).getName(); + } + // CraftBukkit end + + if (nbttagcompound.hasKey("SpawnX") && nbttagcompound.hasKey("SpawnY") && nbttagcompound.hasKey("SpawnZ")) { + this.b = new ChunkCoordinates(nbttagcompound.e("SpawnX"), nbttagcompound.e("SpawnY"), nbttagcompound.e("SpawnZ")); + } + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("Inventory", (NBTBase) this.inventory.a(new NBTTagList())); + nbttagcompound.a("Dimension", this.dimension); + nbttagcompound.a("Sleeping", this.sleeping); + nbttagcompound.a("SleepTimer", (short) this.sleepTicks); + if (this.b != null) { + nbttagcompound.a("SpawnX", this.b.x); + nbttagcompound.a("SpawnY", this.b.y); + nbttagcompound.a("SpawnZ", this.b.z); + nbttagcompound.setString("SpawnWorld", this.spawnWorld); // CraftBukkit + } + } + + public void a(IInventory iinventory) {} + + public void b(int i, int j, int k) {} + + public void receive(Entity entity, int i) {} + + public float t() { + return 0.12F; + } + + protected void s() { + this.height = 1.62F; + } + + public boolean damageEntity(Entity entity, int i) { + this.ay = 0; + if (this.health <= 0) { + return false; + } else { + if (this.isSleeping() && !this.world.isStatic) { + this.a(true, true, false); + } + + if (entity instanceof EntityMonster || entity instanceof EntityArrow) { + if (this.world.spawnMonsters == 0) { + i = 0; + } + + if (this.world.spawnMonsters == 1) { + i = i / 3 + 1; + } + + if (this.world.spawnMonsters == 3) { + i = i * 3 / 2; + } + } + + if (i == 0) { + return false; + } else { + Object object = entity; + + if (entity instanceof EntityArrow && ((EntityArrow) entity).shooter != null) { + object = ((EntityArrow) entity).shooter; + } + + if (object instanceof EntityLiving) { + // CraftBukkit start - this is here instead of EntityMonster because EntityLiving(s) that aren't monsters + // also damage the player in this way. For example, EntitySlime. + + // We handle projectiles in their individual classes! + if (!(entity.getBukkitEntity() instanceof Projectile)) { + org.bukkit.entity.Entity damager = ((Entity) object).getBukkitEntity(); + org.bukkit.entity.Entity damagee = this.getBukkitEntity(); + + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(damager, damagee, EntityDamageEvent.DamageCause.ENTITY_ATTACK, i); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled() || event.getDamage() == 0) { + return false; + } + + i = event.getDamage(); + } + // CraftBukkit end + + this.a((EntityLiving) object, false); + } + + this.a(StatisticList.x, i); + return super.damageEntity(entity, i); + } + } + } + + protected boolean j_() { + return false; + } + + protected void a(EntityLiving entityliving, boolean flag) { + if (!(entityliving instanceof EntityCreeper) && !(entityliving instanceof EntityGhast)) { + if (entityliving instanceof EntityWolf) { + EntityWolf entitywolf = (EntityWolf) entityliving; + + if (entitywolf.isTamed() && this.name.equals(entitywolf.getOwnerName())) { + return; + } + } + + if (!(entityliving instanceof EntityHuman) || this.j_()) { + List list = this.world.a(EntityWolf.class, AxisAlignedBB.b(this.locX, this.locY, this.locZ, this.locX + 1.0D, this.locY + 1.0D, this.locZ + 1.0D).b(16.0D, 4.0D, 16.0D)); + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); + EntityWolf entitywolf1 = (EntityWolf) entity; + + if (entitywolf1.isTamed() && entitywolf1.F() == null && this.name.equals(entitywolf1.getOwnerName()) && (!flag || !entitywolf1.isSitting())) { + // CraftBukkit start + org.bukkit.entity.Entity bukkitTarget = entity == null ? null : entityliving.getBukkitEntity(); + + EntityTargetEvent event; + if (flag) { + event = new EntityTargetEvent(entitywolf1.getBukkitEntity(), bukkitTarget, EntityTargetEvent.TargetReason.OWNER_ATTACKED_TARGET); + } else { + event = new EntityTargetEvent(entitywolf1.getBukkitEntity(), bukkitTarget, EntityTargetEvent.TargetReason.TARGET_ATTACKED_OWNER); + } + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + continue; + } + // CraftBukkit end + + entitywolf1.setSitting(false); + entitywolf1.setTarget(entityliving); + } + } + } + } + } + + protected void c(int i) { + int j = 25 - this.inventory.g(); + int k = i * j + this.d; + + this.inventory.c(i); + i = k / 25; + this.d = k % 25; + super.c(i); + } + + public void a(TileEntityFurnace tileentityfurnace) {} + + public void a(TileEntityDispenser tileentitydispenser) {} + + public void a(TileEntitySign tileentitysign) {} + + public void c(Entity entity) { + if (!entity.a(this)) { + ItemStack itemstack = this.G(); + + if (itemstack != null && entity instanceof EntityLiving) { + itemstack.a((EntityLiving) entity); + // CraftBukkit - bypass infinite items; <= 0 -> == 0 + if (itemstack.count == 0) { + itemstack.a(this); + this.H(); + } + } + } + } + + public ItemStack G() { + return this.inventory.getItemInHand(); + } + + public void H() { + this.inventory.setItem(this.inventory.itemInHandIndex, (ItemStack) null); + } + + public double I() { + return (double) (this.height - 0.5F); + } + + public void w() { + this.q = -1; + this.p = true; + } + + public void d(Entity entity) { + int i = this.inventory.a(entity); + + if (i > 0) { + if (this.motY < 0.0D) { + ++i; + } + + // CraftBukkit start - Don't call the event when the entity is human since it will be called with damageEntity + if (entity instanceof EntityLiving && !(entity instanceof EntityHuman)) { + org.bukkit.entity.Entity damager = this.getBukkitEntity(); + org.bukkit.entity.Entity damagee = (entity == null) ? null : entity.getBukkitEntity(); + + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(damager, damagee, EntityDamageEvent.DamageCause.ENTITY_ATTACK, i); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled() || event.getDamage() == 0) { + return; + } + + i = event.getDamage(); + } + // CraftBukkit end + + // CraftBukkit start - Return when the damage fails so that the item will not lose durability + double d0 = entity.motX; + double d1 = entity.motY; + double d2 = entity.motZ; + + if (!entity.damageEntity(this, i)) { + return; + } + + if (entity instanceof EntityPlayer && entity.velocityChanged && PoseidonConfig.getInstance().getBoolean("settings.player-knockback-fix.enabled", true)) { + boolean cancelled = false; + org.bukkit.entity.Player player = (org.bukkit.entity.Player) entity.getBukkitEntity(); + org.bukkit.util.Vector velocity = new org.bukkit.util.Vector(d0, d1, d2); + + org.bukkit.event.player.PlayerVelocityEvent event = new org.bukkit.event.player.PlayerVelocityEvent(player, velocity.clone()); + this.world.getServer().getPluginManager().callEvent(event); + + if(event.isCancelled()) { + cancelled = true; + } else if(!velocity.equals(event.getVelocity())) { + player.setVelocity(velocity); + } + + if (!cancelled) { + ((EntityPlayer)entity).netServerHandler.sendPacket(new Packet28EntityVelocity(entity)); + entity.velocityChanged = false; + entity.motX = d0; + entity.motY = d1; + entity.motZ = d2; + } + } + + // CraftBukkit end + + ItemStack itemstack = this.G(); + + if (itemstack != null && entity instanceof EntityLiving) { + itemstack.a((EntityLiving) entity, this); + // CraftBukkit - bypass infinite items; <= 0 -> == 0 + if (itemstack.count == 0) { + itemstack.a(this); + this.H(); + } + } + + if (entity instanceof EntityLiving) { + if (entity.T()) { + this.a((EntityLiving) entity, true); + } + + this.a(StatisticList.w, i); + } + } + } + + public void a(ItemStack itemstack) {} + + public void die() { + super.die(); + this.defaultContainer.a(this); + if (this.activeContainer != null) { + this.activeContainer.a(this); + } + } + + public boolean K() { + return !this.sleeping && super.K(); + } + + public EnumBedError a(int i, int j, int k) { + if (!this.world.isStatic) { + if (this.isSleeping() || !this.T()) { + return EnumBedError.OTHER_PROBLEM; + } + + if (this.world.worldProvider.c) { + return EnumBedError.NOT_POSSIBLE_HERE; + } + + if (this.world.d()) { + return EnumBedError.NOT_POSSIBLE_NOW; + } + + if (Math.abs(this.locX - (double) i) > 3.0D || Math.abs(this.locY - (double) j) > 2.0D || Math.abs(this.locZ - (double) k) > 3.0D) { + return EnumBedError.TOO_FAR_AWAY; + } + } + + // CraftBukkit start + if (this.getBukkitEntity() instanceof Player) { + Player player = (Player) this.getBukkitEntity(); + org.bukkit.block.Block bed = this.world.getWorld().getBlockAt(i, j, k); + + PlayerBedEnterEvent event = new PlayerBedEnterEvent(player, bed); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return EnumBedError.OTHER_PROBLEM; + } + } + // CraftBukkit end + + this.b(0.2F, 0.2F); + this.height = 0.2F; + if (this.world.isLoaded(i, j, k)) { + int l = this.world.getData(i, j, k); + int i1 = BlockBed.c(l); + float f = 0.5F; + float f1 = 0.5F; + + switch (i1) { + case 0: + f1 = 0.9F; + break; + + case 1: + f = 0.1F; + break; + + case 2: + f1 = 0.1F; + break; + + case 3: + f = 0.9F; + } + + this.e(i1); + this.setPosition((double) ((float) i + f), (double) ((float) j + 0.9375F), (double) ((float) k + f1)); + } else { + this.setPosition((double) ((float) i + 0.5F), (double) ((float) j + 0.9375F), (double) ((float) k + 0.5F)); + } + + this.sleeping = true; + this.sleepTicks = 0; + this.A = new ChunkCoordinates(i, j, k); + this.motX = this.motZ = this.motY = 0.0D; + if (!this.world.isStatic) { + this.world.everyoneSleeping(); + } + + return EnumBedError.OK; + } + + private void e(int i) { + this.B = 0.0F; + this.C = 0.0F; + switch (i) { + case 0: + this.C = -1.8F; + break; + + case 1: + this.B = 1.8F; + break; + + case 2: + this.C = 1.8F; + break; + + case 3: + this.B = -1.8F; + } + } + + public void a(boolean flag, boolean flag1, boolean flag2) { + this.b(0.6F, 1.8F); + this.s(); + ChunkCoordinates chunkcoordinates = this.A; + ChunkCoordinates chunkcoordinates1 = this.A; + + if (chunkcoordinates != null && this.world.getTypeId(chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z) == Block.BED.id) { + BlockBed.a(this.world, chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z, false); + chunkcoordinates1 = BlockBed.f(this.world, chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z, 0); + if (chunkcoordinates1 == null) { + chunkcoordinates1 = new ChunkCoordinates(chunkcoordinates.x, chunkcoordinates.y + 1, chunkcoordinates.z); + } + + this.setPosition((double) ((float) chunkcoordinates1.x + 0.5F), (double) ((float) chunkcoordinates1.y + this.height + 0.1F), (double) ((float) chunkcoordinates1.z + 0.5F)); + } + + this.sleeping = false; + if (!this.world.isStatic && flag1) { + this.world.everyoneSleeping(); + } + + // CraftBukkit start + if (this.getBukkitEntity() instanceof Player) { + Player player = (Player) this.getBukkitEntity(); + + org.bukkit.block.Block bed; + if (chunkcoordinates != null) { + bed = this.world.getWorld().getBlockAt(chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z); + } else { + bed = this.world.getWorld().getBlockAt(player.getLocation()); + } + + PlayerBedLeaveEvent event = new PlayerBedLeaveEvent(player, bed); + this.world.getServer().getPluginManager().callEvent(event); + } + // CraftBukkit end + + if (flag) { + this.sleepTicks = 0; + } else { + this.sleepTicks = 100; + } + + if (flag2) { + this.a(this.A); + } + } + + private boolean o() { + return this.world.getTypeId(this.A.x, this.A.y, this.A.z) == Block.BED.id; + } + + public static ChunkCoordinates getBed(World world, ChunkCoordinates chunkcoordinates) { + IChunkProvider ichunkprovider = world.o(); + + ichunkprovider.getChunkAt(chunkcoordinates.x - 3 >> 4, chunkcoordinates.z - 3 >> 4); + ichunkprovider.getChunkAt(chunkcoordinates.x + 3 >> 4, chunkcoordinates.z - 3 >> 4); + ichunkprovider.getChunkAt(chunkcoordinates.x - 3 >> 4, chunkcoordinates.z + 3 >> 4); + ichunkprovider.getChunkAt(chunkcoordinates.x + 3 >> 4, chunkcoordinates.z + 3 >> 4); + if (world.getTypeId(chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z) != Block.BED.id) { + return null; + } else { + ChunkCoordinates chunkcoordinates1 = BlockBed.f(world, chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z, 0); + + return chunkcoordinates1; + } + } + + public boolean isSleeping() { + return this.sleeping; + } + + public boolean isDeeplySleeping() { + return this.sleeping && this.sleepTicks >= 100; + } + + public void a(String s) {} + + public ChunkCoordinates getBed() { + return this.b; + } + + public void a(ChunkCoordinates chunkcoordinates) { + if (chunkcoordinates != null) { + this.b = new ChunkCoordinates(chunkcoordinates); + this.spawnWorld = this.world.worldData.name; // CraftBukkit + } else { + this.b = null; + } + } + + public void a(Statistic statistic) { + this.a(statistic, 1); + } + + public void a(Statistic statistic, int i) {} + + protected void O() { + super.O(); + this.a(StatisticList.u, 1); + } + + public void a(float f, float f1) { + double d0 = this.locX; + double d1 = this.locY; + double d2 = this.locZ; + + super.a(f, f1); + this.h(this.locX - d0, this.locY - d1, this.locZ - d2); + } + + private void h(double d0, double d1, double d2) { + if (this.vehicle == null) { + int i; + + if (this.a(Material.WATER)) { + i = Math.round(MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); + if (i > 0) { + this.a(StatisticList.q, i); + } + } else if (this.ad()) { + i = Math.round(MathHelper.a(d0 * d0 + d2 * d2) * 100.0F); + if (i > 0) { + this.a(StatisticList.m, i); + } + } else if (this.p()) { + if (d1 > 0.0D) { + this.a(StatisticList.o, (int) Math.round(d1 * 100.0D)); + } + } else if (this.onGround) { + i = Math.round(MathHelper.a(d0 * d0 + d2 * d2) * 100.0F); + if (i > 0) { + this.a(StatisticList.l, i); + } + } else { + i = Math.round(MathHelper.a(d0 * d0 + d2 * d2) * 100.0F); + if (i > 25) { + this.a(StatisticList.p, i); + } + } + } + } + + private void i(double d0, double d1, double d2) { + if (this.vehicle != null) { + int i = Math.round(MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); + + if (i > 0) { + if (this.vehicle instanceof EntityMinecart) { + this.a(StatisticList.r, i); + if (this.c == null) { + this.c = new ChunkCoordinates(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)); + } else if (this.c.a(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)) >= 1000.0D) { + this.a(AchievementList.q, 1); + } + } else if (this.vehicle instanceof EntityBoat) { + this.a(StatisticList.s, i); + } else if (this.vehicle instanceof EntityPig) { + this.a(StatisticList.t, i); + } + } + } + } + + protected void a(float f) { + if (f >= 2.0F) { + this.a(StatisticList.n, (int) Math.round((double) f * 100.0D)); + } + + super.a(f); + } + + public void a(EntityLiving entityliving) { + if (entityliving instanceof EntityMonster) { + this.a((Statistic) AchievementList.s); + } + } + + public void P() { + if (this.D > 0) { + this.D = 10; + } else { + this.E = true; + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java new file mode 100644 index 0000000..3cbfcc4 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityItem.java @@ -0,0 +1,185 @@ +package net.minecraft.server; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.player.PlayerPickupItemEvent; + +import java.util.logging.Level; + +public class EntityItem extends Entity { + + public ItemStack itemStack; + private int e; + public int b = 0; + public int pickupDelay; + private int f = 5; + public float d = (float) (Math.random() * 3.141592653589793D * 2.0D); + private int lastTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit + + public EntityItem(World world, double d0, double d1, double d2, ItemStack itemstack) { + super(world); + this.b(0.25F, 0.25F); + this.height = this.width / 2.0F; + this.setPosition(d0, d1, d2); + this.itemStack = itemstack; + // CraftBukkit start - infinite item fix + if (this.itemStack.count <= -1) { + this.itemStack.count = 1; + } + // CraftBukkit end + // Project Poseidon start - kill ourselves if the item is null + if (this.itemStack.id < 0 || this.itemStack.id >= Item.byId.length || Item.byId[this.itemStack.id] == null) { + this.die(); + MinecraftException e = new MinecraftException("Unknown item id " + this.itemStack.id); + Bukkit.getLogger().log(Level.WARNING, "Created the EntityItem object with an unknown item: " + this.itemStack, e); + this.itemStack = new ItemStack(Block.STONE); // Workaround for the EntityTracker + } + // Project Poseidon end + this.yaw = (float) (Math.random() * 360.0D); + this.motX = (double) ((float) (Math.random() * 0.20000000298023224D - 0.10000000149011612D)); + this.motY = 0.20000000298023224D; + this.motZ = (double) ((float) (Math.random() * 0.20000000298023224D - 0.10000000149011612D)); + } + + protected boolean n() { + return false; + } + + public EntityItem(World world) { + super(world); + this.b(0.25F, 0.25F); + this.height = this.width / 2.0F; + } + + protected void b() {} + + public void m_() { + super.m_(); + // CraftBukkit start + int currentTick = (int) (System.currentTimeMillis() / 50); + this.pickupDelay -= (currentTick - this.lastTick); + this.lastTick = currentTick; + // CraftBukkit end + // Project Poseidon start - kill ourselves if the item is null + if (this.itemStack.id < 0 || this.itemStack.id >= Item.byId.length || Item.byId[this.itemStack.id] == null) { + this.b = 6000_174; //TODO: Configurable lifetime of the EntityItem + this.die(); + } + // Project Poseidon end + + this.lastX = this.locX; + this.lastY = this.locY; + this.lastZ = this.locZ; + this.motY -= 0.03999999910593033D; + if (this.world.getMaterial(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)) == Material.LAVA) { + this.motY = 0.20000000298023224D; + this.motX = (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.2F); + this.motZ = (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.2F); + this.world.makeSound(this, "random.fizz", 0.4F, 2.0F + this.random.nextFloat() * 0.4F); + } + + this.g(this.locX, (this.boundingBox.b + this.boundingBox.e) / 2.0D, this.locZ); + this.move(this.motX, this.motY, this.motZ); + float f = 0.98F; + + if (this.onGround) { + f = 0.58800006F; + int i = this.world.getTypeId(MathHelper.floor(this.locX), MathHelper.floor(this.boundingBox.b) - 1, MathHelper.floor(this.locZ)); + + if (i > 0) { + f = Block.byId[i].frictionFactor * 0.98F; + } + } + + this.motX *= (double) f; + this.motY *= 0.9800000190734863D; + this.motZ *= (double) f; + if (this.onGround) { + this.motY *= -0.5D; + } + + ++this.e; + ++this.b; + if (this.b >= 6000) { + //Project Poseidon Start + if (CraftEventFactory.callItemDespawnEvent(this).isCancelled()) { + this.b = 0; + return; + } + // CraftBukkit end + this.die(); + } + } + + public boolean f_() { + return this.world.a(this.boundingBox, Material.WATER, this); + } + + protected void burn(int i) { + this.damageEntity((Entity) null, i); + } + + public boolean damageEntity(Entity entity, int i) { + this.af(); + this.f -= i; + if (this.f <= 0) { + this.die(); + } + + return false; + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("Health", (short) ((byte) this.f)); + nbttagcompound.a("Age", (short) this.b); + nbttagcompound.a("Item", this.itemStack.a(new NBTTagCompound())); + } + + public void a(NBTTagCompound nbttagcompound) { + this.f = nbttagcompound.d("Health") & 255; + this.b = nbttagcompound.d("Age"); + NBTTagCompound nbttagcompound1 = nbttagcompound.k("Item"); + + this.itemStack = new ItemStack(nbttagcompound1); + } + + public void b(EntityHuman entityhuman) { + if (!this.world.isStatic) { + int i = this.itemStack.count; + + // CraftBukkit start + int canHold = entityhuman.inventory.canHold(this.itemStack); + int remaining = this.itemStack.count - canHold; + if (this.pickupDelay <= 0 && canHold > 0) { + this.itemStack.count = canHold; + PlayerPickupItemEvent event = new PlayerPickupItemEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); + this.world.getServer().getPluginManager().callEvent(event); + this.itemStack.count = canHold + remaining; + + if (event.isCancelled()) { + return; + } + + // Possibly < 0; fix here so we do not have to modify code below + this.pickupDelay = 0; + } + // CraftBukkit end + + if (this.pickupDelay == 0 && entityhuman.inventory.pickup(this.itemStack)) { + if (this.itemStack.id == Block.LOG.id) { + entityhuman.a((Statistic) AchievementList.g); + } + + if (this.itemStack.id == Item.LEATHER.id) { + entityhuman.a((Statistic) AchievementList.t); + } + + this.world.makeSound(this, "random.pop", 0.2F, ((this.random.nextFloat() - this.random.nextFloat()) * 0.7F + 1.0F) * 2.0F); + entityhuman.receive(this, i); + if (this.itemStack.count <= 0) { + this.die(); + } + } + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityList.java b/src/main/java/net/minecraft/server/EntityList.java new file mode 100644 index 0000000..8335e59 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityList.java @@ -0,0 +1,160 @@ +package net.minecraft.server; + +public class EntityList { + + private transient EntityListEntry[] a = new EntityListEntry[16]; + private transient int b; + private int c = 12; + private final float d = 0.75F; + private transient volatile int e; + + public EntityList() {} + + private static int g(int i) { + i ^= i >>> 20 ^ i >>> 12; + return i ^ i >>> 7 ^ i >>> 4; + } + + private static int a(int i, int j) { + return i & j - 1; + } + + public Object a(int i) { + int j = g(i); + + for (EntityListEntry entitylistentry = this.a[a(j, this.a.length)]; entitylistentry != null; entitylistentry = entitylistentry.c) { + if (entitylistentry.a == i) { + return entitylistentry.b; + } + } + + return null; + } + + public boolean b(int i) { + return this.c(i) != null; + } + + final EntityListEntry c(int i) { + int j = g(i); + + for (EntityListEntry entitylistentry = this.a[a(j, this.a.length)]; entitylistentry != null; entitylistentry = entitylistentry.c) { + if (entitylistentry.a == i) { + return entitylistentry; + } + } + + return null; + } + + public void a(int i, Object object) { + int j = g(i); + int k = a(j, this.a.length); + + for (EntityListEntry entitylistentry = this.a[k]; entitylistentry != null; entitylistentry = entitylistentry.c) { + if (entitylistentry.a == i) { + entitylistentry.b = object; + } + } + + ++this.e; + this.a(j, i, object, k); + } + + private void h(int i) { + EntityListEntry[] aentitylistentry = this.a; + int j = aentitylistentry.length; + + if (j == 1073741824) { + this.c = Integer.MAX_VALUE; + } else { + EntityListEntry[] aentitylistentry1 = new EntityListEntry[i]; + + this.a(aentitylistentry1); + this.a = aentitylistentry1; + this.c = (int) ((float) i * this.d); + } + } + + private void a(EntityListEntry[] aentitylistentry) { + EntityListEntry[] aentitylistentry1 = this.a; + int i = aentitylistentry.length; + + for (int j = 0; j < aentitylistentry1.length; ++j) { + EntityListEntry entitylistentry = aentitylistentry1[j]; + + if (entitylistentry != null) { + aentitylistentry1[j] = null; + + EntityListEntry entitylistentry1; + + do { + entitylistentry1 = entitylistentry.c; + int k = a(entitylistentry.d, i); + + entitylistentry.c = aentitylistentry[k]; + aentitylistentry[k] = entitylistentry; + entitylistentry = entitylistentry1; + } while (entitylistentry1 != null); + } + } + } + + public Object d(int i) { + EntityListEntry entitylistentry = this.e(i); + + return entitylistentry == null ? null : entitylistentry.b; + } + + final EntityListEntry e(int i) { + int j = g(i); + int k = a(j, this.a.length); + EntityListEntry entitylistentry = this.a[k]; + + EntityListEntry entitylistentry1; + EntityListEntry entitylistentry2; + + for (entitylistentry1 = entitylistentry; entitylistentry1 != null; entitylistentry1 = entitylistentry2) { + entitylistentry2 = entitylistentry1.c; + if (entitylistentry1.a == i) { + ++this.e; + --this.b; + if (entitylistentry == entitylistentry1) { + this.a[k] = entitylistentry2; + } else { + entitylistentry.c = entitylistentry2; + } + + return entitylistentry1; + } + + entitylistentry = entitylistentry1; + } + + return entitylistentry1; + } + + public void a() { + ++this.e; + EntityListEntry[] aentitylistentry = this.a; + + for (int i = 0; i < aentitylistentry.length; ++i) { + aentitylistentry[i] = null; + } + + this.b = 0; + } + + private void a(int i, int j, Object object, int k) { + EntityListEntry entitylistentry = this.a[k]; + + this.a[k] = new EntityListEntry(i, j, object, entitylistentry); + if (this.b++ >= this.c) { + this.h(2 * this.a.length); + } + } + + static int f(int i) { + return g(i); + } +} diff --git a/src/main/java/net/minecraft/server/EntityListEntry.java b/src/main/java/net/minecraft/server/EntityListEntry.java new file mode 100644 index 0000000..59506d9 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityListEntry.java @@ -0,0 +1,53 @@ +package net.minecraft.server; + +class EntityListEntry { + + final int a; + Object b; + EntityListEntry c; + final int d; + + EntityListEntry(int i, int j, Object object, EntityListEntry entitylistentry) { + this.b = object; + this.c = entitylistentry; + this.a = j; + this.d = i; + } + + public final int a() { + return this.a; + } + + public final Object b() { + return this.b; + } + + public final boolean equals(Object object) { + if (!(object instanceof EntityListEntry)) { + return false; + } else { + EntityListEntry entitylistentry = (EntityListEntry) object; + Integer integer = Integer.valueOf(this.a()); + Integer integer1 = Integer.valueOf(entitylistentry.a()); + + if (integer == integer1 || integer != null && integer.equals(integer1)) { + Object object1 = this.b(); + Object object2 = entitylistentry.b(); + + if (object1 == object2 || object1 != null && object1.equals(object2)) { + return true; + } + } + + return false; + } + } + + public final int hashCode() { + return EntityList.f(this.a); + } + + public final String toString() { + return this.a() + "=" + this.b(); + } +} diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java new file mode 100644 index 0000000..befe2cc --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -0,0 +1,909 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.craftbukkit.TrigMath; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.event.entity.EntityDamageByBlockEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public abstract class EntityLiving extends Entity { + + public int maxNoDamageTicks = 20; + public float I; + public float J; + public float K = 0.0F; + public float L = 0.0F; + protected float M; + protected float N; + protected float O; + protected float P; + protected boolean Q = true; + protected String texture = "/mob/char.png"; + protected boolean S = true; + protected float T = 0.0F; + protected String U = null; + protected float V = 1.0F; + protected int W = 0; + protected float X = 0.0F; + public boolean Y = false; + public float Z; + public float aa; + public int health = 10; + public int ac; + private int a; + public int hurtTicks; + public int ae; + public float af = 0.0F; + public int deathTicks = 0; + public int attackTicks = 0; + public float ai; + public float aj; + protected boolean ak = false; + public int al = -1; + public float am = (float) (Math.random() * 0.8999999761581421D + 0.10000000149011612D); + public float an; + public float ao; + public float ap; + protected int aq; + protected double ar; + protected double as; + protected double at; + protected double au; + protected double av; + float aw = 0.0F; + public int lastDamage = 0; // CraftBukkit - protected -> public + protected int ay = 0; + protected float az; + protected float aA; + protected float aB; + protected boolean aC = false; + protected float aD = 0.0F; + protected float aE = 0.7F; + private Entity b; + protected int aF = 0; + + public EntityLiving(World world) { + super(world); + this.aI = true; + this.J = (float) (Math.random() + 1.0D) * 0.01F; + this.setPosition(this.locX, this.locY, this.locZ); + this.I = (float) Math.random() * 12398.0F; + this.yaw = (float) (Math.random() * 3.1415927410125732D * 2.0D); + this.bs = 0.5F; + } + + protected void b() {} + + public boolean e(Entity entity) { + return this.world.a(Vec3D.create(this.locX, this.locY + (double) this.t(), this.locZ), Vec3D.create(entity.locX, entity.locY + (double) entity.t(), entity.locZ)) == null; + } + + public boolean l_() { + return !this.dead; + } + + public boolean d_() { + return !this.dead; + } + + public float t() { + return this.width * 0.85F; + } + + public int e() { + return 80; + } + + public void Q() { + String s = this.g(); + + if (s != null) { + this.world.makeSound(this, s, this.k(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + } + } + + public void R() { + this.Z = this.aa; + super.R(); + if (this.random.nextInt(1000) < this.a++) { + this.a = -this.e(); + this.Q(); + } + + if (this.T() && this.K()) { + // CraftBukkit start + EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.SUFFOCATION, 1); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.damageEntity((Entity) null, event.getDamage()); + } + // CraftBukkit end + } + + if (this.fireProof || this.world.isStatic) { + this.fireTicks = 0; + } + + int i; + + if (this.T() && this.a(Material.WATER) && !this.b_()) { + --this.airTicks; + if (this.airTicks == -20) { + this.airTicks = 0; + + for (i = 0; i < 8; ++i) { + float f = this.random.nextFloat() - this.random.nextFloat(); + float f1 = this.random.nextFloat() - this.random.nextFloat(); + float f2 = this.random.nextFloat() - this.random.nextFloat(); + + this.world.a("bubble", this.locX + (double) f, this.locY + (double) f1, this.locZ + (double) f2, this.motX, this.motY, this.motZ); + } + + // CraftBukkit start + EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.DROWNING, 2); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled() && event.getDamage() != 0) { + boolean vc = this.velocityChanged; + this.damageEntity((Entity) null, event.getDamage()); + if (PoseidonConfig.getInstance().getBoolean("settings.fix-drowning-push-down.enabled", true)) this.velocityChanged = vc; + } + // CraftBukkit end + } + + this.fireTicks = 0; + } else { + this.airTicks = this.maxAirTicks; + } + + this.ai = this.aj; + if (this.attackTicks > 0) { + --this.attackTicks; + } + + if (this.hurtTicks > 0) { + --this.hurtTicks; + } + + if (this.noDamageTicks > 0) { + --this.noDamageTicks; + } + + if (this.health <= 0) { + ++this.deathTicks; + if (this.deathTicks > 20) { + this.X(); + this.die(); + + for (i = 0; i < 20; ++i) { + double d0 = this.random.nextGaussian() * 0.02D; + double d1 = this.random.nextGaussian() * 0.02D; + double d2 = this.random.nextGaussian() * 0.02D; + + this.world.a("explode", this.locX + (double) (this.random.nextFloat() * this.length * 2.0F) - (double) this.length, this.locY + (double) (this.random.nextFloat() * this.width), this.locZ + (double) (this.random.nextFloat() * this.length * 2.0F) - (double) this.length, d0, d1, d2); + } + } + } + + this.P = this.O; + this.L = this.K; + this.lastYaw = this.yaw; + this.lastPitch = this.pitch; + } + + public void S() { + for (int i = 0; i < 20; ++i) { + double d0 = this.random.nextGaussian() * 0.02D; + double d1 = this.random.nextGaussian() * 0.02D; + double d2 = this.random.nextGaussian() * 0.02D; + double d3 = 10.0D; + + this.world.a("explode", this.locX + (double) (this.random.nextFloat() * this.length * 2.0F) - (double) this.length - d0 * d3, this.locY + (double) (this.random.nextFloat() * this.width) - d1 * d3, this.locZ + (double) (this.random.nextFloat() * this.length * 2.0F) - (double) this.length - d2 * d3, d0, d1, d2); + } + } + + public void E() { + super.E(); + this.M = this.N; + this.N = 0.0F; + } + + public void m_() { + super.m_(); + this.v(); + double d0 = this.locX - this.lastX; + double d1 = this.locZ - this.lastZ; + float f = MathHelper.a(d0 * d0 + d1 * d1); + float f1 = this.K; + float f2 = 0.0F; + + this.M = this.N; + float f3 = 0.0F; + + if (f > 0.05F) { + f3 = 1.0F; + f2 = f * 3.0F; + // CraftBukkit - Math -> TrigMath + f1 = (float) TrigMath.atan2(d1, d0) * 180.0F / 3.1415927F - 90.0F; + } + + if (this.aa > 0.0F) { + f1 = this.yaw; + } + + if (!this.onGround) { + f3 = 0.0F; + } + + this.N += (f3 - this.N) * 0.3F; + + float f4; + + for (f4 = f1 - this.K; f4 < -180.0F; f4 += 360.0F) { + ; + } + + while (f4 >= 180.0F) { + f4 -= 360.0F; + } + + this.K += f4 * 0.3F; + + float f5; + + for (f5 = this.yaw - this.K; f5 < -180.0F; f5 += 360.0F) { + ; + } + + while (f5 >= 180.0F) { + f5 -= 360.0F; + } + + boolean flag = f5 < -90.0F || f5 >= 90.0F; + + if (f5 < -75.0F) { + f5 = -75.0F; + } + + if (f5 >= 75.0F) { + f5 = 75.0F; + } + + this.K = this.yaw - f5; + if (f5 * f5 > 2500.0F) { + this.K += f5 * 0.2F; + } + + if (flag) { + f2 *= -1.0F; + } + + while (this.yaw - this.lastYaw < -180.0F) { + this.lastYaw -= 360.0F; + } + + while (this.yaw - this.lastYaw >= 180.0F) { + this.lastYaw += 360.0F; + } + + while (this.K - this.L < -180.0F) { + this.L -= 360.0F; + } + + while (this.K - this.L >= 180.0F) { + this.L += 360.0F; + } + + while (this.pitch - this.lastPitch < -180.0F) { + this.lastPitch -= 360.0F; + } + + while (this.pitch - this.lastPitch >= 180.0F) { + this.lastPitch += 360.0F; + } + + this.O += f2; + } + + protected void b(float f, float f1) { + super.b(f, f1); + } + + // CraftBukkit start - delegate so we can handle providing a reason for health being regained + public void b(int i) { + b(i, RegainReason.CUSTOM); + } + + public void b(int i, RegainReason regainReason) { + if (this.health > 0) { + EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), i, regainReason); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.health += event.getAmount(); + } + // CraftBukkit end + if (this.health > 20) { + this.health = 20; + } + + this.noDamageTicks = this.maxNoDamageTicks / 2; + } + } + + public boolean damageEntity(Entity entity, int i) { + if (this.world.isStatic) { + return false; + } else { + this.ay = 0; + if (this.health <= 0) { + return false; + } else { + this.ao = 1.5F; + boolean flag = true; + + if ((float) this.noDamageTicks > (float) this.maxNoDamageTicks / 2.0F) { + if (i <= this.lastDamage) { + return false; + } + + this.c(i - this.lastDamage); + this.lastDamage = i; + flag = false; + } else { + this.lastDamage = i; + this.ac = this.health; + this.noDamageTicks = this.maxNoDamageTicks; + this.c(i); + this.hurtTicks = this.ae = 10; + } + + this.af = 0.0F; + if (flag) { + this.world.a(this, (byte) 2); + this.af(); + if (entity != null) { + this.airBorne = true; + double d0 = entity.locX - this.locX; + + double d1; + + for (d1 = entity.locZ - this.locZ; d0 * d0 + d1 * d1 < 1.0E-4D; d1 = (Math.random() - Math.random()) * 0.01D) { + d0 = (Math.random() - Math.random()) * 0.01D; + } + + this.af = (float) (Math.atan2(d1, d0) * 180.0D / 3.1415927410125732D) - this.yaw; + this.a(entity, i, d0, d1); + } else { + this.af = (float) ((int) (Math.random() * 2.0D) * 180); + } + } + + if (this.health <= 0) { + if (flag) { + this.world.makeSound(this, this.i(), this.k(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + } + + this.die(entity); + } else if (flag) { + this.world.makeSound(this, this.h(), this.k(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + } + + return true; + } + } + } + + protected void c(int i) { + this.health -= i; + } + + protected float k() { + return 1.0F; + } + + protected String g() { + return null; + } + + protected String h() { + return "random.hurt"; + } + + protected String i() { + return "random.hurt"; + } + + public void a(Entity entity, int i, double d0, double d1) { + float f = MathHelper.a(d0 * d0 + d1 * d1); + float f1 = 0.4F; + + this.motX /= 2.0D; + this.motY /= 2.0D; + this.motZ /= 2.0D; + this.motX -= d0 / (double) f * (double) f1; + this.motY += 0.4000000059604645D; + this.motZ -= d1 / (double) f * (double) f1; + if (this.motY > 0.4000000059604645D) { + this.motY = 0.4000000059604645D; + } + } + + public void die(Entity entity) { + if (this.W >= 0 && entity != null) { + entity.c(this, this.W); + } + + if (entity != null) { + entity.a(this); + } + + this.ak = true; + if (!this.world.isStatic) { + this.q(); + } + + this.world.a(this, (byte) 3); + } + + protected void q() { + int i = this.j(); + + // CraftBukkit start - whole method + List loot = new java.util.ArrayList(); + int count = this.random.nextInt(3); + + if ((i > 0) && (count > 0)) { + loot.add(new org.bukkit.inventory.ItemStack(i, count)); + } + + CraftEntity entity = (CraftEntity) this.getBukkitEntity(); + EntityDeathEvent event = new EntityDeathEvent(entity, loot); + org.bukkit.World bworld = this.world.getWorld(); + this.world.getServer().getPluginManager().callEvent(event); + + for (org.bukkit.inventory.ItemStack stack: event.getDrops()) { + bworld.dropItemNaturally(entity.getLocation(), stack); + } + // CraftBukkit end + } + + protected int j() { + return 0; + } + + protected void a(float f) { + super.a(f); + int i = (int) Math.ceil((double) (f - 3.0F)); + + if (i > 0) { + // CraftBukkit start + EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.FALL, i); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled() && event.getDamage() != 0) { + this.damageEntity((Entity) null, event.getDamage()); + } + // CraftBukkit end + + int j = this.world.getTypeId(MathHelper.floor(this.locX), MathHelper.floor(this.locY - 0.20000000298023224D - (double) this.height), MathHelper.floor(this.locZ)); + + if (j > 0) { + StepSound stepsound = Block.byId[j].stepSound; + + this.world.makeSound(this, stepsound.getName(), stepsound.getVolume1() * 0.5F, stepsound.getVolume2() * 0.75F); + } + } + } + + public void a(float f, float f1) { + double d0; + + if (this.ad()) { + d0 = this.locY; + this.a(f, f1, 0.02F); + this.move(this.motX, this.motY, this.motZ); + this.motX *= 0.800000011920929D; + this.motY *= 0.800000011920929D; + this.motZ *= 0.800000011920929D; + this.motY -= 0.02D; + if (this.positionChanged && this.d(this.motX, this.motY + 0.6000000238418579D - this.locY + d0, this.motZ)) { + this.motY = 0.30000001192092896D; + } + } else if (this.ae()) { + d0 = this.locY; + this.a(f, f1, 0.02F); + this.move(this.motX, this.motY, this.motZ); + this.motX *= 0.5D; + this.motY *= 0.5D; + this.motZ *= 0.5D; + this.motY -= 0.02D; + if (this.positionChanged && this.d(this.motX, this.motY + 0.6000000238418579D - this.locY + d0, this.motZ)) { + this.motY = 0.30000001192092896D; + } + } else { + float f2 = 0.91F; + + if (this.onGround) { + f2 = 0.54600006F; + int i = this.world.getTypeId(MathHelper.floor(this.locX), MathHelper.floor(this.boundingBox.b) - 1, MathHelper.floor(this.locZ)); + + if (i > 0) { + f2 = Block.byId[i].frictionFactor * 0.91F; + } + } + + float f3 = 0.16277136F / (f2 * f2 * f2); + + this.a(f, f1, this.onGround ? 0.1F * f3 : 0.02F); + f2 = 0.91F; + if (this.onGround) { + f2 = 0.54600006F; + int j = this.world.getTypeId(MathHelper.floor(this.locX), MathHelper.floor(this.boundingBox.b) - 1, MathHelper.floor(this.locZ)); + + if (j > 0) { + f2 = Block.byId[j].frictionFactor * 0.91F; + } + } + + if (this.p()) { + float f4 = 0.15F; + + if (this.motX < (double) (-f4)) { + this.motX = (double) (-f4); + } + + if (this.motX > (double) f4) { + this.motX = (double) f4; + } + + if (this.motZ < (double) (-f4)) { + this.motZ = (double) (-f4); + } + + if (this.motZ > (double) f4) { + this.motZ = (double) f4; + } + + this.fallDistance = 0.0F; + if (this.motY < -0.15D) { + this.motY = -0.15D; + } + + if (this.isSneaking() && this.motY < 0.0D) { + this.motY = 0.0D; + } + } + + this.move(this.motX, this.motY, this.motZ); + if (this.positionChanged && this.p()) { + this.motY = 0.2D; + } + + this.motY -= 0.08D; + this.motY *= 0.9800000190734863D; + this.motX *= (double) f2; + this.motZ *= (double) f2; + } + + this.an = this.ao; + d0 = this.locX - this.lastX; + double d1 = this.locZ - this.lastZ; + float f5 = MathHelper.a(d0 * d0 + d1 * d1) * 4.0F; + + if (f5 > 1.0F) { + f5 = 1.0F; + } + + this.ao += (f5 - this.ao) * 0.4F; + this.ap += this.ao; + } + + public boolean p() { + int i = MathHelper.floor(this.locX); + int j = MathHelper.floor(this.boundingBox.b); + int k = MathHelper.floor(this.locZ); + + return this.world.getTypeId(i, j, k) == Block.LADDER.id; + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("Health", (short) this.health); + nbttagcompound.a("HurtTime", (short) this.hurtTicks); + nbttagcompound.a("DeathTime", (short) this.deathTicks); + nbttagcompound.a("AttackTime", (short) this.attackTicks); + } + + public void a(NBTTagCompound nbttagcompound) { + this.health = nbttagcompound.d("Health"); + if (!nbttagcompound.hasKey("Health")) { + this.health = 10; + } + + this.hurtTicks = nbttagcompound.d("HurtTime"); + this.deathTicks = nbttagcompound.d("DeathTime"); + this.attackTicks = nbttagcompound.d("AttackTime"); + } + + public boolean T() { + return !this.dead && this.health > 0; + } + + public boolean b_() { + return false; + } + + public void v() { + if (this.aq > 0) { + double d0 = this.locX + (this.ar - this.locX) / (double) this.aq; + double d1 = this.locY + (this.as - this.locY) / (double) this.aq; + double d2 = this.locZ + (this.at - this.locZ) / (double) this.aq; + + double d3; + + for (d3 = this.au - (double) this.yaw; d3 < -180.0D; d3 += 360.0D) { + ; + } + + while (d3 >= 180.0D) { + d3 -= 360.0D; + } + + this.yaw = (float) ((double) this.yaw + d3 / (double) this.aq); + this.pitch = (float) ((double) this.pitch + (this.av - (double) this.pitch) / (double) this.aq); + --this.aq; + this.setPosition(d0, d1, d2); + this.c(this.yaw, this.pitch); + List list = this.world.getEntities(this, this.boundingBox.shrink(0.03125D, 0.0D, 0.03125D)); + + if (list.size() > 0) { + double d4 = 0.0D; + + for (int i = 0; i < list.size(); ++i) { + AxisAlignedBB axisalignedbb = (AxisAlignedBB) list.get(i); + + if (axisalignedbb.e > d4) { + d4 = axisalignedbb.e; + } + } + + d1 += d4 - this.boundingBox.b; + this.setPosition(d0, d1, d2); + } + } + + if (this.D()) { + this.aC = false; + this.az = 0.0F; + this.aA = 0.0F; + this.aB = 0.0F; + } else if (!this.Y) { + this.c_(); + } + + boolean flag = this.ad(); + boolean flag1 = this.ae(); + + if (this.aC) { + if (flag) { + this.motY += 0.03999999910593033D; + } else if (flag1) { + this.motY += 0.03999999910593033D; + } else if (this.onGround) { + this.O(); + } + } + + this.az *= 0.98F; + this.aA *= 0.98F; + this.aB *= 0.9F; + this.a(this.az, this.aA); + List list1 = this.world.b((Entity) this, this.boundingBox.b(0.20000000298023224D, 0.0D, 0.20000000298023224D)); + + if (list1 != null && list1.size() > 0) { + for (int j = 0; j < list1.size(); ++j) { + Entity entity = (Entity) list1.get(j); + + if (entity.d_()) { + entity.collide(this); + } + } + } + } + + protected boolean D() { + return this.health <= 0; + } + + protected void O() { + this.motY = 0.41999998688697815D; + this.airBorne = true; + } + + protected boolean h_() { + return true; + } + + protected void U() { + EntityHuman entityhuman = this.world.findNearbyPlayer(this, -1.0D); + + if (this.h_() && entityhuman != null) { + double d0 = entityhuman.locX - this.locX; + double d1 = entityhuman.locY - this.locY; + double d2 = entityhuman.locZ - this.locZ; + double d3 = d0 * d0 + d1 * d1 + d2 * d2; + + if (d3 > 16384.0D) { + this.die(); + } + + if (this.ay > 600 && this.random.nextInt(800) == 0) { + if (d3 < 1024.0D) { + this.ay = 0; + } else { + this.die(); + } + } + } + } + + protected void c_() { + ++this.ay; + EntityHuman entityhuman = this.world.findNearbyPlayer(this, -1.0D); + + this.U(); + this.az = 0.0F; + this.aA = 0.0F; + float f = 8.0F; + + if (this.random.nextFloat() < 0.02F) { + entityhuman = this.world.findNearbyPlayer(this, (double) f); + if (entityhuman != null) { + this.b = entityhuman; + this.aF = 10 + this.random.nextInt(20); + } else { + this.aB = (this.random.nextFloat() - 0.5F) * 20.0F; + } + } + + if (this.b != null) { + this.a(this.b, 10.0F, (float) this.u()); + if (this.aF-- <= 0 || this.b.dead || this.b.g(this) > (double) (f * f)) { + this.b = null; + } + } else { + if (this.random.nextFloat() < 0.05F) { + this.aB = (this.random.nextFloat() - 0.5F) * 20.0F; + } + + this.yaw += this.aB; + this.pitch = this.aD; + } + + boolean flag = this.ad(); + boolean flag1 = this.ae(); + + if (flag || flag1) { + this.aC = this.random.nextFloat() < 0.8F; + } + } + + protected int u() { + return 40; + } + + public void a(Entity entity, float f, float f1) { + double d0 = entity.locX - this.locX; + double d1 = entity.locZ - this.locZ; + double d2; + + if (entity instanceof EntityLiving) { + EntityLiving entityliving = (EntityLiving) entity; + + d2 = this.locY + (double) this.t() - (entityliving.locY + (double) entityliving.t()); + } else { + d2 = (entity.boundingBox.b + entity.boundingBox.e) / 2.0D - (this.locY + (double) this.t()); + } + + double d3 = (double) MathHelper.a(d0 * d0 + d1 * d1); + float f2 = (float) (Math.atan2(d1, d0) * 180.0D / 3.1415927410125732D) - 90.0F; + float f3 = (float) (-(Math.atan2(d2, d3) * 180.0D / 3.1415927410125732D)); + + this.pitch = -this.b(this.pitch, f3, f1); + this.yaw = this.b(this.yaw, f2, f); + } + + public boolean V() { + return this.b != null; + } + + public Entity W() { + return this.b; + } + + private float b(float f, float f1, float f2) { + float f3; + + for (f3 = f1 - f; f3 < -180.0F; f3 += 360.0F) { + ; + } + + while (f3 >= 180.0F) { + f3 -= 360.0F; + } + + if (f3 > f2) { + f3 = f2; + } + + if (f3 < -f2) { + f3 = -f2; + } + + return f + f3; + } + + public void X() {} + + public boolean d() { + return this.world.containsEntity(this.boundingBox) && this.world.getEntities(this, this.boundingBox).size() == 0 && !this.world.c(this.boundingBox); + } + + protected void Y() { + // CraftBukkit start + EntityDamageByBlockEvent event = new EntityDamageByBlockEvent(null, this.getBukkitEntity(), EntityDamageEvent.DamageCause.VOID, 4); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled() || event.getDamage() == 0) { + return; + } + + this.damageEntity((Entity) null, event.getDamage()); + // CraftBukkit end + } + + public Vec3D Z() { + return this.b(1.0F); + } + + public Vec3D b(float f) { + float f1; + float f2; + float f3; + float f4; + + if (f == 1.0F) { + f1 = MathHelper.cos(-this.yaw * 0.017453292F - 3.1415927F); + f2 = MathHelper.sin(-this.yaw * 0.017453292F - 3.1415927F); + f3 = -MathHelper.cos(-this.pitch * 0.017453292F); + f4 = MathHelper.sin(-this.pitch * 0.017453292F); + return Vec3D.create((double) (f2 * f3), (double) f4, (double) (f1 * f3)); + } else { + f1 = this.lastPitch + (this.pitch - this.lastPitch) * f; + f2 = this.lastYaw + (this.yaw - this.lastYaw) * f; + f3 = MathHelper.cos(-f2 * 0.017453292F - 3.1415927F); + f4 = MathHelper.sin(-f2 * 0.017453292F - 3.1415927F); + float f5 = -MathHelper.cos(-f1 * 0.017453292F); + float f6 = MathHelper.sin(-f1 * 0.017453292F); + + return Vec3D.create((double) (f4 * f5), (double) f6, (double) (f3 * f5)); + } + } + + public int l() { + return 4; + } + + public boolean isSleeping() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/EntityMinecart.java b/src/main/java/net/minecraft/server/EntityMinecart.java new file mode 100644 index 0000000..db84104 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityMinecart.java @@ -0,0 +1,887 @@ +package net.minecraft.server; + +import org.bukkit.Location; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.vehicle.*; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityMinecart extends Entity implements IInventory { + + private ItemStack[] items; + public int damage; + public int b; + public int c; + private boolean i; + public int type; + public int e; + public double f; + public double g; + private static final int[][][] matrix = new int[][][] { { { 0, 0, -1}, { 0, 0, 1}}, { { -1, 0, 0}, { 1, 0, 0}}, { { -1, -1, 0}, { 1, 0, 0}}, { { -1, 0, 0}, { 1, -1, 0}}, { { 0, 0, -1}, { 0, -1, 1}}, { { 0, -1, -1}, { 0, 0, 1}}, { { 0, 0, 1}, { 1, 0, 0}}, { { 0, 0, 1}, { -1, 0, 0}}, { { 0, 0, -1}, { -1, 0, 0}}, { { 0, 0, -1}, { 1, 0, 0}}}; + private int k; + private double l; + private double m; + private double n; + private double o; + private double p; + + // CraftBukkit start + public boolean slowWhenEmpty = true; + public double derailedX = 0.5; + public double derailedY = 0.5; + public double derailedZ = 0.5; + public double flyingX = 0.95; + public double flyingY = 0.95; + public double flyingZ = 0.95; + public double maxSpeed = 0.4D; + + public ItemStack[] getContents() { + return this.items; + } + // CraftBukkit end + + public EntityMinecart(World world) { + super(world); + this.items = new ItemStack[27]; // CraftBukkit + this.damage = 0; + this.b = 0; + this.c = 1; + this.i = false; + this.aI = true; + this.b(0.98F, 0.7F); + this.height = this.width / 2.0F; + } + + protected boolean n() { + return false; + } + + protected void b() {} + + public AxisAlignedBB a_(Entity entity) { + return entity.boundingBox; + } + + public AxisAlignedBB e_() { + return null; + } + + public boolean d_() { + return true; + } + + public EntityMinecart(World world, double d0, double d1, double d2, int i) { + this(world); + this.setPosition(d0, d1 + (double) this.height, d2); + this.motX = 0.0D; + this.motY = 0.0D; + this.motZ = 0.0D; + this.lastX = d0; + this.lastY = d1; + this.lastZ = d2; + this.type = i; + + this.world.getServer().getPluginManager().callEvent(new VehicleCreateEvent((Vehicle) this.getBukkitEntity())); // CraftBukkit + } + + public double m() { + return (double) this.width * 0.0D - 0.30000001192092896D; + } + + public boolean damageEntity(Entity entity, int i) { + if (!this.world.isStatic && !this.dead) { + // CraftBukkit start + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); + org.bukkit.entity.Entity passenger = (entity == null) ? null : entity.getBukkitEntity(); + + VehicleDamageEvent event = new VehicleDamageEvent(vehicle, passenger, i); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return true; + } + + i = event.getDamage(); + // CraftBukkit end + + this.c = -this.c; + this.b = 10; + this.af(); + this.damage += i * 10; + if (this.damage > 40) { + if (this.passenger != null) { + this.passenger.mount(this); + } + + // CraftBukkit start + VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, passenger); + this.world.getServer().getPluginManager().callEvent(destroyEvent); + + if (destroyEvent.isCancelled()) { + this.damage = 40; // Maximize damage so this doesn't get triggered again right away + return true; + } + // CraftBukkit end + + this.die(); + this.a(Item.MINECART.id, 1, 0.0F); + if (this.type == 1) { + EntityMinecart entityminecart = this; + + for (int j = 0; j < entityminecart.getSize(); ++j) { + ItemStack itemstack = entityminecart.getItem(j); + + if (itemstack != null) { + float f = this.random.nextFloat() * 0.8F + 0.1F; + float f1 = this.random.nextFloat() * 0.8F + 0.1F; + float f2 = this.random.nextFloat() * 0.8F + 0.1F; + + while (itemstack.count > 0) { + int k = this.random.nextInt(21) + 10; + + if (k > itemstack.count) { + k = itemstack.count; + } + + itemstack.count -= k; + EntityItem entityitem = new EntityItem(this.world, this.locX + (double) f, this.locY + (double) f1, this.locZ + (double) f2, new ItemStack(itemstack.id, k, itemstack.getData())); + float f3 = 0.05F; + + entityitem.motX = (double) ((float) this.random.nextGaussian() * f3); + entityitem.motY = (double) ((float) this.random.nextGaussian() * f3 + 0.2F); + entityitem.motZ = (double) ((float) this.random.nextGaussian() * f3); + this.world.addEntity(entityitem); + } + entityminecart.setItem(j, null); + } + } + + this.a(Block.CHEST.id, 1, 0.0F); + } else if (this.type == 2) { + this.a(Block.FURNACE.id, 1, 0.0F); + } + } + + return true; + } else { + return true; + } + } + + public boolean l_() { + return !this.dead; + } + + public void die() { + for (int i = 0; i < this.getSize(); ++i) { + ItemStack itemstack = this.getItem(i); + + if (itemstack != null) { + float f = this.random.nextFloat() * 0.8F + 0.1F; + float f1 = this.random.nextFloat() * 0.8F + 0.1F; + float f2 = this.random.nextFloat() * 0.8F + 0.1F; + + while (itemstack.count > 0) { + int j = this.random.nextInt(21) + 10; + + if (j > itemstack.count) { + j = itemstack.count; + } + + itemstack.count -= j; + EntityItem entityitem = new EntityItem(this.world, this.locX + (double) f, this.locY + (double) f1, this.locZ + (double) f2, new ItemStack(itemstack.id, j, itemstack.getData())); + float f3 = 0.05F; + + entityitem.motX = (double) ((float) this.random.nextGaussian() * f3); + entityitem.motY = (double) ((float) this.random.nextGaussian() * f3 + 0.2F); + entityitem.motZ = (double) ((float) this.random.nextGaussian() * f3); + this.world.addEntity(entityitem); + } + } + } + + super.die(); + } + + public void m_() { + // CraftBukkit start + double prevX = this.locX; + double prevY = this.locY; + double prevZ = this.locZ; + float prevYaw = this.yaw; + float prevPitch = this.pitch; + // CraftBukkit end + + if (this.b > 0) { + --this.b; + } + + if (this.damage > 0) { + --this.damage; + } + + double d0; + + if (this.world.isStatic && this.k > 0) { + if (this.k > 0) { + double d1 = this.locX + (this.l - this.locX) / (double) this.k; + double d2 = this.locY + (this.m - this.locY) / (double) this.k; + double d3 = this.locZ + (this.n - this.locZ) / (double) this.k; + + for (d0 = this.o - (double) this.yaw; d0 < -180.0D; d0 += 360.0D) { + ; + } + + while (d0 >= 180.0D) { + d0 -= 360.0D; + } + + this.yaw = (float) ((double) this.yaw + d0 / (double) this.k); + this.pitch = (float) ((double) this.pitch + (this.p - (double) this.pitch) / (double) this.k); + --this.k; + this.setPosition(d1, d2, d3); + this.c(this.yaw, this.pitch); + } else { + this.setPosition(this.locX, this.locY, this.locZ); + this.c(this.yaw, this.pitch); + } + } else { + this.lastX = this.locX; + this.lastY = this.locY; + this.lastZ = this.locZ; + this.motY -= 0.03999999910593033D; + int i = MathHelper.floor(this.locX); + int j = MathHelper.floor(this.locY); + int k = MathHelper.floor(this.locZ); + + if (BlockMinecartTrack.g(this.world, i, j - 1, k)) { + --j; + } + + // CraftBukkit + double d4 = this.maxSpeed; + boolean flag = false; + + d0 = 0.0078125D; + int l = this.world.getTypeId(i, j, k); + + if (BlockMinecartTrack.c(l)) { + Vec3D vec3d = this.h(this.locX, this.locY, this.locZ); + int i1 = this.world.getData(i, j, k); + + this.locY = (double) j; + boolean flag1 = false; + boolean flag2 = false; + + if (l == Block.GOLDEN_RAIL.id) { + flag1 = (i1 & 8) != 0; + flag2 = !flag1; + } + + if (((BlockMinecartTrack) Block.byId[l]).f()) { + i1 &= 7; + } + + if (i1 >= 2 && i1 <= 5) { + this.locY = (double) (j + 1); + } + + if (i1 == 2) { + this.motX -= d0; + } + + if (i1 == 3) { + this.motX += d0; + } + + if (i1 == 4) { + this.motZ += d0; + } + + if (i1 == 5) { + this.motZ -= d0; + } + + int[][] aint = matrix[i1]; + double d5 = (double) (aint[1][0] - aint[0][0]); + double d6 = (double) (aint[1][2] - aint[0][2]); + double d7 = Math.sqrt(d5 * d5 + d6 * d6); + double d8 = this.motX * d5 + this.motZ * d6; + + if (d8 < 0.0D) { + d5 = -d5; + d6 = -d6; + } + + double d9 = Math.sqrt(this.motX * this.motX + this.motZ * this.motZ); + + this.motX = d9 * d5 / d7; + this.motZ = d9 * d6 / d7; + double d10; + + if (flag2) { + d10 = Math.sqrt(this.motX * this.motX + this.motZ * this.motZ); + if (d10 < 0.03D) { + this.motX *= 0.0D; + this.motY *= 0.0D; + this.motZ *= 0.0D; + } else { + this.motX *= 0.5D; + this.motY *= 0.0D; + this.motZ *= 0.5D; + } + } + + d10 = 0.0D; + double d11 = (double) i + 0.5D + (double) aint[0][0] * 0.5D; + double d12 = (double) k + 0.5D + (double) aint[0][2] * 0.5D; + double d13 = (double) i + 0.5D + (double) aint[1][0] * 0.5D; + double d14 = (double) k + 0.5D + (double) aint[1][2] * 0.5D; + + d5 = d13 - d11; + d6 = d14 - d12; + double d15; + double d16; + double d17; + + if (d5 == 0.0D) { + this.locX = (double) i + 0.5D; + d10 = this.locZ - (double) k; + } else if (d6 == 0.0D) { + this.locZ = (double) k + 0.5D; + d10 = this.locX - (double) i; + } else { + d16 = this.locX - d11; + d15 = this.locZ - d12; + d17 = (d16 * d5 + d15 * d6) * 2.0D; + d10 = d17; + } + + this.locX = d11 + d5 * d10; + this.locZ = d12 + d6 * d10; + this.setPosition(this.locX, this.locY + (double) this.height, this.locZ); + d16 = this.motX; + d15 = this.motZ; + if (this.passenger != null) { + d16 *= 0.75D; + d15 *= 0.75D; + } + + if (d16 < -d4) { + d16 = -d4; + } + + if (d16 > d4) { + d16 = d4; + } + + if (d15 < -d4) { + d15 = -d4; + } + + if (d15 > d4) { + d15 = d4; + } + + this.move(d16, 0.0D, d15); + if (aint[0][1] != 0 && MathHelper.floor(this.locX) - i == aint[0][0] && MathHelper.floor(this.locZ) - k == aint[0][2]) { + this.setPosition(this.locX, this.locY + (double) aint[0][1], this.locZ); + } else if (aint[1][1] != 0 && MathHelper.floor(this.locX) - i == aint[1][0] && MathHelper.floor(this.locZ) - k == aint[1][2]) { + this.setPosition(this.locX, this.locY + (double) aint[1][1], this.locZ); + } + + // CraftBukkit + if (this.passenger != null || !this.slowWhenEmpty) { + this.motX *= 0.996999979019165D; + this.motY *= 0.0D; + this.motZ *= 0.996999979019165D; + } else { + if (this.type == 2) { + d17 = (double) MathHelper.a(this.f * this.f + this.g * this.g); + if (d17 > 0.01D) { + flag = true; + this.f /= d17; + this.g /= d17; + double d18 = 0.04D; + + this.motX *= 0.800000011920929D; + this.motY *= 0.0D; + this.motZ *= 0.800000011920929D; + this.motX += this.f * d18; + this.motZ += this.g * d18; + } else { + this.motX *= 0.8999999761581421D; + this.motY *= 0.0D; + this.motZ *= 0.8999999761581421D; + } + } + + this.motX *= 0.9599999785423279D; + this.motY *= 0.0D; + this.motZ *= 0.9599999785423279D; + } + + Vec3D vec3d1 = this.h(this.locX, this.locY, this.locZ); + + if (vec3d1 != null && vec3d != null) { + double d19 = (vec3d.b - vec3d1.b) * 0.05D; + + d9 = Math.sqrt(this.motX * this.motX + this.motZ * this.motZ); + if (d9 > 0.0D) { + this.motX = this.motX / d9 * (d9 + d19); + this.motZ = this.motZ / d9 * (d9 + d19); + } + + this.setPosition(this.locX, vec3d1.b, this.locZ); + } + + int j1 = MathHelper.floor(this.locX); + int k1 = MathHelper.floor(this.locZ); + + if (j1 != i || k1 != k) { + d9 = Math.sqrt(this.motX * this.motX + this.motZ * this.motZ); + this.motX = d9 * (double) (j1 - i); + this.motZ = d9 * (double) (k1 - k); + } + + double d20; + + if (this.type == 2) { + d20 = (double) MathHelper.a(this.f * this.f + this.g * this.g); + if (d20 > 0.01D && this.motX * this.motX + this.motZ * this.motZ > 0.0010D) { + this.f /= d20; + this.g /= d20; + if (this.f * this.motX + this.g * this.motZ < 0.0D) { + this.f = 0.0D; + this.g = 0.0D; + } else { + this.f = this.motX; + this.g = this.motZ; + } + } + } + + if (flag1) { + d20 = Math.sqrt(this.motX * this.motX + this.motZ * this.motZ); + if (d20 > 0.01D) { + double d21 = 0.06D; + + this.motX += this.motX / d20 * d21; + this.motZ += this.motZ / d20 * d21; + } else if (i1 == 1) { + if (this.world.e(i - 1, j, k)) { + this.motX = 0.02D; + } else if (this.world.e(i + 1, j, k)) { + this.motX = -0.02D; + } + } else if (i1 == 0) { + if (this.world.e(i, j, k - 1)) { + this.motZ = 0.02D; + } else if (this.world.e(i, j, k + 1)) { + this.motZ = -0.02D; + } + } + } + } else { + if (this.motX < -d4) { + this.motX = -d4; + } + + if (this.motX > d4) { + this.motX = d4; + } + + if (this.motZ < -d4) { + this.motZ = -d4; + } + + if (this.motZ > d4) { + this.motZ = d4; + } + + if (this.onGround) { + // CraftBukkit start + this.motX *= this.derailedX; + this.motY *= this.derailedY; + this.motZ *= this.derailedZ; + // CraftBukkit start + } + + this.move(this.motX, this.motY, this.motZ); + if (!this.onGround) { + // CraftBukkit start + this.motX *= this.flyingX; + this.motY *= this.flyingY; + this.motZ *= this.flyingZ; + // CraftBukkit start + } + } + + this.pitch = 0.0F; + double d22 = this.lastX - this.locX; + double d23 = this.lastZ - this.locZ; + + if (d22 * d22 + d23 * d23 > 0.0010D) { + this.yaw = (float) (Math.atan2(d23, d22) * 180.0D / 3.141592653589793D); + if (this.i) { + this.yaw += 180.0F; + } + } + + double d24; + + for (d24 = (double) (this.yaw - this.lastYaw); d24 >= 180.0D; d24 -= 360.0D) { + ; + } + + while (d24 < -180.0D) { + d24 += 360.0D; + } + + if (d24 < -170.0D || d24 >= 170.0D) { + this.yaw += 180.0F; + this.i = !this.i; + } + + this.c(this.yaw, this.pitch); + + // CraftBukkit start + org.bukkit.World bworld = this.world.getWorld(); + Location from = new Location(bworld, prevX, prevY, prevZ, prevYaw, prevPitch); + Location to = new Location(bworld, this.locX, this.locY, this.locZ, this.yaw, this.pitch); + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); + + this.world.getServer().getPluginManager().callEvent(new VehicleUpdateEvent(vehicle)); + + if (!from.equals(to)) { + this.world.getServer().getPluginManager().callEvent(new VehicleMoveEvent(vehicle, from, to)); + } + // CraftBukkit end + + List list = this.world.b((Entity) this, this.boundingBox.b(0.20000000298023224D, 0.0D, 0.20000000298023224D)); + + if (list != null && list.size() > 0) { + for (int l1 = 0; l1 < list.size(); ++l1) { + Entity entity = (Entity) list.get(l1); + + if (entity != this.passenger && entity.d_() && entity instanceof EntityMinecart) { + entity.collide(this); + } + } + } + + if (this.passenger != null && this.passenger.dead) { + this.passenger.vehicle = null; // CraftBukkit + this.passenger = null; + } + + if (flag && this.random.nextInt(4) == 0) { + --this.e; + if (this.e < 0) { + this.f = this.g = 0.0D; + } + + this.world.a("largesmoke", this.locX, this.locY + 0.8D, this.locZ, 0.0D, 0.0D, 0.0D); + } + } + } + + public Vec3D h(double d0, double d1, double d2) { + int i = MathHelper.floor(d0); + int j = MathHelper.floor(d1); + int k = MathHelper.floor(d2); + + if (BlockMinecartTrack.g(this.world, i, j - 1, k)) { + --j; + } + + int l = this.world.getTypeId(i, j, k); + + if (BlockMinecartTrack.c(l)) { + int i1 = this.world.getData(i, j, k); + + d1 = (double) j; + if (((BlockMinecartTrack) Block.byId[l]).f()) { + i1 &= 7; + } + + if (i1 >= 2 && i1 <= 5) { + d1 = (double) (j + 1); + } + + int[][] aint = matrix[i1]; + double d3 = 0.0D; + double d4 = (double) i + 0.5D + (double) aint[0][0] * 0.5D; + double d5 = (double) j + 0.5D + (double) aint[0][1] * 0.5D; + double d6 = (double) k + 0.5D + (double) aint[0][2] * 0.5D; + double d7 = (double) i + 0.5D + (double) aint[1][0] * 0.5D; + double d8 = (double) j + 0.5D + (double) aint[1][1] * 0.5D; + double d9 = (double) k + 0.5D + (double) aint[1][2] * 0.5D; + double d10 = d7 - d4; + double d11 = (d8 - d5) * 2.0D; + double d12 = d9 - d6; + + if (d10 == 0.0D) { + d0 = (double) i + 0.5D; + d3 = d2 - (double) k; + } else if (d12 == 0.0D) { + d2 = (double) k + 0.5D; + d3 = d0 - (double) i; + } else { + double d13 = d0 - d4; + double d14 = d2 - d6; + double d15 = (d13 * d10 + d14 * d12) * 2.0D; + + d3 = d15; + } + + d0 = d4 + d10 * d3; + d1 = d5 + d11 * d3; + d2 = d6 + d12 * d3; + if (d11 < 0.0D) { + ++d1; + } + + if (d11 > 0.0D) { + d1 += 0.5D; + } + + return Vec3D.create(d0, d1, d2); + } else { + return null; + } + } + + protected void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("Type", this.type); + if (this.type == 2) { + nbttagcompound.a("PushX", this.f); + nbttagcompound.a("PushZ", this.g); + nbttagcompound.a("Fuel", (short) this.e); + } else if (this.type == 1) { + NBTTagList nbttaglist = new NBTTagList(); + + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.a("Slot", (byte) i); + this.items[i].a(nbttagcompound1); + nbttaglist.a((NBTBase) nbttagcompound1); + } + } + + nbttagcompound.a("Items", (NBTBase) nbttaglist); + } + } + + protected void a(NBTTagCompound nbttagcompound) { + this.type = nbttagcompound.e("Type"); + if (this.type == 2) { + this.f = nbttagcompound.h("PushX"); + this.g = nbttagcompound.h("PushZ"); + this.e = nbttagcompound.d("Fuel"); + } else if (this.type == 1) { + NBTTagList nbttaglist = nbttagcompound.l("Items"); + + this.items = new ItemStack[this.getSize()]; + + for (int i = 0; i < nbttaglist.c(); ++i) { + NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttaglist.a(i); + int j = nbttagcompound1.c("Slot") & 255; + + if (j >= 0 && j < this.items.length) { + this.items[j] = new ItemStack(nbttagcompound1); + } + } + } + } + + public void collide(Entity entity) { + if (!this.world.isStatic) { + if (entity != this.passenger) { + // CraftBukkit start + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); + org.bukkit.entity.Entity hitEntity = (entity == null) ? null : entity.getBukkitEntity(); + + VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, hitEntity); + this.world.getServer().getPluginManager().callEvent(collisionEvent); + + if (collisionEvent.isCancelled()) { + return; + } + + if (entity instanceof EntityLiving && !(entity instanceof EntityHuman) && this.type == 0 && this.motX * this.motX + this.motZ * this.motZ > 0.01D && this.passenger == null && entity.vehicle == null) { + if (!collisionEvent.isPickupCancelled()) { + VehicleEnterEvent enterEvent = new VehicleEnterEvent(vehicle, hitEntity); + this.world.getServer().getPluginManager().callEvent(enterEvent); + + if (!enterEvent.isCancelled()) { + entity.mount(this); + } + } + } + // CraftBukkit end + + double d0 = entity.locX - this.locX; + double d1 = entity.locZ - this.locZ; + double d2 = d0 * d0 + d1 * d1; + + // CraftBukkit - Collision + if (d2 >= 9.999999747378752E-5D && !collisionEvent.isCollisionCancelled()) { + d2 = (double) MathHelper.a(d2); + d0 /= d2; + d1 /= d2; + double d3 = 1.0D / d2; + + if (d3 > 1.0D) { + d3 = 1.0D; + } + + d0 *= d3; + d1 *= d3; + d0 *= 0.10000000149011612D; + d1 *= 0.10000000149011612D; + d0 *= (double) (1.0F - this.bu); + d1 *= (double) (1.0F - this.bu); + d0 *= 0.5D; + d1 *= 0.5D; + if (entity instanceof EntityMinecart) { + double d4 = entity.locX - this.locX; + double d5 = entity.locZ - this.locZ; + double d6 = d4 * entity.motZ + d5 * entity.lastX; + + d6 *= d6; + if (d6 > 5.0D) { + return; + } + + double d7 = entity.motX + this.motX; + double d8 = entity.motZ + this.motZ; + + if (((EntityMinecart) entity).type == 2 && this.type != 2) { + this.motX *= 0.20000000298023224D; + this.motZ *= 0.20000000298023224D; + this.b(entity.motX - d0, 0.0D, entity.motZ - d1); + entity.motX *= 0.699999988079071D; + entity.motZ *= 0.699999988079071D; + } else if (((EntityMinecart) entity).type != 2 && this.type == 2) { + entity.motX *= 0.20000000298023224D; + entity.motZ *= 0.20000000298023224D; + entity.b(this.motX + d0, 0.0D, this.motZ + d1); + this.motX *= 0.699999988079071D; + this.motZ *= 0.699999988079071D; + } else { + d7 /= 2.0D; + d8 /= 2.0D; + this.motX *= 0.20000000298023224D; + this.motZ *= 0.20000000298023224D; + this.b(d7 - d0, 0.0D, d8 - d1); + entity.motX *= 0.20000000298023224D; + entity.motZ *= 0.20000000298023224D; + entity.b(d7 + d0, 0.0D, d8 + d1); + } + } else { + this.b(-d0, 0.0D, -d1); + entity.b(d0 / 4.0D, 0.0D, d1 / 4.0D); + } + } + } + } + } + + public int getSize() { + return 27; + } + + public ItemStack getItem(int i) { + return this.items[i]; + } + + public ItemStack splitStack(int i, int j) { + if (this.items[i] != null) { + ItemStack itemstack; + + if (this.items[i].count <= j) { + itemstack = this.items[i]; + this.items[i] = null; + return itemstack; + } else { + itemstack = this.items[i].a(j); + if (this.items[i].count == 0) { + this.items[i] = null; + } + + return itemstack; + } + } else { + return null; + } + } + + public void setItem(int i, ItemStack itemstack) { + this.items[i] = itemstack; + if (itemstack != null && itemstack.count > this.getMaxStackSize()) { + itemstack.count = this.getMaxStackSize(); + } + } + + public String getName() { + return "Minecart"; + } + + public int getMaxStackSize() { + return 64; + } + + public void update() {} + + public boolean a(EntityHuman entityhuman) { + if (this.type == 0) { + if (this.passenger != null && this.passenger instanceof EntityHuman && this.passenger != entityhuman) { + return true; + } + + if (!this.world.isStatic) { + // CraftBukkit start + org.bukkit.entity.Entity player = (entityhuman == null) ? null : entityhuman.getBukkitEntity(); + + VehicleEnterEvent event = new VehicleEnterEvent((Vehicle) this.getBukkitEntity(), player); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return true; + } + // CraftBukkit end + + entityhuman.mount(this); + } + } else if (this.type == 1) { + if (!this.world.isStatic) { + entityhuman.a((IInventory) this); + } + } else if (this.type == 2) { + ItemStack itemstack = entityhuman.inventory.getItemInHand(); + + if (itemstack != null && itemstack.id == Item.COAL.id) { + if (--itemstack.count == 0) { + entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, (ItemStack) null); + } + + this.e += 1200; + } + + this.f = this.locX - entityhuman.locX; + this.g = this.locZ - entityhuman.locZ; + } + + return true; + } + + public boolean a_(EntityHuman entityhuman) { + return this.dead ? false : entityhuman.g(this) <= 64.0D; + } +} diff --git a/src/main/java/net/minecraft/server/EntityMonster.java b/src/main/java/net/minecraft/server/EntityMonster.java new file mode 100644 index 0000000..abe59e9 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityMonster.java @@ -0,0 +1,127 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityTargetEvent; +// CraftBukkit end + +public class EntityMonster extends EntityCreature implements IMonster { + + protected int damage = 2; + + public EntityMonster(World world) { + super(world); + this.health = 20; + } + + public void v() { + float f = this.c(1.0F); + + if (f > 0.5F) { + this.ay += 2; + } + + super.v(); + } + + public void m_() { + super.m_(); + if (!this.world.isStatic && this.world.spawnMonsters == 0) { + this.die(); + } + } + + protected Entity findTarget() { + EntityHuman entityhuman = this.world.findNearbyPlayer(this, 16.0D); + + return entityhuman != null && this.e(entityhuman) ? entityhuman : null; + } + + public boolean damageEntity(Entity entity, int i) { + if (super.damageEntity(entity, i)) { + if (this.passenger != entity && this.vehicle != entity) { + if (entity != this) { + // CraftBukkit start + org.bukkit.entity.Entity bukkitTarget = entity == null ? null : entity.getBukkitEntity(); + + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), bukkitTarget, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + this.target = ((CraftEntity) event.getTarget()).getHandle(); + } + } + // CraftBukkit end + } + + return true; + } else { + return true; + } + } else { + return false; + } + } + + protected void a(Entity entity, float f) { + if (this.attackTicks <= 0 && f < 2.0F && entity.boundingBox.e > this.boundingBox.b && entity.boundingBox.b < this.boundingBox.e) { + this.attackTicks = 20; + // CraftBukkit start - this is still duplicated here and EntityHuman because it's possible for lastDamage EntityMonster + // to damage another EntityMonster, and we want to catch those events. + // This does not fire events for slime attacks, av they're not lastDamage EntityMonster. + if (entity instanceof EntityLiving && !(entity instanceof EntityHuman)) { + org.bukkit.entity.Entity damagee = (entity == null) ? null : entity.getBukkitEntity(); + + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(this.getBukkitEntity(), damagee, EntityDamageEvent.DamageCause.ENTITY_ATTACK, this.damage); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + entity.damageEntity(this, event.getDamage()); + } + return; + } + // CraftBukkit end + + entity.damageEntity(this, this.damage); + } + } + + protected float a(int i, int j, int k) { + return 0.5F - this.world.n(i, j, k); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + public boolean d() { + int i = MathHelper.floor(this.locX); + int j = MathHelper.floor(this.boundingBox.b); + int k = MathHelper.floor(this.locZ); + + if (this.world.a(EnumSkyBlock.SKY, i, j, k) > this.random.nextInt(32)) { + return false; + } else { + int l = this.world.getLightLevel(i, j, k); + + if (this.world.u()) { + int i1 = this.world.f; + + this.world.f = 10; + l = this.world.getLightLevel(i, j, k); + this.world.f = i1; + } + + return l <= this.random.nextInt(8) && super.d(); + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityPainting.java b/src/main/java/net/minecraft/server/EntityPainting.java new file mode 100644 index 0000000..ceca21a --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityPainting.java @@ -0,0 +1,266 @@ +package net.minecraft.server; + +import org.bukkit.event.painting.PaintingBreakByEntityEvent; +import org.bukkit.event.painting.PaintingBreakByWorldEvent; + +import java.util.ArrayList; +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityPainting extends Entity { + + private int f; + public int a; + public int b; + public int c; + public int d; + public EnumArt e; + + public EntityPainting(World world) { + super(world); + this.f = 0; + this.a = 0; + this.height = 0.0F; + this.b(0.5F, 0.5F); + } + + public EntityPainting(World world, int i, int j, int k, int l) { + this(world); + this.b = i; + this.c = j; + this.d = k; + ArrayList arraylist = new ArrayList(); + EnumArt[] aenumart = EnumArt.values(); + int i1 = aenumart.length; + + for (int j1 = 0; j1 < i1; ++j1) { + EnumArt enumart = aenumart[j1]; + + this.e = enumart; + this.b(l); + if (this.h()) { + arraylist.add(enumart); + } + } + + if (arraylist.size() > 0) { + this.e = (EnumArt) arraylist.get(this.random.nextInt(arraylist.size())); + } + + this.b(l); + } + + protected void b() {} + + public void b(int i) { + this.a = i; + this.lastYaw = this.yaw = (float) (i * 90); + float f = (float) this.e.B; + float f1 = (float) this.e.C; + float f2 = (float) this.e.B; + + if (i != 0 && i != 2) { + f = 0.5F; + } else { + f2 = 0.5F; + } + + f /= 32.0F; + f1 /= 32.0F; + f2 /= 32.0F; + float f3 = (float) this.b + 0.5F; + float f4 = (float) this.c + 0.5F; + float f5 = (float) this.d + 0.5F; + float f6 = 0.5625F; + + if (i == 0) { + f5 -= f6; + } + + if (i == 1) { + f3 -= f6; + } + + if (i == 2) { + f5 += f6; + } + + if (i == 3) { + f3 += f6; + } + + if (i == 0) { + f3 -= this.c(this.e.B); + } + + if (i == 1) { + f5 += this.c(this.e.B); + } + + if (i == 2) { + f3 += this.c(this.e.B); + } + + if (i == 3) { + f5 -= this.c(this.e.B); + } + + f4 += this.c(this.e.C); + this.setPosition((double) f3, (double) f4, (double) f5); + float f7 = -0.00625F; + + this.boundingBox.c((double) (f3 - f - f7), (double) (f4 - f1 - f7), (double) (f5 - f2 - f7), (double) (f3 + f + f7), (double) (f4 + f1 + f7), (double) (f5 + f2 + f7)); + } + + private float c(int i) { + return i == 32 ? 0.5F : (i == 64 ? 0.5F : 0.0F); + } + + public void m_() { + if (this.f++ == 100 && !this.world.isStatic) { + this.f = 0; + if (!this.h()) { + // CraftBukkit start + PaintingBreakByWorldEvent event = new PaintingBreakByWorldEvent((org.bukkit.entity.Painting) this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end + + this.die(); + this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING))); + } + } + } + + public boolean h() { + if (this.world.getEntities(this, this.boundingBox).size() > 0) { + return false; + } else { + int i = this.e.B / 16; + int j = this.e.C / 16; + int k = this.b; + int l = this.c; + int i1 = this.d; + + if (this.a == 0) { + k = MathHelper.floor(this.locX - (double) ((float) this.e.B / 32.0F)); + } + + if (this.a == 1) { + i1 = MathHelper.floor(this.locZ - (double) ((float) this.e.B / 32.0F)); + } + + if (this.a == 2) { + k = MathHelper.floor(this.locX - (double) ((float) this.e.B / 32.0F)); + } + + if (this.a == 3) { + i1 = MathHelper.floor(this.locZ - (double) ((float) this.e.B / 32.0F)); + } + + l = MathHelper.floor(this.locY - (double) ((float) this.e.C / 32.0F)); + + int j1; + + for (int k1 = 0; k1 < i; ++k1) { + for (j1 = 0; j1 < j; ++j1) { + Material material; + + if (this.a != 0 && this.a != 2) { + material = this.world.getMaterial(this.b, l + j1, i1 + k1); + } else { + material = this.world.getMaterial(k + k1, l + j1, this.d); + } + + if (!material.isBuildable()) { + return false; + } + } + } + + List list = this.world.b((Entity) this, this.boundingBox); + + for (j1 = 0; j1 < list.size(); ++j1) { + if (list.get(j1) instanceof EntityPainting) { + return false; + } + } + + return true; + } + } + + public boolean l_() { + return true; + } + + public boolean damageEntity(Entity entity, int i) { + if (!this.dead && !this.world.isStatic) { + // CraftBukkit start + PaintingBreakByEntityEvent event = new PaintingBreakByEntityEvent((org.bukkit.entity.Painting) this.getBukkitEntity(), entity == null ? null : entity.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return true; + } + // CraftBukkit end + + this.die(); + this.af(); + this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING))); + } + + return true; + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("Dir", (byte) this.a); + nbttagcompound.setString("Motive", this.e.A); + nbttagcompound.a("TileX", this.b); + nbttagcompound.a("TileY", this.c); + nbttagcompound.a("TileZ", this.d); + } + + public void a(NBTTagCompound nbttagcompound) { + this.a = nbttagcompound.c("Dir"); + this.b = nbttagcompound.e("TileX"); + this.c = nbttagcompound.e("TileY"); + this.d = nbttagcompound.e("TileZ"); + String s = nbttagcompound.getString("Motive"); + EnumArt[] aenumart = EnumArt.values(); + int i = aenumart.length; + + for (int j = 0; j < i; ++j) { + EnumArt enumart = aenumart[j]; + + if (enumart.A.equals(s)) { + this.e = enumart; + } + } + + if (this.e == null) { + this.e = EnumArt.KEBAB; + } + + this.b(this.a); + } + + public void a(double d0, double d1, double d2) { + if (!this.world.isStatic && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) { + this.die(); + this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING))); + } + } + + public void b(double d0, double d1, double d2) { + if (!this.world.isStatic && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) { + this.die(); + this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING))); + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityPig.java b/src/main/java/net/minecraft/server/EntityPig.java new file mode 100644 index 0000000..10f4d8a --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityPig.java @@ -0,0 +1,93 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.event.entity.PigZapEvent; +// CraftBukkit end + +public class EntityPig extends EntityAnimal { + + public EntityPig(World world) { + super(world); + this.texture = "/mob/pig.png"; + this.b(0.9F, 0.9F); + } + + protected void b() { + this.datawatcher.a(16, Byte.valueOf((byte) 0)); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("Saddle", this.hasSaddle()); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.setSaddle(nbttagcompound.m("Saddle")); + } + + protected String g() { + return "mob.pig"; + } + + protected String h() { + return "mob.pig"; + } + + protected String i() { + return "mob.pigdeath"; + } + + public boolean a(EntityHuman entityhuman) { + if (this.hasSaddle() && !this.world.isStatic && (this.passenger == null || this.passenger == entityhuman)) { + entityhuman.mount(this); + return true; + } else { + return false; + } + } + + protected int j() { + return this.fireTicks > 0 ? Item.GRILLED_PORK.id : Item.PORK.id; + } + + public boolean hasSaddle() { + return (this.datawatcher.a(16) & 1) != 0; + } + + public void setSaddle(boolean flag) { + if (flag) { + this.datawatcher.watch(16, Byte.valueOf((byte) 1)); + } else { + this.datawatcher.watch(16, Byte.valueOf((byte) 0)); + } + } + + public void a(EntityWeatherStorm entityweatherstorm) { + if (!this.world.isStatic) { + EntityPigZombie entitypigzombie = new EntityPigZombie(this.world); + + // CraftBukkit start + PigZapEvent event = new PigZapEvent(this.getBukkitEntity(), entityweatherstorm.getBukkitEntity(), entitypigzombie.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end + + entitypigzombie.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, this.pitch); + // CraftBukkit - added a reason for spawning this creature + this.world.addEntity(entitypigzombie, SpawnReason.LIGHTNING); + this.die(); + } + } + + protected void a(float f) { + super.a(f); + if (f > 5.0F && this.passenger instanceof EntityHuman) { + ((EntityHuman) this.passenger).a((Statistic) AchievementList.u); + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityPigZombie.java b/src/main/java/net/minecraft/server/EntityPigZombie.java new file mode 100644 index 0000000..a01c9ad --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityPigZombie.java @@ -0,0 +1,114 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.event.entity.EntityTargetEvent; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityPigZombie extends EntityZombie { + + public int angerLevel = 0; // CraftBukkit - private -> public + private int soundDelay = 0; + private static final ItemStack f = new ItemStack(Item.GOLD_SWORD, 1); + + public EntityPigZombie(World world) { + super(world); + this.texture = "/mob/pigzombie.png"; + this.aE = 0.5F; + this.damage = 5; + this.fireProof = true; + } + + public void m_() { + this.aE = this.target != null ? 0.95F : 0.5F; + if (this.soundDelay > 0 && --this.soundDelay == 0) { + this.world.makeSound(this, "mob.zombiepig.zpigangry", this.k() * 2.0F, ((this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F) * 1.8F); + } + + super.m_(); + } + + public boolean d() { + return this.world.spawnMonsters > 0 && this.world.containsEntity(this.boundingBox) && this.world.getEntities(this, this.boundingBox).size() == 0 && !this.world.c(this.boundingBox); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("Anger", (short) this.angerLevel); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.angerLevel = nbttagcompound.d("Anger"); + } + + protected Entity findTarget() { + return this.angerLevel == 0 ? null : super.findTarget(); + } + + public void v() { + super.v(); + } + + public boolean damageEntity(Entity entity, int i) { + if (entity instanceof EntityHuman) { + List list = this.world.b((Entity) this, this.boundingBox.b(32.0D, 32.0D, 32.0D)); + + for (int j = 0; j < list.size(); ++j) { + Entity entity1 = (Entity) list.get(j); + + if (entity1 instanceof EntityPigZombie) { + EntityPigZombie entitypigzombie = (EntityPigZombie) entity1; + + entitypigzombie.d(entity); + } + } + + this.d(entity); + } + + return super.damageEntity(entity, i); + } + + private void d(Entity entity) { + // CraftBukkit start + org.bukkit.entity.Entity bukkitTarget = entity == null ? null : entity.getBukkitEntity(); + + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), bukkitTarget, EntityTargetEvent.TargetReason.PIG_ZOMBIE_TARGET); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + if (event.getTarget() == null) { + this.target = null; + return; + } + entity = ((CraftEntity) event.getTarget()).getHandle(); + // CraftBukkit end + + this.target = entity; + this.angerLevel = 400 + this.random.nextInt(400); + this.soundDelay = this.random.nextInt(40); + } + + protected String g() { + return "mob.zombiepig.zpig"; + } + + protected String h() { + return "mob.zombiepig.zpighurt"; + } + + protected String i() { + return "mob.zombiepig.zpigdeath"; + } + + protected int j() { + return Item.GRILLED_PORK.id; + } +} diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java new file mode 100644 index 0000000..a256dd5 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityPlayer.java @@ -0,0 +1,601 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.event.PlayerDeathEvent; +import com.projectposeidon.api.PoseidonUUID; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.ChunkCompressionThread; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.inventory.ChestOpenedEvent; + +import java.util.*; + +// CraftBukkit start + +public class EntityPlayer extends EntityHuman implements ICrafting { + + public NetServerHandler netServerHandler; + public MinecraftServer b; + public ItemInWorldManager itemInWorldManager; + public double d; + public double e; + public List chunkCoordIntPairQueue = new LinkedList(); + public Set playerChunkCoordIntPairs = new HashSet(); + public final List removeQueue = new LinkedList(); // poseidon + private int bL = -99999999; + private int bM = 60; + private ItemStack[] bN = new ItemStack[]{null, null, null, null, null}; + private int bO = 0; + public boolean h; + + public EntityPlayer(MinecraftServer minecraftserver, World world, String s, ItemInWorldManager iteminworldmanager) { + super(world); + iteminworldmanager.player = this; + this.itemInWorldManager = iteminworldmanager; + ChunkCoordinates chunkcoordinates = world.getSpawn(); + int i = chunkcoordinates.x; + int j = chunkcoordinates.z; + int k = chunkcoordinates.y; + float yaw = world.worldData.getYaw(); // Poseidon + float pitch = world.worldData.getPitch(); // Poseidon + + if (!world.worldProvider.e) { + k = world.f(i, j); //Project Poseidon: This finds a solid block, this needs to be left outside of the setting + if ((boolean) PoseidonConfig.getInstance().getProperty("world-settings.randomize-spawn")) { //Project Poseidon: Moved randomizing X and Y axis into a config option + i += this.random.nextInt(20) - 10; + j += this.random.nextInt(20) - 10; + } + } + + this.setPositionRotation((double) i + 0.5D, (double) k, (double) j + 0.5D, yaw, pitch); + this.b = minecraftserver; + this.bs = 0.0F; + this.name = s; + this.height = 0.0F; + + // CraftBukkit start + this.displayName = this.name; + this.playerUUID = PoseidonUUID.getPlayerGracefulUUID(this.name); //Project Poseidon + } + + public String displayName; + public UUID playerUUID; //Project Poseidon + public org.bukkit.Location compassTarget; + // CraftBukkit end + + public void spawnIn(World world) { + super.spawnIn(world); + // CraftBukkit - world fallback code, either respawn location or global spawn + if (world == null) { + this.dead = false; + ChunkCoordinates position = null; + if (this.spawnWorld != null && !this.spawnWorld.equals("")) { + CraftWorld cworld = (CraftWorld) Bukkit.getServer().getWorld(this.spawnWorld); + if (cworld != null && this.getBed() != null) { + world = cworld.getHandle(); + position = EntityHuman.getBed(cworld.getHandle(), this.getBed()); + } + } + if (world == null || position == null) { + world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle(); + position = world.getSpawn(); + } + this.world = world; + this.setPosition(position.x + 0.5, position.y, position.z + 0.5); + } + this.dimension = ((WorldServer) this.world).dimension; + // CraftBukkit end + this.itemInWorldManager = new ItemInWorldManager((WorldServer) world); + this.itemInWorldManager.player = this; + } + + public void syncInventory() { + this.activeContainer.a((ICrafting) this); + } + + public ItemStack[] getEquipment() { + return this.bN; + } + + protected void s() { + this.height = 0.0F; + } + + public float t() { + return 1.62F; + } + + public void m_() { + this.itemInWorldManager.a(); + --this.bM; + this.activeContainer.a(); + + for (int i = 0; i < 5; ++i) { + ItemStack itemstack = this.c_(i); + + if (itemstack != this.bN[i]) { + this.b.getTracker(this.dimension).a(this, new Packet5EntityEquipment(this.id, i, itemstack)); + this.bN[i] = itemstack; + } + } + } + + public ItemStack c_(int i) { + return i == 0 ? this.inventory.getItemInHand() : this.inventory.armor[i - 1]; + } + + public void die(Entity entity) { + // CraftBukkit start + java.util.List loot = new java.util.ArrayList(); + + for (int i = 0; i < this.inventory.items.length; ++i) { + if (this.inventory.items[i] != null) { + loot.add(new CraftItemStack(this.inventory.items[i])); + } + } + + for (int i = 0; i < this.inventory.armor.length; ++i) { + if (this.inventory.armor[i] != null) { + loot.add(new CraftItemStack(this.inventory.armor[i])); + } + } + + org.bukkit.entity.Entity bukkitEntity = this.getBukkitEntity(); + CraftWorld bworld = this.world.getWorld(); + + PlayerDeathEvent event = new PlayerDeathEvent(bukkitEntity, loot); + this.world.getServer().getPluginManager().callEvent(event); + + if(event.getDeathMessage() != null && !event.getDeathMessage().trim().isEmpty()) { + this.b.serverConfigurationManager.sendAll(new Packet3Chat(event.getDeathMessage())); + } + + // CraftBukkit - we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory. + + //Poseidon - Only clear inventory if keep inventory is false + if(!event.getKeepInventory()) { + for (int i = 0; i < this.inventory.items.length; ++i) { + this.inventory.items[i] = null; + } + + for (int i = 0; i < this.inventory.armor.length; ++i) { + this.inventory.armor[i] = null; + } + } + + for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { + bworld.dropItemNaturally(bukkitEntity.getLocation(), stack); + } + + this.y(); + // CraftBukkit end + } + + public boolean damageEntity(Entity entity, int i) { + if (this.bM > 0) { + return false; + } else { + // CraftBukkit - this.b.pvpMode -> this.world.pvpMode + if (!this.world.pvpMode) { + if (entity instanceof EntityHuman) { + return false; + } + + if (entity instanceof EntityArrow) { + EntityArrow entityarrow = (EntityArrow) entity; + + if (entityarrow.shooter instanceof EntityHuman) { + return false; + } + } + } + + return super.damageEntity(entity, i); + } + } + + protected boolean j_() { + return this.b.pvpMode; + } + + public void b(int i) { + super.b(i, RegainReason.EATING); + } + + public WorldServer getWorldServer() { + return (WorldServer) this.world; + } + + public void a(boolean flag) { + super.m_(); + + // Poseidon start + while (!this.removeQueue.isEmpty()) { + int i = Math.min(this.removeQueue.size(), 127); + int[] aint = new int[i]; + Iterator iterator = this.removeQueue.iterator(); + int j = 0; + + while (iterator.hasNext() && j < i) { + aint[j++] = ((Integer) iterator.next()).intValue(); + iterator.remove(); + } + + for (int k = 0; k < aint.length; k++) { // cant use array since not supported in b1.7.3 + this.netServerHandler.sendPacket(new Packet29DestroyEntity(aint[k])); + } + } + // poseidon end + + for (int i = 0; i < this.inventory.getSize(); ++i) { + ItemStack itemstack = this.inventory.getItem(i); + + if (itemstack != null && Item.byId[itemstack.id].b() && this.netServerHandler.b() <= 2) { + Packet packet = ((ItemWorldMapBase) Item.byId[itemstack.id]).b(itemstack, this.world, this); + + if (packet != null) { + this.netServerHandler.sendPacket(packet); + } + } + } + + // Poseidon start + if (flag && !this.chunkCoordIntPairQueue.isEmpty()) { + if (PoseidonConfig.getInstance().getBoolean("settings.faster-packets.enabled", true)) { + ArrayList arraylist = new ArrayList(); + Iterator iterator1 = this.chunkCoordIntPairQueue.iterator(); + ArrayList arraylist1 = new ArrayList(); + + while (iterator1.hasNext() && arraylist.size() < 5) { + ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator1.next(); + + iterator1.remove(); + if (chunkcoordintpair != null && this.world.isLoaded(chunkcoordintpair.x << 4, 0, chunkcoordintpair.z << 4)) { + // CraftBukkit start - Get tile entities directly from the chunk instead of the world + Chunk chunk = this.world.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z); + arraylist.add(chunk); + arraylist1.addAll(chunk.tileEntities.values()); + // CraftBukkit end + } + } + + if (!arraylist.isEmpty()) { + Iterator iterator2 = arraylist.iterator(); + + while (iterator2.hasNext()) { + Chunk chunk = (Chunk) iterator2.next(); + + this.netServerHandler.sendPacket(new Packet51MapChunk(chunk.x * 16, 0, chunk.z * 16, 16, 128, 16, this.getWorldServer())); + this.getWorldServer().tracker.a(this, chunk); + } + + iterator2 = arraylist1.iterator(); + + while (iterator2.hasNext()) { + TileEntity tileentity = (TileEntity) iterator2.next(); + + this.a(tileentity); + } + } + } else { + ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) this.chunkCoordIntPairQueue.get(0); + + if (chunkcoordintpair != null) { + boolean flag1 = false; + + if (this.netServerHandler.b() + ChunkCompressionThread.getPlayerQueueSize(this) < 4) { // CraftBukkit - Add check against Chunk Packets in the ChunkCompressionThread. + flag1 = true; + } + + if (flag1) { + WorldServer worldserver = this.b.getWorldServer(this.dimension); + + this.chunkCoordIntPairQueue.remove(chunkcoordintpair); + this.netServerHandler.sendPacket(new Packet51MapChunk(chunkcoordintpair.x * 16, 0, chunkcoordintpair.z * 16, 16, 128, 16, worldserver)); + + Chunk chunk = this.world.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z); + this.getWorldServer().tracker.a(this, chunk); + + List list = worldserver.getTileEntities(chunkcoordintpair.x * 16, 0, chunkcoordintpair.z * 16, chunkcoordintpair.x * 16 + 16, 128, chunkcoordintpair.z * 16 + 16); + + for (int j = 0; j < list.size(); ++j) { + this.a((TileEntity) list.get(j)); + } + } + } + } + } + // Poseidon end + + if (this.E) { + //if (this.b.propertyManager.getBoolean("allow-nether", true)) { // CraftBukkit + if (this.activeContainer != this.defaultContainer) { + this.y(); + } + + if (this.vehicle != null) { + this.mount(this.vehicle); + } else { + this.F += 0.0125F; + if (this.F >= 1.0F) { + this.F = 1.0F; + this.D = 10; + this.b.serverConfigurationManager.f(this); + } + } + + this.E = false; + //} // CraftBukkit + } else { + if (this.F > 0.0F) { + this.F -= 0.05F; + } + + if (this.F < 0.0F) { + this.F = 0.0F; + } + } + + if (this.D > 0) { + --this.D; + } + + if (this.health != this.bL) { + this.netServerHandler.sendPacket(new Packet8UpdateHealth(this.health)); + this.bL = this.health; + } + } + + private void a(TileEntity tileentity) { + if (tileentity != null) { + Packet packet = tileentity.f(); + + if (packet != null) { + this.netServerHandler.sendPacket(packet); + } + } + } + + public void v() { + super.v(); + } + + public void receive(Entity entity, int i) { + if (!entity.dead) { + EntityTracker entitytracker = this.b.getTracker(this.dimension); + + if (entity instanceof EntityItem) { + entitytracker.a(entity, new Packet22Collect(entity.id, this.id)); + } + + if (entity instanceof EntityArrow) { + entitytracker.a(entity, new Packet22Collect(entity.id, this.id)); + } + } + + super.receive(entity, i); + this.activeContainer.a(); + } + + public void w() { + if (!this.p) { + this.q = -1; + this.p = true; + EntityTracker entitytracker = this.b.getTracker(this.dimension); + + entitytracker.a(this, new Packet18ArmAnimation(this, 1)); + } + } + + public void x() { + } + + public EnumBedError a(int i, int j, int k) { + EnumBedError enumbederror = super.a(i, j, k); + + if (enumbederror == EnumBedError.OK) { + EntityTracker entitytracker = this.b.getTracker(this.dimension); + Packet17 packet17 = new Packet17(this, 0, i, j, k); + + entitytracker.a(this, packet17); + this.netServerHandler.a(this.locX, this.locY, this.locZ, this.yaw, this.pitch); + this.netServerHandler.sendPacket(packet17); + } + + return enumbederror; + } + + public void a(boolean flag, boolean flag1, boolean flag2) { + if (this.isSleeping()) { + EntityTracker entitytracker = this.b.getTracker(this.dimension); + + entitytracker.sendPacketToEntity(this, new Packet18ArmAnimation(this, 3)); + } + + super.a(flag, flag1, flag2); + if (this.netServerHandler != null) { + this.netServerHandler.a(this.locX, this.locY, this.locZ, this.yaw, this.pitch); + } + } + + public void mount(Entity entity) { + // CraftBukkit start + this.setPassengerOf(entity); + } + + public void setPassengerOf(Entity entity) { + // mount(null) doesn't really fly for overloaded methods, + // so this method is needed + + super.setPassengerOf(entity); + // CraftBukkit end + + this.netServerHandler.sendPacket(new Packet39AttachEntity(this, this.vehicle)); + this.netServerHandler.a(this.locX, this.locY, this.locZ, this.yaw, this.pitch); + } + + protected void a(double d0, boolean flag) { + } + + public void b(double d0, boolean flag) { + super.a(d0, flag); + } + + private void ai() { + this.bO = this.bO % 100 + 1; + } + + public void b(int i, int j, int k) { + this.ai(); + this.netServerHandler.sendPacket(new Packet100OpenWindow(this.bO, 1, "Crafting", 9)); + this.activeContainer = new ContainerWorkbench(this.inventory, this.world, i, j, k); + this.activeContainer.windowId = this.bO; + this.activeContainer.a((ICrafting) this); + } + + public void a(IInventory iinventory) { + this.ai(); + + // Poseidon start + ChestOpenedEvent event = new ChestOpenedEvent((org.bukkit.entity.Player) this.getBukkitEntity(), iinventory.getContents()); + this.world.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) return; + // Poseidon end + + this.netServerHandler.sendPacket(new Packet100OpenWindow(this.bO, 0, iinventory.getName(), iinventory.getSize())); + this.activeContainer = new ContainerChest(this.inventory, iinventory); + this.activeContainer.windowId = this.bO; + this.activeContainer.a((ICrafting) this); + } + + public void a(TileEntityFurnace tileentityfurnace) { + this.ai(); + this.netServerHandler.sendPacket(new Packet100OpenWindow(this.bO, 2, tileentityfurnace.getName(), tileentityfurnace.getSize())); + this.activeContainer = new ContainerFurnace(this.inventory, tileentityfurnace); + this.activeContainer.windowId = this.bO; + this.activeContainer.a((ICrafting) this); + } + + public void a(TileEntityDispenser tileentitydispenser) { + this.ai(); + this.netServerHandler.sendPacket(new Packet100OpenWindow(this.bO, 3, tileentitydispenser.getName(), tileentitydispenser.getSize())); + this.activeContainer = new ContainerDispenser(this.inventory, tileentitydispenser); + this.activeContainer.windowId = this.bO; + this.activeContainer.a((ICrafting) this); + } + + // Poseidon start - check if player editing sign is the same player who placed the sign + public void a(TileEntitySign tileentitysign) { + tileentitysign.setEditingPlayer(this); + } + // Poseidon end + + public void a(Container container, int i, ItemStack itemstack) { + if (!(container.b(i) instanceof SlotResult)) { + if (!this.h) { + this.netServerHandler.sendPacket(new Packet103SetSlot(container.windowId, i, itemstack)); + } + } + } + + public void updateInventory(Container container) { + this.a(container, container.b()); + } + + public void a(Container container, List list) { + this.netServerHandler.sendPacket(new Packet104WindowItems(container.windowId, list)); + this.netServerHandler.sendPacket(new Packet103SetSlot(-1, -1, this.inventory.j())); + } + + public void a(Container container, int i, int j) { + this.netServerHandler.sendPacket(new Packet105CraftProgressBar(container.windowId, i, j)); + } + + public void a(ItemStack itemstack) { + } + + public void y() { + this.netServerHandler.sendPacket(new Packet101CloseWindow(this.activeContainer.windowId)); + this.A(); + } + + public void z() { + if (!this.h) { + this.netServerHandler.sendPacket(new Packet103SetSlot(-1, -1, this.inventory.j())); + } + } + + public void A() { + this.activeContainer.a((EntityHuman) this); + this.activeContainer = this.defaultContainer; + } + + public void a(float f, float f1, boolean flag, boolean flag1, float f2, float f3) { + this.az = f; + this.aA = f1; + this.aC = flag; + this.setSneak(flag1); + this.pitch = f2; + this.yaw = f3; + } + + public void a(Statistic statistic, int i) { + if (statistic != null) { + if (!statistic.g) { + while (i > 100) { + this.netServerHandler.sendPacket(new Packet200Statistic(statistic.e, 100)); + i -= 100; + } + + this.netServerHandler.sendPacket(new Packet200Statistic(statistic.e, i)); + } + } + } + + public void B() { + if (this.vehicle != null) { + this.mount(this.vehicle); + } + + if (this.passenger != null) { + this.passenger.mount(this); + } + + if (this.sleeping) { + this.a(true, false, false); + } + } + + public void C() { + this.bL = -99999999; + } + + public void a(String s) { + StatisticStorage statisticstorage = StatisticStorage.a(); + String s1 = statisticstorage.a(s); + + this.netServerHandler.sendPacket(new Packet3Chat(s1)); + } + + // CraftBukkit start + public long timeOffset = 0; + public boolean relativeTime = true; + + public long getPlayerTime() { + if (this.relativeTime) { + // Adds timeOffset to the current server time. + return this.world.getTime() + this.timeOffset; + } else { + // Adds timeOffset to the beginning of this day. + return this.world.getTime() - (this.world.getTime() % 24000) + this.timeOffset; + } + } + + @Override + public String toString() { + return super.toString() + "(" + this.name + " at " + this.locX + "," + this.locY + "," + this.locZ + ")"; + } + // CraftBukkit end +} diff --git a/src/main/java/net/minecraft/server/EntitySheep.java b/src/main/java/net/minecraft/server/EntitySheep.java new file mode 100644 index 0000000..cb2e3f1 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntitySheep.java @@ -0,0 +1,124 @@ +package net.minecraft.server; + +import java.util.Random; + +public class EntitySheep extends EntityAnimal { + + public static final float[][] a = new float[][] { { 1.0F, 1.0F, 1.0F}, { 0.95F, 0.7F, 0.2F}, { 0.9F, 0.5F, 0.85F}, { 0.6F, 0.7F, 0.95F}, { 0.9F, 0.9F, 0.2F}, { 0.5F, 0.8F, 0.1F}, { 0.95F, 0.7F, 0.8F}, { 0.3F, 0.3F, 0.3F}, { 0.6F, 0.6F, 0.6F}, { 0.3F, 0.6F, 0.7F}, { 0.7F, 0.4F, 0.9F}, { 0.2F, 0.4F, 0.8F}, { 0.5F, 0.4F, 0.3F}, { 0.4F, 0.5F, 0.2F}, { 0.8F, 0.3F, 0.3F}, { 0.1F, 0.1F, 0.1F}}; + + public EntitySheep(World world) { + super(world); + this.texture = "/mob/sheep.png"; + this.b(0.9F, 1.3F); + } + + protected void b() { + super.b(); + this.datawatcher.a(16, new Byte((byte) 0)); + } + + public boolean damageEntity(Entity entity, int i) { + return super.damageEntity(entity, i); + } + + protected void q() { + // CraftBukkit start - whole method + java.util.List loot = new java.util.ArrayList(); + + if (!this.isSheared()) { + loot.add(new org.bukkit.inventory.ItemStack(org.bukkit.Material.WOOL, 1, (short) 0, (byte) this.getColor())); + } + + org.bukkit.World bworld = this.world.getWorld(); + org.bukkit.entity.Entity entity = this.getBukkitEntity(); + + org.bukkit.event.entity.EntityDeathEvent event = new org.bukkit.event.entity.EntityDeathEvent(entity, loot); + this.world.getServer().getPluginManager().callEvent(event); + + for (org.bukkit.inventory.ItemStack stack: event.getDrops()) { + bworld.dropItemNaturally(entity.getLocation(), stack); + } + // CraftBukkit end + } + + protected int j() { + return Block.WOOL.id; + } + + public boolean a(EntityHuman entityhuman) { + ItemStack itemstack = entityhuman.inventory.getItemInHand(); + + if (itemstack != null && itemstack.id == Item.SHEARS.id && !this.isSheared()) { + if (!this.world.isStatic) { + this.setSheared(true); + int i = 2 + this.random.nextInt(3); + + for (int j = 0; j < i; ++j) { + EntityItem entityitem = this.a(new ItemStack(Block.WOOL.id, 1, this.getColor()), 1.0F); + + entityitem.motY += (double) (this.random.nextFloat() * 0.05F); + entityitem.motX += (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F); + entityitem.motZ += (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F); + } + } + + itemstack.damage(1, entityhuman); + } + + return false; + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("Sheared", this.isSheared()); + nbttagcompound.a("Color", (byte) this.getColor()); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.setSheared(nbttagcompound.m("Sheared")); + this.setColor(nbttagcompound.c("Color")); + } + + protected String g() { + return "mob.sheep"; + } + + protected String h() { + return "mob.sheep"; + } + + protected String i() { + return "mob.sheep"; + } + + public int getColor() { + return this.datawatcher.a(16) & 15; + } + + public void setColor(int i) { + byte b0 = this.datawatcher.a(16); + + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 & 240 | i & 15))); + } + + public boolean isSheared() { + return (this.datawatcher.a(16) & 16) != 0; + } + + public void setSheared(boolean flag) { + byte b0 = this.datawatcher.a(16); + + if (flag) { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 | 16))); + } else { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 & -17))); + } + } + + public static int a(Random random) { + int i = random.nextInt(100); + + return i < 5 ? 15 : (i < 10 ? 7 : (i < 15 ? 8 : (i < 18 ? 12 : (random.nextInt(500) == 0 ? 6 : 0)))); + } +} diff --git a/src/main/java/net/minecraft/server/EntitySkeleton.java b/src/main/java/net/minecraft/server/EntitySkeleton.java new file mode 100644 index 0000000..2067f2b --- /dev/null +++ b/src/main/java/net/minecraft/server/EntitySkeleton.java @@ -0,0 +1,113 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +// CraftBukkit start +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDeathEvent; +// CraftBukkit end + +public class EntitySkeleton extends EntityMonster { + + private static final ItemStack a = new ItemStack(Item.BOW, 1); + + public EntitySkeleton(World world) { + super(world); + this.texture = "/mob/skeleton.png"; + } + + protected String g() { + return "mob.skeleton"; + } + + protected String h() { + return "mob.skeletonhurt"; + } + + protected String i() { + return "mob.skeletonhurt"; + } + + public void v() { + if (this.world.d()) { + float f = this.c(1.0F); + + if (f > 0.5F && this.world.isChunkLoaded(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) { + // CraftBukkit start + EntityCombustEvent event = new EntityCombustEvent(this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.fireTicks = 300; + } + // CraftBukkit end + } + } + + super.v(); + } + + protected void a(Entity entity, float f) { + if (f < 10.0F) { + double d0 = entity.locX - this.locX; + double d1 = entity.locZ - this.locZ; + + if (this.attackTicks == 0) { + EntityArrow entityarrow = new EntityArrow(this.world, this); + + ++entityarrow.locY; + double d2 = entity.locY + (double) entity.t() - 0.20000000298023224D - entityarrow.locY; + float f1 = MathHelper.a(d0 * d0 + d1 * d1) * 0.2F; + + if ((boolean) PoseidonConfig.getInstance().getConfigOption("world.settings.skeleton-shooting-sound-fix.enabled", true)) { + this.world.e(1002, MathHelper.floor(this.locX), MathHelper.floor(this.locY - (double)this.height), MathHelper.floor(this.locZ), 0); // Poseidon - fix skeleton bow sounds (Strultz) + } else { + this.world.makeSound(this, "random.bow", 1.0F, 1.0F / (this.random.nextFloat() * 0.4F + 0.8F)); + } + entityarrow.a(d0, d2 + (double) f1, d1, 0.6F, 12.0F); + this.world.addEntity(entityarrow); + this.attackTicks = 30; + } + + this.yaw = (float) (Math.atan2(d1, d0) * 180.0D / 3.1415927410125732D) - 90.0F; + this.e = true; + } + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + protected int j() { + return Item.ARROW.id; + } + + protected void q() { + // CraftBukkit start - whole method + java.util.List loot = new java.util.ArrayList(); + + int count = this.random.nextInt(3); + if (count > 0) { + loot.add(new org.bukkit.inventory.ItemStack(org.bukkit.Material.ARROW, count)); + } + + count = this.random.nextInt(3); + if (count > 0) { + loot.add(new org.bukkit.inventory.ItemStack(org.bukkit.Material.BONE, count)); + } + + org.bukkit.World bworld = this.world.getWorld(); + org.bukkit.entity.Entity entity = this.getBukkitEntity(); + + EntityDeathEvent event = new EntityDeathEvent(entity, loot); + this.world.getServer().getPluginManager().callEvent(event); + + for (org.bukkit.inventory.ItemStack stack: event.getDrops()) { + bworld.dropItemNaturally(entity.getLocation(), stack); + } + // CraftBukkit end + } +} diff --git a/src/main/java/net/minecraft/server/EntitySlime.java b/src/main/java/net/minecraft/server/EntitySlime.java new file mode 100644 index 0000000..23e1bbb --- /dev/null +++ b/src/main/java/net/minecraft/server/EntitySlime.java @@ -0,0 +1,149 @@ +package net.minecraft.server; + +public class EntitySlime extends EntityLiving implements IMonster { + + public float a; + public float b; + private int size = 0; + + public EntitySlime(World world) { + super(world); + this.texture = "/mob/slime.png"; + int i = 1 << this.random.nextInt(3); + + this.height = 0.0F; + this.size = this.random.nextInt(20) + 10; + this.setSize(i); + } + + protected void b() { + super.b(); + this.datawatcher.a(16, new Byte((byte) 1)); + } + + public void setSize(int i) { + this.datawatcher.watch(16, new Byte((byte) i)); + this.b(0.6F * (float) i, 0.6F * (float) i); + this.health = i * i; + this.setPosition(this.locX, this.locY, this.locZ); + } + + public int getSize() { + return this.datawatcher.a(16); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("Size", this.getSize() - 1); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.setSize(nbttagcompound.e("Size") + 1); + } + + public void m_() { + this.b = this.a; + boolean flag = this.onGround; + + super.m_(); + if (this.onGround && !flag) { + int i = this.getSize(); + + for (int j = 0; j < i * 8; ++j) { + float f = this.random.nextFloat() * 3.1415927F * 2.0F; + float f1 = this.random.nextFloat() * 0.5F + 0.5F; + float f2 = MathHelper.sin(f) * (float) i * 0.5F * f1; + float f3 = MathHelper.cos(f) * (float) i * 0.5F * f1; + + this.world.a("slime", this.locX + (double) f2, this.boundingBox.b, this.locZ + (double) f3, 0.0D, 0.0D, 0.0D); + } + + if (i > 2) { + this.world.makeSound(this, "mob.slime", this.k(), ((this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F) / 0.8F); + } + + this.a = -0.5F; + } + + this.a *= 0.6F; + } + + protected void c_() { + this.U(); + EntityHuman entityhuman = this.world.findNearbyPlayer(this, 16.0D); + + if (entityhuman != null) { + this.a(entityhuman, 10.0F, 20.0F); + } + + if (this.onGround && this.size-- <= 0) { + this.size = this.random.nextInt(20) + 10; + if (entityhuman != null) { + this.size /= 3; + } + + this.aC = true; + if (this.getSize() > 1) { + this.world.makeSound(this, "mob.slime", this.k(), ((this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F) * 0.8F); + } + + this.a = 1.0F; + this.az = 1.0F - this.random.nextFloat() * 2.0F; + this.aA = (float) (1 * this.getSize()); + } else { + this.aC = false; + if (this.onGround) { + this.az = this.aA = 0.0F; + } + } + } + + public void die() { + int i = this.getSize(); + + if (!this.world.isStatic && i > 1 && this.health <= 0) { + for (int j = 0; j < 4; ++j) { + float f = ((float) (j % 2) - 0.5F) * (float) i / 4.0F; + float f1 = ((float) (j / 2) - 0.5F) * (float) i / 4.0F; + EntitySlime entityslime = new EntitySlime(this.world); + + entityslime.setSize(i / 2); + entityslime.setPositionRotation(this.locX + (double) f, this.locY + 0.5D, this.locZ + (double) f1, this.random.nextFloat() * 360.0F, 0.0F); + this.world.addEntity(entityslime); + } + } + + super.die(); + } + + public void b(EntityHuman entityhuman) { + int i = this.getSize(); + + if (i > 1 && this.e(entityhuman) && (double) this.f(entityhuman) < 0.6D * (double) i && entityhuman.damageEntity(this, i)) { + this.world.makeSound(this, "mob.slimeattack", 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + } + } + + protected String h() { + return "mob.slime"; + } + + protected String i() { + return "mob.slime"; + } + + protected int j() { + return this.getSize() == 1 ? Item.SLIME_BALL.id : 0; + } + + public boolean d() { + Chunk chunk = this.world.getChunkAtWorldCoords(MathHelper.floor(this.locX), MathHelper.floor(this.locZ)); + + return (this.getSize() == 1 || this.world.spawnMonsters > 0) && this.random.nextInt(10) == 0 && chunk.a(987234911L).nextInt(10) == 0 && this.locY < 16.0D; + } + + protected float k() { + return 0.6F; + } +} diff --git a/src/main/java/net/minecraft/server/EntitySnowball.java b/src/main/java/net/minecraft/server/EntitySnowball.java new file mode 100644 index 0000000..ec280cd --- /dev/null +++ b/src/main/java/net/minecraft/server/EntitySnowball.java @@ -0,0 +1,259 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.entity.CraftLivingEntity; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.ProjectileHitEvent; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntitySnowball extends Entity { + + private int b = -1; + private int c = -1; + private int d = -1; + private int e = 0; + private boolean f = false; + public int a = 0; + public EntityLiving shooter; // CraftBukkit - private -> public + private int h; + private int i = 0; + + public EntitySnowball(World world) { + super(world); + this.b(0.25F, 0.25F); + } + + protected void b() {} + + public EntitySnowball(World world, EntityLiving entityliving) { + super(world); + this.shooter = entityliving; + this.b(0.25F, 0.25F); + this.setPositionRotation(entityliving.locX, entityliving.locY + (double) entityliving.t(), entityliving.locZ, entityliving.yaw, entityliving.pitch); + this.locX -= (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.locY -= 0.10000000149011612D; + this.locZ -= (double) (MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * 0.16F); + this.setPosition(this.locX, this.locY, this.locZ); + this.height = 0.0F; + float f = 0.4F; + + this.motX = (double) (-MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + this.motZ = (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F) * f); + this.motY = (double) (-MathHelper.sin(this.pitch / 180.0F * 3.1415927F) * f); + this.a(this.motX, this.motY, this.motZ, 1.5F, 1.0F); + } + + public EntitySnowball(World world, double d0, double d1, double d2) { + super(world); + this.h = 0; + this.b(0.25F, 0.25F); + this.setPosition(d0, d1, d2); + this.height = 0.0F; + } + + public void a(double d0, double d1, double d2, float f, float f1) { + float f2 = MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + + d0 /= (double) f2; + d1 /= (double) f2; + d2 /= (double) f2; + d0 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d1 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d2 += this.random.nextGaussian() * 0.007499999832361937D * (double) f1; + d0 *= (double) f; + d1 *= (double) f; + d2 *= (double) f; + this.motX = d0; + this.motY = d1; + this.motZ = d2; + float f3 = MathHelper.a(d0 * d0 + d2 * d2); + + this.lastYaw = this.yaw = (float) (Math.atan2(d0, d2) * 180.0D / 3.1415927410125732D); + this.lastPitch = this.pitch = (float) (Math.atan2(d1, (double) f3) * 180.0D / 3.1415927410125732D); + this.h = 0; + } + + public void m_() { + this.bo = this.locX; + this.bp = this.locY; + this.bq = this.locZ; + super.m_(); + if (this.a > 0) { + --this.a; + } + + if (this.f) { + int i = this.world.getTypeId(this.b, this.c, this.d); + + if (i == this.e) { + ++this.h; + if (this.h == 1200) { + this.die(); + } + + return; + } + + this.f = false; + this.motX *= (double) (this.random.nextFloat() * 0.2F); + this.motY *= (double) (this.random.nextFloat() * 0.2F); + this.motZ *= (double) (this.random.nextFloat() * 0.2F); + this.h = 0; + this.i = 0; + } else { + ++this.i; + } + + Vec3D vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + Vec3D vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + MovingObjectPosition movingobjectposition = this.world.a(vec3d, vec3d1); + + vec3d = Vec3D.create(this.locX, this.locY, this.locZ); + vec3d1 = Vec3D.create(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + if (movingobjectposition != null) { + vec3d1 = Vec3D.create(movingobjectposition.f.a, movingobjectposition.f.b, movingobjectposition.f.c); + } + + if (!this.world.isStatic) { + Entity entity = null; + List list = this.world.b((Entity) this, this.boundingBox.a(this.motX, this.motY, this.motZ).b(1.0D, 1.0D, 1.0D)); + double d0 = 0.0D; + + for (int j = 0; j < list.size(); ++j) { + Entity entity1 = (Entity) list.get(j); + + if (entity1.l_() && (entity1 != this.shooter || this.i >= 5)) { + float f = 0.3F; + AxisAlignedBB axisalignedbb = entity1.boundingBox.b((double) f, (double) f, (double) f); + MovingObjectPosition movingobjectposition1 = axisalignedbb.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { + double d1 = vec3d.a(movingobjectposition1.f); + + if (d1 < d0 || d0 == 0.0D) { + entity = entity1; + d0 = d1; + } + } + } + } + + if (entity != null) { + movingobjectposition = new MovingObjectPosition(entity); + } + } + + if (movingobjectposition != null) { + // CraftBukkit start + ProjectileHitEvent phe = new ProjectileHitEvent((Projectile) this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(phe); + + if (movingobjectposition.entity != null) { + boolean stick; + if (movingobjectposition.entity instanceof EntityLiving) { + org.bukkit.entity.Entity damagee = movingobjectposition.entity.getBukkitEntity(); + Projectile projectile = (Projectile) this.getBukkitEntity(); + + // TODO @see EntityArrow#162 + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(projectile, damagee, EntityDamageEvent.DamageCause.PROJECTILE, 0); + this.world.getServer().getPluginManager().callEvent(event); + this.shooter = (projectile.getShooter() == null) ? null : ((CraftLivingEntity) projectile.getShooter()).getHandle(); + + if (event.isCancelled()) { + stick = !projectile.doesBounce(); + } else { + // this function returns if the snowball should stick in or not, i.e. !bounce + stick = movingobjectposition.entity.damageEntity(this, event.getDamage()); + } + } else { + stick = movingobjectposition.entity.damageEntity(this.shooter, 0); + } + if (stick) { + ; + } + } + // CraftBukkit end + + for (int k = 0; k < 8; ++k) { + this.world.a("snowballpoof", this.locX, this.locY, this.locZ, 0.0D, 0.0D, 0.0D); + } + + this.die(); + } + + this.locX += this.motX; + this.locY += this.motY; + this.locZ += this.motZ; + float f1 = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + + this.yaw = (float) (Math.atan2(this.motX, this.motZ) * 180.0D / 3.1415927410125732D); + + for (this.pitch = (float) (Math.atan2(this.motY, (double) f1) * 180.0D / 3.1415927410125732D); this.pitch - this.lastPitch < -180.0F; this.lastPitch -= 360.0F) { + ; + } + + while (this.pitch - this.lastPitch >= 180.0F) { + this.lastPitch += 360.0F; + } + + while (this.yaw - this.lastYaw < -180.0F) { + this.lastYaw -= 360.0F; + } + + while (this.yaw - this.lastYaw >= 180.0F) { + this.lastYaw += 360.0F; + } + + this.pitch = this.lastPitch + (this.pitch - this.lastPitch) * 0.2F; + this.yaw = this.lastYaw + (this.yaw - this.lastYaw) * 0.2F; + float f2 = 0.99F; + float f3 = 0.03F; + + if (this.ad()) { + for (int l = 0; l < 4; ++l) { + float f4 = 0.25F; + + this.world.a("bubble", this.locX - this.motX * (double) f4, this.locY - this.motY * (double) f4, this.locZ - this.motZ * (double) f4, this.motX, this.motY, this.motZ); + } + + f2 = 0.8F; + } + + this.motX *= (double) f2; + this.motY *= (double) f2; + this.motZ *= (double) f2; + this.motY -= (double) f3; + this.setPosition(this.locX, this.locY, this.locZ); + } + + public void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("xTile", (short) this.b); + nbttagcompound.a("yTile", (short) this.c); + nbttagcompound.a("zTile", (short) this.d); + nbttagcompound.a("inTile", (byte) this.e); + nbttagcompound.a("shake", (byte) this.a); + nbttagcompound.a("inGround", (byte) (this.f ? 1 : 0)); + } + + public void a(NBTTagCompound nbttagcompound) { + this.b = nbttagcompound.d("xTile"); + this.c = nbttagcompound.d("yTile"); + this.d = nbttagcompound.d("zTile"); + this.e = nbttagcompound.c("inTile") & 255; + this.a = nbttagcompound.c("shake") & 255; + this.f = nbttagcompound.c("inGround") == 1; + } + + public void b(EntityHuman entityhuman) { + if (this.f && this.shooter == entityhuman && this.a <= 0 && entityhuman.inventory.pickup(new ItemStack(Item.ARROW, 1))) { + this.world.makeSound(this, "random.pop", 0.2F, ((this.random.nextFloat() - this.random.nextFloat()) * 0.7F + 1.0F) * 2.0F); + entityhuman.receive(this, 1); + this.die(); + } + } +} diff --git a/src/main/java/net/minecraft/server/EntitySpider.java b/src/main/java/net/minecraft/server/EntitySpider.java new file mode 100644 index 0000000..b1e77d3 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntitySpider.java @@ -0,0 +1,98 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.event.entity.EntityTargetEvent; +// CraftBukkit end + +public class EntitySpider extends EntityMonster { + + public EntitySpider(World world) { + super(world); + this.texture = "/mob/spider.png"; + this.b(1.4F, 0.9F); + this.aE = 0.8F; + } + + public double m() { + return (double) this.width * 0.75D - 0.5D; + } + + protected boolean n() { + return false; + } + + protected Entity findTarget() { + float f = this.c(1.0F); + + if (f < 0.5F) { + double d0 = 16.0D; + + return this.world.findNearbyPlayer(this, d0); + } else { + return null; + } + } + + protected String g() { + return "mob.spider"; + } + + protected String h() { + return "mob.spider"; + } + + protected String i() { + return "mob.spiderdeath"; + } + + protected void a(Entity entity, float f) { + float f1 = this.c(1.0F); + + if (f1 > 0.5F && this.random.nextInt(100) == 0) { + // CraftBukkit start + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), null, EntityTargetEvent.TargetReason.FORGOT_TARGET); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + this.target = ((CraftEntity) event.getTarget()).getHandle(); + } + return; + } + // CraftBukkit end + } else { + if (f > 2.0F && f < 6.0F && this.random.nextInt(10) == 0) { + if (this.onGround) { + double d0 = entity.locX - this.locX; + double d1 = entity.locZ - this.locZ; + float f2 = MathHelper.a(d0 * d0 + d1 * d1); + + this.motX = d0 / (double) f2 * 0.5D * 0.800000011920929D + this.motX * 0.20000000298023224D; + this.motZ = d1 / (double) f2 * 0.5D * 0.800000011920929D + this.motZ * 0.20000000298023224D; + this.motY = 0.4000000059604645D; + } + } else { + super.a(entity, f); + } + } + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + protected int j() { + return Item.STRING.id; + } + + public boolean p() { + return this.positionChanged; + } +} diff --git a/src/main/java/net/minecraft/server/EntitySquid.java b/src/main/java/net/minecraft/server/EntitySquid.java new file mode 100644 index 0000000..f22b146 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntitySquid.java @@ -0,0 +1,157 @@ +package net.minecraft.server; + +import org.bukkit.event.entity.EntityDeathEvent; + +public class EntitySquid extends EntityWaterAnimal { + + public float a = 0.0F; + public float b = 0.0F; + public float c = 0.0F; + public float f = 0.0F; + public float g = 0.0F; + public float h = 0.0F; + public float i = 0.0F; + public float j = 0.0F; + private float k = 0.0F; + private float l = 0.0F; + private float m = 0.0F; + private float n = 0.0F; + private float o = 0.0F; + private float p = 0.0F; + + public EntitySquid(World world) { + super(world); + this.texture = "/mob/squid.png"; + this.b(0.95F, 0.95F); + this.l = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + protected String g() { + return null; + } + + protected String h() { + return null; + } + + protected String i() { + return null; + } + + protected float k() { + return 0.4F; + } + + protected int j() { + return 0; + } + + protected void q() { + // CraftBukkit start - whole method + java.util.List loot = new java.util.ArrayList(); + + int count = this.random.nextInt(3) + 1; + if (count > 0) { + loot.add(new org.bukkit.inventory.ItemStack(org.bukkit.Material.INK_SACK, count)); + } + + org.bukkit.World bworld = this.world.getWorld(); + org.bukkit.entity.Entity entity = this.getBukkitEntity(); + + EntityDeathEvent event = new EntityDeathEvent(entity, loot); + this.world.getServer().getPluginManager().callEvent(event); + + for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { + bworld.dropItemNaturally(entity.getLocation(), stack); + } + // CraftBukkit end + } + + public boolean a(EntityHuman entityhuman) { + return false; + } + + public boolean ad() { + return this.world.a(this.boundingBox.b(0.0D, -0.6000000238418579D, 0.0D), Material.WATER, this); + } + + public void v() { + super.v(); + this.b = this.a; + this.f = this.c; + this.h = this.g; + this.j = this.i; + this.g += this.l; + if (this.g > 6.2831855F) { + this.g -= 6.2831855F; + if (this.random.nextInt(10) == 0) { + this.l = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; + } + } + + if (this.ad()) { + float f; + + if (this.g < 3.1415927F) { + f = this.g / 3.1415927F; + this.i = MathHelper.sin(f * f * 3.1415927F) * 3.1415927F * 0.25F; + if ((double) f > 0.75D) { + this.k = 1.0F; + this.m = 1.0F; + } else { + this.m *= 0.8F; + } + } else { + this.i = 0.0F; + this.k *= 0.9F; + this.m *= 0.99F; + } + + if (!this.Y) { + this.motX = (double) (this.n * this.k); + this.motY = (double) (this.o * this.k); + this.motZ = (double) (this.p * this.k); + } + + f = MathHelper.a(this.motX * this.motX + this.motZ * this.motZ); + this.K += (-((float) Math.atan2(this.motX, this.motZ)) * 180.0F / 3.1415927F - this.K) * 0.1F; + this.yaw = this.K; + this.c += 3.1415927F * this.m * 1.5F; + this.a += (-((float) Math.atan2((double) f, this.motY)) * 180.0F / 3.1415927F - this.a) * 0.1F; + } else { + this.i = MathHelper.abs(MathHelper.sin(this.g)) * 3.1415927F * 0.25F; + if (!this.Y) { + this.motX = 0.0D; + this.motY -= 0.08D; + this.motY *= 0.9800000190734863D; + this.motZ = 0.0D; + } + + this.a = (float) ((double) this.a + (double) (-90.0F - this.a) * 0.02D); + } + } + + public void a(float f, float f1) { + this.move(this.motX, this.motY, this.motZ); + } + + protected void c_() { + if (this.random.nextInt(50) == 0 || !this.bA || this.n == 0.0F && this.o == 0.0F && this.p == 0.0F) { + float f = this.random.nextFloat() * 3.1415927F * 2.0F; + + this.n = MathHelper.cos(f) * 0.2F; + this.o = -0.1F + this.random.nextFloat() * 0.2F; + this.p = MathHelper.sin(f) * 0.2F; + } + + this.U(); + } +} diff --git a/src/main/java/net/minecraft/server/EntityTNTPrimed.java b/src/main/java/net/minecraft/server/EntityTNTPrimed.java new file mode 100644 index 0000000..1140cd4 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityTNTPrimed.java @@ -0,0 +1,100 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.entity.Explosive; +import org.bukkit.event.entity.ExplosionPrimeEvent; +// CraftBukkit end + +public class EntityTNTPrimed extends Entity { + + public int fuseTicks; + public float yield = 4; // CraftBukkit + public boolean isIncendiary = false; // CraftBukkit + + public EntityTNTPrimed(World world) { + super(world); + this.fuseTicks = 0; + this.aI = true; + this.b(0.98F, 0.98F); + this.height = this.width / 2.0F; + } + + public EntityTNTPrimed(World world, double d0, double d1, double d2) { + this(world); + this.setPosition(d0, d1, d2); + float f = (float) (Math.random() * 3.1415927410125732D * 2.0D); + + this.motX = (double) (-MathHelper.sin(f * 3.1415927F / 180.0F) * 0.02F); + this.motY = 0.20000000298023224D; + this.motZ = (double) (-MathHelper.cos(f * 3.1415927F / 180.0F) * 0.02F); + this.fuseTicks = 80; + this.lastX = d0; + this.lastY = d1; + this.lastZ = d2; + } + + protected void b() {} + + protected boolean n() { + return false; + } + + public boolean l_() { + return !this.dead; + } + + public void m_() { + this.lastX = this.locX; + this.lastY = this.locY; + this.lastZ = this.locZ; + this.motY -= 0.03999999910593033D; + this.move(this.motX, this.motY, this.motZ); + this.motX *= 0.9800000190734863D; + this.motY *= 0.9800000190734863D; + this.motZ *= 0.9800000190734863D; + if (this.onGround) { + this.motX *= 0.699999988079071D; + this.motZ *= 0.699999988079071D; + this.motY *= -0.5D; + } + + if (this.fuseTicks-- <= 0) { + if (!this.world.isStatic) { + // CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event. + this.explode(); + this.die(); + // CraftBukkit end + } else { + this.die(); + } + } else { + this.world.a("smoke", this.locX, this.locY + 0.5D, this.locZ, 0.0D, 0.0D, 0.0D); + } + } + + private void explode() { + // CraftBukkit start + // float f = 4.0F; + + CraftServer server = this.world.getServer(); + + ExplosionPrimeEvent event = new ExplosionPrimeEvent((Explosive) CraftEntity.getEntity(server, this)); + server.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + // give 'this' instead of (Entity) null so we know what causes the damage + this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire()); + } + // CraftBukkit end + } + + protected void b(NBTTagCompound nbttagcompound) { + nbttagcompound.a("Fuse", (byte) this.fuseTicks); + } + + protected void a(NBTTagCompound nbttagcompound) { + this.fuseTicks = nbttagcompound.c("Fuse"); + } +} diff --git a/src/main/java/net/minecraft/server/EntityTracker.java b/src/main/java/net/minecraft/server/EntityTracker.java new file mode 100644 index 0000000..22a597c --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityTracker.java @@ -0,0 +1,178 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class EntityTracker { + + private Set a = new HashSet(); + public EntityList b = new EntityList(); //Project Poseidon: private -> public + private MinecraftServer c; + private int d; + private int e; + + public EntityTracker(MinecraftServer minecraftserver, int i) { + this.c = minecraftserver; + this.e = i; + this.d = minecraftserver.serverConfigurationManager.a(); + } + + // CraftBukkit - synchronized + public synchronized void track(Entity entity) { + if (entity instanceof EntityPlayer) { + this.a(entity, 512, 2); + EntityPlayer entityplayer = (EntityPlayer) entity; + Iterator iterator = this.a.iterator(); + + while (iterator.hasNext()) { + EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); + + if (entitytrackerentry.tracker != entityplayer) { + entitytrackerentry.b(entityplayer); + } + } + } else if (entity instanceof EntityFish) { + this.a(entity, 64, 5, true); + } else if (entity instanceof EntityArrow) { + this.a(entity, 64, 20, false); + } else if (entity instanceof EntityFireball) { + this.a(entity, 64, 10, false); + } else if (entity instanceof EntitySnowball) { + this.a(entity, 64, 10, true); + } else if (entity instanceof EntityEgg) { + this.a(entity, 64, 10, true); + } else if (entity instanceof EntityItem) { + this.a(entity, 64, 20, true); + } else if (entity instanceof EntityMinecart) { + this.a(entity, 160, 5, true); + } else if (entity instanceof EntityBoat) { + this.a(entity, 160, 5, true); + } else if (entity instanceof EntitySquid) { + this.a(entity, 160, 3, true); + } else if (entity instanceof IAnimal) { + this.a(entity, 160, 3); + } else if (entity instanceof EntityTNTPrimed) { + this.a(entity, 160, 10, true); + } else if (entity instanceof EntityFallingSand) { + this.a(entity, 160, 20, true); + } else if (entity instanceof EntityPainting) { + this.a(entity, 160, Integer.MAX_VALUE, false); + } + } + + public void a(Entity entity, int i, int j) { + this.a(entity, i, j, false); + } + + // CraftBukkit - synchronized + public synchronized void a(Entity entity, int i, int j, boolean flag) { + if (i > this.d) { + i = this.d; + } + + if (this.b.b(entity.id)) { + // CraftBukkit - removed exception throw as tracking an already tracked entity theoretically shouldn't cause any issues. + // throw new IllegalStateException("Entity is already tracked!"); + } else { + EntityTrackerEntry entitytrackerentry = new EntityTrackerEntry(entity, i, j, flag); + + this.a.add(entitytrackerentry); + this.b.a(entity.id, entitytrackerentry); + entitytrackerentry.scanPlayers(this.c.getWorldServer(this.e).players); + } + } + + // CraftBukkit - synchronized + public synchronized void untrackEntity(Entity entity) { + if (entity instanceof EntityPlayer) { + EntityPlayer entityplayer = (EntityPlayer) entity; + Iterator iterator = this.a.iterator(); + + while (iterator.hasNext()) { + EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); + + entitytrackerentry.a(entityplayer); + } + } + + EntityTrackerEntry entitytrackerentry1 = (EntityTrackerEntry) this.b.d(entity.id); + + if (entitytrackerentry1 != null) { + this.a.remove(entitytrackerentry1); + entitytrackerentry1.a(); + } + } + + // CraftBukkit - synchronized + public synchronized void updatePlayers() { + ArrayList arraylist = new ArrayList(); + Iterator iterator = this.a.iterator(); + + while (iterator.hasNext()) { + EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); + + entitytrackerentry.track(this.c.getWorldServer(this.e).players); + if (entitytrackerentry.m && entitytrackerentry.tracker instanceof EntityPlayer) { + arraylist.add((EntityPlayer) entitytrackerentry.tracker); + } + } + + for (int i = 0; i < arraylist.size(); ++i) { + EntityPlayer entityplayer = (EntityPlayer) arraylist.get(i); + Iterator iterator1 = this.a.iterator(); + + while (iterator1.hasNext()) { + EntityTrackerEntry entitytrackerentry1 = (EntityTrackerEntry) iterator1.next(); + + if (entitytrackerentry1.tracker != entityplayer) { + entitytrackerentry1.b(entityplayer); + } + } + } + } + + // CraftBukkit - synchronized + public synchronized void a(Entity entity, Packet packet) { + EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.b.a(entity.id); + + if (entitytrackerentry != null) { + entitytrackerentry.a(packet); + } + } + + // CraftBukkit - synchronized + public synchronized void sendPacketToEntity(Entity entity, Packet packet) { + EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.b.a(entity.id); + + if (entitytrackerentry != null) { + entitytrackerentry.b(packet); + } + } + + // CraftBukkit - synchronized + public synchronized void untrackPlayer(EntityPlayer entityplayer) { + Iterator iterator = this.a.iterator(); + + while (iterator.hasNext()) { + EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); + + entitytrackerentry.c(entityplayer); + } + } + + // Poseidon + // CraftBukkit - synchronized + public synchronized void a(EntityPlayer entityplayer, Chunk chunk) { + Iterator iterator = this.a.iterator(); + + while (iterator.hasNext()) { + EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); + + if (entitytrackerentry.tracker != entityplayer && entitytrackerentry.tracker.bH == chunk.x && entitytrackerentry.tracker.bJ == chunk.z) { + entitytrackerentry.b(entityplayer); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java new file mode 100644 index 0000000..3c75c76 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java @@ -0,0 +1,405 @@ +package net.minecraft.server; + +import org.bukkit.entity.Player; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +public class EntityTrackerEntry { + + public Entity tracker; + public int b; + public int c; + public int d; + public int e; + public int f; + public int g; + public int h; + public double i; + public double j; + public double k; + public int l = 0; + private double o; + private double p; + private double q; + private boolean r = false; + private boolean isMoving; + private int t = 0; + public boolean m = false; + public Set trackedPlayers = new HashSet(); + + public EntityTrackerEntry(Entity entity, int i, int j, boolean flag) { + this.tracker = entity; + this.b = i; + this.c = j; + this.isMoving = flag; + this.d = MathHelper.floor(entity.locX * 32.0D); + this.e = MathHelper.floor(entity.locY * 32.0D); + this.f = MathHelper.floor(entity.locZ * 32.0D); + this.g = MathHelper.d(entity.yaw * 256.0F / 360.0F); + this.h = MathHelper.d(entity.pitch * 256.0F / 360.0F); + } + + public boolean equals(Object object) { + return object instanceof EntityTrackerEntry ? ((EntityTrackerEntry) object).tracker.id == this.tracker.id : false; + } + + public int hashCode() { + return this.tracker.id; + } + + public void track(List list) { + this.m = false; + if (!this.r || this.tracker.e(this.o, this.p, this.q) > 16.0D) { + this.o = this.tracker.locX; + this.p = this.tracker.locY; + this.q = this.tracker.locZ; + this.r = true; + this.m = true; + this.scanPlayers(list); + } + + if (++this.l % this.c == 0 || this.tracker.airBorne || this.tracker.aa().a()) { + ++this.t; // Poseidon - moved below + + // encoded means multiplied by 32 + // this is required to send it to the client, as the relative position is sent as the float multiplied by 32 + int newEncodedPosX = MathHelper.floor(this.tracker.locX * 32.0D); + int newEncodedPosY = MathHelper.floor(this.tracker.locY * 32.0D); + int newEncodedPosZ = MathHelper.floor(this.tracker.locZ * 32.0D); + int newEncodedRotationYaw = MathHelper.d(this.tracker.yaw * 256.0F / 360.0F); + int newEncodedRotationPitch = MathHelper.d(this.tracker.pitch * 256.0F / 360.0F); + int encodedDiffX = newEncodedPosX - this.d; + int encodedDiffY = newEncodedPosY - this.e; + int encodedDiffZ = newEncodedPosZ - this.f; + Object packet = null; + // mob movement fix, credit to Oldmana#7086 from the Modification Station discord server + // https://discordapp.com/channels/397834523028488203/397839387465089054/684637208199823377 + int movementUpdateTreshold = 1; + int rotationUpdateTreshold = 1; + boolean needsPositionUpdate = Math.abs(encodedDiffX) >= movementUpdateTreshold || Math.abs(encodedDiffY) >= movementUpdateTreshold || Math.abs(encodedDiffZ) >= movementUpdateTreshold + || tracker instanceof EntityBoat || tracker instanceof EntityMinecart; + + boolean needsRotationUpdate = Math.abs(newEncodedRotationYaw - this.g) >= rotationUpdateTreshold || Math.abs(newEncodedRotationPitch - this.h) >= rotationUpdateTreshold; + + // CraftBukkit start - Code moved from below + if (needsPositionUpdate) { + this.d = newEncodedPosX; + this.e = newEncodedPosY; + this.f = newEncodedPosZ; + } + + if (needsRotationUpdate) { + this.g = newEncodedRotationYaw; + this.h = newEncodedRotationPitch; + } + // CraftBukkit end + + if (encodedDiffX >= -128 && encodedDiffX < 128 && encodedDiffY >= -128 && encodedDiffY < 128 && encodedDiffZ >= -128 && encodedDiffZ < 128 && this.t <= 400) { + // entity has moved less than 4 blocks + if (needsPositionUpdate && needsRotationUpdate) { + packet = new Packet33RelEntityMoveLook(this.tracker.id, (byte) encodedDiffX, (byte) encodedDiffY, (byte) encodedDiffZ, (byte) newEncodedRotationYaw, (byte) newEncodedRotationPitch); + } else if (needsPositionUpdate) { + packet = new Packet31RelEntityMove(this.tracker.id, (byte) encodedDiffX, (byte) encodedDiffY, (byte) encodedDiffZ); + } else if (needsRotationUpdate) { + packet = new Packet32EntityLook(this.tracker.id, (byte) newEncodedRotationYaw, (byte) newEncodedRotationPitch); + } + } else { + this.t = 0; + // minecart clipping fix + //this.tracker.locX = (double) i / 32.0D; + //this.tracker.locY = (double) j / 32.0D; + //this.tracker.locZ = (double) k / 32.0D; + // entity has moved more than 4 blocks, send teleport + + // CraftBukkit start - Refresh list of who can see a player before sending teleport packet + if (this.tracker instanceof EntityPlayer) { + this.scanPlayers(new java.util.ArrayList(this.trackedPlayers)); + } + // CraftBukkit end + + packet = new Packet34EntityTeleport(this.tracker.id, newEncodedPosX, newEncodedPosY, newEncodedPosZ, (byte) newEncodedRotationYaw, (byte) newEncodedRotationPitch); + } + + if (this.isMoving) { + double d0 = this.tracker.motX - this.i; + double d1 = this.tracker.motY - this.j; + double d2 = this.tracker.motZ - this.k; + double d3 = 0.02D; + double d4 = d0 * d0 + d1 * d1 + d2 * d2; + + if (d4 > d3 * d3 || d4 > 0.0D && this.tracker.motX == 0.0D && this.tracker.motY == 0.0D && this.tracker.motZ == 0.0D) { + this.i = this.tracker.motX; + this.j = this.tracker.motY; + this.k = this.tracker.motZ; + this.a((Packet) (new Packet28EntityVelocity(this.tracker.id, this.i, this.j, this.k))); + } + } + + if (packet != null) { + this.a((Packet) packet); + } + + DataWatcher datawatcher = this.tracker.aa(); + + if (datawatcher.a()) { + this.b((Packet) (new Packet40EntityMetadata(this.tracker.id, datawatcher))); + } + + /* CraftBukkit start - Code moved up + if (needsPositionUpdate) { + this.d = newEncodedPosX; + this.e = newEncodedPosY; + this.f = newEncodedPosZ; + } + + if (needsRotationUpdate) { + this.g = newEncodedRotationYaw; + this.h = newEncodedRotationPitch; + } + // Craftbukkit end */ + this.tracker.airBorne = false; + } + + if (this.tracker.velocityChanged) { + // CraftBukkit start - create PlayerVelocity event + boolean cancelled = false; + + if(this.tracker instanceof EntityPlayer) { + org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.tracker.getBukkitEntity(); + org.bukkit.util.Vector velocity = player.getVelocity(); + + org.bukkit.event.player.PlayerVelocityEvent event = new org.bukkit.event.player.PlayerVelocityEvent(player, velocity); + this.tracker.world.getServer().getPluginManager().callEvent(event); + + if(event.isCancelled()) { + cancelled = true; + } + else if(!velocity.equals(event.getVelocity())) { + player.setVelocity(velocity); + } + } + + if(!cancelled) { + this.b((Packet) (new Packet28EntityVelocity(this.tracker))); + } + // CraftBukkit end + this.tracker.velocityChanged = false; + } + } + + public void a(Packet packet) { + Iterator iterator = this.trackedPlayers.iterator(); + + while (iterator.hasNext()) { + EntityPlayer entityplayer = (EntityPlayer) iterator.next(); + + entityplayer.netServerHandler.sendPacket(packet); + } + } + + public void b(Packet packet) { + this.a(packet); + if (this.tracker instanceof EntityPlayer) { + ((EntityPlayer) this.tracker).netServerHandler.sendPacket(packet); + } + } + + public void a() { + // Poseidon start + //this.a((Packet) (new Packet29DestroyEntity(this.tracker.id))); + Iterator iterator = this.trackedPlayers.iterator(); + + while (iterator.hasNext()) { + EntityPlayer entityplayer = (EntityPlayer) iterator.next(); + + entityplayer.removeQueue.add(Integer.valueOf(this.tracker.id)); + } + // Poseidon end + } + + public void a(EntityPlayer entityplayer) { + if (this.trackedPlayers.contains(entityplayer)) { + entityplayer.removeQueue.add(Integer.valueOf(this.tracker.id)); // Poseidon + this.trackedPlayers.remove(entityplayer); + } + } + + public void b(EntityPlayer entityplayer) { + if (entityplayer != this.tracker) { + double d0 = entityplayer.locX - (double) (this.d / 32); + double d1 = entityplayer.locZ - (double) (this.f / 32); + + if (d0 >= (double) (-this.b) && d0 <= (double) this.b && d1 >= (double) (-this.b) && d1 <= (double) this.b) { + if (!this.trackedPlayers.contains(entityplayer) && this.d(entityplayer)) { + // CraftBukkit start + if (tracker instanceof EntityPlayer) { + org.bukkit.entity.Player player = (Player) ((EntityPlayer) tracker).getBukkitEntity(); + if (!((Player) entityplayer.getBukkitEntity()).canSee(player)) { + return; + } + } + + entityplayer.removeQueue.remove(Integer.valueOf(this.tracker.id)); + // CraftBukkit end + + this.trackedPlayers.add(entityplayer); + Packet packet = this.b(); + entityplayer.netServerHandler.sendPacket(packet); + // Poseidon Start + if (!this.tracker.datawatcher.getD()) { + entityplayer.netServerHandler.sendPacket(new Packet40EntityMetadata(this.tracker.id, this.tracker.datawatcher)); + } + + this.i = this.tracker.motX; + this.j = this.tracker.motY; + this.k = this.tracker.motZ; + if (this.isMoving) { + entityplayer.netServerHandler.sendPacket(new Packet28EntityVelocity(this.tracker.id, this.tracker.motX, this.tracker.motY, this.tracker.motZ)); + } + + if (this.tracker.vehicle != null) { + entityplayer.netServerHandler.sendPacket(new Packet39AttachEntity(this.tracker, this.tracker.vehicle)); + } + // Poseidon end + + // CraftBukkit start + if (this.tracker.passenger != null) { + entityplayer.netServerHandler.sendPacket(new Packet39AttachEntity(this.tracker.passenger, this.tracker)); + } + // CraftBukkit end + + ItemStack[] aitemstack = this.tracker.getEquipment(); + + if (aitemstack != null) { + for (int i = 0; i < aitemstack.length; ++i) { + entityplayer.netServerHandler.sendPacket(new Packet5EntityEquipment(this.tracker.id, i, aitemstack[i])); + } + } + + if (this.tracker instanceof EntityHuman) { + EntityHuman entityhuman = (EntityHuman) this.tracker; + + if (entityhuman.isSleeping()) { + entityplayer.netServerHandler.sendPacket(new Packet17(this.tracker, 0, MathHelper.floor(this.tracker.locX), MathHelper.floor(this.tracker.locY), MathHelper.floor(this.tracker.locZ))); + } + } + } + } else if (this.trackedPlayers.contains(entityplayer)) { + this.trackedPlayers.remove(entityplayer); + entityplayer.removeQueue.add(Integer.valueOf(this.tracker.id)); // Poseidon + //entityplayer.netServerHandler.sendPacket(new Packet29DestroyEntity(this.tracker.id)); + } + } + } + + private boolean d(EntityPlayer entityplayer) { + return entityplayer.getWorldServer().getPlayerManager().a(entityplayer, this.tracker.bH, this.tracker.bJ); + } + + public void scanPlayers(List list) { + for (int i = 0; i < list.size(); ++i) { + this.b((EntityPlayer) list.get(i)); + } + } + + private Packet b() { + if (this.tracker.dead) { // Poseidon + // CraftBukkit start - Remove useless error spam, just return + // System.out.println("Fetching addPacket for removed entity"); + return null; + // CraftBukkit end + } + + if (this.tracker instanceof EntityItem) { + EntityItem entityitem = (EntityItem) this.tracker; + Packet21PickupSpawn packet21pickupspawn = new Packet21PickupSpawn(entityitem); + + // There's no reason to set the item's position to the compressed position + //entityitem.locX = (double) packet21pickupspawn.b / 32.0D; + //entityitem.locY = (double) packet21pickupspawn.c / 32.0D; + //entityitem.locZ = (double) packet21pickupspawn.d / 32.0D; + return packet21pickupspawn; + } else if (this.tracker instanceof EntityPlayer) { + // CraftBukkit start - limit name length to 16 characters + if (((EntityHuman) this.tracker).name.length() > 16) { + ((EntityHuman) this.tracker).name = ((EntityHuman) this.tracker).name.substring(0, 16); + } + // CraftBukkit end + return new Packet20NamedEntitySpawn((EntityHuman) this.tracker); + } else { + if (this.tracker instanceof EntityMinecart) { + EntityMinecart entityminecart = (EntityMinecart) this.tracker; + + if (entityminecart.type == 0) { + return new Packet23VehicleSpawn(this.tracker, 10); + } + + if (entityminecart.type == 1) { + return new Packet23VehicleSpawn(this.tracker, 11); + } + + if (entityminecart.type == 2) { + return new Packet23VehicleSpawn(this.tracker, 12); + } + } + + if (this.tracker instanceof EntityBoat) { + return new Packet23VehicleSpawn(this.tracker, 1); + } else if (this.tracker instanceof IAnimal) { + return new Packet24MobSpawn((EntityLiving) this.tracker); + } else if (this.tracker instanceof EntityFish) { + return new Packet23VehicleSpawn(this.tracker, 90); + } else if (this.tracker instanceof EntityArrow) { + EntityLiving entityliving = ((EntityArrow) this.tracker).shooter; + + return new Packet23VehicleSpawn(this.tracker, 60, entityliving != null ? entityliving.id : this.tracker.id); + } else if (this.tracker instanceof EntitySnowball) { + return new Packet23VehicleSpawn(this.tracker, 61); + } else if (this.tracker instanceof EntityFireball) { + EntityFireball entityfireball = (EntityFireball) this.tracker; + // CraftBukkit start - added check for null shooter + int shooter = ((EntityFireball) this.tracker).shooter != null ? ((EntityFireball) this.tracker).shooter.id : 1; + Packet23VehicleSpawn packet23vehiclespawn = new Packet23VehicleSpawn(this.tracker, 63, shooter); + // CraftBukkit end + + packet23vehiclespawn.e = (int) (entityfireball.c * 8000.0D); + packet23vehiclespawn.f = (int) (entityfireball.d * 8000.0D); + packet23vehiclespawn.g = (int) (entityfireball.e * 8000.0D); + return packet23vehiclespawn; + } else if (this.tracker instanceof EntityEgg) { + return new Packet23VehicleSpawn(this.tracker, 62); + } else if (this.tracker instanceof EntityTNTPrimed) { + return new Packet23VehicleSpawn(this.tracker, 50); + } else { + if (this.tracker instanceof EntityFallingSand) { + EntityFallingSand entityfallingsand = (EntityFallingSand) this.tracker; + + if (entityfallingsand.a == Block.SAND.id) { + return new Packet23VehicleSpawn(this.tracker, 70); + } + + if (entityfallingsand.a == Block.GRAVEL.id) { + return new Packet23VehicleSpawn(this.tracker, 71); + } + } + + if (this.tracker instanceof EntityPainting) { + return new Packet25EntityPainting((EntityPainting) this.tracker); + } else { + throw new IllegalArgumentException("Don\'t know how to add " + this.tracker.getClass() + "!"); + } + } + } + } + + public void c(EntityPlayer entityplayer) { + if (this.trackedPlayers.contains(entityplayer)) { + this.trackedPlayers.remove(entityplayer); + entityplayer.removeQueue.add(Integer.valueOf(this.tracker.id)); // Poseidon + //entityplayer.netServerHandler.sendPacket(new Packet29DestroyEntity(this.tracker.id)); + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java new file mode 100644 index 0000000..53c001d --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityTypes.java @@ -0,0 +1,94 @@ +package net.minecraft.server; + +import java.util.HashMap; +import java.util.Map; + +public class EntityTypes { + + private static Map a = new HashMap(); + private static Map b = new HashMap(); + private static Map c = new HashMap(); + private static Map d = new HashMap(); + + public EntityTypes() {} + + private static void a(Class oclass, String s, int i) { + a.put(s, oclass); + b.put(oclass, s); + c.put(Integer.valueOf(i), oclass); + d.put(oclass, Integer.valueOf(i)); + } + + public static Entity a(String s, World world) { + Entity entity = null; + + try { + Class oclass = (Class) a.get(s); + + if (oclass != null) { + entity = (Entity) oclass.getConstructor(new Class[] { World.class}).newInstance(new Object[] { world}); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + + return entity; + } + + public static Entity a(NBTTagCompound nbttagcompound, World world) { + Entity entity = null; + + try { + Class oclass = (Class) a.get(nbttagcompound.getString("id")); + + if (oclass != null) { + entity = (Entity) oclass.getConstructor(new Class[] { World.class}).newInstance(new Object[] { world}); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + + if (entity != null) { + entity.e(nbttagcompound); + } else { + System.out.println("Skipping Entity with id " + nbttagcompound.getString("id")); + } + + return entity; + } + + public static int a(Entity entity) { + return ((Integer) d.get(entity.getClass())).intValue(); + } + + public static String b(Entity entity) { + return (String) b.get(entity.getClass()); + } + + static { + a(EntityArrow.class, "Arrow", 10); + a(EntitySnowball.class, "Snowball", 11); + a(EntityItem.class, "Item", 1); + a(EntityPainting.class, "Painting", 9); + a(EntityLiving.class, "Mob", 48); + a(EntityMonster.class, "Monster", 49); + a(EntityCreeper.class, "Creeper", 50); + a(EntitySkeleton.class, "Skeleton", 51); + a(EntitySpider.class, "Spider", 52); + a(EntityGiantZombie.class, "Giant", 53); + a(EntityZombie.class, "Zombie", 54); + a(EntitySlime.class, "Slime", 55); + a(EntityGhast.class, "Ghast", 56); + a(EntityPigZombie.class, "PigZombie", 57); + a(EntityPig.class, "Pig", 90); + a(EntitySheep.class, "Sheep", 91); + a(EntityCow.class, "Cow", 92); + a(EntityChicken.class, "Chicken", 93); + a(EntitySquid.class, "Squid", 94); + a(EntityWolf.class, "Wolf", 95); + a(EntityTNTPrimed.class, "PrimedTnt", 20); + a(EntityFallingSand.class, "FallingSand", 21); + a(EntityMinecart.class, "Minecart", 40); + a(EntityBoat.class, "Boat", 41); + } +} diff --git a/src/main/java/net/minecraft/server/EntityWaterAnimal.java b/src/main/java/net/minecraft/server/EntityWaterAnimal.java new file mode 100644 index 0000000..580238f --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityWaterAnimal.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +public class EntityWaterAnimal extends EntityCreature implements IAnimal { + + public EntityWaterAnimal(World world) { + super(world); + } + + public boolean b_() { + return true; + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + } + + public boolean d() { + return this.world.containsEntity(this.boundingBox); + } + + public int e() { + return 120; + } +} diff --git a/src/main/java/net/minecraft/server/EntityWeather.java b/src/main/java/net/minecraft/server/EntityWeather.java new file mode 100644 index 0000000..03ff54c --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityWeather.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +public abstract class EntityWeather extends Entity { + + public EntityWeather(World world) { + super(world); + } +} diff --git a/src/main/java/net/minecraft/server/EntityWeatherStorm.java b/src/main/java/net/minecraft/server/EntityWeatherStorm.java new file mode 100644 index 0000000..59db801 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityWeatherStorm.java @@ -0,0 +1,130 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; + +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityWeatherStorm extends EntityWeather { + + private int lifeTicks; + public long a = 0L; + private int c; + + // CraftBukkit start + private CraftWorld cworld; + public boolean isEffect = false; + + public EntityWeatherStorm(World world, double d0, double d1, double d2) { + this(world, d0, d1, d2, false); + } + + public EntityWeatherStorm(World world, double d0, double d1, double d2, boolean isEffect) { + // CraftBukkit end + + super(world); + + // CraftBukkit start + this.isEffect = isEffect; + this.cworld = world.getWorld(); + // CraftBukkit end + + this.setPositionRotation(d0, d1, d2, 0.0F, 0.0F); + this.lifeTicks = 2; + this.a = this.random.nextLong(); + this.c = this.random.nextInt(3) + 1; + // CraftBukkit + if (!isEffect && world.spawnMonsters >= 2 && world.areChunksLoaded(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2), 10)) { + int i = MathHelper.floor(d0); + int j = MathHelper.floor(d1); + int k = MathHelper.floor(d2); + + if (world.getTypeId(i, j, k) == 0 && Block.FIRE.canPlace(world, i, j, k)) { + // CraftBukkit start + BlockIgniteEvent event = new BlockIgniteEvent(this.cworld.getBlockAt(i, j, k), IgniteCause.LIGHTNING, null); + world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + world.setTypeId(i, j, k, Block.FIRE.id); + } + // CraftBukkit end + } + + for (i = 0; i < 4; ++i) { + j = MathHelper.floor(d0) + this.random.nextInt(3) - 1; + k = MathHelper.floor(d1) + this.random.nextInt(3) - 1; + int l = MathHelper.floor(d2) + this.random.nextInt(3) - 1; + + if (world.getTypeId(j, k, l) == 0 && Block.FIRE.canPlace(world, j, k, l)) { + // CraftBukkit start + BlockIgniteEvent event = new BlockIgniteEvent(this.cworld.getBlockAt(j, k, l), IgniteCause.LIGHTNING, null); + world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + world.setTypeId(j, k, l, Block.FIRE.id); + } + // CraftBukkit end + } + } + } + } + + public void m_() { + super.m_(); + if (this.lifeTicks == 2) { + this.world.makeSound(this.locX, this.locY, this.locZ, "ambient.weather.thunder", 10000.0F, 0.8F + this.random.nextFloat() * 0.2F); + this.world.makeSound(this.locX, this.locY, this.locZ, "random.explode", 2.0F, 0.5F + this.random.nextFloat() * 0.2F); + } + + --this.lifeTicks; + if (this.lifeTicks < 0) { + if (this.c == 0) { + this.die(); + } else if (this.lifeTicks < -this.random.nextInt(10)) { + --this.c; + this.lifeTicks = 1; + this.a = this.random.nextLong(); + // CraftBukkit + if (!this.isEffect && this.world.areChunksLoaded(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ), 10)) { + int i = MathHelper.floor(this.locX); + int j = MathHelper.floor(this.locY); + int k = MathHelper.floor(this.locZ); + + if (this.world.getTypeId(i, j, k) == 0 && Block.FIRE.canPlace(this.world, i, j, k)) { + // CraftBukkit start + BlockIgniteEvent event = new BlockIgniteEvent(this.cworld.getBlockAt(i, j, k), IgniteCause.LIGHTNING, null); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.world.setTypeId(i, j, k, Block.FIRE.id); + } + // CraftBukkit end + } + } + } + } + + if (this.lifeTicks >= 0 && !this.isEffect) { // CraftBukkit + double d0 = 3.0D; + List list = this.world.b((Entity) this, AxisAlignedBB.b(this.locX - d0, this.locY - d0, this.locZ - d0, this.locX + d0, this.locY + 6.0D + d0, this.locZ + d0)); + + for (int l = 0; l < list.size(); ++l) { + Entity entity = (Entity) list.get(l); + + entity.a(this); + } + + this.world.n = 2; + } + } + + protected void b() {} + + protected void a(NBTTagCompound nbttagcompound) {} + + protected void b(NBTTagCompound nbttagcompound) {} +} diff --git a/src/main/java/net/minecraft/server/EntityWolf.java b/src/main/java/net/minecraft/server/EntityWolf.java new file mode 100644 index 0000000..c3458b7 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityWolf.java @@ -0,0 +1,478 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.entity.EntityTargetEvent; + +import java.util.Iterator; +import java.util.List; + +// CraftBukkit start +// CraftBukkit end + +public class EntityWolf extends EntityAnimal { + + private boolean a = false; + private float b; + private float c; + private boolean f; + private boolean g; + private float h; + private float i; + + public EntityWolf(World world) { + super(world); + this.texture = "/mob/wolf.png"; + this.b(0.8F, 0.8F); + this.aE = 1.1F; + this.health = 8; + } + + protected void b() { + super.b(); + this.datawatcher.a(16, Byte.valueOf((byte) 0)); + this.datawatcher.a(17, ""); + this.datawatcher.a(18, new Integer(this.health)); + } + + protected boolean n() { + return false; + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("Angry", this.isAngry()); + nbttagcompound.a("Sitting", this.isSitting()); + if (this.getOwnerName() == null) { + nbttagcompound.setString("Owner", ""); + } else { + nbttagcompound.setString("Owner", this.getOwnerName()); + } + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.setAngry(nbttagcompound.m("Angry")); + this.setSitting(nbttagcompound.m("Sitting")); + String s = nbttagcompound.getString("Owner"); + + if (s.length() > 0) { + this.setOwnerName(s); + this.setTamed(true); + } + } + + protected boolean h_() { + return !this.isTamed(); + } + + protected String g() { + return this.isAngry() ? "mob.wolf.growl" : (this.random.nextInt(3) == 0 ? (this.isTamed() && this.datawatcher.b(18) < 10 ? "mob.wolf.whine" : "mob.wolf.panting") : "mob.wolf.bark"); + } + + protected String h() { + return "mob.wolf.hurt"; + } + + protected String i() { + return "mob.wolf.death"; + } + + protected float k() { + return 0.4F; + } + + protected int j() { + return -1; + } + + protected void c_() { + super.c_(); + if (!this.e && !this.C() && this.isTamed() && this.vehicle == null) { + EntityHuman entityhuman = this.world.a(this.getOwnerName()); + + if (entityhuman != null) { + float f = entityhuman.f(this); + + if (f > 5.0F) { + this.c(entityhuman, f); + } + } else if (!this.ad()) { + this.setSitting(true); + } + } else if (this.target == null && !this.C() && !this.isTamed() && this.world.random.nextInt(100) == 0) { + List list = this.world.a(EntitySheep.class, AxisAlignedBB.b(this.locX, this.locY, this.locZ, this.locX + 1.0D, this.locY + 1.0D, this.locZ + 1.0D).b(16.0D, 4.0D, 16.0D)); + + if (!list.isEmpty()) { + // CraftBukkit start + Entity entity = (Entity) list.get(this.world.random.nextInt(list.size())); + org.bukkit.entity.Entity bukkitTarget = entity == null ? null : entity.getBukkitEntity(); + + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), bukkitTarget, EntityTargetEvent.TargetReason.RANDOM_TARGET); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled() || event.getTarget() != null ) { + this.setTarget(entity); + } + // CraftBukkit end + } + } + + if (this.ad()) { + this.setSitting(false); + } + + if (!this.world.isStatic) { + this.datawatcher.watch(18, Integer.valueOf(this.health)); + } + } + + public void v() { + super.v(); + this.a = false; + if (this.V() && !this.C() && !this.isAngry()) { + Entity entity = this.W(); + + if (entity instanceof EntityHuman) { + EntityHuman entityhuman = (EntityHuman) entity; + ItemStack itemstack = entityhuman.inventory.getItemInHand(); + + if (itemstack != null) { + if (!this.isTamed() && itemstack.id == Item.BONE.id) { + this.a = true; + } else if (this.isTamed() && Item.byId[itemstack.id] instanceof ItemFood) { + this.a = ((ItemFood) Item.byId[itemstack.id]).l(); + } + } + } + } + + if (!this.Y && this.f && !this.g && !this.C() && this.onGround) { + this.g = true; + this.h = 0.0F; + this.i = 0.0F; + this.world.a(this, (byte) 8); + } + } + + public void m_() { + super.m_(); + this.c = this.b; + if (this.a) { + this.b += (1.0F - this.b) * 0.4F; + } else { + this.b += (0.0F - this.b) * 0.4F; + } + + if (this.a) { + this.aF = 10; + } + + if (this.ac()) { + this.f = true; + this.g = false; + this.h = 0.0F; + this.i = 0.0F; + } else if ((this.f || this.g) && this.g) { + if (this.h == 0.0F) { + this.world.makeSound(this, "mob.wolf.shake", this.k(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + } + + this.i = this.h; + this.h += 0.05F; + if (this.i >= 2.0F) { + this.f = false; + this.g = false; + this.i = 0.0F; + this.h = 0.0F; + } + + if (this.h > 0.4F) { + float f = (float) this.boundingBox.b; + int i = (int) (MathHelper.sin((this.h - 0.4F) * 3.1415927F) * 7.0F); + + for (int j = 0; j < i; ++j) { + float f1 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length * 0.5F; + float f2 = (this.random.nextFloat() * 2.0F - 1.0F) * this.length * 0.5F; + + this.world.a("splash", this.locX + (double) f1, (double) (f + 0.8F), this.locZ + (double) f2, this.motX, this.motY, this.motZ); + } + } + } + } + + public float t() { + return this.width * 0.8F; + } + + protected int u() { + return this.isSitting() ? 20 : super.u(); + } + + private void c(Entity entity, float f) { + PathEntity pathentity = this.world.findPath(this, entity, 16.0F); + + if (pathentity == null && f > 12.0F) { + int i = MathHelper.floor(entity.locX) - 2; + int j = MathHelper.floor(entity.locZ) - 2; + int k = MathHelper.floor(entity.boundingBox.b); + + for (int l = 0; l <= 4; ++l) { + for (int i1 = 0; i1 <= 4; ++i1) { + if ((l < 1 || i1 < 1 || l > 3 || i1 > 3) && this.world.e(i + l, k - 1, j + i1) && !this.world.e(i + l, k, j + i1) && !this.world.e(i + l, k + 1, j + i1)) { + this.setPositionRotation((double) ((float) (i + l) + 0.5F), (double) k, (double) ((float) (j + i1) + 0.5F), this.yaw, this.pitch); + return; + } + } + } + } else { + this.setPathEntity(pathentity); + } + } + + protected boolean w() { + return this.isSitting() || this.g; + } + + public boolean damageEntity(Entity entity, int i) { + this.setSitting(false); + if (entity != null && !(entity instanceof EntityHuman) && !(entity instanceof EntityArrow)) { + i = (i + 1) / 2; + } + + if (!super.damageEntity((Entity) entity, i)) { + return false; + } else { + if (!this.isTamed() && !this.isAngry()) { + if (entity instanceof EntityHuman) { + // CraftBukkit start + org.bukkit.entity.Entity bukkitTarget = entity == null ? null : entity.getBukkitEntity(); + + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), bukkitTarget, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + this.setAngry(true); + this.target = ((CraftEntity) event.getTarget()).getHandle(); + } + } + // CraftBukkit end + } + + if (entity instanceof EntityArrow && ((EntityArrow) entity).shooter != null) { + entity = ((EntityArrow) entity).shooter; + } + + if (entity instanceof EntityLiving) { + List list = this.world.a(EntityWolf.class, AxisAlignedBB.b(this.locX, this.locY, this.locZ, this.locX + 1.0D, this.locY + 1.0D, this.locZ + 1.0D).b(16.0D, 4.0D, 16.0D)); + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { + Entity entity1 = (Entity) iterator.next(); + EntityWolf entitywolf = (EntityWolf) entity1; + + if (!entitywolf.isTamed() && entitywolf.target == null) { + // CraftBukkit start + org.bukkit.entity.Entity bukkitTarget = entity == null ? null : entity.getBukkitEntity(); + + EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), bukkitTarget, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (event.getTarget() == null) { + this.target = null; + } else { + entitywolf.target = (Entity) entity; + if (entity instanceof EntityHuman) { + entitywolf.setAngry(true); + } + } + } + // CraftBukkit end + } + } + } + } else if (entity != this && entity != null) { + if (this.isTamed() && entity instanceof EntityHuman && ((EntityHuman) entity).name.equalsIgnoreCase(this.getOwnerName())) { + return true; + } + + this.target = (Entity) entity; + } + + return true; + } + } + + protected Entity findTarget() { + return this.isAngry() ? this.world.findNearbyPlayer(this, 16.0D) : null; + } + + protected void a(Entity entity, float f) { + if (f > 2.0F && f < 6.0F && this.random.nextInt(10) == 0) { + if (this.onGround) { + double d0 = entity.locX - this.locX; + double d1 = entity.locZ - this.locZ; + float f1 = MathHelper.a(d0 * d0 + d1 * d1); + + this.motX = d0 / (double) f1 * 0.5D * 0.800000011920929D + this.motX * 0.20000000298023224D; + this.motZ = d1 / (double) f1 * 0.5D * 0.800000011920929D + this.motZ * 0.20000000298023224D; + this.motY = 0.4000000059604645D; + } + } else if ((double) f < 1.5D && entity.boundingBox.e > this.boundingBox.b && entity.boundingBox.b < this.boundingBox.e) { + this.attackTicks = 20; + byte b0 = 2; + + if (this.isTamed()) { + b0 = 4; + } + // CraftBukkit start + org.bukkit.entity.Entity damager = this.getBukkitEntity(); + org.bukkit.entity.Entity damagee = entity == null ? null : entity.getBukkitEntity(); + + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(damager, damagee, EntityDamageEvent.DamageCause.ENTITY_ATTACK, b0); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end + + entity.damageEntity(this, b0); + } + } + + public boolean a(EntityHuman entityhuman) { + ItemStack itemstack = entityhuman.inventory.getItemInHand(); + + if (!this.isTamed()) { + if (itemstack != null && itemstack.id == Item.BONE.id && !this.isAngry()) { + --itemstack.count; + if (itemstack.count <= 0) { + entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, (ItemStack) null); + } + + if (!this.world.isStatic) { + // CraftBukkit - added event call and isCancelled check. + if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) { + // CraftBukkit end + this.setTamed(true); + this.setPathEntity((PathEntity) null); + this.setSitting(true); + this.health = 20; + this.setOwnerName(entityhuman.name); + this.a(true); + this.world.a(this, (byte) 7); + } else { + this.a(false); + this.world.a(this, (byte) 6); + } + } + + return true; + } + } else { + if (itemstack != null && Item.byId[itemstack.id] instanceof ItemFood) { + ItemFood itemfood = (ItemFood) Item.byId[itemstack.id]; + + if (itemfood.l() && this.datawatcher.b(18) < 20) { + --itemstack.count; + if (itemstack.count <= 0) { + entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, (ItemStack) null); + } + + this.b(((ItemFood) Item.PORK).k(), RegainReason.EATING); + return true; + } + } + + if (entityhuman.name.equalsIgnoreCase(this.getOwnerName())) { + if (!this.world.isStatic) { + this.setSitting(!this.isSitting()); + this.aC = false; + this.setPathEntity((PathEntity) null); + } + + return true; + } + } + + return false; + } + + void a(boolean flag) { + String s = "heart"; + + if (!flag) { + s = "smoke"; + } + + for (int i = 0; i < 7; ++i) { + double d0 = this.random.nextGaussian() * 0.02D; + double d1 = this.random.nextGaussian() * 0.02D; + double d2 = this.random.nextGaussian() * 0.02D; + + this.world.a(s, this.locX + (double) (this.random.nextFloat() * this.length * 2.0F) - (double) this.length, this.locY + 0.5D + (double) (this.random.nextFloat() * this.width), this.locZ + (double) (this.random.nextFloat() * this.length * 2.0F) - (double) this.length, d0, d1, d2); + } + } + + public int l() { + return 8; + } + + public String getOwnerName() { + return this.datawatcher.c(17); + } + + public void setOwnerName(String s) { + this.datawatcher.watch(17, s); + } + + public boolean isSitting() { + return (this.datawatcher.a(16) & 1) != 0; + } + + public void setSitting(boolean flag) { + byte b0 = this.datawatcher.a(16); + + if (flag) { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 | 1))); + } else { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 & -2))); + } + } + + public boolean isAngry() { + return (this.datawatcher.a(16) & 2) != 0; + } + + public void setAngry(boolean flag) { + byte b0 = this.datawatcher.a(16); + + if (flag) { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 | 2))); + } else { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 & -3))); + } + } + + public boolean isTamed() { + return (this.datawatcher.a(16) & 4) != 0; + } + + public void setTamed(boolean flag) { + byte b0 = this.datawatcher.a(16); + + if (flag) { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 | 4))); + } else { + this.datawatcher.watch(16, Byte.valueOf((byte) (b0 & -5))); + } + } +} diff --git a/src/main/java/net/minecraft/server/EntityZombie.java b/src/main/java/net/minecraft/server/EntityZombie.java new file mode 100644 index 0000000..ab4b721 --- /dev/null +++ b/src/main/java/net/minecraft/server/EntityZombie.java @@ -0,0 +1,48 @@ +package net.minecraft.server; + +import org.bukkit.event.entity.EntityCombustEvent; + +public class EntityZombie extends EntityMonster { + + public EntityZombie(World world) { + super(world); + this.texture = "/mob/zombie.png"; + this.aE = 0.5F; + this.damage = 5; + } + + public void v() { + if (this.world.d()) { + float f = this.c(1.0F); + + if (f > 0.5F && this.world.isChunkLoaded(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) { + // CraftBukkit start + EntityCombustEvent event = new EntityCombustEvent(this.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.fireTicks = 300; + } + // CraftBukkit end + } + } + + super.v(); + } + + protected String g() { + return "mob.zombie"; + } + + protected String h() { + return "mob.zombiehurt"; + } + + protected String i() { + return "mob.zombiedeath"; + } + + protected int j() { + return Item.FEATHER.id; + } +} diff --git a/src/main/java/net/minecraft/server/EnumArt.java b/src/main/java/net/minecraft/server/EnumArt.java new file mode 100644 index 0000000..7695136 --- /dev/null +++ b/src/main/java/net/minecraft/server/EnumArt.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +public enum EnumArt { + + KEBAB("Kebab", 0, "Kebab", 16, 16, 0, 0), AZTEC("Aztec", 1, "Aztec", 16, 16, 16, 0), ALBAN("Alban", 2, "Alban", 16, 16, 32, 0), AZTEC2("Aztec2", 3, "Aztec2", 16, 16, 48, 0), BOMB("Bomb", 4, "Bomb", 16, 16, 64, 0), PLANT("Plant", 5, "Plant", 16, 16, 80, 0), WASTELAND("Wasteland", 6, "Wasteland", 16, 16, 96, 0), POOL("Pool", 7, "Pool", 32, 16, 0, 32), COURBET("Courbet", 8, "Courbet", 32, 16, 32, 32), SEA("Sea", 9, "Sea", 32, 16, 64, 32), SUNSET("Sunset", 10, "Sunset", 32, 16, 96, 32), CREEBET("Creebet", 11, "Creebet", 32, 16, 128, 32), WANDERER("Wanderer", 12, "Wanderer", 16, 32, 0, 64), GRAHAM("Graham", 13, "Graham", 16, 32, 16, 64), MATCH("Match", 14, "Match", 32, 32, 0, 128), BUST("Bust", 15, "Bust", 32, 32, 32, 128), STAGE("Stage", 16, "Stage", 32, 32, 64, 128), VOID("Void", 17, "Void", 32, 32, 96, 128), SKULL_AND_ROSES("SkullAndRoses", 18, "SkullAndRoses", 32, 32, 128, 128), FIGHTERS("Fighters", 19, "Fighters", 64, 32, 0, 96), POINTER("Pointer", 20, "Pointer", 64, 64, 0, 192), PIGSCENE("Pigscene", 21, "Pigscene", 64, 64, 64, 192), BURNINGSKULL("BurningSkull", 22, "BurningSkull", 64, 64, 128, 192), SKELETON("Skeleton", 23, "Skeleton", 64, 48, 192, 64), DONKEYKONG("DonkeyKong", 24, "DonkeyKong", 64, 48, 192, 112); + public static final int z = "SkullAndRoses".length(); + public final String A; + public final int B; + public final int C; + public final int D; + public final int E; + + private static final EnumArt[] F = new EnumArt[] { KEBAB, AZTEC, ALBAN, AZTEC2, BOMB, PLANT, WASTELAND, POOL, COURBET, SEA, SUNSET, CREEBET, WANDERER, GRAHAM, MATCH, BUST, STAGE, VOID, SKULL_AND_ROSES, FIGHTERS, POINTER, PIGSCENE, BURNINGSKULL, SKELETON, DONKEYKONG}; + + private EnumArt(String s, int i, String s1, int j, int k, int l, int i1) { + this.A = s1; + this.B = j; + this.C = k; + this.D = l; + this.E = i1; + } +} diff --git a/src/main/java/net/minecraft/server/EnumBedError.java b/src/main/java/net/minecraft/server/EnumBedError.java new file mode 100644 index 0000000..337c262 --- /dev/null +++ b/src/main/java/net/minecraft/server/EnumBedError.java @@ -0,0 +1,10 @@ +package net.minecraft.server; + +public enum EnumBedError { + + OK("OK", 0), NOT_POSSIBLE_HERE("NOT_POSSIBLE_HERE", 1), NOT_POSSIBLE_NOW("NOT_POSSIBLE_NOW", 2), TOO_FAR_AWAY("TOO_FAR_AWAY", 3), OTHER_PROBLEM("OTHER_PROBLEM", 4); + + private static final EnumBedError[] f = new EnumBedError[] { OK, NOT_POSSIBLE_HERE, NOT_POSSIBLE_NOW, TOO_FAR_AWAY, OTHER_PROBLEM}; + + private EnumBedError(String s, int i) {} +} diff --git a/src/main/java/net/minecraft/server/EnumCreatureType.java b/src/main/java/net/minecraft/server/EnumCreatureType.java new file mode 100644 index 0000000..7e9baf6 --- /dev/null +++ b/src/main/java/net/minecraft/server/EnumCreatureType.java @@ -0,0 +1,37 @@ +package net.minecraft.server; + +public enum EnumCreatureType { + + MONSTER(IMonster.class, 70, Material.AIR, false), + CREATURE(EntityAnimal.class, 15, Material.AIR, true), + WATER_CREATURE(EntityWaterAnimal.class, 5, Material.WATER, true); + private final Class baseClass; + private final int maxCount; + private final Material spawnMaterial; + private final boolean isPeaceful; + + private static final EnumCreatureType[] h = new EnumCreatureType[]{MONSTER, CREATURE, WATER_CREATURE}; + + EnumCreatureType(Class baseClass, int maxCount, Material spawnMaterial, boolean isPeaceful) { + this.baseClass = baseClass; + this.maxCount = maxCount; + this.spawnMaterial = spawnMaterial; + this.isPeaceful = isPeaceful; + } + + public Class getBaseClass() { + return this.baseClass; + } + + public int getMaxCount() { + return this.maxCount; + } + + public Material getSpawnMaterial() { + return this.spawnMaterial; + } + + public boolean isPeaceful() { + return this.isPeaceful; + } +} diff --git a/src/main/java/net/minecraft/server/EnumMobType.java b/src/main/java/net/minecraft/server/EnumMobType.java new file mode 100644 index 0000000..b8da2b0 --- /dev/null +++ b/src/main/java/net/minecraft/server/EnumMobType.java @@ -0,0 +1,10 @@ +package net.minecraft.server; + +public enum EnumMobType { + + EVERYTHING("everything", 0), MOBS("mobs", 1), PLAYERS("players", 2); + + private static final EnumMobType[] d = new EnumMobType[] { EVERYTHING, MOBS, PLAYERS}; + + private EnumMobType(String s, int i) {} +} diff --git a/src/main/java/net/minecraft/server/EnumMovingObjectType.java b/src/main/java/net/minecraft/server/EnumMovingObjectType.java new file mode 100644 index 0000000..b08f28b --- /dev/null +++ b/src/main/java/net/minecraft/server/EnumMovingObjectType.java @@ -0,0 +1,10 @@ +package net.minecraft.server; + +public enum EnumMovingObjectType { + + TILE("TILE", 0), ENTITY("ENTITY", 1); + + private static final EnumMovingObjectType[] c = new EnumMovingObjectType[] { TILE, ENTITY}; + + private EnumMovingObjectType(String s, int i) {} +} diff --git a/src/main/java/net/minecraft/server/EnumSkyBlock.java b/src/main/java/net/minecraft/server/EnumSkyBlock.java new file mode 100644 index 0000000..d34a615 --- /dev/null +++ b/src/main/java/net/minecraft/server/EnumSkyBlock.java @@ -0,0 +1,13 @@ +package net.minecraft.server; + +public enum EnumSkyBlock { + + SKY("Sky", 0, 15), BLOCK("Block", 1, 0); + public final int c; + + private static final EnumSkyBlock[] d = new EnumSkyBlock[] { SKY, BLOCK}; + + private EnumSkyBlock(String s, int i, int j) { + this.c = j; + } +} diff --git a/src/main/java/net/minecraft/server/EnumToolMaterial.java b/src/main/java/net/minecraft/server/EnumToolMaterial.java new file mode 100644 index 0000000..80c3e1a --- /dev/null +++ b/src/main/java/net/minecraft/server/EnumToolMaterial.java @@ -0,0 +1,35 @@ +package net.minecraft.server; + +public enum EnumToolMaterial { + + WOOD("WOOD", 0, 0, 59, 2.0F, 0), STONE("STONE", 1, 1, 131, 4.0F, 1), IRON("IRON", 2, 2, 250, 6.0F, 2), DIAMOND("EMERALD", 3, 3, 1561, 8.0F, 3), GOLD("GOLD", 4, 0, 32, 12.0F, 0); + private final int f; + private final int g; + private final float h; + private final int i; + + private static final EnumToolMaterial[] j = new EnumToolMaterial[] { WOOD, STONE, IRON, DIAMOND, GOLD}; + + private EnumToolMaterial(String s, int i, int j, int k, float f, int l) { + this.f = j; + this.g = k; + this.h = f; + this.i = l; + } + + public int a() { + return this.g; + } + + public float b() { + return this.h; + } + + public int c() { + return this.i; + } + + public int d() { + return this.f; + } +} diff --git a/src/main/java/net/minecraft/server/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java new file mode 100644 index 0000000..6a541c0 --- /dev/null +++ b/src/main/java/net/minecraft/server/Explosion.java @@ -0,0 +1,365 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.Location; +import org.bukkit.event.entity.EntityDamageByBlockEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +// CraftBukkit start +// CraftBukkit end + +public class Explosion { + public boolean setFire = false; + private final Random random = new Random(); + private final World world; + public double posX; + public double posY; + public double posZ; + public Entity source; + public EntityDamageEvent.DamageCause customDamageCause = null; // Poseidon + public float size; + public Set blocks = new HashSet<>(); // UberBukkit: Set -> Set + + public boolean wasCanceled = false; // CraftBukkit + + public Explosion(World world, Entity entity, double d0, double d1, double d2, float f) { + this.world = world; + this.source = entity; + this.size = f; + this.posX = d0; + this.posY = d1; + this.posZ = d2; + } + + public void a() { + float f = this.size; + byte b0 = 16; + + int i; + int j; + int k; + double d0; + double d1; + double d2; + + for (i = 0; i < b0; ++i) { + for (j = 0; j < b0; ++j) { + for (k = 0; k < b0; ++k) { + if (i == 0 || i == b0 - 1 || j == 0 || j == b0 - 1 || k == 0 || k == b0 - 1) { + double d3 = ((float) i / ((float) b0 - 1.0F) * 2.0F - 1.0F); + double d4 = ((float) j / ((float) b0 - 1.0F) * 2.0F - 1.0F); + double d5 = ((float) k / ((float) b0 - 1.0F) * 2.0F - 1.0F); + double d6 = Math.sqrt(d3 * d3 + d4 * d4 + d5 * d5); + + d3 /= d6; + d4 /= d6; + d5 /= d6; + float f1 = this.size * (0.7F + this.world.random.nextFloat() * 0.6F); + + d0 = this.posX; + d1 = this.posY; + d2 = this.posZ; + + for (float f2 = 0.3F; f1 > 0.0F; f1 -= f2 * 0.75F) { + int l = MathHelper.floor(d0); + int i1 = MathHelper.floor(d1); + int j1 = MathHelper.floor(d2); + int k1 = this.world.getTypeId(l, i1, j1); + + if (k1 > 0) { + f1 -= (Block.byId[k1].a(this.source) + 0.3F) * f2; + } + + if (f1 > 0.0F) { + this.blocks.add(new ChunkPosition(l, i1, j1)); + } + + d0 += d3 * (double) f2; + d1 += d4 * (double) f2; + d2 += d5 * (double) f2; + } + } + } + } + } + + this.size *= 2.0F; + i = MathHelper.floor(this.posX - (double) this.size - 1.0D); + j = MathHelper.floor(this.posX + (double) this.size + 1.0D); + k = MathHelper.floor(this.posY - (double) this.size - 1.0D); + int l1 = MathHelper.floor(this.posY + (double) this.size + 1.0D); + int i2 = MathHelper.floor(this.posZ - (double) this.size - 1.0D); + int j2 = MathHelper.floor(this.posZ + (double) this.size + 1.0D); + List list = this.world.b(this.source, AxisAlignedBB.b(i, k, i2, j, l1, j2)); + Vec3D vec3d = Vec3D.create(this.posX, this.posY, this.posZ); + + /* + * Whether explosions should be optimized or not + * A backport from PaperMC + * Config option: + * optimizedExplosions: false + */ + boolean optimizeExplosions = (boolean) PoseidonConfig.getInstance().getProperty("world-settings.optimized-explosions"); + boolean sendMotion = (boolean) PoseidonConfig.getInstance().getProperty("world-settings.send-explosion-velocity"); + + for (int k2 = 0; k2 < list.size(); ++k2) { + Entity entity = (Entity) list.get(k2); + double d7 = entity.f(this.posX, this.posY, this.posZ) / (double) this.size; + + if (d7 <= 1.0D) { + d0 = entity.locX - this.posX; + d1 = entity.locY - this.posY; + d2 = entity.locZ - this.posZ; + double d8 = MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + + d0 /= d8; + d1 /= d8; + d2 /= d8; + double d9; + if (optimizeExplosions) { + d9 = this.getBlockDensity(vec3d, entity); // Paper - Optimize explosions + } else { + d9 = this.world.a(vec3d, entity.boundingBox); + } + double d10 = (1.0D - d7) * d9; + + // CraftBukkit start - explosion damage hook + org.bukkit.Server server = this.world.getServer(); + org.bukkit.entity.Entity damagee = (entity == null) ? null : entity.getBukkitEntity(); + int damageDone = (int) ((d10 * d10 + d10) / 2.0D * 8.0D * (double) this.size + 1.0D); + + // Block explosion, damagee is not null + if (damagee != null && (this.source == null || this.source instanceof EntityTNTPrimed)) { + // This event gets fired by tnt, exploding beds, and explosions created by plugins + // TODO: get the x/y/z of the tnt block? + EntityDamageByBlockEvent event = getEntityDamageByBlockEvent(damagee, damageDone); + server.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + entity.damageEntity(this.source, event.getDamage()); + entity.motX += d0 * d10; + entity.motY += d1 * d10; + entity.motZ += d2 * d10; + if (sendMotion) { // Poseidon: fix explosion velocity + entity.velocityChanged = true; + } + } + } else { + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(this.source.getBukkitEntity(), damagee, EntityDamageEvent.DamageCause.ENTITY_EXPLOSION, damageDone); + server.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + entity.damageEntity(this.source, event.getDamage()); + entity.motX += d0 * d10; + entity.motY += d1 * d10; + entity.motZ += d2 * d10; + if (sendMotion) { // Poseidon: fix explosion velocity + entity.velocityChanged = true; + } + } + } + // CraftBukkit end + } + } + + this.size = f; + + ArrayList arraylist = new ArrayList<>(); + arraylist.addAll(this.blocks); + + if (this.setFire) { + for (int l2 = arraylist.size() - 1; l2 >= 0; --l2) { + ChunkPosition chunkposition = arraylist.get(l2); + int i3 = chunkposition.x; + int j3 = chunkposition.y; + int k3 = chunkposition.z; + int l3 = this.world.getTypeId(i3, j3, k3); + int i4 = this.world.getTypeId(i3, j3 - 1, k3); + + if (l3 == 0 && Block.o[i4] && this.random.nextInt(3) == 0) { + this.world.setTypeId(i3, j3, k3, Block.FIRE.id); + } + } + } + } + + @NotNull + private EntityDamageByBlockEvent getEntityDamageByBlockEvent(org.bukkit.entity.Entity damagee, int damageDone) { + EntityDamageByBlockEvent event; + if (this.customDamageCause != null) { + event = new EntityDamageByBlockEvent(null, damagee, this.customDamageCause, damageDone); + } else if (this.source instanceof EntityTNTPrimed) { + event = new EntityDamageByBlockEvent(null, damagee, EntityDamageEvent.DamageCause.TNT_EXPLOSION, damageDone); + } else { + event = new EntityDamageByBlockEvent(null, damagee, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION, damageDone); + } + return event; + } + + public void a(boolean flag) { + this.world.makeSound(this.posX, this.posY, this.posZ, "random.explode", 4.0F, (1.0F + (this.world.random.nextFloat() - this.world.random.nextFloat()) * 0.2F) * 0.7F); + + ArrayList blocksCopy = new ArrayList<>(this.blocks); + + // CraftBukkit start + org.bukkit.World bworld = this.world.getWorld(); + org.bukkit.entity.Entity explode = this.source == null ? null : this.source.getBukkitEntity(); + Location location = new Location(bworld, this.posX, this.posY, this.posZ); + + List blockList = new ArrayList<>(); + for (int j = blocksCopy.size() - 1; j >= 0; j--) { + ChunkPosition cpos = blocksCopy.get(j); + // UberBukkit - No need to handle blocks that aren't in the world's boundaries + if (cpos.y > 127 || cpos.y < 0) { + blocksCopy.remove(j); + continue; + } + + org.bukkit.block.Block block = bworld.getBlockAt(cpos.x, cpos.y, cpos.z); + if (block.getType() != org.bukkit.Material.AIR) { + blockList.add(block); + } + } + + EntityExplodeEvent event = new EntityExplodeEvent(explode, location, blockList); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + this.wasCanceled = true; + return; + } + + // Project Poseidon Start + // Backport from newer CraftBukkit + blocksCopy.clear(); + this.blocks.clear(); + for (final org.bukkit.block.Block block2 : event.blockList()) { + final ChunkPosition coords = new ChunkPosition(block2.getX(), block2.getY(), block2.getZ()); + blocksCopy.add(coords); + this.blocks.add(coords); + } + // Project Poseidon End + // CraftBukkit end + + for (int i = blocksCopy.size() - 1; i >= 0; --i) { + ChunkPosition chunkposition = blocksCopy.get(i); + int j = chunkposition.x; + int k = chunkposition.y; + int l = chunkposition.z; + int i1 = this.world.getTypeId(j, k, l); + + if (flag) { + double d0 = (float) j + this.world.random.nextFloat(); + double d1 = (float) k + this.world.random.nextFloat(); + double d2 = (float) l + this.world.random.nextFloat(); + double d3 = d0 - this.posX; + double d4 = d1 - this.posY; + double d5 = d2 - this.posZ; + double d6 = MathHelper.a(d3 * d3 + d4 * d4 + d5 * d5); + + d3 /= d6; + d4 /= d6; + d5 /= d6; + double d7 = 0.5D / (d6 / (double) this.size + 0.1D); + + d7 *= this.world.random.nextFloat() * this.world.random.nextFloat() + 0.3F; + d3 *= d7; + d4 *= d7; + d5 *= d7; + this.world.a("explode", (d0 + this.posX) / 2.0D, (d1 + this.posY) / 2.0D, (d2 + this.posZ) / 2.0D, d3, d4, d5); + this.world.a("smoke", d0, d1, d2, d3, d4, d5); + } + + // CraftBukkit - stop explosions from putting out fire + if (i1 > 0 && i1 != Block.FIRE.id) { + // CraftBukkit + Block.byId[i1].dropNaturally(this.world, j, k, l, this.world.getData(j, k, l), event.getYield()); + this.world.setTypeId(j, k, l, 0); + Block.byId[i1].d(this.world, j, k, l); + } + } + } + + // Paper start - Optimize explosions + private float getBlockDensity(Vec3D vec3d, Entity entity) { + CacheKey key = new CacheKey(this, entity.boundingBox); + Float blockDensity = this.world.explosionDensityCache.get(key); + if (blockDensity == null) { + blockDensity = this.world.a(vec3d, entity.boundingBox); + this.world.explosionDensityCache.put(key, blockDensity); + } + + return blockDensity; + } + + static class CacheKey { + private final World world; + private final double posX, posY, posZ; + private final double minX, minY, minZ; + private final double maxX, maxY, maxZ; + + public CacheKey(Explosion explosion, AxisAlignedBB aabb) { + this.world = explosion.world; + this.posX = explosion.posX; + this.posY = explosion.posY; + this.posZ = explosion.posZ; + this.minX = aabb.a; + this.minY = aabb.b; + this.minZ = aabb.c; + this.maxX = aabb.d; + this.maxY = aabb.e; + this.maxZ = aabb.f; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CacheKey cacheKey = (CacheKey) o; + + if (Double.compare(cacheKey.posX, posX) != 0) return false; + if (Double.compare(cacheKey.posY, posY) != 0) return false; + if (Double.compare(cacheKey.posZ, posZ) != 0) return false; + if (Double.compare(cacheKey.minX, minX) != 0) return false; + if (Double.compare(cacheKey.minY, minY) != 0) return false; + if (Double.compare(cacheKey.minZ, minZ) != 0) return false; + if (Double.compare(cacheKey.maxX, maxX) != 0) return false; + if (Double.compare(cacheKey.maxY, maxY) != 0) return false; + if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false; + return world.equals(cacheKey.world); + } + + @Override + public int hashCode() { + int result; + long temp; + result = world.hashCode(); + temp = Double.doubleToLongBits(posX); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(posY); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(posZ); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(minX); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(minY); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(minZ); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxX); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxY); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxZ); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + } + // Paper end +} diff --git a/src/main/java/net/minecraft/server/FontAllowedCharacters.java b/src/main/java/net/minecraft/server/FontAllowedCharacters.java new file mode 100644 index 0000000..9407954 --- /dev/null +++ b/src/main/java/net/minecraft/server/FontAllowedCharacters.java @@ -0,0 +1,33 @@ +package net.minecraft.server; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +public class FontAllowedCharacters { + + public static final String allowedCharacters = a(); + public static final char[] b = new char[] { '/', '\n', '\r', '\t', '\u0000', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':'}; + + public FontAllowedCharacters() {} + + private static String a() { + String s = ""; + + try { + BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(FontAllowedCharacters.class.getResourceAsStream("/font.txt"), "UTF-8")); + String s1 = ""; + + while ((s1 = bufferedreader.readLine()) != null) { + if (!s1.startsWith("#")) { + s = s + s1; + } + } + + bufferedreader.close(); + } catch (Exception exception) { + ; + } + + return s; + } +} diff --git a/src/main/java/net/minecraft/server/FurnaceRecipes.java b/src/main/java/net/minecraft/server/FurnaceRecipes.java new file mode 100644 index 0000000..fc65aff --- /dev/null +++ b/src/main/java/net/minecraft/server/FurnaceRecipes.java @@ -0,0 +1,39 @@ +package net.minecraft.server; + +import java.util.HashMap; +import java.util.Map; + +public class FurnaceRecipes { + + private static final FurnaceRecipes a = new FurnaceRecipes(); + private Map b = new HashMap(); + + public static final FurnaceRecipes getInstance() { + return a; + } + + private FurnaceRecipes() { + this.registerRecipe(Block.IRON_ORE.id, new ItemStack(Item.IRON_INGOT)); + this.registerRecipe(Block.GOLD_ORE.id, new ItemStack(Item.GOLD_INGOT)); + this.registerRecipe(Block.DIAMOND_ORE.id, new ItemStack(Item.DIAMOND)); + this.registerRecipe(Block.SAND.id, new ItemStack(Block.GLASS)); + this.registerRecipe(Item.PORK.id, new ItemStack(Item.GRILLED_PORK)); + this.registerRecipe(Item.RAW_FISH.id, new ItemStack(Item.COOKED_FISH)); + this.registerRecipe(Block.COBBLESTONE.id, new ItemStack(Block.STONE)); + this.registerRecipe(Item.CLAY_BALL.id, new ItemStack(Item.CLAY_BRICK)); + this.registerRecipe(Block.CACTUS.id, new ItemStack(Item.INK_SACK, 1, 2)); + this.registerRecipe(Block.LOG.id, new ItemStack(Item.COAL, 1, 1)); + } + + public void registerRecipe(int i, ItemStack itemstack) { + this.b.put(Integer.valueOf(i), itemstack); + } + + public ItemStack a(int i) { + return (ItemStack) this.b.get(Integer.valueOf(i)); + } + + public Map b() { + return this.b; + } +} diff --git a/src/main/java/net/minecraft/server/GuiLogFormatter.java b/src/main/java/net/minecraft/server/GuiLogFormatter.java new file mode 100644 index 0000000..6805b42 --- /dev/null +++ b/src/main/java/net/minecraft/server/GuiLogFormatter.java @@ -0,0 +1,50 @@ +package net.minecraft.server; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.logging.Formatter; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +class GuiLogFormatter extends Formatter { + + final GuiLogOutputHandler a; + + GuiLogFormatter(GuiLogOutputHandler guilogoutputhandler) { + this.a = guilogoutputhandler; + } + + public String format(LogRecord logrecord) { + StringBuilder stringbuilder = new StringBuilder(); + Level level = logrecord.getLevel(); + + if (level == Level.FINEST) { + stringbuilder.append("[FINEST] "); + } else if (level == Level.FINER) { + stringbuilder.append("[FINER] "); + } else if (level == Level.FINE) { + stringbuilder.append("[FINE] "); + } else if (level == Level.INFO) { + stringbuilder.append("[INFO] "); + } else if (level == Level.WARNING) { + stringbuilder.append("[WARNING] "); + } else if (level == Level.SEVERE) { + stringbuilder.append("[SEVERE] "); + } else if (level == Level.SEVERE) { + stringbuilder.append("[" + level.getLocalizedName() + "] "); + } + + stringbuilder.append(logrecord.getMessage()); + stringbuilder.append('\n'); + Throwable throwable = logrecord.getThrown(); + + if (throwable != null) { + StringWriter stringwriter = new StringWriter(); + + throwable.printStackTrace(new PrintWriter(stringwriter)); + stringbuilder.append(stringwriter.toString()); + } + + return stringbuilder.toString(); + } +} diff --git a/src/main/java/net/minecraft/server/GuiLogOutputHandler.java b/src/main/java/net/minecraft/server/GuiLogOutputHandler.java new file mode 100644 index 0000000..537aca6 --- /dev/null +++ b/src/main/java/net/minecraft/server/GuiLogOutputHandler.java @@ -0,0 +1,38 @@ +package net.minecraft.server; + +import javax.swing.*; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +public class GuiLogOutputHandler extends Handler { + + private int[] b = new int[1024]; + private int c = 0; + Formatter a = new GuiLogFormatter(this); + private JTextArea d; + + public GuiLogOutputHandler(JTextArea jtextarea) { + this.setFormatter(this.a); + this.d = jtextarea; + } + + public void close() {} + + public void flush() {} + + public void publish(LogRecord logrecord) { + int i = this.d.getDocument().getLength(); + + this.d.append(this.a.format(logrecord)); + this.d.setCaretPosition(this.d.getDocument().getLength()); + int j = this.d.getDocument().getLength() - i; + + if (this.b[this.c] != 0) { + this.d.replaceRange("", 0, this.b[this.c]); + } + + this.b[this.c] = j; + this.c = (this.c + 1) % 1024; + } +} diff --git a/src/main/java/net/minecraft/server/GuiStatsComponent.java b/src/main/java/net/minecraft/server/GuiStatsComponent.java new file mode 100644 index 0000000..c676931 --- /dev/null +++ b/src/main/java/net/minecraft/server/GuiStatsComponent.java @@ -0,0 +1,57 @@ +package net.minecraft.server; + +import javax.swing.*; +import java.awt.*; + +public class GuiStatsComponent extends JComponent { + + private int[] a = new int[256]; + private int b = 0; + private String[] c = new String[10]; + + public GuiStatsComponent() { + this.setPreferredSize(new Dimension(256, 196)); + this.setMinimumSize(new Dimension(256, 196)); + this.setMaximumSize(new Dimension(256, 196)); + (new Timer(500, new GuiStatsListener(this))).start(); + this.setBackground(Color.BLACK); + } + + private void a() { + long i = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); + + System.gc(); + this.c[0] = "Memory use: " + i / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)"; + this.c[1] = "Threads: " + NetworkManager.b + " + " + NetworkManager.c; + this.a[this.b++ & 255] = (int) (i * 100L / Runtime.getRuntime().maxMemory()); + this.repaint(); + } + + public void paint(Graphics graphics) { + graphics.setColor(new Color(16777215)); + graphics.fillRect(0, 0, 256, 192); + + int i; + + for (i = 0; i < 256; ++i) { + int j = this.a[i + this.b & 255]; + + graphics.setColor(new Color(j + 28 << 16)); + graphics.fillRect(i, 100 - j, 1, j); + } + + graphics.setColor(Color.BLACK); + + for (i = 0; i < this.c.length; ++i) { + String s = this.c[i]; + + if (s != null) { + graphics.drawString(s, 32, 116 + i * 16); + } + } + } + + static void a(GuiStatsComponent guistatscomponent) { + guistatscomponent.a(); + } +} diff --git a/src/main/java/net/minecraft/server/GuiStatsListener.java b/src/main/java/net/minecraft/server/GuiStatsListener.java new file mode 100644 index 0000000..c3eae6b --- /dev/null +++ b/src/main/java/net/minecraft/server/GuiStatsListener.java @@ -0,0 +1,17 @@ +package net.minecraft.server; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +class GuiStatsListener implements ActionListener { + + final GuiStatsComponent a; + + GuiStatsListener(GuiStatsComponent guistatscomponent) { + this.a = guistatscomponent; + } + + public void actionPerformed(ActionEvent actionevent) { + GuiStatsComponent.a(this.a); + } +} diff --git a/src/main/java/net/minecraft/server/IAnimal.java b/src/main/java/net/minecraft/server/IAnimal.java new file mode 100644 index 0000000..78d3914 --- /dev/null +++ b/src/main/java/net/minecraft/server/IAnimal.java @@ -0,0 +1,3 @@ +package net.minecraft.server; + +public interface IAnimal {} diff --git a/src/main/java/net/minecraft/server/IBlockAccess.java b/src/main/java/net/minecraft/server/IBlockAccess.java new file mode 100644 index 0000000..9f9073c --- /dev/null +++ b/src/main/java/net/minecraft/server/IBlockAccess.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public interface IBlockAccess { + + int getTypeId(int i, int j, int k); + + TileEntity getTileEntity(int i, int j, int k); + + int getData(int i, int j, int k); + + Material getMaterial(int i, int j, int k); + + boolean e(int i, int j, int k); +} diff --git a/src/main/java/net/minecraft/server/IChunkLoader.java b/src/main/java/net/minecraft/server/IChunkLoader.java new file mode 100644 index 0000000..e614f3c --- /dev/null +++ b/src/main/java/net/minecraft/server/IChunkLoader.java @@ -0,0 +1,16 @@ +package net.minecraft.server; + +import java.io.IOException; + +public interface IChunkLoader { + + Chunk a(World world, int i, int j) throws IOException; + + void a(World world, Chunk chunk); + + void b(World world, Chunk chunk); + + void a(); + + void b(); +} diff --git a/src/main/java/net/minecraft/server/IChunkProvider.java b/src/main/java/net/minecraft/server/IChunkProvider.java new file mode 100644 index 0000000..fe28025 --- /dev/null +++ b/src/main/java/net/minecraft/server/IChunkProvider.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +public interface IChunkProvider { + + boolean isChunkLoaded(int i, int j); + + Chunk getOrCreateChunk(int i, int j); + + Chunk getChunkAt(int i, int j); + + void getChunkAt(IChunkProvider ichunkprovider, int i, int j); + + boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate); + + boolean unloadChunks(); + + boolean canSave(); +} diff --git a/src/main/java/net/minecraft/server/ICommandListener.java b/src/main/java/net/minecraft/server/ICommandListener.java new file mode 100644 index 0000000..b119c58 --- /dev/null +++ b/src/main/java/net/minecraft/server/ICommandListener.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +public interface ICommandListener { + + void sendMessage(String s); + + String getName(); +} diff --git a/src/main/java/net/minecraft/server/ICrafting.java b/src/main/java/net/minecraft/server/ICrafting.java new file mode 100644 index 0000000..d361a7c --- /dev/null +++ b/src/main/java/net/minecraft/server/ICrafting.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +import java.util.List; + +public interface ICrafting { + + void a(Container container, List list); + + void a(Container container, int i, ItemStack itemstack); + + void a(Container container, int i, int j); +} diff --git a/src/main/java/net/minecraft/server/IDataManager.java b/src/main/java/net/minecraft/server/IDataManager.java new file mode 100644 index 0000000..8fe975c --- /dev/null +++ b/src/main/java/net/minecraft/server/IDataManager.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +import java.io.File; +import java.util.List; +import java.util.UUID; + +public interface IDataManager { + + WorldData c(); + + void b(); + + IChunkLoader a(WorldProvider worldprovider); + + void a(WorldData worlddata, List list); + + void a(WorldData worlddata); + + PlayerFileData d(); + + void e(); + + File b(String s); + + UUID getUUID(); // CraftBukkit +} diff --git a/src/main/java/net/minecraft/server/IInventory.java b/src/main/java/net/minecraft/server/IInventory.java new file mode 100644 index 0000000..67fc692 --- /dev/null +++ b/src/main/java/net/minecraft/server/IInventory.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +public interface IInventory { + + int getSize(); + + ItemStack getItem(int i); + + ItemStack splitStack(int i, int j); + + void setItem(int i, ItemStack itemstack); + + String getName(); + + int getMaxStackSize(); + + void update(); + + boolean a_(EntityHuman entityhuman); + + ItemStack[] getContents(); // CraftBukkit +} diff --git a/src/main/java/net/minecraft/server/IMonster.java b/src/main/java/net/minecraft/server/IMonster.java new file mode 100644 index 0000000..0891c78 --- /dev/null +++ b/src/main/java/net/minecraft/server/IMonster.java @@ -0,0 +1,3 @@ +package net.minecraft.server; + +public interface IMonster extends IAnimal {} diff --git a/src/main/java/net/minecraft/server/IProgressUpdate.java b/src/main/java/net/minecraft/server/IProgressUpdate.java new file mode 100644 index 0000000..e2765e3 --- /dev/null +++ b/src/main/java/net/minecraft/server/IProgressUpdate.java @@ -0,0 +1,10 @@ +package net.minecraft.server; + +public interface IProgressUpdate { + + void a(String s); + + void b(String s); + + void a(int i); +} diff --git a/src/main/java/net/minecraft/server/IUpdatePlayerListBox.java b/src/main/java/net/minecraft/server/IUpdatePlayerListBox.java new file mode 100644 index 0000000..c62e6f2 --- /dev/null +++ b/src/main/java/net/minecraft/server/IUpdatePlayerListBox.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +public interface IUpdatePlayerListBox { + + void a(); +} diff --git a/src/main/java/net/minecraft/server/IWorldAccess.java b/src/main/java/net/minecraft/server/IWorldAccess.java new file mode 100644 index 0000000..1c236fd --- /dev/null +++ b/src/main/java/net/minecraft/server/IWorldAccess.java @@ -0,0 +1,24 @@ +package net.minecraft.server; + +public interface IWorldAccess { + + void a(int i, int j, int k); + + void a(int i, int j, int k, int l, int i1, int j1); + + void a(String s, double d0, double d1, double d2, float f, float f1); + + void a(String s, double d0, double d1, double d2, double d3, double d4, double d5); + + void a(Entity entity); + + void b(Entity entity); + + void a(); + + void a(String s, int i, int j, int k); + + void a(int i, int j, int k, TileEntity tileentity); + + void a(EntityHuman entityhuman, int i, int j, int k, int l, int i1); +} diff --git a/src/main/java/net/minecraft/server/InventoryCraftResult.java b/src/main/java/net/minecraft/server/InventoryCraftResult.java new file mode 100644 index 0000000..2d0964f --- /dev/null +++ b/src/main/java/net/minecraft/server/InventoryCraftResult.java @@ -0,0 +1,51 @@ +package net.minecraft.server; + +public class InventoryCraftResult implements IInventory { + + private ItemStack[] items = new ItemStack[1]; + + // CraftBukkit start + public ItemStack[] getContents() { + return this.items; + } + // CraftBukkit end + + public InventoryCraftResult() {} + + public int getSize() { + return 1; + } + + public ItemStack getItem(int i) { + return this.items[i]; + } + + public String getName() { + return "Result"; + } + + public ItemStack splitStack(int i, int j) { + if (this.items[i] != null) { + ItemStack itemstack = this.items[i]; + + this.items[i] = null; + return itemstack; + } else { + return null; + } + } + + public void setItem(int i, ItemStack itemstack) { + this.items[i] = itemstack; + } + + public int getMaxStackSize() { + return 64; + } + + public void update() {} + + public boolean a_(EntityHuman entityhuman) { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/InventoryCrafting.java b/src/main/java/net/minecraft/server/InventoryCrafting.java new file mode 100644 index 0000000..9151b8b --- /dev/null +++ b/src/main/java/net/minecraft/server/InventoryCrafting.java @@ -0,0 +1,82 @@ +package net.minecraft.server; + +public class InventoryCrafting implements IInventory { + + private ItemStack[] items; + private int b; + private Container c; + + // CraftBukkit start + public ItemStack[] getContents() { + return this.items; + } + // CraftBukkit end + + public InventoryCrafting(Container container, int i, int j) { + int k = i * j; + + this.items = new ItemStack[k]; + this.c = container; + this.b = i; + } + + public int getSize() { + return this.items.length; + } + + public ItemStack getItem(int i) { + return i >= this.getSize() ? null : this.items[i]; + } + + public ItemStack b(int i, int j) { + if (i >= 0 && i < this.b) { + int k = i + j * this.b; + + return this.getItem(k); + } else { + return null; + } + } + + public String getName() { + return "Crafting"; + } + + public ItemStack splitStack(int i, int j) { + if (this.items[i] != null) { + ItemStack itemstack; + + if (this.items[i].count <= j) { + itemstack = this.items[i]; + this.items[i] = null; + this.c.a((IInventory) this); + return itemstack; + } else { + itemstack = this.items[i].a(j); + if (this.items[i].count == 0) { + this.items[i] = null; + } + + this.c.a((IInventory) this); + return itemstack; + } + } else { + return null; + } + } + + public void setItem(int i, ItemStack itemstack) { + this.items[i] = itemstack; + this.c.a((IInventory) this); + } + + public int getMaxStackSize() { + return 64; + } + + public void update() {} + + public boolean a_(EntityHuman entityhuman) { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/InventoryLargeChest.java b/src/main/java/net/minecraft/server/InventoryLargeChest.java new file mode 100644 index 0000000..15dcdd8 --- /dev/null +++ b/src/main/java/net/minecraft/server/InventoryLargeChest.java @@ -0,0 +1,61 @@ +package net.minecraft.server; + +public class InventoryLargeChest implements IInventory { + + private String a; + private IInventory b; + private IInventory c; + + // CraftBukkit start + public ItemStack[] getContents() { + ItemStack[] result = new ItemStack[this.getSize()]; + for (int i = 0; i < result.length; i++) { + result[i] = this.getItem(i); + } + return result; + } + // CraftBukkit end + + public InventoryLargeChest(String s, IInventory iinventory, IInventory iinventory1) { + this.a = s; + this.b = iinventory; + this.c = iinventory1; + } + + public int getSize() { + return this.b.getSize() + this.c.getSize(); + } + + public String getName() { + return this.a; + } + + public ItemStack getItem(int i) { + return i >= this.b.getSize() ? this.c.getItem(i - this.b.getSize()) : this.b.getItem(i); + } + + public ItemStack splitStack(int i, int j) { + return i >= this.b.getSize() ? this.c.splitStack(i - this.b.getSize(), j) : this.b.splitStack(i, j); + } + + public void setItem(int i, ItemStack itemstack) { + if (i >= this.b.getSize()) { + this.c.setItem(i - this.b.getSize(), itemstack); + } else { + this.b.setItem(i, itemstack); + } + } + + public int getMaxStackSize() { + return this.b.getMaxStackSize(); + } + + public void update() { + this.b.update(); + this.c.update(); + } + + public boolean a_(EntityHuman entityhuman) { + return this.b.a_(entityhuman) && this.c.a_(entityhuman); + } +} diff --git a/src/main/java/net/minecraft/server/InventoryPlayer.java b/src/main/java/net/minecraft/server/InventoryPlayer.java new file mode 100644 index 0000000..f25e699 --- /dev/null +++ b/src/main/java/net/minecraft/server/InventoryPlayer.java @@ -0,0 +1,386 @@ +package net.minecraft.server; + +public class InventoryPlayer implements IInventory { + + public ItemStack[] items = new ItemStack[36]; + public ItemStack[] armor = new ItemStack[4]; + public int itemInHandIndex = 0; + public EntityHuman d; // CraftBukkit - private -> public + private ItemStack f; + public boolean e = false; + + // CraftBukkit start + public ItemStack[] getContents() { + return this.items; + } + + public ItemStack[] getArmorContents() { + return this.armor; + } + // CraftBukkit end + + public InventoryPlayer(EntityHuman entityhuman) { + this.d = entityhuman; + } + + public ItemStack getItemInHand() { + return this.itemInHandIndex < 9 && this.itemInHandIndex >= 0 ? this.items[this.itemInHandIndex] : null; + } + + public static int e() { + return 9; + } + + private int d(int i) { + for (int j = 0; j < this.items.length; ++j) { + if (this.items[j] != null && this.items[j].id == i) { + return j; + } + } + + return -1; + } + + private int firstPartial(ItemStack itemstack) { + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] != null && this.items[i].id == itemstack.id && this.items[i].isStackable() && this.items[i].count < this.items[i].getMaxStackSize() && this.items[i].count < this.getMaxStackSize() && (!this.items[i].usesData() || this.items[i].getData() == itemstack.getData())) { + return i; + } + } + + return -1; + } + + // CraftBukkit start - watch method above! :D + public int canHold(ItemStack itemstack) { + int remains = itemstack.count; + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] == null) return itemstack.count; + + // Taken from firstPartial(ItemStack) + if (this.items[i] != null && this.items[i].id == itemstack.id && this.items[i].isStackable() && this.items[i].count < this.items[i].getMaxStackSize() && this.items[i].count < this.getMaxStackSize() && (!this.items[i].usesData() || this.items[i].getData() == itemstack.getData())) { + remains -= (this.items[i].getMaxStackSize() < this.getMaxStackSize() ? this.items[i].getMaxStackSize() : this.getMaxStackSize()) - this.items[i].count; + } + if (remains <= 0) return itemstack.count; + } + return itemstack.count - remains; + } + // CraftBukkit end + + private int k() { + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] == null) { + return i; + } + } + + return -1; + } + + private int e(ItemStack itemstack) { + int i = itemstack.id; + int j = itemstack.count; + int k = this.firstPartial(itemstack); + + if (k < 0) { + k = this.k(); + } + + if (k < 0) { + return j; + } else { + if (this.items[k] == null) { + this.items[k] = new ItemStack(i, 0, itemstack.getData()); + } + + int l = j; + + if (j > this.items[k].getMaxStackSize() - this.items[k].count) { + l = this.items[k].getMaxStackSize() - this.items[k].count; + } + + if (l > this.getMaxStackSize() - this.items[k].count) { + l = this.getMaxStackSize() - this.items[k].count; + } + + if (l == 0) { + return j; + } else { + j -= l; + this.items[k].count += l; + this.items[k].b = 5; + return j; + } + } + } + + public void f() { + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] != null) { + this.items[i].a(this.d.world, this.d, i, this.itemInHandIndex == i); + } + } + } + + public boolean b(int i) { + int j = this.d(i); + + if (j < 0) { + return false; + } else { + if (--this.items[j].count <= 0) { + this.items[j] = null; + } + + return true; + } + } + + public boolean pickup(ItemStack itemstack) { + int i; + + if (itemstack.f()) { + i = this.k(); + if (i >= 0) { + this.items[i] = ItemStack.b(itemstack); + this.items[i].b = 5; + itemstack.count = 0; + return true; + } else { + return false; + } + } else { + do { + i = itemstack.count; + itemstack.count = this.e(itemstack); + } while (itemstack.count > 0 && itemstack.count < i); + + return itemstack.count < i; + } + } + + public ItemStack splitStack(int i, int j) { + ItemStack[] aitemstack = this.items; + + if (i >= this.items.length) { + aitemstack = this.armor; + i -= this.items.length; + } + + if (aitemstack[i] != null) { + ItemStack itemstack; + + if (aitemstack[i].count <= j) { + itemstack = aitemstack[i]; + aitemstack[i] = null; + return itemstack; + } else { + itemstack = aitemstack[i].a(j); + if (aitemstack[i].count == 0) { + aitemstack[i] = null; + } + + return itemstack; + } + } else { + return null; + } + } + + public void setItem(int i, ItemStack itemstack) { + ItemStack[] aitemstack = this.items; + + if (i >= aitemstack.length) { + i -= aitemstack.length; + aitemstack = this.armor; + } + + aitemstack[i] = itemstack; + } + + public float a(Block block) { + float f = 1.0F; + + if (this.items[this.itemInHandIndex] != null) { + f *= this.items[this.itemInHandIndex].a(block); + } + + return f; + } + + public NBTTagList a(NBTTagList nbttaglist) { + int i; + NBTTagCompound nbttagcompound; + + for (i = 0; i < this.items.length; ++i) { + if (this.items[i] != null) { + nbttagcompound = new NBTTagCompound(); + nbttagcompound.a("Slot", (byte) i); + this.items[i].a(nbttagcompound); + nbttaglist.a((NBTBase) nbttagcompound); + } + } + + for (i = 0; i < this.armor.length; ++i) { + if (this.armor[i] != null) { + nbttagcompound = new NBTTagCompound(); + nbttagcompound.a("Slot", (byte) (i + 100)); + this.armor[i].a(nbttagcompound); + nbttaglist.a((NBTBase) nbttagcompound); + } + } + + return nbttaglist; + } + + public void b(NBTTagList nbttaglist) { + this.items = new ItemStack[36]; + this.armor = new ItemStack[4]; + + for (int i = 0; i < nbttaglist.c(); ++i) { + NBTTagCompound nbttagcompound = (NBTTagCompound) nbttaglist.a(i); + int j = nbttagcompound.c("Slot") & 255; + ItemStack itemstack = new ItemStack(nbttagcompound); + + if (itemstack.getItem() != null) { + if (j >= 0 && j < this.items.length) { + this.items[j] = itemstack; + } + + if (j >= 100 && j < this.armor.length + 100) { + this.armor[j - 100] = itemstack; + } + } + } + } + + public int getSize() { + return this.items.length + 4; + } + + public ItemStack getItem(int i) { + ItemStack[] aitemstack = this.items; + + if (i >= aitemstack.length) { + i -= aitemstack.length; + aitemstack = this.armor; + } + + return aitemstack[i]; + } + + public String getName() { + return "Inventory"; + } + + public int getMaxStackSize() { + return 64; + } + + public int a(Entity entity) { + ItemStack itemstack = this.getItem(this.itemInHandIndex); + + return itemstack != null ? itemstack.a(entity) : 1; + } + + public boolean b(Block block) { + if (block.material.i()) { + return true; + } else { + ItemStack itemstack = this.getItem(this.itemInHandIndex); + + return itemstack != null ? itemstack.b(block) : false; + } + } + + public int g() { + int i = 0; + int j = 0; + int k = 0; + + for (int l = 0; l < this.armor.length; ++l) { + if (this.armor[l] != null && this.armor[l].getItem() instanceof ItemArmor) { + int i1 = this.armor[l].i(); + int j1 = this.armor[l].g(); + int k1 = i1 - j1; + + j += k1; + k += i1; + int l1 = ((ItemArmor) this.armor[l].getItem()).bl; + + i += l1; + } + } + + if (k == 0) { + return 0; + } else { + return (i - 1) * j / k + 1; + } + } + + public void c(int i) { + for (int j = 0; j < this.armor.length; ++j) { + if (this.armor[j] != null && this.armor[j].getItem() instanceof ItemArmor) { + this.armor[j].damage(i, this.d); + if (this.armor[j].count == 0) { + this.armor[j].a(this.d); + this.armor[j] = null; + } + } + } + } + + public void h() { + int i; + + for (i = 0; i < this.items.length; ++i) { + if (this.items[i] != null) { + this.d.a(this.items[i], true); + this.items[i] = null; + } + } + + for (i = 0; i < this.armor.length; ++i) { + if (this.armor[i] != null) { + this.d.a(this.armor[i], true); + this.armor[i] = null; + } + } + } + + public void update() { + this.e = true; + } + + public void b(ItemStack itemstack) { + this.f = itemstack; + this.d.a(itemstack); + } + + public ItemStack j() { + return this.f; + } + + public boolean a_(EntityHuman entityhuman) { + return this.d.dead ? false : entityhuman.g(this.d) <= 64.0D; + } + + public boolean c(ItemStack itemstack) { + int i; + + for (i = 0; i < this.armor.length; ++i) { + if (this.armor[i] != null && this.armor[i].c(itemstack)) { + return true; + } + } + + for (i = 0; i < this.items.length; ++i) { + if (this.items[i] != null && this.items[i].c(itemstack)) { + return true; + } + } + + return false; + } +} diff --git a/src/main/java/net/minecraft/server/Item.java b/src/main/java/net/minecraft/server/Item.java new file mode 100644 index 0000000..b67fe18 --- /dev/null +++ b/src/main/java/net/minecraft/server/Item.java @@ -0,0 +1,254 @@ +package net.minecraft.server; + +import java.util.Random; + +public class Item { + + protected static Random b = new Random(); + public static Item[] byId = new Item[32000]; + public static Item IRON_SPADE = (new ItemSpade(0, EnumToolMaterial.IRON)).a(2, 5).a("shovelIron"); + public static Item IRON_PICKAXE = (new ItemPickaxe(1, EnumToolMaterial.IRON)).a(2, 6).a("pickaxeIron"); + public static Item IRON_AXE = (new ItemAxe(2, EnumToolMaterial.IRON)).a(2, 7).a("hatchetIron"); + public static Item FLINT_AND_STEEL = (new ItemFlintAndSteel(3)).a(5, 0).a("flintAndSteel"); + public static Item APPLE = (new ItemFood(4, 4, false)).a(10, 0).a("apple"); + public static Item BOW = (new ItemBow(5)).a(5, 1).a("bow"); + public static Item ARROW = (new Item(6)).a(5, 2).a("arrow"); + public static Item COAL = (new ItemCoal(7)).a(7, 0).a("coal"); + public static Item DIAMOND = (new Item(8)).a(7, 3).a("emerald"); + public static Item IRON_INGOT = (new Item(9)).a(7, 1).a("ingotIron"); + public static Item GOLD_INGOT = (new Item(10)).a(7, 2).a("ingotGold"); + public static Item IRON_SWORD = (new ItemSword(11, EnumToolMaterial.IRON)).a(2, 4).a("swordIron"); + public static Item WOOD_SWORD = (new ItemSword(12, EnumToolMaterial.WOOD)).a(0, 4).a("swordWood"); + public static Item WOOD_SPADE = (new ItemSpade(13, EnumToolMaterial.WOOD)).a(0, 5).a("shovelWood"); + public static Item WOOD_PICKAXE = (new ItemPickaxe(14, EnumToolMaterial.WOOD)).a(0, 6).a("pickaxeWood"); + public static Item WOOD_AXE = (new ItemAxe(15, EnumToolMaterial.WOOD)).a(0, 7).a("hatchetWood"); + public static Item STONE_SWORD = (new ItemSword(16, EnumToolMaterial.STONE)).a(1, 4).a("swordStone"); + public static Item STONE_SPADE = (new ItemSpade(17, EnumToolMaterial.STONE)).a(1, 5).a("shovelStone"); + public static Item STONE_PICKAXE = (new ItemPickaxe(18, EnumToolMaterial.STONE)).a(1, 6).a("pickaxeStone"); + public static Item STONE_AXE = (new ItemAxe(19, EnumToolMaterial.STONE)).a(1, 7).a("hatchetStone"); + public static Item DIAMOND_SWORD = (new ItemSword(20, EnumToolMaterial.DIAMOND)).a(3, 4).a("swordDiamond"); + public static Item DIAMOND_SPADE = (new ItemSpade(21, EnumToolMaterial.DIAMOND)).a(3, 5).a("shovelDiamond"); + public static Item DIAMOND_PICKAXE = (new ItemPickaxe(22, EnumToolMaterial.DIAMOND)).a(3, 6).a("pickaxeDiamond"); + public static Item DIAMOND_AXE = (new ItemAxe(23, EnumToolMaterial.DIAMOND)).a(3, 7).a("hatchetDiamond"); + public static Item STICK = (new Item(24)).a(5, 3).g().a("stick"); + public static Item BOWL = (new Item(25)).a(7, 4).a("bowl"); + public static Item MUSHROOM_SOUP = (new ItemSoup(26, 10)).a(8, 4).a("mushroomStew"); + public static Item GOLD_SWORD = (new ItemSword(27, EnumToolMaterial.GOLD)).a(4, 4).a("swordGold"); + public static Item GOLD_SPADE = (new ItemSpade(28, EnumToolMaterial.GOLD)).a(4, 5).a("shovelGold"); + public static Item GOLD_PICKAXE = (new ItemPickaxe(29, EnumToolMaterial.GOLD)).a(4, 6).a("pickaxeGold"); + public static Item GOLD_AXE = (new ItemAxe(30, EnumToolMaterial.GOLD)).a(4, 7).a("hatchetGold"); + public static Item STRING = (new Item(31)).a(8, 0).a("string"); + public static Item FEATHER = (new Item(32)).a(8, 1).a("feather"); + public static Item SULPHUR = (new Item(33)).a(8, 2).a("sulphur"); + public static Item WOOD_HOE = (new ItemHoe(34, EnumToolMaterial.WOOD)).a(0, 8).a("hoeWood"); + public static Item STONE_HOE = (new ItemHoe(35, EnumToolMaterial.STONE)).a(1, 8).a("hoeStone"); + public static Item IRON_HOE = (new ItemHoe(36, EnumToolMaterial.IRON)).a(2, 8).a("hoeIron"); + public static Item DIAMOND_HOE = (new ItemHoe(37, EnumToolMaterial.DIAMOND)).a(3, 8).a("hoeDiamond"); + public static Item GOLD_HOE = (new ItemHoe(38, EnumToolMaterial.GOLD)).a(4, 8).a("hoeGold"); + public static Item SEEDS = (new ItemSeeds(39, Block.CROPS.id)).a(9, 0).a("seeds"); + public static Item WHEAT = (new Item(40)).a(9, 1).a("wheat"); + public static Item BREAD = (new ItemFood(41, 5, false)).a(9, 2).a("bread"); + public static Item LEATHER_HELMET = (new ItemArmor(42, 0, 0, 0)).a(0, 0).a("helmetCloth"); + public static Item LEATHER_CHESTPLATE = (new ItemArmor(43, 0, 0, 1)).a(0, 1).a("chestplateCloth"); + public static Item LEATHER_LEGGINGS = (new ItemArmor(44, 0, 0, 2)).a(0, 2).a("leggingsCloth"); + public static Item LEATHER_BOOTS = (new ItemArmor(45, 0, 0, 3)).a(0, 3).a("bootsCloth"); + public static Item CHAINMAIL_HELMET = (new ItemArmor(46, 1, 1, 0)).a(1, 0).a("helmetChain"); + public static Item CHAINMAIL_CHESTPLATE = (new ItemArmor(47, 1, 1, 1)).a(1, 1).a("chestplateChain"); + public static Item CHAINMAIL_LEGGINGS = (new ItemArmor(48, 1, 1, 2)).a(1, 2).a("leggingsChain"); + public static Item CHAINMAIL_BOOTS = (new ItemArmor(49, 1, 1, 3)).a(1, 3).a("bootsChain"); + public static Item IRON_HELMET = (new ItemArmor(50, 2, 2, 0)).a(2, 0).a("helmetIron"); + public static Item IRON_CHESTPLATE = (new ItemArmor(51, 2, 2, 1)).a(2, 1).a("chestplateIron"); + public static Item IRON_LEGGINGS = (new ItemArmor(52, 2, 2, 2)).a(2, 2).a("leggingsIron"); + public static Item IRON_BOOTS = (new ItemArmor(53, 2, 2, 3)).a(2, 3).a("bootsIron"); + public static Item DIAMOND_HELMET = (new ItemArmor(54, 3, 3, 0)).a(3, 0).a("helmetDiamond"); + public static Item DIAMOND_CHESTPLATE = (new ItemArmor(55, 3, 3, 1)).a(3, 1).a("chestplateDiamond"); + public static Item DIAMOND_LEGGINGS = (new ItemArmor(56, 3, 3, 2)).a(3, 2).a("leggingsDiamond"); + public static Item DIAMOND_BOOTS = (new ItemArmor(57, 3, 3, 3)).a(3, 3).a("bootsDiamond"); + public static Item GOLD_HELMET = (new ItemArmor(58, 1, 4, 0)).a(4, 0).a("helmetGold"); + public static Item GOLD_CHESTPLATE = (new ItemArmor(59, 1, 4, 1)).a(4, 1).a("chestplateGold"); + public static Item GOLD_LEGGINGS = (new ItemArmor(60, 1, 4, 2)).a(4, 2).a("leggingsGold"); + public static Item GOLD_BOOTS = (new ItemArmor(61, 1, 4, 3)).a(4, 3).a("bootsGold"); + public static Item FLINT = (new Item(62)).a(6, 0).a("flint"); + public static Item PORK = (new ItemFood(63, 3, true)).a(7, 5).a("porkchopRaw"); + public static Item GRILLED_PORK = (new ItemFood(64, 8, true)).a(8, 5).a("porkchopCooked"); + public static Item PAINTING = (new ItemPainting(65)).a(10, 1).a("painting"); + public static Item GOLDEN_APPLE = (new ItemFood(66, 42, false)).a(11, 0).a("appleGold"); + public static Item SIGN = (new ItemSign(67)).a(10, 2).a("sign"); + public static Item WOOD_DOOR = (new ItemDoor(68, Material.WOOD)).a(11, 2).a("doorWood"); + public static Item BUCKET = (new ItemBucket(69, 0)).a(10, 4).a("bucket"); + public static Item WATER_BUCKET = (new ItemBucket(70, Block.WATER.id)).a(11, 4).a("bucketWater").a(BUCKET); + public static Item LAVA_BUCKET = (new ItemBucket(71, Block.LAVA.id)).a(12, 4).a("bucketLava").a(BUCKET); + public static Item MINECART = (new ItemMinecart(72, 0)).a(7, 8).a("minecart"); + public static Item SADDLE = (new ItemSaddle(73)).a(8, 6).a("saddle"); + public static Item IRON_DOOR = (new ItemDoor(74, Material.ORE)).a(12, 2).a("doorIron"); + public static Item REDSTONE = (new ItemRedstone(75)).a(8, 3).a("redstone"); + public static Item SNOW_BALL = (new ItemSnowball(76)).a(14, 0).a("snowball"); + public static Item BOAT = (new ItemBoat(77)).a(8, 8).a("boat"); + public static Item LEATHER = (new Item(78)).a(7, 6).a("leather"); + public static Item MILK_BUCKET = (new ItemBucket(79, -1)).a(13, 4).a("milk").a(BUCKET); + public static Item CLAY_BRICK = (new Item(80)).a(6, 1).a("brick"); + public static Item CLAY_BALL = (new Item(81)).a(9, 3).a("clay"); + public static Item SUGAR_CANE = (new ItemReed(82, Block.SUGAR_CANE_BLOCK)).a(11, 1).a("reeds"); + public static Item PAPER = (new Item(83)).a(10, 3).a("paper"); + public static Item BOOK = (new Item(84)).a(11, 3).a("book"); + public static Item SLIME_BALL = (new Item(85)).a(14, 1).a("slimeball"); + public static Item STORAGE_MINECART = (new ItemMinecart(86, 1)).a(7, 9).a("minecartChest"); + public static Item POWERED_MINECART = (new ItemMinecart(87, 2)).a(7, 10).a("minecartFurnace"); + public static Item EGG = (new ItemEgg(88)).a(12, 0).a("egg"); + public static Item COMPASS = (new Item(89)).a(6, 3).a("compass"); + public static Item FISHING_ROD = (new ItemFishingRod(90)).a(5, 4).a("fishingRod"); + public static Item WATCH = (new Item(91)).a(6, 4).a("clock"); + public static Item GLOWSTONE_DUST = (new Item(92)).a(9, 4).a("yellowDust"); + public static Item RAW_FISH = (new ItemFood(93, 2, false)).a(9, 5).a("fishRaw"); + public static Item COOKED_FISH = (new ItemFood(94, 5, false)).a(10, 5).a("fishCooked"); + public static Item INK_SACK = (new ItemDye(95)).a(14, 4).a("dyePowder"); + public static Item BONE = (new Item(96)).a(12, 1).a("bone").g(); + public static Item SUGAR = (new Item(97)).a(13, 0).a("sugar").g(); + public static Item CAKE = (new ItemReed(98, Block.CAKE_BLOCK)).c(1).a(13, 1).a("cake"); + public static Item BED = (new ItemBed(99)).c(1).a(13, 2).a("bed"); + public static Item DIODE = (new ItemReed(100, Block.DIODE_OFF)).a(6, 5).a("diode"); + public static Item COOKIE = (new ItemCookie(101, 1, false, 8)).a(12, 5).a("cookie"); + public static ItemWorldMap MAP = (ItemWorldMap) (new ItemWorldMap(102)).a(12, 3).a("map"); + public static ItemShears SHEARS = (ItemShears) (new ItemShears(103)).a(13, 5).a("shears"); + public static Item GOLD_RECORD = (new ItemRecord(2000, "13")).a(0, 15).a("record"); + public static Item GREEN_RECORD = (new ItemRecord(2001, "cat")).a(1, 15).a("record"); + public final int id; + protected int maxStackSize = 64; + private int durability = 0; + protected int textureId; + protected boolean bi = false; + protected boolean bj = false; + private Item craftingResult = null; + private String name; + + protected Item(int i) { + this.id = 256 + i; + if (byId[256 + i] != null) { + System.out.println("CONFLICT @ " + i); + } + + byId[256 + i] = this; + } + + public Item b(int i) { + this.textureId = i; + return this; + } + + public Item c(int i) { + this.maxStackSize = i; + return this; + } + + public Item a(int i, int j) { + this.textureId = i + j * 16; + return this; + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + return false; + } + + public float a(ItemStack itemstack, Block block) { + return 1.0F; + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + return itemstack; + } + + public int getMaxStackSize() { + return this.maxStackSize; + } + + public int filterData(int i) { + return 0; + } + + public boolean d() { + return this.bj; + } + + protected Item a(boolean flag) { + this.bj = flag; + return this; + } + + public int e() { + return this.durability; + } + + protected Item d(int i) { + this.durability = i; + return this; + } + + public boolean f() { + return this.durability > 0 && !this.bj; + } + + public boolean a(ItemStack itemstack, EntityLiving entityliving, EntityLiving entityliving1) { + return false; + } + + public boolean a(ItemStack itemstack, int i, int j, int k, int l, EntityLiving entityliving) { + return false; + } + + public int a(Entity entity) { + return 1; + } + + public boolean a(Block block) { + return false; + } + + public void a(ItemStack itemstack, EntityLiving entityliving) {} + + public Item g() { + this.bi = true; + return this; + } + + public Item a(String s) { + this.name = "item." + s; + return this; + } + + public String a() { + return this.name; + } + + public Item a(Item item) { + if (this.maxStackSize > 1) { + throw new IllegalArgumentException("Max stack size must be 1 for items with crafting results"); + } else { + this.craftingResult = item; + return this; + } + } + + public Item h() { + return this.craftingResult; + } + + public boolean i() { + return this.craftingResult != null; + } + + public String j() { + return StatisticCollector.a(this.a() + ".name"); + } + + public void a(ItemStack itemstack, World world, Entity entity, int i, boolean flag) {} + + public void c(ItemStack itemstack, World world, EntityHuman entityhuman) {} + + public boolean b() { + return false; + } + + static { + StatisticList.c(); + } +} diff --git a/src/main/java/net/minecraft/server/ItemArmor.java b/src/main/java/net/minecraft/server/ItemArmor.java new file mode 100644 index 0000000..b88dfc5 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemArmor.java @@ -0,0 +1,21 @@ +package net.minecraft.server; + +public class ItemArmor extends Item { + + private static final int[] bn = new int[] { 3, 8, 6, 3}; + private static final int[] bo = new int[] { 11, 16, 15, 13}; + public final int a; + public final int bk; + public final int bl; + public final int bm; + + public ItemArmor(int i, int j, int k, int l) { + super(i); + this.a = j; + this.bk = l; + this.bm = k; + this.bl = bn[l]; + this.d(bo[l] * 3 << j); + this.maxStackSize = 1; + } +} diff --git a/src/main/java/net/minecraft/server/ItemAxe.java b/src/main/java/net/minecraft/server/ItemAxe.java new file mode 100644 index 0000000..72b8627 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemAxe.java @@ -0,0 +1,10 @@ +package net.minecraft.server; + +public class ItemAxe extends ItemTool { + + private static Block[] bk = new Block[] { Block.WOOD, Block.BOOKSHELF, Block.LOG, Block.CHEST}; + + protected ItemAxe(int i, EnumToolMaterial enumtoolmaterial) { + super(i, 3, enumtoolmaterial, bk); + } +} diff --git a/src/main/java/net/minecraft/server/ItemBed.java b/src/main/java/net/minecraft/server/ItemBed.java new file mode 100644 index 0000000..5d19b7d --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemBed.java @@ -0,0 +1,65 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemBed extends Item { + + public ItemBed(int i) { + super(i); + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + if (l != 1) { + return false; + } else { + int clickedX = i, clickedY = j, clickedZ = k; // CraftBukkit + + ++j; + BlockBed blockbed = (BlockBed) Block.BED; + int i1 = MathHelper.floor((double) (entityhuman.yaw * 4.0F / 360.0F) + 0.5D) & 3; + byte b0 = 0; + byte b1 = 0; + + if (i1 == 0) { + b1 = 1; + } + + if (i1 == 1) { + b0 = -1; + } + + if (i1 == 2) { + b1 = -1; + } + + if (i1 == 3) { + b0 = 1; + } + + if (world.isEmpty(i, j, k) && world.isEmpty(i + b0, j, k + b1) && world.e(i, j - 1, k) && world.e(i + b0, j - 1, k + b1)) { + CraftBlockState blockState = CraftBlockState.getBlockState(world, i, j, k); // CraftBukkit + + world.setTypeIdAndData(i, j, k, blockbed.id, i1); + + // CraftBukkit start - bed + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, clickedX, clickedY, clickedZ, blockbed); + + if (event.isCancelled() || !event.canBuild()) { + event.getBlockPlaced().setTypeIdAndData(blockState.getTypeId(), blockState.getRawData(), false); + return false; + } + // CraftBukkit end + + world.setTypeIdAndData(i + b0, j, k + b1, blockbed.id, i1 + 8); + --itemstack.count; + return true; + } else { + return false; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemBlock.java b/src/main/java/net/minecraft/server/ItemBlock.java new file mode 100644 index 0000000..b627746 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemBlock.java @@ -0,0 +1,130 @@ +package net.minecraft.server; + +// CraftBukkit start +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemBlock extends Item { + + private int id; + + public ItemBlock(int i) { + super(i); + this.id = i + 256; + this.b(Block.byId[i + 256].a(2)); + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + int clickedX = i, clickedY = j, clickedZ = k; // CraftBukkit + + if (world.getTypeId(i, j, k) == Block.SNOW.id) { + l = 0; + } else { + if (l == 0) { + --j; + } + + if (l == 1) { + ++j; + } + + if (l == 2) { + --k; + } + + if (l == 3) { + ++k; + } + + if (l == 4) { + --i; + } + + if (l == 5) { + ++i; + } + } + + if (itemstack.count == 0) { + return false; + } else if (j == 127 && Block.byId[this.id].material.isBuildable()) { + return false; + } else if (world.a(this.id, i, j, k, false, l)) { + Block block = Block.byId[this.id]; + + // CraftBukkit start - This executes the placement of the block + CraftBlockState replacedBlockState = CraftBlockState.getBlockState(world, i, j, k); + + // There are like 30 combinations you can mix and match steps and double steps + // of different materials, so there are a lot of different cases of what + // would happen if you place x step onto another y step, so let's just keep + // track of the entire state + CraftBlockState blockStateBelow = null; + // Toggles whether the normal or the block below is used for the place event + boolean eventUseBlockBelow = false; + if ((world.getTypeId(i, j - 1, k) == Block.STEP.id || world.getTypeId(i, j - 1, k) == Block.DOUBLE_STEP.id) + && (itemstack.id == Block.DOUBLE_STEP.id || itemstack.id == Block.STEP.id)) { + blockStateBelow = CraftBlockState.getBlockState(world, i, j - 1, k); + // Step is placed on step, forms a doublestep replacing the original step, so we need the lower block + eventUseBlockBelow = itemstack.id == Block.STEP.id && blockStateBelow.getTypeId() == Block.STEP.id; + } + + /** + * @see net.minecraft.server.World#setTypeIdAndData(int i, int j, int k, int l, int i1) + * + * This replaces world.setTypeIdAndData(IIIII), we're doing this because we need to + * hook between the 'placement' and the informing to 'world' so we can + * sanely undo this. + * + * Whenever the call to 'world.setTypeIdAndData' changes we need to figure out again what to + * replace this with. + */ + if (world.setRawTypeIdAndData(i, j, k, this.id, this.filterData(itemstack.getData()))) { // <-- world.setTypeIdAndData does this to place the block + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, eventUseBlockBelow ? blockStateBelow : replacedBlockState, clickedX, clickedY, clickedZ, block); + + if (event.isCancelled() || !event.canBuild()) { + if (blockStateBelow != null) { // Used for steps + world.setTypeIdAndData(i, j, k, replacedBlockState.getTypeId(), replacedBlockState.getRawData()); + world.setTypeIdAndData(i, j - 1, k, blockStateBelow.getTypeId(), blockStateBelow.getRawData()); + + } else { + + if (this.id == Block.ICE.id) { + // Ice will explode if we set straight to 0 + world.setTypeId(i, j, k, 20); + } + + world.setTypeIdAndData(i, j, k, replacedBlockState.getTypeId(), replacedBlockState.getRawData()); + } + return true; + + } + // CraftBukkit end + + if (PoseidonConfig.getInstance().getConfigBoolean("world.settings.pistons.other-fixes.enabled", true) && (this.id == 29 || this.id == 33)) { + Block.byId[this.id].postPlace(world, i, j, k, l); + Block.byId[this.id].postPlace(world, i, j, k, entityhuman); + world.update(i, j, k, this.id); // <-- world.setTypeIdAndData does this on success (tell the world) + } else { + world.update(i, j, k, this.id); + Block.byId[this.id].postPlace(world, i, j, k, l); + Block.byId[this.id].postPlace(world, i, j, k, entityhuman); + } + + world.makeSound((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), block.stepSound.getName(), (block.stepSound.getVolume1() + 1.0F) / 2.0F, block.stepSound.getVolume2() * 0.8F); + --itemstack.count; + } + + return true; + } else { + return false; + } + } + + public String a() { + return Block.byId[this.id].l(); + } +} diff --git a/src/main/java/net/minecraft/server/ItemBoat.java b/src/main/java/net/minecraft/server/ItemBoat.java new file mode 100644 index 0000000..b84d665 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemBoat.java @@ -0,0 +1,64 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +// CraftBukkit end + +public class ItemBoat extends Item { + + public ItemBoat(int i) { + super(i); + this.maxStackSize = 1; + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + float f = 1.0F; + float f1 = entityhuman.lastPitch + (entityhuman.pitch - entityhuman.lastPitch) * f; + float f2 = entityhuman.lastYaw + (entityhuman.yaw - entityhuman.lastYaw) * f; + double d0 = entityhuman.lastX + (entityhuman.locX - entityhuman.lastX) * (double) f; + double d1 = entityhuman.lastY + (entityhuman.locY - entityhuman.lastY) * (double) f + 1.62D - (double) entityhuman.height; + double d2 = entityhuman.lastZ + (entityhuman.locZ - entityhuman.lastZ) * (double) f; + Vec3D vec3d = Vec3D.create(d0, d1, d2); + float f3 = MathHelper.cos(-f2 * 0.017453292F - 3.1415927F); + float f4 = MathHelper.sin(-f2 * 0.017453292F - 3.1415927F); + float f5 = -MathHelper.cos(-f1 * 0.017453292F); + float f6 = MathHelper.sin(-f1 * 0.017453292F); + float f7 = f4 * f5; + float f8 = f3 * f5; + double d3 = 5.0D; + Vec3D vec3d1 = vec3d.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3); + MovingObjectPosition movingobjectposition = world.rayTrace(vec3d, vec3d1, true); + + if (movingobjectposition == null) { + return itemstack; + } else { + if (movingobjectposition.type == EnumMovingObjectType.TILE) { + int i = movingobjectposition.b; + int j = movingobjectposition.c; + int k = movingobjectposition.d; + + if (!world.isStatic) { + // CraftBukkit start - Boat placement + PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(entityhuman, Action.RIGHT_CLICK_BLOCK, i, j, k, movingobjectposition.face, itemstack); + + if (event.isCancelled()) { + return itemstack; + } + // CraftBukkit end + + if (world.getTypeId(i, j, k) == Block.SNOW.id) { + --j; + } + + world.addEntity(new EntityBoat(world, (double) ((float) i + 0.5F), (double) ((float) j + 1.0F), (double) ((float) k + 0.5F))); + } + + --itemstack.count; + } + + return itemstack; + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemBow.java b/src/main/java/net/minecraft/server/ItemBow.java new file mode 100644 index 0000000..9fbc8d9 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemBow.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +public class ItemBow extends Item { + + public ItemBow(int i) { + super(i); + this.maxStackSize = 1; + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + if (entityhuman.inventory.b(Item.ARROW.id)) { + if ((boolean) PoseidonConfig.getInstance().getProperty("world.settings.skeleton-shooting-sound-fix.enabled")) { + world.a(entityhuman, 1002, MathHelper.floor(entityhuman.locX), MathHelper.floor(entityhuman.locY - (double)entityhuman.height), MathHelper.floor(entityhuman.locZ), 0); // Poseidon - fix player bow sounds (Strultz) + } else { + world.makeSound(entityhuman, "random.bow", 1.0F, 1.0F / (b.nextFloat() * 0.4F + 0.8F)); + } + if (!world.isStatic) { + world.addEntity(new EntityArrow(world, entityhuman)); + } + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ItemBucket.java b/src/main/java/net/minecraft/server/ItemBucket.java new file mode 100644 index 0000000..e1c2866 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemBucket.java @@ -0,0 +1,169 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.Location; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; +// CraftBukkit end + +public class ItemBucket extends Item { + + private int a; + + public ItemBucket(int i, int j) { + super(i); + this.maxStackSize = 1; + this.a = j; + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + float f = 1.0F; + float f1 = entityhuman.lastPitch + (entityhuman.pitch - entityhuman.lastPitch) * f; + float f2 = entityhuman.lastYaw + (entityhuman.yaw - entityhuman.lastYaw) * f; + double d0 = entityhuman.lastX + (entityhuman.locX - entityhuman.lastX) * (double) f; + double d1 = entityhuman.lastY + (entityhuman.locY - entityhuman.lastY) * (double) f + 1.62D - (double) entityhuman.height; + double d2 = entityhuman.lastZ + (entityhuman.locZ - entityhuman.lastZ) * (double) f; + Vec3D vec3d = Vec3D.create(d0, d1, d2); + float f3 = MathHelper.cos(-f2 * 0.017453292F - 3.1415927F); + float f4 = MathHelper.sin(-f2 * 0.017453292F - 3.1415927F); + float f5 = -MathHelper.cos(-f1 * 0.017453292F); + float f6 = MathHelper.sin(-f1 * 0.017453292F); + float f7 = f4 * f5; + float f8 = f3 * f5; + double d3 = 5.0D; + Vec3D vec3d1 = vec3d.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3); + MovingObjectPosition movingobjectposition = world.rayTrace(vec3d, vec3d1, this.a == 0); + + if (movingobjectposition == null) { + return itemstack; + } else { + if (movingobjectposition.type == EnumMovingObjectType.TILE) { + int i = movingobjectposition.b; + int j = movingobjectposition.c; + int k = movingobjectposition.d; + + if (!world.a(entityhuman, i, j, k)) { + return itemstack; + } + + if (this.a == 0) { + if (world.getMaterial(i, j, k) == Material.WATER && world.getData(i, j, k) == 0) { + // CraftBukkit start + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, i, j, k, -1, itemstack, Item.WATER_BUCKET); + + if (event.isCancelled()) { + return itemstack; + } + + CraftItemStack itemInHand = (CraftItemStack) event.getItemStack(); + byte data = itemInHand.getData() == null ? (byte) 0 : itemInHand.getData().getData(); + // CraftBukkit end + + world.setTypeId(i, j, k, 0); + return new ItemStack(itemInHand.getTypeId(), itemInHand.getAmount(), data); // CraftBukkit + } + + if (world.getMaterial(i, j, k) == Material.LAVA && world.getData(i, j, k) == 0) { + // CraftBukkit start + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, i, j, k, -1, itemstack, Item.LAVA_BUCKET); + + if (event.isCancelled()) { + return itemstack; + } + + CraftItemStack itemInHand = (CraftItemStack) event.getItemStack(); + byte data = itemInHand.getData() == null ? (byte) 0 : itemInHand.getData().getData(); + // CraftBukkit end + + world.setTypeId(i, j, k, 0); + return new ItemStack(itemInHand.getTypeId(), itemInHand.getAmount(), data); // CraftBukkit + } + } else { + if (this.a < 0) { + // CraftBukkit start + PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent(entityhuman, i, j, k, movingobjectposition.face, itemstack); + + if (event.isCancelled()) { + return itemstack; + } + + CraftItemStack itemInHand = (CraftItemStack) event.getItemStack(); + byte data = itemInHand.getData() == null ? (byte) 0 : itemInHand.getData().getData(); + return new ItemStack(itemInHand.getTypeId(), itemInHand.getAmount(), data); + } + + int clickedX = i, clickedY = j, clickedZ = k; + // CraftBukkit end + + if (movingobjectposition.face == 0) { + --j; + } + + if (movingobjectposition.face == 1) { + ++j; + } + + if (movingobjectposition.face == 2) { + --k; + } + + if (movingobjectposition.face == 3) { + ++k; + } + + if (movingobjectposition.face == 4) { + --i; + } + + if (movingobjectposition.face == 5) { + ++i; + } + + if (world.isEmpty(i, j, k) || !world.getMaterial(i, j, k).isBuildable()) { + // CraftBukkit start + PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent(entityhuman, clickedX, clickedY, clickedZ, movingobjectposition.face, itemstack); + + if (event.isCancelled()) { + return itemstack; + } + // CraftBukkit end + + if (world.worldProvider.d && this.a == Block.WATER.id) { + world.makeSound(d0 + 0.5D, d1 + 0.5D, d2 + 0.5D, "random.fizz", 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); + + for (int l = 0; l < 8; ++l) { + world.a("largesmoke", (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D); + } + } else { + world.setTypeIdAndData(i, j, k, this.a, 0); + } + + // CraftBukkit start + CraftItemStack itemInHand = (CraftItemStack) event.getItemStack(); + byte data = itemInHand.getData() == null ? (byte) 0 : itemInHand.getData().getData(); + + return new ItemStack(itemInHand.getTypeId(), itemInHand.getAmount(), data); + // CraftBukkit end + } + } + } else if (this.a == 0 && movingobjectposition.entity instanceof EntityCow) { + // CraftBukkit start - This codepath seems to be *NEVER* called + Location loc = movingobjectposition.entity.getBukkitEntity().getLocation(); + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), -1, itemstack, Item.MILK_BUCKET); + + if (event.isCancelled()) { + return itemstack; + } + + CraftItemStack itemInHand = (CraftItemStack) event.getItemStack(); + byte data = itemInHand.getData() == null ? (byte) 0 : itemInHand.getData().getData(); + return new ItemStack(itemInHand.getTypeId(), itemInHand.getAmount(), data); + // CraftBukkit end + } + + return itemstack; + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemCloth.java b/src/main/java/net/minecraft/server/ItemCloth.java new file mode 100644 index 0000000..a27cf95 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemCloth.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public class ItemCloth extends ItemBlock { + + public ItemCloth(int i) { + super(i); + this.d(0); + this.a(true); + } + + public int filterData(int i) { + return i; + } +} diff --git a/src/main/java/net/minecraft/server/ItemCoal.java b/src/main/java/net/minecraft/server/ItemCoal.java new file mode 100644 index 0000000..587e7ab --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemCoal.java @@ -0,0 +1,10 @@ +package net.minecraft.server; + +public class ItemCoal extends Item { + + public ItemCoal(int i) { + super(i); + this.a(true); + this.d(0); + } +} diff --git a/src/main/java/net/minecraft/server/ItemCookie.java b/src/main/java/net/minecraft/server/ItemCookie.java new file mode 100644 index 0000000..69a7fd6 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemCookie.java @@ -0,0 +1,9 @@ +package net.minecraft.server; + +public class ItemCookie extends ItemFood { + + public ItemCookie(int i, int j, boolean flag, int k) { + super(i, j, flag); + this.maxStackSize = k; + } +} diff --git a/src/main/java/net/minecraft/server/ItemDoor.java b/src/main/java/net/minecraft/server/ItemDoor.java new file mode 100644 index 0000000..69571f8 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemDoor.java @@ -0,0 +1,94 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemDoor extends Item { + + private Material a; + + public ItemDoor(int i, Material material) { + super(i); + this.a = material; + this.maxStackSize = 1; + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + if (l != 1) { + return false; + } else { + ++j; + Block block; + + if (this.a == Material.WOOD) { + block = Block.WOODEN_DOOR; + } else { + block = Block.IRON_DOOR_BLOCK; + } + + if (!block.canPlace(world, i, j, k)) { + return false; + } else { + int i1 = MathHelper.floor((double) ((entityhuman.yaw + 180.0F) * 4.0F / 360.0F) - 0.5D) & 3; + byte b0 = 0; + byte b1 = 0; + + if (i1 == 0) { + b1 = 1; + } + + if (i1 == 1) { + b0 = -1; + } + + if (i1 == 2) { + b1 = -1; + } + + if (i1 == 3) { + b0 = 1; + } + + int j1 = (world.e(i - b0, j, k - b1) ? 1 : 0) + (world.e(i - b0, j + 1, k - b1) ? 1 : 0); + int k1 = (world.e(i + b0, j, k + b1) ? 1 : 0) + (world.e(i + b0, j + 1, k + b1) ? 1 : 0); + boolean flag = world.getTypeId(i - b0, j, k - b1) == block.id || world.getTypeId(i - b0, j + 1, k - b1) == block.id; + boolean flag1 = world.getTypeId(i + b0, j, k + b1) == block.id || world.getTypeId(i + b0, j + 1, k + b1) == block.id; + boolean flag2 = false; + + if (flag && !flag1) { + flag2 = true; + } else if (k1 > j1) { + flag2 = true; + } + + if (flag2) { + i1 = i1 - 1 & 3; + i1 += 4; + } + + CraftBlockState blockState = CraftBlockState.getBlockState(world, i, j, k); // CraftBukkit + world.suppressPhysics = true; + world.setTypeIdAndData(i, j, k, block.id, i1); + + // CraftBukkit start + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, i, j, k, block); + + if (event.isCancelled() || !event.canBuild()) { + event.getBlockPlaced().setTypeIdAndData(blockState.getTypeId(), blockState.getRawData(), false); + return false; + } + // CraftBukkit end + + world.setTypeIdAndData(i, j + 1, k, block.id, i1 + 8); + world.suppressPhysics = false; + world.applyPhysics(i, j, k, block.id); + world.applyPhysics(i, j + 1, k, block.id); + --itemstack.count; + return true; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemDye.java b/src/main/java/net/minecraft/server/ItemDye.java new file mode 100644 index 0000000..5b87a6d --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemDye.java @@ -0,0 +1,85 @@ +package net.minecraft.server; + +public class ItemDye extends Item { + + public static final String[] a = new String[] { "black", "red", "green", "brown", "blue", "purple", "cyan", "silver", "gray", "pink", "lime", "yellow", "lightBlue", "magenta", "orange", "white"}; + public static final int[] bk = new int[] { 1973019, 11743532, 3887386, 5320730, 2437522, 8073150, 2651799, 2651799, 4408131, 14188952, 4312372, 14602026, 6719955, 12801229, 15435844, 15790320}; + + public ItemDye(int i) { + super(i); + this.a(true); + this.d(0); + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + if (itemstack.getData() == 15) { + int i1 = world.getTypeId(i, j, k); + + if (i1 == Block.SAPLING.id) { + if (!world.isStatic) { + ((BlockSapling) Block.SAPLING).b(world, i, j, k, world.random); + --itemstack.count; + } + + return true; + } + + if (i1 == Block.CROPS.id) { + if (!world.isStatic) { + ((BlockCrops) Block.CROPS).d_(world, i, j, k); + --itemstack.count; + } + + return true; + } + + if (i1 == Block.GRASS.id) { + if (!world.isStatic) { + --itemstack.count; + + label53: + for (int j1 = 0; j1 < 128; ++j1) { + int k1 = i; + int l1 = j + 1; + int i2 = k; + + for (int j2 = 0; j2 < j1 / 16; ++j2) { + k1 += b.nextInt(3) - 1; + l1 += (b.nextInt(3) - 1) * b.nextInt(3) / 2; + i2 += b.nextInt(3) - 1; + if (world.getTypeId(k1, l1 - 1, i2) != Block.GRASS.id || world.e(k1, l1, i2)) { + continue label53; + } + } + + if (world.getTypeId(k1, l1, i2) == 0) { + if (b.nextInt(10) != 0) { + world.setTypeIdAndData(k1, l1, i2, Block.LONG_GRASS.id, 1); + } else if (b.nextInt(3) != 0) { + world.setTypeId(k1, l1, i2, Block.YELLOW_FLOWER.id); + } else { + world.setTypeId(k1, l1, i2, Block.RED_ROSE.id); + } + } + } + } + + return true; + } + } + + return false; + } + + public void a(ItemStack itemstack, EntityLiving entityliving) { + if (entityliving instanceof EntitySheep) { + EntitySheep entitysheep = (EntitySheep) entityliving; + int i = BlockCloth.c(itemstack.getData()); + + if (!entitysheep.isSheared() && entitysheep.getColor() != i) { + entitysheep.setColor(i); + --itemstack.count; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemEgg.java b/src/main/java/net/minecraft/server/ItemEgg.java new file mode 100644 index 0000000..0591f44 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemEgg.java @@ -0,0 +1,19 @@ +package net.minecraft.server; + +public class ItemEgg extends Item { + + public ItemEgg(int i) { + super(i); + this.maxStackSize = 16; + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + --itemstack.count; + world.makeSound(entityhuman, "random.bow", 0.5F, 0.4F / (b.nextFloat() * 0.4F + 0.8F)); + if (!world.isStatic) { + world.addEntity(new EntityEgg(world, entityhuman)); + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ItemFishingRod.java b/src/main/java/net/minecraft/server/ItemFishingRod.java new file mode 100644 index 0000000..caa8784 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemFishingRod.java @@ -0,0 +1,38 @@ +package net.minecraft.server; + +import org.bukkit.event.player.PlayerFishEvent; + +public class ItemFishingRod extends Item { + + public ItemFishingRod(int i) { + super(i); + this.d(64); + this.c(1); + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + if (entityhuman.hookedFish != null) { + int i = entityhuman.hookedFish.h(); + + itemstack.damage(i, entityhuman); + entityhuman.w(); + } else { + // CraftBukkit start + PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), null,PlayerFishEvent.State.FISHING); + world.getServer().getPluginManager().callEvent(playerFishEvent); + + if (playerFishEvent.isCancelled()) { + return itemstack; + } + // CraftBukkit end + world.makeSound(entityhuman, "random.bow", 0.5F, 0.4F / (b.nextFloat() * 0.4F + 0.8F)); + if (!world.isStatic) { + world.addEntity(new EntityFish(world, entityhuman)); + } + + entityhuman.w(); + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ItemFlintAndSteel.java b/src/main/java/net/minecraft/server/ItemFlintAndSteel.java new file mode 100644 index 0000000..97cfdda --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemFlintAndSteel.java @@ -0,0 +1,80 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemFlintAndSteel extends Item { + + public ItemFlintAndSteel(int i) { + super(i); + this.maxStackSize = 1; + this.d(64); + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + int clickedX = i, clickedY = j, clickedZ = k; // CraftBukkit + + if (l == 0) { + --j; + } + + if (l == 1) { + ++j; + } + + if (l == 2) { + --k; + } + + if (l == 3) { + ++k; + } + + if (l == 4) { + --i; + } + + if (l == 5) { + ++i; + } + + int i1 = world.getTypeId(i, j, k); + + if (i1 == 0) { + // CraftBukkit start - store the clicked block + org.bukkit.block.Block blockClicked = world.getWorld().getBlockAt(i, j, k); + Player thePlayer = (Player) entityhuman.getBukkitEntity(); + + BlockIgniteEvent eventIgnite = new BlockIgniteEvent(blockClicked, BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, thePlayer); + world.getServer().getPluginManager().callEvent(eventIgnite); + + if (eventIgnite.isCancelled()) { + itemstack.damage(1, entityhuman); + return false; + } + + CraftBlockState blockState = CraftBlockState.getBlockState(world, i, j, k); + // CraftBukkit end + + world.makeSound((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D, "fire.ignite", 1.0F, b.nextFloat() * 0.4F + 0.8F); + world.setTypeId(i, j, k, Block.FIRE.id); + + // CraftBukkit start + BlockPlaceEvent placeEvent = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, clickedX, clickedY, clickedZ, Block.FIRE.id); + + if (placeEvent.isCancelled() || !placeEvent.canBuild()) { + placeEvent.getBlockPlaced().setTypeIdAndData(0, (byte) 0, false); + return false; + } + // CraftBukkit end + } + + itemstack.damage(1, entityhuman); + return true; + } +} diff --git a/src/main/java/net/minecraft/server/ItemFood.java b/src/main/java/net/minecraft/server/ItemFood.java new file mode 100644 index 0000000..e40cf54 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemFood.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +public class ItemFood extends Item { + + private int a; + private boolean bk; + + public ItemFood(int i, int j, boolean flag) { + super(i); + this.a = j; + this.bk = flag; + this.maxStackSize = 1; + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + --itemstack.count; + entityhuman.b(this.a); + return itemstack; + } + + public int k() { + return this.a; + } + + public boolean l() { + return this.bk; + } +} diff --git a/src/main/java/net/minecraft/server/ItemHoe.java b/src/main/java/net/minecraft/server/ItemHoe.java new file mode 100644 index 0000000..0885451 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemHoe.java @@ -0,0 +1,48 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemHoe extends Item { + + public ItemHoe(int i, EnumToolMaterial enumtoolmaterial) { + super(i); + this.maxStackSize = 1; + this.d(enumtoolmaterial.a()); + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + int i1 = world.getTypeId(i, j, k); + int j1 = world.getTypeId(i, j + 1, k); + + if ((l == 0 || j1 != 0 || i1 != Block.GRASS.id) && i1 != Block.DIRT.id) { + return false; + } else { + Block block = Block.SOIL; + + world.makeSound((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), block.stepSound.getName(), (block.stepSound.getVolume1() + 1.0F) / 2.0F, block.stepSound.getVolume2() * 0.8F); + if (world.isStatic) { + return true; + } else { + CraftBlockState blockState = CraftBlockState.getBlockState(world, i, j, k); // CraftBukkit + + world.setTypeId(i, j, k, block.id); + + // CraftBukkit start - Hoes - blockface -1 for 'SELF' + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, i, j, k, block); + + if (event.isCancelled() || !event.canBuild()) { + event.getBlockPlaced().setTypeId(blockState.getTypeId()); + return false; + } + // CraftBukkit end + + itemstack.damage(1, entityhuman); + return true; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemInWorldManager.java b/src/main/java/net/minecraft/server/ItemInWorldManager.java new file mode 100644 index 0000000..391cbb1 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemInWorldManager.java @@ -0,0 +1,248 @@ +package net.minecraft.server; + +// CraftBukkit start + +import com.legacyminecraft.poseidon.packets.ArtificialPacket53BlockChange; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.Event; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.player.PlayerInteractEvent; +// CraftBukkit end + +public class ItemInWorldManager { + + private WorldServer world; + public EntityHuman player; + private float c = 0.0F; + private int lastDigTick; + private int e; + private int f; + private int g; + private int currentTick; + private boolean i; + private int j; + private int k; + private int l; + private int m; + + public ItemInWorldManager(WorldServer worldserver) { + this.world = worldserver; + } + + public void a() { + this.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit + if (this.i) { + int i = this.currentTick - this.m; + int j = this.world.getTypeId(this.j, this.k, this.l); + + if (j != 0) { + Block block = Block.byId[j]; + float f = block.getDamage(this.player) * (float) (i + 1); + + if (f >= 1.0F) { + this.i = false; + this.c(this.j, this.k, this.l); + } + } else { + this.i = false; + } + } + } + + public void dig(int i, int j, int k, int l) { + // this.world.douseFire((EntityHuman) null, i, j, k, l); // CraftBukkit - moved down + this.lastDigTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit + int i1 = this.world.getTypeId(i, j, k); + + // CraftBukkit start + // Swings at air do *NOT* exist. + if (i1 <= 0) { + return; + } + + PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, i, j, k, l, this.player.inventory.getItemInHand()); + + if (event.useInteractedBlock() == Event.Result.DENY) { + // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. + if (i1 == Block.WOODEN_DOOR.id) { + // For some reason *BOTH* the bottom/top part have to be marked updated. + boolean bottom = (this.world.getData(i, j, k) & 8) == 0; + ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, this.world)); + ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j + (bottom ? 1 : -1), k, this.world)); + } else if (i1 == Block.TRAP_DOOR.id) { + ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, this.world)); + } + } else { + Block.byId[i1].b(this.world, i, j, k, this.player); + // Allow fire punching to be blocked + this.world.douseFire((EntityHuman) null, i, j, k, l); + } + + // Handle hitting a block + float toolDamage = Block.byId[i1].getDamage(this.player); + if (event.useItemInHand() == Event.Result.DENY) { + // If we 'insta destroyed' then the client needs to be informed. + if (toolDamage > 1.0f) { + ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, this.world)); + } + return; + } + BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, i, j, k, this.player.inventory.getItemInHand(), toolDamage >= 1.0f); + + if (blockEvent.isCancelled()) { + return; + } + + if (blockEvent.getInstaBreak()) { + toolDamage = 2.0f; + } + + if (toolDamage >= 1.0F) { + // CraftBukkit end + this.c(i, j, k); + } else { + this.e = i; + this.f = j; + this.g = k; + } + } + + public void a(int i, int j, int k) { + if (i == this.e && j == this.f && k == this.g) { + this.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit + int l = this.currentTick - this.lastDigTick; + int i1 = this.world.getTypeId(i, j, k); + + if (i1 != 0) { + Block block = Block.byId[i1]; + float f = block.getDamage(this.player) * (float) (l + 1); + + if (f >= 0.7F) { + this.c(i, j, k); + } else if (!this.i) { + this.i = true; + this.j = i; + this.k = j; + this.l = k; + this.m = this.lastDigTick; + } + } + // CraftBukkit start - force blockreset to client + } else { + ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, this.world)); + // CraftBukkit end + } + + this.c = 0.0F; + } + + public boolean b(int i, int j, int k) { + Block block = Block.byId[this.world.getTypeId(i, j, k)]; + int l = this.world.getData(i, j, k); + boolean flag = this.world.setTypeId(i, j, k, 0); + + if (block != null && flag) { + block.postBreak(this.world, i, j, k, l); + } + + return flag; + } + + public boolean c(int i, int j, int k) { + int l = this.world.getTypeId(i, j, k); + int i1 = this.world.getData(i, j, k); + + // CraftBukkit start + if (this.player instanceof EntityPlayer) { + org.bukkit.block.Block block = this.world.getWorld().getBlockAt(i, j, k); + + // Poseidon start - CraftBukkit backport + // Tell the client the block is gone immediately then process events + if (world.getTileEntity(i, j, k) == null) { + ((EntityPlayer) this.player).netServerHandler.sendPacket(new ArtificialPacket53BlockChange(i, j, k, 0,0)); + } + // Poseidon end + BlockBreakEvent event = new BlockBreakEvent(block, (org.bukkit.entity.Player) this.player.getBukkitEntity()); + this.world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + // Poseidon - Inform the client if the event was cancelled + ((EntityPlayer) this.player).netServerHandler.sendPacket(new ArtificialPacket53BlockChange(i, j, k, l, i1)); + return false; + } + } + // CraftBukkit end + + // Poseidon - moved up + //int l = this.world.getTypeId(i, j, k); + //int i1 = this.world.getData(i, j, k); + + this.world.a(this.player, 2001, i, j, k, l + this.world.getData(i, j, k) * 256); + boolean flag = this.b(i, j, k); + ItemStack itemstack = this.player.G(); + + if (flag && this.player.b(Block.byId[l])) { + Block.byId[l].a(this.world, this.player, i, j, k, i1); + ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, this.world)); + } + + if (itemstack != null) { + itemstack.a(l, i, j, k, this.player); + if (itemstack.count == 0) { + itemstack.a(this.player); + this.player.H(); + } + } + + return flag; + } + + public boolean useItem(EntityHuman entityhuman, World world, ItemStack itemstack) { + int i = itemstack.count; + ItemStack itemstack1 = itemstack.a(world, entityhuman); + + if (itemstack1 == itemstack && (itemstack1 == null || itemstack1.count == i)) { + return false; + } else { + entityhuman.inventory.items[entityhuman.inventory.itemInHandIndex] = itemstack1; + if (itemstack1.count == 0) { + entityhuman.inventory.items[entityhuman.inventory.itemInHandIndex] = null; + } + + return true; + } + } + + public boolean interact(EntityHuman entityhuman, World world, ItemStack itemstack, int i, int j, int k, int l) { + int i1 = world.getTypeId(i, j, k); + + // CraftBukkit start - Interact + boolean result = false; + if (i1 > 0) { + PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(entityhuman, Action.RIGHT_CLICK_BLOCK, i, j, k, l, itemstack); + if (event.useInteractedBlock() == Event.Result.DENY) { + // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. + if (i1 == Block.WOODEN_DOOR.id) { + boolean bottom = (world.getData(i, j, k) & 8) == 0; + ((EntityPlayer) entityhuman).netServerHandler.sendPacket(new Packet53BlockChange(i, j + (bottom ? 1 : -1), k, world)); + } + result = (event.useItemInHand() != Event.Result.ALLOW); + } else { + result = Block.byId[i1].interact(world, i, j, k, entityhuman); + } + + if (itemstack != null && !result) { + result = itemstack.placeItem(entityhuman, world, i, j, k, l); + } + + // If we have 'true' and no explicit deny *or* an explicit allow -- run the item part of the hook + if (itemstack != null && ((!result && event.useItemInHand() != Event.Result.DENY) || event.useItemInHand() == Event.Result.ALLOW)) { + this.useItem(entityhuman, world, itemstack); + } + } + return result; + // CraftBukkit end + } +} diff --git a/src/main/java/net/minecraft/server/ItemLeaves.java b/src/main/java/net/minecraft/server/ItemLeaves.java new file mode 100644 index 0000000..5b3f6a5 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemLeaves.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public class ItemLeaves extends ItemBlock { + + public ItemLeaves(int i) { + super(i); + this.d(0); + this.a(true); + } + + public int filterData(int i) { + return i | 8; + } +} diff --git a/src/main/java/net/minecraft/server/ItemLog.java b/src/main/java/net/minecraft/server/ItemLog.java new file mode 100644 index 0000000..ba933fa --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemLog.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public class ItemLog extends ItemBlock { + + public ItemLog(int i) { + super(i); + this.d(0); + this.a(true); + } + + public int filterData(int i) { + return i; + } +} diff --git a/src/main/java/net/minecraft/server/ItemMinecart.java b/src/main/java/net/minecraft/server/ItemMinecart.java new file mode 100644 index 0000000..5e83b1a --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemMinecart.java @@ -0,0 +1,41 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +// CraftBukkit end + +public class ItemMinecart extends Item { + + public int a; + + public ItemMinecart(int i, int j) { + super(i); + this.maxStackSize = 1; + this.a = j; + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + int i1 = world.getTypeId(i, j, k); + + if (BlockMinecartTrack.c(i1)) { + if (!world.isStatic) { + // CraftBukkit start - Minecarts + PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(entityhuman, Action.RIGHT_CLICK_BLOCK, i, j, k, l, itemstack); + + if (event.isCancelled()) { + return false; + } + // CraftBukkit end + + world.addEntity(new EntityMinecart(world, (double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), this.a)); + } + + --itemstack.count; + return true; + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemPainting.java b/src/main/java/net/minecraft/server/ItemPainting.java new file mode 100644 index 0000000..5b8543a --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemPainting.java @@ -0,0 +1,62 @@ +package net.minecraft.server; + +// CraftBukkit start + +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.entity.Player; +import org.bukkit.event.painting.PaintingPlaceEvent; +// CraftBukkit end + +public class ItemPainting extends Item { + + public ItemPainting(int i) { + super(i); + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + if (l == 0) { + return false; + } else if (l == 1) { + return false; + } else { + byte b0 = 0; + + if (l == 4) { + b0 = 1; + } + + if (l == 3) { + b0 = 2; + } + + if (l == 5) { + b0 = 3; + } + + EntityPainting entitypainting = new EntityPainting(world, i, j, k, b0); + + if (entitypainting.h()) { + if (!world.isStatic) { + // CraftBukkit start + Player who = (entityhuman == null) ? null : (Player) entityhuman.getBukkitEntity(); + + org.bukkit.block.Block blockClicked = world.getWorld().getBlockAt(i, j, k); + org.bukkit.block.BlockFace blockFace = CraftBlock.notchToBlockFace(l); + + PaintingPlaceEvent event = new PaintingPlaceEvent((org.bukkit.entity.Painting) entitypainting.getBukkitEntity(), who, blockClicked, blockFace); + world.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return false; + } + // CraftBukkit end + world.addEntity(entitypainting); + } + + --itemstack.count; + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemPickaxe.java b/src/main/java/net/minecraft/server/ItemPickaxe.java new file mode 100644 index 0000000..8c51b36 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemPickaxe.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public class ItemPickaxe extends ItemTool { + + private static Block[] bk = new Block[] { Block.COBBLESTONE, Block.DOUBLE_STEP, Block.STEP, Block.STONE, Block.SANDSTONE, Block.MOSSY_COBBLESTONE, Block.IRON_ORE, Block.IRON_BLOCK, Block.COAL_ORE, Block.GOLD_BLOCK, Block.GOLD_ORE, Block.DIAMOND_ORE, Block.DIAMOND_BLOCK, Block.ICE, Block.NETHERRACK, Block.LAPIS_ORE, Block.LAPIS_BLOCK}; + + protected ItemPickaxe(int i, EnumToolMaterial enumtoolmaterial) { + super(i, 2, enumtoolmaterial, bk); + } + + public boolean a(Block block) { + return block == Block.OBSIDIAN ? this.a.d() == 3 : (block != Block.DIAMOND_BLOCK && block != Block.DIAMOND_ORE ? (block != Block.GOLD_BLOCK && block != Block.GOLD_ORE ? (block != Block.IRON_BLOCK && block != Block.IRON_ORE ? (block != Block.LAPIS_BLOCK && block != Block.LAPIS_ORE ? (block != Block.REDSTONE_ORE && block != Block.GLOWING_REDSTONE_ORE ? (block.material == Material.STONE ? true : block.material == Material.ORE) : this.a.d() >= 2) : this.a.d() >= 1) : this.a.d() >= 1) : this.a.d() >= 2) : this.a.d() >= 2); + } +} diff --git a/src/main/java/net/minecraft/server/ItemPiston.java b/src/main/java/net/minecraft/server/ItemPiston.java new file mode 100644 index 0000000..e94826e --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemPiston.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +public class ItemPiston extends ItemBlock { + + public ItemPiston(int i) { + super(i); + } + + public int filterData(int i) { + return 7; + } +} diff --git a/src/main/java/net/minecraft/server/ItemRecord.java b/src/main/java/net/minecraft/server/ItemRecord.java new file mode 100644 index 0000000..8fc7615 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemRecord.java @@ -0,0 +1,27 @@ +package net.minecraft.server; + +public class ItemRecord extends Item { + + public final String a; + + protected ItemRecord(int i, String s) { + super(i); + this.a = s; + this.maxStackSize = 1; + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + if (world.getTypeId(i, j, k) == Block.JUKEBOX.id && world.getData(i, j, k) == 0) { + if (world.isStatic) { + return true; + } else { + ((BlockJukeBox) Block.JUKEBOX).f(world, i, j, k, this.id); + world.a((EntityHuman) null, 1005, i, j, k, this.id); + --itemstack.count; + return true; + } + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemRedstone.java b/src/main/java/net/minecraft/server/ItemRedstone.java new file mode 100644 index 0000000..f50305b --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemRedstone.java @@ -0,0 +1,69 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemRedstone extends Item { + + public ItemRedstone(int i) { + super(i); + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + int clickedX = i, clickedY = j, clickedZ = k; // CraftBukkit + + if (world.getTypeId(i, j, k) != Block.SNOW.id) { + if (l == 0) { + --j; + } + + if (l == 1) { + ++j; + } + + if (l == 2) { + --k; + } + + if (l == 3) { + ++k; + } + + if (l == 4) { + --i; + } + + if (l == 5) { + ++i; + } + + if (!world.isEmpty(i, j, k)) { + return false; + } + } + + if (Block.REDSTONE_WIRE.canPlace(world, i, j, k)) { + CraftBlockState blockState = CraftBlockState.getBlockState(world, i, j, k); // CraftBukkit + + world.setRawTypeId(i, j, k, Block.REDSTONE_WIRE.id); // CraftBukkit - We update after the event + + // CraftBukkit start - redstone + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, clickedX, clickedY, clickedZ, Block.REDSTONE_WIRE); + + if (event.isCancelled() || !event.canBuild()) { + event.getBlockPlaced().setTypeIdAndData(blockState.getTypeId(), blockState.getRawData(), false); + return false; + } + + world.update( i, j, k, Block.REDSTONE_WIRE.id); // Must take place after BlockPlaceEvent, we need to update all other blocks. + // CraftBukkit end + + --itemstack.count; // CraftBukkit - ORDER MATTERS + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/ItemReed.java b/src/main/java/net/minecraft/server/ItemReed.java new file mode 100644 index 0000000..2cfeac8 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemReed.java @@ -0,0 +1,90 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemReed extends Item { + + private int id; + + public ItemReed(int i, Block block) { + super(i); + this.id = block.id; + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + int clickedX = i, clickedY = j, clickedZ = k; // CraftBukkit + + if (world.getTypeId(i, j, k) == Block.SNOW.id) { + l = 0; + } else { + if (l == 0) { + --j; + } + + if (l == 1) { + ++j; + } + + if (l == 2) { + --k; + } + + if (l == 3) { + ++k; + } + + if (l == 4) { + --i; + } + + if (l == 5) { + ++i; + } + } + + if (itemstack.count == 0) { + return false; + } else { + if (world.a(this.id, i, j, k, false, l)) { + Block block = Block.byId[this.id]; + + // CraftBukkit start - This executes the placement of the block + CraftBlockState replacedBlockState = CraftBlockState.getBlockState(world, i, j, k); // CraftBukkit + /** + * @see net.minecraft.server.World#setTypeId(int i, int j, int k, int l) + * + * This replaces world.setTypeId(IIII), we're doing this because we need to + * hook between the 'placement' and the informing to 'world' so we can + * sanely undo this. + * + * Whenever the call to 'world.setTypeId' changes we need to figure out again what to + * replace this with. + */ + if (world.setRawTypeId(i, j, k, this.id)) { // <-- world.e does this to place the block + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, replacedBlockState, clickedX, clickedY, clickedZ, block); + + if (event.isCancelled() || !event.canBuild()) { + // CraftBukkit - undo; this only has reed, repeater and pie blocks + world.setTypeIdAndData(i, j, k, replacedBlockState.getTypeId(), replacedBlockState.getRawData()); + + return true; + } + + world.update(i, j, k, this.id); // <-- world.setTypeId does this on success (tell the world) + // CraftBukkit end + + Block.byId[this.id].postPlace(world, i, j, k, l); + Block.byId[this.id].postPlace(world, i, j, k, entityhuman); + world.makeSound((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), block.stepSound.getName(), (block.stepSound.getVolume1() + 1.0F) / 2.0F, block.stepSound.getVolume2() * 0.8F); + --itemstack.count; + } + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemSaddle.java b/src/main/java/net/minecraft/server/ItemSaddle.java new file mode 100644 index 0000000..eefbfaa --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSaddle.java @@ -0,0 +1,25 @@ +package net.minecraft.server; + +public class ItemSaddle extends Item { + + public ItemSaddle(int i) { + super(i); + this.maxStackSize = 1; + } + + public void a(ItemStack itemstack, EntityLiving entityliving) { + if (entityliving instanceof EntityPig) { + EntityPig entitypig = (EntityPig) entityliving; + + if (!entitypig.hasSaddle()) { + entitypig.setSaddle(true); + --itemstack.count; + } + } + } + + public boolean a(ItemStack itemstack, EntityLiving entityliving, EntityLiving entityliving1) { + this.a(itemstack, entityliving); + return true; + } +} diff --git a/src/main/java/net/minecraft/server/ItemSapling.java b/src/main/java/net/minecraft/server/ItemSapling.java new file mode 100644 index 0000000..523afb1 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSapling.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public class ItemSapling extends ItemBlock { + + public ItemSapling(int i) { + super(i); + this.d(0); + this.a(true); + } + + public int filterData(int i) { + return i; + } +} diff --git a/src/main/java/net/minecraft/server/ItemSeeds.java b/src/main/java/net/minecraft/server/ItemSeeds.java new file mode 100644 index 0000000..a45fd6b --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSeeds.java @@ -0,0 +1,45 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemSeeds extends Item { + + private int id; + + public ItemSeeds(int i, int j) { + super(i); + this.id = j; + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + if (l != 1) { + return false; + } else { + int i1 = world.getTypeId(i, j, k); + + if (i1 == Block.SOIL.id && world.isEmpty(i, j + 1, k)) { + CraftBlockState blockState = CraftBlockState.getBlockState(world, i, j + 1, k); // CraftBukkit + + world.setTypeId(i, j + 1, k, this.id); + + // CraftBukkit start - seeds + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, i, j, k, this.id); + + if (event.isCancelled() || !event.canBuild()) { + event.getBlockPlaced().setTypeId(0); + return false; + } + // CraftBukkit end + + --itemstack.count; + return true; + } else { + return false; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemShears.java b/src/main/java/net/minecraft/server/ItemShears.java new file mode 100644 index 0000000..87d4f08 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemShears.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +public class ItemShears extends Item { + + public ItemShears(int i) { + super(i); + this.c(1); + this.d(238); + } + + public boolean a(ItemStack itemstack, int i, int j, int k, int l, EntityLiving entityliving) { + if (i == Block.LEAVES.id || i == Block.WEB.id) { + itemstack.damage(1, entityliving); + } + + return super.a(itemstack, i, j, k, l, entityliving); + } + + public boolean a(Block block) { + return block.id == Block.WEB.id; + } + + public float a(ItemStack itemstack, Block block) { + return block.id != Block.WEB.id && block.id != Block.LEAVES.id ? (block.id == Block.WOOL.id ? 5.0F : super.a(itemstack, block)) : 15.0F; + } +} diff --git a/src/main/java/net/minecraft/server/ItemSign.java b/src/main/java/net/minecraft/server/ItemSign.java new file mode 100644 index 0000000..def29a9 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSign.java @@ -0,0 +1,75 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockPlaceEvent; +// CraftBukkit end + +public class ItemSign extends Item { + + public ItemSign(int i) { + super(i); + this.maxStackSize = 1; + } + + public boolean a(ItemStack itemstack, EntityHuman entityhuman, World world, int i, int j, int k, int l) { + if (l == 0) { + return false; + } else if (!world.getMaterial(i, j, k).isBuildable()) { + return false; + } else { + int clickedX = i, clickedY = j, clickedZ = k; // CraftBukkit + + if (l == 1) { + ++j; + } + + if (l == 2) { + --k; + } + + if (l == 3) { + ++k; + } + + if (l == 4) { + --i; + } + + if (l == 5) { + ++i; + } + + if (!Block.SIGN_POST.canPlace(world, i, j, k)) { + return false; + } else { + CraftBlockState blockState = CraftBlockState.getBlockState(world, i, j, k); // CraftBukkit + + if (l == 1) { + world.setTypeIdAndData(i, j, k, Block.SIGN_POST.id, MathHelper.floor((double) ((entityhuman.yaw + 180.0F) * 16.0F / 360.0F) + 0.5D) & 15); + } else { + world.setTypeIdAndData(i, j, k, Block.WALL_SIGN.id, l); + } + + // CraftBukkit start - sign + BlockPlaceEvent event = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, clickedX, clickedY, clickedZ, l == 1 ? Block.SIGN_POST : Block.WALL_SIGN); + + if (event.isCancelled() || !event.canBuild()) { + event.getBlockPlaced().setTypeIdAndData(blockState.getTypeId(), blockState.getRawData(), false); + return false; + } + // CraftBukkit end + + --itemstack.count; + TileEntitySign tileentitysign = (TileEntitySign) world.getTileEntity(i, j, k); + + if (tileentitysign != null) { + entityhuman.a(tileentitysign); + } + + return true; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/ItemSnowball.java b/src/main/java/net/minecraft/server/ItemSnowball.java new file mode 100644 index 0000000..7c230e4 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSnowball.java @@ -0,0 +1,19 @@ +package net.minecraft.server; + +public class ItemSnowball extends Item { + + public ItemSnowball(int i) { + super(i); + this.maxStackSize = 16; + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + --itemstack.count; + world.makeSound(entityhuman, "random.bow", 0.5F, 0.4F / (b.nextFloat() * 0.4F + 0.8F)); + if (!world.isStatic) { + world.addEntity(new EntitySnowball(world, entityhuman)); + } + + return itemstack; + } +} diff --git a/src/main/java/net/minecraft/server/ItemSoup.java b/src/main/java/net/minecraft/server/ItemSoup.java new file mode 100644 index 0000000..94089fb --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSoup.java @@ -0,0 +1,13 @@ +package net.minecraft.server; + +public class ItemSoup extends ItemFood { + + public ItemSoup(int i, int j) { + super(i, j, false); + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { + super.a(itemstack, world, entityhuman); + return new ItemStack(Item.BOWL); + } +} diff --git a/src/main/java/net/minecraft/server/ItemSpade.java b/src/main/java/net/minecraft/server/ItemSpade.java new file mode 100644 index 0000000..ccd0c60 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSpade.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public class ItemSpade extends ItemTool { + + private static Block[] bk = new Block[] { Block.GRASS, Block.DIRT, Block.SAND, Block.GRAVEL, Block.SNOW, Block.SNOW_BLOCK, Block.CLAY, Block.SOIL}; + + public ItemSpade(int i, EnumToolMaterial enumtoolmaterial) { + super(i, 1, enumtoolmaterial, bk); + } + + public boolean a(Block block) { + return block == Block.SNOW ? true : block == Block.SNOW_BLOCK; + } +} diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java new file mode 100644 index 0000000..6569c13 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemStack.java @@ -0,0 +1,224 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerItemDamageEvent; + +public final class ItemStack { + + public int count; + public int b; + public int id; + public int damage; // CraftBukkit - private -> public + + public ItemStack(Block block) { + this(block, 1); + } + + public ItemStack(Block block, int i) { + this(block.id, i, 0); + } + + public ItemStack(Block block, int i, int j) { + this(block.id, i, j); + } + + public ItemStack(Item item) { + this(item.id, 1, 0); + } + + public ItemStack(Item item, int i) { + this(item.id, i, 0); + } + + public ItemStack(Item item, int i, int j) { + this(item.id, i, j); + } + + public ItemStack(int i, int j, int k) { + this.count = 0; + this.id = i; + this.count = j; + this.damage = k; + } + + public ItemStack(NBTTagCompound nbttagcompound) { + this.count = 0; + this.b(nbttagcompound); + } + + public ItemStack a(int i) { + this.count -= i; + return new ItemStack(this.id, i, this.damage); + } + + public Item getItem() { + return Item.byId[this.id]; + } + + public boolean placeItem(EntityHuman entityhuman, World world, int i, int j, int k, int l) { + boolean flag = this.getItem().a(this, entityhuman, world, i, j, k, l); + + if (flag) { + entityhuman.a(StatisticList.E[this.id], 1); + } + + return flag; + } + + public float a(Block block) { + return this.getItem().a(this, block); + } + + public ItemStack a(World world, EntityHuman entityhuman) { + return this.getItem().a(this, world, entityhuman); + } + + public NBTTagCompound a(NBTTagCompound nbttagcompound) { + nbttagcompound.a("id", (short) this.id); + nbttagcompound.a("Count", (byte) this.count); + nbttagcompound.a("Damage", (short) this.damage); + return nbttagcompound; + } + + public void b(NBTTagCompound nbttagcompound) { + this.id = nbttagcompound.d("id"); + this.count = nbttagcompound.c("Count"); + this.damage = nbttagcompound.d("Damage"); + } + + public int getMaxStackSize() { + return this.getItem().getMaxStackSize(); + } + + public boolean isStackable() { + return this.getMaxStackSize() > 1 && (!this.d() || !this.f()); + } + + public boolean d() { + return Item.byId[this.id].e() > 0; + } + + public boolean usesData() { + return Item.byId[this.id].d(); + } + + public boolean f() { + return this.d() && this.damage > 0; + } + + public int g() { + return this.damage; + } + + public int getData() { + return this.damage; + } + + public void b(int i) { + this.damage = i; + } + + public int i() { + return Item.byId[this.id].e(); + } + + @SuppressWarnings("deprecation") + public void damage(int i, Entity entity) { + if (this.d()) { + if (entity instanceof EntityPlayer) { + PlayerItemDamageEvent event = new PlayerItemDamageEvent((Player)entity.getBukkitEntity(), new CraftItemStack(this), i); + event.getPlayer().getServer().getPluginManager().callEvent(event); + if (i != event.getDamage() || event.isCancelled()) + event.getPlayer().updateInventory(); + if (event.isCancelled()) + return; + i = event.getDamage(); + } + this.damage += i; + if (this.damage > this.i()) { + if (entity instanceof EntityHuman) { + ((EntityHuman) entity).a(StatisticList.F[this.id], 1); + } + + --this.count; + if (this.count < 0) { + this.count = 0; + } + + this.damage = 0; + } + } + } + + public void a(EntityLiving entityliving, EntityHuman entityhuman) { + boolean flag = Item.byId[this.id].a(this, entityliving, (EntityLiving) entityhuman); + + if (flag) { + entityhuman.a(StatisticList.E[this.id], 1); + } + } + + public void a(int i, int j, int k, int l, EntityHuman entityhuman) { + boolean flag = Item.byId[this.id].a(this, i, j, k, l, entityhuman); + + if (flag) { + entityhuman.a(StatisticList.E[this.id], 1); + } + } + + public int a(Entity entity) { + return Item.byId[this.id].a(entity); + } + + public boolean b(Block block) { + return Item.byId[this.id].a(block); + } + + public void a(EntityHuman entityhuman) {} + + public void a(EntityLiving entityliving) { + Item.byId[this.id].a(this, entityliving); + } + + public ItemStack cloneItemStack() { + return new ItemStack(this.id, this.count, this.damage); + } + + public static boolean equals(ItemStack itemstack, ItemStack itemstack1) { + return itemstack == null && itemstack1 == null ? true : (itemstack != null && itemstack1 != null ? itemstack.d(itemstack1) : false); + } + + private boolean d(ItemStack itemstack) { + return this.count != itemstack.count ? false : (this.id != itemstack.id ? false : this.damage == itemstack.damage); + } + + public boolean doMaterialsMatch(ItemStack itemstack) { + return this.id == itemstack.id && this.damage == itemstack.damage; + } + + public static ItemStack b(ItemStack itemstack) { + return itemstack == null ? null : itemstack.cloneItemStack(); + } + + public String toString() { + return this.count + "x" + (this.id < 0 || this.id >= Item.byId.length ? "missingno" : Item.byId[this.id].a()) + "@" + this.damage; // Project Poseidon: Fixes ArrayIndexOutOfBoundsException + } + + public void a(World world, Entity entity, int i, boolean flag) { + if (this.b > 0) { + --this.b; + } + + Item.byId[this.id].a(this, world, entity, i, flag); + } + + public void b(World world, EntityHuman entityhuman) { + entityhuman.a(StatisticList.D[this.id], this.count); + Item.byId[this.id].c(this, world, entityhuman); + } + + public boolean c(ItemStack itemstack) { + return this.id == itemstack.id && this.count == itemstack.count && this.damage == itemstack.damage; + } +} diff --git a/src/main/java/net/minecraft/server/ItemStep.java b/src/main/java/net/minecraft/server/ItemStep.java new file mode 100644 index 0000000..dde71da --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemStep.java @@ -0,0 +1,14 @@ +package net.minecraft.server; + +public class ItemStep extends ItemBlock { + + public ItemStep(int i) { + super(i); + this.d(0); + this.a(true); + } + + public int filterData(int i) { + return i; + } +} diff --git a/src/main/java/net/minecraft/server/ItemSword.java b/src/main/java/net/minecraft/server/ItemSword.java new file mode 100644 index 0000000..4c47bfd --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemSword.java @@ -0,0 +1,35 @@ +package net.minecraft.server; + +public class ItemSword extends Item { + + private int a; + + public ItemSword(int i, EnumToolMaterial enumtoolmaterial) { + super(i); + this.maxStackSize = 1; + this.d(enumtoolmaterial.a()); + this.a = 4 + enumtoolmaterial.c() * 2; + } + + public float a(ItemStack itemstack, Block block) { + return block.id == Block.WEB.id ? 15.0F : 1.5F; + } + + public boolean a(ItemStack itemstack, EntityLiving entityliving, EntityLiving entityliving1) { + itemstack.damage(1, entityliving1); + return true; + } + + public boolean a(ItemStack itemstack, int i, int j, int k, int l, EntityLiving entityliving) { + itemstack.damage(2, entityliving); + return true; + } + + public int a(Entity entity) { + return this.a; + } + + public boolean a(Block block) { + return block.id == Block.WEB.id; + } +} diff --git a/src/main/java/net/minecraft/server/ItemTool.java b/src/main/java/net/minecraft/server/ItemTool.java new file mode 100644 index 0000000..a33e75e --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemTool.java @@ -0,0 +1,43 @@ +package net.minecraft.server; + +public class ItemTool extends Item { + + private Block[] bk; + private float bl = 4.0F; + private int bm; + protected EnumToolMaterial a; + + protected ItemTool(int i, int j, EnumToolMaterial enumtoolmaterial, Block[] ablock) { + super(i); + this.a = enumtoolmaterial; + this.bk = ablock; + this.maxStackSize = 1; + this.d(enumtoolmaterial.a()); + this.bl = enumtoolmaterial.b(); + this.bm = j + enumtoolmaterial.c(); + } + + public float a(ItemStack itemstack, Block block) { + for (int i = 0; i < this.bk.length; ++i) { + if (this.bk[i] == block) { + return this.bl; + } + } + + return 1.0F; + } + + public boolean a(ItemStack itemstack, EntityLiving entityliving, EntityLiving entityliving1) { + itemstack.damage(2, entityliving1); + return true; + } + + public boolean a(ItemStack itemstack, int i, int j, int k, int l, EntityLiving entityliving) { + itemstack.damage(1, entityliving); + return true; + } + + public int a(Entity entity) { + return this.bm; + } +} diff --git a/src/main/java/net/minecraft/server/ItemWorldMap.java b/src/main/java/net/minecraft/server/ItemWorldMap.java new file mode 100644 index 0000000..9ec729c --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemWorldMap.java @@ -0,0 +1,246 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.Bukkit; +import org.bukkit.event.server.MapInitializeEvent; +// CraftBukkit end + +public class ItemWorldMap extends ItemWorldMapBase { + + protected ItemWorldMap(int i) { + super(i); + this.c(1); + } + + public WorldMap a(ItemStack itemstack, World world) { + + WorldMap worldmap = (WorldMap) world.a(WorldMap.class, "map_" + itemstack.getData()); + + if (worldmap == null) { + itemstack.b(world.b("map")); + String s = "map_" + itemstack.getData(); + + worldmap = new WorldMap(s); + worldmap.b = world.q().c(); + worldmap.c = world.q().e(); + worldmap.e = 3; + worldmap.map = (byte) world.worldProvider.dimension; + worldmap.a(); + world.a(s, (WorldMapBase) worldmap); + + // CraftBukkit start + MapInitializeEvent event = new MapInitializeEvent(worldmap.mapView); + Bukkit.getServer().getPluginManager().callEvent(event); + // CraftBukkit end + } + + return worldmap; + } + + public void a(World world, Entity entity, WorldMap worldmap) { + if (((WorldServer) world).dimension == worldmap.map) { // CraftBukkit + short short1 = 128; + short short2 = 128; + int i = 1 << worldmap.e; + int j = worldmap.b; + int k = worldmap.c; + int l = MathHelper.floor(entity.locX - (double) j) / i + short1 / 2; + int i1 = MathHelper.floor(entity.locZ - (double) k) / i + short2 / 2; + int j1 = 128 / i; + + if (world.worldProvider.e) { + j1 /= 2; + } + + ++worldmap.g; + + for (int k1 = l - j1 + 1; k1 < l + j1; ++k1) { + if ((k1 & 15) == (worldmap.g & 15)) { + int l1 = 255; + int i2 = 0; + double d0 = 0.0D; + + for (int j2 = i1 - j1 - 1; j2 < i1 + j1; ++j2) { + if (k1 >= 0 && j2 >= -1 && k1 < short1 && j2 < short2) { + int k2 = k1 - l; + int l2 = j2 - i1; + boolean flag = k2 * k2 + l2 * l2 > (j1 - 2) * (j1 - 2); + int i3 = (j / i + k1 - short1 / 2) * i; + int j3 = (k / i + j2 - short2 / 2) * i; + byte b0 = 0; + byte b1 = 0; + byte b2 = 0; + int[] aint = new int[256]; + Chunk chunk = world.getChunkAtWorldCoords(i3, j3); + if (chunk.isEmpty()) continue; // CraftBukkit + int k3 = i3 & 15; + int l3 = j3 & 15; + int i4 = 0; + double d1 = 0.0D; + int j4; + int k4; + int l4; + int i5; + + if (world.worldProvider.e) { + l4 = i3 + j3 * 231871; + l4 = l4 * l4 * 31287121 + l4 * 11; + if ((l4 >> 20 & 1) == 0) { + aint[Block.DIRT.id] += 10; + } else { + aint[Block.STONE.id] += 10; + } + + d1 = 100.0D; + } else { + for (l4 = 0; l4 < i; ++l4) { + for (j4 = 0; j4 < i; ++j4) { + k4 = chunk.b(l4 + k3, j4 + l3) + 1; + int j5 = 0; + + if (k4 > 1) { + boolean flag1 = false; + + do { + flag1 = true; + j5 = chunk.getTypeId(l4 + k3, k4 - 1, j4 + l3); + if (j5 == 0) { + flag1 = false; + } else if (k4 > 0 && j5 > 0 && Block.byId[j5].material.C == MaterialMapColor.b) { + flag1 = false; + } + + if (!flag1) { + --k4; + if (k4 <= 0) break; // CraftBukkit + j5 = chunk.getTypeId(l4 + k3, k4 - 1, j4 + l3); + } + } while (!flag1); + + if (j5 != 0 && Block.byId[j5].material.isLiquid()) { + i5 = k4 - 1; + boolean flag2 = false; + + int k5; + + do { + k5 = chunk.getTypeId(l4 + k3, i5--, j4 + l3); + ++i4; + } while (i5 > 0 && k5 != 0 && Block.byId[k5].material.isLiquid()); + } + } + + d1 += (double) k4 / (double) (i * i); + ++aint[j5]; + } + } + } + + i4 /= i * i; + int l5 = b0 / (i * i); + + l5 = b1 / (i * i); + l5 = b2 / (i * i); + l4 = 0; + j4 = 0; + + for (k4 = 0; k4 < 256; ++k4) { + if (aint[k4] > l4) { + j4 = k4; + l4 = aint[k4]; + } + } + + double d2 = (d1 - d0) * 4.0D / (double) (i + 4) + ((double) (k1 + j2 & 1) - 0.5D) * 0.4D; + byte b3 = 1; + + if (d2 > 0.6D) { + b3 = 2; + } + + if (d2 < -0.6D) { + b3 = 0; + } + + i5 = 0; + if (j4 > 0) { + MaterialMapColor materialmapcolor = Block.byId[j4].material.C; + + if (materialmapcolor == MaterialMapColor.n) { + d2 = (double) i4 * 0.1D + (double) (k1 + j2 & 1) * 0.2D; + b3 = 1; + if (d2 < 0.5D) { + b3 = 2; + } + + if (d2 > 0.9D) { + b3 = 0; + } + } + + i5 = materialmapcolor.q; + } + + d0 = d1; + if (j2 >= 0 && k2 * k2 + l2 * l2 < j1 * j1 && (!flag || (k1 + j2 & 1) != 0)) { + byte b4 = worldmap.f[k1 + j2 * short1]; + byte b5 = (byte) (i5 * 4 + b3); + + if (b4 != b5) { + if (l1 > j2) { + l1 = j2; + } + + if (i2 < j2) { + i2 = j2; + } + + worldmap.f[k1 + j2 * short1] = b5; + } + } + } + } + + if (l1 <= i2) { + worldmap.a(k1, l1, i2); + } + } + } + } + } + + public void a(ItemStack itemstack, World world, Entity entity, int i, boolean flag) { + if (!world.isStatic) { + WorldMap worldmap = this.a(itemstack, world); + + if (entity instanceof EntityHuman) { + EntityHuman entityhuman = (EntityHuman) entity; + + worldmap.a(entityhuman, itemstack); + } + + if (flag) { + this.a(world, entity, worldmap); + } + } + } + + public void c(ItemStack itemstack, World world, EntityHuman entityhuman) { + itemstack.b(world.b("map")); + String s = "map_" + itemstack.getData(); + WorldMap worldmap = new WorldMap(s); + + world.a(s, (WorldMapBase) worldmap); + worldmap.b = MathHelper.floor(entityhuman.locX); + worldmap.c = MathHelper.floor(entityhuman.locZ); + worldmap.e = 3; + worldmap.map = (byte) ((WorldServer) world).dimension; // CraftBukkit + worldmap.a(); + } + + public Packet b(ItemStack itemstack, World world, EntityHuman entityhuman) { + byte[] abyte = this.a(itemstack, world).a(itemstack, world, entityhuman); + + return abyte == null ? null : new Packet131((short) Item.MAP.id, (short) itemstack.getData(), abyte); + } +} diff --git a/src/main/java/net/minecraft/server/ItemWorldMapBase.java b/src/main/java/net/minecraft/server/ItemWorldMapBase.java new file mode 100644 index 0000000..aa3f665 --- /dev/null +++ b/src/main/java/net/minecraft/server/ItemWorldMapBase.java @@ -0,0 +1,16 @@ +package net.minecraft.server; + +public class ItemWorldMapBase extends Item { + + protected ItemWorldMapBase(int i) { + super(i); + } + + public boolean b() { + return true; + } + + public Packet b(ItemStack itemstack, World world, EntityHuman entityhuman) { + return null; + } +} diff --git a/src/main/java/net/minecraft/server/MapGenBase.java b/src/main/java/net/minecraft/server/MapGenBase.java new file mode 100644 index 0000000..54bb5ce --- /dev/null +++ b/src/main/java/net/minecraft/server/MapGenBase.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +import java.util.Random; + +public class MapGenBase { + + protected int a = 8; + protected Random b = new Random(); + + public MapGenBase() {} + + public void a(IChunkProvider ichunkprovider, World world, int i, int j, byte[] abyte) { + int k = this.a; + + this.b.setSeed(world.getSeed()); + long l = this.b.nextLong() / 2L * 2L + 1L; + long i1 = this.b.nextLong() / 2L * 2L + 1L; + + for (int j1 = i - k; j1 <= i + k; ++j1) { + for (int k1 = j - k; k1 <= j + k; ++k1) { + this.b.setSeed((long) j1 * l + (long) k1 * i1 ^ world.getSeed()); + this.a(world, j1, k1, i, j, abyte); + } + } + } + + protected void a(World world, int i, int j, int k, int l, byte[] abyte) {} +} diff --git a/src/main/java/net/minecraft/server/MapGenCaves.java b/src/main/java/net/minecraft/server/MapGenCaves.java new file mode 100644 index 0000000..5a25b1d --- /dev/null +++ b/src/main/java/net/minecraft/server/MapGenCaves.java @@ -0,0 +1,200 @@ +package net.minecraft.server; + +import java.util.Random; + +public class MapGenCaves extends MapGenBase { + + public MapGenCaves() {} + + protected void a(int i, int j, byte[] abyte, double d0, double d1, double d2) { + this.a(i, j, abyte, d0, d1, d2, 1.0F + this.b.nextFloat() * 6.0F, 0.0F, 0.0F, -1, -1, 0.5D); + } + + protected void a(int i, int j, byte[] abyte, double d0, double d1, double d2, float f, float f1, float f2, int k, int l, double d3) { + double d4 = (double) (i * 16 + 8); + double d5 = (double) (j * 16 + 8); + float f3 = 0.0F; + float f4 = 0.0F; + Random random = new Random(this.b.nextLong()); + + if (l <= 0) { + int i1 = this.a * 16 - 16; + + l = i1 - random.nextInt(i1 / 4); + } + + boolean flag = false; + + if (k == -1) { + k = l / 2; + flag = true; + } + + int j1 = random.nextInt(l / 2) + l / 4; + + for (boolean flag1 = random.nextInt(6) == 0; k < l; ++k) { + double d6 = 1.5D + (double) (MathHelper.sin((float) k * 3.1415927F / (float) l) * f * 1.0F); + double d7 = d6 * d3; + float f5 = MathHelper.cos(f2); + float f6 = MathHelper.sin(f2); + + d0 += (double) (MathHelper.cos(f1) * f5); + d1 += (double) f6; + d2 += (double) (MathHelper.sin(f1) * f5); + if (flag1) { + f2 *= 0.92F; + } else { + f2 *= 0.7F; + } + + f2 += f4 * 0.1F; + f1 += f3 * 0.1F; + f4 *= 0.9F; + f3 *= 0.75F; + f4 += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2.0F; + f3 += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4.0F; + if (!flag && k == j1 && f > 1.0F) { + this.a(i, j, abyte, d0, d1, d2, random.nextFloat() * 0.5F + 0.5F, f1 - 1.5707964F, f2 / 3.0F, k, l, 1.0D); + this.a(i, j, abyte, d0, d1, d2, random.nextFloat() * 0.5F + 0.5F, f1 + 1.5707964F, f2 / 3.0F, k, l, 1.0D); + return; + } + + if (flag || random.nextInt(4) != 0) { + double d8 = d0 - d4; + double d9 = d2 - d5; + double d10 = (double) (l - k); + double d11 = (double) (f + 2.0F + 16.0F); + + if (d8 * d8 + d9 * d9 - d10 * d10 > d11 * d11) { + return; + } + + if (d0 >= d4 - 16.0D - d6 * 2.0D && d2 >= d5 - 16.0D - d6 * 2.0D && d0 <= d4 + 16.0D + d6 * 2.0D && d2 <= d5 + 16.0D + d6 * 2.0D) { + int k1 = MathHelper.floor(d0 - d6) - i * 16 - 1; + int l1 = MathHelper.floor(d0 + d6) - i * 16 + 1; + int i2 = MathHelper.floor(d1 - d7) - 1; + int j2 = MathHelper.floor(d1 + d7) + 1; + int k2 = MathHelper.floor(d2 - d6) - j * 16 - 1; + int l2 = MathHelper.floor(d2 + d6) - j * 16 + 1; + + if (k1 < 0) { + k1 = 0; + } + + if (l1 > 16) { + l1 = 16; + } + + if (i2 < 1) { + i2 = 1; + } + + if (j2 > 120) { + j2 = 120; + } + + if (k2 < 0) { + k2 = 0; + } + + if (l2 > 16) { + l2 = 16; + } + + boolean flag2 = false; + + int i3; + int j3; + + for (j3 = k1; !flag2 && j3 < l1; ++j3) { + for (int k3 = k2; !flag2 && k3 < l2; ++k3) { + for (int l3 = j2 + 1; !flag2 && l3 >= i2 - 1; --l3) { + i3 = (j3 * 16 + k3) * 128 + l3; + if (l3 >= 0 && l3 < 128) { + if (abyte[i3] == Block.WATER.id || abyte[i3] == Block.STATIONARY_WATER.id) { + flag2 = true; + } + + if (l3 != i2 - 1 && j3 != k1 && j3 != l1 - 1 && k3 != k2 && k3 != l2 - 1) { + l3 = i2; + } + } + } + } + } + + if (!flag2) { + for (j3 = k1; j3 < l1; ++j3) { + double d12 = ((double) (j3 + i * 16) + 0.5D - d0) / d6; + + for (i3 = k2; i3 < l2; ++i3) { + double d13 = ((double) (i3 + j * 16) + 0.5D - d2) / d6; + int i4 = (j3 * 16 + i3) * 128 + j2; + boolean flag3 = false; + + if (d12 * d12 + d13 * d13 < 1.0D) { + for (int j4 = j2 - 1; j4 >= i2; --j4) { + double d14 = ((double) j4 + 0.5D - d1) / d7; + + if (d14 > -0.7D && d12 * d12 + d14 * d14 + d13 * d13 < 1.0D) { + byte b0 = abyte[i4]; + + if (b0 == Block.GRASS.id) { + flag3 = true; + } + + if (b0 == Block.STONE.id || b0 == Block.DIRT.id || b0 == Block.GRASS.id) { + if (j4 < 10) { + abyte[i4] = (byte) Block.LAVA.id; + } else { + abyte[i4] = 0; + if (flag3 && abyte[i4 - 1] == Block.DIRT.id) { + abyte[i4 - 1] = (byte) Block.GRASS.id; + } + } + } + } + + --i4; + } + } + } + } + + if (flag) { + break; + } + } + } + } + } + } + + protected void a(World world, int i, int j, int k, int l, byte[] abyte) { + int i1 = this.b.nextInt(this.b.nextInt(this.b.nextInt(40) + 1) + 1); + + if (this.b.nextInt(15) != 0) { + i1 = 0; + } + + for (int j1 = 0; j1 < i1; ++j1) { + double d0 = (double) (i * 16 + this.b.nextInt(16)); + double d1 = (double) this.b.nextInt(this.b.nextInt(120) + 8); + double d2 = (double) (j * 16 + this.b.nextInt(16)); + int k1 = 1; + + if (this.b.nextInt(4) == 0) { + this.a(k, l, abyte, d0, d1, d2); + k1 += this.b.nextInt(4); + } + + for (int l1 = 0; l1 < k1; ++l1) { + float f = this.b.nextFloat() * 3.1415927F * 2.0F; + float f1 = (this.b.nextFloat() - 0.5F) * 2.0F / 8.0F; + float f2 = this.b.nextFloat() * 2.0F + this.b.nextFloat(); + + this.a(k, l, abyte, d0, d1, d2, f2, f, f1, 0, 0, 1.0D); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/MapGenCavesHell.java b/src/main/java/net/minecraft/server/MapGenCavesHell.java new file mode 100644 index 0000000..37d55d9 --- /dev/null +++ b/src/main/java/net/minecraft/server/MapGenCavesHell.java @@ -0,0 +1,186 @@ +package net.minecraft.server; + +import java.util.Random; + +public class MapGenCavesHell extends MapGenBase { + + public MapGenCavesHell() {} + + protected void a(int i, int j, byte[] abyte, double d0, double d1, double d2) { + this.a(i, j, abyte, d0, d1, d2, 1.0F + this.b.nextFloat() * 6.0F, 0.0F, 0.0F, -1, -1, 0.5D); + } + + protected void a(int i, int j, byte[] abyte, double d0, double d1, double d2, float f, float f1, float f2, int k, int l, double d3) { + double d4 = (double) (i * 16 + 8); + double d5 = (double) (j * 16 + 8); + float f3 = 0.0F; + float f4 = 0.0F; + Random random = new Random(this.b.nextLong()); + + if (l <= 0) { + int i1 = this.a * 16 - 16; + + l = i1 - random.nextInt(i1 / 4); + } + + boolean flag = false; + + if (k == -1) { + k = l / 2; + flag = true; + } + + int j1 = random.nextInt(l / 2) + l / 4; + + for (boolean flag1 = random.nextInt(6) == 0; k < l; ++k) { + double d6 = 1.5D + (double) (MathHelper.sin((float) k * 3.1415927F / (float) l) * f * 1.0F); + double d7 = d6 * d3; + float f5 = MathHelper.cos(f2); + float f6 = MathHelper.sin(f2); + + d0 += (double) (MathHelper.cos(f1) * f5); + d1 += (double) f6; + d2 += (double) (MathHelper.sin(f1) * f5); + if (flag1) { + f2 *= 0.92F; + } else { + f2 *= 0.7F; + } + + f2 += f4 * 0.1F; + f1 += f3 * 0.1F; + f4 *= 0.9F; + f3 *= 0.75F; + f4 += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2.0F; + f3 += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4.0F; + if (!flag && k == j1 && f > 1.0F) { + this.a(i, j, abyte, d0, d1, d2, random.nextFloat() * 0.5F + 0.5F, f1 - 1.5707964F, f2 / 3.0F, k, l, 1.0D); + this.a(i, j, abyte, d0, d1, d2, random.nextFloat() * 0.5F + 0.5F, f1 + 1.5707964F, f2 / 3.0F, k, l, 1.0D); + return; + } + + if (flag || random.nextInt(4) != 0) { + double d8 = d0 - d4; + double d9 = d2 - d5; + double d10 = (double) (l - k); + double d11 = (double) (f + 2.0F + 16.0F); + + if (d8 * d8 + d9 * d9 - d10 * d10 > d11 * d11) { + return; + } + + if (d0 >= d4 - 16.0D - d6 * 2.0D && d2 >= d5 - 16.0D - d6 * 2.0D && d0 <= d4 + 16.0D + d6 * 2.0D && d2 <= d5 + 16.0D + d6 * 2.0D) { + int k1 = MathHelper.floor(d0 - d6) - i * 16 - 1; + int l1 = MathHelper.floor(d0 + d6) - i * 16 + 1; + int i2 = MathHelper.floor(d1 - d7) - 1; + int j2 = MathHelper.floor(d1 + d7) + 1; + int k2 = MathHelper.floor(d2 - d6) - j * 16 - 1; + int l2 = MathHelper.floor(d2 + d6) - j * 16 + 1; + + if (k1 < 0) { + k1 = 0; + } + + if (l1 > 16) { + l1 = 16; + } + + if (i2 < 1) { + i2 = 1; + } + + if (j2 > 120) { + j2 = 120; + } + + if (k2 < 0) { + k2 = 0; + } + + if (l2 > 16) { + l2 = 16; + } + + boolean flag2 = false; + + int i3; + int j3; + + for (j3 = k1; !flag2 && j3 < l1; ++j3) { + for (int k3 = k2; !flag2 && k3 < l2; ++k3) { + for (int l3 = j2 + 1; !flag2 && l3 >= i2 - 1; --l3) { + i3 = (j3 * 16 + k3) * 128 + l3; + if (l3 >= 0 && l3 < 128) { + if (abyte[i3] == Block.LAVA.id || abyte[i3] == Block.STATIONARY_LAVA.id) { + flag2 = true; + } + + if (l3 != i2 - 1 && j3 != k1 && j3 != l1 - 1 && k3 != k2 && k3 != l2 - 1) { + l3 = i2; + } + } + } + } + } + + if (!flag2) { + for (j3 = k1; j3 < l1; ++j3) { + double d12 = ((double) (j3 + i * 16) + 0.5D - d0) / d6; + + for (i3 = k2; i3 < l2; ++i3) { + double d13 = ((double) (i3 + j * 16) + 0.5D - d2) / d6; + int i4 = (j3 * 16 + i3) * 128 + j2; + + for (int j4 = j2 - 1; j4 >= i2; --j4) { + double d14 = ((double) j4 + 0.5D - d1) / d7; + + if (d14 > -0.7D && d12 * d12 + d14 * d14 + d13 * d13 < 1.0D) { + byte b0 = abyte[i4]; + + if (b0 == Block.NETHERRACK.id || b0 == Block.DIRT.id || b0 == Block.GRASS.id) { + abyte[i4] = 0; + } + } + + --i4; + } + } + } + + if (flag) { + break; + } + } + } + } + } + } + + protected void a(World world, int i, int j, int k, int l, byte[] abyte) { + int i1 = this.b.nextInt(this.b.nextInt(this.b.nextInt(10) + 1) + 1); + + if (this.b.nextInt(5) != 0) { + i1 = 0; + } + + for (int j1 = 0; j1 < i1; ++j1) { + double d0 = (double) (i * 16 + this.b.nextInt(16)); + double d1 = (double) this.b.nextInt(128); + double d2 = (double) (j * 16 + this.b.nextInt(16)); + int k1 = 1; + + if (this.b.nextInt(4) == 0) { + this.a(k, l, abyte, d0, d1, d2); + k1 += this.b.nextInt(4); + } + + for (int l1 = 0; l1 < k1; ++l1) { + float f = this.b.nextFloat() * 3.1415927F * 2.0F; + float f1 = (this.b.nextFloat() - 0.5F) * 2.0F / 8.0F; + float f2 = this.b.nextFloat() * 2.0F + this.b.nextFloat(); + + this.a(k, l, abyte, d0, d1, d2, f2 * 2.0F, f, f1, 0, 0, 0.5D); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/Material.java b/src/main/java/net/minecraft/server/Material.java new file mode 100644 index 0000000..d525b3d --- /dev/null +++ b/src/main/java/net/minecraft/server/Material.java @@ -0,0 +1,109 @@ +package net.minecraft.server; + +public class Material { + + public static final Material AIR = new MaterialTransparent(MaterialMapColor.b); + public static final Material GRASS = new Material(MaterialMapColor.c); + public static final Material EARTH = new Material(MaterialMapColor.l); + public static final Material WOOD = (new Material(MaterialMapColor.o)).o(); + public static final Material STONE = (new Material(MaterialMapColor.m)).n(); + public static final Material ORE = (new Material(MaterialMapColor.h)).n(); + public static final Material WATER = (new MaterialLiquid(MaterialMapColor.n)).k(); + public static final Material LAVA = (new MaterialLiquid(MaterialMapColor.f)).k(); + public static final Material LEAVES = (new Material(MaterialMapColor.i)).o().m().k(); + public static final Material PLANT = (new MaterialLogic(MaterialMapColor.i)).k(); + public static final Material SPONGE = new Material(MaterialMapColor.e); + public static final Material CLOTH = (new Material(MaterialMapColor.e)).o(); + public static final Material FIRE = (new MaterialTransparent(MaterialMapColor.b)).k(); + public static final Material SAND = new Material(MaterialMapColor.d); + public static final Material ORIENTABLE = (new MaterialLogic(MaterialMapColor.b)).k(); + public static final Material SHATTERABLE = (new Material(MaterialMapColor.b)).m(); + public static final Material TNT = (new Material(MaterialMapColor.f)).o().m(); + public static final Material CORAL = (new Material(MaterialMapColor.i)).k(); + public static final Material ICE = (new Material(MaterialMapColor.g)).m(); + public static final Material SNOW_LAYER = (new MaterialLogic(MaterialMapColor.j)).f().m().n().k(); + public static final Material SNOW_BLOCK = (new Material(MaterialMapColor.j)).n(); + public static final Material CACTUS = (new Material(MaterialMapColor.i)).m().k(); + public static final Material CLAY = new Material(MaterialMapColor.k); + public static final Material PUMPKIN = (new Material(MaterialMapColor.i)).k(); + public static final Material PORTAL = (new MaterialPortal(MaterialMapColor.b)).l(); + public static final Material CAKE = (new Material(MaterialMapColor.b)).k(); + public static final Material WEB = (new Material(MaterialMapColor.e)).n().k(); + public static final Material PISTON = (new Material(MaterialMapColor.m)).l(); + private boolean canBurn; + private boolean E; + private boolean F; + public final MaterialMapColor C; + private boolean G = true; + private int H; + + public Material(MaterialMapColor materialmapcolor) { + this.C = materialmapcolor; + } + + public boolean isLiquid() { + return false; + } + + public boolean isBuildable() { + return true; + } + + public boolean blocksLight() { + return true; + } + + public boolean isSolid() { + return true; + } + + private Material m() { + this.F = true; + return this; + } + + private Material n() { + this.G = false; + return this; + } + + private Material o() { + this.canBurn = true; + return this; + } + + public boolean isBurnable() { + return this.canBurn; + } + + public Material f() { + this.E = true; + return this; + } + + public boolean isReplacable() { + return this.E; + } + + public boolean h() { + return this.F ? false : this.isSolid(); + } + + public boolean i() { + return this.G; + } + + public int j() { + return this.H; + } + + protected Material k() { + this.H = 1; + return this; + } + + protected Material l() { + this.H = 2; + return this; + } +} diff --git a/src/main/java/net/minecraft/server/MaterialLiquid.java b/src/main/java/net/minecraft/server/MaterialLiquid.java new file mode 100644 index 0000000..1670104 --- /dev/null +++ b/src/main/java/net/minecraft/server/MaterialLiquid.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +public class MaterialLiquid extends Material { + + public MaterialLiquid(MaterialMapColor materialmapcolor) { + super(materialmapcolor); + this.f(); + this.k(); + } + + public boolean isLiquid() { + return true; + } + + public boolean isSolid() { + return false; + } + + public boolean isBuildable() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/MaterialLogic.java b/src/main/java/net/minecraft/server/MaterialLogic.java new file mode 100644 index 0000000..43952d4 --- /dev/null +++ b/src/main/java/net/minecraft/server/MaterialLogic.java @@ -0,0 +1,20 @@ +package net.minecraft.server; + +public class MaterialLogic extends Material { + + public MaterialLogic(MaterialMapColor materialmapcolor) { + super(materialmapcolor); + } + + public boolean isBuildable() { + return false; + } + + public boolean blocksLight() { + return false; + } + + public boolean isSolid() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/MaterialMapColor.java b/src/main/java/net/minecraft/server/MaterialMapColor.java new file mode 100644 index 0000000..7419aeb --- /dev/null +++ b/src/main/java/net/minecraft/server/MaterialMapColor.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +public class MaterialMapColor { + + public static final MaterialMapColor[] a = new MaterialMapColor[16]; + public static final MaterialMapColor b = new MaterialMapColor(0, 0); + public static final MaterialMapColor c = new MaterialMapColor(1, 8368696); + public static final MaterialMapColor d = new MaterialMapColor(2, 16247203); + public static final MaterialMapColor e = new MaterialMapColor(3, 10987431); + public static final MaterialMapColor f = new MaterialMapColor(4, 16711680); + public static final MaterialMapColor g = new MaterialMapColor(5, 10526975); + public static final MaterialMapColor h = new MaterialMapColor(6, 10987431); + public static final MaterialMapColor i = new MaterialMapColor(7, 31744); + public static final MaterialMapColor j = new MaterialMapColor(8, 16777215); + public static final MaterialMapColor k = new MaterialMapColor(9, 10791096); + public static final MaterialMapColor l = new MaterialMapColor(10, 12020271); + public static final MaterialMapColor m = new MaterialMapColor(11, 7368816); + public static final MaterialMapColor n = new MaterialMapColor(12, 4210943); + public static final MaterialMapColor o = new MaterialMapColor(13, 6837042); + public final int p; + public final int q; + + private MaterialMapColor(int i, int j) { + this.q = i; + this.p = j; + a[i] = this; + } +} diff --git a/src/main/java/net/minecraft/server/MaterialPortal.java b/src/main/java/net/minecraft/server/MaterialPortal.java new file mode 100644 index 0000000..4f3ab40 --- /dev/null +++ b/src/main/java/net/minecraft/server/MaterialPortal.java @@ -0,0 +1,20 @@ +package net.minecraft.server; + +public class MaterialPortal extends Material { + + public MaterialPortal(MaterialMapColor materialmapcolor) { + super(materialmapcolor); + } + + public boolean isBuildable() { + return false; + } + + public boolean blocksLight() { + return false; + } + + public boolean isSolid() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/MaterialTransparent.java b/src/main/java/net/minecraft/server/MaterialTransparent.java new file mode 100644 index 0000000..378cb89 --- /dev/null +++ b/src/main/java/net/minecraft/server/MaterialTransparent.java @@ -0,0 +1,21 @@ +package net.minecraft.server; + +public class MaterialTransparent extends Material { + + public MaterialTransparent(MaterialMapColor materialmapcolor) { + super(materialmapcolor); + this.f(); + } + + public boolean isBuildable() { + return false; + } + + public boolean blocksLight() { + return false; + } + + public boolean isSolid() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/MathHelper.java b/src/main/java/net/minecraft/server/MathHelper.java new file mode 100644 index 0000000..b152f57 --- /dev/null +++ b/src/main/java/net/minecraft/server/MathHelper.java @@ -0,0 +1,58 @@ +package net.minecraft.server; + +public class MathHelper { + + private static float[] a = new float[65536]; + + public MathHelper() {} + + public static final float sin(float f) { + return a[(int) (f * 10430.378F) & '\uffff']; + } + + public static final float cos(float f) { + return a[(int) (f * 10430.378F + 16384.0F) & '\uffff']; + } + + public static final float c(float f) { + return (float) Math.sqrt((double) f); + } + + public static final float a(double d0) { + return (float) Math.sqrt(d0); + } + + public static int d(float f) { + int i = (int) f; + + return f < (float) i ? i - 1 : i; + } + + public static int floor(double d0) { + int i = (int) d0; + + return d0 < (double) i ? i - 1 : i; + } + + public static float abs(float f) { + return f >= 0.0F ? f : -f; + } + + public static double a(double d0, double d1) { + if (d0 < 0.0D) { + d0 = -d0; + } + + if (d1 < 0.0D) { + d1 = -d1; + } + + return d0 > d1 ? d0 : d1; + } + + static { + for (int i = 0; i < 65536; ++i) { + a[i] = (float) Math.sin((double) i * 3.141592653589793D * 2.0D / 65536.0D); + } + } +} diff --git a/src/main/java/net/minecraft/server/MetadataChunkBlock.java b/src/main/java/net/minecraft/server/MetadataChunkBlock.java new file mode 100644 index 0000000..17cd406 --- /dev/null +++ b/src/main/java/net/minecraft/server/MetadataChunkBlock.java @@ -0,0 +1,217 @@ +package net.minecraft.server; + +public class MetadataChunkBlock { + + public final EnumSkyBlock a; + public int b; + public int c; + public int d; + public int e; + public int f; + public int g; + + public MetadataChunkBlock(EnumSkyBlock enumskyblock, int i, int j, int k, int l, int i1, int j1) { + this.a = enumskyblock; + this.b = i; + this.c = j; + this.d = k; + this.e = l; + this.f = i1; + this.g = j1; + } + + public void a(World world) { + int i = this.e - this.b + 1; + int j = this.f - this.c + 1; + int k = this.g - this.d + 1; + int l = i * j * k; + + if (l > '\u8000') { + System.out.println("Light too large, skipping!"); + } else { + int i1 = 0; + int j1 = 0; + boolean flag = false; + boolean flag1 = false; + + for (int k1 = this.b; k1 <= this.e; ++k1) { + for (int l1 = this.d; l1 <= this.g; ++l1) { + int i2 = k1 >> 4; + int j2 = l1 >> 4; + boolean flag2 = false; + + if (flag && i2 == i1 && j2 == j1) { + flag2 = flag1; + } else { + flag2 = world.areChunksLoaded(k1, 0, l1, 1); + if (flag2) { + Chunk chunk = world.getChunkAt(k1 >> 4, l1 >> 4); + + if (chunk.isEmpty()) { + flag2 = false; + } + } + + flag1 = flag2; + i1 = i2; + j1 = j2; + } + + if (flag2) { + if (this.c < 0) { + this.c = 0; + } + + if (this.f >= 128) { + this.f = 127; + } + + for (int k2 = this.c; k2 <= this.f; ++k2) { + int l2 = world.a(this.a, k1, k2, l1); + boolean flag3 = false; + int i3 = world.getTypeId(k1, k2, l1); + int j3 = Block.q[i3]; + + if (j3 == 0) { + j3 = 1; + } + + int k3 = 0; + + if (this.a == EnumSkyBlock.SKY) { + if (world.m(k1, k2, l1)) { + k3 = 15; + } + } else if (this.a == EnumSkyBlock.BLOCK) { + k3 = Block.s[i3]; + } + + int l3; + int i4; + + if (j3 >= 15 && k3 == 0) { + i4 = 0; + } else { + l3 = world.a(this.a, k1 - 1, k2, l1); + int j4 = world.a(this.a, k1 + 1, k2, l1); + int k4 = world.a(this.a, k1, k2 - 1, l1); + int l4 = world.a(this.a, k1, k2 + 1, l1); + int i5 = world.a(this.a, k1, k2, l1 - 1); + int j5 = world.a(this.a, k1, k2, l1 + 1); + + i4 = l3; + if (j4 > l3) { + i4 = j4; + } + + if (k4 > i4) { + i4 = k4; + } + + if (l4 > i4) { + i4 = l4; + } + + if (i5 > i4) { + i4 = i5; + } + + if (j5 > i4) { + i4 = j5; + } + + i4 -= j3; + if (i4 < 0) { + i4 = 0; + } + + if (k3 > i4) { + i4 = k3; + } + } + + if (l2 != i4) { + world.b(this.a, k1, k2, l1, i4); + l3 = i4 - 1; + if (l3 < 0) { + l3 = 0; + } + + world.a(this.a, k1 - 1, k2, l1, l3); + world.a(this.a, k1, k2 - 1, l1, l3); + world.a(this.a, k1, k2, l1 - 1, l3); + if (k1 + 1 >= this.e) { + world.a(this.a, k1 + 1, k2, l1, l3); + } + + if (k2 + 1 >= this.f) { + world.a(this.a, k1, k2 + 1, l1, l3); + } + + if (l1 + 1 >= this.g) { + world.a(this.a, k1, k2, l1 + 1, l3); + } + } + } + } + } + } + } + } + + public boolean a(int i, int j, int k, int l, int i1, int j1) { + if (i >= this.b && j >= this.c && k >= this.d && l <= this.e && i1 <= this.f && j1 <= this.g) { + return true; + } else { + byte b0 = 1; + + if (i >= this.b - b0 && j >= this.c - b0 && k >= this.d - b0 && l <= this.e + b0 && i1 <= this.f + b0 && j1 <= this.g + b0) { + int k1 = this.e - this.b; + int l1 = this.f - this.c; + int i2 = this.g - this.d; + + if (i > this.b) { + i = this.b; + } + + if (j > this.c) { + j = this.c; + } + + if (k > this.d) { + k = this.d; + } + + if (l < this.e) { + l = this.e; + } + + if (i1 < this.f) { + i1 = this.f; + } + + if (j1 < this.g) { + j1 = this.g; + } + + int j2 = l - i; + int k2 = i1 - j; + int l2 = j1 - k; + int i3 = k1 * l1 * i2; + int j3 = j2 * k2 * l2; + + if (j3 - i3 <= 2) { + this.b = i; + this.c = j; + this.d = k; + this.e = l; + this.f = i1; + this.g = j1; + return true; + } + } + + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/MinecartTrackLogic.java b/src/main/java/net/minecraft/server/MinecartTrackLogic.java new file mode 100644 index 0000000..aa5d8a7 --- /dev/null +++ b/src/main/java/net/minecraft/server/MinecartTrackLogic.java @@ -0,0 +1,359 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +class MinecartTrackLogic { + + private World b; + private int c; + private int d; + private int e; + private final boolean f; + private List g; + + final BlockMinecartTrack a; + + public MinecartTrackLogic(BlockMinecartTrack blockminecarttrack, World world, int i, int j, int k) { + this.a = blockminecarttrack; + this.g = new ArrayList(); + this.b = world; + this.c = i; + this.d = j; + this.e = k; + int l = world.getTypeId(i, j, k); + int i1 = world.getData(i, j, k); + + if (BlockMinecartTrack.a((BlockMinecartTrack) Block.byId[l])) { + this.f = true; + i1 &= -9; + } else { + this.f = false; + } + + this.a(i1); + } + + private void a(int i) { + this.g.clear(); + if (i == 0) { + this.g.add(new ChunkPosition(this.c, this.d, this.e - 1)); + this.g.add(new ChunkPosition(this.c, this.d, this.e + 1)); + } else if (i == 1) { + this.g.add(new ChunkPosition(this.c - 1, this.d, this.e)); + this.g.add(new ChunkPosition(this.c + 1, this.d, this.e)); + } else if (i == 2) { + this.g.add(new ChunkPosition(this.c - 1, this.d, this.e)); + this.g.add(new ChunkPosition(this.c + 1, this.d + 1, this.e)); + } else if (i == 3) { + this.g.add(new ChunkPosition(this.c - 1, this.d + 1, this.e)); + this.g.add(new ChunkPosition(this.c + 1, this.d, this.e)); + } else if (i == 4) { + this.g.add(new ChunkPosition(this.c, this.d + 1, this.e - 1)); + this.g.add(new ChunkPosition(this.c, this.d, this.e + 1)); + } else if (i == 5) { + this.g.add(new ChunkPosition(this.c, this.d, this.e - 1)); + this.g.add(new ChunkPosition(this.c, this.d + 1, this.e + 1)); + } else if (i == 6) { + this.g.add(new ChunkPosition(this.c + 1, this.d, this.e)); + this.g.add(new ChunkPosition(this.c, this.d, this.e + 1)); + } else if (i == 7) { + this.g.add(new ChunkPosition(this.c - 1, this.d, this.e)); + this.g.add(new ChunkPosition(this.c, this.d, this.e + 1)); + } else if (i == 8) { + this.g.add(new ChunkPosition(this.c - 1, this.d, this.e)); + this.g.add(new ChunkPosition(this.c, this.d, this.e - 1)); + } else if (i == 9) { + this.g.add(new ChunkPosition(this.c + 1, this.d, this.e)); + this.g.add(new ChunkPosition(this.c, this.d, this.e - 1)); + } + } + + private void a() { + for (int i = 0; i < this.g.size(); ++i) { + MinecartTrackLogic minecarttracklogic = this.a((ChunkPosition) this.g.get(i)); + + if (minecarttracklogic != null && minecarttracklogic.b(this)) { + this.g.set(i, new ChunkPosition(minecarttracklogic.c, minecarttracklogic.d, minecarttracklogic.e)); + } else { + this.g.remove(i--); + } + } + } + + private boolean a(int i, int j, int k) { + return BlockMinecartTrack.g(this.b, i, j, k) ? true : (BlockMinecartTrack.g(this.b, i, j + 1, k) ? true : BlockMinecartTrack.g(this.b, i, j - 1, k)); + } + + private MinecartTrackLogic a(ChunkPosition chunkposition) { + return BlockMinecartTrack.g(this.b, chunkposition.x, chunkposition.y, chunkposition.z) ? new MinecartTrackLogic(this.a, this.b, chunkposition.x, chunkposition.y, chunkposition.z) : (BlockMinecartTrack.g(this.b, chunkposition.x, chunkposition.y + 1, chunkposition.z) ? new MinecartTrackLogic(this.a, this.b, chunkposition.x, chunkposition.y + 1, chunkposition.z) : (BlockMinecartTrack.g(this.b, chunkposition.x, chunkposition.y - 1, chunkposition.z) ? new MinecartTrackLogic(this.a, this.b, chunkposition.x, chunkposition.y - 1, chunkposition.z) : null)); + } + + private boolean b(MinecartTrackLogic minecarttracklogic) { + for (int i = 0; i < this.g.size(); ++i) { + ChunkPosition chunkposition = (ChunkPosition) this.g.get(i); + + if (chunkposition.x == minecarttracklogic.c && chunkposition.z == minecarttracklogic.e) { + return true; + } + } + + return false; + } + + private boolean b(int i, int j, int k) { + for (int l = 0; l < this.g.size(); ++l) { + ChunkPosition chunkposition = (ChunkPosition) this.g.get(l); + + if (chunkposition.x == i && chunkposition.z == k) { + return true; + } + } + + return false; + } + + private int b() { + int i = 0; + + if (this.a(this.c, this.d, this.e - 1)) { + ++i; + } + + if (this.a(this.c, this.d, this.e + 1)) { + ++i; + } + + if (this.a(this.c - 1, this.d, this.e)) { + ++i; + } + + if (this.a(this.c + 1, this.d, this.e)) { + ++i; + } + + return i; + } + + private boolean c(MinecartTrackLogic minecarttracklogic) { + if (this.b(minecarttracklogic)) { + return true; + } else if (this.g.size() == 2) { + return false; + } else if (this.g.size() == 0) { + return true; + } else { + ChunkPosition chunkposition = (ChunkPosition) this.g.get(0); + + return minecarttracklogic.d == this.d && chunkposition.y == this.d ? true : true; + } + } + + private void d(MinecartTrackLogic minecarttracklogic) { + this.g.add(new ChunkPosition(minecarttracklogic.c, minecarttracklogic.d, minecarttracklogic.e)); + boolean flag = this.b(this.c, this.d, this.e - 1); + boolean flag1 = this.b(this.c, this.d, this.e + 1); + boolean flag2 = this.b(this.c - 1, this.d, this.e); + boolean flag3 = this.b(this.c + 1, this.d, this.e); + byte b0 = -1; + + if (flag || flag1) { + b0 = 0; + } + + if (flag2 || flag3) { + b0 = 1; + } + + if (!this.f) { + if (flag1 && flag3 && !flag && !flag2) { + b0 = 6; + } + + if (flag1 && flag2 && !flag && !flag3) { + b0 = 7; + } + + if (flag && flag2 && !flag1 && !flag3) { + b0 = 8; + } + + if (flag && flag3 && !flag1 && !flag2) { + b0 = 9; + } + } + + if (b0 == 0) { + if (BlockMinecartTrack.g(this.b, this.c, this.d + 1, this.e - 1)) { + b0 = 4; + } + + if (BlockMinecartTrack.g(this.b, this.c, this.d + 1, this.e + 1)) { + b0 = 5; + } + } + + if (b0 == 1) { + if (BlockMinecartTrack.g(this.b, this.c + 1, this.d + 1, this.e)) { + b0 = 2; + } + + if (BlockMinecartTrack.g(this.b, this.c - 1, this.d + 1, this.e)) { + b0 = 3; + } + } + + if (b0 < 0) { + b0 = 0; + } + + int i = b0; + + if (this.f) { + i = this.b.getData(this.c, this.d, this.e) & 8 | b0; + } + + this.b.setData(this.c, this.d, this.e, i); + } + + private boolean c(int i, int j, int k) { + MinecartTrackLogic minecarttracklogic = this.a(new ChunkPosition(i, j, k)); + + if (minecarttracklogic == null) { + return false; + } else { + minecarttracklogic.a(); + return minecarttracklogic.c(this); + } + } + + public void a(boolean flag, boolean flag1) { + boolean flag2 = this.c(this.c, this.d, this.e - 1); + boolean flag3 = this.c(this.c, this.d, this.e + 1); + boolean flag4 = this.c(this.c - 1, this.d, this.e); + boolean flag5 = this.c(this.c + 1, this.d, this.e); + byte b0 = -1; + + if ((flag2 || flag3) && !flag4 && !flag5) { + b0 = 0; + } + + if ((flag4 || flag5) && !flag2 && !flag3) { + b0 = 1; + } + + if (!this.f) { + if (flag3 && flag5 && !flag2 && !flag4) { + b0 = 6; + } + + if (flag3 && flag4 && !flag2 && !flag5) { + b0 = 7; + } + + if (flag2 && flag4 && !flag3 && !flag5) { + b0 = 8; + } + + if (flag2 && flag5 && !flag3 && !flag4) { + b0 = 9; + } + } + + if (b0 == -1) { + if (flag2 || flag3) { + b0 = 0; + } + + if (flag4 || flag5) { + b0 = 1; + } + + if (!this.f) { + if (flag) { + if (flag3 && flag5) { + b0 = 6; + } + + if (flag4 && flag3) { + b0 = 7; + } + + if (flag5 && flag2) { + b0 = 9; + } + + if (flag2 && flag4) { + b0 = 8; + } + } else { + if (flag2 && flag4) { + b0 = 8; + } + + if (flag5 && flag2) { + b0 = 9; + } + + if (flag4 && flag3) { + b0 = 7; + } + + if (flag3 && flag5) { + b0 = 6; + } + } + } + } + + if (b0 == 0) { + if (BlockMinecartTrack.g(this.b, this.c, this.d + 1, this.e - 1)) { + b0 = 4; + } + + if (BlockMinecartTrack.g(this.b, this.c, this.d + 1, this.e + 1)) { + b0 = 5; + } + } + + if (b0 == 1) { + if (BlockMinecartTrack.g(this.b, this.c + 1, this.d + 1, this.e)) { + b0 = 2; + } + + if (BlockMinecartTrack.g(this.b, this.c - 1, this.d + 1, this.e)) { + b0 = 3; + } + } + + if (b0 < 0) { + b0 = 0; + } + + this.a(b0); + int i = b0; + + if (this.f) { + i = this.b.getData(this.c, this.d, this.e) & 8 | b0; + } + + if (flag1 || this.b.getData(this.c, this.d, this.e) != i) { + this.b.setData(this.c, this.d, this.e, i); + + for (int j = 0; j < this.g.size(); ++j) { + MinecartTrackLogic minecarttracklogic = this.a((ChunkPosition) this.g.get(j)); + + if (minecarttracklogic != null) { + minecarttracklogic.a(); + if (minecarttracklogic.c(this)) { + minecarttracklogic.d(this); + } + } + } + } + } + + static int a(MinecartTrackLogic minecarttracklogic) { + return minecarttracklogic.b(); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftException.java b/src/main/java/net/minecraft/server/MinecraftException.java new file mode 100644 index 0000000..74f2d40 --- /dev/null +++ b/src/main/java/net/minecraft/server/MinecraftException.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +public class MinecraftException extends RuntimeException { + + public MinecraftException(String s) { + super(s); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java new file mode 100644 index 0000000..1b94ced --- /dev/null +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -0,0 +1,710 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.Poseidon; +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.PoseidonPlugin; +import com.legacyminecraft.poseidon.util.ServerLogRotator; +import com.legacyminecraft.poseidon.utility.PerformanceStatistic; +import com.legacyminecraft.poseidon.utility.PoseidonVersionChecker; +import com.projectposeidon.johnymuffin.UUIDManager; +import com.legacyminecraft.poseidon.watchdog.WatchDogThread; +import jline.ConsoleReader; +import joptsimple.OptionSet; +import org.bukkit.Bukkit; +import org.bukkit.World.Environment; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.LoggerOutputStream; +import org.bukkit.craftbukkit.command.ColouredConsoleSender; +import org.bukkit.craftbukkit.scheduler.CraftScheduler; +import org.bukkit.craftbukkit.util.ServerShutdownThread; +import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.event.world.WorldInitEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldSaveEvent; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.plugin.PluginLoadOrder; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +// CraftBukkit start +//import com.projectposeidon.johnymuffin.UUIDCacheFile; +// CraftBukkit end + +public class MinecraftServer implements Runnable, ICommandListener { + + public static Logger log = Logger.getLogger("Minecraft"); + public static HashMap trackerList = new HashMap(); + public NetworkListenThread networkListenThread; + public PropertyManager propertyManager; + // public WorldServer[] worldServer; // CraftBukkit - removed! + public ServerConfigurationManager serverConfigurationManager; + public ConsoleCommandHandler consoleCommandHandler; // CraftBukkit - made public + private boolean isRunning = true; + public boolean isStopped = false; + int ticks = 0; + public String i; + public int j; + private List r = new ArrayList(); + private List s = Collections.synchronizedList(new ArrayList()); + // public EntityTracker[] tracker = new EntityTracker[2]; // CraftBukkit - removed! + public boolean onlineMode; + public boolean spawnAnimals; + public boolean pvpMode; + public boolean allowFlight; + + // CraftBukkit start + public List worlds = new ArrayList(); + public CraftServer server; + public OptionSet options; + public ColouredConsoleSender console; + public ConsoleReader reader; + public static int currentTick; + // CraftBukkit end + + //Poseidon Start +// private WatchDogThread watchDogThread; + private boolean modLoaderSupport = false; +// private PoseidonVersionChecker poseidonVersionChecker; + //Poseidon End + + public MinecraftServer(OptionSet options) { // CraftBukkit - adds argument OptionSet + new ThreadSleepForever(this); + + // CraftBukkit start + this.options = options; + try { + this.reader = new ConsoleReader(); + } catch (IOException ex) { + Logger.getLogger(MinecraftServer.class.getName()).log(Level.SEVERE, null, ex); + } + Runtime.getRuntime().addShutdownHook(new ServerShutdownThread(this)); + // CraftBukkit end + } + + private boolean init() throws UnknownHostException { // CraftBukkit - added throws UnknownHostException + this.consoleCommandHandler = new ConsoleCommandHandler(this); + ThreadCommandReader threadcommandreader = new ThreadCommandReader(this); + + threadcommandreader.setDaemon(true); + threadcommandreader.start(); + ConsoleLogManager.init(this); // CraftBukkit + + // CraftBukkit start + System.setOut(new PrintStream(new LoggerOutputStream(log, Level.INFO), true)); + System.setErr(new PrintStream(new LoggerOutputStream(log, Level.SEVERE), true)); + // CraftBukkit end + + //If Poseidon Config DEBUG is enabled, enable debug mode + if (options.has("debug-config")) { + log.info("[Poseidon] Configuration debug mode has been enabled. This will cause the poseidon.yml to be reloaded every time the server starts."); + PoseidonConfig.getInstance().resetConfig(); + } + + modLoaderSupport = PoseidonConfig.getInstance().getBoolean("settings.support.modloader.enable", false); + + if (modLoaderSupport) { + log.info("EXPERIMENTAL MODLOADERMP SUPPORT ENABLED."); + if (!isModloaderPresent()) { + log.severe("ModLoaderMP support is enabled, however, it isn't present. Please install it before enabling this setting"); + return false; + } + net.minecraft.server.ModLoader.Init(this); + } + + log.info("Starting minecraft server version Beta 1.7.3"); + if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) { + log.warning("**** NOT ENOUGH RAM!"); + log.warning("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); + } + + log.info("Loading properties"); + this.propertyManager = new PropertyManager(this.options); // CraftBukkit - CLI argument support + String s = this.propertyManager.getString("server-ip", ""); + + this.onlineMode = this.propertyManager.getBoolean("online-mode", false); //Project Poseidon - False by default + this.spawnAnimals = this.propertyManager.getBoolean("spawn-animals", true); + this.pvpMode = this.propertyManager.getBoolean("pvp", true); + this.allowFlight = this.propertyManager.getBoolean("allow-flight", false); + InetAddress inetaddress = null; + + if (s.length() > 0) { + inetaddress = InetAddress.getByName(s); + } + + int i = this.propertyManager.getInt("server-port", 25565); + + log.info("Starting Minecraft server on " + (s.length() == 0 ? "*" : s) + ":" + i); + + try { + this.networkListenThread = new NetworkListenThread(this, inetaddress, i); + } catch (Throwable ioexception) { // CraftBukkit - IOException -> Throwable + log.warning("**** FAILED TO BIND TO PORT!"); + log.log(Level.WARNING, "The exception was: " + ioexception.toString()); + log.warning("Perhaps a server is already running on that port?"); + return false; + } + + if (!this.onlineMode) { + log.warning("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + log.warning("The server will make no attempt to authenticate usernames. Beware."); + log.warning("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); + log.warning("To change this, set \"online-mode\" to \"true\" in the server.settings file."); + } + + this.serverConfigurationManager = new ServerConfigurationManager(this); + // CraftBukkit - removed trackers + long j = System.nanoTime(); + String s1 = this.propertyManager.getString("level-name", "world"); + String s2 = this.propertyManager.getString("level-seed", ""); + long k = (new Random()).nextLong(); + + if (s2.length() > 0) { + try { + k = Long.parseLong(s2); + } catch (NumberFormatException numberformatexception) { + k = (long) s2.hashCode(); + } + } + + log.info("Preparing level \"" + s1 + "\""); + this.a(new WorldLoaderServer(new File(".")), s1, k); + + //Project Poseidon Start + Poseidon.getServer().initializeServer(); + //Project Poseidon End + + // CraftBukkit start + long elapsed = System.nanoTime() - j; + String time = String.format("%.3fs", elapsed / 10000000000.0D); + log.info("Done (" + time + ")! For help, type \"help\" or \"?\""); + + // log rotator process start. + if ((boolean) PoseidonConfig.getInstance().getConfigOption("settings.per-day-log-file.enabled") && (boolean) PoseidonConfig.getInstance().getConfigOption("settings.per-day-log-file.latest-log.enabled")) { + String latestLogFileName = "latest"; + ServerLogRotator serverLogRotator = new ServerLogRotator(latestLogFileName); + serverLogRotator.start(); + } + + if (this.propertyManager.properties.containsKey("spawn-protection")) { + log.info("'spawn-protection' in server.properties has been moved to 'settings.spawn-radius' in bukkit.yml. I will move your config for you."); + this.server.setSpawnRadius(this.propertyManager.getInt("spawn-protection", 16)); + this.propertyManager.properties.remove("spawn-protection"); + this.propertyManager.savePropertiesFile(); + } + return true; + } + + public boolean isModloaderPresent() { + try { + Class.forName("net.minecraft.server.ModLoader"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + private void a(Convertable convertable, String s, long i) { + if (convertable.isConvertable(s)) { + log.info("Converting map!"); + convertable.convert(s, new ConvertProgressUpdater(this)); + } + + // CraftBukkit start + for (int j = 0; j < (this.propertyManager.getBoolean("allow-nether", true) ? 2 : 1); ++j) { + WorldServer world; + int dimension = j == 0 ? 0 : -1; + String worldType = Environment.getEnvironment(dimension).toString().toLowerCase(); + String name = (dimension == 0) ? s : s + "_" + worldType; + + ChunkGenerator gen = this.server.getGenerator(name); + + if (j == 0) { + world = new WorldServer(this, new ServerNBTManager(new File("."), s, true), s, dimension, i, org.bukkit.World.Environment.getEnvironment(dimension), gen); // CraftBukkit + } else { + String dim = "DIM-1"; + + File newWorld = new File(new File(name), dim); + File oldWorld = new File(new File(s), dim); + + if ((!newWorld.isDirectory()) && (oldWorld.isDirectory())) { + log.info("---- Migration of old " + worldType + " folder required ----"); + log.info("Unfortunately due to the way that Minecraft implemented multiworld support in 1.6, Bukkit requires that you move your " + worldType + " folder to a new location in order to operate correctly."); + log.info("We will move this folder for you, but it will mean that you need to move it back should you wish to stop using Bukkit in the future."); + log.info("Attempting to move " + oldWorld + " to " + newWorld + "..."); + + if (newWorld.exists()) { + log.severe("A file or folder already exists at " + newWorld + "!"); + log.info("---- Migration of old " + worldType + " folder failed ----"); + } else if (newWorld.getParentFile().mkdirs()) { + if (oldWorld.renameTo(newWorld)) { + log.info("Success! To restore the nether in the future, simply move " + newWorld + " to " + oldWorld); + log.info("---- Migration of old " + worldType + " folder complete ----"); + } else { + log.severe("Could not move folder " + oldWorld + " to " + newWorld + "!"); + log.info("---- Migration of old " + worldType + " folder failed ----"); + } + } else { + log.severe("Could not create path for " + newWorld + "!"); + log.info("---- Migration of old " + worldType + " folder failed ----"); + } + } + + world = new SecondaryWorldServer(this, new ServerNBTManager(new File("."), name, true), name, dimension, i, this.worlds.get(0), org.bukkit.World.Environment.getEnvironment(dimension), gen); // CraftBukkit + } + + if (gen != null) { + world.getWorld().getPopulators().addAll(gen.getDefaultPopulators(world.getWorld())); + } + + this.server.getPluginManager().callEvent(new WorldInitEvent(world.getWorld())); + + world.tracker = new EntityTracker(this, dimension); + world.addIWorldAccess(new WorldManager(this, world)); + world.spawnMonsters = this.propertyManager.getBoolean("spawn-monsters", true) ? 1 : 0; + world.setSpawnFlags(this.propertyManager.getBoolean("spawn-monsters", true), this.spawnAnimals); + this.worlds.add(world); + this.serverConfigurationManager.setPlayerFileData(this.worlds.toArray(new WorldServer[0])); + } + // CraftBukkit end + + short short1 = 196; + long k = System.currentTimeMillis(); + + // CraftBukkit start + for (int l = 0; l < this.worlds.size(); ++l) { + // if (l == 0 || this.propertyManager.getBoolean("allow-nether", true)) { + WorldServer worldserver = this.worlds.get(l); + log.info("Preparing start region for level " + l + " (Seed: " + worldserver.getSeed() + ")"); + if (worldserver.getWorld().getKeepSpawnInMemory()) { + // CraftBukkit end + ChunkCoordinates chunkcoordinates = worldserver.getSpawn(); + + for (int i1 = -short1; i1 <= short1 && this.isRunning; i1 += 16) { + for (int j1 = -short1; j1 <= short1 && this.isRunning; j1 += 16) { + long k1 = System.currentTimeMillis(); + + if (k1 < k) { + k = k1; + } + + if (k1 > k + 1000L) { + int l1 = (short1 * 2 + 1) * (short1 * 2 + 1); + int i2 = (i1 + short1) * (short1 * 2 + 1) + j1 + 1; + + this.a("Preparing spawn area", i2 * 100 / l1); + k = k1; + } + + worldserver.chunkProviderServer.getChunkAt(chunkcoordinates.x + i1 >> 4, chunkcoordinates.z + j1 >> 4); + + while (worldserver.doLighting() && this.isRunning) { + ; + } + } + } + } // CraftBukkit + } + + // CraftBukkit start + for (World world : this.worlds) { + this.server.getPluginManager().callEvent(new WorldLoadEvent(world.getWorld())); + } + // CraftBukkit end + + this.e(); + } + + private void a(String s, int i) { + this.i = s; + this.j = i; + log.info(s + ": " + i + "%"); + } + + private void e() { + this.i = null; + this.j = 0; + + this.server.enablePlugins(PluginLoadOrder.POSTWORLD); // CraftBukkit + } + + void saveChunks() { // CraftBukkit - private -> default + log.info("Saving chunks"); + + // CraftBukkit start + for (int i = 0; i < this.worlds.size(); ++i) { + WorldServer worldserver = this.worlds.get(i); + + worldserver.save(true, (IProgressUpdate) null); + worldserver.saveLevel(); + + WorldSaveEvent event = new WorldSaveEvent(worldserver.getWorld()); + this.server.getPluginManager().callEvent(event); + } + + WorldServer world = this.worlds.get(0); + if (!world.canSave) { + this.serverConfigurationManager.savePlayers(); + } + // CraftBukkit end + } + + public void stop() { // CraftBukkit - private -> public + log.info("Stopping server"); + + //Project Poseidon Start + + // This is done before disablePlugins() to ensure the watchdog doesn't detect plugins disabling as a server hang + Poseidon.getServer().shutdownServer(); + + //Project Poseidon End + + // CraftBukkit start + if (this.server != null) { + this.server.disablePlugins(); + } + // CraftBukkit end + + if (this.serverConfigurationManager != null) { + this.serverConfigurationManager.savePlayers(); + } + + // CraftBukkit start - multiworld is handled in saveChunks() already. + WorldServer worldserver = this.worlds.get(0); + + if (worldserver != null) { + this.saveChunks(); + } + // CraftBukkit end + + // Poseidon Start + Map listenerStatistics = new HashMap<>(); + + // Only get the Listener Statistics if the Poseidon Server is not null. Prevents null pointer exceptions. + if (Poseidon.getServer() != null && Poseidon.getServer().getConfig().getConfigBoolean("settings.performance-monitoring.listener-reporting.print-statistics-on-shutdown.enabled")) { + listenerStatistics = Poseidon.getServer().getSortedListenerPerformance(); + } + + // Check if the statistics map is not empty + if (listenerStatistics != null && !listenerStatistics.isEmpty()) { + log.info("[Poseidon] Listener statistics from this session:"); + + // Iterate over each listener and log their statistics + for (Map.Entry entry : listenerStatistics.entrySet()) { + String listener = entry.getKey(); + PerformanceStatistic stats = entry.getValue(); + + if (stats.getMaxExecutionTime() == 0) { + continue; + } + + if (stats != null) { + log.info(String.format("[Poseidon] Listener: %s - Processed %d events, Total Execution Time: %d ms, Avg Time: %d ms", + listener, + stats.getEventCount(), + stats.getTotalExecutionTime(), + stats.getAverageExecutionTime())); + } else { + log.warning("[Poseidon] No statistics available for listener: " + listener); + } + } + } + + + // Check if the statistics map is not empty + + Map taskStatistics = new HashMap<>(); + + // Only get the Task Statistics if the Poseidon Server is not null. Prevents null pointer exceptions. + if (Poseidon.getServer() != null && Poseidon.getServer().getConfig().getConfigBoolean("settings.performance-monitoring.listener-reporting.print-statistics-on-shutdown.enabled")) { + taskStatistics = Poseidon.getServer().getSortedTaskPerformance(); + } + + if (taskStatistics != null && !taskStatistics.isEmpty()) { + log.info("[Poseidon] Synchronous task statistics from this session:"); + + // Iterate over each task and log their statistics + for (Map.Entry entry : taskStatistics.entrySet()) { + String task = entry.getKey(); + PerformanceStatistic stats = entry.getValue(); + + if (stats.getMaxExecutionTime() == 0) { + continue; + } + + if (stats != null) { + log.info(String.format("[Poseidon] Task: %s - Processed %d events, Total Execution Time: %d ms, Avg Time: %d ms", + task, + stats.getEventCount(), + stats.getTotalExecutionTime(), + stats.getAverageExecutionTime())); + } else { + log.warning("[Poseidon] No statistics available for task: " + task); + } + } + } + // Poseidon End + } + + public void a() { + this.isRunning = false; + } + + public void run() { + try { + if (this.init()) { + long i = System.currentTimeMillis(); + + for (long j = 0L; this.isRunning; Thread.sleep(1L)) { + if (modLoaderSupport) { + net.minecraft.server.ModLoader.OnTick(this); + } + + long k = System.currentTimeMillis(); + long l = k - i; + + if (l > 2000L) { + log.warning("Can\'t keep up! Did the system time change, or is the server overloaded?"); + l = 2000L; + } + + if (l < 0L) { + log.warning("Time ran backwards! Did the system time change?"); + l = 0L; + } + + j += l; + i = k; + if (this.worlds.get(0).everyoneDeeplySleeping()) { // CraftBukkit + this.h(); + j = 0L; + } else { + while (j > 50L) { + MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit + getWatchdog().tickUpdate(); // Project Poseidon + j -= 50L; + this.h(); + } + } + } + } else { + while (this.isRunning) { + this.b(); + + try { + Thread.sleep(10L); + } catch (InterruptedException interruptedexception) { + interruptedexception.printStackTrace(); + } + } + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + log.log(Level.SEVERE, "Unexpected exception", throwable); + + while (this.isRunning) { + this.b(); + + try { + Thread.sleep(10L); + } catch (InterruptedException interruptedexception1) { + interruptedexception1.printStackTrace(); + } + } + } finally { + try { + this.stop(); + this.isStopped = true; + } catch (Throwable throwable1) { + throwable1.printStackTrace(); + } finally { + System.exit(0); + } + } + } + + //Project Poseidon Start - Tick Update + private final LinkedList tpsRecords = new LinkedList<>(); + private long lastTick = System.currentTimeMillis(); + private int tickCount = 0; + + public LinkedList getTpsRecords() { + return tpsRecords; + } + //Project Poseidon End - Tick Update + + private void h() { + ArrayList arraylist = new ArrayList(); + Iterator iterator = trackerList.keySet().iterator(); + + while (iterator.hasNext()) { + String s = (String) iterator.next(); + int i = ((Integer) trackerList.get(s)).intValue(); + + if (i > 0) { + trackerList.put(s, Integer.valueOf(i - 1)); + } else { + arraylist.add(s); + } + } + + int j; + + for (j = 0; j < arraylist.size(); ++j) { + trackerList.remove(arraylist.get(j)); + } + + AxisAlignedBB.a(); + Vec3D.a(); + ++this.ticks; + + ((CraftScheduler) this.server.getScheduler()).mainThreadHeartbeat(this.ticks); // CraftBukkit + + //Project Poseidon Start - Tick Update + long currentTime = System.currentTimeMillis(); + tickCount++; + + //Check if a second has passed + if (currentTime - lastTick >= 1000) { + double tps = tickCount / ((currentTime - lastTick) / 1000.0); + tpsRecords.addFirst(tps); + if (tpsRecords.size() > 900) { //Don't keep more than 15 minutes of data + tpsRecords.removeLast(); + } + + tickCount = 0; + lastTick = currentTime; + } + + //Project Poseidon End - Tick Update + + + for (j = 0; j < this.worlds.size(); ++j) { // CraftBukkit + // if (j == 0 || this.propertyManager.getBoolean("allow-nether", true)) { // CraftBukkit + WorldServer worldserver = this.worlds.get(j); // CraftBukkit + + if (this.ticks % 20 == 0) { + // CraftBukkit start - only send timeupdates to the people in that world + for (int i = 0; i < worldserver.players.size(); ++i) { // Project Poseidon: serverConfigurationManager -> worldserver.players + EntityPlayer entityPlayer = (EntityPlayer) worldserver.players.get(i); + if (entityPlayer != null) { + entityPlayer.netServerHandler.sendPacket(new Packet4UpdateTime(entityPlayer.getPlayerTime())); // Add support for per player time + + } + } + // CraftBukkit end + } + + worldserver.doTick(); + + while (worldserver.doLighting()) { + ; + } + + worldserver.cleanUp(); + } + // } // CraftBukkit + + this.networkListenThread.a(); + this.serverConfigurationManager.b(); + + // CraftBukkit start + for (j = 0; j < this.worlds.size(); ++j) { + this.worlds.get(j).tracker.updatePlayers(); + } + // CraftBukkit end + + for (j = 0; j < this.r.size(); ++j) { + ((IUpdatePlayerListBox) this.r.get(j)).a(); + } + + try { + this.b(); + } catch (Exception exception) { + log.log(Level.WARNING, "Unexpected exception while parsing console command", exception); + } + } + + public void issueCommand(String s, ICommandListener icommandlistener) { + this.s.add(new ServerCommand(s, icommandlistener)); + } + + public void b() { + while (this.s.size() > 0) { + ServerCommand servercommand = (ServerCommand) this.s.remove(0); + + // CraftBukkit start - ServerCommand for preprocessing + ServerCommandEvent event = new ServerCommandEvent(this.console, servercommand.command); + this.server.getPluginManager().callEvent(event); + servercommand = new ServerCommand(event.getCommand(), servercommand.b); + // CraftBukkit end + + // this.consoleCommandHandler.handle(servercommand); // CraftBukkit - Removed its now called in server.dispatchCommand + this.server.dispatchCommand(this.console, servercommand); // CraftBukkit + } + } + + public void a(IUpdatePlayerListBox iupdateplayerlistbox) { + this.r.add(iupdateplayerlistbox); + } + + public static void main(final OptionSet options) { // CraftBukkit - replaces main(String args[]) + StatisticList.a(); + + try { + MinecraftServer minecraftserver = new MinecraftServer(options); // CraftBukkit - pass in the options + + // CraftBukkit - remove gui + + (new ThreadServerApplication("Server thread", minecraftserver)).start(); + } catch (Exception exception) { + log.log(Level.SEVERE, "Failed to start the minecraft server", exception); + } + } + + public File a(String s) { + return new File(s); + } + + public void sendMessage(String s) { + log.info(s); + } + + public void c(String s) { + log.warning(s); + } + + public String getName() { + return "CONSOLE"; + } + + public WorldServer getWorldServer(int i) { + // CraftBukkit start + for (WorldServer world : this.worlds) { + if (world.dimension == i) { + return world; + } + } + + return this.worlds.get(0); + // CraftBukkit end + } + + public EntityTracker getTracker(int i) { + return this.getWorldServer(i).tracker; // CraftBukkit + } + + public static boolean isRunning(MinecraftServer minecraftserver) { + return minecraftserver.isRunning; + } + + public WatchDogThread getWatchdog() { + return Poseidon.getServer().getWatchDogThread(); + } +} diff --git a/src/main/java/net/minecraft/server/MovingObjectPosition.java b/src/main/java/net/minecraft/server/MovingObjectPosition.java new file mode 100644 index 0000000..85c3d30 --- /dev/null +++ b/src/main/java/net/minecraft/server/MovingObjectPosition.java @@ -0,0 +1,27 @@ +package net.minecraft.server; + +public class MovingObjectPosition { + + public EnumMovingObjectType type; + public int b; + public int c; + public int d; + public int face; + public Vec3D f; + public Entity entity; + + public MovingObjectPosition(int i, int j, int k, int l, Vec3D vec3d) { + this.type = EnumMovingObjectType.TILE; + this.b = i; + this.c = j; + this.d = k; + this.face = l; + this.f = Vec3D.create(vec3d.a, vec3d.b, vec3d.c); + } + + public MovingObjectPosition(Entity entity) { + this.type = EnumMovingObjectType.ENTITY; + this.entity = entity; + this.f = Vec3D.create(entity.locX, entity.locY, entity.locZ); + } +} diff --git a/src/main/java/net/minecraft/server/NBTBase.java b/src/main/java/net/minecraft/server/NBTBase.java new file mode 100644 index 0000000..ff79be8 --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTBase.java @@ -0,0 +1,129 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public abstract class NBTBase { + + private String a = null; + + public NBTBase() {} + + abstract void a(DataOutput dataoutput) throws IOException; + + abstract void a(DataInput datainput) throws IOException; + + public abstract byte a(); + + public String b() { + return this.a == null ? "" : this.a; + } + + public NBTBase a(String s) { + this.a = s; + return this; + } + + public static NBTBase b(DataInput datainput) throws IOException { + byte b0 = datainput.readByte(); + + if (b0 == 0) { + return new NBTTagEnd(); + } else { + NBTBase nbtbase = a(b0); + + nbtbase.a = datainput.readUTF(); + nbtbase.a(datainput); + return nbtbase; + } + } + + public static void a(NBTBase nbtbase, DataOutput dataoutput) throws IOException { + dataoutput.writeByte(nbtbase.a()); + if (nbtbase.a() != 0) { + dataoutput.writeUTF(nbtbase.b()); + nbtbase.a(dataoutput); + } + } + + public static NBTBase a(byte b0) { + switch (b0) { + case 0: + return new NBTTagEnd(); + + case 1: + return new NBTTagByte(); + + case 2: + return new NBTTagShort(); + + case 3: + return new NBTTagInt(); + + case 4: + return new NBTTagLong(); + + case 5: + return new NBTTagFloat(); + + case 6: + return new NBTTagDouble(); + + case 7: + return new NBTTagByteArray(); + + case 8: + return new NBTTagString(); + + case 9: + return new NBTTagList(); + + case 10: + return new NBTTagCompound(); + + default: + return null; + } + } + + public static String b(byte b0) { + switch (b0) { + case 0: + return "TAG_End"; + + case 1: + return "TAG_Byte"; + + case 2: + return "TAG_Short"; + + case 3: + return "TAG_Int"; + + case 4: + return "TAG_Long"; + + case 5: + return "TAG_Float"; + + case 6: + return "TAG_Double"; + + case 7: + return "TAG_Byte_Array"; + + case 8: + return "TAG_String"; + + case 9: + return "TAG_List"; + + case 10: + return "TAG_Compound"; + + default: + return "UNKNOWN"; + } + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagByte.java b/src/main/java/net/minecraft/server/NBTTagByte.java new file mode 100644 index 0000000..fb59413 --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagByte.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagByte extends NBTBase { + + public byte a; + + public NBTTagByte() {} + + public NBTTagByte(byte b0) { + this.a = b0; + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeByte(this.a); + } + + void a(DataInput datainput) throws IOException { + this.a = datainput.readByte(); + } + + public byte a() { + return (byte) 1; + } + + public String toString() { + return "" + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagByteArray.java b/src/main/java/net/minecraft/server/NBTTagByteArray.java new file mode 100644 index 0000000..8757d64 --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagByteArray.java @@ -0,0 +1,36 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagByteArray extends NBTBase { + + public byte[] a; + + public NBTTagByteArray() {} + + public NBTTagByteArray(byte[] abyte) { + this.a = abyte; + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeInt(this.a.length); + dataoutput.write(this.a); + } + + void a(DataInput datainput) throws IOException { + int i = datainput.readInt(); + + this.a = new byte[i]; + datainput.readFully(this.a); + } + + public byte a() { + return (byte) 7; + } + + public String toString() { + return "[" + this.a.length + " bytes]"; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagCompound.java b/src/main/java/net/minecraft/server/NBTTagCompound.java new file mode 100644 index 0000000..51d7cc8 --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagCompound.java @@ -0,0 +1,142 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class NBTTagCompound extends NBTBase { + + private Map a = new HashMap(); + + public NBTTagCompound() {} + + void a(DataOutput dataoutput) throws IOException { + Iterator iterator = this.a.values().iterator(); + + while (iterator.hasNext()) { + NBTBase nbtbase = (NBTBase) iterator.next(); + + NBTBase.a(nbtbase, dataoutput); + } + + dataoutput.writeByte(0); + } + + void a(DataInput datainput) throws IOException { + this.a.clear(); + + NBTBase nbtbase; + + while ((nbtbase = NBTBase.b(datainput)).a() != 0) { + this.a.put(nbtbase.b(), nbtbase); + } + } + + public Collection c() { + return this.a.values(); + } + + public byte a() { + return (byte) 10; + } + + public void a(String s, NBTBase nbtbase) { + this.a.put(s, nbtbase.a(s)); + } + + public void a(String s, byte b0) { + this.a.put(s, (new NBTTagByte(b0)).a(s)); + } + + public void a(String s, short short1) { + this.a.put(s, (new NBTTagShort(short1)).a(s)); + } + + public void a(String s, int i) { + this.a.put(s, (new NBTTagInt(i)).a(s)); + } + + public void setLong(String s, long i) { + this.a.put(s, (new NBTTagLong(i)).a(s)); + } + + public void a(String s, float f) { + this.a.put(s, (new NBTTagFloat(f)).a(s)); + } + + public void a(String s, double d0) { + this.a.put(s, (new NBTTagDouble(d0)).a(s)); + } + + public void setString(String s, String s1) { + this.a.put(s, (new NBTTagString(s1)).a(s)); + } + + public void a(String s, byte[] abyte) { + this.a.put(s, (new NBTTagByteArray(abyte)).a(s)); + } + + public void a(String s, NBTTagCompound nbttagcompound) { + this.a.put(s, nbttagcompound.a(s)); + } + + public void a(String s, boolean flag) { + this.a(s, (byte) (flag ? 1 : 0)); + } + + public boolean hasKey(String s) { + return this.a.containsKey(s); + } + + public byte c(String s) { + return !this.a.containsKey(s) ? 0 : ((NBTTagByte) this.a.get(s)).a; + } + + public short d(String s) { + return !this.a.containsKey(s) ? 0 : ((NBTTagShort) this.a.get(s)).a; + } + + public int e(String s) { + return !this.a.containsKey(s) ? 0 : ((NBTTagInt) this.a.get(s)).a; + } + + public long getLong(String s) { + return !this.a.containsKey(s) ? 0L : ((NBTTagLong) this.a.get(s)).a; + } + + public float g(String s) { + return !this.a.containsKey(s) ? 0.0F : ((NBTTagFloat) this.a.get(s)).a; + } + + public double h(String s) { + return !this.a.containsKey(s) ? 0.0D : ((NBTTagDouble) this.a.get(s)).a; + } + + public String getString(String s) { + return !this.a.containsKey(s) ? "" : ((NBTTagString) this.a.get(s)).a; + } + + public byte[] j(String s) { + return !this.a.containsKey(s) ? new byte[0] : ((NBTTagByteArray) this.a.get(s)).a; + } + + public NBTTagCompound k(String s) { + return !this.a.containsKey(s) ? new NBTTagCompound() : (NBTTagCompound) this.a.get(s); + } + + public NBTTagList l(String s) { + return !this.a.containsKey(s) ? new NBTTagList() : (NBTTagList) this.a.get(s); + } + + public boolean m(String s) { + return this.c(s) != 0; + } + + public String toString() { + return "" + this.a.size() + " entries"; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagDouble.java b/src/main/java/net/minecraft/server/NBTTagDouble.java new file mode 100644 index 0000000..d4458f8 --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagDouble.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagDouble extends NBTBase { + + public double a; + + public NBTTagDouble() {} + + public NBTTagDouble(double d0) { + this.a = d0; + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeDouble(this.a); + } + + void a(DataInput datainput) throws IOException { + this.a = datainput.readDouble(); + } + + public byte a() { + return (byte) 6; + } + + public String toString() { + return "" + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagEnd.java b/src/main/java/net/minecraft/server/NBTTagEnd.java new file mode 100644 index 0000000..18e516e --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagEnd.java @@ -0,0 +1,21 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; + +public class NBTTagEnd extends NBTBase { + + public NBTTagEnd() {} + + void a(DataInput datainput) {} + + void a(DataOutput dataoutput) {} + + public byte a() { + return (byte) 0; + } + + public String toString() { + return "END"; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagFloat.java b/src/main/java/net/minecraft/server/NBTTagFloat.java new file mode 100644 index 0000000..ee64cb0 --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagFloat.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagFloat extends NBTBase { + + public float a; + + public NBTTagFloat() {} + + public NBTTagFloat(float f) { + this.a = f; + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeFloat(this.a); + } + + void a(DataInput datainput) throws IOException { + this.a = datainput.readFloat(); + } + + public byte a() { + return (byte) 5; + } + + public String toString() { + return "" + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagInt.java b/src/main/java/net/minecraft/server/NBTTagInt.java new file mode 100644 index 0000000..888d96a --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagInt.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagInt extends NBTBase { + + public int a; + + public NBTTagInt() {} + + public NBTTagInt(int i) { + this.a = i; + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeInt(this.a); + } + + void a(DataInput datainput) throws IOException { + this.a = datainput.readInt(); + } + + public byte a() { + return (byte) 3; + } + + public String toString() { + return "" + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagList.java b/src/main/java/net/minecraft/server/NBTTagList.java new file mode 100644 index 0000000..53fc22f --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagList.java @@ -0,0 +1,65 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class NBTTagList extends NBTBase { + + private List a = new ArrayList(); + private byte b; + + public NBTTagList() {} + + void a(DataOutput dataoutput) throws IOException { + if (this.a.size() > 0) { + this.b = ((NBTBase) this.a.get(0)).a(); + } else { + this.b = 1; + } + + dataoutput.writeByte(this.b); + dataoutput.writeInt(this.a.size()); + + for (int i = 0; i < this.a.size(); ++i) { + ((NBTBase) this.a.get(i)).a(dataoutput); + } + } + + void a(DataInput datainput) throws IOException { + this.b = datainput.readByte(); + int i = datainput.readInt(); + + this.a = new ArrayList(); + + for (int j = 0; j < i; ++j) { + NBTBase nbtbase = NBTBase.a(this.b); + + nbtbase.a(datainput); + this.a.add(nbtbase); + } + } + + public byte a() { + return (byte) 9; + } + + public String toString() { + return "" + this.a.size() + " entries of type " + NBTBase.b(this.b); + } + + public void a(NBTBase nbtbase) { + this.b = nbtbase.a(); + this.a.add(nbtbase); + } + + public NBTBase a(int i) { + return (NBTBase) this.a.get(i); + } + + public int c() { + return this.a.size(); + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagLong.java b/src/main/java/net/minecraft/server/NBTTagLong.java new file mode 100644 index 0000000..f143ff7 --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagLong.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagLong extends NBTBase { + + public long a; + + public NBTTagLong() {} + + public NBTTagLong(long i) { + this.a = i; + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeLong(this.a); + } + + void a(DataInput datainput) throws IOException { + this.a = datainput.readLong(); + } + + public byte a() { + return (byte) 4; + } + + public String toString() { + return "" + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagShort.java b/src/main/java/net/minecraft/server/NBTTagShort.java new file mode 100644 index 0000000..5cb013c --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagShort.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagShort extends NBTBase { + + public short a; + + public NBTTagShort() {} + + public NBTTagShort(short short1) { + this.a = short1; + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeShort(this.a); + } + + void a(DataInput datainput) throws IOException { + this.a = datainput.readShort(); + } + + public byte a() { + return (byte) 2; + } + + public String toString() { + return "" + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/NBTTagString.java b/src/main/java/net/minecraft/server/NBTTagString.java new file mode 100644 index 0000000..a52555d --- /dev/null +++ b/src/main/java/net/minecraft/server/NBTTagString.java @@ -0,0 +1,35 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagString extends NBTBase { + + public String a; + + public NBTTagString() {} + + public NBTTagString(String s) { + this.a = s; + if (s == null) { + throw new IllegalArgumentException("Empty string not allowed"); + } + } + + void a(DataOutput dataoutput) throws IOException { + dataoutput.writeUTF(this.a); + } + + void a(DataInput datainput) throws IOException { + this.a = datainput.readUTF(); + } + + public byte a() { + return (byte) 8; + } + + public String toString() { + return "" + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/NetHandler.java b/src/main/java/net/minecraft/server/NetHandler.java new file mode 100644 index 0000000..db70d65 --- /dev/null +++ b/src/main/java/net/minecraft/server/NetHandler.java @@ -0,0 +1,214 @@ +package net.minecraft.server; + +public abstract class NetHandler { + + public NetHandler() {} + + public abstract boolean c(); + + public void a(Packet51MapChunk packet51mapchunk) {} + + public void a(Packet packet) {} + + public void a(String s, Object[] aobject) {} + + public void a(Packet0KeepAlive packet0KeepAlive) { + this.a((Packet) packet0KeepAlive); + } + + public void a(Packet255KickDisconnect packet255kickdisconnect) { + this.a((Packet) packet255kickdisconnect); + } + + public void a(Packet1Login packet1login) { + this.a((Packet) packet1login); + } + + public void a(Packet10Flying packet10flying) { + this.a((Packet) packet10flying); + } + + public void a(Packet52MultiBlockChange packet52multiblockchange) { + this.a((Packet) packet52multiblockchange); + } + + public void a(Packet14BlockDig packet14blockdig) { + this.a((Packet) packet14blockdig); + } + + public void a(Packet53BlockChange packet53blockchange) { + this.a((Packet) packet53blockchange); + } + + public void a(Packet50PreChunk packet50prechunk) { + this.a((Packet) packet50prechunk); + } + + public void a(Packet20NamedEntitySpawn packet20namedentityspawn) { + this.a((Packet) packet20namedentityspawn); + } + + public void a(Packet30Entity packet30entity) { + this.a((Packet) packet30entity); + } + + public void a(Packet34EntityTeleport packet34entityteleport) { + this.a((Packet) packet34entityteleport); + } + + public void a(Packet15Place packet15place) { + this.a((Packet) packet15place); + } + + public void a(Packet16BlockItemSwitch packet16blockitemswitch) { + this.a((Packet) packet16blockitemswitch); + } + + public void a(Packet29DestroyEntity packet29destroyentity) { + this.a((Packet) packet29destroyentity); + } + + public void a(Packet21PickupSpawn packet21pickupspawn) { + this.a((Packet) packet21pickupspawn); + } + + public void a(Packet22Collect packet22collect) { + this.a((Packet) packet22collect); + } + + public void a(Packet3Chat packet3chat) { + this.a((Packet) packet3chat); + } + + public void a(Packet23VehicleSpawn packet23vehiclespawn) { + this.a((Packet) packet23vehiclespawn); + } + + public void a(Packet18ArmAnimation packet18armanimation) { + this.a((Packet) packet18armanimation); + } + + public void a(Packet19EntityAction packet19entityaction) { + this.a((Packet) packet19entityaction); + } + + public void a(Packet2Handshake packet2handshake) { + this.a((Packet) packet2handshake); + } + + public void a(Packet24MobSpawn packet24mobspawn) { + this.a((Packet) packet24mobspawn); + } + + public void a(Packet4UpdateTime packet4updatetime) { + this.a((Packet) packet4updatetime); + } + + public void a(Packet6SpawnPosition packet6spawnposition) { + this.a((Packet) packet6spawnposition); + } + + public void a(Packet28EntityVelocity packet28entityvelocity) { + this.a((Packet) packet28entityvelocity); + } + + public void a(Packet40EntityMetadata packet40entitymetadata) { + this.a((Packet) packet40entitymetadata); + } + + public void a(Packet39AttachEntity packet39attachentity) { + this.a((Packet) packet39attachentity); + } + + public void a(Packet7UseEntity packet7useentity) { + this.a((Packet) packet7useentity); + } + + public void a(Packet38EntityStatus packet38entitystatus) { + this.a((Packet) packet38entitystatus); + } + + public void a(Packet8UpdateHealth packet8updatehealth) { + this.a((Packet) packet8updatehealth); + } + + public void a(Packet9Respawn packet9respawn) { + this.a((Packet) packet9respawn); + } + + public void a(Packet60Explosion packet60explosion) { + this.a((Packet) packet60explosion); + } + + public void a(Packet100OpenWindow packet100openwindow) { + this.a((Packet) packet100openwindow); + } + + public void a(Packet101CloseWindow packet101closewindow) { + this.a((Packet) packet101closewindow); + } + + public void a(Packet102WindowClick packet102windowclick) { + this.a((Packet) packet102windowclick); + } + + public void a(Packet103SetSlot packet103setslot) { + this.a((Packet) packet103setslot); + } + + public void a(Packet104WindowItems packet104windowitems) { + this.a((Packet) packet104windowitems); + } + + public void a(Packet130UpdateSign packet130updatesign) { + this.a((Packet) packet130updatesign); + } + + public void a(Packet105CraftProgressBar packet105craftprogressbar) { + this.a((Packet) packet105craftprogressbar); + } + + public void a(Packet5EntityEquipment packet5entityequipment) { + this.a((Packet) packet5entityequipment); + } + + public void a(Packet106Transaction packet106transaction) { + this.a((Packet) packet106transaction); + } + + public void a(Packet25EntityPainting packet25entitypainting) { + this.a((Packet) packet25entitypainting); + } + + public void a(Packet54PlayNoteBlock packet54playnoteblock) { + this.a((Packet) packet54playnoteblock); + } + + public void a(Packet200Statistic packet200statistic) { + this.a((Packet) packet200statistic); + } + + public void a(Packet17 packet17) { + this.a((Packet) packet17); + } + + public void a(Packet27 packet27) { + this.a((Packet) packet27); + } + + public void a(Packet70Bed packet70bed) { + this.a((Packet) packet70bed); + } + + public void a(Packet71Weather packet71weather) { + this.a((Packet) packet71weather); + } + + public void a(Packet131 packet131) { + this.a((Packet) packet131); + } + + public void a(Packet61 packet61) { + this.a((Packet) packet61); + } +} diff --git a/src/main/java/net/minecraft/server/NetLoginHandler.java b/src/main/java/net/minecraft/server/NetLoginHandler.java new file mode 100644 index 0000000..1605d74 --- /dev/null +++ b/src/main/java/net/minecraft/server/NetLoginHandler.java @@ -0,0 +1,257 @@ +package net.minecraft.server; + +import com.projectposeidon.ConnectionType; +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.projectposeidon.johnymuffin.LoginProcessHandler; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.craftbukkit.CraftServer; + +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Random; +import java.util.logging.Logger; + +import static com.legacyminecraft.poseidon.util.Release2Beta.deserializeAddress; + +public class NetLoginHandler extends NetHandler { + + public static Logger a = Logger.getLogger("Minecraft"); + private static Random d = new Random(); + public NetworkManager networkManager; + public boolean c = false; + private MinecraftServer server; + private int f = 0; + private String g = null; + private Packet1Login h = null; + private String serverId = ""; + private ConnectionType connectionType; + private boolean usingReleaseToBeta = false; //Poseidon -> Release2Beta support + private boolean receivedLoginPacket = false; + private int rawConnectionType; + private boolean receivedKeepAlive = false; + + private final String msgKickShutdown; + + public NetLoginHandler(MinecraftServer minecraftserver, Socket socket, String s) { + this.server = minecraftserver; + this.networkManager = new NetworkManager(socket, s, this); + this.networkManager.f = 0; + + this.msgKickShutdown = PoseidonConfig.getInstance().getConfigString("message.kick.shutdown"); + } + + // CraftBukkit start + public Socket getSocket() { + return this.networkManager.socket; + } + // CraftBukkit end + + public void a() { + if (this.h != null) { + this.b(this.h); + this.h = null; + } + + if (this.f++ == 600) { + this.disconnect("Took too long to log in"); + } else { + this.networkManager.b(); + } + } + + public void disconnect(String s) { + try { + a.info("Disconnecting " + this.b() + ": " + s); + this.networkManager.queue(new Packet255KickDisconnect(s)); + this.networkManager.d(); + this.c = true; + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public void a(Packet2Handshake packet2handshake) { + if (this.server.onlineMode) { + this.serverId = Long.toHexString(d.nextLong()); + this.networkManager.queue(new Packet2Handshake(this.serverId)); + } else { + this.networkManager.queue(new Packet2Handshake("-")); + } + } + + public void a(Packet0KeepAlive packet0KeepAlive) { + receivedKeepAlive = true; + } + + public boolean isCracked() { + return this.g != null && this.g.startsWith("."); + } + + public void a(Packet1Login packet1login) { + + if (receivedLoginPacket) { + this.disconnect("Multiple login packets received."); + return; + } + receivedLoginPacket = true; + this.g = packet1login.name; + + // Kick players if they are using the wrong version + if (packet1login.a != 14) { + if (packet1login.a > 14) { + this.disconnect("Outdated server! I'm still on Beta 1.7.3"); + } else { + this.disconnect("Outdated client! Please use Beta 1.7.3"); + } + } + + + // Handle proxies (e.g., BungeeCord, Release2Beta) + if (!proxyHandler(packet1login)) { + return; + } + + this.finishLogin(packet1login); + } + + public void updateUsername(String newUsername) { + this.g = newUsername; + } + + private boolean proxyHandler(Packet1Login packet1login) { + //Project Poseidon - Start (Release2Beta) + if (packet1login.d == (byte) -999 || packet1login.d == (byte) 25) { + connectionType = ConnectionType.RELEASE2BETA_OFFLINE_MODE_IP_FORWARDING; + } else if (packet1login.d == (byte) 26) { + connectionType = ConnectionType.RELEASE2BETA_ONLINE_MODE_IP_FORWARDING; + } else if (packet1login.d == (byte) 1) { + connectionType = ConnectionType.RELEASE2BETA; + } else if (packet1login.d == (byte) 2) { + connectionType = ConnectionType.BUNGEECORD_OFFLINE_MODE_IP_FORWARDING; + } else { + connectionType = ConnectionType.NORMAL; + } + rawConnectionType = packet1login.d; + //TODO: We need to find a better and cleaner way to support these different Beta proxies, Maybe a handler class??? + if ((Boolean) PoseidonConfig.getInstance().getConfigOption("settings.bungeecord.bungee-mode.enable") && !connectionType.equals(ConnectionType.BUNGEECORD_OFFLINE_MODE_IP_FORWARDING) && !connectionType.equals(ConnectionType.BUNGEECORD_ONLINE_MODE_IP_FORWARDING)) { + a.info(packet1login.name + " is not using BungeeCord, kicking the player."); + this.disconnect((String) PoseidonConfig.getInstance().getConfigOption("settings.bungeecord.bungee-mode.kick-message")); + return false; + } + + if (connectionType.equals(ConnectionType.RELEASE2BETA_OFFLINE_MODE_IP_FORWARDING) || connectionType.equals(ConnectionType.RELEASE2BETA_ONLINE_MODE_IP_FORWARDING) || connectionType.equals(ConnectionType.BUNGEECORD_OFFLINE_MODE_IP_FORWARDING) || connectionType.equals(ConnectionType.BUNGEECORD_ONLINE_MODE_IP_FORWARDING)) { + //Proxy has IP Forwarding enabled + if ((Boolean) PoseidonConfig.getInstance().getConfigOption("settings.release2beta.enable-ip-pass-through")) { + //IP Forwarding is enabled server side + if (this.getSocket().getInetAddress().getHostAddress().equalsIgnoreCase(String.valueOf(PoseidonConfig.getInstance().getConfigOption("settings.release2beta.proxy-ip", "127.0.0.1")))) { + //Release2Beta server is authorized - Override IP address + InetSocketAddress address = deserializeAddress(packet1login.c); + a.info(packet1login.name + " has been detected using Release2Beta, using the IP passed through: " + address.getAddress().getHostAddress()); + this.networkManager.setSocketAddress(address); + this.usingReleaseToBeta = true; + } else { + //Release2Beta server isn't authorized + a.info(packet1login.name + " is attempting to use a unauthorized Release2Beta server, kicking the player."); + this.disconnect(ChatColor.RED + "The Release2Beta server you are connecting through is unauthorized."); + return false; + } + } else { + //Poseidon doesn't support IP Forwarding + a.info(packet1login.name + " is trying to connect through R2B with IP Forwarding enabled, however, it is disabled in Poseidon. Kicking player!"); + this.disconnect(ChatColor.RED + "IP Forwarding is disabled in Poseidon. Please disable in Release2Beta."); + return false; + } + } + //Project Poseidon - End (Release2Beta + + return true; + } + + public void finishLogin(Packet1Login packet1login) { + + if (((CraftServer) Bukkit.getServer()).isShuttingdown()) { + this.disconnect(this.msgKickShutdown); + return; + } + + + new LoginProcessHandler(this, packet1login, this.server.server, this.server.onlineMode); + // (new ThreadLoginVerifier(this, packet1login, this.server.server)).start(); // CraftBukkit +// } + } + + public void b(Packet1Login packet1login) { + EntityPlayer entityplayer = this.server.serverConfigurationManager.a(this, packet1login.name); + + if (entityplayer != null) { + this.server.serverConfigurationManager.b(entityplayer); + // entityplayer.a((World) this.server.a(entityplayer.dimension)); // CraftBukkit - set by Entity + // CraftBukkit - add world and location to 'logged in' message. + a.info(this.b() + " logged in with entity id " + entityplayer.id + " at ([" + entityplayer.world.worldData.name + "] " + entityplayer.locX + ", " + entityplayer.locY + ", " + entityplayer.locZ + ")"); + WorldServer worldserver = (WorldServer) entityplayer.world; // CraftBukkit + ChunkCoordinates chunkcoordinates = worldserver.getSpawn(); + NetServerHandler netserverhandler = new NetServerHandler(this.server, this.networkManager, entityplayer); + //Poseidon Start + netserverhandler.setUsingReleaseToBeta(usingReleaseToBeta); + netserverhandler.setConnectionType(connectionType); + netserverhandler.setRawConnectionType(rawConnectionType); + netserverhandler.setReceivedKeepAlive(receivedKeepAlive); + //Poseidon End + netserverhandler.sendPacket(new Packet1Login("", entityplayer.id, worldserver.getSeed(), (byte) worldserver.worldProvider.dimension)); + netserverhandler.sendPacket(new Packet6SpawnPosition(chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z)); + this.server.serverConfigurationManager.a(entityplayer, worldserver); + // this.server.serverConfigurationManager.sendAll(new Packet3Chat("\u00A7e" + entityplayer.name + " joined the game.")); // CraftBukkit - message moved to join event + this.server.serverConfigurationManager.c(entityplayer); + netserverhandler.a(entityplayer.locX, entityplayer.locY, entityplayer.locZ, entityplayer.yaw, entityplayer.pitch); + this.server.networkListenThread.a(netserverhandler); + netserverhandler.sendPacket(new Packet4UpdateTime(entityplayer.getPlayerTime())); // CraftBukkit - add support for player specific time + entityplayer.syncInventory(); + // poseidon start + if (PoseidonConfig.getInstance().getBoolean("settings.support.modloader.enable", false)) { + net.minecraft.server.ModLoaderMp.HandleAllLogins(entityplayer); + } + // poseidon end + } + + this.c = true; + } + + public void a(String s, Object[] aobject) { + a.info(this.b() + " lost connection"); + this.c = true; + } + + public void a(Packet packet) { + this.disconnect("Protocol error"); + } + + public String b() { + return this.g != null ? this.g + " [" + this.networkManager.getSocketAddress().toString() + "]" : this.networkManager.getSocketAddress().toString(); + } + + //This can and will return null for multiple packets. + public String getUsername() { + return this.g; + } + + public boolean c() { + return true; + } + + /** + * @author moderator_man + * @returns the session id for this player + */ + public String getServerID() { + return serverId; + } + + static String a(NetLoginHandler netloginhandler) { + return netloginhandler.serverId; + } + + public static Packet1Login a(NetLoginHandler netloginhandler, Packet1Login packet1login) { + return netloginhandler.h = packet1login; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraft/server/NetServerHandler.java b/src/main/java/net/minecraft/server/NetServerHandler.java new file mode 100644 index 0000000..cdd70be --- /dev/null +++ b/src/main/java/net/minecraft/server/NetServerHandler.java @@ -0,0 +1,1217 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.Poseidon; +import com.legacyminecraft.poseidon.PoseidonServer; +import com.legacyminecraft.poseidon.event.PlayerSendPacketEvent; +import com.projectposeidon.ConnectionType; +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.command.CommandException; +import org.bukkit.craftbukkit.ChunkCompressionThread; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.TextWrapper; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.entity.Player; +import org.bukkit.entity.StorageMinecart; +import org.bukkit.event.Event; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.packet.PacketReceivedEvent; +import org.bukkit.event.player.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +// CraftBukkit start +// CraftBukkit end + +public class NetServerHandler extends NetHandler implements ICommandListener { + + public static Logger a = Logger.getLogger("Minecraft"); + public NetworkManager networkManager; + public boolean disconnected = false; + private MinecraftServer minecraftServer; + public EntityPlayer player; // CraftBukkit - private -> public + private int f; + private int g; + private int h; + private boolean i; + private double x; + private double y; + private double z; + private boolean checkMovement = true; + private Map n = new HashMap(); + private boolean usingReleaseToBeta = false; //Project Poseidon - Create Variable + private ConnectionType connectionType = ConnectionType.NORMAL; //Project Poseidon - Create Variable + private int rawConnectionType = 0; //Project Poseidon - Create Variable + private boolean receivedKeepAlive = false; + private boolean firePacketEvents; + + private final String msgPlayerLeave; + + public boolean isReceivedKeepAlive() { + return receivedKeepAlive; + } + + public void setReceivedKeepAlive(boolean receivedKeepAlive) { + this.receivedKeepAlive = receivedKeepAlive; + } + + public NetServerHandler(MinecraftServer minecraftserver, NetworkManager networkmanager, EntityPlayer entityplayer) { + this.minecraftServer = minecraftserver; + this.networkManager = networkmanager; + networkmanager.a((NetHandler) this); + this.player = entityplayer; + entityplayer.netServerHandler = this; + + // CraftBukkit start + this.server = minecraftserver.server; + this.firePacketEvents = PoseidonConfig.getInstance().getBoolean("settings.packet-events.enabled", false); //Poseidon + this.msgPlayerLeave = PoseidonConfig.getInstance().getConfigString("message.player.leave"); + } + + //Project Poseidon - Start + public boolean isUsingReleaseToBeta() { + return usingReleaseToBeta; + } + + public void setUsingReleaseToBeta(boolean usingReleaseToBeta) { + this.usingReleaseToBeta = usingReleaseToBeta; + } + + public ConnectionType getConnectionType() { + return this.connectionType; + } + + public void setConnectionType(ConnectionType connectionType) { + this.connectionType = connectionType; + } + + public void setRawConnectionType(int rawConnectionType) { + this.rawConnectionType = rawConnectionType; + } + + public int getRawConnectionType() { + return this.rawConnectionType; + } + + + //Project Poseidon - End + + private final CraftServer server; + private int lastTick = MinecraftServer.currentTick; + private int lastDropTick = MinecraftServer.currentTick; + private int dropCount = 0; + private static final int PLACE_DISTANCE_SQUARED = 6 * 6; + + // Get position of last block hit for BlockDamageLevel.STOPPED + private double lastPosX = Double.MAX_VALUE; + private double lastPosY = Double.MAX_VALUE; + private double lastPosZ = Double.MAX_VALUE; + private float lastPitch = Float.MAX_VALUE; + private float lastYaw = Float.MAX_VALUE; + private boolean justTeleported = false; + + // For the packet15 hack :( + Long lastPacket; + + // Store the last block right clicked and what type it was + private int lastMaterial; + + public CraftPlayer getPlayer() { + return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity(); + } + // CraftBukkit end + + public void a() { + this.i = false; + this.networkManager.b(); + if (this.f - this.g > 20) { + this.sendPacket(new Packet0KeepAlive()); + } + } + + public void disconnect(String s) { + if (disconnected) return; // Poseidon: Kick/Disconnect spam fix + + // CraftBukkit start + String leaveMessage = this.msgPlayerLeave.replace("%player%", this.player.name); + + PlayerKickEvent event = new PlayerKickEvent(this.server.getPlayer(this.player), s, leaveMessage); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + // Do not kick the player + return; + } + // Send the possibly modified leave message + s = event.getReason(); + // CraftBukkit end + + this.player.B(); + this.sendPacket(new Packet255KickDisconnect(s)); + this.networkManager.d(); + + // CraftBukkit start + leaveMessage = event.getLeaveMessage(); + if (leaveMessage != null) { + this.minecraftServer.serverConfigurationManager.sendAll(new Packet3Chat(leaveMessage)); + } + // CraftBukkit end + + this.minecraftServer.serverConfigurationManager.disconnect(this.player); + this.disconnected = true; + } + + public void a(Packet27 packet27) { + // poseidon + PacketReceivedEvent event = new PacketReceivedEvent(server.getPlayer(player), packet27); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + return; + + this.player.a(packet27.c(), packet27.e(), packet27.g(), packet27.h(), packet27.d(), packet27.f()); + } + + public void a(Packet10Flying packet10flying) { + // poseidon + PacketReceivedEvent pevent = new PacketReceivedEvent(server.getPlayer(player), packet10flying); + server.getPluginManager().callEvent(pevent); + if (pevent.isCancelled()) + return; + + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + + this.i = true; + double d0; + + if (!this.checkMovement) { + d0 = packet10flying.y - this.y; + if (packet10flying.x == this.x && d0 * d0 < 0.01D && packet10flying.z == this.z) { + this.checkMovement = true; + } + } + + // CraftBukkit start + Player player = this.getPlayer(); + Location from = new Location(player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch); // Get the Players previous Event location. + Location to = player.getLocation().clone(); // Start off the To location as the Players current location. + + // If the packet contains movement information then we update the To location with the correct XYZ. + if (packet10flying.h && !(packet10flying.h && packet10flying.y == -999.0D && packet10flying.stance == -999.0D)) { + to.setX(packet10flying.x); + to.setY(packet10flying.y); + to.setZ(packet10flying.z); + } + + // If the packet contains look information then we update the To location with the correct Yaw & Pitch. + if (packet10flying.hasLook) { + to.setYaw(packet10flying.yaw); + to.setPitch(packet10flying.pitch); + } + + // Prevent 40 event-calls for less than a single pixel of movement >.> + double delta = Math.pow(this.lastPosX - to.getX(), 2) + Math.pow(this.lastPosY - to.getY(), 2) + Math.pow(this.lastPosZ - to.getZ(), 2); + float deltaAngle = Math.abs(this.lastYaw - to.getYaw()) + Math.abs(this.lastPitch - to.getPitch()); + + if ((delta > 1f / 256 || deltaAngle > 10f) && (this.checkMovement && !this.player.dead)) { + this.lastPosX = to.getX(); + this.lastPosY = to.getY(); + this.lastPosZ = to.getZ(); + this.lastYaw = to.getYaw(); + this.lastPitch = to.getPitch(); + + // Skip the first time we do this + if (from.getX() != Double.MAX_VALUE) { + PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); + this.server.getPluginManager().callEvent(event); + + // If the event is cancelled we move the player back to their old location. + if (event.isCancelled()) { + this.player.netServerHandler.sendPacket(new Packet13PlayerLookMove(from.getX(), from.getY() + 1.6200000047683716D, from.getY(), from.getZ(), from.getYaw(), from.getPitch(), false)); + return; + } + + /* If a Plugin has changed the To destination then we teleport the Player + there to avoid any 'Moved wrongly' or 'Moved too quickly' errors. + We only do this if the Event was not cancelled. */ + if (!to.equals(event.getTo()) && !event.isCancelled()) { + this.player.getBukkitEntity().teleport(event.getTo()); + return; + } + + /* Check to see if the Players Location has some how changed during the call of the event. + This can happen due to a plugin teleporting the player instead of using .setTo() */ + if (!from.equals(this.getPlayer().getLocation()) && this.justTeleported) { + this.justTeleported = false; + return; + } + } + } + + if (Double.isNaN(packet10flying.x) || Double.isNaN(packet10flying.y) || Double.isNaN(packet10flying.z) || Double.isNaN(packet10flying.stance) && player.isOnline() && !disconnected) { + player.teleport(player.getWorld().getSpawnLocation()); + System.err.println(player.getName() + " was caught trying to crash the server with an invalid position."); + player.kickPlayer("Nope!"); + return; + } + + if (this.checkMovement && !this.player.dead) { + // CraftBukkit end + double d1; + double d2; + double d3; + double d4; + + if (this.player.vehicle != null) { + float f = this.player.yaw; + float f1 = this.player.pitch; + + this.player.vehicle.f(); + d1 = this.player.locX; + d2 = this.player.locY; + d3 = this.player.locZ; + double d5 = 0.0D; + + d4 = 0.0D; + if (packet10flying.hasLook) { + f = packet10flying.yaw; + f1 = packet10flying.pitch; + } + + if (packet10flying.h && packet10flying.y == -999.0D && packet10flying.stance == -999.0D) { + d5 = packet10flying.x; + d4 = packet10flying.z; + + // Project Poseidon - Start + // Boat crash fix ported from UberBukkit + + double d8 = d5 * d5 + d4 * d4; + if (d8 > 100.0D) { + a.warning("[Poseidon]" + this.player.name + " tried crashing server on entity " + this.player.vehicle.toString() + ". They have been kicked."); + player.kickPlayer("Boat crash attempt detected!"); + return; + } + + // Project Poseidon - End + + } + + this.player.onGround = packet10flying.g; + this.player.a(true); + this.player.move(d5, 0.0D, d4); + this.player.setLocation(d1, d2, d3, f, f1); + this.player.motX = d5; + this.player.motZ = d4; + if (this.player.vehicle != null) { + worldserver.vehicleEnteredWorld(this.player.vehicle, true); + } + + if (this.player.vehicle != null) { + this.player.vehicle.f(); + this.player.vehicle.airBorne = true; + } + + this.minecraftServer.serverConfigurationManager.d(this.player); + this.x = this.player.locX; + this.y = this.player.locY; + this.z = this.player.locZ; + worldserver.playerJoinedWorld(this.player); + return; + } + + if (this.player.isSleeping()) { + this.player.a(true); + this.player.setLocation(this.x, this.y, this.z, this.player.yaw, this.player.pitch); + worldserver.playerJoinedWorld(this.player); + return; + } + + d0 = this.player.locY; + this.x = this.player.locX; + this.y = this.player.locY; + this.z = this.player.locZ; + d1 = this.player.locX; + d2 = this.player.locY; + d3 = this.player.locZ; + float f2 = this.player.yaw; + float f3 = this.player.pitch; + + if (packet10flying.h && packet10flying.y == -999.0D && packet10flying.stance == -999.0D) { + packet10flying.h = false; + } + + if (packet10flying.h) { + d1 = packet10flying.x; + d2 = packet10flying.y; + d3 = packet10flying.z; + d4 = packet10flying.stance - packet10flying.y; + if (!this.player.isSleeping() && (d4 > 1.65D || d4 < 0.1D)) { + this.disconnect("Illegal stance"); + a.warning(this.player.name + " had an illegal stance: " + d4); + return; + } + + if (Math.abs(packet10flying.x) > 3.2E7D || Math.abs(packet10flying.z) > 3.2E7D) { + this.disconnect("Illegal position"); + return; + } + } + + if (packet10flying.hasLook) { + f2 = packet10flying.yaw; + f3 = packet10flying.pitch; + } + + this.player.a(true); + this.player.br = 0.0F; + this.player.setLocation(this.x, this.y, this.z, f2, f3); + if (!this.checkMovement) { + return; + } + + d4 = d1 - this.player.locX; + double d6 = d2 - this.player.locY; + double d7 = d3 - this.player.locZ; + double d14 = this.player.motX * this.player.motX + this.player.motY * this.player.motY + this.player.motZ * this.player.motZ; + double d8 = d4 * d4 + d6 * d6 + d7 * d7; + + if ((boolean) PoseidonConfig.getInstance().getConfigOption("world.settings.speed-hack-check.enabled", true)) { + if (d8 - d14 > (double) PoseidonConfig.getInstance().getConfigOption("world.settings.speed-hack-check.distance", 100.0D) && this.checkMovement) { // CraftBukkit - Added this.checkMovement condition to solve this check being triggered by teleports + a.warning(this.player.name + " moved too quickly! " + d4 + "," + d6 + "," + d7 + " (" + d4 + ", " + d6 + ", " + d7 + ")"); + if ((boolean) PoseidonConfig.getInstance().getConfigOption("world.settings.speed-hack-check.teleport", true)) { + this.a(this.x, this.y, this.z, this.player.yaw, this.player.pitch); + } else { + this.disconnect("You moved too quickly :( (Hacking?)"); + } + return; + } + } + + float f4 = 0.0625F; + boolean flag = worldserver.getEntities(this.player, this.player.boundingBox.clone().shrink((double) f4, (double) f4, (double) f4)).size() == 0; + + this.player.move(d4, d6, d7); + d4 = d1 - this.player.locX; + d6 = d2 - this.player.locY; + if (d6 > -0.5D || d6 < 0.5D) { + d6 = 0.0D; + } + + d7 = d3 - this.player.locZ; + d8 = d4 * d4 + d6 * d6 + d7 * d7; + boolean flag1 = false; + + if (d8 > 0.0625D && !this.player.isSleeping()) { + flag1 = true; + a.warning(this.player.name + " moved wrongly!"); + System.out.println("Got position " + d1 + ", " + d2 + ", " + d3); + System.out.println("Expected " + this.player.locX + ", " + this.player.locY + ", " + this.player.locZ); + } + + this.player.setLocation(d1, d2, d3, f2, f3); + boolean flag2 = worldserver.getEntities(this.player, this.player.boundingBox.clone().shrink((double) f4, (double) f4, (double) f4)).size() == 0; + + if (flag && (flag1 || !flag2) && !this.player.isSleeping()) { + this.a(this.x, this.y, this.z, f2, f3); + return; + } + + AxisAlignedBB axisalignedbb = this.player.boundingBox.clone().b((double) f4, (double) f4, (double) f4).a(0.0D, -0.55D, 0.0D); + + if (!this.minecraftServer.allowFlight && !worldserver.b(axisalignedbb)) { + if (d6 >= -0.03125D) { + ++this.h; + if (this.h > 80) { + a.warning(this.player.name + " was kicked for floating too long!"); + this.disconnect("Flying is not enabled on this server"); + return; + } + } + } else { + this.h = 0; + } + + this.player.onGround = packet10flying.g; + this.minecraftServer.serverConfigurationManager.d(this.player); + this.player.b(this.player.locY - d0, packet10flying.g); + } + } + + public void a(double d0, double d1, double d2, float f, float f1) { + // CraftBukkit start - Delegate to teleport(Location) + Player player = this.getPlayer(); + Location from = player.getLocation(); + Location to = new Location(this.getPlayer().getWorld(), d0, d1, d2, f, f1); + PlayerTeleportEvent event = new PlayerTeleportEvent(player, from, to); + this.server.getPluginManager().callEvent(event); + + from = event.getFrom(); + to = event.isCancelled() ? from : event.getTo(); + + this.teleport(to); + } + + public void teleport(Location dest) { + double d0, d1, d2; + float f, f1; + + d0 = dest.getX(); + d1 = dest.getY(); + d2 = dest.getZ(); + f = dest.getYaw(); + f1 = dest.getPitch(); + + // TODO: make sure this is the best way to address this. + if (Float.isNaN(f)) { + f = 0; + } + + if (Float.isNaN(f1)) { + f1 = 0; + } + + this.lastPosX = d0; + this.lastPosY = d1; + this.lastPosZ = d2; + this.lastYaw = f; + this.lastPitch = f1; + this.justTeleported = true; + // CraftBukkit end + + this.checkMovement = false; + this.x = d0; + this.y = d1; + this.z = d2; + this.player.setLocation(d0, d1, d2, f, f1); + this.player.netServerHandler.sendPacket(new Packet13PlayerLookMove(d0, d1 + 1.6200000047683716D, d1, d2, f, f1, false)); + } + + public void a(Packet14BlockDig packet14blockdig) { + // poseidon + PacketReceivedEvent event = new PacketReceivedEvent(server.getPlayer(player), packet14blockdig); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + return; + + if (this.player.dead) return; // CraftBukkit + + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + + if (packet14blockdig.e == 4) { + // CraftBukkit start + // If the ticks aren't the same then the count starts from 0 and we update the lastDropTick. + if (this.lastDropTick != MinecraftServer.currentTick) { + this.dropCount = 0; + this.lastDropTick = MinecraftServer.currentTick; + } else { + // Else we increment the drop count and check the amount. + this.dropCount++; + if (this.dropCount >= 20) { + a.warning(this.player.name + " dropped their items too quickly!"); + this.disconnect("You dropped your items too quickly (Hacking?)"); + } + } + // CraftBukkit end + this.player.F(); + } else { + boolean flag = worldserver.weirdIsOpCache = worldserver.dimension != 0 || this.minecraftServer.serverConfigurationManager.isOp(this.player.name); // CraftBukkit + boolean flag1 = false; + + if (packet14blockdig.e == 0) { + flag1 = true; + } + + if (packet14blockdig.e == 2) { + flag1 = true; + } + + int i = packet14blockdig.a; + int j = packet14blockdig.b; + int k = packet14blockdig.c; + + if (flag1) { + double d0 = this.player.locX - ((double) i + 0.5D); + double d1 = this.player.locY - ((double) j + 0.5D); + double d2 = this.player.locZ - ((double) k + 0.5D); + double d3 = d0 * d0 + d1 * d1 + d2 * d2; + + if (d3 > 36.0D) { + return; + } + } + + ChunkCoordinates chunkcoordinates = worldserver.getSpawn(); + int l = (int) MathHelper.abs((float) (i - chunkcoordinates.x)); + int i1 = (int) MathHelper.abs((float) (k - chunkcoordinates.z)); + + if (l > i1) { + i1 = l; + } + + if (packet14blockdig.e == 0) { + // CraftBukkit + if (i1 < this.server.getSpawnRadius() && !flag) { + this.player.netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, worldserver)); + } else { + // CraftBukkit - add face argument + this.player.itemInWorldManager.dig(i, j, k, packet14blockdig.face); + } + } else if (packet14blockdig.e == 2) { + this.player.itemInWorldManager.a(i, j, k); + if (worldserver.getTypeId(i, j, k) != 0) { + this.player.netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, worldserver)); + } + } else if (packet14blockdig.e == 3) { + double d4 = this.player.locX - ((double) i + 0.5D); + double d5 = this.player.locY - ((double) j + 0.5D); + double d6 = this.player.locZ - ((double) k + 0.5D); + double d7 = d4 * d4 + d5 * d5 + d6 * d6; + + if (d7 < 256.0D) { + this.player.netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, worldserver)); + } + } + + worldserver.weirdIsOpCache = false; + } + } + + public void a(Packet15Place packet15place) { + // poseidon + PacketReceivedEvent pevent = new PacketReceivedEvent(server.getPlayer(player), packet15place); + server.getPluginManager().callEvent(pevent); + if (pevent.isCancelled()) + return; + + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + + // CraftBukkit start + if (this.player.dead) return; + + // This is a horrible hack needed because the client sends 2 packets on 'right mouse click' + // aimed at a block. We shouldn't need to get the second packet if the data is handled + // but we cannot know what the client will do, so we might still get it + // + // If the time between packets is small enough, and the 'signature' similar, we discard the + // second one. This sadly has to remain until Mojang makes their packets saner. :( + // -- Grum + + if (packet15place.face == 255) { + if (packet15place.itemstack != null && packet15place.itemstack.id == this.lastMaterial && this.lastPacket != null && packet15place.timestamp - this.lastPacket < 100) { + this.lastPacket = null; + return; + } + } else { + this.lastMaterial = packet15place.itemstack == null ? -1 : packet15place.itemstack.id; + this.lastPacket = packet15place.timestamp; + } + + // CraftBukkit - if rightclick decremented the item, always send the update packet. + // this is not here for CraftBukkit's own functionality; rather it is to fix + // a notch bug where the item doesn't update correctly. + boolean always = false; + + // CraftBukkit end + + ItemStack itemstack = this.player.inventory.getItemInHand(); + boolean flag = worldserver.weirdIsOpCache = worldserver.dimension != 0 || this.minecraftServer.serverConfigurationManager.isOp(this.player.name); // CraftBukkit + + if (packet15place.face == 255) { + if (itemstack == null) { + return; + } + + // CraftBukkit start + int itemstackAmount = itemstack.count; + PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemstack); + if (event.useItemInHand() != Event.Result.DENY) { + this.player.itemInWorldManager.useItem(this.player, this.player.world, itemstack); + } + + // CraftBukkit - notch decrements the counter by 1 in the above method with food, + // snowballs and so forth, but he does it in a place that doesn't cause the + // inventory update packet to get sent + always = (itemstack.count != itemstackAmount); + // CraftBukkit end + } else { + int i = packet15place.a; + int j = packet15place.b; + int k = packet15place.c; + int l = packet15place.face; + ChunkCoordinates chunkcoordinates = worldserver.getSpawn(); + int i1 = (int) MathHelper.abs((float) (i - chunkcoordinates.x)); + int j1 = (int) MathHelper.abs((float) (k - chunkcoordinates.z)); + + if (i1 > j1) { + j1 = i1; + } + + // CraftBukkit start - Check if we can actually do something over this large a distance + Location eyeLoc = this.getPlayer().getEyeLocation(); + if (Math.pow(eyeLoc.getX() - i, 2) + Math.pow(eyeLoc.getY() - j, 2) + Math.pow(eyeLoc.getZ() - k, 2) > PLACE_DISTANCE_SQUARED) { + return; + } + flag = true; // spawn protection moved to ItemBlock!!! + // CraftBukkit end + + if (j1 > 16 || flag) { + this.player.itemInWorldManager.interact(this.player, worldserver, itemstack, i, j, k, l); + } + + this.player.netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, worldserver)); + if (l == 0) { + --j; + } + + if (l == 1) { + ++j; + } + + if (l == 2) { + --k; + } + + if (l == 3) { + ++k; + } + + if (l == 4) { + --i; + } + + if (l == 5) { + ++i; + } + + this.player.netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, worldserver)); + } + + itemstack = this.player.inventory.getItemInHand(); + if (itemstack != null && itemstack.count == 0) { + this.player.inventory.items[this.player.inventory.itemInHandIndex] = null; + } + + this.player.h = true; + this.player.inventory.items[this.player.inventory.itemInHandIndex] = ItemStack.b(this.player.inventory.items[this.player.inventory.itemInHandIndex]); + Slot slot = this.player.activeContainer.a(this.player.inventory, this.player.inventory.itemInHandIndex); + + this.player.activeContainer.a(); + this.player.h = false; + // CraftBukkit + if (!ItemStack.equals(this.player.inventory.getItemInHand(), packet15place.itemstack) || always) { + this.sendPacket(new Packet103SetSlot(this.player.activeContainer.windowId, slot.a, this.player.inventory.getItemInHand())); + } + + worldserver.weirdIsOpCache = false; + } + + public void a(String s, Object[] aobject) { + if (this.disconnected) return; // CraftBukkit - rarely it would send a disconnect line twice + + + if (!(boolean) PoseidonConfig.getInstance().getConfigOption("settings.remove-join-leave-debug", true) || !s.equals("disconnect.quitting")) { + a.info(this.player.name + " lost connection: " + s); + } + + a.info(this.player.name + " has left the game."); + // CraftBukkit start - we need to handle custom quit messages + String quitMessage = this.minecraftServer.serverConfigurationManager.disconnect(this.player); + if (quitMessage != null) { + this.minecraftServer.serverConfigurationManager.sendAll(new Packet3Chat(quitMessage)); + } + // CraftBukkit end + this.disconnected = true; + } + + public void a(Packet packet) { + a.warning(this.getClass() + " wasn\'t prepared to deal with a " + packet.getClass()); + this.disconnect("Protocol error, unexpected packet"); + } + + public void sendPacket(Packet packet) { + //Poseidon Start - Send Packet Event + if (packet == null) // Why do anything if there's no packet? (fixes Internal server error) + return; + + if (firePacketEvents) { + PlayerSendPacketEvent event = new PlayerSendPacketEvent(this.player.name, packet); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + packet = event.getPacket(); //In case a plugin replaces the entire packet + } + //Poseidon End + + + // CraftBukkit start + if (packet instanceof Packet6SpawnPosition) { + Packet6SpawnPosition packet6 = (Packet6SpawnPosition) packet; + this.player.compassTarget = new Location(this.getPlayer().getWorld(), packet6.x, packet6.y, packet6.z); + } else if (packet instanceof Packet3Chat) { + String message = ((Packet3Chat) packet).message; + for (final String line : TextWrapper.wrapText(message)) { + this.networkManager.queue(new Packet3Chat(line)); + } + packet = null; + } else if (packet.k == true) { + // Reroute all low-priority packets through to compression thread. + ChunkCompressionThread.sendPacket(this.player, packet); + packet = null; + } + if (packet != null) this.networkManager.queue(packet); + // CraftBukkit end + + this.g = this.f; + } + + public void a(Packet16BlockItemSwitch packet16blockitemswitch) { + // poseidon + PacketReceivedEvent pevent = new PacketReceivedEvent(server.getPlayer(player), packet16blockitemswitch); + server.getPluginManager().callEvent(pevent); + if (pevent.isCancelled()) + return; + + if (this.player.dead) return; // CraftBukkit + + if (packet16blockitemswitch.itemInHandIndex >= 0 && packet16blockitemswitch.itemInHandIndex <= InventoryPlayer.e()) { + // CraftBukkit start + PlayerItemHeldEvent event = new PlayerItemHeldEvent(this.getPlayer(), this.player.inventory.itemInHandIndex, packet16blockitemswitch.itemInHandIndex); + this.server.getPluginManager().callEvent(event); + // CraftBukkit end + + this.player.inventory.itemInHandIndex = packet16blockitemswitch.itemInHandIndex; + } else { + a.warning(this.player.name + " tried to set an invalid carried item"); + this.disconnect("Invalid hotbar selection (Hacking?)"); + } + } + + public void a(Packet3Chat packet3chat) { + // poseidon + PacketReceivedEvent event = new PacketReceivedEvent(server.getPlayer(player), packet3chat); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + return; + + String s = packet3chat.message; + + if (s.length() > 100) { + this.disconnect("Chat message too long"); + } else { + s = s.trim(); + + for (int i = 0; i < s.length(); ++i) { + if (FontAllowedCharacters.allowedCharacters.indexOf(s.charAt(i)) < 0) { + this.disconnect("Illegal characters in chat"); + return; + } + } + + // CraftBukkit start + this.chat(s); + } + } + + public boolean chat(String s) { + if (!this.player.dead) { + if (s.startsWith("/")) { + this.handleCommand(s); + return true; + } else { + Player player = this.getPlayer(); + PlayerChatEvent event = new PlayerChatEvent(player, s); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return true; + } + + s = String.format(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()); + minecraftServer.console.sendMessage(s); + for (Player recipient : event.getRecipients()) { + recipient.sendMessage(s); + } + } + } + + return false; + // CraftBukkit end + } + + private void handleCommand(String s) { + // CraftBukkit start + CraftPlayer player = this.getPlayer(); + + PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(player, s); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + s = event.getMessage(); //Poseidon: Override command with new command string. + + try { + if (this.server.dispatchCommand(player, s.substring(1))) { + //Project Poseidon Start + //Hide commands from being logged in console + String cmdName = s.split(" ")[0].replaceAll("/", ""); + + if (Poseidon.getServer().isCommandHidden(cmdName)) { + a.info(player.getName() + " issued server command: COMMAND REDACTED"); + } else { + a.info(player.getName() + " issued server command: " + s); + } + + //Project Poseidon End + return; + } + } catch (CommandException ex) { + player.sendMessage(ChatColor.RED + "An internal error occurred while attempting to perform this command"); + Logger.getLogger(NetServerHandler.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + return; + } + // CraftBukkit end + + /* CraftBukkit start - No longer neaded av we have already handled it server.dispatchCommand above. + if (s.toLowerCase().startsWith("/me ")) { + s = "* " + this.player.name + " " + s.substring(s.indexOf(" ")).trim(); + a.info(s); + this.minecraftServer.serverConfigurationManager.sendAll(new Packet3Chat(s)); + } else if (s.toLowerCase().startsWith("/kill")) { + this.player.damageEntity(this.player, 1000); // CraftBukkit - replace null entity with player entity; TODO: decide if we want damage with a null source to fire an event. + } else if (s.toLowerCase().startsWith("/tell ")) { + String[] astring = s.split(" "); + + if (astring.length >= 3) { + s = s.substring(s.indexOf(" ")).trim(); + s = s.substring(s.indexOf(" ")).trim(); + s = "\u00A77" + this.player.name + " whispers " + s; + a.info(s + " to " + astring[1]); + if (!this.minecraftServer.serverConfigurationManager.a(astring[1], (Packet) (new Packet3Chat(s)))) { + this.sendPacket(new Packet3Chat("\u00A7cThere\'s no player by that name online.")); + } + } + } else { + String s1; + + if (this.minecraftServer.serverConfigurationManager.isOp(this.player.name)) { + s1 = s.substring(1); + a.info(this.player.name + " issued server command: " + s1); + this.minecraftServer.issueCommand(s1, this); + } else { + s1 = s.substring(1); + a.info(this.player.name + " tried command: " + s1); + } + } + // CraftBukkit end */ + } + + public void a(Packet18ArmAnimation packet18armanimation) { + // poseidon + PacketReceivedEvent pevent = new PacketReceivedEvent(server.getPlayer(player), packet18armanimation); + server.getPluginManager().callEvent(pevent); + if (pevent.isCancelled()) + return; + + if (this.player.dead) return; // CraftBukkit + + if (packet18armanimation.b == 1) { + // CraftBukkit start - raytrace to look for 'rogue armswings' + float f = 1.0F; + float f1 = this.player.lastPitch + (this.player.pitch - this.player.lastPitch) * f; + float f2 = this.player.lastYaw + (this.player.yaw - this.player.lastYaw) * f; + double d0 = this.player.lastX + (this.player.locX - this.player.lastX) * (double) f; + double d1 = this.player.lastY + (this.player.locY - this.player.lastY) * (double) f + 1.62D - (double) this.player.height; + double d2 = this.player.lastZ + (this.player.locZ - this.player.lastZ) * (double) f; + Vec3D vec3d = Vec3D.create(d0, d1, d2); + + float f3 = MathHelper.cos(-f2 * 0.017453292F - 3.1415927F); + float f4 = MathHelper.sin(-f2 * 0.017453292F - 3.1415927F); + float f5 = -MathHelper.cos(-f1 * 0.017453292F); + float f6 = MathHelper.sin(-f1 * 0.017453292F); + float f7 = f4 * f5; + float f8 = f3 * f5; + double d3 = 5.0D; + Vec3D vec3d1 = vec3d.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3); + MovingObjectPosition movingobjectposition = this.player.world.rayTrace(vec3d, vec3d1, true); + + if (movingobjectposition == null || movingobjectposition.type != EnumMovingObjectType.TILE) { + CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_AIR, this.player.inventory.getItemInHand()); + } + + // Arm swing animation + PlayerAnimationEvent event = new PlayerAnimationEvent(this.getPlayer()); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) return; + // CraftBukkit end + + this.player.w(); + } + } + + public void a(Packet19EntityAction packet19entityaction) { + // poseidon + PacketReceivedEvent pevent = new PacketReceivedEvent(server.getPlayer(player), packet19entityaction); + server.getPluginManager().callEvent(pevent); + if (pevent.isCancelled()) + return; + + // CraftBukkit start + if (this.player.dead) return; + + if (packet19entityaction.animation == 1 || packet19entityaction.animation == 2) { + PlayerToggleSneakEvent event = new PlayerToggleSneakEvent(this.getPlayer(), packet19entityaction.animation == 1); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + } + // CraftBukkit end + + if (packet19entityaction.animation == 1) { + this.player.setSneak(true); + } else if (packet19entityaction.animation == 2) { + this.player.setSneak(false); + } else if (packet19entityaction.animation == 3) { + this.player.a(false, true, true); + this.checkMovement = false; + } + } + + public void a(Packet0KeepAlive packet0KeepAlive) { + this.receivedKeepAlive = true; + } + + public void a(Packet255KickDisconnect packet255kickdisconnect) { + // poseidon + PacketReceivedEvent event = new PacketReceivedEvent(server.getPlayer(player), packet255kickdisconnect); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + return; + + this.networkManager.a("disconnect.quitting", new Object[0]); + } + + public int b() { + return this.networkManager.e(); + } + + public void sendMessage(String s) { + this.sendPacket(new Packet3Chat("\u00A77" + s)); + } + + public String getName() { + return this.player.name; + } + + public void a(Packet7UseEntity packet7useentity) { + // poseidon + PacketReceivedEvent pevent = new PacketReceivedEvent(server.getPlayer(player), packet7useentity); + server.getPluginManager().callEvent(pevent); + if (pevent.isCancelled()) + return; + + if (this.player.dead) return; // CraftBukkit + + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + Entity entity = worldserver.getEntity(packet7useentity.target); + ItemStack itemInHand = this.player.inventory.getItemInHand(); + + if (entity != null && this.player.e(entity) && this.player.g(entity) < 36.0D) { + if (packet7useentity.c == 0) { + Player player = (Player) this.getPlayer(); + org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); + // CraftBukkit start + //Project Poseidon Start - Fixes a Minecart dupe glitch + if (player.isInsideVehicle() && bukkitEntity instanceof StorageMinecart) { + return; + } + //Project Poseidon End + PlayerInteractEntityEvent event = new PlayerInteractEntityEvent(player, bukkitEntity); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end + this.player.c(entity); + // CraftBukkit start - update the client if the item is an infinite one + if (itemInHand != null && itemInHand.count <= -1) { + this.player.updateInventory(this.player.activeContainer); + } + // CraftBukkit end + } else if (packet7useentity.c == 1) { + this.player.d(entity); + // CraftBukkit start - update the client if the item is an infinite one + if (itemInHand != null && itemInHand.count <= -1) { + this.player.updateInventory(this.player.activeContainer); + } + // CraftBukkit end + } + } + } + + public void a(Packet9Respawn packet9respawn) { + // poseidon + PacketReceivedEvent event = new PacketReceivedEvent(server.getPlayer(player), packet9respawn); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + return; + + if (this.player.health <= 0) { + this.player = this.minecraftServer.serverConfigurationManager.moveToWorld(this.player, 0); + + this.getPlayer().setHandle(this.player); // CraftBukkit + } + } + + public void a(Packet101CloseWindow packet101closewindow) { + if (this.player.dead) return; // CraftBukkit + + this.player.A(); + } + + public void a(Packet102WindowClick packet102windowclick) { + // poseidon + PacketReceivedEvent event = new PacketReceivedEvent(server.getPlayer(player), packet102windowclick); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + return; + + if (this.player.dead) return; // CraftBukkit + + if (this.player.activeContainer.windowId == packet102windowclick.a && this.player.activeContainer.c(this.player)) { + ItemStack itemstack = this.player.activeContainer.a(packet102windowclick.b, packet102windowclick.c, packet102windowclick.f, this.player); + + if (ItemStack.equals(packet102windowclick.e, itemstack)) { + this.player.netServerHandler.sendPacket(new Packet106Transaction(packet102windowclick.a, packet102windowclick.d, true)); + this.player.h = true; + this.player.activeContainer.a(); + this.player.z(); + this.player.h = false; + } else { + this.n.put(Integer.valueOf(this.player.activeContainer.windowId), Short.valueOf(packet102windowclick.d)); + this.player.netServerHandler.sendPacket(new Packet106Transaction(packet102windowclick.a, packet102windowclick.d, false)); + this.player.activeContainer.a(this.player, false); + ArrayList arraylist = new ArrayList(); + + for (int i = 0; i < this.player.activeContainer.e.size(); ++i) { + arraylist.add(((Slot) this.player.activeContainer.e.get(i)).getItem()); + } + + this.player.a(this.player.activeContainer, arraylist); + } + } + } + + public void a(Packet106Transaction packet106transaction) { + // poseidon + PacketReceivedEvent event = new PacketReceivedEvent(server.getPlayer(player), packet106transaction); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + return; + + if (this.player.dead) return; // CraftBukkit + + Short oshort = (Short) this.n.get(Integer.valueOf(this.player.activeContainer.windowId)); + + if (oshort != null && packet106transaction.b == oshort.shortValue() && this.player.activeContainer.windowId == packet106transaction.a && !this.player.activeContainer.c(this.player)) { + this.player.activeContainer.a(this.player, true); + } + } + + public void a(Packet130UpdateSign packet130updatesign) { + // poseidon + PacketReceivedEvent pevent = new PacketReceivedEvent(server.getPlayer(player), packet130updatesign); + server.getPluginManager().callEvent(pevent); + if (pevent.isCancelled()) + return; + + if (this.player.dead) return; // CraftBukkit + + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + + if (worldserver.isLoaded(packet130updatesign.x, packet130updatesign.y, packet130updatesign.z)) { + TileEntity tileentity = worldserver.getTileEntity(packet130updatesign.x, packet130updatesign.y, packet130updatesign.z); + + if (tileentity instanceof TileEntitySign) { + TileEntitySign tileentitysign = (TileEntitySign) tileentity; + + if (!tileentitysign.a()) { + this.minecraftServer.c("Player " + this.player.name + " just tried to change non-editable sign"); + // CraftBukkit + this.sendPacket(new Packet130UpdateSign(packet130updatesign.x, packet130updatesign.y, packet130updatesign.z, tileentitysign.lines)); + return; + } + + // Poseidon start - check if player editing sign is the same player who placed the sign + if (!tileentitysign.isEditableBy(this.player)) { + this.minecraftServer.c("Player " + this.player.name + " just tried to change a sign they are not editing"); + this.sendPacket(new Packet130UpdateSign(packet130updatesign.x, packet130updatesign.y, packet130updatesign.z, tileentitysign.lines)); + return; + } + // Poseidon end + } + + int i; + int j; + + for (j = 0; j < 4; ++j) { + boolean flag = true; + + if (packet130updatesign.lines[j].length() > 15) { + flag = false; + } else { + for (i = 0; i < packet130updatesign.lines[j].length(); ++i) { + if (FontAllowedCharacters.allowedCharacters.indexOf(packet130updatesign.lines[j].charAt(i)) < 0) { + flag = false; + } + } + } + + if (!flag) { + packet130updatesign.lines[j] = "!?"; + } + } + + if (tileentity instanceof TileEntitySign) { + j = packet130updatesign.x; + int k = packet130updatesign.y; + + i = packet130updatesign.z; + TileEntitySign tileentitysign1 = (TileEntitySign) tileentity; + + // CraftBukkit start + Player player = this.server.getPlayer(this.player); + SignChangeEvent event = new SignChangeEvent((CraftBlock) player.getWorld().getBlockAt(j, k, i), this.server.getPlayer(this.player), packet130updatesign.lines); + this.server.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + for (int l = 0; l < 4; ++l) { + tileentitysign1.lines[l] = event.getLine(l); + } + } + tileentitysign1.a(false); // Poseidon + // CraftBukkit end + + tileentitysign1.update(); + worldserver.notify(j, k, i); + } + } + } + + public boolean c() { + return true; + } +} diff --git a/src/main/java/net/minecraft/server/NetworkAcceptThread.java b/src/main/java/net/minecraft/server/NetworkAcceptThread.java new file mode 100644 index 0000000..abca5a8 --- /dev/null +++ b/src/main/java/net/minecraft/server/NetworkAcceptThread.java @@ -0,0 +1,45 @@ +package net.minecraft.server; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.util.HashMap; + +class NetworkAcceptThread extends Thread { + + final MinecraftServer a; + + final NetworkListenThread b; + + NetworkAcceptThread(NetworkListenThread networklistenthread, String s, MinecraftServer minecraftserver) { + super(s); + this.b = networklistenthread; + this.a = minecraftserver; + } + + public void run() { + HashMap hashmap = new HashMap(); + + while (this.b.b) { + try { + Socket socket = NetworkListenThread.a(this.b).accept(); + + if (socket != null) { + InetAddress inetaddress = socket.getInetAddress(); + + if (hashmap.containsKey(inetaddress) && !"127.0.0.1".equals(inetaddress.getHostAddress()) && System.currentTimeMillis() - ((Long) hashmap.get(inetaddress)).longValue() < 5000L) { + hashmap.put(inetaddress, Long.valueOf(System.currentTimeMillis())); + socket.close(); + } else { + hashmap.put(inetaddress, Long.valueOf(System.currentTimeMillis())); + NetLoginHandler netloginhandler = new NetLoginHandler(this.a, socket, "Connection #" + NetworkListenThread.b(this.b)); + + NetworkListenThread.a(this.b, netloginhandler); + } + } + } catch (IOException ioexception) { + ioexception.printStackTrace(); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/NetworkListenThread.java b/src/main/java/net/minecraft/server/NetworkListenThread.java new file mode 100644 index 0000000..522b15f --- /dev/null +++ b/src/main/java/net/minecraft/server/NetworkListenThread.java @@ -0,0 +1,97 @@ +package net.minecraft.server; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class NetworkListenThread { + + public static Logger a = Logger.getLogger("Minecraft"); + private ServerSocket d; + private Thread e; + public volatile boolean b = false; + private int f = 0; + private ArrayList g = new ArrayList(); + private ArrayList h = new ArrayList(); + public MinecraftServer c; + + public NetworkListenThread(MinecraftServer minecraftserver, InetAddress inetaddress, int i) throws IOException { + this.c = minecraftserver; + this.d = new ServerSocket(i, 0, inetaddress); + this.d.setPerformancePreferences(0, 2, 1); + this.b = true; + this.e = new NetworkAcceptThread(this, "Listen thread", minecraftserver); + this.e.start(); + } + + public void a(NetServerHandler netserverhandler) { + this.h.add(netserverhandler); + } + + private void a(NetLoginHandler netloginhandler) { + if (netloginhandler == null) { + throw new IllegalArgumentException("Got null pendingconnection!"); + } else { + this.g.add(netloginhandler); + } + } + + public void a() { + int i; + + for (i = 0; i < this.g.size(); ++i) { + NetLoginHandler netloginhandler = (NetLoginHandler) this.g.get(i); + + try { + netloginhandler.a(); + } catch (Exception exception) { + if (netloginhandler == null) { + a.log(Level.WARNING, "Looks like someone tried to crash the server, stopped their attempt."); + this.g.remove(i); + return; + } else { + netloginhandler.disconnect("Internal server error"); + a.log(Level.WARNING, "Failed to handle packet: " + exception, exception); + } + } + + if (netloginhandler.c) { + this.g.remove(i--); + } + + netloginhandler.networkManager.a(); + } + + for (i = 0; i < this.h.size(); ++i) { + NetServerHandler netserverhandler = (NetServerHandler) this.h.get(i); + + try { + netserverhandler.a(); + } catch (Exception exception1) { + a.log(Level.WARNING, "Failed to handle packet: " + exception1, exception1); + netserverhandler.disconnect("Internal server error"); + } + + if (netserverhandler.disconnected) { + this.h.remove(i--); + } + + netserverhandler.networkManager.a(); + } + } + + static ServerSocket a(NetworkListenThread networklistenthread) { + return networklistenthread.d; + } + + static int b(NetworkListenThread networklistenthread) { + return networklistenthread.f++; + } + + static void a(NetworkListenThread networklistenthread, NetLoginHandler netloginhandler) { + networklistenthread.a(netloginhandler); + } +} diff --git a/src/main/java/net/minecraft/server/NetworkManager.java b/src/main/java/net/minecraft/server/NetworkManager.java new file mode 100644 index 0000000..c90a93a --- /dev/null +++ b/src/main/java/net/minecraft/server/NetworkManager.java @@ -0,0 +1,354 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.event.PlayerReceivePacketEvent; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.net.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class NetworkManager { + + public static final Object a = new Object(); + public static int b; + public static int c; + private Object g = new Object(); + public Socket socket; // CraftBukkit - private -> public + private SocketAddress i; //Project Poseidon - remove final statement + private DataInputStream input; + private DataOutputStream output; + private boolean l = true; + private List m = Collections.synchronizedList(new ArrayList()); + private List highPriorityQueue = Collections.synchronizedList(new ArrayList()); + private List lowPriorityQueue = Collections.synchronizedList(new ArrayList()); + private NetHandler p; + private boolean q = false; + private Thread r; + private Thread s; + private boolean t = false; + private String u = ""; + private Object[] v; + private int w = 0; + private int x = 0; + public static int[] d = new int[256]; + public static int[] e = new int[256]; + public int f = 0; + private int lowPriorityQueueDelay = 50; + private final boolean firePacketEvents; + + private final boolean spamDetection; + + private final int threshold; + + public NetworkManager(Socket socket, String s, NetHandler nethandler) { + this.socket = socket; + this.i = socket.getRemoteSocketAddress(); + this.p = nethandler; + + //Poseidon + this.firePacketEvents = PoseidonConfig.getInstance().getBoolean("settings.packet-events.enabled", false); + this.spamDetection = PoseidonConfig.getInstance().getBoolean("settings.packet-spam-detection.enabled", true); + this.threshold = PoseidonConfig.getInstance().getInt("settings.packet-spam-detection.threshold", 1000); + + //Debug for packet spam detection +// System.out.println("[Poseidon] Packet spam detection is " + (this.spamDetection ? "enabled" : "disabled") + " with a threshold of " + this.threshold + " packets"); + + // CraftBukkit start - IPv6 stack in Java on BSD/OSX doesn't support setTrafficClass + try { + socket.setTrafficClass(24); + } catch (SocketException e) { + } + // CraftBukkit end + + try { + // CraftBukkit start - cant compile these outside the try + socket.setSoTimeout(30000); + if (PoseidonConfig.getEmptyNode().getBoolean("settings.enable-tpc-nodelay", false)) { + socket.setTcpNoDelay(true); + } + this.input = new DataInputStream(socket.getInputStream()); + this.output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), 5120)); + } catch (java.io.IOException socketexception) { + // CraftBukkit end + System.err.println(socketexception.getMessage()); + } + + /* CraftBukkit start - moved up + this.input = new DataInputStream(socket.getInputStream()); + this.output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), 5120)); + // CraftBukkit end */ + this.s = new NetworkReaderThread(this, s + " read thread"); + this.r = new NetworkWriterThread(this, s + " write thread"); + this.s.start(); + this.r.start(); + } + + //Project Poseidon Start + public void setSocketAddress(SocketAddress socketAddress) { + this.i = socketAddress; + } + + public SocketAddress generateSocketAddress(String hostname, int port) { + return new InetSocketAddress(hostname, port); + } + + //Project Poseidon End + + public void a(NetHandler nethandler) { + this.p = nethandler; + } + + public void queue(Packet packet) { + if (!this.q) { + Object object = this.g; + + synchronized (this.g) { + this.x += packet.a() + 1; + if (packet.k) { + this.lowPriorityQueue.add(packet); + } else { + this.highPriorityQueue.add(packet); + } + } + } + } + + private boolean f() { + boolean flag = false; + + try { + Object object; + Packet packet; + int i; + int[] aint; + + if (!this.highPriorityQueue.isEmpty() && (this.f == 0 || System.currentTimeMillis() - ((Packet) this.highPriorityQueue.get(0)).timestamp >= (long) this.f)) { + object = this.g; + synchronized (this.g) { + packet = (Packet) this.highPriorityQueue.remove(0); + this.x -= packet.a() + 1; + } + + Packet.a(packet, this.output); + aint = e; + i = packet.b(); + aint[i] += packet.a() + 1; + flag = true; + } + + // CraftBukkit - don't allow low priority packet to be sent unless it was placed in the queue before the first packet on the high priority queue + if ((flag || this.lowPriorityQueueDelay-- <= 0) && !this.lowPriorityQueue.isEmpty() && (this.highPriorityQueue.isEmpty() || ((Packet) this.highPriorityQueue.get(0)).timestamp > ((Packet) this.lowPriorityQueue.get(0)).timestamp)) { + object = this.g; + synchronized (this.g) { + packet = (Packet) this.lowPriorityQueue.remove(0); + this.x -= packet.a() + 1; + } + + Packet.a(packet, this.output); + aint = e; + i = packet.b(); + aint[i] += packet.a() + 1; + this.lowPriorityQueueDelay = 0; + flag = true; + } + + return flag; + } catch (Exception exception) { + if (!this.t) { + this.a(exception); + } + + return false; + } + } + + public void a() { + this.s.interrupt(); + this.r.interrupt(); + } + + private boolean g() { + boolean flag = false; + + try { + Packet packet = Packet.a(this.input, this.p.c()); + + if (packet != null) { + int[] aint = d; + int i = packet.b(); + + aint[i] += packet.a() + 1; + this.m.add(packet); + flag = true; + } else { + this.a("disconnect.endOfStream", new Object[0]); + } + + return flag; + } catch (Exception exception) { + if (!this.t) { + this.a(exception); + } + + return false; + } + } + + private void a(Exception exception) { + exception.printStackTrace(); + this.a("disconnect.genericReason", new Object[]{"Internal exception: " + exception.toString()}); + } + + public void a(String s, Object... aobject) { + if (this.l) { + this.t = true; + this.u = s; + this.v = aobject; + (new NetworkMasterThread(this)).start(); + this.l = false; + + try { + this.input.close(); + this.input = null; + } catch (Throwable throwable) { + ; + } + + try { + this.output.close(); + this.output = null; + } catch (Throwable throwable1) { + ; + } + + try { + this.socket.close(); + this.socket = null; + } catch (Throwable throwable2) { + ; + } + } + } + + public void b() { + boolean fast = PoseidonConfig.getInstance().getBoolean("settings.faster-packets.enabled", true); + if (this.x > (fast ? 2097152 : 1048576)) { + this.a("disconnect.overflow", new Object[0]); + } + + if (this.m.isEmpty()) { + if (this.w++ == 1200) { + this.a("disconnect.timeout", new Object[0]); + } + } else { + this.w = 0; + } + + int i = (fast ? 1000 : 100); + + //Poseidon - Packet spam detection + if (spamDetection) { + if (this.m.size() > threshold) { + String playerUsername = "Unknown"; + if (this.p instanceof NetServerHandler) { + playerUsername = ((NetServerHandler) this.p).player.name; + ((NetServerHandler) this.p).disconnect(ChatColor.RED + "[Poseidon] You have been kicked for packet spamming."); + } else { + this.a("disconnect.spam", new Object[0]); + } + System.out.println("[Poseidon] Player " + playerUsername + " has been kicked for packet spamming. The queue size was " + this.m.size() + " and the threshold was " + threshold + "."); + } + } + +// if(this.m.size() > 1000) { +// String playerUsername = "Unknown"; +// if (this.p instanceof NetServerHandler) { +// System.out.println("The packet queue size is " + this.m.size() + " for player " + ((NetServerHandler) this.p).player.name + "."); +// } +// } + + + while (!this.m.isEmpty() && i-- >= 0) { + Packet packet = (Packet) this.m.remove(0); + + //Poseidon Start - Packet Receive Event + if (firePacketEvents && this.p instanceof NetServerHandler) { + PlayerReceivePacketEvent event = new PlayerReceivePacketEvent(((NetServerHandler) this.p).player.name, packet); + Bukkit.getPluginManager().callEvent(event); + packet = event.getPacket(); + if (!event.isCancelled()) { + packet.a(this.p); + } + + } else { + packet.a(this.p); + } + + //Poseidon End + +// packet.a(this.p); + } + + this.a(); + if (this.t && this.m.isEmpty()) { + this.p.a(this.u, this.v); + } + } + + public SocketAddress getSocketAddress() { + return this.i; + } + + public void d() { + this.a(); + this.q = true; + this.s.interrupt(); + (new ThreadMonitorConnection(this)).start(); + } + + public int e() { + return this.lowPriorityQueue.size(); + } + + static boolean a(NetworkManager networkmanager) { + return networkmanager.l; + } + + static boolean b(NetworkManager networkmanager) { + return networkmanager.q; + } + + static boolean c(NetworkManager networkmanager) { + return networkmanager.g(); + } + + static boolean d(NetworkManager networkmanager) { + return networkmanager.f(); + } + + static DataOutputStream e(NetworkManager networkmanager) { + return networkmanager.output; + } + + static boolean f(NetworkManager networkmanager) { + return networkmanager.t; + } + + static void a(NetworkManager networkmanager, Exception exception) { + networkmanager.a(exception); + } + + static Thread g(NetworkManager networkmanager) { + return networkmanager.s; + } + + static Thread h(NetworkManager networkmanager) { + return networkmanager.r; + } +} diff --git a/src/main/java/net/minecraft/server/NetworkMasterThread.java b/src/main/java/net/minecraft/server/NetworkMasterThread.java new file mode 100644 index 0000000..d7e4047 --- /dev/null +++ b/src/main/java/net/minecraft/server/NetworkMasterThread.java @@ -0,0 +1,33 @@ +package net.minecraft.server; + +class NetworkMasterThread extends Thread { + + final NetworkManager a; + + NetworkMasterThread(NetworkManager networkmanager) { + this.a = networkmanager; + } + + public void run() { + try { + Thread.sleep(5000L); + if (NetworkManager.g(this.a).isAlive()) { + try { + NetworkManager.g(this.a).stop(); + } catch (Throwable throwable) { + ; + } + } + + if (NetworkManager.h(this.a).isAlive()) { + try { + NetworkManager.h(this.a).stop(); + } catch (Throwable throwable1) { + ; + } + } + } catch (InterruptedException interruptedexception) { + interruptedexception.printStackTrace(); + } + } +} diff --git a/src/main/java/net/minecraft/server/NetworkReaderThread.java b/src/main/java/net/minecraft/server/NetworkReaderThread.java new file mode 100644 index 0000000..1f77eb0 --- /dev/null +++ b/src/main/java/net/minecraft/server/NetworkReaderThread.java @@ -0,0 +1,62 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; + +class NetworkReaderThread extends Thread { + private boolean fast; // Poseidon + final NetworkManager a; + + NetworkReaderThread(NetworkManager networkmanager, String s) { + super(s); + this.a = networkmanager; + this.fast = PoseidonConfig.getInstance().getBoolean("settings.faster-packets.enabled", true); // Poseidon + } + + public void run() { + Object object = NetworkManager.a; + + synchronized (NetworkManager.a) { + ++NetworkManager.b; + } + + while (true) { + boolean flag = false; + + try { + flag = true; + if (!NetworkManager.a(this.a)) { + flag = false; + break; + } + + if (NetworkManager.b(this.a)) { + flag = false; + break; + } + + while (NetworkManager.c(this.a)) { + ; + } + + try { + sleep(this.fast ? 2L : 100L); + } catch (InterruptedException interruptedexception) { + ; + } + } finally { + if (flag) { + Object object1 = NetworkManager.a; + + synchronized (NetworkManager.a) { + --NetworkManager.b; + } + } + } + } + + object = NetworkManager.a; + synchronized (NetworkManager.a) { + --NetworkManager.b; + } + } +} diff --git a/src/main/java/net/minecraft/server/NetworkWriterThread.java b/src/main/java/net/minecraft/server/NetworkWriterThread.java new file mode 100644 index 0000000..301ec16 --- /dev/null +++ b/src/main/java/net/minecraft/server/NetworkWriterThread.java @@ -0,0 +1,80 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import java.io.IOException; + +class NetworkWriterThread extends Thread { + private boolean fast; // Poseidon + final NetworkManager a; + + NetworkWriterThread(NetworkManager networkmanager, String s) { + super(s); + this.a = networkmanager; + this.fast = PoseidonConfig.getInstance().getBoolean("settings.faster-packets.enabled", true); // Poseidon + } + + public void run() { + Object object = NetworkManager.a; + + synchronized (NetworkManager.a) { + ++NetworkManager.c; + } + + while (true) { + boolean flag = false; + + try { + flag = true; + if (!NetworkManager.a(this.a)) { + flag = false; + break; + } + + while (NetworkManager.d(this.a)) { + ; + } + + if (!this.fast) { // Poseidon + try { + sleep(100L); + } catch (InterruptedException interruptedexception) { + ; + } + } + + try { + if (NetworkManager.e(this.a) != null) { + NetworkManager.e(this.a).flush(); + } + } catch (IOException ioexception) { + if (!NetworkManager.f(this.a)) { + NetworkManager.a(this.a, (Exception) ioexception); + } + + //ioexception.printStackTrace(); //Project Poseidon Remove - Credit to Notcz in Modification Station + } + + if (this.fast) { // Poseidon + try { + sleep(2L); + } catch (InterruptedException interruptedexception) { + ; + } + } + } finally { + if (flag) { + Object object1 = NetworkManager.a; + + synchronized (NetworkManager.a) { + --NetworkManager.c; + } + } + } + } + + object = NetworkManager.a; + synchronized (NetworkManager.a) { + --NetworkManager.c; + } + } +} diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java new file mode 100644 index 0000000..3e01456 --- /dev/null +++ b/src/main/java/net/minecraft/server/NextTickListEntry.java @@ -0,0 +1,44 @@ +package net.minecraft.server; + +public class NextTickListEntry implements Comparable { + + private static long f = 0L; + public int a; + public int b; + public int c; + public int d; + public long e; + private long g; + + public NextTickListEntry(int i, int j, int k, int l) { + this.g = (long) (f++); + this.a = i; + this.b = j; + this.c = k; + this.d = l; + } + + public boolean equals(Object object) { + if (!(object instanceof NextTickListEntry)) { + return false; + } else { + NextTickListEntry nextticklistentry = (NextTickListEntry) object; + + return this.a == nextticklistentry.a && this.b == nextticklistentry.b && this.c == nextticklistentry.c && this.d == nextticklistentry.d; + } + } + + public int hashCode() { + return (this.a * 128 * 1024 + this.c * 128 + this.b) * 256 + this.d; + } + + public NextTickListEntry a(long i) { + this.e = i; + return this; + } + + public int compareTo(Object o) { + NextTickListEntry nextticklistentry = (NextTickListEntry) o; + return this.e < nextticklistentry.e ? -1 : (this.e > nextticklistentry.e ? 1 : (this.g < nextticklistentry.g ? -1 : (this.g > nextticklistentry.g ? 1 : 0))); + } +} diff --git a/src/main/java/net/minecraft/server/NibbleArray.java b/src/main/java/net/minecraft/server/NibbleArray.java new file mode 100644 index 0000000..186e896 --- /dev/null +++ b/src/main/java/net/minecraft/server/NibbleArray.java @@ -0,0 +1,38 @@ +package net.minecraft.server; + +public class NibbleArray { + + public final byte[] a; + + public NibbleArray(int i) { + this.a = new byte[i >> 1]; + } + + public NibbleArray(byte[] abyte) { + this.a = abyte; + } + + public int a(int i, int j, int k) { + int l = i << 11 | k << 7 | j; + int i1 = l >> 1; + int j1 = l & 1; + + return j1 == 0 ? this.a[i1] & 15 : this.a[i1] >> 4 & 15; + } + + public void a(int i, int j, int k, int l) { + int i1 = i << 11 | k << 7 | j; + int j1 = i1 >> 1; + int k1 = i1 & 1; + + if (k1 == 0) { + this.a[j1] = (byte) (this.a[j1] & 240 | l & 15); + } else { + this.a[j1] = (byte) (this.a[j1] & 15 | (l & 15) << 4); + } + } + + public boolean a() { + return this.a != null; + } +} diff --git a/src/main/java/net/minecraft/server/NoiseGenerator.java b/src/main/java/net/minecraft/server/NoiseGenerator.java new file mode 100644 index 0000000..07827ed --- /dev/null +++ b/src/main/java/net/minecraft/server/NoiseGenerator.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +public abstract class NoiseGenerator { + + public NoiseGenerator() {} +} diff --git a/src/main/java/net/minecraft/server/NoiseGenerator2.java b/src/main/java/net/minecraft/server/NoiseGenerator2.java new file mode 100644 index 0000000..e672bdf --- /dev/null +++ b/src/main/java/net/minecraft/server/NoiseGenerator2.java @@ -0,0 +1,121 @@ +package net.minecraft.server; + +import java.util.Random; + +public class NoiseGenerator2 { + + private static int[][] d = new int[][] { { 1, 1, 0}, { -1, 1, 0}, { 1, -1, 0}, { -1, -1, 0}, { 1, 0, 1}, { -1, 0, 1}, { 1, 0, -1}, { -1, 0, -1}, { 0, 1, 1}, { 0, -1, 1}, { 0, 1, -1}, { 0, -1, -1}}; + private int[] e; + public double a; + public double b; + public double c; + private static final double f = 0.5D * (Math.sqrt(3.0D) - 1.0D); + private static final double g = (3.0D - Math.sqrt(3.0D)) / 6.0D; + + public NoiseGenerator2() { + this(new Random()); + } + + public NoiseGenerator2(Random random) { + this.e = new int[512]; + this.a = random.nextDouble() * 256.0D; + this.b = random.nextDouble() * 256.0D; + this.c = random.nextDouble() * 256.0D; + + int i; + + for (i = 0; i < 256; this.e[i] = i++) { + ; + } + + for (i = 0; i < 256; ++i) { + int j = random.nextInt(256 - i) + i; + int k = this.e[i]; + + this.e[i] = this.e[j]; + this.e[j] = k; + this.e[i + 256] = this.e[i]; + } + } + + private static int a(double d0) { + return d0 > 0.0D ? (int) d0 : (int) d0 - 1; + } + + private static double a(int[] aint, double d0, double d1) { + return (double) aint[0] * d0 + (double) aint[1] * d1; + } + + public void a(double[] adouble, double d0, double d1, int i, int j, double d2, double d3, double d4) { + int k = 0; + + for (int l = 0; l < i; ++l) { + double d5 = (d0 + (double) l) * d2 + this.a; + + for (int i1 = 0; i1 < j; ++i1) { + double d6 = (d1 + (double) i1) * d3 + this.b; + double d7 = (d5 + d6) * f; + int j1 = a(d5 + d7); + int k1 = a(d6 + d7); + double d8 = (double) (j1 + k1) * g; + double d9 = (double) j1 - d8; + double d10 = (double) k1 - d8; + double d11 = d5 - d9; + double d12 = d6 - d10; + byte b0; + byte b1; + + if (d11 > d12) { + b0 = 1; + b1 = 0; + } else { + b0 = 0; + b1 = 1; + } + + double d13 = d11 - (double) b0 + g; + double d14 = d12 - (double) b1 + g; + double d15 = d11 - 1.0D + 2.0D * g; + double d16 = d12 - 1.0D + 2.0D * g; + int l1 = j1 & 255; + int i2 = k1 & 255; + int j2 = this.e[l1 + this.e[i2]] % 12; + int k2 = this.e[l1 + b0 + this.e[i2 + b1]] % 12; + int l2 = this.e[l1 + 1 + this.e[i2 + 1]] % 12; + double d17 = 0.5D - d11 * d11 - d12 * d12; + double d18; + + if (d17 < 0.0D) { + d18 = 0.0D; + } else { + d17 *= d17; + d18 = d17 * d17 * a(d[j2], d11, d12); + } + + double d19 = 0.5D - d13 * d13 - d14 * d14; + double d20; + + if (d19 < 0.0D) { + d20 = 0.0D; + } else { + d19 *= d19; + d20 = d19 * d19 * a(d[k2], d13, d14); + } + + double d21 = 0.5D - d15 * d15 - d16 * d16; + double d22; + + if (d21 < 0.0D) { + d22 = 0.0D; + } else { + d21 *= d21; + d22 = d21 * d21 * a(d[l2], d15, d16); + } + + int i3 = k++; + + adouble[i3] += 70.0D * (d18 + d20 + d22) * d4; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/NoiseGeneratorOctaves.java b/src/main/java/net/minecraft/server/NoiseGeneratorOctaves.java new file mode 100644 index 0000000..bab39a2 --- /dev/null +++ b/src/main/java/net/minecraft/server/NoiseGeneratorOctaves.java @@ -0,0 +1,53 @@ +package net.minecraft.server; + +import java.util.Random; + +public class NoiseGeneratorOctaves extends NoiseGenerator { + + private NoiseGeneratorPerlin[] a; + private int b; + + public NoiseGeneratorOctaves(Random random, int i) { + this.b = i; + this.a = new NoiseGeneratorPerlin[i]; + + for (int j = 0; j < i; ++j) { + this.a[j] = new NoiseGeneratorPerlin(random); + } + } + + public double a(double d0, double d1) { + double d2 = 0.0D; + double d3 = 1.0D; + + for (int i = 0; i < this.b; ++i) { + d2 += this.a[i].a(d0 * d3, d1 * d3) / d3; + d3 /= 2.0D; + } + + return d2; + } + + public double[] a(double[] adouble, double d0, double d1, double d2, int i, int j, int k, double d3, double d4, double d5) { + if (adouble == null) { + adouble = new double[i * j * k]; + } else { + for (int l = 0; l < adouble.length; ++l) { + adouble[l] = 0.0D; + } + } + + double d6 = 1.0D; + + for (int i1 = 0; i1 < this.b; ++i1) { + this.a[i1].a(adouble, d0, d1, d2, i, j, k, d3 * d6, d4 * d6, d5 * d6, d6); + d6 /= 2.0D; + } + + return adouble; + } + + public double[] a(double[] adouble, int i, int j, int k, int l, double d0, double d1, double d2) { + return this.a(adouble, (double) i, 10.0D, (double) j, k, 1, l, d0, 1.0D, d1); + } +} diff --git a/src/main/java/net/minecraft/server/NoiseGeneratorOctaves2.java b/src/main/java/net/minecraft/server/NoiseGeneratorOctaves2.java new file mode 100644 index 0000000..0f1a6fa --- /dev/null +++ b/src/main/java/net/minecraft/server/NoiseGeneratorOctaves2.java @@ -0,0 +1,45 @@ +package net.minecraft.server; + +import java.util.Random; + +public class NoiseGeneratorOctaves2 extends NoiseGenerator { + + private NoiseGenerator2[] a; + private int b; + + public NoiseGeneratorOctaves2(Random random, int i) { + this.b = i; + this.a = new NoiseGenerator2[i]; + + for (int j = 0; j < i; ++j) { + this.a[j] = new NoiseGenerator2(random); + } + } + + public double[] a(double[] adouble, double d0, double d1, int i, int j, double d2, double d3, double d4) { + return this.a(adouble, d0, d1, i, j, d2, d3, d4, 0.5D); + } + + public double[] a(double[] adouble, double d0, double d1, int i, int j, double d2, double d3, double d4, double d5) { + d2 /= 1.5D; + d3 /= 1.5D; + if (adouble != null && adouble.length >= i * j) { + for (int k = 0; k < adouble.length; ++k) { + adouble[k] = 0.0D; + } + } else { + adouble = new double[i * j]; + } + + double d6 = 1.0D; + double d7 = 1.0D; + + for (int l = 0; l < this.b; ++l) { + this.a[l].a(adouble, d0, d1, i, j, d2 * d7, d3 * d7, 0.55D / d6); + d7 *= d4; + d6 *= d5; + } + + return adouble; + } +} diff --git a/src/main/java/net/minecraft/server/NoiseGeneratorPerlin.java b/src/main/java/net/minecraft/server/NoiseGeneratorPerlin.java new file mode 100644 index 0000000..7051d59 --- /dev/null +++ b/src/main/java/net/minecraft/server/NoiseGeneratorPerlin.java @@ -0,0 +1,244 @@ +package net.minecraft.server; + +import java.util.Random; + +public class NoiseGeneratorPerlin extends NoiseGenerator { + + private int[] d; + public double a; + public double b; + public double c; + + public NoiseGeneratorPerlin() { + this(new Random()); + } + + public NoiseGeneratorPerlin(Random random) { + this.d = new int[512]; + this.a = random.nextDouble() * 256.0D; + this.b = random.nextDouble() * 256.0D; + this.c = random.nextDouble() * 256.0D; + + int i; + + for (i = 0; i < 256; this.d[i] = i++) { + ; + } + + for (i = 0; i < 256; ++i) { + int j = random.nextInt(256 - i) + i; + int k = this.d[i]; + + this.d[i] = this.d[j]; + this.d[j] = k; + this.d[i + 256] = this.d[i]; + } + } + + public double a(double d0, double d1, double d2) { + double d3 = d0 + this.a; + double d4 = d1 + this.b; + double d5 = d2 + this.c; + int i = (int) d3; + int j = (int) d4; + int k = (int) d5; + + if (d3 < (double) i) { + --i; + } + + if (d4 < (double) j) { + --j; + } + + if (d5 < (double) k) { + --k; + } + + int l = i & 255; + int i1 = j & 255; + int j1 = k & 255; + + d3 -= (double) i; + d4 -= (double) j; + d5 -= (double) k; + double d6 = d3 * d3 * d3 * (d3 * (d3 * 6.0D - 15.0D) + 10.0D); + double d7 = d4 * d4 * d4 * (d4 * (d4 * 6.0D - 15.0D) + 10.0D); + double d8 = d5 * d5 * d5 * (d5 * (d5 * 6.0D - 15.0D) + 10.0D); + int k1 = this.d[l] + i1; + int l1 = this.d[k1] + j1; + int i2 = this.d[k1 + 1] + j1; + int j2 = this.d[l + 1] + i1; + int k2 = this.d[j2] + j1; + int l2 = this.d[j2 + 1] + j1; + + return this.b(d8, this.b(d7, this.b(d6, this.a(this.d[l1], d3, d4, d5), this.a(this.d[k2], d3 - 1.0D, d4, d5)), this.b(d6, this.a(this.d[i2], d3, d4 - 1.0D, d5), this.a(this.d[l2], d3 - 1.0D, d4 - 1.0D, d5))), this.b(d7, this.b(d6, this.a(this.d[l1 + 1], d3, d4, d5 - 1.0D), this.a(this.d[k2 + 1], d3 - 1.0D, d4, d5 - 1.0D)), this.b(d6, this.a(this.d[i2 + 1], d3, d4 - 1.0D, d5 - 1.0D), this.a(this.d[l2 + 1], d3 - 1.0D, d4 - 1.0D, d5 - 1.0D)))); + } + + public final double b(double d0, double d1, double d2) { + return d1 + d0 * (d2 - d1); + } + + public final double a(int i, double d0, double d1) { + int j = i & 15; + double d2 = (double) (1 - ((j & 8) >> 3)) * d0; + double d3 = j < 4 ? 0.0D : (j != 12 && j != 14 ? d1 : d0); + + return ((j & 1) == 0 ? d2 : -d2) + ((j & 2) == 0 ? d3 : -d3); + } + + public final double a(int i, double d0, double d1, double d2) { + int j = i & 15; + double d3 = j < 8 ? d0 : d1; + double d4 = j < 4 ? d1 : (j != 12 && j != 14 ? d2 : d0); + + return ((j & 1) == 0 ? d3 : -d3) + ((j & 2) == 0 ? d4 : -d4); + } + + public double a(double d0, double d1) { + return this.a(d0, d1, 0.0D); + } + + public void a(double[] adouble, double d0, double d1, double d2, int i, int j, int k, double d3, double d4, double d5, double d6) { + int l; + int i1; + double d7; + double d8; + double d9; + int j1; + double d10; + int k1; + int l1; + int i2; + int j2; + + if (j == 1) { + boolean flag = false; + boolean flag1 = false; + boolean flag2 = false; + boolean flag3 = false; + double d11 = 0.0D; + double d12 = 0.0D; + + j2 = 0; + double d13 = 1.0D / d6; + + for (int k2 = 0; k2 < i; ++k2) { + d7 = (d0 + (double) k2) * d3 + this.a; + int l2 = (int) d7; + + if (d7 < (double) l2) { + --l2; + } + + int i3 = l2 & 255; + + d7 -= (double) l2; + d8 = d7 * d7 * d7 * (d7 * (d7 * 6.0D - 15.0D) + 10.0D); + + for (j1 = 0; j1 < k; ++j1) { + d9 = (d2 + (double) j1) * d5 + this.c; + k1 = (int) d9; + if (d9 < (double) k1) { + --k1; + } + + l1 = k1 & 255; + d9 -= (double) k1; + d10 = d9 * d9 * d9 * (d9 * (d9 * 6.0D - 15.0D) + 10.0D); + l = this.d[i3] + 0; + int j3 = this.d[l] + l1; + int k3 = this.d[i3 + 1] + 0; + + i1 = this.d[k3] + l1; + d11 = this.b(d8, this.a(this.d[j3], d7, d9), this.a(this.d[i1], d7 - 1.0D, 0.0D, d9)); + d12 = this.b(d8, this.a(this.d[j3 + 1], d7, 0.0D, d9 - 1.0D), this.a(this.d[i1 + 1], d7 - 1.0D, 0.0D, d9 - 1.0D)); + double d14 = this.b(d10, d11, d12); + + i2 = j2++; + adouble[i2] += d14 * d13; + } + } + } else { + l = 0; + double d15 = 1.0D / d6; + + i1 = -1; + boolean flag4 = false; + boolean flag5 = false; + boolean flag6 = false; + boolean flag7 = false; + boolean flag8 = false; + boolean flag9 = false; + double d16 = 0.0D; + + d7 = 0.0D; + double d17 = 0.0D; + + d8 = 0.0D; + + for (j1 = 0; j1 < i; ++j1) { + d9 = (d0 + (double) j1) * d3 + this.a; + k1 = (int) d9; + if (d9 < (double) k1) { + --k1; + } + + l1 = k1 & 255; + d9 -= (double) k1; + d10 = d9 * d9 * d9 * (d9 * (d9 * 6.0D - 15.0D) + 10.0D); + + for (int l3 = 0; l3 < k; ++l3) { + double d18 = (d2 + (double) l3) * d5 + this.c; + int i4 = (int) d18; + + if (d18 < (double) i4) { + --i4; + } + + int j4 = i4 & 255; + + d18 -= (double) i4; + double d19 = d18 * d18 * d18 * (d18 * (d18 * 6.0D - 15.0D) + 10.0D); + + for (int k4 = 0; k4 < j; ++k4) { + double d20 = (d1 + (double) k4) * d4 + this.b; + int l4 = (int) d20; + + if (d20 < (double) l4) { + --l4; + } + + int i5 = l4 & 255; + + d20 -= (double) l4; + double d21 = d20 * d20 * d20 * (d20 * (d20 * 6.0D - 15.0D) + 10.0D); + + if (k4 == 0 || i5 != i1) { + i1 = i5; + int j5 = this.d[l1] + i5; + int k5 = this.d[j5] + j4; + int l5 = this.d[j5 + 1] + j4; + int i6 = this.d[l1 + 1] + i5; + + j2 = this.d[i6] + j4; + int j6 = this.d[i6 + 1] + j4; + + d16 = this.b(d10, this.a(this.d[k5], d9, d20, d18), this.a(this.d[j2], d9 - 1.0D, d20, d18)); + d7 = this.b(d10, this.a(this.d[l5], d9, d20 - 1.0D, d18), this.a(this.d[j6], d9 - 1.0D, d20 - 1.0D, d18)); + d17 = this.b(d10, this.a(this.d[k5 + 1], d9, d20, d18 - 1.0D), this.a(this.d[j2 + 1], d9 - 1.0D, d20, d18 - 1.0D)); + d8 = this.b(d10, this.a(this.d[l5 + 1], d9, d20 - 1.0D, d18 - 1.0D), this.a(this.d[j6 + 1], d9 - 1.0D, d20 - 1.0D, d18 - 1.0D)); + } + + double d22 = this.b(d21, d16, d7); + double d23 = this.b(d21, d17, d8); + double d24 = this.b(d19, d22, d23); + + i2 = l++; + adouble[i2] += d24 * d15; + } + } + } + } + } +} diff --git a/src/main/java/net/minecraft/server/Packet.java b/src/main/java/net/minecraft/server/Packet.java new file mode 100644 index 0000000..f4161cc --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet.java @@ -0,0 +1,249 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.packets.ArtificialPacket53BlockChange; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public abstract class Packet { + + private static Map packetIdToClassMap = new HashMap(); + private static Map packetClassToIdMap = new HashMap(); + private static Set clientPacketIdList = new HashSet(); + private static Set serverPacketIdList = new HashSet(); + public final long timestamp = System.currentTimeMillis(); + public boolean k = false; + private static HashMap e; + private static int f; + + public Packet() {} + + /** + * Register a packet + * @author moderator_Man + * @param id + * @param clientSide + * @param serverSide + * @param oclass + */ + public static void registerPacket(int id, boolean clientSide, boolean serverSide, Class oclass) + { + if (packetIdToClassMap.containsKey(Integer.valueOf(id))) + throw new IllegalArgumentException("Duplicate packet id:" + id); + else if (packetClassToIdMap.containsKey(oclass)) + throw new IllegalArgumentException("Duplicate packet class:" + oclass); + else { + packetIdToClassMap.put(Integer.valueOf(id), oclass); + packetClassToIdMap.put(oclass, Integer.valueOf(id)); + if (clientSide) + clientPacketIdList.add(Integer.valueOf(id)); + if (serverSide) + serverPacketIdList.add(Integer.valueOf(id)); + } + } + + static void a(int i, boolean flag, boolean flag1, Class oclass) { + if (packetIdToClassMap.containsKey(Integer.valueOf(i))) { + throw new IllegalArgumentException("Duplicate packet id:" + i); + } else if (packetClassToIdMap.containsKey(oclass)) { + throw new IllegalArgumentException("Duplicate packet class:" + oclass); + } else { + packetIdToClassMap.put(Integer.valueOf(i), oclass); + packetClassToIdMap.put(oclass, Integer.valueOf(i)); + if (flag) { + clientPacketIdList.add(Integer.valueOf(i)); + } + + if (flag1) { + serverPacketIdList.add(Integer.valueOf(i)); + } + } + } + + public static Packet a(int i) { + try { + Class oclass = (Class) packetIdToClassMap.get(Integer.valueOf(i)); + + return oclass == null ? null : (Packet) oclass.newInstance(); + } catch (Exception exception) { + exception.printStackTrace(); + System.out.println("Skipping packet with id " + i); + return null; + } + } + + public final int b() { + return ((Integer) packetClassToIdMap.get(this.getClass())).intValue(); + } + + // CraftBukkit - throws IOException + public static Packet a(DataInputStream datainputstream, boolean flag) throws IOException { + boolean flag1 = false; + Packet packet = null; + + int i; + + try { + i = datainputstream.read(); + if (i == -1) { + return null; + } + + if (flag && !serverPacketIdList.contains(Integer.valueOf(i)) || !flag && !clientPacketIdList.contains(Integer.valueOf(i))) { + System.out.println("Bad packet id: " + i); //Project Poseidon + return null; //Project Poseidon + //throw new IOException("Bad packet id " + i); //Project Poseidon - Comment Out + } + + packet = a(i); + if (packet == null) { + throw new IOException("Bad packet id " + i); + } + + packet.a(datainputstream); + } catch (EOFException eofexception) { + System.out.println("Reached end of stream"); + return null; + } + + // CraftBukkit start + catch (java.net.SocketTimeoutException exception) { + System.out.println("Read timed out"); + return null; + } catch (java.net.SocketException exception) { + if (!(boolean) PoseidonConfig.getInstance().getConfigOption("settings.remove-join-leave-debug", true)) { + System.out.println("Connection reset"); + } + return null; + } + // CraftBukkit end + + PacketCounter packetcounter = (PacketCounter) e.get(Integer.valueOf(i)); + + if (packetcounter == null) { + packetcounter = new PacketCounter((EmptyClass1) null); + e.put(Integer.valueOf(i), packetcounter); + } + + packetcounter.a(packet.a()); + ++f; + if (f % 1000 == 0) { + ; + } + + return packet; + } + + // CraftBukkit - throws IOException + public static void a(Packet packet, DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.write(packet.b()); + packet.a(dataoutputstream); + } + + // CraftBukkit - throws IOException + public static void a(String s, DataOutputStream dataoutputstream) throws IOException { + if (s.length() > 32767) { + throw new IOException("String too big"); + } else { + dataoutputstream.writeShort(s.length()); + dataoutputstream.writeChars(s); + } + } + + // CraftBukkit - throws IOException + public static String a(DataInputStream datainputstream, int i) throws IOException { + short short1 = datainputstream.readShort(); + + if (short1 > i) { + throw new IOException("Received string length longer than maximum allowed (" + short1 + " > " + i + ")"); + } else if (short1 < 0) { + throw new IOException("Received string length is less than zero! Weird string!"); + } else { + StringBuilder stringbuilder = new StringBuilder(); + + for (int j = 0; j < short1; ++j) { + stringbuilder.append(datainputstream.readChar()); + } + + return stringbuilder.toString(); + } + } + + public abstract void a(DataInputStream datainputstream) throws IOException; // CraftBukkit + + public abstract void a(DataOutputStream dataoutputstream) throws IOException; // CraftBukkit + + public abstract void a(NetHandler nethandler); + + public abstract int a(); + + static { + a(0, true, true, Packet0KeepAlive.class); + a(1, true, true, Packet1Login.class); + a(2, true, true, Packet2Handshake.class); + a(3, true, true, Packet3Chat.class); + a(4, true, false, Packet4UpdateTime.class); + a(5, true, false, Packet5EntityEquipment.class); + a(6, true, false, Packet6SpawnPosition.class); + a(7, false, true, Packet7UseEntity.class); + a(8, true, false, Packet8UpdateHealth.class); + a(9, true, true, Packet9Respawn.class); + a(10, true, true, Packet10Flying.class); + a(11, true, true, Packet11PlayerPosition.class); + a(12, true, true, Packet12PlayerLook.class); + a(13, true, true, Packet13PlayerLookMove.class); + a(14, false, true, Packet14BlockDig.class); + a(15, false, true, Packet15Place.class); + a(16, false, true, Packet16BlockItemSwitch.class); + a(17, true, false, Packet17.class); + a(18, true, true, Packet18ArmAnimation.class); + a(19, false, true, Packet19EntityAction.class); + a(20, true, false, Packet20NamedEntitySpawn.class); + a(21, true, false, Packet21PickupSpawn.class); + a(22, true, false, Packet22Collect.class); + a(23, true, false, Packet23VehicleSpawn.class); + a(24, true, false, Packet24MobSpawn.class); + a(25, true, false, Packet25EntityPainting.class); + a(27, false, false, Packet27.class); // CraftBukkit - true -> false; disabled unused packet. TODO -- check if needed + a(28, true, false, Packet28EntityVelocity.class); + a(29, true, false, Packet29DestroyEntity.class); + a(30, true, false, Packet30Entity.class); + a(31, true, false, Packet31RelEntityMove.class); + a(32, true, false, Packet32EntityLook.class); + a(33, true, false, Packet33RelEntityMoveLook.class); + a(34, true, false, Packet34EntityTeleport.class); + a(38, true, false, Packet38EntityStatus.class); + a(39, true, false, Packet39AttachEntity.class); + a(40, true, false, Packet40EntityMetadata.class); + a(50, true, false, Packet50PreChunk.class); + a(51, true, false, Packet51MapChunk.class); + a(52, true, false, Packet52MultiBlockChange.class); + a(53, true, false, Packet53BlockChange.class); + a(54, true, false, Packet54PlayNoteBlock.class); + a(60, true, false, Packet60Explosion.class); + a(61, true, false, Packet61.class); + a(70, true, false, Packet70Bed.class); + a(71, true, false, Packet71Weather.class); + a(100, true, false, Packet100OpenWindow.class); + a(101, true, true, Packet101CloseWindow.class); + a(102, false, true, Packet102WindowClick.class); + a(103, true, false, Packet103SetSlot.class); + a(104, true, false, Packet104WindowItems.class); + a(105, true, false, Packet105CraftProgressBar.class); + a(106, true, true, Packet106Transaction.class); + a(130, true, true, Packet130UpdateSign.class); + a(131, true, false, Packet131.class); + a(200, true, false, Packet200Statistic.class); + a(255, true, true, Packet255KickDisconnect.class); + packetClassToIdMap.put(ArtificialPacket53BlockChange.class, 53); //Poseidon - Artificial Block Change Packet + e = new HashMap(); + f = 0; + } +} diff --git a/src/main/java/net/minecraft/server/Packet0KeepAlive.java b/src/main/java/net/minecraft/server/Packet0KeepAlive.java new file mode 100644 index 0000000..5456aee --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet0KeepAlive.java @@ -0,0 +1,24 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; + +public class Packet0KeepAlive extends Packet { + + public Packet0KeepAlive() { + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) { + } + + public void a(DataOutputStream dataoutputstream) { + } + + public int a() { + return 0; + } +} diff --git a/src/main/java/net/minecraft/server/Packet100OpenWindow.java b/src/main/java/net/minecraft/server/Packet100OpenWindow.java new file mode 100644 index 0000000..5832f17 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet100OpenWindow.java @@ -0,0 +1,44 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet100OpenWindow extends Packet { + + public int a; + public int b; + public String c; + public int d; + + public Packet100OpenWindow() {} + + public Packet100OpenWindow(int i, int j, String s, int k) { + this.a = i; + this.b = j; + this.c = s; + this.d = k; + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + this.b = datainputstream.readByte(); + this.c = datainputstream.readUTF(); + this.d = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + dataoutputstream.writeByte(this.b); + dataoutputstream.writeUTF(this.c); + dataoutputstream.writeByte(this.d); + } + + public int a() { + return 3 + this.c.length(); + } +} diff --git a/src/main/java/net/minecraft/server/Packet101CloseWindow.java b/src/main/java/net/minecraft/server/Packet101CloseWindow.java new file mode 100644 index 0000000..c5929ce --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet101CloseWindow.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet101CloseWindow extends Packet { + + public int a; + + public Packet101CloseWindow() {} + + public Packet101CloseWindow(int i) { + this.a = i; + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + } + + public int a() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/Packet102WindowClick.java b/src/main/java/net/minecraft/server/Packet102WindowClick.java new file mode 100644 index 0000000..b8e93db --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet102WindowClick.java @@ -0,0 +1,58 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet102WindowClick extends Packet { + + public int a; + public int b; + public int c; + public short d; + public ItemStack e; + public boolean f; + + public Packet102WindowClick() {} + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + this.b = datainputstream.readShort(); + this.c = datainputstream.readByte(); + this.d = datainputstream.readShort(); + this.f = datainputstream.readBoolean(); + short short1 = datainputstream.readShort(); + + if (short1 >= 0) { + byte b0 = datainputstream.readByte(); + short short2 = datainputstream.readShort(); + + this.e = new ItemStack(short1, b0, short2); + } else { + this.e = null; + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeByte(this.c); + dataoutputstream.writeShort(this.d); + dataoutputstream.writeBoolean(this.f); + if (this.e == null) { + dataoutputstream.writeShort(-1); + } else { + dataoutputstream.writeShort(this.e.id); + dataoutputstream.writeByte(this.e.count); + dataoutputstream.writeShort(this.e.getData()); + } + } + + public int a() { + return 11; + } +} diff --git a/src/main/java/net/minecraft/server/Packet103SetSlot.java b/src/main/java/net/minecraft/server/Packet103SetSlot.java new file mode 100644 index 0000000..47699f5 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet103SetSlot.java @@ -0,0 +1,55 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet103SetSlot extends Packet { + + public int a; + public int b; + public ItemStack c; + + public Packet103SetSlot() {} + + public Packet103SetSlot(int i, int j, ItemStack itemstack) { + this.a = i; + this.b = j; + this.c = itemstack == null ? itemstack : itemstack.cloneItemStack(); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + this.b = datainputstream.readShort(); + short short1 = datainputstream.readShort(); + + if (short1 >= 0) { + byte b0 = datainputstream.readByte(); + short short2 = datainputstream.readShort(); + + this.c = new ItemStack(short1, b0, short2); + } else { + this.c = null; + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + dataoutputstream.writeShort(this.b); + if (this.c == null) { + dataoutputstream.writeShort(-1); + } else { + dataoutputstream.writeShort(this.c.id); + dataoutputstream.writeByte(this.c.count); + dataoutputstream.writeShort(this.c.getData()); + } + } + + public int a() { + return 8; + } +} diff --git a/src/main/java/net/minecraft/server/Packet104WindowItems.java b/src/main/java/net/minecraft/server/Packet104WindowItems.java new file mode 100644 index 0000000..abd6f20 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet104WindowItems.java @@ -0,0 +1,66 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; + +public class Packet104WindowItems extends Packet { + + public int a; + public ItemStack[] b; + + public Packet104WindowItems() {} + + public Packet104WindowItems(int i, List list) { + this.a = i; + this.b = new ItemStack[list.size()]; + + for (int j = 0; j < this.b.length; ++j) { + ItemStack itemstack = (ItemStack) list.get(j); + + this.b[j] = itemstack == null ? null : itemstack.cloneItemStack(); + } + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + short short1 = datainputstream.readShort(); + + this.b = new ItemStack[short1]; + + for (int i = 0; i < short1; ++i) { + short short2 = datainputstream.readShort(); + + if (short2 >= 0) { + byte b0 = datainputstream.readByte(); + short short3 = datainputstream.readShort(); + + this.b[i] = new ItemStack(short2, b0, short3); + } + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + dataoutputstream.writeShort(this.b.length); + + for (int i = 0; i < this.b.length; ++i) { + if (this.b[i] == null) { + dataoutputstream.writeShort(-1); + } else { + dataoutputstream.writeShort((short) this.b[i].id); + dataoutputstream.writeByte((byte) this.b[i].count); + dataoutputstream.writeShort((short) this.b[i].getData()); + } + } + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 3 + this.b.length * 5; + } +} diff --git a/src/main/java/net/minecraft/server/Packet105CraftProgressBar.java b/src/main/java/net/minecraft/server/Packet105CraftProgressBar.java new file mode 100644 index 0000000..33e5e91 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet105CraftProgressBar.java @@ -0,0 +1,40 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet105CraftProgressBar extends Packet { + + public int a; + public int b; + public int c; + + public Packet105CraftProgressBar() {} + + public Packet105CraftProgressBar(int i, int j, int k) { + this.a = i; + this.b = j; + this.c = k; + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + this.b = datainputstream.readShort(); + this.c = datainputstream.readShort(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeShort(this.c); + } + + public int a() { + return 5; + } +} diff --git a/src/main/java/net/minecraft/server/Packet106Transaction.java b/src/main/java/net/minecraft/server/Packet106Transaction.java new file mode 100644 index 0000000..ce64488 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet106Transaction.java @@ -0,0 +1,40 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet106Transaction extends Packet { + + public int a; + public short b; + public boolean c; + + public Packet106Transaction() {} + + public Packet106Transaction(int i, short short1, boolean flag) { + this.a = i; + this.b = short1; + this.c = flag; + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + this.b = datainputstream.readShort(); + this.c = datainputstream.readByte() != 0; + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeByte(this.c ? 1 : 0); + } + + public int a() { + return 4; + } +} diff --git a/src/main/java/net/minecraft/server/Packet10Flying.java b/src/main/java/net/minecraft/server/Packet10Flying.java new file mode 100644 index 0000000..8d6bfb9 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet10Flying.java @@ -0,0 +1,36 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet10Flying extends Packet { + + public double x; + public double y; + public double z; + public double stance; + public float yaw; + public float pitch; + public boolean g; + public boolean h; + public boolean hasLook; + + public Packet10Flying() {} + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.g = datainputstream.read() != 0; + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.write(this.g ? 1 : 0); + } + + public int a() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/Packet11PlayerPosition.java b/src/main/java/net/minecraft/server/Packet11PlayerPosition.java new file mode 100644 index 0000000..66f1015 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet11PlayerPosition.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet11PlayerPosition extends Packet10Flying { + + public Packet11PlayerPosition() { + this.h = true; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.x = datainputstream.readDouble(); + this.y = datainputstream.readDouble(); + this.stance = datainputstream.readDouble(); + this.z = datainputstream.readDouble(); + super.a(datainputstream); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeDouble(this.x); + dataoutputstream.writeDouble(this.y); + dataoutputstream.writeDouble(this.stance); + dataoutputstream.writeDouble(this.z); + super.a(dataoutputstream); + } + + public int a() { + return 33; + } +} diff --git a/src/main/java/net/minecraft/server/Packet12PlayerLook.java b/src/main/java/net/minecraft/server/Packet12PlayerLook.java new file mode 100644 index 0000000..d872465 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet12PlayerLook.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet12PlayerLook extends Packet10Flying { + + public Packet12PlayerLook() { + this.hasLook = true; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.yaw = datainputstream.readFloat(); + this.pitch = datainputstream.readFloat(); + super.a(datainputstream); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeFloat(this.yaw); + dataoutputstream.writeFloat(this.pitch); + super.a(dataoutputstream); + } + + public int a() { + return 9; + } +} diff --git a/src/main/java/net/minecraft/server/Packet130UpdateSign.java b/src/main/java/net/minecraft/server/Packet130UpdateSign.java new file mode 100644 index 0000000..f68432d --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet130UpdateSign.java @@ -0,0 +1,60 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet130UpdateSign extends Packet { + + public int x; + public int y; + public int z; + public String[] lines; + + public Packet130UpdateSign() { + this.k = true; + } + + public Packet130UpdateSign(int i, int j, int k, String[] astring) { + this.k = true; + this.x = i; + this.y = j; + this.z = k; + this.lines = astring; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.x = datainputstream.readInt(); + this.y = datainputstream.readShort(); + this.z = datainputstream.readInt(); + this.lines = new String[4]; + + for (int i = 0; i < 4; ++i) { + this.lines[i] = a(datainputstream, 15); + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.x); + dataoutputstream.writeShort(this.y); + dataoutputstream.writeInt(this.z); + + for (int i = 0; i < 4; ++i) { + a(this.lines[i], dataoutputstream); + } + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + int i = 0; + + for (int j = 0; j < 4; ++j) { + i += this.lines[j].length(); + } + + return i; + } +} diff --git a/src/main/java/net/minecraft/server/Packet131.java b/src/main/java/net/minecraft/server/Packet131.java new file mode 100644 index 0000000..d879a8d --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet131.java @@ -0,0 +1,45 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet131 extends Packet { + + public short a; + public short b; + public byte[] c; + + public Packet131() { + this.k = true; + } + + public Packet131(short short1, short short2, byte[] abyte) { + this.k = true; + this.a = short1; + this.b = short2; + this.c = abyte; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readShort(); + this.b = datainputstream.readShort(); + this.c = new byte[datainputstream.readByte() & 255]; + datainputstream.readFully(this.c); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeShort(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeByte(this.c.length); + dataoutputstream.write(this.c); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 4 + this.c.length; + } +} diff --git a/src/main/java/net/minecraft/server/Packet13PlayerLookMove.java b/src/main/java/net/minecraft/server/Packet13PlayerLookMove.java new file mode 100644 index 0000000..0dfe286 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet13PlayerLookMove.java @@ -0,0 +1,49 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet13PlayerLookMove extends Packet10Flying { + + public Packet13PlayerLookMove() { + this.hasLook = true; + this.h = true; + } + + public Packet13PlayerLookMove(double d0, double d1, double d2, double d3, float f, float f1, boolean flag) { + this.x = d0; + this.y = d1; + this.stance = d2; + this.z = d3; + this.yaw = f; + this.pitch = f1; + this.g = flag; + this.hasLook = true; + this.h = true; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.x = datainputstream.readDouble(); + this.y = datainputstream.readDouble(); + this.stance = datainputstream.readDouble(); + this.z = datainputstream.readDouble(); + this.yaw = datainputstream.readFloat(); + this.pitch = datainputstream.readFloat(); + super.a(datainputstream); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeDouble(this.x); + dataoutputstream.writeDouble(this.y); + dataoutputstream.writeDouble(this.stance); + dataoutputstream.writeDouble(this.z); + dataoutputstream.writeFloat(this.yaw); + dataoutputstream.writeFloat(this.pitch); + super.a(dataoutputstream); + } + + public int a() { + return 41; + } +} diff --git a/src/main/java/net/minecraft/server/Packet14BlockDig.java b/src/main/java/net/minecraft/server/Packet14BlockDig.java new file mode 100644 index 0000000..835a817 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet14BlockDig.java @@ -0,0 +1,40 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet14BlockDig extends Packet { + + public int a; + public int b; + public int c; + public int face; + public int e; + + public Packet14BlockDig() {} + + public void a(DataInputStream datainputstream) throws IOException { + this.e = datainputstream.read(); + this.a = datainputstream.readInt(); + this.b = datainputstream.read(); + this.c = datainputstream.readInt(); + this.face = datainputstream.read(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.write(this.e); + dataoutputstream.writeInt(this.a); + dataoutputstream.write(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.write(this.face); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 11; + } +} diff --git a/src/main/java/net/minecraft/server/Packet15Place.java b/src/main/java/net/minecraft/server/Packet15Place.java new file mode 100644 index 0000000..0b0d18b --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet15Place.java @@ -0,0 +1,55 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet15Place extends Packet { + + public int a; + public int b; + public int c; + public int face; + public ItemStack itemstack; + + public Packet15Place() {} + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.read(); + this.c = datainputstream.readInt(); + this.face = datainputstream.read(); + short short1 = datainputstream.readShort(); + + if (short1 >= 0) { + byte b0 = datainputstream.readByte(); + short short2 = datainputstream.readShort(); + + this.itemstack = new ItemStack(short1, b0, short2); + } else { + this.itemstack = null; + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.write(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.write(this.face); + if (this.itemstack == null) { + dataoutputstream.writeShort(-1); + } else { + dataoutputstream.writeShort(this.itemstack.id); + dataoutputstream.writeByte(this.itemstack.count); + dataoutputstream.writeShort(this.itemstack.getData()); + } + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 15; + } +} diff --git a/src/main/java/net/minecraft/server/Packet16BlockItemSwitch.java b/src/main/java/net/minecraft/server/Packet16BlockItemSwitch.java new file mode 100644 index 0000000..e3ea7e5 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet16BlockItemSwitch.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet16BlockItemSwitch extends Packet { + + public int itemInHandIndex; + + public Packet16BlockItemSwitch() {} + + public void a(DataInputStream datainputstream) throws IOException { + this.itemInHandIndex = datainputstream.readShort(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeShort(this.itemInHandIndex); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 2; + } +} diff --git a/src/main/java/net/minecraft/server/Packet17.java b/src/main/java/net/minecraft/server/Packet17.java new file mode 100644 index 0000000..60581e3 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet17.java @@ -0,0 +1,48 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet17 extends Packet { + + public int a; + public int b; + public int c; + public int d; + public int e; + + public Packet17() {} + + public Packet17(Entity entity, int i, int j, int k, int l) { + this.e = i; + this.b = j; + this.c = k; + this.d = l; + this.a = entity.id; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.e = datainputstream.readByte(); + this.b = datainputstream.readInt(); + this.c = datainputstream.readByte(); + this.d = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.e); + dataoutputstream.writeInt(this.b); + dataoutputstream.writeByte(this.c); + dataoutputstream.writeInt(this.d); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 14; + } +} diff --git a/src/main/java/net/minecraft/server/Packet18ArmAnimation.java b/src/main/java/net/minecraft/server/Packet18ArmAnimation.java new file mode 100644 index 0000000..53ed5a7 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet18ArmAnimation.java @@ -0,0 +1,36 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet18ArmAnimation extends Packet { + + public int a; + public int b; + + public Packet18ArmAnimation() {} + + public Packet18ArmAnimation(Entity entity, int i) { + this.a = entity.id; + this.b = i; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.b); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 5; + } +} diff --git a/src/main/java/net/minecraft/server/Packet19EntityAction.java b/src/main/java/net/minecraft/server/Packet19EntityAction.java new file mode 100644 index 0000000..24436fb --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet19EntityAction.java @@ -0,0 +1,31 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet19EntityAction extends Packet { + + public int a; + public int animation; + + public Packet19EntityAction() {} + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.animation = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.animation); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 5; + } +} diff --git a/src/main/java/net/minecraft/server/Packet1Login.java b/src/main/java/net/minecraft/server/Packet1Login.java new file mode 100644 index 0000000..1a89ae6 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet1Login.java @@ -0,0 +1,44 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet1Login extends Packet { + + public int a; + public String name; + public long c; + public byte d; + + public Packet1Login() {} + + public Packet1Login(String s, int i, long j, byte b0) { + this.name = s; + this.a = i; + this.c = j; + this.d = b0; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.name = a(datainputstream, 16); + this.c = datainputstream.readLong(); + this.d = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + a(this.name, dataoutputstream); + dataoutputstream.writeLong(this.c); + dataoutputstream.writeByte(this.d); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 4 + this.name.length() + 4 + 5; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraft/server/Packet200Statistic.java b/src/main/java/net/minecraft/server/Packet200Statistic.java new file mode 100644 index 0000000..0438e97 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet200Statistic.java @@ -0,0 +1,36 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet200Statistic extends Packet { + + public int a; + public int b; + + public Packet200Statistic() {} + + public Packet200Statistic(int i, int j) { + this.a = i; + this.b = j; + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.b); + } + + public int a() { + return 6; + } +} diff --git a/src/main/java/net/minecraft/server/Packet20NamedEntitySpawn.java b/src/main/java/net/minecraft/server/Packet20NamedEntitySpawn.java new file mode 100644 index 0000000..09e33ce --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet20NamedEntitySpawn.java @@ -0,0 +1,62 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet20NamedEntitySpawn extends Packet { + + public int a; + public String b; + public int c; + public int d; + public int e; + public byte f; + public byte g; + public int h; + + public Packet20NamedEntitySpawn() {} + + public Packet20NamedEntitySpawn(EntityHuman entityhuman) { + this.a = entityhuman.id; + this.b = entityhuman.name; + this.c = MathHelper.floor(entityhuman.locX * 32.0D); + this.d = MathHelper.floor(entityhuman.locY * 32.0D); + this.e = MathHelper.floor(entityhuman.locZ * 32.0D); + this.f = (byte) ((int) (entityhuman.yaw * 256.0F / 360.0F)); + this.g = (byte) ((int) (entityhuman.pitch * 256.0F / 360.0F)); + ItemStack itemstack = entityhuman.inventory.getItemInHand(); + + this.h = itemstack == null ? 0 : itemstack.id; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = a(datainputstream, 16); + this.c = datainputstream.readInt(); + this.d = datainputstream.readInt(); + this.e = datainputstream.readInt(); + this.f = datainputstream.readByte(); + this.g = datainputstream.readByte(); + this.h = datainputstream.readShort(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + a(this.b, dataoutputstream); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeInt(this.d); + dataoutputstream.writeInt(this.e); + dataoutputstream.writeByte(this.f); + dataoutputstream.writeByte(this.g); + dataoutputstream.writeShort(this.h); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 28; + } +} diff --git a/src/main/java/net/minecraft/server/Packet21PickupSpawn.java b/src/main/java/net/minecraft/server/Packet21PickupSpawn.java new file mode 100644 index 0000000..a5d3082 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet21PickupSpawn.java @@ -0,0 +1,68 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet21PickupSpawn extends Packet { + + public int a; + public int b; + public int c; + public int d; + public byte e; + public byte f; + public byte g; + public int h; + public int i; + public int l; + + public Packet21PickupSpawn() {} + + public Packet21PickupSpawn(EntityItem entityitem) { + this.a = entityitem.id; + this.h = entityitem.itemStack.id; + this.i = entityitem.itemStack.count; + this.l = entityitem.itemStack.getData(); + this.b = MathHelper.floor(entityitem.locX * 32.0D); + this.c = MathHelper.floor(entityitem.locY * 32.0D); + this.d = MathHelper.floor(entityitem.locZ * 32.0D); + this.e = (byte) ((int) (entityitem.motX * 128.0D)); + this.f = (byte) ((int) (entityitem.motY * 128.0D)); + this.g = (byte) ((int) (entityitem.motZ * 128.0D)); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.h = datainputstream.readShort(); + this.i = datainputstream.readByte(); + this.l = datainputstream.readShort(); + this.b = datainputstream.readInt(); + this.c = datainputstream.readInt(); + this.d = datainputstream.readInt(); + this.e = datainputstream.readByte(); + this.f = datainputstream.readByte(); + this.g = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeShort(this.h); + dataoutputstream.writeByte(this.i); + dataoutputstream.writeShort(this.l); + dataoutputstream.writeInt(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeInt(this.d); + dataoutputstream.writeByte(this.e); + dataoutputstream.writeByte(this.f); + dataoutputstream.writeByte(this.g); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 24; + } +} diff --git a/src/main/java/net/minecraft/server/Packet22Collect.java b/src/main/java/net/minecraft/server/Packet22Collect.java new file mode 100644 index 0000000..9f128bb --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet22Collect.java @@ -0,0 +1,36 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet22Collect extends Packet { + + public int a; + public int b; + + public Packet22Collect() {} + + public Packet22Collect(int i, int j) { + this.a = i; + this.b = j; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeInt(this.b); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 8; + } +} diff --git a/src/main/java/net/minecraft/server/Packet23VehicleSpawn.java b/src/main/java/net/minecraft/server/Packet23VehicleSpawn.java new file mode 100644 index 0000000..1116df2 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet23VehicleSpawn.java @@ -0,0 +1,103 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet23VehicleSpawn extends Packet { + + public int a; + public int b; + public int c; + public int d; + public int e; + public int f; + public int g; + public int h; + public int i; + + public Packet23VehicleSpawn() {} + + public Packet23VehicleSpawn(Entity entity, int i) { + this(entity, i, 0); + } + + public Packet23VehicleSpawn(Entity entity, int i, int j) { + this.a = entity.id; + this.b = MathHelper.floor(entity.locX * 32.0D); + this.c = MathHelper.floor(entity.locY * 32.0D); + this.d = MathHelper.floor(entity.locZ * 32.0D); + this.h = i; + this.i = j; + if (j > 0) { + double d0 = entity.motX; + double d1 = entity.motY; + double d2 = entity.motZ; + double d3 = 3.9D; + + if (d0 < -d3) { + d0 = -d3; + } + + if (d1 < -d3) { + d1 = -d3; + } + + if (d2 < -d3) { + d2 = -d3; + } + + if (d0 > d3) { + d0 = d3; + } + + if (d1 > d3) { + d1 = d3; + } + + if (d2 > d3) { + d2 = d3; + } + + this.e = (int) (d0 * 8000.0D); + this.f = (int) (d1 * 8000.0D); + this.g = (int) (d2 * 8000.0D); + } + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.h = datainputstream.readByte(); + this.b = datainputstream.readInt(); + this.c = datainputstream.readInt(); + this.d = datainputstream.readInt(); + this.i = datainputstream.readInt(); + if (this.i > 0) { + this.e = datainputstream.readShort(); + this.f = datainputstream.readShort(); + this.g = datainputstream.readShort(); + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.h); + dataoutputstream.writeInt(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeInt(this.d); + dataoutputstream.writeInt(this.i); + if (this.i > 0) { + dataoutputstream.writeShort(this.e); + dataoutputstream.writeShort(this.f); + dataoutputstream.writeShort(this.g); + } + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 21 + this.i > 0 ? 6 : 0; + } +} diff --git a/src/main/java/net/minecraft/server/Packet24MobSpawn.java b/src/main/java/net/minecraft/server/Packet24MobSpawn.java new file mode 100644 index 0000000..262b9b8 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet24MobSpawn.java @@ -0,0 +1,62 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; + +public class Packet24MobSpawn extends Packet { + + public int a; + public byte b; + public int c; + public int d; + public int e; + public byte f; + public byte g; + private DataWatcher h; + private List i; + + public Packet24MobSpawn() {} + + public Packet24MobSpawn(EntityLiving entityliving) { + this.a = entityliving.id; + this.b = (byte) EntityTypes.a(entityliving); + this.c = MathHelper.floor(entityliving.locX * 32.0D); + this.d = MathHelper.floor(entityliving.locY * 32.0D); + this.e = MathHelper.floor(entityliving.locZ * 32.0D); + this.f = (byte) ((int) (entityliving.yaw * 256.0F / 360.0F)); + this.g = (byte) ((int) (entityliving.pitch * 256.0F / 360.0F)); + this.h = entityliving.aa(); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readByte(); + this.c = datainputstream.readInt(); + this.d = datainputstream.readInt(); + this.e = datainputstream.readInt(); + this.f = datainputstream.readByte(); + this.g = datainputstream.readByte(); + this.i = DataWatcher.a(datainputstream); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeInt(this.d); + dataoutputstream.writeInt(this.e); + dataoutputstream.writeByte(this.f); + dataoutputstream.writeByte(this.g); + this.h.a(dataoutputstream); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 20; + } +} diff --git a/src/main/java/net/minecraft/server/Packet255KickDisconnect.java b/src/main/java/net/minecraft/server/Packet255KickDisconnect.java new file mode 100644 index 0000000..6230574 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet255KickDisconnect.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet255KickDisconnect extends Packet { + + public String a; + + public Packet255KickDisconnect() {} + + public Packet255KickDisconnect(String s) { + this.a = s; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = a(datainputstream, 100); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + a(this.a, dataoutputstream); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return this.a.length(); + } +} diff --git a/src/main/java/net/minecraft/server/Packet25EntityPainting.java b/src/main/java/net/minecraft/server/Packet25EntityPainting.java new file mode 100644 index 0000000..eac0998 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet25EntityPainting.java @@ -0,0 +1,52 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet25EntityPainting extends Packet { + + public int a; + public int b; + public int c; + public int d; + public int e; + public String f; + + public Packet25EntityPainting() {} + + public Packet25EntityPainting(EntityPainting entitypainting) { + this.a = entitypainting.id; + this.b = entitypainting.b; + this.c = entitypainting.c; + this.d = entitypainting.d; + this.e = entitypainting.a; + this.f = entitypainting.e.A; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.f = a(datainputstream, EnumArt.z); + this.b = datainputstream.readInt(); + this.c = datainputstream.readInt(); + this.d = datainputstream.readInt(); + this.e = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + a(this.f, dataoutputstream); + dataoutputstream.writeInt(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeInt(this.d); + dataoutputstream.writeInt(this.e); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 24; + } +} diff --git a/src/main/java/net/minecraft/server/Packet27.java b/src/main/java/net/minecraft/server/Packet27.java new file mode 100644 index 0000000..13caee0 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet27.java @@ -0,0 +1,67 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet27 extends Packet { + + private float a; + private float b; + private boolean c; + private boolean d; + private float e; + private float f; + + public Packet27() {} + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readFloat(); + this.b = datainputstream.readFloat(); + this.e = datainputstream.readFloat(); + this.f = datainputstream.readFloat(); + this.c = datainputstream.readBoolean(); + this.d = datainputstream.readBoolean(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeFloat(this.a); + dataoutputstream.writeFloat(this.b); + dataoutputstream.writeFloat(this.e); + dataoutputstream.writeFloat(this.f); + dataoutputstream.writeBoolean(this.c); + dataoutputstream.writeBoolean(this.d); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 18; + } + + public float c() { + return this.a; + } + + public float d() { + return this.e; + } + + public float e() { + return this.b; + } + + public float f() { + return this.f; + } + + public boolean g() { + return this.c; + } + + public boolean h() { + return this.d; + } +} diff --git a/src/main/java/net/minecraft/server/Packet28EntityVelocity.java b/src/main/java/net/minecraft/server/Packet28EntityVelocity.java new file mode 100644 index 0000000..5abcae1 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet28EntityVelocity.java @@ -0,0 +1,74 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet28EntityVelocity extends Packet { + + public int a; + public int b; + public int c; + public int d; + + public Packet28EntityVelocity() {} + + public Packet28EntityVelocity(Entity entity) { + this(entity.id, entity.motX, entity.motY, entity.motZ); + } + + public Packet28EntityVelocity(int i, double d0, double d1, double d2) { + this.a = i; + double d3 = 3.9D; + + if (d0 < -d3) { + d0 = -d3; + } + + if (d1 < -d3) { + d1 = -d3; + } + + if (d2 < -d3) { + d2 = -d3; + } + + if (d0 > d3) { + d0 = d3; + } + + if (d1 > d3) { + d1 = d3; + } + + if (d2 > d3) { + d2 = d3; + } + + this.b = (int) (d0 * 8000.0D); + this.c = (int) (d1 * 8000.0D); + this.d = (int) (d2 * 8000.0D); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readShort(); + this.c = datainputstream.readShort(); + this.d = datainputstream.readShort(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeShort(this.c); + dataoutputstream.writeShort(this.d); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 10; + } +} diff --git a/src/main/java/net/minecraft/server/Packet29DestroyEntity.java b/src/main/java/net/minecraft/server/Packet29DestroyEntity.java new file mode 100644 index 0000000..a667ada --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet29DestroyEntity.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet29DestroyEntity extends Packet { + + public int a; + + public Packet29DestroyEntity() {} + + public Packet29DestroyEntity(int i) { + this.a = i; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 4; + } +} diff --git a/src/main/java/net/minecraft/server/Packet2Handshake.java b/src/main/java/net/minecraft/server/Packet2Handshake.java new file mode 100644 index 0000000..c1700d1 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet2Handshake.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet2Handshake extends Packet { + + public String a; + + public Packet2Handshake() {} + + public Packet2Handshake(String s) { + this.a = s; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = a(datainputstream, 32); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + a(this.a, dataoutputstream); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 4 + this.a.length() + 4; + } +} diff --git a/src/main/java/net/minecraft/server/Packet30Entity.java b/src/main/java/net/minecraft/server/Packet30Entity.java new file mode 100644 index 0000000..8ddbc07 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet30Entity.java @@ -0,0 +1,38 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet30Entity extends Packet { + + public int a; + public byte b; + public byte c; + public byte d; + public byte e; + public byte f; + public boolean g = false; + + public Packet30Entity() {} + + public Packet30Entity(int i) { + this.a = i; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 4; + } +} diff --git a/src/main/java/net/minecraft/server/Packet31RelEntityMove.java b/src/main/java/net/minecraft/server/Packet31RelEntityMove.java new file mode 100644 index 0000000..5348c4b --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet31RelEntityMove.java @@ -0,0 +1,35 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet31RelEntityMove extends Packet30Entity { + + public Packet31RelEntityMove() {} + + public Packet31RelEntityMove(int i, byte b0, byte b1, byte b2) { + super(i); + this.b = b0; + this.c = b1; + this.d = b2; + } + + public void a(DataInputStream datainputstream) throws IOException { + super.a(datainputstream); + this.b = datainputstream.readByte(); + this.c = datainputstream.readByte(); + this.d = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + super.a(dataoutputstream); + dataoutputstream.writeByte(this.b); + dataoutputstream.writeByte(this.c); + dataoutputstream.writeByte(this.d); + } + + public int a() { + return 7; + } +} diff --git a/src/main/java/net/minecraft/server/Packet32EntityLook.java b/src/main/java/net/minecraft/server/Packet32EntityLook.java new file mode 100644 index 0000000..69f3a74 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet32EntityLook.java @@ -0,0 +1,35 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet32EntityLook extends Packet30Entity { + + public Packet32EntityLook() { + this.g = true; + } + + public Packet32EntityLook(int i, byte b0, byte b1) { + super(i); + this.e = b0; + this.f = b1; + this.g = true; + } + + public void a(DataInputStream datainputstream) throws IOException { + super.a(datainputstream); + this.e = datainputstream.readByte(); + this.f = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + super.a(dataoutputstream); + dataoutputstream.writeByte(this.e); + dataoutputstream.writeByte(this.f); + } + + public int a() { + return 6; + } +} diff --git a/src/main/java/net/minecraft/server/Packet33RelEntityMoveLook.java b/src/main/java/net/minecraft/server/Packet33RelEntityMoveLook.java new file mode 100644 index 0000000..80a5e8b --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet33RelEntityMoveLook.java @@ -0,0 +1,44 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet33RelEntityMoveLook extends Packet30Entity { + + public Packet33RelEntityMoveLook() { + this.g = true; + } + + public Packet33RelEntityMoveLook(int i, byte b0, byte b1, byte b2, byte b3, byte b4) { + super(i); + this.b = b0; + this.c = b1; + this.d = b2; + this.e = b3; + this.f = b4; + this.g = true; + } + + public void a(DataInputStream datainputstream) throws IOException { + super.a(datainputstream); + this.b = datainputstream.readByte(); + this.c = datainputstream.readByte(); + this.d = datainputstream.readByte(); + this.e = datainputstream.readByte(); + this.f = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + super.a(dataoutputstream); + dataoutputstream.writeByte(this.b); + dataoutputstream.writeByte(this.c); + dataoutputstream.writeByte(this.d); + dataoutputstream.writeByte(this.e); + dataoutputstream.writeByte(this.f); + } + + public int a() { + return 9; + } +} diff --git a/src/main/java/net/minecraft/server/Packet34EntityTeleport.java b/src/main/java/net/minecraft/server/Packet34EntityTeleport.java new file mode 100644 index 0000000..7f3c62e --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet34EntityTeleport.java @@ -0,0 +1,61 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet34EntityTeleport extends Packet { + + public int a; + public int b; + public int c; + public int d; + public byte e; + public byte f; + + public Packet34EntityTeleport() {} + + public Packet34EntityTeleport(Entity entity) { + this.a = entity.id; + this.b = MathHelper.floor(entity.locX * 32.0D); + this.c = MathHelper.floor(entity.locY * 32.0D); + this.d = MathHelper.floor(entity.locZ * 32.0D); + this.e = (byte) ((int) (entity.yaw * 256.0F / 360.0F)); + this.f = (byte) ((int) (entity.pitch * 256.0F / 360.0F)); + } + + public Packet34EntityTeleport(int i, int j, int k, int l, byte b0, byte b1) { + this.a = i; + this.b = j; + this.c = k; + this.d = l; + this.e = b0; + this.f = b1; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readInt(); + this.c = datainputstream.readInt(); + this.d = datainputstream.readInt(); + this.e = (byte) datainputstream.read(); + this.f = (byte) datainputstream.read(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeInt(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeInt(this.d); + dataoutputstream.write(this.e); + dataoutputstream.write(this.f); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 34; + } +} diff --git a/src/main/java/net/minecraft/server/Packet38EntityStatus.java b/src/main/java/net/minecraft/server/Packet38EntityStatus.java new file mode 100644 index 0000000..df43c9f --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet38EntityStatus.java @@ -0,0 +1,36 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet38EntityStatus extends Packet { + + public int a; + public byte b; + + public Packet38EntityStatus() {} + + public Packet38EntityStatus(int i, byte b0) { + this.a = i; + this.b = b0; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.b); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 5; + } +} diff --git a/src/main/java/net/minecraft/server/Packet39AttachEntity.java b/src/main/java/net/minecraft/server/Packet39AttachEntity.java new file mode 100644 index 0000000..4666b9e --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet39AttachEntity.java @@ -0,0 +1,36 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet39AttachEntity extends Packet { + + public int a; + public int b; + + public Packet39AttachEntity() {} + + public Packet39AttachEntity(Entity entity, Entity entity1) { + this.a = entity.id; + this.b = entity1 != null ? entity1.id : -1; + } + + public int a() { + return 8; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeInt(this.b); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } +} diff --git a/src/main/java/net/minecraft/server/Packet3Chat.java b/src/main/java/net/minecraft/server/Packet3Chat.java new file mode 100644 index 0000000..655f5e0 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet3Chat.java @@ -0,0 +1,38 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet3Chat extends Packet { + + public String message; + + public Packet3Chat() {} + + public Packet3Chat(String s) { + /* CraftBukkit start - handle this later + if (s.length() > 119) { + s = s.substring(0, 119); + } + // CraftBukkit end */ + + this.message = s; + } + + public void a(DataInputStream datainputstream) throws IOException { // CraftBukkit + this.message = a(datainputstream, 119); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { // CraftBukkit + a(this.message, dataoutputstream); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return this.message.length(); + } +} diff --git a/src/main/java/net/minecraft/server/Packet40EntityMetadata.java b/src/main/java/net/minecraft/server/Packet40EntityMetadata.java new file mode 100644 index 0000000..6e86279 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet40EntityMetadata.java @@ -0,0 +1,37 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; + +public class Packet40EntityMetadata extends Packet { + + public int a; + private List b; + + public Packet40EntityMetadata() {} + + public Packet40EntityMetadata(int i, DataWatcher datawatcher) { + this.a = i; + this.b = datawatcher.b(); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = DataWatcher.a(datainputstream); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + DataWatcher.a(this.b, dataoutputstream); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 5; + } +} diff --git a/src/main/java/net/minecraft/server/Packet4UpdateTime.java b/src/main/java/net/minecraft/server/Packet4UpdateTime.java new file mode 100644 index 0000000..7d507d5 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet4UpdateTime.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet4UpdateTime extends Packet { + + public long a; + + public Packet4UpdateTime() {} + + public Packet4UpdateTime(long i) { + this.a = i; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readLong(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeLong(this.a); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 8; + } +} diff --git a/src/main/java/net/minecraft/server/Packet50PreChunk.java b/src/main/java/net/minecraft/server/Packet50PreChunk.java new file mode 100644 index 0000000..2a191b5 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet50PreChunk.java @@ -0,0 +1,43 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet50PreChunk extends Packet { + + public int a; + public int b; + public boolean c; + + public Packet50PreChunk() { + this.k = false; + } + + public Packet50PreChunk(int i, int j, boolean flag) { + this.k = false; + this.a = i; + this.b = j; + this.c = flag; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readInt(); + this.c = datainputstream.read() != 0; + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeInt(this.b); + dataoutputstream.write(this.c ? 1 : 0); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 9; + } +} diff --git a/src/main/java/net/minecraft/server/Packet51MapChunk.java b/src/main/java/net/minecraft/server/Packet51MapChunk.java new file mode 100644 index 0000000..ae6f434 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet51MapChunk.java @@ -0,0 +1,97 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; + +public class Packet51MapChunk extends Packet { + + public int a; + public int b; + public int c; + public int d; + public int e; + public int f; + public byte[] g; + public int h; // CraftBukkit - private -> public + public byte[] rawData; // CraftBukkit + + public Packet51MapChunk() { + this.k = true; + } + + // CraftBukkit start + public Packet51MapChunk(int i, int j, int k, int l, int i1, int j1, World world) { + this(i, j, k, l, i1, j1, world.getMultiChunkData(i, j, k, l, i1, j1)); + } + + public Packet51MapChunk(int i, int j, int k, int l, int i1, int j1, byte[] data) { + // CraftBukkit end + this.k = true; + this.a = i; + this.b = j; + this.c = k; + this.d = l; + this.e = i1; + this.f = j1; + /* CraftBukkit - Moved compression into its own method. + byte[] abyte = data; // CraftBukkit - uses data from above constructor + Deflater deflater = new Deflater(-1); + + try { + deflater.setInput(abyte); + deflater.finish(); + this.g = new byte[l * i1 * j1 * 5 / 2]; + this.h = deflater.deflate(this.g); + } finally { + deflater.end(); + }*/ + this.rawData = data; // CraftBukkit + } + + public void a(DataInputStream datainputstream) throws IOException { // CraftBukkit - throws IOEXception + this.a = datainputstream.readInt(); + this.b = datainputstream.readShort(); + this.c = datainputstream.readInt(); + this.d = datainputstream.read() + 1; + this.e = datainputstream.read() + 1; + this.f = datainputstream.read() + 1; + this.h = datainputstream.readInt(); + byte[] abyte = new byte[this.h]; + + datainputstream.readFully(abyte); + this.g = new byte[this.d * this.e * this.f * 5 / 2]; + Inflater inflater = new Inflater(); + + inflater.setInput(abyte); + + try { + inflater.inflate(this.g); + } catch (DataFormatException dataformatexception) { + throw new IOException("Bad compressed data format"); + } finally { + inflater.end(); + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { // CraftBukkit - throws IOException + dataoutputstream.writeInt(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.write(this.d - 1); + dataoutputstream.write(this.e - 1); + dataoutputstream.write(this.f - 1); + dataoutputstream.writeInt(this.h); + dataoutputstream.write(this.g, 0, this.h); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 17 + this.h; + } +} diff --git a/src/main/java/net/minecraft/server/Packet52MultiBlockChange.java b/src/main/java/net/minecraft/server/Packet52MultiBlockChange.java new file mode 100644 index 0000000..28163cb --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet52MultiBlockChange.java @@ -0,0 +1,77 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet52MultiBlockChange extends Packet { + + public int a; + public int b; + public short[] c; + public byte[] d; + public byte[] e; + public int f; + + public Packet52MultiBlockChange() { + this.k = true; + } + + public Packet52MultiBlockChange(int i, int j, short[] ashort, int k, World world) { + this.k = true; + this.a = i; + this.b = j; + this.f = k; + this.c = new short[k]; + this.d = new byte[k]; + this.e = new byte[k]; + Chunk chunk = world.getChunkAt(i, j); + + for (int l = 0; l < k; ++l) { + int i1 = ashort[l] >> 12 & 15; + int j1 = ashort[l] >> 8 & 15; + int k1 = ashort[l] & 255; + + this.c[l] = ashort[l]; + this.d[l] = (byte) chunk.getTypeId(i1, k1, j1); + this.e[l] = (byte) chunk.getData(i1, k1, j1); + } + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readInt(); + this.f = datainputstream.readShort() & '\uffff'; + this.c = new short[this.f]; + this.d = new byte[this.f]; + this.e = new byte[this.f]; + + for (int i = 0; i < this.f; ++i) { + this.c[i] = datainputstream.readShort(); + } + + datainputstream.readFully(this.d); + datainputstream.readFully(this.e); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeInt(this.b); + dataoutputstream.writeShort((short) this.f); + + for (int i = 0; i < this.f; ++i) { + dataoutputstream.writeShort(this.c[i]); + } + + dataoutputstream.write(this.d); + dataoutputstream.write(this.e); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 10 + this.f * 4; + } +} diff --git a/src/main/java/net/minecraft/server/Packet53BlockChange.java b/src/main/java/net/minecraft/server/Packet53BlockChange.java new file mode 100644 index 0000000..a0b3a8a --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet53BlockChange.java @@ -0,0 +1,51 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet53BlockChange extends Packet { + + public int a; + public int b; + public int c; + public int material; + public int data; + + public Packet53BlockChange() { + this.k = true; + } + + public Packet53BlockChange(int i, int j, int k, World world) { + this.k = true; + this.a = i; + this.b = j; + this.c = k; + this.material = world.getTypeId(i, j, k); + this.data = world.getData(i, j, k); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.read(); + this.c = datainputstream.readInt(); + this.material = datainputstream.read(); + this.data = datainputstream.read(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.write(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.write(this.material); + dataoutputstream.write(this.data); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 11; + } +} diff --git a/src/main/java/net/minecraft/server/Packet54PlayNoteBlock.java b/src/main/java/net/minecraft/server/Packet54PlayNoteBlock.java new file mode 100644 index 0000000..f5a6927 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet54PlayNoteBlock.java @@ -0,0 +1,48 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet54PlayNoteBlock extends Packet { + + public int a; + public int b; + public int c; + public int d; + public int e; + + public Packet54PlayNoteBlock() {} + + public Packet54PlayNoteBlock(int i, int j, int k, int l, int i1) { + this.a = i; + this.b = j; + this.c = k; + this.d = l; + this.e = i1; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readShort(); + this.c = datainputstream.readInt(); + this.d = datainputstream.read(); + this.e = datainputstream.read(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.write(this.d); + dataoutputstream.write(this.e); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 12; + } +} diff --git a/src/main/java/net/minecraft/server/Packet5EntityEquipment.java b/src/main/java/net/minecraft/server/Packet5EntityEquipment.java new file mode 100644 index 0000000..00725c8 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet5EntityEquipment.java @@ -0,0 +1,49 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet5EntityEquipment extends Packet { + + public int a; + public int b; + public int c; + public int d; + + public Packet5EntityEquipment() {} + + public Packet5EntityEquipment(int i, int j, ItemStack itemstack) { + this.a = i; + this.b = j; + if (itemstack == null) { + this.c = -1; + this.d = 0; + } else { + this.c = itemstack.id; + this.d = itemstack.getData(); + } + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.b = datainputstream.readShort(); + this.c = datainputstream.readShort(); + this.d = datainputstream.readShort(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeShort(this.b); + dataoutputstream.writeShort(this.c); + dataoutputstream.writeShort(this.d); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 8; + } +} diff --git a/src/main/java/net/minecraft/server/Packet60Explosion.java b/src/main/java/net/minecraft/server/Packet60Explosion.java new file mode 100644 index 0000000..61b9602 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet60Explosion.java @@ -0,0 +1,79 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class Packet60Explosion extends Packet { + + public double a; + public double b; + public double c; + public float d; + public Set e; + + public Packet60Explosion() {} + + public Packet60Explosion(double d0, double d1, double d2, float f, Set set) { + this.a = d0; + this.b = d1; + this.c = d2; + this.d = f; + this.e = new HashSet(set); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readDouble(); + this.b = datainputstream.readDouble(); + this.c = datainputstream.readDouble(); + this.d = datainputstream.readFloat(); + int i = datainputstream.readInt(); + + this.e = new HashSet(); + int j = (int) this.a; + int k = (int) this.b; + int l = (int) this.c; + + for (int i1 = 0; i1 < i; ++i1) { + int j1 = datainputstream.readByte() + j; + int k1 = datainputstream.readByte() + k; + int l1 = datainputstream.readByte() + l; + + this.e.add(new ChunkPosition(j1, k1, l1)); + } + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeDouble(this.a); + dataoutputstream.writeDouble(this.b); + dataoutputstream.writeDouble(this.c); + dataoutputstream.writeFloat(this.d); + dataoutputstream.writeInt(this.e.size()); + int i = (int) this.a; + int j = (int) this.b; + int k = (int) this.c; + Iterator iterator = this.e.iterator(); + + while (iterator.hasNext()) { + ChunkPosition chunkposition = (ChunkPosition) iterator.next(); + int l = chunkposition.x - i; + int i1 = chunkposition.y - j; + int j1 = chunkposition.z - k; + + dataoutputstream.writeByte(l); + dataoutputstream.writeByte(i1); + dataoutputstream.writeByte(j1); + } + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 32 + this.e.size() * 3; + } +} diff --git a/src/main/java/net/minecraft/server/Packet61.java b/src/main/java/net/minecraft/server/Packet61.java new file mode 100644 index 0000000..a051829 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet61.java @@ -0,0 +1,48 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet61 extends Packet { + + public int a; + public int b; + public int c; + public int d; + public int e; + + public Packet61() {} + + public Packet61(int i, int j, int k, int l, int i1) { + this.a = i; + this.c = j; + this.d = k; + this.e = l; + this.b = i1; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.c = datainputstream.readInt(); + this.d = datainputstream.readByte(); + this.e = datainputstream.readInt(); + this.b = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeByte(this.d); + dataoutputstream.writeInt(this.e); + dataoutputstream.writeInt(this.b); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 20; + } +} diff --git a/src/main/java/net/minecraft/server/Packet6SpawnPosition.java b/src/main/java/net/minecraft/server/Packet6SpawnPosition.java new file mode 100644 index 0000000..080e44f --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet6SpawnPosition.java @@ -0,0 +1,40 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet6SpawnPosition extends Packet { + + public int x; + public int y; + public int z; + + public Packet6SpawnPosition() {} + + public Packet6SpawnPosition(int i, int j, int k) { + this.x = i; + this.y = j; + this.z = k; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.x = datainputstream.readInt(); + this.y = datainputstream.readInt(); + this.z = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.x); + dataoutputstream.writeInt(this.y); + dataoutputstream.writeInt(this.z); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 12; + } +} diff --git a/src/main/java/net/minecraft/server/Packet70Bed.java b/src/main/java/net/minecraft/server/Packet70Bed.java new file mode 100644 index 0000000..a965a2c --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet70Bed.java @@ -0,0 +1,33 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet70Bed extends Packet { + + public static final String[] a = new String[] { "tile.bed.notValid", null, null}; + public int b; + + public Packet70Bed() {} + + public Packet70Bed(int i) { + this.b = i; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.b = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.b); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/Packet71Weather.java b/src/main/java/net/minecraft/server/Packet71Weather.java new file mode 100644 index 0000000..8d53c34 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet71Weather.java @@ -0,0 +1,50 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet71Weather extends Packet { + + public int a; + public int b; + public int c; + public int d; + public int e; + + public Packet71Weather() {} + + public Packet71Weather(Entity entity) { + this.a = entity.id; + this.b = MathHelper.floor(entity.locX * 32.0D); + this.c = MathHelper.floor(entity.locY * 32.0D); + this.d = MathHelper.floor(entity.locZ * 32.0D); + if (entity instanceof EntityWeatherStorm) { + this.e = 1; + } + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.e = datainputstream.readByte(); + this.b = datainputstream.readInt(); + this.c = datainputstream.readInt(); + this.d = datainputstream.readInt(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeByte(this.e); + dataoutputstream.writeInt(this.b); + dataoutputstream.writeInt(this.c); + dataoutputstream.writeInt(this.d); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 17; + } +} diff --git a/src/main/java/net/minecraft/server/Packet7UseEntity.java b/src/main/java/net/minecraft/server/Packet7UseEntity.java new file mode 100644 index 0000000..03fde2f --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet7UseEntity.java @@ -0,0 +1,34 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet7UseEntity extends Packet { + + public int a; + public int target; + public int c; + + public Packet7UseEntity() {} + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readInt(); + this.target = datainputstream.readInt(); + this.c = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeInt(this.a); + dataoutputstream.writeInt(this.target); + dataoutputstream.writeByte(this.c); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 9; + } +} diff --git a/src/main/java/net/minecraft/server/Packet8UpdateHealth.java b/src/main/java/net/minecraft/server/Packet8UpdateHealth.java new file mode 100644 index 0000000..783a785 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet8UpdateHealth.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet8UpdateHealth extends Packet { + + public int a; + + public Packet8UpdateHealth() {} + + public Packet8UpdateHealth(int i) { + this.a = i; + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readShort(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeShort(this.a); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return 2; + } +} diff --git a/src/main/java/net/minecraft/server/Packet9Respawn.java b/src/main/java/net/minecraft/server/Packet9Respawn.java new file mode 100644 index 0000000..4821d07 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet9Respawn.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet9Respawn extends Packet { + + public byte a; + + public Packet9Respawn() {} + + public Packet9Respawn(byte b0) { + this.a = b0; + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public void a(DataInputStream datainputstream) throws IOException { + this.a = datainputstream.readByte(); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeByte(this.a); + } + + public int a() { + return 1; + } +} diff --git a/src/main/java/net/minecraft/server/PacketCounter.java b/src/main/java/net/minecraft/server/PacketCounter.java new file mode 100644 index 0000000..38239ab --- /dev/null +++ b/src/main/java/net/minecraft/server/PacketCounter.java @@ -0,0 +1,18 @@ +package net.minecraft.server; + +class PacketCounter { + + private int a; + private long b; + + private PacketCounter() {} + + public void a(int i) { + ++this.a; + this.b += (long) i; + } + + PacketCounter(EmptyClass1 emptyclass1) { + this(); + } +} diff --git a/src/main/java/net/minecraft/server/Path.java b/src/main/java/net/minecraft/server/Path.java new file mode 100644 index 0000000..9575e13 --- /dev/null +++ b/src/main/java/net/minecraft/server/Path.java @@ -0,0 +1,128 @@ +package net.minecraft.server; + +public class Path { + + private PathPoint[] a = new PathPoint[1024]; + private int b = 0; + + public Path() {} + + public PathPoint a(PathPoint pathpoint) { + if (pathpoint.d >= 0) { + throw new IllegalStateException("OW KNOWS!"); + } else { + if (this.b == this.a.length) { + PathPoint[] apathpoint = new PathPoint[this.b << 1]; + + System.arraycopy(this.a, 0, apathpoint, 0, this.b); + this.a = apathpoint; + } + + this.a[this.b] = pathpoint; + pathpoint.d = this.b; + this.a(this.b++); + return pathpoint; + } + } + + public void a() { + this.b = 0; + } + + public PathPoint b() { + PathPoint pathpoint = this.a[0]; + + this.a[0] = this.a[--this.b]; + this.a[this.b] = null; + if (this.b > 0) { + this.b(0); + } + + pathpoint.d = -1; + return pathpoint; + } + + public void a(PathPoint pathpoint, float f) { + float f1 = pathpoint.g; + + pathpoint.g = f; + if (f < f1) { + this.a(pathpoint.d); + } else { + this.b(pathpoint.d); + } + } + + private void a(int i) { + PathPoint pathpoint = this.a[i]; + + int j; + + for (float f = pathpoint.g; i > 0; i = j) { + j = i - 1 >> 1; + PathPoint pathpoint1 = this.a[j]; + + if (f >= pathpoint1.g) { + break; + } + + this.a[i] = pathpoint1; + pathpoint1.d = i; + } + + this.a[i] = pathpoint; + pathpoint.d = i; + } + + private void b(int i) { + PathPoint pathpoint = this.a[i]; + float f = pathpoint.g; + + while (true) { + int j = 1 + (i << 1); + int k = j + 1; + + if (j >= this.b) { + break; + } + + PathPoint pathpoint1 = this.a[j]; + float f1 = pathpoint1.g; + PathPoint pathpoint2; + float f2; + + if (k >= this.b) { + pathpoint2 = null; + f2 = Float.POSITIVE_INFINITY; + } else { + pathpoint2 = this.a[k]; + f2 = pathpoint2.g; + } + + if (f1 < f2) { + if (f1 >= f) { + break; + } + + this.a[i] = pathpoint1; + pathpoint1.d = i; + i = j; + } else { + if (f2 >= f) { + break; + } + + this.a[i] = pathpoint2; + pathpoint2.d = i; + i = k; + } + } + + this.a[i] = pathpoint; + pathpoint.d = i; + } + + public boolean c() { + return this.b == 0; + } +} diff --git a/src/main/java/net/minecraft/server/PathEntity.java b/src/main/java/net/minecraft/server/PathEntity.java new file mode 100644 index 0000000..2a6130d --- /dev/null +++ b/src/main/java/net/minecraft/server/PathEntity.java @@ -0,0 +1,33 @@ +package net.minecraft.server; + +public class PathEntity { + + private final PathPoint[] b; + public final int a; + private int c; + + public PathEntity(PathPoint[] apathpoint) { + this.b = apathpoint; + this.a = apathpoint.length; + } + + public void a() { + ++this.c; + } + + public boolean b() { + return this.c >= this.b.length; + } + + public PathPoint c() { + return this.a > 0 ? this.b[this.a - 1] : null; + } + + public Vec3D a(Entity entity) { + double d0 = (double) this.b[this.c].a + (double) ((int) (entity.length + 1.0F)) * 0.5D; + double d1 = (double) this.b[this.c].b; + double d2 = (double) this.b[this.c].c + (double) ((int) (entity.length + 1.0F)) * 0.5D; + + return Vec3D.create(d0, d1, d2); + } +} diff --git a/src/main/java/net/minecraft/server/PathPoint.java b/src/main/java/net/minecraft/server/PathPoint.java new file mode 100644 index 0000000..0f7e000 --- /dev/null +++ b/src/main/java/net/minecraft/server/PathPoint.java @@ -0,0 +1,56 @@ +package net.minecraft.server; + +public class PathPoint { + + public final int a; + public final int b; + public final int c; + private final int j; + int d = -1; + float e; + float f; + float g; + PathPoint h; + public boolean i = false; + + public PathPoint(int i, int j, int k) { + this.a = i; + this.b = j; + this.c = k; + this.j = a(i, j, k); + } + + public static int a(int i, int j, int k) { + return j & 255 | (i & 32767) << 8 | (k & 32767) << 24 | (i < 0 ? Integer.MIN_VALUE : 0) | (k < 0 ? '\u8000' : 0); + } + + public float a(PathPoint pathpoint) { + float f = (float) (pathpoint.a - this.a); + float f1 = (float) (pathpoint.b - this.b); + float f2 = (float) (pathpoint.c - this.c); + + return MathHelper.c(f * f + f1 * f1 + f2 * f2); + } + + public boolean equals(Object object) { + if (!(object instanceof PathPoint)) { + return false; + } else { + PathPoint pathpoint = (PathPoint) object; + + return this.j == pathpoint.j && this.a == pathpoint.a && this.b == pathpoint.b && this.c == pathpoint.c; + } + } + + public int hashCode() { + return this.j; + } + + public boolean a() { + return this.d >= 0; + } + + public String toString() { + return this.a + ", " + this.b + ", " + this.c; + } +} diff --git a/src/main/java/net/minecraft/server/Pathfinder.java b/src/main/java/net/minecraft/server/Pathfinder.java new file mode 100644 index 0000000..b304b9f --- /dev/null +++ b/src/main/java/net/minecraft/server/Pathfinder.java @@ -0,0 +1,217 @@ +package net.minecraft.server; + +public class Pathfinder { + + private IBlockAccess a; + private Path b = new Path(); + private EntityList c = new EntityList(); + private PathPoint[] d = new PathPoint[32]; + + public Pathfinder(IBlockAccess iblockaccess) { + this.a = iblockaccess; + } + + public PathEntity a(Entity entity, Entity entity1, float f) { + return this.a(entity, entity1.locX, entity1.boundingBox.b, entity1.locZ, f); + } + + public PathEntity a(Entity entity, int i, int j, int k, float f) { + return this.a(entity, (double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F), f); + } + + private PathEntity a(Entity entity, double d0, double d1, double d2, float f) { + this.b.a(); + this.c.a(); + PathPoint pathpoint = this.a(MathHelper.floor(entity.boundingBox.a), MathHelper.floor(entity.boundingBox.b), MathHelper.floor(entity.boundingBox.c)); + PathPoint pathpoint1 = this.a(MathHelper.floor(d0 - (double) (entity.length / 2.0F)), MathHelper.floor(d1), MathHelper.floor(d2 - (double) (entity.length / 2.0F))); + PathPoint pathpoint2 = new PathPoint(MathHelper.d(entity.length + 1.0F), MathHelper.d(entity.width + 1.0F), MathHelper.d(entity.length + 1.0F)); + PathEntity pathentity = this.a(entity, pathpoint, pathpoint1, pathpoint2, f); + + return pathentity; + } + + private PathEntity a(Entity entity, PathPoint pathpoint, PathPoint pathpoint1, PathPoint pathpoint2, float f) { + pathpoint.e = 0.0F; + pathpoint.f = pathpoint.a(pathpoint1); + pathpoint.g = pathpoint.f; + this.b.a(); + this.b.a(pathpoint); + PathPoint pathpoint3 = pathpoint; + + while (!this.b.c()) { + PathPoint pathpoint4 = this.b.b(); + + if (pathpoint4.equals(pathpoint1)) { + return this.a(pathpoint, pathpoint1); + } + + if (pathpoint4.a(pathpoint1) < pathpoint3.a(pathpoint1)) { + pathpoint3 = pathpoint4; + } + + pathpoint4.i = true; + int i = this.b(entity, pathpoint4, pathpoint2, pathpoint1, f); + + for (int j = 0; j < i; ++j) { + PathPoint pathpoint5 = this.d[j]; + float f1 = pathpoint4.e + pathpoint4.a(pathpoint5); + + if (!pathpoint5.a() || f1 < pathpoint5.e) { + pathpoint5.h = pathpoint4; + pathpoint5.e = f1; + pathpoint5.f = pathpoint5.a(pathpoint1); + if (pathpoint5.a()) { + this.b.a(pathpoint5, pathpoint5.e + pathpoint5.f); + } else { + pathpoint5.g = pathpoint5.e + pathpoint5.f; + this.b.a(pathpoint5); + } + } + } + } + + if (pathpoint3 == pathpoint) { + return null; + } else { + return this.a(pathpoint, pathpoint3); + } + } + + private int b(Entity entity, PathPoint pathpoint, PathPoint pathpoint1, PathPoint pathpoint2, float f) { + int i = 0; + byte b0 = 0; + + if (this.a(entity, pathpoint.a, pathpoint.b + 1, pathpoint.c, pathpoint1) == 1) { + b0 = 1; + } + + PathPoint pathpoint3 = this.a(entity, pathpoint.a, pathpoint.b, pathpoint.c + 1, pathpoint1, b0); + PathPoint pathpoint4 = this.a(entity, pathpoint.a - 1, pathpoint.b, pathpoint.c, pathpoint1, b0); + PathPoint pathpoint5 = this.a(entity, pathpoint.a + 1, pathpoint.b, pathpoint.c, pathpoint1, b0); + PathPoint pathpoint6 = this.a(entity, pathpoint.a, pathpoint.b, pathpoint.c - 1, pathpoint1, b0); + + if (pathpoint3 != null && !pathpoint3.i && pathpoint3.a(pathpoint2) < f) { + this.d[i++] = pathpoint3; + } + + if (pathpoint4 != null && !pathpoint4.i && pathpoint4.a(pathpoint2) < f) { + this.d[i++] = pathpoint4; + } + + if (pathpoint5 != null && !pathpoint5.i && pathpoint5.a(pathpoint2) < f) { + this.d[i++] = pathpoint5; + } + + if (pathpoint6 != null && !pathpoint6.i && pathpoint6.a(pathpoint2) < f) { + this.d[i++] = pathpoint6; + } + + return i; + } + + private PathPoint a(Entity entity, int i, int j, int k, PathPoint pathpoint, int l) { + PathPoint pathpoint1 = null; + + if (this.a(entity, i, j, k, pathpoint) == 1) { + pathpoint1 = this.a(i, j, k); + } + + if (pathpoint1 == null && l > 0 && this.a(entity, i, j + l, k, pathpoint) == 1) { + pathpoint1 = this.a(i, j + l, k); + j += l; + } + + if (pathpoint1 != null) { + int i1 = 0; + int j1 = 0; + + while (j > 0 && (j1 = this.a(entity, i, j - 1, k, pathpoint)) == 1) { + ++i1; + if (i1 >= 4) { + return null; + } + + --j; + if (j > 0) { + pathpoint1 = this.a(i, j, k); + } + } + + if (j1 == -2) { + return null; + } + } + + return pathpoint1; + } + + private final PathPoint a(int i, int j, int k) { + int l = PathPoint.a(i, j, k); + PathPoint pathpoint = (PathPoint) this.c.a(l); + + if (pathpoint == null) { + pathpoint = new PathPoint(i, j, k); + this.c.a(l, pathpoint); + } + + return pathpoint; + } + + private int a(Entity entity, int i, int j, int k, PathPoint pathpoint) { + for (int l = i; l < i + pathpoint.a; ++l) { + for (int i1 = j; i1 < j + pathpoint.b; ++i1) { + for (int j1 = k; j1 < k + pathpoint.c; ++j1) { + int k1 = this.a.getTypeId(l, i1, j1); + + if (k1 > 0) { + if (k1 != Block.IRON_DOOR_BLOCK.id && k1 != Block.WOODEN_DOOR.id) { + Material material = Block.byId[k1].material; + + if (material.isSolid()) { + return 0; + } + + if (material == Material.WATER) { + return -1; + } + + if (material == Material.LAVA) { + return -2; + } + } else { + int l1 = this.a.getData(l, i1, j1); + + if (!BlockDoor.e(l1)) { + return 0; + } + } + } + } + } + } + + return 1; + } + + private PathEntity a(PathPoint pathpoint, PathPoint pathpoint1) { + int i = 1; + + PathPoint pathpoint2; + + for (pathpoint2 = pathpoint1; pathpoint2.h != null; pathpoint2 = pathpoint2.h) { + ++i; + } + + PathPoint[] apathpoint = new PathPoint[i]; + + pathpoint2 = pathpoint1; + --i; + + for (apathpoint[i] = pathpoint1; pathpoint2.h != null; apathpoint[i] = pathpoint2) { + pathpoint2 = pathpoint2.h; + --i; + } + + return new PathEntity(apathpoint); + } +} diff --git a/src/main/java/net/minecraft/server/PistonBlockTextures.java b/src/main/java/net/minecraft/server/PistonBlockTextures.java new file mode 100644 index 0000000..1d2b290 --- /dev/null +++ b/src/main/java/net/minecraft/server/PistonBlockTextures.java @@ -0,0 +1,11 @@ +package net.minecraft.server; + +public class PistonBlockTextures { + + public static final int[] a = new int[] { 1, 0, 3, 2, 5, 4}; + public static final int[] b = new int[] { 0, 0, 0, 0, -1, 1}; + public static final int[] c = new int[] { -1, 1, 0, 0, 0, 0}; + public static final int[] d = new int[] { 0, 0, -1, 1, 0, 0}; + + public PistonBlockTextures() {} +} diff --git a/src/main/java/net/minecraft/server/PlayerFileData.java b/src/main/java/net/minecraft/server/PlayerFileData.java new file mode 100644 index 0000000..078b785 --- /dev/null +++ b/src/main/java/net/minecraft/server/PlayerFileData.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +public interface PlayerFileData { + + void a(EntityHuman entityhuman); + + void b(EntityHuman entityhuman); +} diff --git a/src/main/java/net/minecraft/server/PlayerInstance.java b/src/main/java/net/minecraft/server/PlayerInstance.java new file mode 100644 index 0000000..81a84a8 --- /dev/null +++ b/src/main/java/net/minecraft/server/PlayerInstance.java @@ -0,0 +1,201 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +class PlayerInstance { + + private List b; + private int chunkX; + private int chunkZ; + private ChunkCoordIntPair location; + private short[] dirtyBlocks; + private int dirtyCount; + private int h; + private int i; + private int j; + private int k; + private int l; + private int m; + + final PlayerManager playerManager; + + public PlayerInstance(PlayerManager playermanager, int i, int j) { + this.playerManager = playermanager; + this.b = new ArrayList(); + this.dirtyBlocks = new short[10]; + this.dirtyCount = 0; + this.chunkX = i; + this.chunkZ = j; + this.location = new ChunkCoordIntPair(i, j); + playermanager.a().chunkProviderServer.getChunkAt(i, j); + } + + public void a(EntityPlayer entityplayer) { + if (this.b.contains(entityplayer)) { + throw new IllegalStateException("Failed to add player. " + entityplayer + " already is in chunk " + this.chunkX + ", " + this.chunkZ); + } else { + // CraftBukkit start + if (entityplayer.playerChunkCoordIntPairs.add(this.location)) { + entityplayer.netServerHandler.sendPacket(new Packet50PreChunk(this.location.x, this.location.z, true)); + } + // CraftBukkit end + + this.b.add(entityplayer); + entityplayer.chunkCoordIntPairQueue.add(this.location); + } + } + + public void b(EntityPlayer entityplayer) { + if (this.b.contains(entityplayer)) { + this.b.remove(entityplayer); + if (this.b.size() == 0) { + long i = (long) this.chunkX + 2147483647L | (long) this.chunkZ + 2147483647L << 32; + + PlayerManager.a(this.playerManager).b(i); + if (this.dirtyCount > 0) { + PlayerManager.b(this.playerManager).remove(this); + } + + this.playerManager.a().chunkProviderServer.queueUnload(this.chunkX, this.chunkZ); + } + + entityplayer.chunkCoordIntPairQueue.remove(this.location); + // CraftBukkit - contains -> remove -- TODO VERIFY!!!! + if (entityplayer.playerChunkCoordIntPairs.remove(this.location)) { + entityplayer.netServerHandler.sendPacket(new Packet50PreChunk(this.chunkX, this.chunkZ, false)); + } + } + } + + public void a(int i, int j, int k) { + if (this.dirtyCount == 0) { + PlayerManager.b(this.playerManager).add(this); + this.h = this.i = i; + this.j = this.k = j; + this.l = this.m = k; + } + + if (this.h > i) { + this.h = i; + } + + if (this.i < i) { + this.i = i; + } + + if (this.j > j) { + this.j = j; + } + + if (this.k < j) { + this.k = j; + } + + if (this.l > k) { + this.l = k; + } + + if (this.m < k) { + this.m = k; + } + + if (this.dirtyCount < 10) { + short short1 = (short) (i << 12 | k << 8 | j); + + for (int l = 0; l < this.dirtyCount; ++l) { + if (this.dirtyBlocks[l] == short1) { + return; + } + } + + this.dirtyBlocks[this.dirtyCount++] = short1; + } + } + + public void sendAll(Packet packet) { + for (int i = 0; i < this.b.size(); ++i) { + EntityPlayer entityplayer = (EntityPlayer) this.b.get(i); + + if (entityplayer.playerChunkCoordIntPairs.contains(this.location)) { + entityplayer.netServerHandler.sendPacket(packet); + } + } + } + + public void a() { + WorldServer worldserver = this.playerManager.a(); + + if (this.dirtyCount != 0) { + int i; + int j; + int k; + + if (this.dirtyCount == 1) { + i = this.chunkX * 16 + this.h; + j = this.j; + k = this.chunkZ * 16 + this.l; + this.sendAll(new Packet53BlockChange(i, j, k, worldserver)); + if (Block.isTileEntity[worldserver.getTypeId(i, j, k)]) { + this.sendTileEntity(worldserver.getTileEntity(i, j, k)); + } + } else { + int l; + + if (this.dirtyCount == 10) { + this.j = this.j / 2 * 2; + this.k = (this.k / 2 + 1) * 2; + i = this.h + this.chunkX * 16; + j = this.j; + k = this.l + this.chunkZ * 16; + l = this.i - this.h + 1; + int i1 = this.k - this.j + 2; + int j1 = this.m - this.l + 1; + + this.sendAll(new Packet51MapChunk(i, j, k, l, i1, j1, worldserver)); + List list = worldserver.getTileEntities(i, j, k, i + l, j + i1, k + j1); + + for (int k1 = 0; k1 < list.size(); ++k1) { + this.sendTileEntity((TileEntity) list.get(k1)); + } + } else { + this.sendAll(new Packet52MultiBlockChange(this.chunkX, this.chunkZ, this.dirtyBlocks, this.dirtyCount, worldserver)); + + for (i = 0; i < this.dirtyCount; ++i) { + // CraftBukkit start - Fixes TileEntity updates occurring upon a multi-block change; dirtyCount -> dirtyBlocks[i] + j = this.chunkX * 16 + (this.dirtyBlocks[i] >> 12 & 15); + k = this.dirtyBlocks[i] & 255; + l = this.chunkZ * 16 + (this.dirtyBlocks[i] >> 8 & 15); + // CraftBukkit end + + if (Block.isTileEntity[worldserver.getTypeId(j, k, l)]) { + // System.out.println("Sending!"); // CraftBukkit + this.sendTileEntity(worldserver.getTileEntity(j, k, l)); + } + } + } + } + + this.dirtyCount = 0; + } + } + + private void sendTileEntity(TileEntity tileentity) { + if (tileentity != null) { + Packet packet = tileentity.f(); + + if (packet != null) { + this.sendAll(packet); + } + } + } + + // Poseidon + static ChunkCoordIntPair a(PlayerInstance playerchunk) { + return playerchunk.location; + } + + static List b(PlayerInstance playerchunk) { + return playerchunk.b; + } +} diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java new file mode 100644 index 0000000..e30fc3d --- /dev/null +++ b/src/main/java/net/minecraft/server/PlayerList.java @@ -0,0 +1,137 @@ +package net.minecraft.server; + +public class PlayerList { + + private transient PlayerListEntry[] a = new PlayerListEntry[16]; + private transient int b; + private int c = 12; + private final float d = 0.75F; + private transient volatile int e; + + public PlayerList() {} + + private static int e(long i) { + return a((int) (i ^ i >>> 32)); + } + + private static int a(int i) { + i ^= i >>> 20 ^ i >>> 12; + return i ^ i >>> 7 ^ i >>> 4; + } + + private static int a(int i, int j) { + return i & j - 1; + } + + public Object a(long i) { + int j = e(i); + + for (PlayerListEntry playerlistentry = this.a[a(j, this.a.length)]; playerlistentry != null; playerlistentry = playerlistentry.c) { + if (playerlistentry.a == i) { + return playerlistentry.b; + } + } + + return null; + } + + public void a(long i, Object object) { + int j = e(i); + int k = a(j, this.a.length); + + for (PlayerListEntry playerlistentry = this.a[k]; playerlistentry != null; playerlistentry = playerlistentry.c) { + if (playerlistentry.a == i) { + playerlistentry.b = object; + } + } + + ++this.e; + this.a(j, i, object, k); + } + + private void b(int i) { + PlayerListEntry[] aplayerlistentry = this.a; + int j = aplayerlistentry.length; + + if (j == 1073741824) { + this.c = Integer.MAX_VALUE; + } else { + PlayerListEntry[] aplayerlistentry1 = new PlayerListEntry[i]; + + this.a(aplayerlistentry1); + this.a = aplayerlistentry1; + this.c = (int) ((float) i * this.d); + } + } + + private void a(PlayerListEntry[] aplayerlistentry) { + PlayerListEntry[] aplayerlistentry1 = this.a; + int i = aplayerlistentry.length; + + for (int j = 0; j < aplayerlistentry1.length; ++j) { + PlayerListEntry playerlistentry = aplayerlistentry1[j]; + + if (playerlistentry != null) { + aplayerlistentry1[j] = null; + + PlayerListEntry playerlistentry1; + + do { + playerlistentry1 = playerlistentry.c; + int k = a(playerlistentry.d, i); + + playerlistentry.c = aplayerlistentry[k]; + aplayerlistentry[k] = playerlistentry; + playerlistentry = playerlistentry1; + } while (playerlistentry1 != null); + } + } + } + + public Object b(long i) { + PlayerListEntry playerlistentry = this.c(i); + + return playerlistentry == null ? null : playerlistentry.b; + } + + final PlayerListEntry c(long i) { + int j = e(i); + int k = a(j, this.a.length); + PlayerListEntry playerlistentry = this.a[k]; + + PlayerListEntry playerlistentry1; + PlayerListEntry playerlistentry2; + + for (playerlistentry1 = playerlistentry; playerlistentry1 != null; playerlistentry1 = playerlistentry2) { + playerlistentry2 = playerlistentry1.c; + if (playerlistentry1.a == i) { + ++this.e; + --this.b; + if (playerlistentry == playerlistentry1) { + this.a[k] = playerlistentry2; + } else { + playerlistentry.c = playerlistentry2; + } + + return playerlistentry1; + } + + playerlistentry = playerlistentry1; + } + + return playerlistentry1; + } + + private void a(int i, long j, Object object, int k) { + PlayerListEntry playerlistentry = this.a[k]; + + this.a[k] = new PlayerListEntry(i, j, object, playerlistentry); + if (this.b++ >= this.c) { + this.b(2 * this.a.length); + } + } + + static int d(long i) { + return e(i); + } +} diff --git a/src/main/java/net/minecraft/server/PlayerListBox.java b/src/main/java/net/minecraft/server/PlayerListBox.java new file mode 100644 index 0000000..fddd5f7 --- /dev/null +++ b/src/main/java/net/minecraft/server/PlayerListBox.java @@ -0,0 +1,27 @@ +package net.minecraft.server; + +import javax.swing.*; +import java.util.Vector; + +public class PlayerListBox extends JList implements IUpdatePlayerListBox { + + private MinecraftServer a; + private int b = 0; + + public PlayerListBox(MinecraftServer minecraftserver) { + this.a = minecraftserver; + minecraftserver.a((IUpdatePlayerListBox) this); + } + + public void a() { + if (this.b++ % 20 == 0) { + Vector vector = new Vector(); + + for (int i = 0; i < this.a.serverConfigurationManager.players.size(); ++i) { + vector.add(((EntityPlayer) this.a.serverConfigurationManager.players.get(i)).name); + } + + this.setListData(vector); + } + } +} diff --git a/src/main/java/net/minecraft/server/PlayerListEntry.java b/src/main/java/net/minecraft/server/PlayerListEntry.java new file mode 100644 index 0000000..2466c69 --- /dev/null +++ b/src/main/java/net/minecraft/server/PlayerListEntry.java @@ -0,0 +1,53 @@ +package net.minecraft.server; + +class PlayerListEntry { + + final long a; + Object b; + PlayerListEntry c; + final int d; + + PlayerListEntry(int i, long j, Object object, PlayerListEntry playerlistentry) { + this.b = object; + this.c = playerlistentry; + this.a = j; + this.d = i; + } + + public final long a() { + return this.a; + } + + public final Object b() { + return this.b; + } + + public final boolean equals(Object object) { + if (!(object instanceof PlayerListEntry)) { + return false; + } else { + PlayerListEntry playerlistentry = (PlayerListEntry) object; + Long olong = Long.valueOf(this.a()); + Long olong1 = Long.valueOf(playerlistentry.a()); + + if (olong == olong1 || olong != null && olong.equals(olong1)) { + Object object1 = this.b(); + Object object2 = playerlistentry.b(); + + if (object1 == object2 || object1 != null && object1.equals(object2)) { + return true; + } + } + + return false; + } + } + + public final int hashCode() { + return PlayerList.d(this.a); + } + + public final String toString() { + return this.a() + "=" + this.b(); + } +} diff --git a/src/main/java/net/minecraft/server/PlayerManager.java b/src/main/java/net/minecraft/server/PlayerManager.java new file mode 100644 index 0000000..76e626a --- /dev/null +++ b/src/main/java/net/minecraft/server/PlayerManager.java @@ -0,0 +1,192 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +public class PlayerManager { + + public List managedPlayers = new ArrayList(); + private PlayerList b = new PlayerList(); + private List c = new ArrayList(); + private MinecraftServer server; + private int e; + private int f; + private final int[][] g = new int[][] { { 1, 0}, { 0, 1}, { -1, 0}, { 0, -1}}; + + public PlayerManager(MinecraftServer minecraftserver, int i, int j) { + if (j > 15) { + throw new IllegalArgumentException("Too big view radius!"); + } else if (j < 3) { + throw new IllegalArgumentException("Too small view radius!"); + } else { + this.f = j; + this.server = minecraftserver; + this.e = i; + } + } + + public WorldServer a() { + return this.server.getWorldServer(this.e); + } + + public void flush() { + for (int i = 0; i < this.c.size(); ++i) { + ((PlayerInstance) this.c.get(i)).a(); + } + + this.c.clear(); + } + + private PlayerInstance a(int i, int j, boolean flag) { + long k = (long) i + 2147483647L | (long) j + 2147483647L << 32; + PlayerInstance playerinstance = (PlayerInstance) this.b.a(k); + + if (playerinstance == null && flag) { + playerinstance = new PlayerInstance(this, i, j); + this.b.a(k, playerinstance); + } + + return playerinstance; + } + + public void flagDirty(int i, int j, int k) { + int l = i >> 4; + int i1 = k >> 4; + PlayerInstance playerinstance = this.a(l, i1, false); + + if (playerinstance != null) { + playerinstance.a(i & 15, j, k & 15); + } + } + + public void addPlayer(EntityPlayer entityplayer) { + int i = (int) entityplayer.locX >> 4; + int j = (int) entityplayer.locZ >> 4; + + entityplayer.d = entityplayer.locX; + entityplayer.e = entityplayer.locZ; + int k = 0; + int l = this.f; + int i1 = 0; + int j1 = 0; + + this.a(i, j, true).a(entityplayer); + + int k1; + + for (k1 = 1; k1 <= l * 2; ++k1) { + for (int l1 = 0; l1 < 2; ++l1) { + int[] aint = this.g[k++ % 4]; + + for (int i2 = 0; i2 < k1; ++i2) { + i1 += aint[0]; + j1 += aint[1]; + this.a(i + i1, j + j1, true).a(entityplayer); + } + } + } + + k %= 4; + + for (k1 = 0; k1 < l * 2; ++k1) { + i1 += this.g[k][0]; + j1 += this.g[k][1]; + this.a(i + i1, j + j1, true).a(entityplayer); + } + + this.managedPlayers.add(entityplayer); + } + + public void removePlayer(EntityPlayer entityplayer) { + int i = (int) entityplayer.d >> 4; + int j = (int) entityplayer.e >> 4; + + for (int k = i - this.f; k <= i + this.f; ++k) { + for (int l = j - this.f; l <= j + this.f; ++l) { + PlayerInstance playerinstance = this.a(k, l, false); + + if (playerinstance != null) { + playerinstance.b(entityplayer); + } + } + } + + this.managedPlayers.remove(entityplayer); + } + + private boolean a(int i, int j, int k, int l) { + int i1 = i - k; + int j1 = j - l; + + return i1 >= -this.f && i1 <= this.f ? j1 >= -this.f && j1 <= this.f : false; + } + + public void movePlayer(EntityPlayer entityplayer) { + int i = (int) entityplayer.locX >> 4; + int j = (int) entityplayer.locZ >> 4; + double d0 = entityplayer.d - entityplayer.locX; + double d1 = entityplayer.e - entityplayer.locZ; + double d2 = d0 * d0 + d1 * d1; + + if (d2 >= 64.0D) { + int k = (int) entityplayer.d >> 4; + int l = (int) entityplayer.e >> 4; + int i1 = i - k; + int j1 = j - l; + + if (i1 != 0 || j1 != 0) { + for (int k1 = i - this.f; k1 <= i + this.f; ++k1) { + for (int l1 = j - this.f; l1 <= j + this.f; ++l1) { + if (!this.a(k1, l1, k, l)) { + this.a(k1, l1, true).a(entityplayer); + } + + if (!this.a(k1 - i1, l1 - j1, i, j)) { + PlayerInstance playerinstance = this.a(k1 - i1, l1 - j1, false); + + if (playerinstance != null) { + playerinstance.b(entityplayer); + } + } + } + } + + entityplayer.d = entityplayer.locX; + entityplayer.e = entityplayer.locZ; + + // CraftBukkit start - send nearest chunks first + if (i1 > 1 || i1 < -1 || j1 > 1 || j1 < -1) { + final int x = i; + final int z = j; + List chunksToSend = entityplayer.chunkCoordIntPairQueue; + + java.util.Collections.sort(chunksToSend, new java.util.Comparator() { + public int compare(ChunkCoordIntPair a, ChunkCoordIntPair b) { + return Math.max(Math.abs(a.x - x), Math.abs(a.z - z)) - Math.max(Math.abs(b.x - x), Math.abs(b.z - z)); + } + }); + } + // CraftBukkit end + } + } + } + + // Poseidon + public boolean a(EntityPlayer entityplayer, int i, int j) { + PlayerInstance playerchunk = this.a(i, j, false); + + return playerchunk == null ? false : PlayerInstance.b(playerchunk).contains(entityplayer) && !entityplayer.chunkCoordIntPairQueue.contains(PlayerInstance.a(playerchunk)); + } + + public int getFurthestViewableBlock() { + return this.f * 16 - 16; + } + + static PlayerList a(PlayerManager playermanager) { + return playermanager.b; + } + + static List b(PlayerManager playermanager) { + return playermanager.c; + } +} diff --git a/src/main/java/net/minecraft/server/PlayerNBTManager.java b/src/main/java/net/minecraft/server/PlayerNBTManager.java new file mode 100644 index 0000000..e432907 --- /dev/null +++ b/src/main/java/net/minecraft/server/PlayerNBTManager.java @@ -0,0 +1,308 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.projectposeidon.johnymuffin.UUIDManager; + +import java.io.*; +import java.util.List; +import java.util.UUID; +import java.util.logging.Logger; + +public class PlayerNBTManager implements PlayerFileData, IDataManager { + + private static final Logger a = Logger.getLogger("Minecraft"); + private final File b; + private final File c; + private final File d; + private final long e = System.currentTimeMillis(); + private UUID uuid = null; // CraftBukkit + + public PlayerNBTManager(File file1, String s, boolean flag) { + this.b = new File(file1, s); + this.b.mkdirs(); + this.c = new File(this.b, "players"); + this.d = new File(this.b, "data"); + this.d.mkdirs(); + if (flag) { + this.c.mkdirs(); + } + + this.f(); + } + + private void f() { + try { + File file1 = new File(this.b, "session.lock"); + DataOutputStream dataoutputstream = new DataOutputStream(new FileOutputStream(file1)); + + try { + dataoutputstream.writeLong(this.e); + } finally { + dataoutputstream.close(); + } + } catch (IOException ioexception) { + ioexception.printStackTrace(); + throw new RuntimeException("Failed to check session lock, aborting"); + } + } + + protected File a() { + return this.b; + } + + public void b() { + try { + File file1 = new File(this.b, "session.lock"); + DataInputStream datainputstream = new DataInputStream(new FileInputStream(file1)); + + try { + if (datainputstream.readLong() != this.e) { + throw new MinecraftException("The save is being accessed from another location, aborting"); + } + } finally { + datainputstream.close(); + } + } catch (IOException ioexception) { + throw new MinecraftException("Failed to check session lock, aborting"); + } + } + + public IChunkLoader a(WorldProvider worldprovider) { + if (worldprovider instanceof WorldProviderHell) { + File file1 = new File(this.b, "DIM-1"); + + file1.mkdirs(); + return new ChunkLoader(file1, true); + } else { + return new ChunkLoader(this.b, true); + } + } + + public WorldData c() { + File file1 = new File(this.b, "level.dat"); + NBTTagCompound nbttagcompound; + NBTTagCompound nbttagcompound1; + + if (file1.exists()) { + try { + nbttagcompound = CompressedStreamTools.a((InputStream) (new FileInputStream(file1))); + nbttagcompound1 = nbttagcompound.k("Data"); + return new WorldData(nbttagcompound1); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + file1 = new File(this.b, "level.dat_old"); + if (file1.exists()) { + try { + nbttagcompound = CompressedStreamTools.a((InputStream) (new FileInputStream(file1))); + nbttagcompound1 = nbttagcompound.k("Data"); + return new WorldData(nbttagcompound1); + } catch (Exception exception1) { + exception1.printStackTrace(); + } + } + + return null; + } + + public void a(WorldData worlddata, List list) { + NBTTagCompound nbttagcompound = worlddata.a(list); + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.a("Data", (NBTBase) nbttagcompound); + + try { + File file1 = new File(this.b, "level.dat_new"); + File file2 = new File(this.b, "level.dat_old"); + File file3 = new File(this.b, "level.dat"); + + CompressedStreamTools.a(nbttagcompound1, (OutputStream) (new FileOutputStream(file1))); + if (file2.exists()) { + file2.delete(); + } + + file3.renameTo(file2); + if (file3.exists()) { + file3.delete(); + } + + file1.renameTo(file3); + if (file1.exists()) { + file1.delete(); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public void a(WorldData worlddata) { + NBTTagCompound nbttagcompound = worlddata.a(); + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.a("Data", (NBTBase) nbttagcompound); + + try { + File file1 = new File(this.b, "level.dat_new"); + File file2 = new File(this.b, "level.dat_old"); + File file3 = new File(this.b, "level.dat"); + + CompressedStreamTools.a(nbttagcompound1, (OutputStream) (new FileOutputStream(file1))); + if (file2.exists()) { + file2.delete(); + } + + file3.renameTo(file2); + if (file3.exists()) { + file3.delete(); + } + + file1.renameTo(file3); + if (file1.exists()) { + file1.delete(); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public void a(EntityHuman entityhuman) { + if ((boolean) PoseidonConfig.getInstance().getConfigOption("settings.save-playerdata-by-uuid")) { + try { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + + entityhuman.d(nbttagcompound); + File file1 = new File(this.c, "_tmp_.dat"); + //File file2 = new File(this.c, entityhuman.name + ".dat"); + //UUIDPlayerStorage.getInstance().getUUIDGraceful(entityhuman.name) + File file2 = new File(this.c, UUIDManager.getInstance().getUUIDGraceful(entityhuman.name) + ".dat"); + CompressedStreamTools.a(nbttagcompound, (OutputStream) (new FileOutputStream(file1))); + if (file2.exists()) { + file2.delete(); + } + + file1.renameTo(file2); + } catch (Exception exception) { + a.warning("Failed to save player data for " + entityhuman.name); + } + } else { + try { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + + entityhuman.d(nbttagcompound); + File file1 = new File(this.c, "_tmp_.dat"); + File file2 = new File(this.c, entityhuman.name + ".dat"); + + CompressedStreamTools.a(nbttagcompound, (OutputStream) (new FileOutputStream(file1))); + if (file2.exists()) { + file2.delete(); + } + + file1.renameTo(file2); + } catch (Exception exception) { + a.warning("Failed to save player data for " + entityhuman.name); + } + } + } + + public void b(EntityHuman entityhuman) { + NBTTagCompound nbttagcompound = this.a(entityhuman.name); + + if (nbttagcompound != null) { + entityhuman.e(nbttagcompound); + } + } + + //Credit https://www.journaldev.com/861/java-copy-file + private static void copyFileUsingStream(File source, File dest) throws IOException { + InputStream is = null; + OutputStream os = null; + try { + is = new FileInputStream(source); + os = new FileOutputStream(dest); + byte[] buffer = new byte[1024]; + int length; + while ((length = is.read(buffer)) > 0) { + os.write(buffer, 0, length); + } + } finally { + is.close(); + os.close(); + } + } + + public NBTTagCompound a(String s) { + if ((boolean) PoseidonConfig.getInstance().getConfigOption("settings.save-playerdata-by-uuid")) { + try { + File file1 = new File(this.c, UUIDManager.getInstance().getUUIDGraceful(s) + ".dat"); + File file2 = new File(this.c, s + ".dat"); + if (!file1.exists()) { + if (file2.exists()) { + //Convert player data + copyFileUsingStream(file2, file1); + File file3 = new File(this.c, s + ".datbackup"); + file2.renameTo(file3); + System.out.println("Converting playerdata for " + s + " to a UUID"); + } + } + + + if (file1.exists()) { + return CompressedStreamTools.a((InputStream) (new FileInputStream(file1))); + } + } catch (Exception exception) { + a.warning("Failed to load player data for " + s); + } + + return null; + } else { + try { + File file1 = new File(this.c, s + ".dat"); + + if (file1.exists()) { + return CompressedStreamTools.a((InputStream) (new FileInputStream(file1))); + } + } catch (Exception exception) { + a.warning("Failed to load player data for " + s); + } + + return null; + } + + } + + public PlayerFileData d() { + return this; + } + + public void e() { + } + + public File b(String s) { + return new File(this.d, s + ".dat"); + } + + // CraftBukkit start + public UUID getUUID() { + if (uuid != null) return uuid; + try { + File file1 = new File(this.b, "uid.dat"); + if (!file1.exists()) { + DataOutputStream dos = new DataOutputStream(new FileOutputStream(file1)); + uuid = UUID.randomUUID(); + dos.writeLong(uuid.getMostSignificantBits()); + dos.writeLong(uuid.getLeastSignificantBits()); + dos.close(); + } else { + DataInputStream dis = new DataInputStream(new FileInputStream(file1)); + uuid = new UUID(dis.readLong(), dis.readLong()); + dis.close(); + } + return uuid; + } catch (IOException ex) { + return null; + } + } + // CraftBukkit end +} diff --git a/src/main/java/net/minecraft/server/PortalTravelAgent.java b/src/main/java/net/minecraft/server/PortalTravelAgent.java new file mode 100644 index 0000000..0a2823d --- /dev/null +++ b/src/main/java/net/minecraft/server/PortalTravelAgent.java @@ -0,0 +1,325 @@ +package net.minecraft.server; + +import org.bukkit.Bukkit; +import org.bukkit.event.world.PortalCreateEvent; + +import java.util.Random; + +// CraftBukkit start +// CraftBukkit end + +public class PortalTravelAgent { + + private Random a = new Random(); + + public PortalTravelAgent() {} + + public void a(World world, Entity entity) { + if (!this.b(world, entity)) { + this.c(world, entity); + this.b(world, entity); + } + } + + public boolean b(World world, Entity entity) { + short short1 = 128; + double d0 = -1.0D; + int i = 0; + int j = 0; + int k = 0; + int l = MathHelper.floor(entity.locX); + int i1 = MathHelper.floor(entity.locZ); + + double d1; + + for (int j1 = l - short1; j1 <= l + short1; ++j1) { + double d2 = (double) j1 + 0.5D - entity.locX; + + for (int k1 = i1 - short1; k1 <= i1 + short1; ++k1) { + double d3 = (double) k1 + 0.5D - entity.locZ; + + for (int l1 = 127; l1 >= 0; --l1) { + if (world.getTypeId(j1, l1, k1) == Block.PORTAL.id) { + while (world.getTypeId(j1, l1 - 1, k1) == Block.PORTAL.id) { + --l1; + } + + d1 = (double) l1 + 0.5D - entity.locY; + double d4 = d2 * d2 + d1 * d1 + d3 * d3; + + if (d0 < 0.0D || d4 < d0) { + d0 = d4; + i = j1; + j = l1; + k = k1; + } + } + } + } + } + + if (d0 >= 0.0D) { + double d5 = (double) i + 0.5D; + double d6 = (double) j + 0.5D; + + d1 = (double) k + 0.5D; + if (world.getTypeId(i - 1, j, k) == Block.PORTAL.id) { + d5 -= 0.5D; + } + + if (world.getTypeId(i + 1, j, k) == Block.PORTAL.id) { + d5 += 0.5D; + } + + if (world.getTypeId(i, j, k - 1) == Block.PORTAL.id) { + d1 -= 0.5D; + } + + if (world.getTypeId(i, j, k + 1) == Block.PORTAL.id) { + d1 += 0.5D; + } + + entity.setPositionRotation(d5, d6, d1, entity.yaw, 0.0F); + entity.motX = entity.motY = entity.motZ = 0.0D; + return true; + } else { + return false; + } + } + + public boolean c(World world, Entity entity) { + byte b0 = 16; + double d0 = -1.0D; + int i = MathHelper.floor(entity.locX); + int j = MathHelper.floor(entity.locY); + int k = MathHelper.floor(entity.locZ); + int l = i; + int i1 = j; + int j1 = k; + int k1 = 0; + int l1 = this.a.nextInt(4); + + int i2; + double d1; + int j2; + double d2; + int k2; + int l2; + int i3; + int j3; + int k3; + int l3; + int i4; + int j4; + int k4; + double d3; + double d4; + + for (i2 = i - b0; i2 <= i + b0; ++i2) { + d1 = (double) i2 + 0.5D - entity.locX; + + for (j2 = k - b0; j2 <= k + b0; ++j2) { + d2 = (double) j2 + 0.5D - entity.locZ; + + label271: + for (l2 = 127; l2 >= 0; --l2) { + if (world.isEmpty(i2, l2, j2)) { + while (l2 > 0 && world.isEmpty(i2, l2 - 1, j2)) { + --l2; + } + + for (k2 = l1; k2 < l1 + 4; ++k2) { + j3 = k2 % 2; + i3 = 1 - j3; + if (k2 % 4 >= 2) { + j3 = -j3; + i3 = -i3; + } + + for (l3 = 0; l3 < 3; ++l3) { + for (k3 = 0; k3 < 4; ++k3) { + for (j4 = -1; j4 < 4; ++j4) { + i4 = i2 + (k3 - 1) * j3 + l3 * i3; + k4 = l2 + j4; + int l4 = j2 + (k3 - 1) * i3 - l3 * j3; + + if (j4 < 0 && !world.getMaterial(i4, k4, l4).isBuildable() || j4 >= 0 && !world.isEmpty(i4, k4, l4)) { + continue label271; + } + } + } + } + + d3 = (double) l2 + 0.5D - entity.locY; + d4 = d1 * d1 + d3 * d3 + d2 * d2; + if (d0 < 0.0D || d4 < d0) { + d0 = d4; + l = i2; + i1 = l2; + j1 = j2; + k1 = k2 % 4; + } + } + } + } + } + } + + if (d0 < 0.0D) { + for (i2 = i - b0; i2 <= i + b0; ++i2) { + d1 = (double) i2 + 0.5D - entity.locX; + + for (j2 = k - b0; j2 <= k + b0; ++j2) { + d2 = (double) j2 + 0.5D - entity.locZ; + + label219: + for (l2 = 127; l2 >= 0; --l2) { + if (world.isEmpty(i2, l2, j2)) { + while (world.isEmpty(i2, l2 - 1, j2)) { + --l2; + } + + for (k2 = l1; k2 < l1 + 2; ++k2) { + j3 = k2 % 2; + i3 = 1 - j3; + + for (l3 = 0; l3 < 4; ++l3) { + for (k3 = -1; k3 < 4; ++k3) { + j4 = i2 + (l3 - 1) * j3; + i4 = l2 + k3; + k4 = j2 + (l3 - 1) * i3; + if (k3 < 0 && !world.getMaterial(j4, i4, k4).isBuildable() || k3 >= 0 && !world.isEmpty(j4, i4, k4)) { + continue label219; + } + } + } + + d3 = (double) l2 + 0.5D - entity.locY; + d4 = d1 * d1 + d3 * d3 + d2 * d2; + if (d0 < 0.0D || d4 < d0) { + d0 = d4; + l = i2; + i1 = l2; + j1 = j2; + k1 = k2 % 2; + } + } + } + } + } + } + } + + int i5 = l; + int j5 = i1; + + j2 = j1; + int k5 = k1 % 2; + int l5 = 1 - k5; + + if (k1 % 4 >= 2) { + k5 = -k5; + l5 = -l5; + } + + boolean flag; + + // CraftBukkit start - portal create event + java.util.Collection blocks = new java.util.HashSet(); + // Find out what blocks the portal is going to modify, duplicated from below + org.bukkit.World bworld = world.getWorld(); + + if (d0 < 0.0D) { + if (i1 < 70) { + i1 = 70; + } + + if (i1 > 118) { + i1 = 118; + } + + j5 = i1; + + for (l2 = -1; l2 <= 1; ++l2) { + for (k2 = 1; k2 < 3; ++k2) { + for (j3 = -1; j3 < 3; ++j3) { + i3 = i5 + (k2 - 1) * k5 + l2 * l5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5 - l2 * k5; + blocks.add(bworld.getBlockAt(i3, l3, k3)); + } + } + } + } + + for (l2 = 0; l2 < 4; ++l2) { + for (k2 = 0; k2 < 4; ++k2) { + for (j3 = -1; j3 < 4; ++j3) { + i3 = i5 + (k2 - 1) * k5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5; + blocks.add(bworld.getBlockAt(i3, l3, k3)); + } + } + } + + PortalCreateEvent event = new PortalCreateEvent(blocks, bworld); + Bukkit.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return true; + } + // CraftBukkit end + + if (d0 < 0.0D) { + if (i1 < 70) { + i1 = 70; + } + + if (i1 > 118) { + i1 = 118; + } + + j5 = i1; + + for (l2 = -1; l2 <= 1; ++l2) { + for (k2 = 1; k2 < 3; ++k2) { + for (j3 = -1; j3 < 3; ++j3) { + i3 = i5 + (k2 - 1) * k5 + l2 * l5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5 - l2 * k5; + flag = j3 < 0; + world.setTypeId(i3, l3, k3, flag ? Block.OBSIDIAN.id : 0); + } + } + } + } + + for (l2 = 0; l2 < 4; ++l2) { + world.suppressPhysics = true; + + for (k2 = 0; k2 < 4; ++k2) { + for (j3 = -1; j3 < 4; ++j3) { + i3 = i5 + (k2 - 1) * k5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5; + flag = k2 == 0 || k2 == 3 || j3 == -1 || j3 == 3; + world.setTypeId(i3, l3, k3, flag ? Block.OBSIDIAN.id : Block.PORTAL.id); + } + } + + world.suppressPhysics = false; + + for (k2 = 0; k2 < 4; ++k2) { + for (j3 = -1; j3 < 4; ++j3) { + i3 = i5 + (k2 - 1) * k5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5; + world.applyPhysics(i3, l3, k3, world.getTypeId(i3, l3, k3)); + } + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/PropertyManager.java b/src/main/java/net/minecraft/server/PropertyManager.java new file mode 100644 index 0000000..6a186b5 --- /dev/null +++ b/src/main/java/net/minecraft/server/PropertyManager.java @@ -0,0 +1,98 @@ +package net.minecraft.server; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class PropertyManager { + + public static Logger a = Logger.getLogger("Minecraft"); + public Properties properties = new Properties(); // CraftBukkit - priv to pub + private File c; + + public PropertyManager(File file1) { + this.c = file1; + if (file1.exists()) { + try { + this.properties.load(new FileInputStream(file1)); + } catch (Exception exception) { + a.log(Level.WARNING, "Failed to load " + file1, exception); + this.a(); + } + } else { + a.log(Level.WARNING, file1 + " does not exist"); + this.a(); + } + } + + // CraftBukkit start + private joptsimple.OptionSet options = null; + + public PropertyManager(final joptsimple.OptionSet options) { + this((File) options.valueOf("config")); + + this.options = options; + } + + private T getOverride(String name, T value) { + if ((this.options != null) && (this.options.has(name))) { + return (T) this.options.valueOf(name); + } + + return value; + } + // CraftBukkit end + + public void a() { + a.log(Level.INFO, "Generating new properties file"); + this.savePropertiesFile(); + } + + public void savePropertiesFile() { + try { + this.properties.store(new FileOutputStream(this.c), "Minecraft server properties"); + } catch (Exception exception) { + a.log(Level.WARNING, "Failed to save " + this.c, exception); + this.a(); + } + } + + public String getString(String s, String s1) { + if (!this.properties.containsKey(s)) { + s1 = this.getOverride(s, s1); // CraftBukkit + this.properties.setProperty(s, s1); + this.savePropertiesFile(); + } + + return this.getOverride(s, this.properties.getProperty(s, s1)); // CraftBukkit + } + + public int getInt(String s, int i) { + try { + return this.getOverride(s, Integer.parseInt(this.getString(s, "" + i))); // CraftBukkit + } catch (Exception exception) { + i = this.getOverride(s, i); // CraftBukkit + this.properties.setProperty(s, "" + i); + return i; + } + } + + public boolean getBoolean(String s, boolean flag) { + try { + return this.getOverride(s, Boolean.parseBoolean(this.getString(s, "" + flag))); // CraftBukkit + } catch (Exception exception) { + flag = this.getOverride(s, flag); // CraftBukkit + this.properties.setProperty(s, "" + flag); + return flag; + } + } + + public void b(String s, boolean flag) { + flag = this.getOverride(s, flag); // CraftBukkit + this.properties.setProperty(s, "" + flag); + this.savePropertiesFile(); + } +} diff --git a/src/main/java/net/minecraft/server/RecipeIngots.java b/src/main/java/net/minecraft/server/RecipeIngots.java new file mode 100644 index 0000000..20076a0 --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipeIngots.java @@ -0,0 +1,20 @@ +package net.minecraft.server; + +public class RecipeIngots { + + private Object[][] a; + + public RecipeIngots() { + this.a = new Object[][] { { Block.GOLD_BLOCK, new ItemStack(Item.GOLD_INGOT, 9)}, { Block.IRON_BLOCK, new ItemStack(Item.IRON_INGOT, 9)}, { Block.DIAMOND_BLOCK, new ItemStack(Item.DIAMOND, 9)}, { Block.LAPIS_BLOCK, new ItemStack(Item.INK_SACK, 9, 4)}}; + } + + public void a(CraftingManager craftingmanager) { + for (int i = 0; i < this.a.length; ++i) { + Block block = (Block) this.a[i][0]; + ItemStack itemstack = (ItemStack) this.a[i][1]; + + craftingmanager.registerShapedRecipe(new ItemStack(block), new Object[] { "###", "###", "###", Character.valueOf('#'), itemstack}); + craftingmanager.registerShapedRecipe(itemstack, new Object[] { "#", Character.valueOf('#'), block}); + } + } +} diff --git a/src/main/java/net/minecraft/server/RecipeSorter.java b/src/main/java/net/minecraft/server/RecipeSorter.java new file mode 100644 index 0000000..0e73c0d --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipeSorter.java @@ -0,0 +1,17 @@ +package net.minecraft.server; + +import java.util.Comparator; + +class RecipeSorter implements Comparator { + + final CraftingManager a; + + RecipeSorter(CraftingManager craftingmanager) { + this.a = craftingmanager; + } + + public int compare(Object o1, Object o2) { + CraftingRecipe craftingrecipe = (CraftingRecipe) o1, craftingrecipe1 = (CraftingRecipe) o2; + return craftingrecipe instanceof ShapelessRecipes && craftingrecipe1 instanceof ShapedRecipes ? 1 : (craftingrecipe1 instanceof ShapelessRecipes && craftingrecipe instanceof ShapedRecipes ? -1 : (craftingrecipe1.a() < craftingrecipe.a() ? -1 : (craftingrecipe1.a() > craftingrecipe.a() ? 1 : 0))); + } +} diff --git a/src/main/java/net/minecraft/server/RecipesArmor.java b/src/main/java/net/minecraft/server/RecipesArmor.java new file mode 100644 index 0000000..805a533 --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipesArmor.java @@ -0,0 +1,23 @@ +package net.minecraft.server; + +public class RecipesArmor { + + private String[][] a = new String[][] { { "XXX", "X X"}, { "X X", "XXX", "XXX"}, { "XXX", "X X", "X X"}, { "X X", "X X"}}; + private Object[][] b; + + public RecipesArmor() { + this.b = new Object[][] { { Item.LEATHER, Block.FIRE, Item.IRON_INGOT, Item.DIAMOND, Item.GOLD_INGOT}, { Item.LEATHER_HELMET, Item.CHAINMAIL_HELMET, Item.IRON_HELMET, Item.DIAMOND_HELMET, Item.GOLD_HELMET}, { Item.LEATHER_CHESTPLATE, Item.CHAINMAIL_CHESTPLATE, Item.IRON_CHESTPLATE, Item.DIAMOND_CHESTPLATE, Item.GOLD_CHESTPLATE}, { Item.LEATHER_LEGGINGS, Item.CHAINMAIL_LEGGINGS, Item.IRON_LEGGINGS, Item.DIAMOND_LEGGINGS, Item.GOLD_LEGGINGS}, { Item.LEATHER_BOOTS, Item.CHAINMAIL_BOOTS, Item.IRON_BOOTS, Item.DIAMOND_BOOTS, Item.GOLD_BOOTS}}; + } + + public void a(CraftingManager craftingmanager) { + for (int i = 0; i < this.b[0].length; ++i) { + Object object = this.b[0][i]; + + for (int j = 0; j < this.b.length - 1; ++j) { + Item item = (Item) this.b[j + 1][i]; + + craftingmanager.registerShapedRecipe(new ItemStack(item), new Object[] { this.a[j], Character.valueOf('X'), object}); + } + } + } +} diff --git a/src/main/java/net/minecraft/server/RecipesCrafting.java b/src/main/java/net/minecraft/server/RecipesCrafting.java new file mode 100644 index 0000000..b4bbb78 --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipesCrafting.java @@ -0,0 +1,13 @@ +package net.minecraft.server; + +public class RecipesCrafting { + + public RecipesCrafting() {} + + public void a(CraftingManager craftingmanager) { + craftingmanager.registerShapedRecipe(new ItemStack(Block.CHEST), new Object[] { "###", "# #", "###", Character.valueOf('#'), Block.WOOD}); + craftingmanager.registerShapedRecipe(new ItemStack(Block.FURNACE), new Object[] { "###", "# #", "###", Character.valueOf('#'), Block.COBBLESTONE}); + craftingmanager.registerShapedRecipe(new ItemStack(Block.WORKBENCH), new Object[] { "##", "##", Character.valueOf('#'), Block.WOOD}); + craftingmanager.registerShapedRecipe(new ItemStack(Block.SANDSTONE), new Object[] { "##", "##", Character.valueOf('#'), Block.SAND}); + } +} diff --git a/src/main/java/net/minecraft/server/RecipesDyes.java b/src/main/java/net/minecraft/server/RecipesDyes.java new file mode 100644 index 0000000..16105ae --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipesDyes.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +public class RecipesDyes { + + public RecipesDyes() {} + + public void a(CraftingManager craftingmanager) { + for (int i = 0; i < 16; ++i) { + craftingmanager.registerShapelessRecipe(new ItemStack(Block.WOOL, 1, BlockCloth.d(i)), new Object[] { new ItemStack(Item.INK_SACK, 1, i), new ItemStack(Item.byId[Block.WOOL.id], 1, 0)}); + } + + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 11), new Object[] { Block.YELLOW_FLOWER}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 1), new Object[] { Block.RED_ROSE}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 3, 15), new Object[] { Item.BONE}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 9), new Object[] { new ItemStack(Item.INK_SACK, 1, 1), new ItemStack(Item.INK_SACK, 1, 15)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 14), new Object[] { new ItemStack(Item.INK_SACK, 1, 1), new ItemStack(Item.INK_SACK, 1, 11)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 10), new Object[] { new ItemStack(Item.INK_SACK, 1, 2), new ItemStack(Item.INK_SACK, 1, 15)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 8), new Object[] { new ItemStack(Item.INK_SACK, 1, 0), new ItemStack(Item.INK_SACK, 1, 15)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 7), new Object[] { new ItemStack(Item.INK_SACK, 1, 8), new ItemStack(Item.INK_SACK, 1, 15)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 3, 7), new Object[] { new ItemStack(Item.INK_SACK, 1, 0), new ItemStack(Item.INK_SACK, 1, 15), new ItemStack(Item.INK_SACK, 1, 15)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 12), new Object[] { new ItemStack(Item.INK_SACK, 1, 4), new ItemStack(Item.INK_SACK, 1, 15)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 6), new Object[] { new ItemStack(Item.INK_SACK, 1, 4), new ItemStack(Item.INK_SACK, 1, 2)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 5), new Object[] { new ItemStack(Item.INK_SACK, 1, 4), new ItemStack(Item.INK_SACK, 1, 1)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 2, 13), new Object[] { new ItemStack(Item.INK_SACK, 1, 5), new ItemStack(Item.INK_SACK, 1, 9)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 3, 13), new Object[] { new ItemStack(Item.INK_SACK, 1, 4), new ItemStack(Item.INK_SACK, 1, 1), new ItemStack(Item.INK_SACK, 1, 9)}); + craftingmanager.registerShapelessRecipe(new ItemStack(Item.INK_SACK, 4, 13), new Object[] { new ItemStack(Item.INK_SACK, 1, 4), new ItemStack(Item.INK_SACK, 1, 1), new ItemStack(Item.INK_SACK, 1, 1), new ItemStack(Item.INK_SACK, 1, 15)}); + } +} diff --git a/src/main/java/net/minecraft/server/RecipesFood.java b/src/main/java/net/minecraft/server/RecipesFood.java new file mode 100644 index 0000000..428b89e --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipesFood.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +public class RecipesFood { + + public RecipesFood() {} + + public void a(CraftingManager craftingmanager) { + craftingmanager.registerShapedRecipe(new ItemStack(Item.MUSHROOM_SOUP), new Object[] { "Y", "X", "#", Character.valueOf('X'), Block.BROWN_MUSHROOM, Character.valueOf('Y'), Block.RED_MUSHROOM, Character.valueOf('#'), Item.BOWL}); + craftingmanager.registerShapedRecipe(new ItemStack(Item.MUSHROOM_SOUP), new Object[] { "Y", "X", "#", Character.valueOf('X'), Block.RED_MUSHROOM, Character.valueOf('Y'), Block.BROWN_MUSHROOM, Character.valueOf('#'), Item.BOWL}); + craftingmanager.registerShapedRecipe(new ItemStack(Item.COOKIE, 8), new Object[] { "#X#", Character.valueOf('X'), new ItemStack(Item.INK_SACK, 1, 3), Character.valueOf('#'), Item.WHEAT}); + } +} diff --git a/src/main/java/net/minecraft/server/RecipesTools.java b/src/main/java/net/minecraft/server/RecipesTools.java new file mode 100644 index 0000000..27fcd58 --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipesTools.java @@ -0,0 +1,25 @@ +package net.minecraft.server; + +public class RecipesTools { + + private String[][] a = new String[][] { { "XXX", " # ", " # "}, { "X", "#", "#"}, { "XX", "X#", " #"}, { "XX", " #", " #"}}; + private Object[][] b; + + public RecipesTools() { + this.b = new Object[][] { { Block.WOOD, Block.COBBLESTONE, Item.IRON_INGOT, Item.DIAMOND, Item.GOLD_INGOT}, { Item.WOOD_PICKAXE, Item.STONE_PICKAXE, Item.IRON_PICKAXE, Item.DIAMOND_PICKAXE, Item.GOLD_PICKAXE}, { Item.WOOD_SPADE, Item.STONE_SPADE, Item.IRON_SPADE, Item.DIAMOND_SPADE, Item.GOLD_SPADE}, { Item.WOOD_AXE, Item.STONE_AXE, Item.IRON_AXE, Item.DIAMOND_AXE, Item.GOLD_AXE}, { Item.WOOD_HOE, Item.STONE_HOE, Item.IRON_HOE, Item.DIAMOND_HOE, Item.GOLD_HOE}}; + } + + public void a(CraftingManager craftingmanager) { + for (int i = 0; i < this.b[0].length; ++i) { + Object object = this.b[0][i]; + + for (int j = 0; j < this.b.length - 1; ++j) { + Item item = (Item) this.b[j + 1][i]; + + craftingmanager.registerShapedRecipe(new ItemStack(item), new Object[] { this.a[j], Character.valueOf('#'), Item.STICK, Character.valueOf('X'), object}); + } + } + + craftingmanager.registerShapedRecipe(new ItemStack(Item.SHEARS), new Object[] { " #", "# ", Character.valueOf('#'), Item.IRON_INGOT}); + } +} diff --git a/src/main/java/net/minecraft/server/RecipesWeapons.java b/src/main/java/net/minecraft/server/RecipesWeapons.java new file mode 100644 index 0000000..6c6ed56 --- /dev/null +++ b/src/main/java/net/minecraft/server/RecipesWeapons.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +public class RecipesWeapons { + + private String[][] a = new String[][] { { "X", "X", "#"}}; + private Object[][] b; + + public RecipesWeapons() { + this.b = new Object[][] { { Block.WOOD, Block.COBBLESTONE, Item.IRON_INGOT, Item.DIAMOND, Item.GOLD_INGOT}, { Item.WOOD_SWORD, Item.STONE_SWORD, Item.IRON_SWORD, Item.DIAMOND_SWORD, Item.GOLD_SWORD}}; + } + + public void a(CraftingManager craftingmanager) { + for (int i = 0; i < this.b[0].length; ++i) { + Object object = this.b[0][i]; + + for (int j = 0; j < this.b.length - 1; ++j) { + Item item = (Item) this.b[j + 1][i]; + + craftingmanager.registerShapedRecipe(new ItemStack(item), new Object[] { this.a[j], Character.valueOf('#'), Item.STICK, Character.valueOf('X'), object}); + } + } + + craftingmanager.registerShapedRecipe(new ItemStack(Item.BOW, 1), new Object[] { " #X", "# X", " #X", Character.valueOf('X'), Item.STRING, Character.valueOf('#'), Item.STICK}); + craftingmanager.registerShapedRecipe(new ItemStack(Item.ARROW, 4), new Object[] { "X", "#", "Y", Character.valueOf('Y'), Item.FEATHER, Character.valueOf('X'), Item.FLINT, Character.valueOf('#'), Item.STICK}); + } +} diff --git a/src/main/java/net/minecraft/server/RedstoneUpdateInfo.java b/src/main/java/net/minecraft/server/RedstoneUpdateInfo.java new file mode 100644 index 0000000..1fbe56a --- /dev/null +++ b/src/main/java/net/minecraft/server/RedstoneUpdateInfo.java @@ -0,0 +1,16 @@ +package net.minecraft.server; + +class RedstoneUpdateInfo { + + int a; + int b; + int c; + long d; + + public RedstoneUpdateInfo(int i, int j, int k, long l) { + this.a = i; + this.b = j; + this.c = k; + this.d = l; + } +} diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java new file mode 100644 index 0000000..53795ec --- /dev/null +++ b/src/main/java/net/minecraft/server/RegionFile.java @@ -0,0 +1,278 @@ +package net.minecraft.server; + +import java.io.*; +import java.util.ArrayList; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; + +public class RegionFile { + + private static final byte[] a = new byte[4096]; + private final File b; + private RandomAccessFile c; + private final int[] d = new int[1024]; + private final int[] e = new int[1024]; + private ArrayList f; + private int g; + private long h = 0L; + + public RegionFile(File file1) { + this.b = file1; + this.b("REGION LOAD " + this.b); + this.g = 0; + + try { + if (file1.exists()) { + this.h = file1.lastModified(); + } + + this.c = new RandomAccessFile(file1, "rw"); + int i; + + if (this.c.length() < 4096L) { + for (i = 0; i < 1024; ++i) { + this.c.writeInt(0); + } + + for (i = 0; i < 1024; ++i) { + this.c.writeInt(0); + } + + this.g += 8192; + } + + if ((this.c.length() & 4095L) != 0L) { + for (i = 0; (long) i < (this.c.length() & 4095L); ++i) { + this.c.write(0); + } + } + + i = (int) this.c.length() / 4096; + this.f = new ArrayList(i); + + int j; + + for (j = 0; j < i; ++j) { + this.f.add(Boolean.valueOf(true)); + } + + this.f.set(0, Boolean.valueOf(false)); + this.f.set(1, Boolean.valueOf(false)); + this.c.seek(0L); + + int k; + + for (j = 0; j < 1024; ++j) { + k = this.c.readInt(); + this.d[j] = k; + if (k != 0 && (k >> 8) + (k & 255) <= this.f.size()) { + for (int l = 0; l < (k & 255); ++l) { + this.f.set((k >> 8) + l, Boolean.valueOf(false)); + } + } + } + + for (j = 0; j < 1024; ++j) { + k = this.c.readInt(); + this.e[j] = k; + } + } catch (IOException ioexception) { + ioexception.printStackTrace(); + } + } + + public synchronized int a() { + int i = this.g; + + this.g = 0; + return i; + } + + private void a(String s) {} + + private void b(String s) { + this.a(s + "\n"); + } + + private void a(String s, int i, int j, String s1) { + this.a("REGION " + s + " " + this.b.getName() + "[" + i + "," + j + "] = " + s1); + } + + private void a(String s, int i, int j, int k, String s1) { + this.a("REGION " + s + " " + this.b.getName() + "[" + i + "," + j + "] " + k + "B = " + s1); + } + + private void b(String s, int i, int j, String s1) { + this.a(s, i, j, s1 + "\n"); + } + + public synchronized DataInputStream a(int i, int j) { + if (this.d(i, j)) { + this.b("READ", i, j, "out of bounds"); + return null; + } else { + try { + int k = this.e(i, j); + + if (k == 0) { + return null; + } else { + int l = k >> 8; + int i1 = k & 255; + + if (l + i1 > this.f.size()) { + this.b("READ", i, j, "invalid sector"); + return null; + } else { + this.c.seek((long) (l * 4096)); + int j1 = this.c.readInt(); + + if (j1 > 4096 * i1) { + this.b("READ", i, j, "invalid length: " + j1 + " > 4096 * " + i1); + return null; + } else { + byte b0 = this.c.readByte(); + byte[] abyte; + DataInputStream datainputstream; + + if (b0 == 1) { + abyte = new byte[j1 - 1]; + this.c.read(abyte); + datainputstream = new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(abyte))); + return datainputstream; + } else if (b0 == 2) { + abyte = new byte[j1 - 1]; + this.c.read(abyte); + datainputstream = new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(abyte))); + return datainputstream; + } else { + this.b("READ", i, j, "unknown version " + b0); + return null; + } + } + } + } + } catch (IOException ioexception) { + this.b("READ", i, j, "exception"); + return null; + } + } + } + + public DataOutputStream b(int i, int j) { + return this.d(i, j) ? null : new DataOutputStream(new DeflaterOutputStream(new ChunkBuffer(this, i, j))); + } + + protected synchronized void a(int i, int j, byte[] abyte, int k) { + try { + int l = this.e(i, j); + int i1 = l >> 8; + int j1 = l & 255; + int k1 = (k + 5) / 4096 + 1; + + if (k1 >= 256) { + return; + } + + if (i1 != 0 && j1 == k1) { + this.a("SAVE", i, j, k, "rewrite"); + this.a(i1, abyte, k); + } else { + int l1; + + for (l1 = 0; l1 < j1; ++l1) { + this.f.set(i1 + l1, Boolean.valueOf(true)); + } + + l1 = this.f.indexOf(Boolean.valueOf(true)); + int i2 = 0; + int j2; + + if (l1 != -1) { + for (j2 = l1; j2 < this.f.size(); ++j2) { + if (i2 != 0) { + if (((Boolean) this.f.get(j2)).booleanValue()) { + ++i2; + } else { + i2 = 0; + } + } else if (((Boolean) this.f.get(j2)).booleanValue()) { + l1 = j2; + i2 = 1; + } + + if (i2 >= k1) { + break; + } + } + } + + if (i2 >= k1) { + this.a("SAVE", i, j, k, "reuse"); + i1 = l1; + this.a(i, j, l1 << 8 | k1); + + for (j2 = 0; j2 < k1; ++j2) { + this.f.set(i1 + j2, Boolean.valueOf(false)); + } + + this.a(i1, abyte, k); + } else { + this.a("SAVE", i, j, k, "grow"); + this.c.seek(this.c.length()); + i1 = this.f.size(); + + for (j2 = 0; j2 < k1; ++j2) { + this.c.write(a); + this.f.add(Boolean.valueOf(false)); + } + + this.g += 4096 * k1; + this.a(i1, abyte, k); + this.a(i, j, i1 << 8 | k1); + } + } + + this.b(i, j, (int) (System.currentTimeMillis() / 1000L)); + } catch (IOException ioexception) { + ioexception.printStackTrace(); + } + } + + private void a(int i, byte[] abyte, int j) throws IOException { + this.b(" " + i); + this.c.seek((long) (i * 4096)); + this.c.writeInt(j + 1); + this.c.writeByte(2); + this.c.write(abyte, 0, j); + } + + private boolean d(int i, int j) { + return i < 0 || i >= 32 || j < 0 || j >= 32; + } + + private int e(int i, int j) { + return this.d[i + j * 32]; + } + + public boolean c(int i, int j) { + return this.e(i, j) != 0; + } + + private void a(int i, int j, int k) throws IOException { + this.d[i + j * 32] = k; + this.c.seek((long) ((i + j * 32) * 4)); + this.c.writeInt(k); + } + + private void b(int i, int j, int k) throws IOException { + this.e[i + j * 32] = k; + this.c.seek((long) (4096 + (i + j * 32) * 4)); + this.c.writeInt(k); + } + + public void b() throws IOException { + this.c.close(); + } +} diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java new file mode 100644 index 0000000..d8f2311 --- /dev/null +++ b/src/main/java/net/minecraft/server/RegionFileCache.java @@ -0,0 +1,82 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class RegionFileCache { + + private static final Map a = new HashMap(); + + private RegionFileCache() {} + + public static synchronized RegionFile a(File file1, int i, int j) { + File file2 = new File(file1, "region"); + File file3 = new File(file2, "r." + (i >> 5) + "." + (j >> 5) + ".mcr"); + Reference reference = (Reference) a.get(file3); + RegionFile regionfile; + + if (reference != null) { + regionfile = (RegionFile) reference.get(); + if (regionfile != null) { + return regionfile; + } + } + + if (!file2.exists()) { + file2.mkdirs(); + } + + if (a.size() >= 256) { + a(); + } + + regionfile = new RegionFile(file3); + a.put(file3, new SoftReference(regionfile)); + return regionfile; + } + + public static synchronized void a() { + Iterator iterator = a.values().iterator(); + + while (iterator.hasNext()) { + Reference reference = (Reference) iterator.next(); + + try { + RegionFile regionfile = (RegionFile) reference.get(); + + if (regionfile != null) { + regionfile.b(); + } + } catch (IOException ioexception) { + ioexception.printStackTrace(); + } + } + + a.clear(); + } + + public static int b(File file1, int i, int j) { + RegionFile regionfile = a(file1, i, j); + + return regionfile.a(); + } + + public static DataInputStream c(File file1, int i, int j) { + RegionFile regionfile = a(file1, i, j); + + return regionfile.a(i & 31, j & 31); + } + + public static DataOutputStream d(File file1, int i, int j) { + RegionFile regionfile = a(file1, i, j); + + return regionfile.b(i & 31, j & 31); + } +} diff --git a/src/main/java/net/minecraft/server/SecondaryWorldServer.java b/src/main/java/net/minecraft/server/SecondaryWorldServer.java new file mode 100644 index 0000000..3a7d4df --- /dev/null +++ b/src/main/java/net/minecraft/server/SecondaryWorldServer.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +import org.bukkit.generator.ChunkGenerator; + +public class SecondaryWorldServer extends WorldServer { + // CraftBukkit start + public SecondaryWorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, String s, int i, long j, WorldServer worldserver, org.bukkit.World.Environment env, ChunkGenerator gen) { + super(minecraftserver, idatamanager, s, i, j, env, gen); + // CraftBukkit end + this.worldMaps = worldserver.worldMaps; + } +} diff --git a/src/main/java/net/minecraft/server/ServerCommand.java b/src/main/java/net/minecraft/server/ServerCommand.java new file mode 100644 index 0000000..b4361df --- /dev/null +++ b/src/main/java/net/minecraft/server/ServerCommand.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +public class ServerCommand { + + public final String command; + public final ICommandListener b; + + public ServerCommand(String s, ICommandListener icommandlistener) { + this.command = s; + this.b = icommandlistener; + } +} diff --git a/src/main/java/net/minecraft/server/ServerConfigurationManager.java b/src/main/java/net/minecraft/server/ServerConfigurationManager.java new file mode 100644 index 0000000..7c00cd9 --- /dev/null +++ b/src/main/java/net/minecraft/server/ServerConfigurationManager.java @@ -0,0 +1,691 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.Poseidon; +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.command.ColouredConsoleSender; +import org.bukkit.entity.Player; +import org.bukkit.event.player.*; + +import java.io.*; +import java.util.*; +import java.util.logging.Logger; + +// CraftBukkit start +// CraftBukkit end + +public class ServerConfigurationManager { + + public static Logger a = Logger.getLogger("Minecraft"); + public List players = new ArrayList(); + public MinecraftServer server; // CraftBukkit - private -> public + // private PlayerManager[] d = new PlayerManager[2]; // CraftBukkit - removed + public int maxPlayers; // CraftBukkit - private -> public + public Set banByName = new HashSet(); // CraftBukkit - private -> public + public Set banByIP = new HashSet(); // CraftBukkit - private -> public + private Set h = new HashSet(); + private Set i = new HashSet(); + private File j; + private File k; + private File l; + private File m; + public PlayerFileData playerFileData; // CraftBukkit - private - >public + public boolean o; // Craftbukkit - private -> public + + // CraftBukkit start + private CraftServer cserver; + private final String msgKickBanned, msgKickIPBanned, msgKickWhitelist, msgKickServerFull, msgPlayerJoin, msgPlayerLeave; + + public ServerConfigurationManager(MinecraftServer minecraftserver) { + minecraftserver.server = new CraftServer(minecraftserver, this); + minecraftserver.console = new ColouredConsoleSender(minecraftserver.server); + this.cserver = minecraftserver.server; + // CraftBukkit end + this.msgKickBanned = PoseidonConfig.getInstance().getConfigString("message.kick.banned"); + this.msgKickIPBanned = PoseidonConfig.getInstance().getConfigString("message.kick.ip-banned"); + this.msgKickWhitelist = PoseidonConfig.getInstance().getConfigString("message.kick.not-whitelisted"); + this.msgKickServerFull = PoseidonConfig.getInstance().getConfigString("message.kick.full"); + this.msgPlayerJoin = PoseidonConfig.getInstance().getConfigString("message.player.join"); + this.msgPlayerLeave = PoseidonConfig.getInstance().getConfigString("message.player.leave"); + + this.server = minecraftserver; + this.j = minecraftserver.a("banned-players.txt"); + this.k = minecraftserver.a("banned-ips.txt"); + this.l = minecraftserver.a("ops.txt"); + this.m = minecraftserver.a("white-list.txt"); + int i = minecraftserver.propertyManager.getInt("view-distance", 10); + + // CraftBukkit - removed playermanagers + this.maxPlayers = minecraftserver.propertyManager.getInt("max-players", 20); + this.o = minecraftserver.propertyManager.getBoolean("white-list", false); + this.g(); + this.i(); + this.k(); + this.m(); + this.h(); + this.j(); + this.l(); + this.n(); + } + + public void setPlayerFileData(WorldServer[] aworldserver) { + if (this.playerFileData != null) return; // CraftBukkit + this.playerFileData = aworldserver[0].p().d(); + } + + public void a(EntityPlayer entityplayer) { + // CraftBukkit - removed playermanagers + for (WorldServer world : this.server.worlds) { + if (world.manager.managedPlayers.contains(entityplayer)) { + world.manager.removePlayer(entityplayer); + break; + } + } + this.getPlayerManager(entityplayer.dimension).addPlayer(entityplayer); + WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension); + + worldserver.chunkProviderServer.getChunkAt((int) entityplayer.locX >> 4, (int) entityplayer.locZ >> 4); + } + + public int a() { + // CraftBukkit start + if (this.server.worlds.size() == 0) { + return this.server.propertyManager.getInt("view-distance", 10) * 16 - 16; + } + return this.server.worlds.get(0).manager.getFurthestViewableBlock(); + // CraftBukkit end + } + + private PlayerManager getPlayerManager(int i) { + return this.server.getWorldServer(i).manager; // CraftBukkit + } + + public void b(EntityPlayer entityplayer) { + this.playerFileData.b(entityplayer); + } + + public void c(EntityPlayer entityplayer) { + this.players.add(entityplayer); + //PlayerTracker.getInstance().addPlayer(entityplayer.name); + WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension); + + worldserver.chunkProviderServer.getChunkAt((int) entityplayer.locX >> 4, (int) entityplayer.locZ >> 4); + + if((boolean) PoseidonConfig.getInstance().getConfigOption("world-settings.teleport-to-highest-safe-block")) { + while (worldserver.getEntities(entityplayer, entityplayer.boundingBox).size() != 0) { + entityplayer.setPosition(entityplayer.locX, entityplayer.locY + 1.0D, entityplayer.locZ); + } + } + + // CraftBukkit start + Player player = this.cserver.getPlayer(entityplayer); + PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(player, msgPlayerJoin.replace("%player%", entityplayer.name)); + this.cserver.getPluginManager().callEvent(playerJoinEvent); + + String joinMessage = playerJoinEvent.getJoinMessage(); + + if (joinMessage != null) { + this.server.serverConfigurationManager.sendAll(new Packet3Chat(joinMessage)); + } + // CraftBukkit end + + // Poseidon Start + // Notify staff of Poseidon update if they are op or have poseidon.update permission + if(PoseidonConfig.getInstance().getConfigBoolean("settings.update-checker.notify-staff.enabled", true) && Poseidon.getServer().isUpdateAvailable()) { + if (player.isOp() || player.hasPermission("poseidon.update")) { + String updateMessage = PoseidonConfig.getInstance().getConfigString("message.update.available"); + updateMessage = updateMessage.replace("%newversion%", Poseidon.getServer().getNewestVersion()); + updateMessage = updateMessage.replace("%currentversion%", Poseidon.getServer().getReleaseVersion()); + player.sendMessage(updateMessage); + } + } + // Poseidon End + + worldserver.addEntity(entityplayer); + this.getPlayerManager(entityplayer.dimension).addPlayer(entityplayer); + } + + public void d(EntityPlayer entityplayer) { + this.getPlayerManager(entityplayer.dimension).movePlayer(entityplayer); + } + + public String disconnect(EntityPlayer entityplayer) { // CraftBukkit - changed return type + //if(entityplayer.netServerHandler.disconnected) return null; // CraftBukkit - exploits fix https://github.com/OvercastNetwork/CraftBukkit/commit/6f79ca5c54d30d04803143975757713a01bf4e35 + + + // CraftBukkit start + // Quitting must be before we do final save of data, in case plugins need to modify it + this.getPlayerManager(entityplayer.dimension).removePlayer(entityplayer); + PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(this.cserver.getPlayer(entityplayer), this.msgPlayerLeave.replace("%player%", entityplayer.name)); + this.cserver.getPluginManager().callEvent(playerQuitEvent); + // CraftBukkit end + + //Project POSEIDON Start +// boolean found = false; +// for (int i = 0; i < this.players.size(); ++i) { +// EntityPlayer ep = (EntityPlayer) this.players.get(i); +// if (entityplayer.name.equalsIgnoreCase(ep.name)) { +// found = true; +// break; +// } +// } +// if (!found) { +// //return null; - This caused a bug which could block future connections if a quit event occurs before a join event, i think +// playerQuitEvent.setQuitMessage(null); +// } +// PlayerTracker.getInstance().removePlayer(entityplayer.name); + //Project POSEIDON End + + // Flush transient cursor/crafting state before save so disconnects cannot lose those items. + entityplayer.defaultContainer.a((EntityHuman) entityplayer); + entityplayer.A(); + this.playerFileData.a(entityplayer); + this.server.getWorldServer(entityplayer.dimension).kill(entityplayer); + this.players.remove(entityplayer); + this.getPlayerManager(entityplayer.dimension).removePlayer(entityplayer); + + return playerQuitEvent.getQuitMessage(); // CraftBukkit + } + + public EntityPlayer a(NetLoginHandler netloginhandler, String s) { + // CraftBukkit start - note: this entire method needs to be changed + // Instead of kicking then returning, we need to store the kick reason + // in the event, check with plugins to see if it's ok, and THEN kick + // depending on the outcome. Also change any reference to this.e.c to entity.world + EntityPlayer entity = new EntityPlayer(this.server, this.server.getWorldServer(0), s, new ItemInWorldManager(this.server.getWorldServer(0))); + Player player = (entity == null) ? null : (Player) entity.getBukkitEntity(); + PlayerLoginEvent event = new PlayerLoginEvent(player, netloginhandler); //Project Poseidon - pass player IP through + + String s1 = netloginhandler.networkManager.getSocketAddress().toString(); + + s1 = s1.substring(s1.indexOf("/") + 1); + s1 = s1.substring(0, s1.indexOf(":")); + + PlayerLoginEvent.Result result = + this.banByName.contains(s.trim().toLowerCase()) ? PlayerLoginEvent.Result.KICK_BANNED : + this.banByIP.contains(s1) ? PlayerLoginEvent.Result.KICK_BANNED_IP : + !this.isWhitelisted(s) ? PlayerLoginEvent.Result.KICK_WHITELIST : + this.players.size() >= this.maxPlayers ? PlayerLoginEvent.Result.KICK_FULL : + PlayerLoginEvent.Result.ALLOWED; + + String kickMessage = + result.equals(PlayerLoginEvent.Result.KICK_BANNED) ? this.msgKickBanned : + result.equals(PlayerLoginEvent.Result.KICK_BANNED_IP) ? this.msgKickIPBanned : + result.equals(PlayerLoginEvent.Result.KICK_WHITELIST) ? this.msgKickWhitelist : + result.equals(PlayerLoginEvent.Result.KICK_FULL) ? msgKickServerFull : + s1; + + event.disallow(result, kickMessage); + + this.cserver.getPluginManager().callEvent(event); + if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { + netloginhandler.disconnect(event.getKickMessage()); + return null; + } + + for (int i = 0; i < this.players.size(); ++i) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(i); + + if (entityplayer.name.equalsIgnoreCase(s)) { + entityplayer.netServerHandler.disconnect("You logged in from another location"); + } + } + + return entity; + // CraftBukkit end + } + + // CraftBukkit start + public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i) { + return this.moveToWorld(entityplayer, i, null); + } + + public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i, Location location) { + this.server.getTracker(entityplayer.dimension).untrackPlayer(entityplayer); + // this.server.getTracker(entityplayer.dimension).untrackEntity(entityplayer); // CraftBukkit + this.getPlayerManager(entityplayer.dimension).removePlayer(entityplayer); + this.players.remove(entityplayer); + //PlayerTracker.getInstance().removePlayer(entityplayer.name); //Project POSEIDON + this.server.getWorldServer(entityplayer.dimension).removeEntity(entityplayer); + ChunkCoordinates chunkcoordinates = entityplayer.getBed(); + + // CraftBukkit start + EntityPlayer entityplayer1 = entityplayer; + org.bukkit.World fromWorld = entityplayer1.getBukkitEntity().getWorld(); + + if (location == null) { + boolean isBedSpawn = false; + CraftWorld cworld = (CraftWorld) this.server.server.getWorld(entityplayer.spawnWorld); + if (cworld != null && chunkcoordinates != null) { + ChunkCoordinates chunkcoordinates1 = EntityHuman.getBed(cworld.getHandle(), chunkcoordinates); + if (chunkcoordinates1 != null) { + isBedSpawn = true; + location = new Location(cworld, chunkcoordinates1.x + 0.5, chunkcoordinates1.y, chunkcoordinates1.z + 0.5); + } else { + entityplayer1.netServerHandler.sendPacket(new Packet70Bed(0)); + } + } + + if (location == null) { + cworld = (CraftWorld) this.server.server.getWorlds().get(0); + chunkcoordinates = cworld.getHandle().getSpawn(); + float yaw = cworld.getHandle().worldData.getYaw(); // Poseidon + float pitch = cworld.getHandle().worldData.getPitch(); // Poseidon + location = new Location(cworld, chunkcoordinates.x + 0.5, chunkcoordinates.y, chunkcoordinates.z + 0.5, yaw, pitch); + } + + Player respawnPlayer = this.cserver.getPlayer(entityplayer); + PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(respawnPlayer, location, isBedSpawn); + this.cserver.getPluginManager().callEvent(respawnEvent); + + location = respawnEvent.getRespawnLocation(); + entityplayer.health = 20; + entityplayer.fireTicks = 0; + entityplayer.fallDistance = 0; + } else { + location.setWorld(this.server.getWorldServer(i).getWorld()); + } + WorldServer worldserver = ((CraftWorld) location.getWorld()).getHandle(); + entityplayer1.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + // CraftBukkit end + + worldserver.chunkProviderServer.getChunkAt((int) entityplayer1.locX >> 4, (int) entityplayer1.locZ >> 4); + + while (worldserver.getEntities(entityplayer1, entityplayer1.boundingBox).size() != 0) { + entityplayer1.setPosition(entityplayer1.locX, entityplayer1.locY + 1.0D, entityplayer1.locZ); + } + + // CraftBukkit start + byte actualDimension = (byte) (worldserver.getWorld().getEnvironment().getId()); + entityplayer1.netServerHandler.sendPacket(new Packet9Respawn((byte) (actualDimension >= 0 ? -1 : 0))); + entityplayer1.netServerHandler.sendPacket(new Packet9Respawn(actualDimension)); + entityplayer1.spawnIn(worldserver); + entityplayer1.dead = false; + entityplayer1.netServerHandler.teleport(new Location(worldserver.getWorld(), entityplayer1.locX, entityplayer1.locY, entityplayer1.locZ, entityplayer1.yaw, entityplayer1.pitch)); + // CraftBukkit end + this.a(entityplayer1, worldserver); + this.getPlayerManager(entityplayer1.dimension).addPlayer(entityplayer1); + worldserver.addEntity(entityplayer1); + this.players.add(entityplayer1); + //PlayerTracker.getInstance().addPlayer(entityplayer1.name); //Project POSEIDON + this.updateClient(entityplayer1); // CraftBukkit + entityplayer1.x(); + // CraftBukkit start - don't fire on respawn + if (fromWorld != location.getWorld()) { + org.bukkit.event.player.PlayerChangedWorldEvent event = new org.bukkit.event.player.PlayerChangedWorldEvent((Player) entityplayer1.getBukkitEntity(), fromWorld); + Bukkit.getServer().getPluginManager().callEvent(event); + } + // CraftBukkit end + return entityplayer1; + } + + public void f(EntityPlayer entityplayer) { + // CraftBukkit start -- Replaced the standard handling of portals with a more customised method. + int dimension = entityplayer.dimension; + WorldServer fromWorld = this.server.getWorldServer(dimension); + WorldServer toWorld = null; + if (dimension < 10) { + int toDimension = dimension == -1 ? 0 : -1; + for (WorldServer world : this.server.worlds) { + if (world.dimension == toDimension) { + toWorld = world; + } + } + } + double blockRatio = dimension == -1 ? 8 : 0.125; + + Location fromLocation = new Location(fromWorld.getWorld(), entityplayer.locX, entityplayer.locY, entityplayer.locZ, entityplayer.yaw, entityplayer.pitch); + Location toLocation = toWorld == null ? null : new Location(toWorld.getWorld(), (entityplayer.locX * blockRatio), entityplayer.locY, (entityplayer.locZ * blockRatio), entityplayer.yaw, entityplayer.pitch); + + org.bukkit.craftbukkit.PortalTravelAgent pta = new org.bukkit.craftbukkit.PortalTravelAgent(); + PlayerPortalEvent event = new PlayerPortalEvent((Player) entityplayer.getBukkitEntity(), fromLocation, toLocation, pta); + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled() || event.getTo() == null) { + return; + } + + Location finalLocation = event.getTo(); + if (event.useTravelAgent()) { + finalLocation = event.getPortalTravelAgent().findOrCreate(finalLocation); + } + toWorld = ((CraftWorld) finalLocation.getWorld()).getHandle(); + this.moveToWorld(entityplayer, toWorld.dimension, finalLocation); + // CraftBukkit end + } + + public void b() { + // CraftBukkit start + for (int i = 0; i < this.server.worlds.size(); ++i) { + this.server.worlds.get(i).manager.flush(); + } + // CraftBukkit end + } + + public void flagDirty(int i, int j, int k, int l) { + this.getPlayerManager(l).flagDirty(i, j, k); + } + + public void sendAll(Packet packet) { + for (int i = 0; i < this.players.size(); ++i) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(i); + + entityplayer.netServerHandler.sendPacket(packet); + } + } + + public void a(Packet packet, int i) { + for (int j = 0; j < this.players.size(); ++j) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(j); + + if (entityplayer.dimension == i) { + entityplayer.netServerHandler.sendPacket(packet); + } + } + } + + public String c() { + String s = ""; + + for (int i = 0; i < this.players.size(); ++i) { + if (i > 0) { + s = s + ", "; + } + + s = s + ((EntityPlayer) this.players.get(i)).name; + } + + return s; + } + + public void a(String s) { + this.banByName.add(s.toLowerCase()); + this.h(); + } + + public void b(String s) { + this.banByName.remove(s.toLowerCase()); + this.h(); + } + + private void g() { + try { + this.banByName.clear(); + BufferedReader bufferedreader = new BufferedReader(new FileReader(this.j)); + String s = ""; + + while ((s = bufferedreader.readLine()) != null) { + this.banByName.add(s.trim().toLowerCase()); + } + + bufferedreader.close(); + } catch (Exception exception) { + a.warning("Failed to load ban list: " + exception); + } + } + + private void h() { + try { + PrintWriter printwriter = new PrintWriter(new FileWriter(this.j, false)); + Iterator iterator = this.banByName.iterator(); + + while (iterator.hasNext()) { + String s = (String) iterator.next(); + + printwriter.println(s); + } + + printwriter.close(); + } catch (Exception exception) { + a.warning("Failed to save ban list: " + exception); + } + } + + public void c(String s) { + this.banByIP.add(s.toLowerCase()); + this.j(); + } + + public void d(String s) { + this.banByIP.remove(s.toLowerCase()); + this.j(); + } + + private void i() { + try { + this.banByIP.clear(); + BufferedReader bufferedreader = new BufferedReader(new FileReader(this.k)); + String s = ""; + + while ((s = bufferedreader.readLine()) != null) { + this.banByIP.add(s.trim().toLowerCase()); + } + + bufferedreader.close(); + } catch (Exception exception) { + a.warning("Failed to load ip ban list: " + exception); + } + } + + private void j() { + try { + PrintWriter printwriter = new PrintWriter(new FileWriter(this.k, false)); + Iterator iterator = this.banByIP.iterator(); + + while (iterator.hasNext()) { + String s = (String) iterator.next(); + + printwriter.println(s); + } + + printwriter.close(); + } catch (Exception exception) { + a.warning("Failed to save ip ban list: " + exception); + } + } + + public void e(String s) { + this.h.add(s.toLowerCase()); + this.l(); + + // Craftbukkit start + Player player = server.server.getPlayer(s); + if (player != null) { + player.recalculatePermissions(); + } + // Craftbukkit end + } + + public void f(String s) { + this.h.remove(s.toLowerCase()); + this.l(); + + // Craftbukkit start + Player player = server.server.getPlayer(s); + if (player != null) { + player.recalculatePermissions(); + } + // Craftbukkit end + } + + private void k() { + try { + this.h.clear(); + BufferedReader bufferedreader = new BufferedReader(new FileReader(this.l)); + String s = ""; + + while ((s = bufferedreader.readLine()) != null) { + this.h.add(s.trim().toLowerCase()); + } + + bufferedreader.close(); + } catch (Exception exception) { + // CraftBukkit - corrected text + a.warning("Failed to load ops: " + exception); + } + } + + private void l() { + try { + PrintWriter printwriter = new PrintWriter(new FileWriter(this.l, false)); + Iterator iterator = this.h.iterator(); + + while (iterator.hasNext()) { + String s = (String) iterator.next(); + + printwriter.println(s); + } + + printwriter.close(); + } catch (Exception exception) { + // CraftBukkit - corrected text + a.warning("Failed to save ops: " + exception); + } + } + + private void m() { + try { + this.i.clear(); + BufferedReader bufferedreader = new BufferedReader(new FileReader(this.m)); + String s = ""; + + while ((s = bufferedreader.readLine()) != null) { + this.i.add(s.trim().toLowerCase()); + } + + bufferedreader.close(); + } catch (Exception exception) { + a.warning("Failed to load white-list: " + exception); + } + } + + private void n() { + try { + PrintWriter printwriter = new PrintWriter(new FileWriter(this.m, false)); + Iterator iterator = this.i.iterator(); + + while (iterator.hasNext()) { + String s = (String) iterator.next(); + + printwriter.println(s); + } + + printwriter.close(); + } catch (Exception exception) { + a.warning("Failed to save white-list: " + exception); + } + } + + public boolean isWhitelisted(String s) { + s = s.trim().toLowerCase(); + return !this.o || this.h.contains(s) || this.i.contains(s); + } + + public boolean isOp(String s) { + return this.h.contains(s.trim().toLowerCase()); + } + + public EntityPlayer i(String s) { + for (int i = 0; i < this.players.size(); ++i) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(i); + + if (entityplayer.name.equalsIgnoreCase(s)) { + return entityplayer; + } + } + + return null; + } + + public void a(String s, String s1) { + EntityPlayer entityplayer = this.i(s); + + if (entityplayer != null) { + entityplayer.netServerHandler.sendPacket(new Packet3Chat(s1)); + } + } + + public void sendPacketNearby(double d0, double d1, double d2, double d3, int i, Packet packet) { + this.sendPacketNearby((EntityHuman) null, d0, d1, d2, d3, i, packet); + } + + public void sendPacketNearby(EntityHuman entityhuman, double d0, double d1, double d2, double d3, int i, Packet packet) { + for (int j = 0; j < this.players.size(); ++j) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(j); + + if (entityplayer != entityhuman && entityplayer.dimension == i) { + double d4 = d0 - entityplayer.locX; + double d5 = d1 - entityplayer.locY; + double d6 = d2 - entityplayer.locZ; + + if (d4 * d4 + d5 * d5 + d6 * d6 < d3 * d3) { + entityplayer.netServerHandler.sendPacket(packet); + } + } + } + } + + public void j(String s) { + Packet3Chat packet3chat = new Packet3Chat(s); + + for (int i = 0; i < this.players.size(); ++i) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(i); + + if (this.isOp(entityplayer.name)) { + entityplayer.netServerHandler.sendPacket(packet3chat); + } + } + } + + public boolean a(String s, Packet packet) { + EntityPlayer entityplayer = this.i(s); + + if (entityplayer != null) { + entityplayer.netServerHandler.sendPacket(packet); + return true; + } else { + return false; + } + } + + public void savePlayers() { + for (int i = 0; i < this.players.size(); ++i) { + this.playerFileData.a((EntityHuman) this.players.get(i)); + } + } + + public void a(int i, int j, int k, TileEntity tileentity) { + } + + public void k(String s) { + this.i.add(s); + this.n(); + } + + public void l(String s) { + this.i.remove(s); + this.n(); + } + + public Set e() { + return this.i; + } + + public void f() { + this.m(); + } + + public void a(EntityPlayer entityplayer, WorldServer worldserver) { + entityplayer.netServerHandler.sendPacket(new Packet4UpdateTime(worldserver.getTime())); + if (worldserver.v()) { + entityplayer.netServerHandler.sendPacket(new Packet70Bed(1)); + } + } + + public void updateClient(EntityPlayer entityplayer) { + entityplayer.updateInventory(entityplayer.defaultContainer); + entityplayer.C(); + } +} diff --git a/src/main/java/net/minecraft/server/ServerGUI.java b/src/main/java/net/minecraft/server/ServerGUI.java new file mode 100644 index 0000000..ad73500 --- /dev/null +++ b/src/main/java/net/minecraft/server/ServerGUI.java @@ -0,0 +1,90 @@ +package net.minecraft.server; + +import javax.swing.*; +import javax.swing.border.EtchedBorder; +import javax.swing.border.TitledBorder; +import java.awt.*; +import java.util.logging.Logger; + +public class ServerGUI extends JComponent implements ICommandListener { + + public static Logger a = Logger.getLogger("Minecraft"); + private MinecraftServer b; + + public static void a(MinecraftServer minecraftserver) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception exception) { + ; + } + + ServerGUI servergui = new ServerGUI(minecraftserver); + JFrame jframe = new JFrame("Minecraft server"); + + jframe.add(servergui); + jframe.pack(); + jframe.setLocationRelativeTo((Component) null); + jframe.setVisible(true); + jframe.addWindowListener(new ServerWindowAdapter(minecraftserver)); + } + + public ServerGUI(MinecraftServer minecraftserver) { + this.b = minecraftserver; + this.setPreferredSize(new Dimension(854, 480)); + this.setLayout(new BorderLayout()); + + try { + this.add(this.c(), "Center"); + this.add(this.a(), "West"); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + private JComponent a() { + JPanel jpanel = new JPanel(new BorderLayout()); + + jpanel.add(new GuiStatsComponent(), "North"); + jpanel.add(this.b(), "Center"); + jpanel.setBorder(new TitledBorder(new EtchedBorder(), "Stats")); + return jpanel; + } + + private JComponent b() { + PlayerListBox playerlistbox = new PlayerListBox(this.b); + JScrollPane jscrollpane = new JScrollPane(playerlistbox, 22, 30); + + jscrollpane.setBorder(new TitledBorder(new EtchedBorder(), "Players")); + return jscrollpane; + } + + private JComponent c() { + JPanel jpanel = new JPanel(new BorderLayout()); + JTextArea jtextarea = new JTextArea(); + + a.addHandler(new GuiLogOutputHandler(jtextarea)); + JScrollPane jscrollpane = new JScrollPane(jtextarea, 22, 30); + + jtextarea.setEditable(false); + JTextField jtextfield = new JTextField(); + + jtextfield.addActionListener(new ServerGuiCommandListener(this, jtextfield)); + jtextarea.addFocusListener(new ServerGuiFocusAdapter(this)); + jpanel.add(jscrollpane, "Center"); + jpanel.add(jtextfield, "South"); + jpanel.setBorder(new TitledBorder(new EtchedBorder(), "Log and chat")); + return jpanel; + } + + public void sendMessage(String s) { + a.info(s); + } + + public String getName() { + return "CONSOLE"; + } + + static MinecraftServer a(ServerGUI servergui) { + return servergui.b; + } +} diff --git a/src/main/java/net/minecraft/server/ServerGuiCommandListener.java b/src/main/java/net/minecraft/server/ServerGuiCommandListener.java new file mode 100644 index 0000000..9ec8f4d --- /dev/null +++ b/src/main/java/net/minecraft/server/ServerGuiCommandListener.java @@ -0,0 +1,27 @@ +package net.minecraft.server; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +class ServerGuiCommandListener implements ActionListener { + + final JTextField a; + + final ServerGUI b; + + ServerGuiCommandListener(ServerGUI servergui, JTextField jtextfield) { + this.b = servergui; + this.a = jtextfield; + } + + public void actionPerformed(ActionEvent actionevent) { + String s = this.a.getText().trim(); + + if (s.length() > 0) { + ServerGUI.a(this.b).issueCommand(s, this.b); + } + + this.a.setText(""); + } +} diff --git a/src/main/java/net/minecraft/server/ServerGuiFocusAdapter.java b/src/main/java/net/minecraft/server/ServerGuiFocusAdapter.java new file mode 100644 index 0000000..aede72f --- /dev/null +++ b/src/main/java/net/minecraft/server/ServerGuiFocusAdapter.java @@ -0,0 +1,15 @@ +package net.minecraft.server; + +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; + +class ServerGuiFocusAdapter extends FocusAdapter { + + final ServerGUI a; + + ServerGuiFocusAdapter(ServerGUI servergui) { + this.a = servergui; + } + + public void focusGained(FocusEvent focusevent) {} +} diff --git a/src/main/java/net/minecraft/server/ServerNBTManager.java b/src/main/java/net/minecraft/server/ServerNBTManager.java new file mode 100644 index 0000000..360efbf --- /dev/null +++ b/src/main/java/net/minecraft/server/ServerNBTManager.java @@ -0,0 +1,33 @@ +package net.minecraft.server; + +import java.io.File; +import java.util.List; + +public class ServerNBTManager extends PlayerNBTManager { + + public ServerNBTManager(File file1, String s, boolean flag) { + super(file1, s, flag); + } + + public IChunkLoader a(WorldProvider worldprovider) { + File file1 = this.a(); + + if (worldprovider instanceof WorldProviderHell) { + File file2 = new File(file1, "DIM-1"); + + file2.mkdirs(); + return new ChunkRegionLoader(file2); + } else { + return new ChunkRegionLoader(file1); + } + } + + public void a(WorldData worlddata, List list) { + worlddata.a(19132); + super.a(worlddata, list); + } + + public void e() { + RegionFileCache.a(); + } +} diff --git a/src/main/java/net/minecraft/server/ServerWindowAdapter.java b/src/main/java/net/minecraft/server/ServerWindowAdapter.java new file mode 100644 index 0000000..cb83947 --- /dev/null +++ b/src/main/java/net/minecraft/server/ServerWindowAdapter.java @@ -0,0 +1,27 @@ +package net.minecraft.server; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +final class ServerWindowAdapter extends WindowAdapter { + + final MinecraftServer a; + + ServerWindowAdapter(MinecraftServer minecraftserver) { + this.a = minecraftserver; + } + + public void windowClosing(WindowEvent windowevent) { + this.a.a(); + + while (!this.a.isStopped) { + try { + Thread.sleep(100L); + } catch (InterruptedException interruptedexception) { + interruptedexception.printStackTrace(); + } + } + + System.exit(0); + } +} diff --git a/src/main/java/net/minecraft/server/ShapedRecipes.java b/src/main/java/net/minecraft/server/ShapedRecipes.java new file mode 100644 index 0000000..6fde0c7 --- /dev/null +++ b/src/main/java/net/minecraft/server/ShapedRecipes.java @@ -0,0 +1,82 @@ +package net.minecraft.server; + +public class ShapedRecipes implements CraftingRecipe { + + private int b; + private int c; + private ItemStack[] d; + private ItemStack e; + public final int a; + + public ShapedRecipes(int i, int j, ItemStack[] aitemstack, ItemStack itemstack) { + this.a = itemstack.id; + this.b = i; + this.c = j; + this.d = aitemstack; + this.e = itemstack; + } + + public ItemStack b() { + return this.e; + } + + public boolean a(InventoryCrafting inventorycrafting) { + for (int i = 0; i <= 3 - this.b; ++i) { + for (int j = 0; j <= 3 - this.c; ++j) { + if (this.a(inventorycrafting, i, j, true)) { + return true; + } + + if (this.a(inventorycrafting, i, j, false)) { + return true; + } + } + } + + return false; + } + + private boolean a(InventoryCrafting inventorycrafting, int i, int j, boolean flag) { + for (int k = 0; k < 3; ++k) { + for (int l = 0; l < 3; ++l) { + int i1 = k - i; + int j1 = l - j; + ItemStack itemstack = null; + + if (i1 >= 0 && j1 >= 0 && i1 < this.b && j1 < this.c) { + if (flag) { + itemstack = this.d[this.b - i1 - 1 + j1 * this.b]; + } else { + itemstack = this.d[i1 + j1 * this.b]; + } + } + + ItemStack itemstack1 = inventorycrafting.b(k, l); + + if (itemstack1 != null || itemstack != null) { + if (itemstack1 == null && itemstack != null || itemstack1 != null && itemstack == null) { + return false; + } + + if (itemstack.id != itemstack1.id) { + return false; + } + + if (itemstack.getData() != -1 && itemstack.getData() != itemstack1.getData()) { + return false; + } + } + } + } + + return true; + } + + public ItemStack b(InventoryCrafting inventorycrafting) { + return new ItemStack(this.e.id, this.e.count, this.e.getData()); + } + + public int a() { + return this.b * this.c; + } +} diff --git a/src/main/java/net/minecraft/server/ShapelessRecipes.java b/src/main/java/net/minecraft/server/ShapelessRecipes.java new file mode 100644 index 0000000..d38896a --- /dev/null +++ b/src/main/java/net/minecraft/server/ShapelessRecipes.java @@ -0,0 +1,59 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ShapelessRecipes implements CraftingRecipe { + + private final ItemStack a; + private final List b; + + public ShapelessRecipes(ItemStack itemstack, List list) { + this.a = itemstack; + this.b = list; + } + + public ItemStack b() { + return this.a; + } + + public boolean a(InventoryCrafting inventorycrafting) { + ArrayList arraylist = new ArrayList(this.b); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + ItemStack itemstack = inventorycrafting.b(j, i); + + if (itemstack != null) { + boolean flag = false; + Iterator iterator = arraylist.iterator(); + + while (iterator.hasNext()) { + ItemStack itemstack1 = (ItemStack) iterator.next(); + + if (itemstack.id == itemstack1.id && (itemstack1.getData() == -1 || itemstack.getData() == itemstack1.getData())) { + flag = true; + arraylist.remove(itemstack1); + break; + } + } + + if (!flag) { + return false; + } + } + } + } + + return arraylist.isEmpty(); + } + + public ItemStack b(InventoryCrafting inventorycrafting) { + return this.a.cloneItemStack(); + } + + public int a() { + return this.b.size(); + } +} diff --git a/src/main/java/net/minecraft/server/Slot.java b/src/main/java/net/minecraft/server/Slot.java new file mode 100644 index 0000000..18cc6a5 --- /dev/null +++ b/src/main/java/net/minecraft/server/Slot.java @@ -0,0 +1,54 @@ +package net.minecraft.server; + +public class Slot { + + public final int index; // CraftBukkit - private -> public + public final IInventory inventory; // CraftBukkit - private -> public + public int a; + public int b; + public int c; + + public Slot(IInventory iinventory, int i, int j, int k) { + this.inventory = iinventory; + this.index = i; + this.b = j; + this.c = k; + } + + public void a(ItemStack itemstack) { + this.c(); + } + + public boolean isAllowed(ItemStack itemstack) { + return true; + } + + public ItemStack getItem() { + return this.inventory.getItem(this.index); + } + + public boolean b() { + return this.getItem() != null; + } + + public void c(ItemStack itemstack) { + this.inventory.setItem(this.index, itemstack); + this.c(); + } + + public void c() { + this.inventory.update(); + } + + public int d() { + return this.inventory.getMaxStackSize(); + } + + public ItemStack a(int i) { + return this.inventory.splitStack(this.index, i); + } + + public boolean a(IInventory iinventory, int i) { + return iinventory == this.inventory && i == this.index; + } +} diff --git a/src/main/java/net/minecraft/server/SlotArmor.java b/src/main/java/net/minecraft/server/SlotArmor.java new file mode 100644 index 0000000..4883a7e --- /dev/null +++ b/src/main/java/net/minecraft/server/SlotArmor.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +class SlotArmor extends Slot { + + final int d; + + final ContainerPlayer e; + + SlotArmor(ContainerPlayer containerplayer, IInventory iinventory, int i, int j, int k, int l) { + super(iinventory, i, j, k); + this.e = containerplayer; + this.d = l; + } + + public int d() { + return 1; + } + + public boolean isAllowed(ItemStack itemstack) { + return itemstack.getItem() instanceof ItemArmor ? ((ItemArmor) itemstack.getItem()).bk == this.d : (itemstack.getItem().id == Block.PUMPKIN.id ? this.d == 0 : false); + } +} diff --git a/src/main/java/net/minecraft/server/SlotResult.java b/src/main/java/net/minecraft/server/SlotResult.java new file mode 100644 index 0000000..bc85172 --- /dev/null +++ b/src/main/java/net/minecraft/server/SlotResult.java @@ -0,0 +1,49 @@ +package net.minecraft.server; + +public class SlotResult extends Slot { + + private final IInventory d; + private EntityHuman e; + + public SlotResult(EntityHuman entityhuman, IInventory iinventory, IInventory iinventory1, int i, int j, int k) { + super(iinventory1, i, j, k); + this.e = entityhuman; + this.d = iinventory; + } + + public boolean isAllowed(ItemStack itemstack) { + return false; + } + + public void a(ItemStack itemstack) { + itemstack.b(this.e.world, this.e); + if (itemstack.id == Block.WORKBENCH.id) { + this.e.a(AchievementList.h, 1); + } else if (itemstack.id == Item.WOOD_PICKAXE.id) { + this.e.a(AchievementList.i, 1); + } else if (itemstack.id == Block.FURNACE.id) { + this.e.a(AchievementList.j, 1); + } else if (itemstack.id == Item.WOOD_HOE.id) { + this.e.a(AchievementList.l, 1); + } else if (itemstack.id == Item.BREAD.id) { + this.e.a(AchievementList.m, 1); + } else if (itemstack.id == Item.CAKE.id) { + this.e.a(AchievementList.n, 1); + } else if (itemstack.id == Item.STONE_PICKAXE.id) { + this.e.a(AchievementList.o, 1); + } else if (itemstack.id == Item.WOOD_SWORD.id) { + this.e.a(AchievementList.r, 1); + } + + for (int i = 0; i < this.d.getSize(); ++i) { + ItemStack itemstack1 = this.d.getItem(i); + + if (itemstack1 != null) { + this.d.splitStack(i, 1); + if (itemstack1.getItem().i()) { + this.d.setItem(i, new ItemStack(itemstack1.getItem().h())); + } + } + } + } +} diff --git a/src/main/java/net/minecraft/server/SlotResult2.java b/src/main/java/net/minecraft/server/SlotResult2.java new file mode 100644 index 0000000..8488019 --- /dev/null +++ b/src/main/java/net/minecraft/server/SlotResult2.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +public class SlotResult2 extends Slot { + + private EntityHuman d; + + public SlotResult2(EntityHuman entityhuman, IInventory iinventory, int i, int j, int k) { + super(iinventory, i, j, k); + this.d = entityhuman; + } + + public boolean isAllowed(ItemStack itemstack) { + return false; + } + + public void a(ItemStack itemstack) { + itemstack.b(this.d.world, this.d); + if (itemstack.id == Item.IRON_INGOT.id) { + this.d.a(AchievementList.k, 1); + } + + if (itemstack.id == Item.COOKED_FISH.id) { + this.d.a(AchievementList.p, 1); + } + + super.a(itemstack); + } +} diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java new file mode 100644 index 0000000..a629613 --- /dev/null +++ b/src/main/java/net/minecraft/server/SpawnerCreature.java @@ -0,0 +1,315 @@ +package net.minecraft.server; + +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +// CraftBukkit + +public final class SpawnerCreature { + + /** + * Chunks around players that are eligible for natural spawns this tick. + */ + private static final Set candidateChunks = new HashSet<>(); + + /** + * Mob classes used when attempting to spawn a monster near a sleeping player. + */ + private static final Class[] SLEEP_SPAWNER_MOBS = new Class[]{EntitySpider.class, EntityZombie.class, EntitySkeleton.class}; + + public SpawnerCreature() { + } + + public static int spawnEntities(World world, boolean allowHostiles, boolean allowPeaceful) { + if (!allowHostiles && !allowPeaceful) { + return 0; + } + + candidateChunks.clear(); + + // Build candidate chunk set around each player (square of radius 8 chunks) + for (int p = 0; p < world.players.size(); ++p) { + EntityHuman player = (EntityHuman) world.players.get(p); + int playerChunkX = MathHelper.floor(player.locX / 16.0D); + int playerChunkZ = MathHelper.floor(player.locZ / 16.0D); + final int radius = 8; + + for (int dx = -radius; dx <= radius; ++dx) { + for (int dz = -radius; dz <= radius; ++dz) { + candidateChunks.add(new ChunkCoordIntPair(playerChunkX + dx, playerChunkZ + dz)); + } + } + } + + int spawnedTotal = 0; + ChunkCoordinates worldSpawn = world.getSpawn(); + EnumCreatureType[] creatureTypes = EnumCreatureType.values(); + + for (EnumCreatureType type : creatureTypes) { + + // Skip if the type doesn't match peaceful/hostile toggles + if ((type.isPeaceful() && !allowPeaceful) || (!type.isPeaceful() && !allowHostiles)) { + continue; + } + + // Skip if the global density cap is exceeded + if (world.a(type.getBaseClass()) > type.getMaxCount() * candidateChunks.size() / 256) { + continue; + } + + Iterator it = candidateChunks.iterator(); + + // Walk all candidate chunks for this creature type + chunksLoop: + while (it.hasNext()) { + ChunkCoordIntPair chunkPos = it.next(); + BiomeBase biome = world.getWorldChunkManager().a(chunkPos); + List spawnEntries = biome.a(type); // weighted list of mobs for the biome+type + + if (spawnEntries == null || spawnEntries.isEmpty()) { + continue; + } + + // Pick BiomeMeta via weight + int totalWeight = 0; + for (BiomeMeta entry : spawnEntries) totalWeight += entry.b; + + int rnd = world.random.nextInt(totalWeight); + BiomeMeta chosen = spawnEntries.get(0); + for (BiomeMeta entry : spawnEntries) { + rnd -= entry.b; + if (rnd < 0) { + chosen = entry; + break; + } + } + + // Pick a random position inside the chunk area + ChunkPosition pos = pickRandomBlockInChunkArea(world, chunkPos.x * 16, chunkPos.z * 16); + int baseX = pos.x; + int baseY = pos.y; + int baseZ = pos.z; + + if (!world.e(baseX, baseY, baseZ) && world.getMaterial(baseX, baseY, baseZ) == type.getSpawnMaterial()) { + int groupSpawned = 0; + + // Up to 3 group attempts + for (int groupAttempt = 0; groupAttempt < 3; ++groupAttempt) { + int x = baseX; + int y = baseY; + int z = baseZ; + final byte spread = 6; + + // Try up to 4 mobs per group, with small random offsets + for (int tries = 0; tries < 4; ++tries) { + x += world.random.nextInt(spread) - world.random.nextInt(spread); + y += world.random.nextInt(1) - world.random.nextInt(1); + z += world.random.nextInt(spread) - world.random.nextInt(spread); + + if (canSpawnHere(type, world, x, y, z)) { + float fx = x + 0.5F; + float fy = y; + float fz = z + 0.5F; + + // Keep spawns away from other players (24 block radius) + if (world.a(fx, fy, fz, 24.0D) == null) { + float dx = fx - worldSpawn.x; + float dy = fy - worldSpawn.y; + float dz = fz - worldSpawn.z; + float dist2 = dx * dx + dy * dy + dz * dz; + + // Don’t spawn too close to world spawn (>= 24 blocks -> 24^2 = 576) + if (dist2 >= 576.0F) { + EntityLiving mob; + + try { + mob = (EntityLiving) chosen.a.getConstructor(World.class).newInstance(world); + } catch (Exception ex) { + ex.printStackTrace(); + return spawnedTotal; + } + + mob.setPositionRotation(fx, fy, fz, world.random.nextFloat() * 360.0F, 0.0F); + + // d() = canSpawn() check + if (mob.d()) { + ++groupSpawned; + world.addEntity(mob, SpawnReason.NATURAL); + applyPostSpawnExtras(mob, world, fx, fy, fz); + + // l() = getMaxGroup() clamp for this entity + if (groupSpawned >= mob.l()) { + // Move to next chunk if we filled a group here + spawnedTotal += groupSpawned; + continue chunksLoop; + } + } + } + } + } + } + } + + spawnedTotal += groupSpawned; + } + } + + } + + return spawnedTotal; + } + + + protected static ChunkPosition pickRandomBlockInChunkArea(World world, int i, int j) { + int k = i + world.random.nextInt(16); + int l = world.random.nextInt(128); + int i1 = j + world.random.nextInt(16); + + return new ChunkPosition(k, l, i1); + } + + /** + * Block/material + headroom checks to determine if an entity type can spawn at (x,y,z). + */ + private static boolean canSpawnHere(EnumCreatureType type, World world, int x, int y, int z) { + if (type.getSpawnMaterial() == Material.WATER) { + // Water creatures: must be in liquid, with air above + return world.getMaterial(x, y, z).isLiquid() && !world.e(x, y + 1, z); + } else { + // Land creatures: solid block below, current block + head clear, and not liquid + return world.e(x, y - 1, z) + && !world.e(x, y, z) + && !world.getMaterial(x, y, z).isLiquid() + && !world.e(x, y + 1, z); + } + } + + private static void applyPostSpawnExtras(EntityLiving entityliving, World world, float f, float f1, float f2) { + if (entityliving instanceof EntitySpider && world.random.nextInt(100) == 0) { + EntitySkeleton entityskeleton = new EntitySkeleton(world); + + entityskeleton.setPositionRotation((double) f, (double) f1, (double) f2, entityliving.yaw, 0.0F); + // CraftBukkit - added a reason for spawning this creature + world.addEntity(entityskeleton, SpawnReason.NATURAL); + entityskeleton.mount(entityliving); + } else if (entityliving instanceof EntitySheep) { + ((EntitySheep) entityliving).setColor(EntitySheep.a(world.random)); + } + } + + public static boolean spawnSleepThreats(World world, List listPlayers) { + boolean anySpawned = false; + Pathfinder pathfinder = new Pathfinder(world); + + for (Object o : listPlayers) { + EntityHuman player = (EntityHuman) o; + Class[] candidates = SLEEP_SPAWNER_MOBS; + + if (candidates == null || candidates.length == 0) continue; + + boolean spawnedNearThisPlayer = false; + + // Up to 20 attempts per player + for (int attempt = 0; attempt < 20 && !spawnedNearThisPlayer; ++attempt) { + int x = MathHelper.floor(player.locX) + world.random.nextInt(32) - world.random.nextInt(32); + int z = MathHelper.floor(player.locZ) + world.random.nextInt(32) - world.random.nextInt(32); + int y = MathHelper.floor(player.locY) + world.random.nextInt(16) - world.random.nextInt(16); + + if (y < 1) y = 1; + else if (y > 128) y = 128; + + // Find solid ground + int groundY; + for (groundY = y; groundY > 2 && !world.e(x, groundY - 1, z); --groundY) { /* descend */ } + + // Nudge upward until a valid spawn block is found (or give up) + while (!canSpawnHere(EnumCreatureType.MONSTER, world, x, groundY, z) && groundY < y + 16 && groundY < 128) { + ++groundY; + } + + if (groundY >= y + 16 || groundY >= 128) { + continue; + } + + float fx = x + 0.5F; + float fy = groundY; + float fz = z + 0.5F; + + // Pick a random monster type from SLEEP_MONSTERS + int pick = world.random.nextInt(candidates.length); + EntityLiving mob; + try { + mob = (EntityLiving) candidates[pick].getConstructor(World.class).newInstance(world); + } catch (Exception ex) { + ex.printStackTrace(); + return anySpawned; + } + + mob.setPositionRotation(fx, fy, fz, world.random.nextFloat() * 360.0F, 0.0F); + + if (mob.d()) { + // Must be able to path to the player + PathEntity path = pathfinder.a(mob, player, 32.0F); + if (path != null && path.a > 1) { + PathPoint firstStep = path.c(); + if (Math.abs(firstStep.a - player.locX) < 1.5D + && Math.abs(firstStep.c - player.locZ) < 1.5D + && Math.abs(firstStep.b - player.locY) < 1.5D) { + + // Try bed-safe placement; fall back to current choice + ChunkCoordinates bed = BlockBed.f(world, + MathHelper.floor(player.locX), + MathHelper.floor(player.locY), + MathHelper.floor(player.locZ), 1); + + if (bed == null) bed = new ChunkCoordinates(x, groundY + 1, z); + + mob.setPositionRotation(bed.x + 0.5F, bed.y, bed.z + 0.5F, 0.0F, 0.0F); + world.addEntity(mob, SpawnReason.BED); + applyPostSpawnExtras(mob, world, bed.x + 0.5F, bed.y, bed.z + 0.5F); + + // Wake the player (vanilla flags) + player.a(true, false, false); + mob.Q(); // finalize spawn behaviors + + anySpawned = true; + spawnedNearThisPlayer = true; + } + } + } + } + } + + return anySpawned; + } + + /* ------------------------------------------------------------ + * Compatibility + * ------------------------------------------------------------ */ + + // Old: protected static ChunkPosition a(World, int, int) + protected static ChunkPosition a(World world, int i, int j) { + return pickRandomBlockInChunkArea(world, i, j); + } + + // Old: private static boolean a(EnumCreatureType, World, int, int, int) + private static boolean a(EnumCreatureType type, World world, int x, int y, int z) { + return canSpawnHere(type, world, x, y, z); + } + + // Old: private static void a(EntityLiving, World, float, float, float) + private static void a(EntityLiving entity, World world, float x, float y, float z) { + applyPostSpawnExtras(entity, world, x, y, z); + } + + // Old: public static boolean a(World, List) + public static boolean a(World world, List list) { + return spawnSleepThreats(world, list); + + } + +} \ No newline at end of file diff --git a/src/main/java/net/minecraft/server/Statistic.java b/src/main/java/net/minecraft/server/Statistic.java new file mode 100644 index 0000000..771ce93 --- /dev/null +++ b/src/main/java/net/minecraft/server/Statistic.java @@ -0,0 +1,50 @@ +package net.minecraft.server; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Locale; + +public class Statistic { + + public final int e; + public final String f; + public boolean g; + public String h; + private final Counter a; + private static NumberFormat b = NumberFormat.getIntegerInstance(Locale.US); + public static Counter i = new UnknownCounter(); + private static DecimalFormat c = new DecimalFormat("########0.00"); + public static Counter j = new TimeCounter(); + public static Counter k = new DistancesCounter(); + + public Statistic(int i, String s, Counter counter) { + this.g = false; + this.e = i; + this.f = s; + this.a = counter; + } + + public Statistic(int i, String s) { + this(i, s, Statistic.i); + } + + public Statistic e() { + this.g = true; + return this; + } + + public Statistic d() { + if (StatisticList.a.containsKey(Integer.valueOf(this.e))) { + throw new RuntimeException("Duplicate stat id: \"" + ((Statistic) StatisticList.a.get(Integer.valueOf(this.e))).f + "\" and \"" + this.f + "\" at id " + this.e); + } else { + StatisticList.b.add(this); + StatisticList.a.put(Integer.valueOf(this.e), this); + this.h = AchievementMap.a(this.e); + return this; + } + } + + public String toString() { + return this.f; + } +} diff --git a/src/main/java/net/minecraft/server/StatisticCollector.java b/src/main/java/net/minecraft/server/StatisticCollector.java new file mode 100644 index 0000000..3841a4e --- /dev/null +++ b/src/main/java/net/minecraft/server/StatisticCollector.java @@ -0,0 +1,16 @@ +package net.minecraft.server; + +public class StatisticCollector { + + private static StatisticStorage a = StatisticStorage.a(); + + public StatisticCollector() {} + + public static String a(String s) { + return a.a(s); + } + + public static String a(String s, Object... aobject) { + return a.a(s, aobject); + } +} diff --git a/src/main/java/net/minecraft/server/StatisticList.java b/src/main/java/net/minecraft/server/StatisticList.java new file mode 100644 index 0000000..d4b2af5 --- /dev/null +++ b/src/main/java/net/minecraft/server/StatisticList.java @@ -0,0 +1,179 @@ +package net.minecraft.server; + +import java.util.*; + +public class StatisticList { + + protected static Map a = new HashMap(); + public static List b = new ArrayList(); + public static List c = new ArrayList(); + public static List d = new ArrayList(); + public static List e = new ArrayList(); + public static Statistic f = (new CounterStatistic(1000, StatisticCollector.a("stat.startGame"))).e().d(); + public static Statistic g = (new CounterStatistic(1001, StatisticCollector.a("stat.createWorld"))).e().d(); + public static Statistic h = (new CounterStatistic(1002, StatisticCollector.a("stat.loadWorld"))).e().d(); + public static Statistic i = (new CounterStatistic(1003, StatisticCollector.a("stat.joinMultiplayer"))).e().d(); + public static Statistic j = (new CounterStatistic(1004, StatisticCollector.a("stat.leaveGame"))).e().d(); + public static Statistic k = (new CounterStatistic(1100, StatisticCollector.a("stat.playOneMinute"), Statistic.j)).e().d(); + public static Statistic l = (new CounterStatistic(2000, StatisticCollector.a("stat.walkOneCm"), Statistic.k)).e().d(); + public static Statistic m = (new CounterStatistic(2001, StatisticCollector.a("stat.swimOneCm"), Statistic.k)).e().d(); + public static Statistic n = (new CounterStatistic(2002, StatisticCollector.a("stat.fallOneCm"), Statistic.k)).e().d(); + public static Statistic o = (new CounterStatistic(2003, StatisticCollector.a("stat.climbOneCm"), Statistic.k)).e().d(); + public static Statistic p = (new CounterStatistic(2004, StatisticCollector.a("stat.flyOneCm"), Statistic.k)).e().d(); + public static Statistic q = (new CounterStatistic(2005, StatisticCollector.a("stat.diveOneCm"), Statistic.k)).e().d(); + public static Statistic r = (new CounterStatistic(2006, StatisticCollector.a("stat.minecartOneCm"), Statistic.k)).e().d(); + public static Statistic s = (new CounterStatistic(2007, StatisticCollector.a("stat.boatOneCm"), Statistic.k)).e().d(); + public static Statistic t = (new CounterStatistic(2008, StatisticCollector.a("stat.pigOneCm"), Statistic.k)).e().d(); + public static Statistic u = (new CounterStatistic(2010, StatisticCollector.a("stat.jump"))).e().d(); + public static Statistic v = (new CounterStatistic(2011, StatisticCollector.a("stat.drop"))).e().d(); + public static Statistic w = (new CounterStatistic(2020, StatisticCollector.a("stat.damageDealt"))).d(); + public static Statistic x = (new CounterStatistic(2021, StatisticCollector.a("stat.damageTaken"))).d(); + public static Statistic y = (new CounterStatistic(2022, StatisticCollector.a("stat.deaths"))).d(); + public static Statistic z = (new CounterStatistic(2023, StatisticCollector.a("stat.mobKills"))).d(); + public static Statistic A = (new CounterStatistic(2024, StatisticCollector.a("stat.playerKills"))).d(); + public static Statistic B = (new CounterStatistic(2025, StatisticCollector.a("stat.fishCaught"))).d(); + public static Statistic[] C = a("stat.mineBlock", 16777216); + public static Statistic[] D; + public static Statistic[] E; + public static Statistic[] F; + private static boolean G; + private static boolean H; + + public StatisticList() {} + + public static void a() {} + + public static void b() { + E = a(E, "stat.useItem", 16908288, 0, Block.byId.length); + F = b(F, "stat.breakItem", 16973824, 0, Block.byId.length); + G = true; + d(); + } + + public static void c() { + E = a(E, "stat.useItem", 16908288, Block.byId.length, 32000); + F = b(F, "stat.breakItem", 16973824, Block.byId.length, 32000); + H = true; + d(); + } + + public static void d() { + if (G && H) { + HashSet hashset = new HashSet(); + Iterator iterator = CraftingManager.getInstance().b().iterator(); + + while (iterator.hasNext()) { + CraftingRecipe craftingrecipe = (CraftingRecipe) iterator.next(); + + hashset.add(Integer.valueOf(craftingrecipe.b().id)); + } + + iterator = FurnaceRecipes.getInstance().b().values().iterator(); + + while (iterator.hasNext()) { + ItemStack itemstack = (ItemStack) iterator.next(); + + hashset.add(Integer.valueOf(itemstack.id)); + } + + D = new Statistic[32000]; + iterator = hashset.iterator(); + + while (iterator.hasNext()) { + Integer integer = (Integer) iterator.next(); + + if (Item.byId[integer.intValue()] != null) { + String s = StatisticCollector.a("stat.craftItem", new Object[] { Item.byId[integer.intValue()].j()}); + + D[integer.intValue()] = (new CraftingStatistic(16842752 + integer.intValue(), s, integer.intValue())).d(); + } + } + + a(D); + } + } + + private static Statistic[] a(String s, int i) { + Statistic[] astatistic = new Statistic[256]; + + for (int j = 0; j < 256; ++j) { + if (Block.byId[j] != null && Block.byId[j].m()) { + String s1 = StatisticCollector.a(s, new Object[] { Block.byId[j].k()}); + + astatistic[j] = (new CraftingStatistic(i + j, s1, j)).d(); + e.add((CraftingStatistic) astatistic[j]); + } + } + + a(astatistic); + return astatistic; + } + + private static Statistic[] a(Statistic[] astatistic, String s, int i, int j, int k) { + if (astatistic == null) { + astatistic = new Statistic[32000]; + } + + for (int l = j; l < k; ++l) { + if (Item.byId[l] != null) { + String s1 = StatisticCollector.a(s, new Object[] { Item.byId[l].j()}); + + astatistic[l] = (new CraftingStatistic(i + l, s1, l)).d(); + if (l >= Block.byId.length) { + d.add((CraftingStatistic) astatistic[l]); + } + } + } + + a(astatistic); + return astatistic; + } + + private static Statistic[] b(Statistic[] astatistic, String s, int i, int j, int k) { + if (astatistic == null) { + astatistic = new Statistic[32000]; + } + + for (int l = j; l < k; ++l) { + if (Item.byId[l] != null && Item.byId[l].f()) { + String s1 = StatisticCollector.a(s, new Object[] { Item.byId[l].j()}); + + astatistic[l] = (new CraftingStatistic(i + l, s1, l)).d(); + } + } + + a(astatistic); + return astatistic; + } + + private static void a(Statistic[] astatistic) { + a(astatistic, Block.STATIONARY_WATER.id, Block.WATER.id); + a(astatistic, Block.STATIONARY_LAVA.id, Block.STATIONARY_LAVA.id); + a(astatistic, Block.JACK_O_LANTERN.id, Block.PUMPKIN.id); + a(astatistic, Block.BURNING_FURNACE.id, Block.FURNACE.id); + a(astatistic, Block.GLOWING_REDSTONE_ORE.id, Block.REDSTONE_ORE.id); + a(astatistic, Block.DIODE_ON.id, Block.DIODE_OFF.id); + a(astatistic, Block.REDSTONE_TORCH_ON.id, Block.REDSTONE_TORCH_OFF.id); + a(astatistic, Block.RED_MUSHROOM.id, Block.BROWN_MUSHROOM.id); + a(astatistic, Block.DOUBLE_STEP.id, Block.STEP.id); + a(astatistic, Block.GRASS.id, Block.DIRT.id); + a(astatistic, Block.SOIL.id, Block.DIRT.id); + } + + private static void a(Statistic[] astatistic, int i, int j) { + if (astatistic[i] != null && astatistic[j] == null) { + astatistic[j] = astatistic[i]; + } else { + b.remove(astatistic[i]); + e.remove(astatistic[i]); + c.remove(astatistic[i]); + astatistic[i] = astatistic[j]; + } + } + + static { + AchievementList.a(); + G = false; + H = false; + } +} diff --git a/src/main/java/net/minecraft/server/StatisticStorage.java b/src/main/java/net/minecraft/server/StatisticStorage.java new file mode 100644 index 0000000..1f8a08a --- /dev/null +++ b/src/main/java/net/minecraft/server/StatisticStorage.java @@ -0,0 +1,33 @@ +package net.minecraft.server; + +import java.io.IOException; +import java.util.Properties; + +public class StatisticStorage { + + private static StatisticStorage a = new StatisticStorage(); + private Properties b = new Properties(); + + private StatisticStorage() { + try { + this.b.load(StatisticStorage.class.getResourceAsStream("/lang/en_US.lang")); + this.b.load(StatisticStorage.class.getResourceAsStream("/lang/stats_US.lang")); + } catch (IOException ioexception) { + ioexception.printStackTrace(); + } + } + + public static StatisticStorage a() { + return a; + } + + public String a(String s) { + return this.b.getProperty(s, s); + } + + public String a(String s, Object... aobject) { + String s1 = this.b.getProperty(s, s); + + return String.format(s1, aobject); + } +} diff --git a/src/main/java/net/minecraft/server/StepSound.java b/src/main/java/net/minecraft/server/StepSound.java new file mode 100644 index 0000000..8a2a3f8 --- /dev/null +++ b/src/main/java/net/minecraft/server/StepSound.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +public class StepSound { + + public final String a; + public final float b; + public final float c; + + public StepSound(String s, float f, float f1) { + this.a = s; + this.b = f; + this.c = f1; + } + + public float getVolume1() { + return this.b; + } + + public float getVolume2() { + return this.c; + } + + public String getName() { + return "step." + this.a; + } +} diff --git a/src/main/java/net/minecraft/server/StepSoundSand.java b/src/main/java/net/minecraft/server/StepSoundSand.java new file mode 100644 index 0000000..a3b7edd --- /dev/null +++ b/src/main/java/net/minecraft/server/StepSoundSand.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +final class StepSoundSand extends StepSound { + + StepSoundSand(String s, float f, float f1) { + super(s, f, f1); + } +} diff --git a/src/main/java/net/minecraft/server/StepSoundStone.java b/src/main/java/net/minecraft/server/StepSoundStone.java new file mode 100644 index 0000000..4fd2eeb --- /dev/null +++ b/src/main/java/net/minecraft/server/StepSoundStone.java @@ -0,0 +1,8 @@ +package net.minecraft.server; + +final class StepSoundStone extends StepSound { + + StepSoundStone(String s, float f, float f1) { + super(s, f, f1); + } +} diff --git a/src/main/java/net/minecraft/server/ThreadCommandReader.java b/src/main/java/net/minecraft/server/ThreadCommandReader.java new file mode 100644 index 0000000..9626fa1 --- /dev/null +++ b/src/main/java/net/minecraft/server/ThreadCommandReader.java @@ -0,0 +1,35 @@ +package net.minecraft.server; + +import java.io.IOException; + +public class ThreadCommandReader extends Thread { + + final MinecraftServer server; + + public ThreadCommandReader(MinecraftServer minecraftserver) { + this.server = minecraftserver; + } + + public void run() { + jline.ConsoleReader bufferedreader = this.server.reader; // CraftBukkit + String s = null; + + try { + // CraftBukkit start - JLine disabling compatibility + while (!this.server.isStopped && MinecraftServer.isRunning(this.server)) { + if (org.bukkit.craftbukkit.Main.useJline) { + s = bufferedreader.readLine(">", null); + } else { + s = bufferedreader.readLine(); + } + if (s != null) { + this.server.issueCommand(s, this.server); + } + // CraftBukkit end + } + } catch (IOException ioexception) { + // CraftBukkit + java.util.logging.Logger.getLogger(ThreadCommandReader.class.getName()).log(java.util.logging.Level.SEVERE, null, ioexception); + } + } +} diff --git a/src/main/java/net/minecraft/server/ThreadLoginVerifier.java b/src/main/java/net/minecraft/server/ThreadLoginVerifier.java new file mode 100644 index 0000000..e56368f --- /dev/null +++ b/src/main/java/net/minecraft/server/ThreadLoginVerifier.java @@ -0,0 +1,71 @@ +package net.minecraft.server; + +import com.projectposeidon.johnymuffin.LoginProcessHandler; +import com.legacyminecraft.poseidon.util.SessionAPI; +import org.bukkit.craftbukkit.CraftServer; + +import java.net.InetSocketAddress; + +// CraftBukkit start +// CraftBukkit end + +public class ThreadLoginVerifier extends Thread { + + final Packet1Login loginPacket; + + final NetLoginHandler netLoginHandler; + + final LoginProcessHandler loginProcessHandler; //Project Poseidon + + // CraftBukkit start + CraftServer server; + + public ThreadLoginVerifier(LoginProcessHandler loginProcessHandler, NetLoginHandler netloginhandler, Packet1Login packet1login, CraftServer server) { + this.server = server; + // CraftBukkit end + this.loginProcessHandler = loginProcessHandler; //Project Poseidon + + this.netLoginHandler = netloginhandler; + this.loginPacket = packet1login; + } + + private String getIP() { + return ((InetSocketAddress) netLoginHandler.networkManager.getSocketAddress()).getAddress().getHostAddress(); + } + + public void run() { + try { + SessionAPI.hasJoined(loginPacket.name, netLoginHandler.getServerID(), getIP(), (int responseCode, String username, String uuid, String ip) -> + { + boolean checkIP = ip == "127.0.0.1" || ip == "localhost"; + + // make sure the request didn't fail (-1), and the response wasn't empty (204) + if (responseCode != -1 && responseCode != 204) + { + // make sure username and ip match up (docs say username is case insensitive https://wiki.vg/Protocol_Encryption#Server) + if (username.equalsIgnoreCase(loginPacket.name)) + { + if (checkIP) + { + if (ip == getIP()) + { + loginProcessHandler.userMojangSessionVerified(); + } + } else { + loginProcessHandler.userMojangSessionVerified(); + } + } else { + loginProcessHandler.cancelLoginProcess("Failed to verify username!"); + } + } else { + //TODO: should this message be different? -moderator_man + loginProcessHandler.cancelLoginProcess("Failed to verify username!"); + } + }); + } catch (Exception exception) { + //this.netLoginHandler.disconnect("Failed to verify username! [internal error " + exception + "]"); + this.loginProcessHandler.cancelLoginProcess("Failed to verify username! [internal error " + exception + "]"); + exception.printStackTrace(); + } + } +} diff --git a/src/main/java/net/minecraft/server/ThreadMonitorConnection.java b/src/main/java/net/minecraft/server/ThreadMonitorConnection.java new file mode 100644 index 0000000..f9745c9 --- /dev/null +++ b/src/main/java/net/minecraft/server/ThreadMonitorConnection.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +class ThreadMonitorConnection extends Thread { + + final NetworkManager a; + + ThreadMonitorConnection(NetworkManager networkmanager) { + this.a = networkmanager; + } + + public void run() { + try { + Thread.sleep(2000L); + if (NetworkManager.a(this.a)) { + NetworkManager.h(this.a).interrupt(); + this.a.a("disconnect.closed", new Object[0]); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } +} diff --git a/src/main/java/net/minecraft/server/ThreadServerApplication.java b/src/main/java/net/minecraft/server/ThreadServerApplication.java new file mode 100644 index 0000000..4e49fae --- /dev/null +++ b/src/main/java/net/minecraft/server/ThreadServerApplication.java @@ -0,0 +1,15 @@ +package net.minecraft.server; + +public final class ThreadServerApplication extends Thread { + + final MinecraftServer a; + + public ThreadServerApplication(String s, MinecraftServer minecraftserver) { + super(s); + this.a = minecraftserver; + } + + public void run() { + this.a.run(); + } +} diff --git a/src/main/java/net/minecraft/server/ThreadSleepForever.java b/src/main/java/net/minecraft/server/ThreadSleepForever.java new file mode 100644 index 0000000..1aa96d7 --- /dev/null +++ b/src/main/java/net/minecraft/server/ThreadSleepForever.java @@ -0,0 +1,24 @@ +package net.minecraft.server; + +public class ThreadSleepForever extends Thread { + + final MinecraftServer a; + + public ThreadSleepForever(MinecraftServer minecraftserver) { + this.a = minecraftserver; + this.setDaemon(true); + this.start(); + } + + public void run() { + while (true) { + try { + while (true) { + Thread.sleep(2147483647L); + } + } catch (InterruptedException interruptedexception) { + ; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java new file mode 100644 index 0000000..64f1f3c --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntity.java @@ -0,0 +1,106 @@ +package net.minecraft.server; + +import java.util.HashMap; +import java.util.Map; + +public class TileEntity { + + private static Map a = new HashMap(); + private static Map b = new HashMap(); + public World world; + public int x; + public int y; + public int z; + protected boolean h; + + public TileEntity() {} + + private static void a(Class oclass, String s) { + if (b.containsKey(s)) { + throw new IllegalArgumentException("Duplicate id: " + s); + } else { + a.put(s, oclass); + b.put(oclass, s); + } + } + + public void a(NBTTagCompound nbttagcompound) { + this.x = nbttagcompound.e("x"); + this.y = nbttagcompound.e("y"); + this.z = nbttagcompound.e("z"); + } + + public void b(NBTTagCompound nbttagcompound) { + String s = (String) b.get(this.getClass()); + + if (s == null) { + throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!"); + } else { + nbttagcompound.setString("id", s); + nbttagcompound.a("x", this.x); + nbttagcompound.a("y", this.y); + nbttagcompound.a("z", this.z); + } + } + + public void g_() {} + + public static TileEntity c(NBTTagCompound nbttagcompound) { + TileEntity tileentity = null; + + try { + Class oclass = (Class) a.get(nbttagcompound.getString("id")); + + if (oclass != null) { + tileentity = (TileEntity) oclass.newInstance(); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + + if (tileentity != null) { + tileentity.a(nbttagcompound); + } else { + System.out.println("Skipping TileEntity with id " + nbttagcompound.getString("id")); + } + + return tileentity; + } + + public int e() { + return this.world.getData(this.x, this.y, this.z); + } + + public void update() { + if (this.world != null) { + this.world.b(this.x, this.y, this.z, this); + } + } + + public Packet f() { + return null; + } + + public boolean g() { + return this.h; + } + + public void h() { + this.h = true; + } + + public void j() { + this.h = false; + } + + static { + a(TileEntityFurnace.class, "Furnace"); + a(TileEntityChest.class, "Chest"); + a(TileEntityRecordPlayer.class, "RecordPlayer"); + a(TileEntityDispenser.class, "Trap"); + a(TileEntitySign.class, "Sign"); + a(TileEntityMobSpawner.class, "MobSpawner"); + a(TileEntityNote.class, "Music"); + a(TileEntityPiston.class, "Piston"); + } +} diff --git a/src/main/java/net/minecraft/server/TileEntityChest.java b/src/main/java/net/minecraft/server/TileEntityChest.java new file mode 100644 index 0000000..dbf08c1 --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntityChest.java @@ -0,0 +1,99 @@ +package net.minecraft.server; + +public class TileEntityChest extends TileEntity implements IInventory { + + private ItemStack[] items = new ItemStack[27]; // CraftBukkit + + // CraftBukkit start + public ItemStack[] getContents() { + return this.items; + } + // CraftBukkit end + + public TileEntityChest() {} + + public int getSize() { + return 27; + } + + public ItemStack getItem(int i) { + return this.items[i]; + } + + public ItemStack splitStack(int i, int j) { + if (this.items[i] != null) { + ItemStack itemstack; + + if (this.items[i].count <= j) { + itemstack = this.items[i]; + this.items[i] = null; + this.update(); + return itemstack; + } else { + itemstack = this.items[i].a(j); + if (this.items[i].count == 0) { + this.items[i] = null; + } + + this.update(); + return itemstack; + } + } else { + return null; + } + } + + public void setItem(int i, ItemStack itemstack) { + this.items[i] = itemstack; + if (itemstack != null && itemstack.count > this.getMaxStackSize()) { + itemstack.count = this.getMaxStackSize(); + } + + this.update(); + } + + public String getName() { + return "Chest"; + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + NBTTagList nbttaglist = nbttagcompound.l("Items"); + + this.items = new ItemStack[this.getSize()]; + + for (int i = 0; i < nbttaglist.c(); ++i) { + NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttaglist.a(i); + int j = nbttagcompound1.c("Slot") & 255; + + if (j >= 0 && j < this.items.length) { + this.items[j] = new ItemStack(nbttagcompound1); + } + } + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + NBTTagList nbttaglist = new NBTTagList(); + + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.a("Slot", (byte) i); + this.items[i].a(nbttagcompound1); + nbttaglist.a((NBTBase) nbttagcompound1); + } + } + + nbttagcompound.a("Items", (NBTBase) nbttaglist); + } + + public int getMaxStackSize() { + return 64; + } + + public boolean a_(EntityHuman entityhuman) { + return this.world.getTileEntity(this.x, this.y, this.z) != this ? false : entityhuman.e((double) this.x + 0.5D, (double) this.y + 0.5D, (double) this.z + 0.5D) <= 64.0D; + } +} diff --git a/src/main/java/net/minecraft/server/TileEntityDispenser.java b/src/main/java/net/minecraft/server/TileEntityDispenser.java new file mode 100644 index 0000000..7a9aab7 --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntityDispenser.java @@ -0,0 +1,129 @@ +package net.minecraft.server; + +import java.util.Random; + +public class TileEntityDispenser extends TileEntity implements IInventory { + + private ItemStack[] items = new ItemStack[9]; + private Random b = new Random(); + + // CraftBukkit start + public ItemStack[] getContents() { + return this.items; + } + // CraftBukkit end + + public TileEntityDispenser() {} + + public int getSize() { + return 9; + } + + public ItemStack getItem(int i) { + return this.items[i]; + } + + public ItemStack splitStack(int i, int j) { + if (this.items[i] != null) { + ItemStack itemstack; + + if (this.items[i].count <= j) { + itemstack = this.items[i]; + this.items[i] = null; + this.update(); + return itemstack; + } else { + itemstack = this.items[i].a(j); + if (this.items[i].count == 0) { + this.items[i] = null; + } + + this.update(); + return itemstack; + } + } else { + return null; + } + } + + // CraftBukkit - change signature + public int findDispenseSlot() { + int i = -1; + int j = 1; + + for (int k = 0; k < this.items.length; ++k) { + if (this.items[k] != null && this.b.nextInt(j++) == 0) { + if (this.items[k].count == 0) continue; // CraftBukkit + i = k; + } + } + + // CraftBukkit start + return i; + } + + public ItemStack b() { + int i = this.findDispenseSlot(); + // CraftBukkit end + + if (i >= 0) { + return this.splitStack(i, 1); + } else { + return null; + } + } + + public void setItem(int i, ItemStack itemstack) { + this.items[i] = itemstack; + if (itemstack != null && itemstack.count > this.getMaxStackSize()) { + itemstack.count = this.getMaxStackSize(); + } + + this.update(); + } + + public String getName() { + return "Trap"; + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + NBTTagList nbttaglist = nbttagcompound.l("Items"); + + this.items = new ItemStack[this.getSize()]; + + for (int i = 0; i < nbttaglist.c(); ++i) { + NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttaglist.a(i); + int j = nbttagcompound1.c("Slot") & 255; + + if (j >= 0 && j < this.items.length) { + this.items[j] = new ItemStack(nbttagcompound1); + } + } + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + NBTTagList nbttaglist = new NBTTagList(); + + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.a("Slot", (byte) i); + this.items[i].a(nbttagcompound1); + nbttaglist.a((NBTBase) nbttagcompound1); + } + } + + nbttagcompound.a("Items", (NBTBase) nbttaglist); + } + + public int getMaxStackSize() { + return 64; + } + + public boolean a_(EntityHuman entityhuman) { + return this.world.getTileEntity(this.x, this.y, this.z) != this ? false : entityhuman.e((double) this.x + 0.5D, (double) this.y + 0.5D, (double) this.z + 0.5D) <= 64.0D; + } +} diff --git a/src/main/java/net/minecraft/server/TileEntityFurnace.java b/src/main/java/net/minecraft/server/TileEntityFurnace.java new file mode 100644 index 0000000..1503cbd --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntityFurnace.java @@ -0,0 +1,248 @@ +package net.minecraft.server; + +// CraftBukkit start +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +// CraftBukkit end + +public class TileEntityFurnace extends TileEntity implements IInventory { + + private ItemStack[] items = new ItemStack[3]; + public int burnTime = 0; + public int ticksForCurrentFuel = 0; + public int cookTime = 0; + + // CraftBukkit start + private int lastTick = (int) (System.currentTimeMillis() / 50); + public ItemStack[] getContents() { + return this.items; + } + // CraftBukkit end + + public TileEntityFurnace() {} + + public int getSize() { + return this.items.length; + } + + public ItemStack getItem(int i) { + return this.items[i]; + } + + public ItemStack splitStack(int i, int j) { + if (this.items[i] != null) { + ItemStack itemstack; + + if (this.items[i].count <= j) { + itemstack = this.items[i]; + this.items[i] = null; + return itemstack; + } else { + itemstack = this.items[i].a(j); + if (this.items[i].count == 0) { + this.items[i] = null; + } + + return itemstack; + } + } else { + return null; + } + } + + public void setItem(int i, ItemStack itemstack) { + this.items[i] = itemstack; + if (itemstack != null && itemstack.count > this.getMaxStackSize()) { + itemstack.count = this.getMaxStackSize(); + } + } + + public String getName() { + return "Furnace"; + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + NBTTagList nbttaglist = nbttagcompound.l("Items"); + + this.items = new ItemStack[this.getSize()]; + + for (int i = 0; i < nbttaglist.c(); ++i) { + NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttaglist.a(i); + byte b0 = nbttagcompound1.c("Slot"); + + if (b0 >= 0 && b0 < this.items.length) { + this.items[b0] = new ItemStack(nbttagcompound1); + } + } + + this.burnTime = nbttagcompound.d("BurnTime"); + this.cookTime = nbttagcompound.d("CookTime"); + this.ticksForCurrentFuel = this.fuelTime(this.items[1]); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("BurnTime", (short) this.burnTime); + nbttagcompound.a("CookTime", (short) this.cookTime); + NBTTagList nbttaglist = new NBTTagList(); + + for (int i = 0; i < this.items.length; ++i) { + if (this.items[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.a("Slot", (byte) i); + this.items[i].a(nbttagcompound1); + nbttaglist.a((NBTBase) nbttagcompound1); + } + } + + nbttagcompound.a("Items", (NBTBase) nbttaglist); + } + + public int getMaxStackSize() { + return 64; + } + + public boolean isBurning() { + return this.burnTime > 0; + } + + public void g_() { + boolean flag = this.burnTime > 0; + boolean flag1 = false; + + // CraftBukkit start + int currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit + int elapsedTicks = currentTick - this.lastTick; + this.lastTick = currentTick; + + // CraftBukkit - moved from below + if (this.isBurning() && this.canBurn()) { + this.cookTime += elapsedTicks; + if (this.cookTime >= 200) { + this.cookTime %= 200; + this.burn(); + flag1 = true; + } + } else { + this.cookTime = 0; + } + // CraftBukkit end + + if (this.burnTime > 0) { + this.burnTime -= elapsedTicks; // CraftBukkit + } + + if (!this.world.isStatic) { + // CraftBukkit start - handle multiple elapsed ticks + if (this.burnTime <= 0 && this.canBurn() && this.items[1] != null) { // CraftBukkit - == to <= + CraftItemStack fuel = new CraftItemStack(this.items[1]); + + FurnaceBurnEvent furnaceBurnEvent = new FurnaceBurnEvent(this.world.getWorld().getBlockAt(this.x, this.y, this.z), fuel, this.fuelTime(this.items[1])); + this.world.getServer().getPluginManager().callEvent(furnaceBurnEvent); + + if (furnaceBurnEvent.isCancelled()) { + return; + } + + this.ticksForCurrentFuel = furnaceBurnEvent.getBurnTime(); + this.burnTime += this.ticksForCurrentFuel; + if (this.burnTime > 0 && furnaceBurnEvent.isBurning()) { + // CraftBukkit end + flag1 = true; + if (this.items[1] != null) { + --this.items[1].count; + if (this.items[1].count == 0) { + this.items[1] = null; + } + } + } + } + + /* CraftBukkit start - moved up + if (this.f() && this.process()) { + ++this.cookTime; + if (this.cookTime == 200) { + this.cookTime = 0; + this.burn(); + flag1 = true; + } + } else { + this.cookTime = 0; + } + // CraftBukkit end */ + + if (flag != this.burnTime > 0) { + flag1 = true; + BlockFurnace.a(this.burnTime > 0, this.world, this.x, this.y, this.z); + } + } + + if (flag1) { + this.update(); + } + } + + private boolean canBurn() { + if (this.items[0] == null) { + return false; + } else { + ItemStack itemstack = FurnaceRecipes.getInstance().a(this.items[0].getItem().id); + + // CraftBukkit - consider resultant count instead of current count + return itemstack == null ? false : (this.items[2] == null ? true : (!this.items[2].doMaterialsMatch(itemstack) ? false : (this.items[2].count + itemstack.count <= this.getMaxStackSize() && this.items[2].count < this.items[2].getMaxStackSize() ? true : this.items[2].count + itemstack.count <= itemstack.getMaxStackSize()))); + } + } + + public void burn() { + if (this.canBurn()) { + ItemStack itemstack = FurnaceRecipes.getInstance().a(this.items[0].getItem().id); + + // CraftBukkit start + CraftItemStack source = new CraftItemStack(this.items[0]); + CraftItemStack result = new CraftItemStack(itemstack.cloneItemStack()); + + FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(this.world.getWorld().getBlockAt(this.x, this.y, this.z), source, result); + this.world.getServer().getPluginManager().callEvent(furnaceSmeltEvent); + + if (furnaceSmeltEvent.isCancelled()) { + return; + } + + org.bukkit.inventory.ItemStack oldResult = furnaceSmeltEvent.getResult(); + ItemStack newResult = new ItemStack(oldResult.getTypeId(), oldResult.getAmount(), oldResult.getDurability()); + itemstack = newResult; + + if (this.items[2] == null) { + this.items[2] = itemstack.cloneItemStack(); + } else if (this.items[2].id == itemstack.id) { + // CraftBukkit - compare damage too + if (this.items[2].damage == itemstack.damage) { + this.items[2].count += itemstack.count; + } + // CraftBukkit end + } + + --this.items[0].count; + if (this.items[0].count <= 0) { + this.items[0] = null; + } + } + } + + private int fuelTime(ItemStack itemstack) { + if (itemstack == null) { + return 0; + } else { + int i = itemstack.getItem().id; + + return i < 256 && Block.byId[i].material == Material.WOOD ? 300 : (i == Item.STICK.id ? 100 : (i == Item.COAL.id ? 1600 : (i == Item.LAVA_BUCKET.id ? 20000 : (i == Block.SAPLING.id ? 100 : 0)))); + } + } + + public boolean a_(EntityHuman entityhuman) { + return this.world.getTileEntity(this.x, this.y, this.z) != this ? false : entityhuman.e((double) this.x + 0.5D, (double) this.y + 0.5D, (double) this.z + 0.5D) <= 64.0D; + } +} diff --git a/src/main/java/net/minecraft/server/TileEntityMobSpawner.java b/src/main/java/net/minecraft/server/TileEntityMobSpawner.java new file mode 100644 index 0000000..349b220 --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntityMobSpawner.java @@ -0,0 +1,136 @@ +package net.minecraft.server; + +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; + +import java.util.List; + +public class TileEntityMobSpawner extends TileEntity { + + public int spawnDelay = -1; + public String mobName = "Pig"; // CraftBukkit - private -> public + public double b; + public double c = 0.0D; + + private static boolean poseidonAreaLimit = PoseidonConfig.getInstance().getConfigBoolean("world.settings.mob-spawner-area-limit.enable"); + private static int poseidonAreaLimitRadius = PoseidonConfig.getInstance().getConfigInteger("world.settings.mob-spawner-area-limit.limit"); + private static int poseidonChunkRadius = PoseidonConfig.getInstance().getConfigInteger("world.settings.mob-spawner-area-limit.chunk-radius"); + + public TileEntityMobSpawner() { + this.spawnDelay = 20; + } + + public void a(String s) { + this.mobName = s; + } + + public boolean a() { + return this.world.a((double) this.x + 0.5D, (double) this.y + 0.5D, (double) this.z + 0.5D, 16.0D) != null; + } + + public void g_() { + this.c = this.b; + if (this.a()) { + double d0 = (double) ((float) this.x + this.world.random.nextFloat()); + double d1 = (double) ((float) this.y + this.world.random.nextFloat()); + double d2 = (double) ((float) this.z + this.world.random.nextFloat()); + + this.world.a("smoke", d0, d1, d2, 0.0D, 0.0D, 0.0D); + this.world.a("flame", d0, d1, d2, 0.0D, 0.0D, 0.0D); + + for (this.b += (double) (1000.0F / ((float) this.spawnDelay + 200.0F)); this.b > 360.0D; this.c -= 360.0D) { + this.b -= 360.0D; + } + + if (!this.world.isStatic) { + if (this.spawnDelay == -1) { + this.c(); + } + + if (this.spawnDelay > 0) { + --this.spawnDelay; + return; + } + + byte b0 = 4; + + for (int i = 0; i < b0; ++i) { + EntityLiving entityliving = (EntityLiving) ((EntityLiving) EntityTypes.a(this.mobName, this.world)); + + if (entityliving == null) { + return; + } + + // CraftBukkit start - The world we're spawning in accepts this creature + boolean isAnimal = entityliving instanceof EntityAnimal || entityliving instanceof EntityWaterAnimal; + if ((isAnimal && !this.world.allowAnimals) || (!isAnimal && !this.world.allowMonsters)) { + return; + } + // CraftBukkit end + + + // Check mob cap within the spawning radius + int j = this.world.a(entityliving.getClass(), AxisAlignedBB.b((double) this.x, (double) this.y, (double) this.z, (double) (this.x + 1), (double) (this.y + 1), (double) (this.z + 1)).b(8.0D, 4.0D, 8.0D)).size(); + + if (j >= 6) { + this.c(); + return; + } + + //Poseidon Start - Ensure the mob cound of the specific type of mob is under the defined limit within the area + if(poseidonAreaLimit) { + double chunkSize = 16.0D; + AxisAlignedBB searchArea = AxisAlignedBB.b(this.x - poseidonChunkRadius * chunkSize, 0.0D, this.z - poseidonChunkRadius * chunkSize, this.x + poseidonChunkRadius * chunkSize, 128, this.z + poseidonChunkRadius * chunkSize); + List existingEntities = this.world.a(entityliving.getClass(), searchArea); + if (existingEntities.size() >= poseidonAreaLimitRadius) { + this.c(); + return; + } + } + //Poseidon End + + if (entityliving != null) { + double d3 = (double) this.x + (this.world.random.nextDouble() - this.world.random.nextDouble()) * 4.0D; + double d4 = (double) (this.y + this.world.random.nextInt(3) - 1); + double d5 = (double) this.z + (this.world.random.nextDouble() - this.world.random.nextDouble()) * 4.0D; + + entityliving.setPositionRotation(d3, d4, d5, this.world.random.nextFloat() * 360.0F, 0.0F); + if (entityliving.d()) { + // CraftBukkit - added a reason for spawning this creature + this.world.addEntity(entityliving, SpawnReason.SPAWNER); + + for (int k = 0; k < 20; ++k) { + d0 = (double) this.x + 0.5D + ((double) this.world.random.nextFloat() - 0.5D) * 2.0D; + d1 = (double) this.y + 0.5D + ((double) this.world.random.nextFloat() - 0.5D) * 2.0D; + d2 = (double) this.z + 0.5D + ((double) this.world.random.nextFloat() - 0.5D) * 2.0D; + this.world.a("smoke", d0, d1, d2, 0.0D, 0.0D, 0.0D); + this.world.a("flame", d0, d1, d2, 0.0D, 0.0D, 0.0D); + } + + entityliving.S(); + this.c(); + } + } + } + } + + super.g_(); + } + } + + private void c() { + this.spawnDelay = 200 + this.world.random.nextInt(600); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.mobName = nbttagcompound.getString("EntityId"); + this.spawnDelay = nbttagcompound.d("Delay"); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.setString("EntityId", this.mobName); + nbttagcompound.a("Delay", (short) this.spawnDelay); + } +} diff --git a/src/main/java/net/minecraft/server/TileEntityNote.java b/src/main/java/net/minecraft/server/TileEntityNote.java new file mode 100644 index 0000000..9b5ea77 --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntityNote.java @@ -0,0 +1,56 @@ +package net.minecraft.server; + +public class TileEntityNote extends TileEntity { + + public byte note = 0; + public boolean b = false; + + public TileEntityNote() {} + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("note", this.note); + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.note = nbttagcompound.c("note"); + if (this.note < 0) { + this.note = 0; + } + + if (this.note > 24) { + this.note = 24; + } + } + + public void a() { + this.note = (byte) ((this.note + 1) % 25); + this.update(); + } + + public void play(World world, int i, int j, int k) { + if (world.getMaterial(i, j + 1, k) == Material.AIR) { + Material material = world.getMaterial(i, j - 1, k); + byte b0 = 0; + + if (material == Material.STONE) { + b0 = 1; + } + + if (material == Material.SAND) { + b0 = 2; + } + + if (material == Material.SHATTERABLE) { + b0 = 3; + } + + if (material == Material.WOOD) { + b0 = 4; + } + + world.playNote(i, j, k, b0, this.note); + } + } +} diff --git a/src/main/java/net/minecraft/server/TileEntityPiston.java b/src/main/java/net/minecraft/server/TileEntityPiston.java new file mode 100644 index 0000000..15d885f --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntityPiston.java @@ -0,0 +1,130 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TileEntityPiston extends TileEntity { + + private int a; + private int b; + private int c; + private boolean i; + private boolean j; + private float k; + private float l; + private static List m = new ArrayList(); + + public TileEntityPiston() {} + + public TileEntityPiston(int i, int j, int k, boolean flag, boolean flag1) { + this.a = i; + this.b = j; + this.c = k; + this.i = flag; + this.j = flag1; + } + + public int a() { + return this.a; + } + + public int e() { + return this.b; + } + + public boolean c() { + return this.i; + } + + public int d() { + return this.c; + } + + public float a(float f) { + if (f > 1.0F) { + f = 1.0F; + } + + return this.l + (this.k - this.l) * f; + } + + private void a(float f, float f1) { + if (!this.i) { + --f; + } else { + f = 1.0F - f; + } + + AxisAlignedBB axisalignedbb = Block.PISTON_MOVING.a(this.world, this.x, this.y, this.z, this.a, f, this.c); + + if (axisalignedbb != null) { + List list = this.world.b((Entity) null, axisalignedbb); + + if (!list.isEmpty()) { + m.addAll(list); + Iterator iterator = m.iterator(); + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); + + entity.move((double) (f1 * (float) PistonBlockTextures.b[this.c]), (double) (f1 * (float) PistonBlockTextures.c[this.c]), (double) (f1 * (float) PistonBlockTextures.d[this.c])); + } + + m.clear(); + } + } + } + + public void k() { + if (this.l < 1.0F) { + this.l = this.k = 1.0F; + this.world.o(this.x, this.y, this.z); + this.h(); + if (this.world.getTypeId(this.x, this.y, this.z) == Block.PISTON_MOVING.id) { + this.world.setTypeIdAndData(this.x, this.y, this.z, this.a, this.b); + } + } + } + + public void g_() { + // CraftBukkit + if (this.world == null) return; + this.l = this.k; + if (this.l >= 1.0F) { + this.a(1.0F, 0.25F); + this.world.o(this.x, this.y, this.z); + this.h(); + if (this.world.getTypeId(this.x, this.y, this.z) == Block.PISTON_MOVING.id) { + this.world.setTypeIdAndData(this.x, this.y, this.z, this.a, this.b); + } + } else { + this.k += 0.5F; + if (this.k >= 1.0F) { + this.k = 1.0F; + } + + if (this.i) { + this.a(this.k, this.k - this.l + 0.0625F); + } + } + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.a = nbttagcompound.e("blockId"); + this.b = nbttagcompound.e("blockData"); + this.c = nbttagcompound.e("facing"); + this.l = this.k = nbttagcompound.g("progress"); + this.i = nbttagcompound.m("extending"); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.a("blockId", this.a); + nbttagcompound.a("blockData", this.b); + nbttagcompound.a("facing", this.c); + nbttagcompound.a("progress", this.l); + nbttagcompound.a("extending", this.i); + } +} diff --git a/src/main/java/net/minecraft/server/TileEntityRecordPlayer.java b/src/main/java/net/minecraft/server/TileEntityRecordPlayer.java new file mode 100644 index 0000000..329e9b4 --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntityRecordPlayer.java @@ -0,0 +1,20 @@ +package net.minecraft.server; + +public class TileEntityRecordPlayer extends TileEntity { + + public int a; + + public TileEntityRecordPlayer() {} + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.a = nbttagcompound.e("Record"); + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + if (this.a > 0) { + nbttagcompound.a("Record", this.a); + } + } +} diff --git a/src/main/java/net/minecraft/server/TileEntitySign.java b/src/main/java/net/minecraft/server/TileEntitySign.java new file mode 100644 index 0000000..aef8a04 --- /dev/null +++ b/src/main/java/net/minecraft/server/TileEntitySign.java @@ -0,0 +1,69 @@ +package net.minecraft.server; + +public class TileEntitySign extends TileEntity { + + public String[] lines = new String[] { "", "", "", ""}; + public int b = -1; + private boolean isEditable = true; + private EntityHuman editingPlayer; // Poseidon + + public TileEntitySign() {} + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.setString("Text1", this.lines[0]); + nbttagcompound.setString("Text2", this.lines[1]); + nbttagcompound.setString("Text3", this.lines[2]); + nbttagcompound.setString("Text4", this.lines[3]); + } + + public void a(NBTTagCompound nbttagcompound) { + this.isEditable = false; + this.editingPlayer = null; // Poseidon + super.a(nbttagcompound); + + for (int i = 0; i < 4; ++i) { + this.lines[i] = nbttagcompound.getString("Text" + (i + 1)); + if (this.lines[i].length() > 15) { + this.lines[i] = this.lines[i].substring(0, 15); + } + } + } + + public Packet f() { + String[] astring = new String[4]; + + for (int i = 0; i < 4; ++i) { + astring[i] = this.lines[i]; + + // CraftBukkit start - limit sign text to 15 chars per line + if (this.lines[i].length() > 15) { + astring[i] = this.lines[i].substring(0, 15); + } + // CraftBukkit end + } + + return new Packet130UpdateSign(this.x, this.y, this.z, astring); + } + + public boolean a() { + return this.isEditable; + } + + public void a(boolean flag) { + this.isEditable = flag; + // Poseidon start - check if player editing sign is the same player who placed the sign + if (!flag) { + this.editingPlayer = null; + } + } + + public void setEditingPlayer(EntityHuman entityhuman) { + this.editingPlayer = entityhuman; + } + + public boolean isEditableBy(EntityHuman entityhuman) { + return this.isEditable && this.editingPlayer != null && this.editingPlayer.equals(entityhuman); + } + // Poseidon end +} diff --git a/src/main/java/net/minecraft/server/TimeCounter.java b/src/main/java/net/minecraft/server/TimeCounter.java new file mode 100644 index 0000000..746fbfc --- /dev/null +++ b/src/main/java/net/minecraft/server/TimeCounter.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +final class TimeCounter implements Counter { + + TimeCounter() {} +} diff --git a/src/main/java/net/minecraft/server/UnknownCounter.java b/src/main/java/net/minecraft/server/UnknownCounter.java new file mode 100644 index 0000000..ee119fe --- /dev/null +++ b/src/main/java/net/minecraft/server/UnknownCounter.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +final class UnknownCounter implements Counter { + + UnknownCounter() {} +} diff --git a/src/main/java/net/minecraft/server/Vec3D.java b/src/main/java/net/minecraft/server/Vec3D.java new file mode 100644 index 0000000..8eac3b7 --- /dev/null +++ b/src/main/java/net/minecraft/server/Vec3D.java @@ -0,0 +1,138 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +public class Vec3D { + + private static List d = new ArrayList(); + private static int e = 0; + public double a; + public double b; + public double c; + + public static Vec3D a(double d0, double d1, double d2) { + return new Vec3D(d0, d1, d2); + } + + public static void a() { + e = 0; + } + + public static Vec3D create(double d0, double d1, double d2) { + if (e >= d.size()) { + d.add(a(0.0D, 0.0D, 0.0D)); + } + + return ((Vec3D) d.get(e++)).e(d0, d1, d2); + } + + private Vec3D(double d0, double d1, double d2) { + if (d0 == -0.0D) { + d0 = 0.0D; + } + + if (d1 == -0.0D) { + d1 = 0.0D; + } + + if (d2 == -0.0D) { + d2 = 0.0D; + } + + this.a = d0; + this.b = d1; + this.c = d2; + } + + private Vec3D e(double d0, double d1, double d2) { + this.a = d0; + this.b = d1; + this.c = d2; + return this; + } + + public Vec3D b() { + double d0 = (double) MathHelper.a(this.a * this.a + this.b * this.b + this.c * this.c); + + return d0 < 1.0E-4D ? create(0.0D, 0.0D, 0.0D) : create(this.a / d0, this.b / d0, this.c / d0); + } + + public Vec3D add(double d0, double d1, double d2) { + return create(this.a + d0, this.b + d1, this.c + d2); + } + + public double a(Vec3D vec3d) { + double d0 = vec3d.a - this.a; + double d1 = vec3d.b - this.b; + double d2 = vec3d.c - this.c; + + return (double) MathHelper.a(d0 * d0 + d1 * d1 + d2 * d2); + } + + public double b(Vec3D vec3d) { + double d0 = vec3d.a - this.a; + double d1 = vec3d.b - this.b; + double d2 = vec3d.c - this.c; + + return d0 * d0 + d1 * d1 + d2 * d2; + } + + public double d(double d0, double d1, double d2) { + double d3 = d0 - this.a; + double d4 = d1 - this.b; + double d5 = d2 - this.c; + + return d3 * d3 + d4 * d4 + d5 * d5; + } + + public double c() { + return (double) MathHelper.a(this.a * this.a + this.b * this.b + this.c * this.c); + } + + public Vec3D a(Vec3D vec3d, double d0) { + double d1 = vec3d.a - this.a; + double d2 = vec3d.b - this.b; + double d3 = vec3d.c - this.c; + + if (d1 * d1 < 1.0000000116860974E-7D) { + return null; + } else { + double d4 = (d0 - this.a) / d1; + + return d4 >= 0.0D && d4 <= 1.0D ? create(this.a + d1 * d4, this.b + d2 * d4, this.c + d3 * d4) : null; + } + } + + public Vec3D b(Vec3D vec3d, double d0) { + double d1 = vec3d.a - this.a; + double d2 = vec3d.b - this.b; + double d3 = vec3d.c - this.c; + + if (d2 * d2 < 1.0000000116860974E-7D) { + return null; + } else { + double d4 = (d0 - this.b) / d2; + + return d4 >= 0.0D && d4 <= 1.0D ? create(this.a + d1 * d4, this.b + d2 * d4, this.c + d3 * d4) : null; + } + } + + public Vec3D c(Vec3D vec3d, double d0) { + double d1 = vec3d.a - this.a; + double d2 = vec3d.b - this.b; + double d3 = vec3d.c - this.c; + + if (d3 * d3 < 1.0000000116860974E-7D) { + return null; + } else { + double d4 = (d0 - this.c) / d3; + + return d4 >= 0.0D && d4 <= 1.0D ? create(this.a + d1 * d4, this.b + d2 * d4, this.c + d3 * d4) : null; + } + } + + public String toString() { + return "(" + this.a + ", " + this.b + ", " + this.c + ")"; + } +} diff --git a/src/main/java/net/minecraft/server/WatchableObject.java b/src/main/java/net/minecraft/server/WatchableObject.java new file mode 100644 index 0000000..8a62006 --- /dev/null +++ b/src/main/java/net/minecraft/server/WatchableObject.java @@ -0,0 +1,40 @@ +package net.minecraft.server; + +public class WatchableObject { + + private final int a; + private final int b; + private Object c; + private boolean d; + + public WatchableObject(int i, int j, Object object) { + this.b = j; + this.c = object; + this.a = i; + this.d = true; + } + + public int a() { + return this.b; + } + + public void a(Object object) { + this.c = object; + } + + public Object b() { + return this.c; + } + + public int c() { + return this.a; + } + + public boolean d() { + return this.d; + } + + public void a(boolean flag) { + this.d = flag; + } +} diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java new file mode 100644 index 0000000..97284b6 --- /dev/null +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +1,2461 @@ +package net.minecraft.server; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.block.BlockCanBuildEvent; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.weather.ThunderChangeEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.util.*; + +// CraftBukkit start +// CraftBukkit end + +public class World implements IBlockAccess { + + public boolean a = false; + private List C = new ArrayList(); + public List entityList = new ArrayList(); + private List D = new ArrayList(); + private TreeSet E = new TreeSet(); + private Set F = new HashSet(); + public List c = new ArrayList(); + private List G = new ArrayList(); + public List players = new ArrayList(); + public List e = new ArrayList(); + private long H = 16777215L; + public int f = 0; + protected int g = (new Random()).nextInt(); + protected final int h = 1013904223; + protected float i; + protected float j; + protected float k; + protected float l; + protected int m = 0; + public int n = 0; + public boolean suppressPhysics = false; + private long I = System.currentTimeMillis(); + protected int p = 40; + public int spawnMonsters; + public Random random = new Random(); + public boolean s = false; + public WorldProvider worldProvider; // CraftBukkit - remove final + protected List u = new ArrayList(); + public IChunkProvider chunkProvider; // CraftBukkit - protected -> public + protected final IDataManager w; + public WorldData worldData; // CraftBukkit - protected -> public + public boolean isLoading; + private boolean J; + public WorldMapCollection worldMaps; + private ArrayList K = new ArrayList(); + private boolean L; + private int M = 0; + public boolean allowMonsters = true; // CraftBukkit - private -> public + public boolean allowAnimals = true; // CraftBukkit - private -> public + static int A = 0; + private Set P = new HashSet(); + private int Q; + private List R; + public boolean isStatic; + public final Map explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions + + public WorldChunkManager getWorldChunkManager() { + return this.worldProvider.b; + } + + // CraftBukkit start + private final CraftWorld world; + public boolean pvpMode; + public boolean keepSpawnInMemory = true; + public ChunkGenerator generator; + Chunk lastChunkAccessed; + int lastXAccessed = Integer.MIN_VALUE; + int lastZAccessed = Integer.MIN_VALUE; + final Object chunkLock = new Object(); + private List tileEntitiesToUnload; + + private boolean canSpawn(int x, int z) { + if (this.generator != null) { + return this.generator.canSpawn(this.getWorld(), x, z); + } else { + return this.worldProvider.canSpawn(x, z); + } + } + + public CraftWorld getWorld() { + return this.world; + } + + public CraftServer getServer() { + return (CraftServer) Bukkit.getServer(); + } + + public void markForRemoval(TileEntity tileentity) { + tileEntitiesToUnload.add(tileentity); + } + + // CraftBukkit - changed signature + public World(IDataManager idatamanager, String s, long i, WorldProvider worldprovider, ChunkGenerator gen, org.bukkit.World.Environment env) { + this.generator = gen; + this.world = new CraftWorld((WorldServer) this, gen, env); + tileEntitiesToUnload = new ArrayList(); + // CraftBukkit end + + this.Q = this.random.nextInt(12000); + this.R = new ArrayList(); + this.isStatic = false; + this.w = idatamanager; + this.worldMaps = new WorldMapCollection(idatamanager); + this.worldData = idatamanager.c(); + this.s = this.worldData == null; + if (worldprovider != null) { + this.worldProvider = worldprovider; + } else if (this.worldData != null && this.worldData.h() == -1) { + this.worldProvider = WorldProvider.byDimension(-1); + } else { + this.worldProvider = WorldProvider.byDimension(0); + } + + boolean flag = false; + + if (this.worldData == null) { + this.worldData = new WorldData(i, s); + flag = true; + } else { + this.worldData.a(s); + } + + this.worldProvider.a(this); + this.chunkProvider = this.b(); + if (flag) { + this.c(); + } + + this.g(); + this.x(); + + this.getServer().addWorld(this.world); // CraftBukkit + } + + protected IChunkProvider b() { + IChunkLoader ichunkloader = this.w.a(this.worldProvider); + + return new ChunkProviderLoadOrGenerate(this, ichunkloader, this.worldProvider.getChunkProvider()); + } + + protected void c() { + this.isLoading = true; + int i = 0; + byte b0 = 64; + + int j; + + // CraftBukkit start + if (this.generator != null) { + Random rand = new Random(this.getSeed()); + Location spawn = this.generator.getFixedSpawnLocation(((WorldServer) this).getWorld(), rand); + + if (spawn != null) { + if (spawn.getWorld() != ((WorldServer) this).getWorld()) { + throw new IllegalStateException("Cannot set spawn point for " + this.worldData.name + " to be in another world (" + spawn.getWorld().getName() + ")"); + } else { + this.worldData.setSpawn(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ()); + this.isLoading = false; + return; + } + } + } + + // Poseidon - Fix OOM in naive custom world generators + int attempts = 0; + + for (j = 0; !this.canSpawn(i, j); j += this.random.nextInt(64) - this.random.nextInt(64)) { + i += this.random.nextInt(64) - this.random.nextInt(64); + attempts += 1; + + if (attempts > 1024) { + i = 0; + j = 0; + + System.out.println("[Poseidon] The generator for the world \"" + this.worldData.name + "\" did not generate a safe spawn location in 1024 attempts. If this world's generator is handled by a plugin, please inform them that they can solve this problem by overriding the \"canSpawn\" method with code more suited to their world type, or to define a fixed spawn location."); + + break; + } + } + + // CraftBukkit end + + this.worldData.setSpawn(i, b0, j); + this.isLoading = false; + } + + public int a(int i, int j) { + int k; + + for (k = 63; !this.isEmpty(i, k + 1, j); ++k) { + ; + } + + return this.getTypeId(i, k, j); + } + + public void save(boolean flag, IProgressUpdate iprogressupdate) { + if (this.chunkProvider.canSave()) { + if (iprogressupdate != null) { + iprogressupdate.a("Saving level"); + } + + this.w(); + if (iprogressupdate != null) { + iprogressupdate.b("Saving chunks"); + } + + this.chunkProvider.saveChunks(flag, iprogressupdate); + } + } + + private void w() { + this.k(); + this.w.a(this.worldData, this.players); + this.worldMaps.a(); + } + + public int getTypeId(int i, int j, int k) { + return i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000 ? (j < 0 ? 0 : (j >= 128 ? 0 : this.getChunkAt(i >> 4, k >> 4).getTypeId(i & 15, j, k & 15))) : 0; + } + + public boolean isEmpty(int i, int j, int k) { + return this.getTypeId(i, j, k) == 0; + } + + public boolean isLoaded(int i, int j, int k) { + return j >= 0 && j < 128 ? this.isChunkLoaded(i >> 4, k >> 4) : false; + } + + public boolean areChunksLoaded(int i, int j, int k, int l) { + return this.a(i - l, j - l, k - l, i + l, j + l, k + l); + } + + public boolean a(int i, int j, int k, int l, int i1, int j1) { + if (i1 >= 0 && j < 128) { + i >>= 4; + j >>= 4; + k >>= 4; + l >>= 4; + i1 >>= 4; + j1 >>= 4; + + for (int k1 = i; k1 <= l; ++k1) { + for (int l1 = k; l1 <= j1; ++l1) { + if (!this.isChunkLoaded(k1, l1)) { + return false; + } + } + } + + return true; + } else { + return false; + } + } + + private boolean isChunkLoaded(int i, int j) { + return this.chunkProvider.isChunkLoaded(i, j); + } + + public Chunk getChunkAtWorldCoords(int i, int j) { + return this.getChunkAt(i >> 4, j >> 4); + } + + // CraftBukkit start + public Chunk getChunkAt(int i, int j) { + Chunk result = null; + synchronized (this.chunkLock) { + if (this.lastChunkAccessed == null || this.lastXAccessed != i || this.lastZAccessed != j) { + this.lastXAccessed = i; + this.lastZAccessed = j; + this.lastChunkAccessed = this.chunkProvider.getOrCreateChunk(i, j); + } + result = this.lastChunkAccessed; + } + return result; + } + // CraftBukkit end + + public boolean setRawTypeIdAndData(int i, int j, int k, int l, int i1) { + if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + if (j < 0) { + return false; + } else if (j >= 128) { + return false; + } else { + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + return chunk.a(i & 15, j, k & 15, l, i1); + } + } else { + return false; + } + } + + public boolean setRawTypeId(int i, int j, int k, int l) { + if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + if (j < 0) { + return false; + } else if (j >= 128) { + return false; + } else { + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + return chunk.a(i & 15, j, k & 15, l); + } + } else { + return false; + } + } + + public Material getMaterial(int i, int j, int k) { + int l = this.getTypeId(i, j, k); + + return l == 0 ? Material.AIR : Block.byId[l].material; + } + + public int getData(int i, int j, int k) { + if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + if (j < 0) { + return 0; + } else if (j >= 128) { + return 0; + } else { + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + i &= 15; + k &= 15; + return chunk.getData(i, j, k); + } + } else { + return 0; + } + } + + public void setData(int i, int j, int k, int l) { + if (this.setRawData(i, j, k, l)) { + int i1 = this.getTypeId(i, j, k); + + if (Block.t[i1 & 255]) { + this.update(i, j, k, i1); + } else { + this.applyPhysics(i, j, k, i1); + } + } + } + + public boolean setRawData(int i, int j, int k, int l) { + if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + if (j < 0) { + return false; + } else if (j >= 128) { + return false; + } else { + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + i &= 15; + k &= 15; + chunk.b(i, j, k, l); + return true; + } + } else { + return false; + } + } + + public boolean setTypeId(int i, int j, int k, int l) { + // CraftBukkit start + int old = this.getTypeId(i, j, k); + if (this.setRawTypeId(i, j, k, l)) { + this.update(i, j, k, l == 0 ? old : l); + return true; + } else { + return false; + } + // CraftBukkit end + } + + public boolean setTypeIdAndData(int i, int j, int k, int l, int i1) { + // CraftBukkit start + int old = this.getTypeId(i, j, k); + if (this.setRawTypeIdAndData(i, j, k, l, i1)) { + this.update(i, j, k, l == 0 ? old : l); + return true; + } else { + return false; + } + // CraftBukkit end + } + + public void notify(int i, int j, int k) { + for (int l = 0; l < this.u.size(); ++l) { + ((IWorldAccess) this.u.get(l)).a(i, j, k); + } + } + + protected void update(int i, int j, int k, int l) { + this.notify(i, j, k); + this.applyPhysics(i, j, k, l); + } + + public void g(int i, int j, int k, int l) { + if (k > l) { + int i1 = l; + + l = k; + k = i1; + } + + this.b(i, k, j, i, l, j); + } + + public void i(int i, int j, int k) { + for (int l = 0; l < this.u.size(); ++l) { + ((IWorldAccess) this.u.get(l)).a(i, j, k, i, j, k); + } + } + + public void b(int i, int j, int k, int l, int i1, int j1) { + for (int k1 = 0; k1 < this.u.size(); ++k1) { + ((IWorldAccess) this.u.get(k1)).a(i, j, k, l, i1, j1); + } + } + + public void applyPhysics(int i, int j, int k, int l) { + this.k(i - 1, j, k, l); + this.k(i + 1, j, k, l); + this.k(i, j - 1, k, l); + this.k(i, j + 1, k, l); + this.k(i, j, k - 1, l); + this.k(i, j, k + 1, l); + } + + private void k(int i, int j, int k, int l) { + if (!this.suppressPhysics && !this.isStatic) { + Block block = Block.byId[this.getTypeId(i, j, k)]; + + if (block != null) { + // CraftBukkit start + CraftWorld world = ((WorldServer) this).getWorld(); + if (world != null) { + BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(i, j, k), l); + this.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + } + // CraftBukkit end + + block.doPhysics(this, i, j, k, l); + } + } + } + + public boolean isChunkLoaded(int i, int j, int k) { + return this.getChunkAt(i >> 4, k >> 4).c(i & 15, j, k & 15); + } + + public int k(int i, int j, int k) { + if (j < 0) { + return 0; + } else { + if (j >= 128) { + j = 127; + } + + return this.getChunkAt(i >> 4, k >> 4).c(i & 15, j, k & 15, 0); + } + } + + public int getLightLevel(int i, int j, int k) { + return this.a(i, j, k, true); + } + + public int a(int i, int j, int k, boolean flag) { + if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + if (flag) { + int l = this.getTypeId(i, j, k); + + if (l == Block.STEP.id || l == Block.SOIL.id || l == Block.COBBLESTONE_STAIRS.id || l == Block.WOOD_STAIRS.id) { + int i1 = this.a(i, j + 1, k, false); + int j1 = this.a(i + 1, j, k, false); + int k1 = this.a(i - 1, j, k, false); + int l1 = this.a(i, j, k + 1, false); + int i2 = this.a(i, j, k - 1, false); + + if (j1 > i1) { + i1 = j1; + } + + if (k1 > i1) { + i1 = k1; + } + + if (l1 > i1) { + i1 = l1; + } + + if (i2 > i1) { + i1 = i2; + } + + return i1; + } + } + + if (j < 0) { + return 0; + } else { + if (j >= 128) { + j = 127; + } + + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + i &= 15; + k &= 15; + return chunk.c(i, j, k, this.f); + } + } else { + return 15; + } + } + + public boolean m(int i, int j, int k) { + if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + if (j < 0) { + return false; + } else if (j >= 128) { + return true; + } else if (!this.isChunkLoaded(i >> 4, k >> 4)) { + return false; + } else { + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + i &= 15; + k &= 15; + return chunk.c(i, j, k); + } + } else { + return false; + } + } + + public int getHighestBlockYAt(int i, int j) { + if (i >= -32000000 && j >= -32000000 && i < 32000000 && j <= 32000000) { + if (!this.isChunkLoaded(i >> 4, j >> 4)) { + return 0; + } else { + Chunk chunk = this.getChunkAt(i >> 4, j >> 4); + + return chunk.b(i & 15, j & 15); + } + } else { + return 0; + } + } + + public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l) { + if (!this.worldProvider.e || enumskyblock != EnumSkyBlock.SKY) { + if (this.isLoaded(i, j, k)) { + if (enumskyblock == EnumSkyBlock.SKY) { + if (this.m(i, j, k)) { + l = 15; + } + } else if (enumskyblock == EnumSkyBlock.BLOCK) { + int i1 = this.getTypeId(i, j, k); + + if (Block.s[i1] > l) { + l = Block.s[i1]; + } + } + + if (this.a(enumskyblock, i, j, k) != l) { + this.a(enumskyblock, i, j, k, i, j, k); + } + } + } + } + + public int a(EnumSkyBlock enumskyblock, int i, int j, int k) { + if (j < 0) { + j = 0; + } + + if (j >= 128) { + j = 127; + } + + if (j >= 0 && j < 128 && i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + int l = i >> 4; + int i1 = k >> 4; + + if (!this.isChunkLoaded(l, i1)) { + return 0; + } else { + Chunk chunk = this.getChunkAt(l, i1); + + return chunk.a(enumskyblock, i & 15, j, k & 15); + } + } else { + return enumskyblock.c; + } + } + + public void b(EnumSkyBlock enumskyblock, int i, int j, int k, int l) { + if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) { + if (j >= 0) { + if (j < 128) { + if (this.isChunkLoaded(i >> 4, k >> 4)) { + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + chunk.a(enumskyblock, i & 15, j, k & 15, l); + + for (int i1 = 0; i1 < this.u.size(); ++i1) { + ((IWorldAccess) this.u.get(i1)).a(i, j, k); + } + } + } + } + } + } + + public float n(int i, int j, int k) { + return this.worldProvider.f[this.getLightLevel(i, j, k)]; + } + + public boolean d() { + return this.f < 4; + } + + public MovingObjectPosition a(Vec3D vec3d, Vec3D vec3d1) { + return this.rayTrace(vec3d, vec3d1, false, false); + } + + public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, boolean flag) { + return this.rayTrace(vec3d, vec3d1, flag, false); + } + + public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, boolean flag, boolean flag1) { + if (!Double.isNaN(vec3d.a) && !Double.isNaN(vec3d.b) && !Double.isNaN(vec3d.c)) { + if (!Double.isNaN(vec3d1.a) && !Double.isNaN(vec3d1.b) && !Double.isNaN(vec3d1.c)) { + int i = MathHelper.floor(vec3d1.a); + int j = MathHelper.floor(vec3d1.b); + int k = MathHelper.floor(vec3d1.c); + int l = MathHelper.floor(vec3d.a); + int i1 = MathHelper.floor(vec3d.b); + int j1 = MathHelper.floor(vec3d.c); + int k1 = this.getTypeId(l, i1, j1); + int l1 = this.getData(l, i1, j1); + Block block = Block.byId[k1]; + + if ((!flag1 || block == null || block.e(this, l, i1, j1) != null) && k1 > 0 && block.a(l1, flag)) { + MovingObjectPosition movingobjectposition = block.a(this, l, i1, j1, vec3d, vec3d1); + + if (movingobjectposition != null) { + return movingobjectposition; + } + } + + k1 = 200; + + while (k1-- >= 0) { + if (Double.isNaN(vec3d.a) || Double.isNaN(vec3d.b) || Double.isNaN(vec3d.c)) { + return null; + } + + if (l == i && i1 == j && j1 == k) { + return null; + } + + boolean flag2 = true; + boolean flag3 = true; + boolean flag4 = true; + double d0 = 999.0D; + double d1 = 999.0D; + double d2 = 999.0D; + + if (i > l) { + d0 = (double) l + 1.0D; + } else if (i < l) { + d0 = (double) l + 0.0D; + } else { + flag2 = false; + } + + if (j > i1) { + d1 = (double) i1 + 1.0D; + } else if (j < i1) { + d1 = (double) i1 + 0.0D; + } else { + flag3 = false; + } + + if (k > j1) { + d2 = (double) j1 + 1.0D; + } else if (k < j1) { + d2 = (double) j1 + 0.0D; + } else { + flag4 = false; + } + + double d3 = 999.0D; + double d4 = 999.0D; + double d5 = 999.0D; + double d6 = vec3d1.a - vec3d.a; + double d7 = vec3d1.b - vec3d.b; + double d8 = vec3d1.c - vec3d.c; + + if (flag2) { + d3 = (d0 - vec3d.a) / d6; + } + + if (flag3) { + d4 = (d1 - vec3d.b) / d7; + } + + if (flag4) { + d5 = (d2 - vec3d.c) / d8; + } + + boolean flag5 = false; + byte b0; + + if (d3 < d4 && d3 < d5) { + if (i > l) { + b0 = 4; + } else { + b0 = 5; + } + + vec3d.a = d0; + vec3d.b += d7 * d3; + vec3d.c += d8 * d3; + } else if (d4 < d5) { + if (j > i1) { + b0 = 0; + } else { + b0 = 1; + } + + vec3d.a += d6 * d4; + vec3d.b = d1; + vec3d.c += d8 * d4; + } else { + if (k > j1) { + b0 = 2; + } else { + b0 = 3; + } + + vec3d.a += d6 * d5; + vec3d.b += d7 * d5; + vec3d.c = d2; + } + + Vec3D vec3d2 = Vec3D.create(vec3d.a, vec3d.b, vec3d.c); + + l = (int) (vec3d2.a = (double) MathHelper.floor(vec3d.a)); + if (b0 == 5) { + --l; + ++vec3d2.a; + } + + i1 = (int) (vec3d2.b = (double) MathHelper.floor(vec3d.b)); + if (b0 == 1) { + --i1; + ++vec3d2.b; + } + + j1 = (int) (vec3d2.c = (double) MathHelper.floor(vec3d.c)); + if (b0 == 3) { + --j1; + ++vec3d2.c; + } + + int i2 = this.getTypeId(l, i1, j1); + int j2 = this.getData(l, i1, j1); + Block block1 = Block.byId[i2]; + + if ((!flag1 || block1 == null || block1.e(this, l, i1, j1) != null) && i2 > 0 && block1.a(j2, flag)) { + MovingObjectPosition movingobjectposition1 = block1.a(this, l, i1, j1, vec3d, vec3d1); + + if (movingobjectposition1 != null) { + return movingobjectposition1; + } + } + } + + return null; + } else { + return null; + } + } else { + return null; + } + } + + public void makeSound(Entity entity, String s, float f, float f1) { + for (int i = 0; i < this.u.size(); ++i) { + ((IWorldAccess) this.u.get(i)).a(s, entity.locX, entity.locY - (double) entity.height, entity.locZ, f, f1); + } + } + + public void makeSound(double d0, double d1, double d2, String s, float f, float f1) { + for (int i = 0; i < this.u.size(); ++i) { + ((IWorldAccess) this.u.get(i)).a(s, d0, d1, d2, f, f1); + } + } + + public void a(String s, int i, int j, int k) { + for (int l = 0; l < this.u.size(); ++l) { + ((IWorldAccess) this.u.get(l)).a(s, i, j, k); + } + } + + public void a(String s, double d0, double d1, double d2, double d3, double d4, double d5) { + for (int i = 0; i < this.u.size(); ++i) { + ((IWorldAccess) this.u.get(i)).a(s, d0, d1, d2, d3, d4, d5); + } + } + + public boolean strikeLightning(Entity entity) { + this.e.add(entity); + return true; + } + + // CraftBukkit start - used for entities other than creatures + public boolean addEntity(Entity entity) { + return this.addEntity(entity, SpawnReason.CUSTOM); // Set reason as Custom by default + } + + + public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason + // CraftBukkit end + int i = MathHelper.floor(entity.locX / 16.0D); + int j = MathHelper.floor(entity.locZ / 16.0D); + boolean flag = false; + + if (entity instanceof EntityHuman) { + flag = true; + } + + // CraftBukkit start + if (entity instanceof EntityLiving && !(entity instanceof EntityPlayer)) { + CreatureSpawnEvent event = CraftEventFactory.callCreatureSpawnEvent((EntityLiving) entity, spawnReason); + + if (event.isCancelled()) { + return false; + } + } else if (entity instanceof EntityItem) { + ItemSpawnEvent event = CraftEventFactory.callItemSpawnEvent((EntityItem) entity); + if (event.isCancelled()) { + return false; + } + } + // CraftBukkit end + + if (!flag && !this.isChunkLoaded(i, j)) { + return false; + } else { + if (entity instanceof EntityHuman) { + EntityHuman entityhuman = (EntityHuman) entity; + + this.players.add(entityhuman); + this.everyoneSleeping(); + } + + this.getChunkAt(i, j).a(entity); + this.entityList.add(entity); + this.c(entity); + return true; + } + } + + protected void c(Entity entity) { + for (int i = 0; i < this.u.size(); ++i) { + ((IWorldAccess) this.u.get(i)).a(entity); + } + } + + protected void d(Entity entity) { + for (int i = 0; i < this.u.size(); ++i) { + ((IWorldAccess) this.u.get(i)).b(entity); + } + } + + public void kill(Entity entity) { + if (entity.passenger != null) { + entity.passenger.mount((Entity) null); + } + + if (entity.vehicle != null) { + entity.mount((Entity) null); + } + + entity.die(); + if (entity instanceof EntityHuman) { + this.players.remove((EntityHuman) entity); + this.everyoneSleeping(); + } + } + + public void removeEntity(Entity entity) { + entity.die(); + if (entity instanceof EntityHuman) { + this.players.remove((EntityHuman) entity); + this.everyoneSleeping(); + } + + int i = entity.bH; + int j = entity.bJ; + + if (entity.bG && this.isChunkLoaded(i, j)) { + this.getChunkAt(i, j).b(entity); + } + + this.entityList.remove(entity); + this.d(entity); + } + + public void addIWorldAccess(IWorldAccess iworldaccess) { + this.u.add(iworldaccess); + } + + public List getEntities(Entity entity, AxisAlignedBB axisalignedbb) { + this.K.clear(); + int i = MathHelper.floor(axisalignedbb.a); + int j = MathHelper.floor(axisalignedbb.d + 1.0D); + int k = MathHelper.floor(axisalignedbb.b); + int l = MathHelper.floor(axisalignedbb.e + 1.0D); + int i1 = MathHelper.floor(axisalignedbb.c); + int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); + + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = i1; l1 < j1; ++l1) { + if (this.isLoaded(k1, 64, l1)) { + for (int i2 = k - 1; i2 < l; ++i2) { + Block block = Block.byId[this.getTypeId(k1, i2, l1)]; + + if (block != null) { + block.a(this, k1, i2, l1, axisalignedbb, this.K); + } + } + } + } + } + + double d0 = 0.25D; + List list = this.b(entity, axisalignedbb.b(d0, d0, d0)); + + for (int j2 = 0; j2 < list.size(); ++j2) { + AxisAlignedBB axisalignedbb1 = ((Entity) list.get(j2)).e_(); + + if (axisalignedbb1 != null && axisalignedbb1.a(axisalignedbb)) { + this.K.add(axisalignedbb1); + } + + axisalignedbb1 = entity.a_((Entity) list.get(j2)); + if (axisalignedbb1 != null && axisalignedbb1.a(axisalignedbb)) { + this.K.add(axisalignedbb1); + } + } + + return this.K; + } + + public int a(float f) { + float f1 = this.b(f); + float f2 = 1.0F - (MathHelper.cos(f1 * 3.1415927F * 2.0F) * 2.0F + 0.5F); + + if (f2 < 0.0F) { + f2 = 0.0F; + } + + if (f2 > 1.0F) { + f2 = 1.0F; + } + + f2 = 1.0F - f2; + f2 = (float) ((double) f2 * (1.0D - (double) (this.d(f) * 5.0F) / 16.0D)); + f2 = (float) ((double) f2 * (1.0D - (double) (this.c(f) * 5.0F) / 16.0D)); + f2 = 1.0F - f2; + return (int) (f2 * 11.0F); + } + + public float b(float f) { + return this.worldProvider.a(this.worldData.f(), f); + } + + public int e(int i, int j) { + Chunk chunk = this.getChunkAtWorldCoords(i, j); + int k = 127; + + i &= 15; + + for (j &= 15; k > 0; --k) { + int l = chunk.getTypeId(i, k, j); + Material material = l == 0 ? Material.AIR : Block.byId[l].material; + + if (material.isSolid() || material.isLiquid()) { + return k + 1; + } + } + + return -1; + } + + public int f(int i, int j) { + Chunk chunk = this.getChunkAtWorldCoords(i, j); + int k = 127; + + i &= 15; + + for (j &= 15; k > 0; --k) { + int l = chunk.getTypeId(i, k, j); + + if (l != 0 && Block.byId[l].material.isSolid()) { + return k + 1; + } + } + + return -1; + } + + public void c(int i, int j, int k, int l, int i1) { + NextTickListEntry nextticklistentry = new NextTickListEntry(i, j, k, l); + byte b0 = 8; + + if (this.a) { + if (this.a(nextticklistentry.a - b0, nextticklistentry.b - b0, nextticklistentry.c - b0, nextticklistentry.a + b0, nextticklistentry.b + b0, nextticklistentry.c + b0)) { + int j1 = this.getTypeId(nextticklistentry.a, nextticklistentry.b, nextticklistentry.c); + + if (j1 == nextticklistentry.d && j1 > 0) { + Block.byId[j1].a(this, nextticklistentry.a, nextticklistentry.b, nextticklistentry.c, this.random); + } + } + } else { + if (this.a(i - b0, j - b0, k - b0, i + b0, j + b0, k + b0)) { + if (l > 0) { + nextticklistentry.a((long) i1 + this.worldData.f()); + } + + if (!this.F.contains(nextticklistentry)) { + this.F.add(nextticklistentry); + this.E.add(nextticklistentry); + } + } + } + } + + public void cleanUp() { + int i; + Entity entity; + + for (i = 0; i < this.e.size(); ++i) { + entity = (Entity) this.e.get(i); + // CraftBukkit start - fixed an NPE + if (entity == null) { + continue; + } + // CraftBukkit end + entity.m_(); + if (entity.dead) { + this.e.remove(i--); + } + } + + this.entityList.removeAll(this.D); + + int j; + int k; + + for (i = 0; i < this.D.size(); ++i) { + entity = (Entity) this.D.get(i); + j = entity.bH; + k = entity.bJ; + if (entity.bG && this.isChunkLoaded(j, k)) { + this.getChunkAt(j, k).b(entity); + } + } + + for (i = 0; i < this.D.size(); ++i) { + this.d((Entity) this.D.get(i)); + } + + this.D.clear(); + + for (i = 0; i < this.entityList.size(); ++i) { + entity = (Entity) this.entityList.get(i); + if (entity.vehicle != null) { + if (!entity.vehicle.dead && entity.vehicle.passenger == entity) { + continue; + } + + entity.vehicle.passenger = null; + entity.vehicle = null; + } + + if (!entity.dead) { + this.playerJoinedWorld(entity); + } + + if (entity.dead) { + j = entity.bH; + k = entity.bJ; + if (entity.bG && this.isChunkLoaded(j, k)) { + this.getChunkAt(j, k).b(entity); + } + + this.entityList.remove(i--); + this.d(entity); + } + } + + this.L = true; + Iterator iterator = this.c.iterator(); + + while (iterator.hasNext()) { + TileEntity tileentity = (TileEntity) iterator.next(); + + if (!tileentity.g()) { + tileentity.g_(); + } + + if (tileentity.g()) { + iterator.remove(); + Chunk chunk = this.getChunkAt(tileentity.x >> 4, tileentity.z >> 4); + + if (chunk != null) { + chunk.e(tileentity.x & 15, tileentity.y, tileentity.z & 15); + } + } + } + + this.L = false; + + // Craftbukkit start + if (!tileEntitiesToUnload.isEmpty()) { + this.c.removeAll(tileEntitiesToUnload); + this.tileEntitiesToUnload.clear(); + } + // Craftbukkit end + + if (!this.G.isEmpty()) { + Iterator iterator1 = this.G.iterator(); + + while (iterator1.hasNext()) { + TileEntity tileentity1 = (TileEntity) iterator1.next(); + + if (!tileentity1.g()) { + // CraftBukkit - order matters, moved down + /* if (!this.c.contains(tileentity1)) { + this.c.add(tileentity1); + } */ + + Chunk chunk1 = this.getChunkAt(tileentity1.x >> 4, tileentity1.z >> 4); + + if (chunk1 != null) { + chunk1.placeTileEntity(tileentity1.x & 15, tileentity1.y, tileentity1.z & 15, tileentity1); + // CraftBukkit start - moved in from above + if (!this.c.contains(tileentity1)) { + this.c.add(tileentity1); + } + // CraftBukkit end + } + + this.notify(tileentity1.x, tileentity1.y, tileentity1.z); + } + } + + this.G.clear(); + } + } + + public void a(Collection collection) { + if (this.L) { + this.G.addAll(collection); + } else { + this.c.addAll(collection); + } + } + + public void playerJoinedWorld(Entity entity) { + this.entityJoinedWorld(entity, true); + } + + public void entityJoinedWorld(Entity entity, boolean flag) { + int i = MathHelper.floor(entity.locX); + int j = MathHelper.floor(entity.locZ); + byte b0 = 32; + + if (!flag || this.a(i - b0, 0, j - b0, i + b0, 128, j + b0)) { + entity.bo = entity.locX; + entity.bp = entity.locY; + entity.bq = entity.locZ; + entity.lastYaw = entity.yaw; + entity.lastPitch = entity.pitch; + if (flag && entity.bG) { + if (entity.vehicle != null) { + entity.E(); + } else { + entity.m_(); + } + } + + if (Double.isNaN(entity.locX) || Double.isInfinite(entity.locX)) { + entity.locX = entity.bo; + } + + if (Double.isNaN(entity.locY) || Double.isInfinite(entity.locY)) { + entity.locY = entity.bp; + } + + if (Double.isNaN(entity.locZ) || Double.isInfinite(entity.locZ)) { + entity.locZ = entity.bq; + } + + if (Double.isNaN((double) entity.pitch) || Double.isInfinite((double) entity.pitch)) { + entity.pitch = entity.lastPitch; + } + + if (Double.isNaN((double) entity.yaw) || Double.isInfinite((double) entity.yaw)) { + entity.yaw = entity.lastYaw; + } + + int k = MathHelper.floor(entity.locX / 16.0D); + int l = MathHelper.floor(entity.locY / 16.0D); + int i1 = MathHelper.floor(entity.locZ / 16.0D); + + if (!entity.bG || entity.bH != k || entity.bI != l || entity.bJ != i1) { + if (entity.bG && this.isChunkLoaded(entity.bH, entity.bJ)) { + this.getChunkAt(entity.bH, entity.bJ).a(entity, entity.bI); + } + + if (this.isChunkLoaded(k, i1)) { + entity.bG = true; + this.getChunkAt(k, i1).a(entity); + } else { + entity.bG = false; + } + } + + if (flag && entity.bG && entity.passenger != null) { + if (!entity.passenger.dead && entity.passenger.vehicle == entity) { + this.playerJoinedWorld(entity.passenger); + } else { + entity.passenger.vehicle = null; + entity.passenger = null; + } + } + } + } + + public boolean containsEntity(AxisAlignedBB axisalignedbb) { + List list = this.b((Entity) null, axisalignedbb); + + for (int i = 0; i < list.size(); ++i) { + Entity entity = (Entity) list.get(i); + + if (!entity.dead && entity.aI) { + return false; + } + } + + return true; + } + + public boolean b(AxisAlignedBB axisalignedbb) { + int i = MathHelper.floor(axisalignedbb.a); + int j = MathHelper.floor(axisalignedbb.d + 1.0D); + int k = MathHelper.floor(axisalignedbb.b); + int l = MathHelper.floor(axisalignedbb.e + 1.0D); + int i1 = MathHelper.floor(axisalignedbb.c); + int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); + + if (axisalignedbb.a < 0.0D) { + --i; + } + + if (axisalignedbb.b < 0.0D) { + --k; + } + + if (axisalignedbb.c < 0.0D) { + --i1; + } + + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = k; l1 < l; ++l1) { + for (int i2 = i1; i2 < j1; ++i2) { + Block block = Block.byId[this.getTypeId(k1, l1, i2)]; + + if (block != null) { + return true; + } + } + } + } + + return false; + } + + public boolean c(AxisAlignedBB axisalignedbb) { + int i = MathHelper.floor(axisalignedbb.a); + int j = MathHelper.floor(axisalignedbb.d + 1.0D); + int k = MathHelper.floor(axisalignedbb.b); + int l = MathHelper.floor(axisalignedbb.e + 1.0D); + int i1 = MathHelper.floor(axisalignedbb.c); + int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); + + if (axisalignedbb.a < 0.0D) { + --i; + } + + if (axisalignedbb.b < 0.0D) { + --k; + } + + if (axisalignedbb.c < 0.0D) { + --i1; + } + + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = k; l1 < l; ++l1) { + for (int i2 = i1; i2 < j1; ++i2) { + Block block = Block.byId[this.getTypeId(k1, l1, i2)]; + + if (block != null && block.material.isLiquid()) { + return true; + } + } + } + } + + return false; + } + + public boolean d(AxisAlignedBB axisalignedbb) { + int i = MathHelper.floor(axisalignedbb.a); + int j = MathHelper.floor(axisalignedbb.d + 1.0D); + int k = MathHelper.floor(axisalignedbb.b); + int l = MathHelper.floor(axisalignedbb.e + 1.0D); + int i1 = MathHelper.floor(axisalignedbb.c); + int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); + + if (this.a(i, k, i1, j, l, j1)) { + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = k; l1 < l; ++l1) { + for (int i2 = i1; i2 < j1; ++i2) { + int j2 = this.getTypeId(k1, l1, i2); + + if (j2 == Block.FIRE.id || j2 == Block.LAVA.id || j2 == Block.STATIONARY_LAVA.id) { + return true; + } + } + } + } + } + + return false; + } + + public boolean a(AxisAlignedBB axisalignedbb, Material material, Entity entity) { + int i = MathHelper.floor(axisalignedbb.a); + int j = MathHelper.floor(axisalignedbb.d + 1.0D); + int k = MathHelper.floor(axisalignedbb.b); + int l = MathHelper.floor(axisalignedbb.e + 1.0D); + int i1 = MathHelper.floor(axisalignedbb.c); + int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); + + if (!this.a(i, k, i1, j, l, j1)) { + return false; + } else { + boolean flag = false; + Vec3D vec3d = Vec3D.create(0.0D, 0.0D, 0.0D); + + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = k; l1 < l; ++l1) { + for (int i2 = i1; i2 < j1; ++i2) { + Block block = Block.byId[this.getTypeId(k1, l1, i2)]; + + if (block != null && block.material == material) { + double d0 = (double) ((float) (l1 + 1) - BlockFluids.c(this.getData(k1, l1, i2))); + + if ((double) l >= d0) { + flag = true; + block.a(this, k1, l1, i2, entity, vec3d); + } + } + } + } + } + + if (vec3d.c() > 0.0D) { + vec3d = vec3d.b(); + double d1 = 0.014D; + + entity.motX += vec3d.a * d1; + entity.motY += vec3d.b * d1; + entity.motZ += vec3d.c * d1; + } + + return flag; + } + } + + public boolean a(AxisAlignedBB axisalignedbb, Material material) { + int i = MathHelper.floor(axisalignedbb.a); + int j = MathHelper.floor(axisalignedbb.d + 1.0D); + int k = MathHelper.floor(axisalignedbb.b); + int l = MathHelper.floor(axisalignedbb.e + 1.0D); + int i1 = MathHelper.floor(axisalignedbb.c); + int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); + + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = k; l1 < l; ++l1) { + for (int i2 = i1; i2 < j1; ++i2) { + Block block = Block.byId[this.getTypeId(k1, l1, i2)]; + + if (block != null && block.material == material) { + return true; + } + } + } + } + + return false; + } + + public boolean b(AxisAlignedBB axisalignedbb, Material material) { + int i = MathHelper.floor(axisalignedbb.a); + int j = MathHelper.floor(axisalignedbb.d + 1.0D); + int k = MathHelper.floor(axisalignedbb.b); + int l = MathHelper.floor(axisalignedbb.e + 1.0D); + int i1 = MathHelper.floor(axisalignedbb.c); + int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); + + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = k; l1 < l; ++l1) { + for (int i2 = i1; i2 < j1; ++i2) { + Block block = Block.byId[this.getTypeId(k1, l1, i2)]; + + if (block != null && block.material == material) { + int j2 = this.getData(k1, l1, i2); + double d0 = (double) (l1 + 1); + + if (j2 < 8) { + d0 = (double) (l1 + 1) - (double) j2 / 8.0D; + } + + if (d0 >= axisalignedbb.b) { + return true; + } + } + } + } + } + + return false; + } + + public Explosion a(Entity entity, double d0, double d1, double d2, float f) { + return this.createExplosion(entity, d0, d1, d2, f, false); + } + + //Project Poseidon Start + public Explosion createExplosion(Entity entity, double d0, double d1, double d2, float f, boolean flag, EntityDamageEvent.DamageCause customDamageCause) { + Explosion explosion = new Explosion(this, entity, d0, d1, d2, f); + explosion.customDamageCause = customDamageCause; + + explosion.setFire = flag; + explosion.a(); + explosion.a(true); + return explosion; + } + //Project Poseidon End + + public Explosion createExplosion(Entity entity, double d0, double d1, double d2, float f, boolean flag) { + Explosion explosion = new Explosion(this, entity, d0, d1, d2, f); + + explosion.setFire = flag; + explosion.a(); + explosion.a(true); + return explosion; + } + + public float a(Vec3D vec3d, AxisAlignedBB axisalignedbb) { + double d0 = 1.0D / ((axisalignedbb.d - axisalignedbb.a) * 2.0D + 1.0D); + double d1 = 1.0D / ((axisalignedbb.e - axisalignedbb.b) * 2.0D + 1.0D); + double d2 = 1.0D / ((axisalignedbb.f - axisalignedbb.c) * 2.0D + 1.0D); + int i = 0; + int j = 0; + + for (float f = 0.0F; f <= 1.0F; f = (float) ((double) f + d0)) { + for (float f1 = 0.0F; f1 <= 1.0F; f1 = (float) ((double) f1 + d1)) { + for (float f2 = 0.0F; f2 <= 1.0F; f2 = (float) ((double) f2 + d2)) { + double d3 = axisalignedbb.a + (axisalignedbb.d - axisalignedbb.a) * (double) f; + double d4 = axisalignedbb.b + (axisalignedbb.e - axisalignedbb.b) * (double) f1; + double d5 = axisalignedbb.c + (axisalignedbb.f - axisalignedbb.c) * (double) f2; + + if (this.a(Vec3D.create(d3, d4, d5), vec3d) == null) { + ++i; + } + + ++j; + } + } + } + + return (float) i / (float) j; + } + + public void douseFire(EntityHuman entityhuman, int i, int j, int k, int l) { + if (l == 0) { + --j; + } + + if (l == 1) { + ++j; + } + + if (l == 2) { + --k; + } + + if (l == 3) { + ++k; + } + + if (l == 4) { + --i; + } + + if (l == 5) { + ++i; + } + + if (this.getTypeId(i, j, k) == Block.FIRE.id) { + this.a(entityhuman, 1004, i, j, k, 0); + this.setTypeId(i, j, k, 0); + } + } + + public TileEntity getTileEntity(int i, int j, int k) { + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + return chunk != null ? chunk.d(i & 15, j, k & 15) : null; + } + + public void setTileEntity(int i, int j, int k, TileEntity tileentity) { + if (!tileentity.g()) { + if (this.L) { + tileentity.x = i; + tileentity.y = j; + tileentity.z = k; + this.G.add(tileentity); + } else { + // CraftBukkit - order matters, moved down + // this.c.add(tileentity); + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + if (chunk != null) { + chunk.placeTileEntity(i & 15, j, k & 15, tileentity); + this.c.add(tileentity); // CraftBukkit - moved in from above + } + } + } + } + + public void o(int i, int j, int k) { + TileEntity tileentity = this.getTileEntity(i, j, k); + + if (tileentity != null && this.L) { + tileentity.h(); + } else { + if (tileentity != null) { + this.c.remove(tileentity); + } + + Chunk chunk = this.getChunkAt(i >> 4, k >> 4); + + if (chunk != null) { + chunk.e(i & 15, j, k & 15); + } + } + } + + public boolean p(int i, int j, int k) { + Block block = Block.byId[this.getTypeId(i, j, k)]; + + return block == null ? false : block.a(); + } + + public boolean e(int i, int j, int k) { + Block block = Block.byId[this.getTypeId(i, j, k)]; + + return block == null ? false : block.material.h() && block.b(); + } + + public boolean doLighting() { + if (this.M >= 50) { + return false; + } else { + ++this.M; + + boolean flag; + + try { + int i = 500; + + while (this.C.size() > 0) { + --i; + if (i <= 0) { + flag = true; + return flag; + } + + ((MetadataChunkBlock) this.C.remove(this.C.size() - 1)).a(this); + } + + flag = false; + } finally { + --this.M; + } + + return flag; + } + } + + public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l, int i1, int j1) { + this.a(enumskyblock, i, j, k, l, i1, j1, true); + } + + public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l, int i1, int j1, boolean flag) { + if (!this.worldProvider.e || enumskyblock != EnumSkyBlock.SKY) { + ++A; + + try { + if (A == 50) { + return; + } + + int k1 = (l + i) / 2; + int l1 = (j1 + k) / 2; + + if (this.isLoaded(k1, 64, l1)) { + if (this.getChunkAtWorldCoords(k1, l1).isEmpty()) { + return; + } + + int i2 = this.C.size(); + int j2; + + if (flag) { + j2 = 5; + if (j2 > i2) { + j2 = i2; + } + + for (int k2 = 0; k2 < j2; ++k2) { + MetadataChunkBlock metadatachunkblock = (MetadataChunkBlock) this.C.get(this.C.size() - k2 - 1); + + if (metadatachunkblock.a == enumskyblock && metadatachunkblock.a(i, j, k, l, i1, j1)) { + return; + } + } + } + + this.C.add(new MetadataChunkBlock(enumskyblock, i, j, k, l, i1, j1)); + j2 = 1000000; + if (this.C.size() > 1000000) { + System.out.println("More than " + j2 + " updates, aborting lighting updates"); + this.C.clear(); + } + + return; + } + } finally { + --A; + } + } + } + + public void g() { + int i = this.a(1.0F); + + if (i != this.f) { + this.f = i; + } + } + + public void setSpawnFlags(boolean flag, boolean flag1) { + this.allowMonsters = flag; + this.allowAnimals = flag1; + } + + public void doTick() { + this.i(); + long i; + + if (this.everyoneDeeplySleeping()) { + boolean flag = false; + + if (this.allowMonsters && this.spawnMonsters >= 1) { + flag = SpawnerCreature.spawnSleepThreats(this, this.players); + } + + if (!flag) { + i = this.worldData.f() + 24000L; + this.worldData.a(i - i % 24000L); + this.s(); + } + } + + // CraftBukkit start - Only call spawner if we have players online and the world allows for mobs or animals + if ((this.allowMonsters || this.allowAnimals) && (this instanceof WorldServer && this.getServer().getHandle().players.size() > 0)) { + SpawnerCreature.spawnEntities(this, this.allowMonsters, this.allowAnimals); + } + // CraftBukkit end + + this.chunkProvider.unloadChunks(); + int j = this.a(1.0F); + + if (j != this.f) { + this.f = j; + + for (int k = 0; k < this.u.size(); ++k) { + ((IWorldAccess) this.u.get(k)).a(); + } + } + + i = this.worldData.f() + 1L; + if (i % (long) this.p == 0L) { + this.save(false, (IProgressUpdate) null); + } + + this.worldData.a(i); + this.a(false); + this.j(); + } + + private void x() { + if (this.worldData.hasStorm()) { + this.j = 1.0F; + if (this.worldData.isThundering()) { + this.l = 1.0F; + } + } + } + + protected void i() { + if (!this.worldProvider.e) { + if (this.m > 0) { + --this.m; + } + + int i = this.worldData.getThunderDuration(); + + if (i <= 0) { + if (this.worldData.isThundering()) { + this.worldData.setThunderDuration(this.random.nextInt(12000) + 3600); + } else { + this.worldData.setThunderDuration(this.random.nextInt(168000) + 12000); + } + } else { + --i; + this.worldData.setThunderDuration(i); + if (i <= 0) { + // CraftBukkit start + ThunderChangeEvent thunder = new ThunderChangeEvent(this.getWorld(), !this.worldData.isThundering()); + this.getServer().getPluginManager().callEvent(thunder); + if (!thunder.isCancelled()) { + this.worldData.setThundering(!this.worldData.isThundering()); + } + // CraftBukkit end + } + } + + int j = this.worldData.getWeatherDuration(); + + if (j <= 0) { + if (this.worldData.hasStorm()) { + this.worldData.setWeatherDuration(this.random.nextInt(12000) + 12000); + } else { + this.worldData.setWeatherDuration(this.random.nextInt(168000) + 12000); + } + } else { + --j; + this.worldData.setWeatherDuration(j); + if (j <= 0) { + // CraftBukkit start + WeatherChangeEvent weather = new WeatherChangeEvent(this.getWorld(), !this.worldData.hasStorm()); + this.getServer().getPluginManager().callEvent(weather); + + if (!weather.isCancelled()) { + this.worldData.setStorm(!this.worldData.hasStorm()); + } + // CraftBukkit end + } + } + + this.i = this.j; + if (this.worldData.hasStorm()) { + this.j = (float) ((double) this.j + 0.01D); + } else { + this.j = (float) ((double) this.j - 0.01D); + } + + if (this.j < 0.0F) { + this.j = 0.0F; + } + + if (this.j > 1.0F) { + this.j = 1.0F; + } + + this.k = this.l; + if (this.worldData.isThundering()) { + this.l = (float) ((double) this.l + 0.01D); + } else { + this.l = (float) ((double) this.l - 0.01D); + } + + if (this.l < 0.0F) { + this.l = 0.0F; + } + + if (this.l > 1.0F) { + this.l = 1.0F; + } + } + } + + private void y() { + // CraftBukkit start + WeatherChangeEvent weather = new WeatherChangeEvent(this.getWorld(), false); + this.getServer().getPluginManager().callEvent(weather); + + ThunderChangeEvent thunder = new ThunderChangeEvent(this.getWorld(), false); + this.getServer().getPluginManager().callEvent(thunder); + if (!weather.isCancelled()) { + this.worldData.setWeatherDuration(0); + this.worldData.setStorm(false); + } + if (!thunder.isCancelled()) { + this.worldData.setThunderDuration(0); + this.worldData.setThundering(false); + } + // CraftBukkit end + } + + protected void j() { + this.P.clear(); + + int i; + int j; + int k; + int l; + + for (int i1 = 0; i1 < this.players.size(); ++i1) { + EntityHuman entityhuman = (EntityHuman) this.players.get(i1); + + i = MathHelper.floor(entityhuman.locX / 16.0D); + j = MathHelper.floor(entityhuman.locZ / 16.0D); + byte b0 = 9; + + for (k = -b0; k <= b0; ++k) { + for (l = -b0; l <= b0; ++l) { + this.P.add(new ChunkCoordIntPair(k + i, l + j)); + } + } + } + + if (this.Q > 0) { + --this.Q; + } + + Iterator iterator = this.P.iterator(); + + while (iterator.hasNext()) { + ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next(); + + i = chunkcoordintpair.x * 16; + j = chunkcoordintpair.z * 16; + Chunk chunk = this.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z); + int j1; + int k1; + int l1; + + if (this.Q == 0) { + this.g = this.g * 3 + 1013904223; + k = this.g >> 2; + l = k & 15; + j1 = k >> 8 & 15; + k1 = k >> 16 & 127; + l1 = chunk.getTypeId(l, k1, j1); + l += i; + j1 += j; + if (l1 == 0 && this.k(l, k1, j1) <= this.random.nextInt(8) && this.a(EnumSkyBlock.SKY, l, k1, j1) <= 0) { + EntityHuman entityhuman1 = this.a((double) l + 0.5D, (double) k1 + 0.5D, (double) j1 + 0.5D, 8.0D); + + if (entityhuman1 != null && entityhuman1.e((double) l + 0.5D, (double) k1 + 0.5D, (double) j1 + 0.5D) > 4.0D) { + this.makeSound((double) l + 0.5D, (double) k1 + 0.5D, (double) j1 + 0.5D, "ambient.cave.cave", 0.7F, 0.8F + this.random.nextFloat() * 0.2F); + this.Q = this.random.nextInt(12000) + 6000; + } + } + } + + if (this.random.nextInt(100000) == 0 && this.v() && this.u()) { + this.g = this.g * 3 + 1013904223; + k = this.g >> 2; + l = i + (k & 15); + j1 = j + (k >> 8 & 15); + k1 = this.e(l, j1); + if (this.s(l, k1, j1)) { + this.strikeLightning(new EntityWeatherStorm(this, (double) l, (double) k1, (double) j1)); + this.m = 2; + } + } + + int i2; + + if (this.random.nextInt(16) == 0) { + this.g = this.g * 3 + 1013904223; + k = this.g >> 2; + l = k & 15; + j1 = k >> 8 & 15; + k1 = this.e(l + i, j1 + j); + if (this.getWorldChunkManager().getBiome(l + i, j1 + j).c() && k1 >= 0 && k1 < 128 && chunk.a(EnumSkyBlock.BLOCK, l, k1, j1) < 10) { + l1 = chunk.getTypeId(l, k1 - 1, j1); + i2 = chunk.getTypeId(l, k1, j1); + if (this.v() && i2 == 0 && Block.SNOW.canPlace(this, l + i, k1, j1 + j) && l1 != 0 && l1 != Block.ICE.id && Block.byId[l1].material.isSolid()) { + // CraftBukkit start + BlockState blockState = this.getWorld().getBlockAt(l + i, k1, j1 + j).getState(); + blockState.setTypeId(Block.SNOW.id); + + BlockFormEvent snow = new BlockFormEvent(blockState.getBlock(), blockState); + this.getServer().getPluginManager().callEvent(snow); + if (!snow.isCancelled()) { + blockState.update(true); + } + // CraftBukkit end + } + + // CraftBukkit start + if (l1 == Block.STATIONARY_WATER.id && chunk.getData(l, k1 - 1, j1) == 0) { + BlockState blockState = this.getWorld().getBlockAt(l + i, k1 - 1, j1 + j).getState(); + blockState.setTypeId(Block.ICE.id); + + BlockFormEvent iceBlockForm = new BlockFormEvent(blockState.getBlock(), blockState); + this.getServer().getPluginManager().callEvent(iceBlockForm); + if (!iceBlockForm.isCancelled()) { + blockState.update(true); + } + } + // CraftBukkit end + } + } + + for (k = 0; k < 80; ++k) { + this.g = this.g * 3 + 1013904223; + l = this.g >> 2; + j1 = l & 15; + k1 = l >> 8 & 15; + l1 = l >> 16 & 127; + i2 = chunk.b[j1 << 11 | k1 << 7 | l1] & 255; + if (Block.n[i2]) { + Block.byId[i2].a(this, j1 + i, l1, k1 + j, this.random); + } + } + } + } + + public boolean a(boolean flag) { + int i = this.E.size(); + + if (i != this.F.size()) { + throw new IllegalStateException("TickNextTick list out of synch"); + } else { + if (i > 1000) { + i = 1000; + } + + for (int j = 0; j < i; ++j) { + NextTickListEntry nextticklistentry = (NextTickListEntry) this.E.first(); + + if (!flag && nextticklistentry.e > this.worldData.f()) { + break; + } + + this.E.remove(nextticklistentry); + this.F.remove(nextticklistentry); + byte b0 = 8; + + if (this.a(nextticklistentry.a - b0, nextticklistentry.b - b0, nextticklistentry.c - b0, nextticklistentry.a + b0, nextticklistentry.b + b0, nextticklistentry.c + b0)) { + int k = this.getTypeId(nextticklistentry.a, nextticklistentry.b, nextticklistentry.c); + + if (k == nextticklistentry.d && k > 0) { + Block.byId[k].a(this, nextticklistentry.a, nextticklistentry.b, nextticklistentry.c, this.random); + } + } + } + + return this.E.size() != 0; + } + } + + public List b(Entity entity, AxisAlignedBB axisalignedbb) { + this.R.clear(); + int i = MathHelper.floor((axisalignedbb.a - 2.0D) / 16.0D); + int j = MathHelper.floor((axisalignedbb.d + 2.0D) / 16.0D); + int k = MathHelper.floor((axisalignedbb.c - 2.0D) / 16.0D); + int l = MathHelper.floor((axisalignedbb.f + 2.0D) / 16.0D); + + for (int i1 = i; i1 <= j; ++i1) { + for (int j1 = k; j1 <= l; ++j1) { + if (this.isChunkLoaded(i1, j1)) { + this.getChunkAt(i1, j1).a(entity, axisalignedbb, this.R); + } + } + } + + return this.R; + } + + public List a(Class oclass, AxisAlignedBB axisalignedbb) { + int i = MathHelper.floor((axisalignedbb.a - 2.0D) / 16.0D); + int j = MathHelper.floor((axisalignedbb.d + 2.0D) / 16.0D); + int k = MathHelper.floor((axisalignedbb.c - 2.0D) / 16.0D); + int l = MathHelper.floor((axisalignedbb.f + 2.0D) / 16.0D); + ArrayList arraylist = new ArrayList(); + + for (int i1 = i; i1 <= j; ++i1) { + for (int j1 = k; j1 <= l; ++j1) { + if (this.isChunkLoaded(i1, j1)) { + this.getChunkAt(i1, j1).a(oclass, axisalignedbb, arraylist); + } + } + } + + return arraylist; + } + + public void b(int i, int j, int k, TileEntity tileentity) { + if (this.isLoaded(i, j, k)) { + this.getChunkAtWorldCoords(i, k).f(); + } + + for (int l = 0; l < this.u.size(); ++l) { + ((IWorldAccess) this.u.get(l)).a(i, j, k, tileentity); + } + } + + public int a(Class oclass) { + int i = 0; + + for (int j = 0; j < this.entityList.size(); ++j) { + Entity entity = (Entity) this.entityList.get(j); + + if (oclass.isAssignableFrom(entity.getClass())) { + ++i; + } + } + + return i; + } + + public void a(List list) { + // CraftBukkit start + Entity entity = null; + for (int i = 0; i < list.size(); ++i) { + entity = (Entity) list.get(i); + // CraftBukkit start - fixed an NPE + if (entity == null) { + continue; + } + // CraftBukkit end + this.entityList.add(entity); + // CraftBukkit end + this.c((Entity) list.get(i)); + } + } + + public void b(List list) { + this.D.addAll(list); + } + + public boolean a(int i, int j, int k, int l, boolean flag, int i1) { + int j1 = this.getTypeId(j, k, l); + Block block = Block.byId[j1]; + Block block1 = Block.byId[i]; + AxisAlignedBB axisalignedbb = block1.e(this, j, k, l); + + if (flag) { + axisalignedbb = null; + } + + boolean defaultReturn; // CraftBukkit - store the default action + + if (axisalignedbb != null && !this.containsEntity(axisalignedbb)) { + defaultReturn = false; // CraftBukkit + } else { + if (block == Block.WATER || block == Block.STATIONARY_WATER || block == Block.LAVA || block == Block.STATIONARY_LAVA || block == Block.FIRE || block == Block.SNOW) { + block = null; + } + + defaultReturn = i > 0 && block == null && block1.canPlace(this, j, k, l, i1); // CraftBukkit + } + + // CraftBukkit start + BlockCanBuildEvent event = new BlockCanBuildEvent(this.getWorld().getBlockAt(j, k, l), i, defaultReturn); + this.getServer().getPluginManager().callEvent(event); + + return event.isBuildable(); + // CraftBukkit end + } + + public PathEntity findPath(Entity entity, Entity entity1, float f) { + int i = MathHelper.floor(entity.locX); + int j = MathHelper.floor(entity.locY); + int k = MathHelper.floor(entity.locZ); + int l = (int) (f + 16.0F); + int i1 = i - l; + int j1 = j - l; + int k1 = k - l; + int l1 = i + l; + int i2 = j + l; + int j2 = k + l; + ChunkCache chunkcache = new ChunkCache(this, i1, j1, k1, l1, i2, j2); + + return (new Pathfinder(chunkcache)).a(entity, entity1, f); + } + + public PathEntity a(Entity entity, int i, int j, int k, float f) { + int l = MathHelper.floor(entity.locX); + int i1 = MathHelper.floor(entity.locY); + int j1 = MathHelper.floor(entity.locZ); + int k1 = (int) (f + 8.0F); + int l1 = l - k1; + int i2 = i1 - k1; + int j2 = j1 - k1; + int k2 = l + k1; + int l2 = i1 + k1; + int i3 = j1 + k1; + ChunkCache chunkcache = new ChunkCache(this, l1, i2, j2, k2, l2, i3); + + return (new Pathfinder(chunkcache)).a(entity, i, j, k, f); + } + + public boolean isBlockFacePowered(int i, int j, int k, int l) { + int i1 = this.getTypeId(i, j, k); + + return i1 == 0 ? false : Block.byId[i1].d(this, i, j, k, l); + } + + public boolean isBlockPowered(int i, int j, int k) { + return this.isBlockFacePowered(i, j - 1, k, 0) ? true : (this.isBlockFacePowered(i, j + 1, k, 1) ? true : (this.isBlockFacePowered(i, j, k - 1, 2) ? true : (this.isBlockFacePowered(i, j, k + 1, 3) ? true : (this.isBlockFacePowered(i - 1, j, k, 4) ? true : this.isBlockFacePowered(i + 1, j, k, 5))))); + } + + public boolean isBlockFaceIndirectlyPowered(int i, int j, int k, int l) { + if (this.e(i, j, k)) { + return this.isBlockPowered(i, j, k); + } else { + int i1 = this.getTypeId(i, j, k); + + return i1 == 0 ? false : Block.byId[i1].a(this, i, j, k, l); + } + } + + public boolean isBlockIndirectlyPowered(int i, int j, int k) { + return this.isBlockFaceIndirectlyPowered(i, j - 1, k, 0) ? true : (this.isBlockFaceIndirectlyPowered(i, j + 1, k, 1) ? true : (this.isBlockFaceIndirectlyPowered(i, j, k - 1, 2) ? true : (this.isBlockFaceIndirectlyPowered(i, j, k + 1, 3) ? true : (this.isBlockFaceIndirectlyPowered(i - 1, j, k, 4) ? true : this.isBlockFaceIndirectlyPowered(i + 1, j, k, 5))))); + } + + public EntityHuman findNearbyPlayer(Entity entity, double d0) { + return this.a(entity.locX, entity.locY, entity.locZ, d0); + } + + public EntityHuman a(double d0, double d1, double d2, double d3) { + double d4 = -1.0D; + EntityHuman entityhuman = null; + + for (int i = 0; i < this.players.size(); ++i) { + EntityHuman entityhuman1 = (EntityHuman) this.players.get(i); + // CraftBukkit start - fixed an NPE + if (entityhuman1 == null || entityhuman1.dead) { + continue; + } + // CraftBukkit end + double d5 = entityhuman1.e(d0, d1, d2); + + if ((d3 < 0.0D || d5 < d3 * d3) && (d4 == -1.0D || d5 < d4)) { + d4 = d5; + entityhuman = entityhuman1; + } + } + + return entityhuman; + } + + public EntityHuman a(String s) { + for (int i = 0; i < this.players.size(); ++i) { + if (s.equals(((EntityHuman) this.players.get(i)).name)) { + return (EntityHuman) this.players.get(i); + } + } + + return null; + } + + public byte[] getMultiChunkData(int i, int j, int k, int l, int i1, int j1) { + byte[] abyte = new byte[l * i1 * j1 * 5 / 2]; + int k1 = i >> 4; + int l1 = k >> 4; + int i2 = i + l - 1 >> 4; + int j2 = k + j1 - 1 >> 4; + int k2 = 0; + int l2 = j; + int i3 = j + i1; + + if (j < 0) { + l2 = 0; + } + + if (i3 > 128) { + i3 = 128; + } + + for (int j3 = k1; j3 <= i2; ++j3) { + int k3 = i - j3 * 16; + int l3 = i + l - j3 * 16; + + if (k3 < 0) { + k3 = 0; + } + + if (l3 > 16) { + l3 = 16; + } + + for (int i4 = l1; i4 <= j2; ++i4) { + int j4 = k - i4 * 16; + int k4 = k + j1 - i4 * 16; + + if (j4 < 0) { + j4 = 0; + } + + if (k4 > 16) { + k4 = 16; + } + + k2 = this.getChunkAt(j3, i4).getData(abyte, k3, l2, j4, l3, i3, k4, k2); + } + } + + return abyte; + } + + public void k() { + this.w.b(); + } + + public void setTime(long i) { + this.worldData.a(i); + } + + public void setTimeAndFixTicklists(long i) { + long j = i - this.worldData.f(); + + NextTickListEntry nextticklistentry; + + for (Iterator iterator = this.F.iterator(); iterator.hasNext(); nextticklistentry.e += j) { + nextticklistentry = (NextTickListEntry) iterator.next(); + } + + this.setTime(i); + } + + public long getSeed() { + return this.worldData.getSeed(); + } + + public long getTime() { + return this.worldData.f(); + } + + public ChunkCoordinates getSpawn() { + return new ChunkCoordinates(this.worldData.c(), this.worldData.d(), this.worldData.e()); + } + + public boolean a(EntityHuman entityhuman, int i, int j, int k) { + return true; + } + + public void a(Entity entity, byte b0) {} + + public IChunkProvider o() { + return this.chunkProvider; + } + + public void playNote(int i, int j, int k, int l, int i1) { + int j1 = this.getTypeId(i, j, k); + + if (j1 > 0) { + Block.byId[j1].a(this, i, j, k, l, i1); + } + } + + public IDataManager p() { + return this.w; + } + + public WorldData q() { + return this.worldData; + } + + public void everyoneSleeping() { + this.J = !this.players.isEmpty(); + Iterator iterator = this.players.iterator(); + + while (iterator.hasNext()) { + EntityHuman entityhuman = (EntityHuman) iterator.next(); + + // CraftBukkit + if (!entityhuman.isSleeping() && !entityhuman.fauxSleeping) { + this.J = false; + break; + } + } + } + + // CraftBukkit start + // Calls the method that checks to see if players are sleeping + // Called by CraftPlayer.setPermanentSleeping() + public void checkSleepStatus() { + if (!this.isStatic) { + this.everyoneSleeping(); + } + } + // CraftBukkit end + + protected void s() { + this.J = false; + Iterator iterator = this.players.iterator(); + + while (iterator.hasNext()) { + EntityHuman entityhuman = (EntityHuman) iterator.next(); + + if (entityhuman.isSleeping()) { + entityhuman.a(false, false, true); + } + } + + this.y(); + } + + public boolean everyoneDeeplySleeping() { + if (this.J && !this.isStatic) { + Iterator iterator = this.players.iterator(); + + // CraftBukkit - This allows us to assume that some people are in bed but not really, allowing time to pass in spite of AFKers + boolean foundActualSleepers = false; + + EntityHuman entityhuman; + + do { + if (!iterator.hasNext()) { + // CraftBukkit + return foundActualSleepers; + } + + entityhuman = (EntityHuman) iterator.next(); + // CraftBukkit start + if (entityhuman.isDeeplySleeping()) { + foundActualSleepers = true; + } + } while (entityhuman.isDeeplySleeping() || entityhuman.fauxSleeping); + // CraftBukkit end + + return false; + } else { + return false; + } + } + + public float c(float f) { + return (this.k + (this.l - this.k) * f) * this.d(f); + } + + public float d(float f) { + return this.i + (this.j - this.i) * f; + } + + public boolean u() { + return (double) this.c(1.0F) > 0.9D; + } + + public boolean v() { + return (double) this.d(1.0F) > 0.2D; + } + + public boolean s(int i, int j, int k) { + if (!this.v()) { + return false; + } else if (!this.isChunkLoaded(i, j, k)) { + return false; + } else if (this.e(i, k) > j) { + return false; + } else { + BiomeBase biomebase = this.getWorldChunkManager().getBiome(i, k); + + return biomebase.c() ? false : biomebase.d(); + } + } + + public void a(String s, WorldMapBase worldmapbase) { + this.worldMaps.a(s, worldmapbase); + } + + public WorldMapBase a(Class oclass, String s) { + return this.worldMaps.a(oclass, s); + } + + public int b(String s) { + return this.worldMaps.a(s); + } + + public void e(int i, int j, int k, int l, int i1) { + this.a((EntityHuman) null, i, j, k, l, i1); + } + + public void a(EntityHuman entityhuman, int i, int j, int k, int l, int i1) { + for (int j1 = 0; j1 < this.u.size(); ++j1) { + ((IWorldAccess) this.u.get(j1)).a(entityhuman, i, j, k, l, i1); + } + } + + // CraftBukkit start + public UUID getUUID() { + return this.w.getUUID(); + } + // CraftBukkit end +} diff --git a/src/main/java/net/minecraft/server/WorldChunkManager.java b/src/main/java/net/minecraft/server/WorldChunkManager.java new file mode 100644 index 0000000..3eff865 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldChunkManager.java @@ -0,0 +1,121 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldChunkManager { + + private NoiseGeneratorOctaves2 e; + private NoiseGeneratorOctaves2 f; + private NoiseGeneratorOctaves2 g; + public double[] temperature; + public double[] rain; + public double[] c; + public BiomeBase[] d; + + protected WorldChunkManager() {} + + public WorldChunkManager(World world) { + this.e = new NoiseGeneratorOctaves2(new Random(world.getSeed() * 9871L), 4); + this.f = new NoiseGeneratorOctaves2(new Random(world.getSeed() * 39811L), 4); + this.g = new NoiseGeneratorOctaves2(new Random(world.getSeed() * 543321L), 2); + } + + public BiomeBase a(ChunkCoordIntPair chunkcoordintpair) { + return this.getBiome(chunkcoordintpair.x << 4, chunkcoordintpair.z << 4); + } + + public BiomeBase getBiome(int i, int j) { + return this.getBiomeData(i, j, 1, 1)[0]; + } + + public BiomeBase[] getBiomeData(int i, int j, int k, int l) { + this.d = this.a(this.d, i, j, k, l); + return this.d; + } + + public double[] a(double[] adouble, int i, int j, int k, int l) { + if (adouble == null || adouble.length < k * l) { + adouble = new double[k * l]; + } + + adouble = this.e.a(adouble, (double) i, (double) j, k, l, 0.02500000037252903D, 0.02500000037252903D, 0.25D); + this.c = this.g.a(this.c, (double) i, (double) j, k, l, 0.25D, 0.25D, 0.5882352941176471D); + int i1 = 0; + + for (int j1 = 0; j1 < k; ++j1) { + for (int k1 = 0; k1 < l; ++k1) { + double d0 = this.c[i1] * 1.1D + 0.5D; + double d1 = 0.01D; + double d2 = 1.0D - d1; + double d3 = (adouble[i1] * 0.15D + 0.7D) * d2 + d0 * d1; + + d3 = 1.0D - (1.0D - d3) * (1.0D - d3); + if (d3 < 0.0D) { + d3 = 0.0D; + } + + if (d3 > 1.0D) { + d3 = 1.0D; + } + + adouble[i1] = d3; + ++i1; + } + } + + return adouble; + } + + public BiomeBase[] a(BiomeBase[] abiomebase, int i, int j, int k, int l) { + if (abiomebase == null || abiomebase.length < k * l) { + abiomebase = new BiomeBase[k * l]; + } + + this.temperature = this.e.a(this.temperature, (double) i, (double) j, k, k, 0.02500000037252903D, 0.02500000037252903D, 0.25D); + this.rain = this.f.a(this.rain, (double) i, (double) j, k, k, 0.05000000074505806D, 0.05000000074505806D, 0.3333333333333333D); + this.c = this.g.a(this.c, (double) i, (double) j, k, k, 0.25D, 0.25D, 0.5882352941176471D); + int i1 = 0; + + for (int j1 = 0; j1 < k; ++j1) { + for (int k1 = 0; k1 < l; ++k1) { + double d0 = this.c[i1] * 1.1D + 0.5D; + double d1 = 0.01D; + double d2 = 1.0D - d1; + double d3 = (this.temperature[i1] * 0.15D + 0.7D) * d2 + d0 * d1; + + d1 = 0.0020D; + d2 = 1.0D - d1; + double d4 = (this.rain[i1] * 0.15D + 0.5D) * d2 + d0 * d1; + + d3 = 1.0D - (1.0D - d3) * (1.0D - d3); + if (d3 < 0.0D) { + d3 = 0.0D; + } + + if (d4 < 0.0D) { + d4 = 0.0D; + } + + if (d3 > 1.0D) { + d3 = 1.0D; + } + + if (d4 > 1.0D) { + d4 = 1.0D; + } + + this.temperature[i1] = d3; + this.rain[i1] = d4; + abiomebase[i1++] = BiomeBase.a(d3, d4); + } + } + + return abiomebase; + } + + // CraftBukkit start + public double getHumidity(int x, int z) { + return this.f.a(this.rain, (double)x, (double)z, 1, 1, 0.05000000074505806D, 0.05000000074505806D, 0.3333333333333333D)[0]; + } + // CraftBukkit end +} diff --git a/src/main/java/net/minecraft/server/WorldChunkManagerHell.java b/src/main/java/net/minecraft/server/WorldChunkManagerHell.java new file mode 100644 index 0000000..031c6b4 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldChunkManagerHell.java @@ -0,0 +1,54 @@ +package net.minecraft.server; + +import java.util.Arrays; + +public class WorldChunkManagerHell extends WorldChunkManager { + + private BiomeBase e; + private double f; + private double g; + + public WorldChunkManagerHell(BiomeBase biomebase, double d0, double d1) { + this.e = biomebase; + this.f = d0; + this.g = d1; + } + + public BiomeBase a(ChunkCoordIntPair chunkcoordintpair) { + return this.e; + } + + public BiomeBase getBiome(int i, int j) { + return this.e; + } + + public BiomeBase[] getBiomeData(int i, int j, int k, int l) { + this.d = this.a(this.d, i, j, k, l); + return this.d; + } + + public double[] a(double[] adouble, int i, int j, int k, int l) { + if (adouble == null || adouble.length < k * l) { + adouble = new double[k * l]; + } + + Arrays.fill(adouble, 0, k * l, this.f); + return adouble; + } + + public BiomeBase[] a(BiomeBase[] abiomebase, int i, int j, int k, int l) { + if (abiomebase == null || abiomebase.length < k * l) { + abiomebase = new BiomeBase[k * l]; + } + + if (this.temperature == null || this.temperature.length < k * l) { + this.temperature = new double[k * l]; + this.rain = new double[k * l]; + } + + Arrays.fill(abiomebase, 0, k * l, this.e); + Arrays.fill(this.rain, 0, k * l, this.g); + Arrays.fill(this.temperature, 0, k * l, this.f); + return abiomebase; + } +} diff --git a/src/main/java/net/minecraft/server/WorldData.java b/src/main/java/net/minecraft/server/WorldData.java new file mode 100644 index 0000000..ccb39e4 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldData.java @@ -0,0 +1,225 @@ +package net.minecraft.server; + +import java.util.List; + +public class WorldData { + + private long a; + private int b; + private int c; + private int d; + private float yaw; // Poseidon + private float pitch; // Poseidon + private long e; + private long f; + private long g; + private NBTTagCompound h; + private int i; + public String name; // CraftBukkit - private -> public + private int k; + private boolean l; + private int m; + private boolean n; + private int o; + + public WorldData(NBTTagCompound nbttagcompound) { + this.a = nbttagcompound.getLong("RandomSeed"); + this.b = nbttagcompound.e("SpawnX"); + this.c = nbttagcompound.e("SpawnY"); + this.d = nbttagcompound.e("SpawnZ"); + this.yaw = nbttagcompound.g("SpawnYaw"); // Poseidon + this.pitch = nbttagcompound.g("SpawnPitch"); // Poseidon + this.e = nbttagcompound.getLong("Time"); + this.f = nbttagcompound.getLong("LastPlayed"); + this.g = nbttagcompound.getLong("SizeOnDisk"); + this.name = nbttagcompound.getString("LevelName"); + this.k = nbttagcompound.e("version"); + this.m = nbttagcompound.e("rainTime"); + this.l = nbttagcompound.m("raining"); + this.o = nbttagcompound.e("thunderTime"); + this.n = nbttagcompound.m("thundering"); + if (nbttagcompound.hasKey("Player")) { + this.h = nbttagcompound.k("Player"); + this.i = this.h.e("Dimension"); + } + } + + public WorldData(long i, String s) { + this.a = i; + this.name = s; + } + + public WorldData(WorldData worlddata) { + this.a = worlddata.a; + this.b = worlddata.b; + this.c = worlddata.c; + this.d = worlddata.d; + this.yaw = worlddata.yaw; // Poseidon + this.pitch = worlddata.pitch; // Poseidon + this.e = worlddata.e; + this.f = worlddata.f; + this.g = worlddata.g; + this.h = worlddata.h; + this.i = worlddata.i; + this.name = worlddata.name; + this.k = worlddata.k; + this.m = worlddata.m; + this.l = worlddata.l; + this.o = worlddata.o; + this.n = worlddata.n; + } + + public NBTTagCompound a() { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + + this.a(nbttagcompound, this.h); + return nbttagcompound; + } + + public NBTTagCompound a(List list) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + EntityHuman entityhuman = null; + NBTTagCompound nbttagcompound1 = null; + + if (list.size() > 0) { + entityhuman = (EntityHuman) list.get(0); + } + + if (entityhuman != null) { + nbttagcompound1 = new NBTTagCompound(); + entityhuman.d(nbttagcompound1); + } + + this.a(nbttagcompound, nbttagcompound1); + return nbttagcompound; + } + + private void a(NBTTagCompound nbttagcompound, NBTTagCompound nbttagcompound1) { + nbttagcompound.setLong("RandomSeed", this.a); + nbttagcompound.a("SpawnX", this.b); + nbttagcompound.a("SpawnY", this.c); + nbttagcompound.a("SpawnZ", this.d); + nbttagcompound.a("SpawnYaw", this.yaw); // Poseidon + nbttagcompound.a("SpawnPitch", this.pitch); // Poseidon + nbttagcompound.setLong("Time", this.e); + nbttagcompound.setLong("SizeOnDisk", this.g); + nbttagcompound.setLong("LastPlayed", System.currentTimeMillis()); + nbttagcompound.setString("LevelName", this.name); + nbttagcompound.a("version", this.k); + nbttagcompound.a("rainTime", this.m); + nbttagcompound.a("raining", this.l); + nbttagcompound.a("thunderTime", this.o); + nbttagcompound.a("thundering", this.n); + if (nbttagcompound1 != null) { + nbttagcompound.a("Player", nbttagcompound1); + } + } + + public long getSeed() { + return this.a; + } + + public int c() { + return this.b; + } + + public int d() { + return this.c; + } + + public int e() { + return this.d; + } + + // Poseidon start + public float getYaw() { + return this.yaw; + } + + public float getPitch() { + return this.pitch; + } + + // Poseidon end + + public long f() { + return this.e; + } + + public long g() { + return this.g; + } + + public int h() { + return this.i; + } + + public void a(long i) { + this.e = i; + } + + public void b(long i) { + this.g = i; + } + + public void setSpawn(int i, int j, int k) { + this.b = i; + this.c = j; + this.d = k; + } + + // Poseidon start + public void setSpawn(int i, int j, int k, float yaw, float pitch) { + this.b = i; + this.c = j; + this.d = k; + this.yaw = yaw; + this.pitch = pitch; + } + + // Poseidon end + + public void a(String s) { + this.name = s; + } + + public int i() { + return this.k; + } + + public void a(int i) { + this.k = i; + } + + public boolean isThundering() { + return this.n; + } + + public void setThundering(boolean flag) { + this.n = flag; + } + + public int getThunderDuration() { + return this.o; + } + + public void setThunderDuration(int i) { + this.o = i; + } + + public boolean hasStorm() { + return this.l; + } + + public void setStorm(boolean flag) { + this.l = flag; + } + + public int getWeatherDuration() { + return this.m; + } + + public void setWeatherDuration(int i) { + this.m = i; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenBigTree.java b/src/main/java/net/minecraft/server/WorldGenBigTree.java new file mode 100644 index 0000000..f5e4b99 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenBigTree.java @@ -0,0 +1,369 @@ +package net.minecraft.server; + +import org.bukkit.BlockChangeDelegate; + +import java.util.Random; + +public class WorldGenBigTree extends WorldGenerator { + + static final byte[] a = new byte[] { (byte) 2, (byte) 0, (byte) 0, (byte) 1, (byte) 2, (byte) 1}; + Random b = new Random(); + BlockChangeDelegate c; // CraftBukkit + int[] d = new int[] { 0, 0, 0}; + int e = 0; + int f; + double g = 0.618D; + double h = 1.0D; + double i = 0.381D; + double j = 1.0D; + double k = 1.0D; + int l = 1; + int m = 12; + int n = 4; + int[][] o; + + public WorldGenBigTree() {} + + void a() { + this.f = (int) ((double) this.e * this.g); + if (this.f >= this.e) { + this.f = this.e - 1; + } + + int i = (int) (1.382D + Math.pow(this.k * (double) this.e / 13.0D, 2.0D)); + + if (i < 1) { + i = 1; + } + + int[][] aint = new int[i * this.e][4]; + int j = this.d[1] + this.e - this.n; + int k = 1; + int l = this.d[1] + this.f; + int i1 = j - this.d[1]; + + aint[0][0] = this.d[0]; + aint[0][1] = j; + aint[0][2] = this.d[2]; + aint[0][3] = l; + --j; + + while (i1 >= 0) { + int j1 = 0; + float f = this.a(i1); + + if (f < 0.0F) { + --j; + --i1; + } else { + for (double d0 = 0.5D; j1 < i; ++j1) { + double d1 = this.j * (double) f * ((double) this.b.nextFloat() + 0.328D); + double d2 = (double) this.b.nextFloat() * 2.0D * 3.14159D; + int k1 = MathHelper.floor(d1 * Math.sin(d2) + (double) this.d[0] + d0); + int l1 = MathHelper.floor(d1 * Math.cos(d2) + (double) this.d[2] + d0); + int[] aint1 = new int[] { k1, j, l1}; + int[] aint2 = new int[] { k1, j + this.n, l1}; + + if (this.a(aint1, aint2) == -1) { + int[] aint3 = new int[] { this.d[0], this.d[1], this.d[2]}; + double d3 = Math.sqrt(Math.pow((double) Math.abs(this.d[0] - aint1[0]), 2.0D) + Math.pow((double) Math.abs(this.d[2] - aint1[2]), 2.0D)); + double d4 = d3 * this.i; + + if ((double) aint1[1] - d4 > (double) l) { + aint3[1] = l; + } else { + aint3[1] = (int) ((double) aint1[1] - d4); + } + + if (this.a(aint3, aint1) == -1) { + aint[k][0] = k1; + aint[k][1] = j; + aint[k][2] = l1; + aint[k][3] = aint3[1]; + ++k; + } + } + } + + --j; + --i1; + } + } + + this.o = new int[k][4]; + System.arraycopy(aint, 0, this.o, 0, k); + } + + void a(int i, int j, int k, float f, byte b0, int l) { + int i1 = (int) ((double) f + 0.618D); + byte b1 = a[b0]; + byte b2 = a[b0 + 3]; + int[] aint = new int[] { i, j, k}; + int[] aint1 = new int[] { 0, 0, 0}; + int j1 = -i1; + int k1 = -i1; + + for (aint1[b0] = aint[b0]; j1 <= i1; ++j1) { + aint1[b1] = aint[b1] + j1; + k1 = -i1; + + while (k1 <= i1) { + double d0 = Math.sqrt(Math.pow((double) Math.abs(j1) + 0.5D, 2.0D) + Math.pow((double) Math.abs(k1) + 0.5D, 2.0D)); + + if (d0 > (double) f) { + ++k1; + } else { + aint1[b2] = aint[b2] + k1; + int l1 = this.c.getTypeId(aint1[0], aint1[1], aint1[2]); + + if (l1 != 0 && l1 != 18) { + ++k1; + } else { + this.c.setRawTypeId(aint1[0], aint1[1], aint1[2], l); + ++k1; + } + } + } + } + } + + float a(int i) { + if ((double) i < (double) ((float) this.e) * 0.3D) { + return -1.618F; + } else { + float f = (float) this.e / 2.0F; + float f1 = (float) this.e / 2.0F - (float) i; + float f2; + + if (f1 == 0.0F) { + f2 = f; + } else if (Math.abs(f1) >= f) { + f2 = 0.0F; + } else { + f2 = (float) Math.sqrt(Math.pow((double) Math.abs(f), 2.0D) - Math.pow((double) Math.abs(f1), 2.0D)); + } + + f2 *= 0.5F; + return f2; + } + } + + float b(int i) { + return i >= 0 && i < this.n ? (i != 0 && i != this.n - 1 ? 3.0F : 2.0F) : -1.0F; + } + + void a(int i, int j, int k) { + int l = j; + + for (int i1 = j + this.n; l < i1; ++l) { + float f = this.b(l - j); + + this.a(i, l, k, f, (byte) 1, 18); + } + } + + void a(int[] aint, int[] aint1, int i) { + int[] aint2 = new int[] { 0, 0, 0}; + byte b0 = 0; + + byte b1; + + for (b1 = 0; b0 < 3; ++b0) { + aint2[b0] = aint1[b0] - aint[b0]; + if (Math.abs(aint2[b0]) > Math.abs(aint2[b1])) { + b1 = b0; + } + } + + if (aint2[b1] != 0) { + byte b2 = a[b1]; + byte b3 = a[b1 + 3]; + byte b4; + + if (aint2[b1] > 0) { + b4 = 1; + } else { + b4 = -1; + } + + double d0 = (double) aint2[b2] / (double) aint2[b1]; + double d1 = (double) aint2[b3] / (double) aint2[b1]; + int[] aint3 = new int[] { 0, 0, 0}; + int j = 0; + + for (int k = aint2[b1] + b4; j != k; j += b4) { + aint3[b1] = MathHelper.floor((double) (aint[b1] + j) + 0.5D); + aint3[b2] = MathHelper.floor((double) aint[b2] + (double) j * d0 + 0.5D); + aint3[b3] = MathHelper.floor((double) aint[b3] + (double) j * d1 + 0.5D); + this.c.setRawTypeId(aint3[0], aint3[1], aint3[2], i); + } + } + } + + void b() { + int i = 0; + + for (int j = this.o.length; i < j; ++i) { + int k = this.o[i][0]; + int l = this.o[i][1]; + int i1 = this.o[i][2]; + + this.a(k, l, i1); + } + } + + boolean c(int i) { + return (double) i >= (double) this.e * 0.2D; + } + + void c() { + int i = this.d[0]; + int j = this.d[1]; + int k = this.d[1] + this.f; + int l = this.d[2]; + int[] aint = new int[] { i, j, l}; + int[] aint1 = new int[] { i, k, l}; + + this.a(aint, aint1, 17); + if (this.l == 2) { + ++aint[0]; + ++aint1[0]; + this.a(aint, aint1, 17); + ++aint[2]; + ++aint1[2]; + this.a(aint, aint1, 17); + aint[0] += -1; + aint1[0] += -1; + this.a(aint, aint1, 17); + } + } + + void d() { + int i = 0; + int j = this.o.length; + + for (int[] aint = new int[] { this.d[0], this.d[1], this.d[2]}; i < j; ++i) { + int[] aint1 = this.o[i]; + int[] aint2 = new int[] { aint1[0], aint1[1], aint1[2]}; + + aint[1] = aint1[3]; + int k = aint[1] - this.d[1]; + + if (this.c(k)) { + this.a(aint, aint2, 17); + } + } + } + + int a(int[] aint, int[] aint1) { + int[] aint2 = new int[] { 0, 0, 0}; + byte b0 = 0; + + byte b1; + + for (b1 = 0; b0 < 3; ++b0) { + aint2[b0] = aint1[b0] - aint[b0]; + if (Math.abs(aint2[b0]) > Math.abs(aint2[b1])) { + b1 = b0; + } + } + + if (aint2[b1] == 0) { + return -1; + } else { + byte b2 = a[b1]; + byte b3 = a[b1 + 3]; + byte b4; + + if (aint2[b1] > 0) { + b4 = 1; + } else { + b4 = -1; + } + + double d0 = (double) aint2[b2] / (double) aint2[b1]; + double d1 = (double) aint2[b3] / (double) aint2[b1]; + int[] aint3 = new int[] { 0, 0, 0}; + int i = 0; + + int j; + + for (j = aint2[b1] + b4; i != j; i += b4) { + aint3[b1] = aint[b1] + i; + aint3[b2] = MathHelper.floor((double) aint[b2] + (double) i * d0); + aint3[b3] = MathHelper.floor((double) aint[b3] + (double) i * d1); + int k = this.c.getTypeId(aint3[0], aint3[1], aint3[2]); + + if (k != 0 && k != 18) { + break; + } + } + + return i == j ? -1 : Math.abs(i); + } + } + + boolean e() { + int[] aint = new int[] { this.d[0], this.d[1], this.d[2]}; + int[] aint1 = new int[] { this.d[0], this.d[1] + this.e - 1, this.d[2]}; + int i = this.c.getTypeId(this.d[0], this.d[1] - 1, this.d[2]); + + if (i != 2 && i != 3) { + return false; + } else { + int j = this.a(aint, aint1); + + if (j == -1) { + return true; + } else if (j < 6) { + return false; + } else { + this.e = j; + return true; + } + } + } + + public void a(double d0, double d1, double d2) { + this.m = (int) (d0 * 12.0D); + if (d0 > 0.5D) { + this.n = 5; + } + + this.j = d1; + this.k = d2; + } + + public boolean a(World world, Random random, int i, int j, int k) { + // CraftBukkit start + // sk: The idea is to have (our) WorldServer implement + // BlockChangeDelegate and then we can implicitly cast World to + // WorldServer (a safe cast, AFAIK) and no code will be broken. This + // then allows plugins to catch manually-invoked generation events + return this.generate((BlockChangeDelegate) world, random, i, j, k); + } + + public boolean generate(BlockChangeDelegate world, Random random, int i, int j, int k) { + // CraftBukkit end + this.c = world; + long l = random.nextLong(); + + this.b.setSeed(l); + this.d[0] = i; + this.d[1] = j; + this.d[2] = k; + if (this.e == 0) { + this.e = 5 + this.b.nextInt(this.m); + } + + if (!this.e()) { + return false; + } else { + this.a(); + this.b(); + this.c(); + this.d(); + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenCactus.java b/src/main/java/net/minecraft/server/WorldGenCactus.java new file mode 100644 index 0000000..02b32d9 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenCactus.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenCactus extends WorldGenerator { + + public WorldGenCactus() {} + + public boolean a(World world, Random random, int i, int j, int k) { + for (int l = 0; l < 10; ++l) { + int i1 = i + random.nextInt(8) - random.nextInt(8); + int j1 = j + random.nextInt(4) - random.nextInt(4); + int k1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.isEmpty(i1, j1, k1)) { + int l1 = 1 + random.nextInt(random.nextInt(3) + 1); + + for (int i2 = 0; i2 < l1; ++i2) { + if (Block.CACTUS.f(world, i1, j1 + i2, k1)) { + world.setRawTypeId(i1, j1 + i2, k1, Block.CACTUS.id); + } + } + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenClay.java b/src/main/java/net/minecraft/server/WorldGenClay.java new file mode 100644 index 0000000..0f16a82 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenClay.java @@ -0,0 +1,63 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenClay extends WorldGenerator { + + private int a; + private int b; + + public WorldGenClay(int i) { + this.a = Block.CLAY.id; + this.b = i; + } + + public boolean a(World world, Random random, int i, int j, int k) { + if (world.getMaterial(i, j, k) != Material.WATER) { + return false; + } else { + float f = random.nextFloat() * 3.1415927F; + double d0 = (double) ((float) (i + 8) + MathHelper.sin(f) * (float) this.b / 8.0F); + double d1 = (double) ((float) (i + 8) - MathHelper.sin(f) * (float) this.b / 8.0F); + double d2 = (double) ((float) (k + 8) + MathHelper.cos(f) * (float) this.b / 8.0F); + double d3 = (double) ((float) (k + 8) - MathHelper.cos(f) * (float) this.b / 8.0F); + double d4 = (double) (j + random.nextInt(3) + 2); + double d5 = (double) (j + random.nextInt(3) + 2); + + for (int l = 0; l <= this.b; ++l) { + double d6 = d0 + (d1 - d0) * (double) l / (double) this.b; + double d7 = d4 + (d5 - d4) * (double) l / (double) this.b; + double d8 = d2 + (d3 - d2) * (double) l / (double) this.b; + double d9 = random.nextDouble() * (double) this.b / 16.0D; + double d10 = (double) (MathHelper.sin((float) l * 3.1415927F / (float) this.b) + 1.0F) * d9 + 1.0D; + double d11 = (double) (MathHelper.sin((float) l * 3.1415927F / (float) this.b) + 1.0F) * d9 + 1.0D; + int i1 = MathHelper.floor(d6 - d10 / 2.0D); + int j1 = MathHelper.floor(d6 + d10 / 2.0D); + int k1 = MathHelper.floor(d7 - d11 / 2.0D); + int l1 = MathHelper.floor(d7 + d11 / 2.0D); + int i2 = MathHelper.floor(d8 - d10 / 2.0D); // CraftBukkit - d6 -> d8 + int j2 = MathHelper.floor(d8 + d10 / 2.0D); // CraftBukkit - d6 -> d8 + + for (int k2 = i1; k2 <= j1; ++k2) { + for (int l2 = k1; l2 <= l1; ++l2) { + for (int i3 = i2; i3 <= j2; ++i3) { + double d12 = ((double) k2 + 0.5D - d6) / (d10 / 2.0D); + double d13 = ((double) l2 + 0.5D - d7) / (d11 / 2.0D); + double d14 = ((double) i3 + 0.5D - d8) / (d10 / 2.0D); + + if (d12 * d12 + d13 * d13 + d14 * d14 < 1.0D) { + int j3 = world.getTypeId(k2, l2, i3); + + if (j3 == Block.SAND.id) { + world.setRawTypeId(k2, l2, i3, this.a); + } + } + } + } + } + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenDeadBush.java b/src/main/java/net/minecraft/server/WorldGenDeadBush.java new file mode 100644 index 0000000..c99fcc8 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenDeadBush.java @@ -0,0 +1,32 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenDeadBush extends WorldGenerator { + + private int a; + + public WorldGenDeadBush(int i) { + this.a = i; + } + + public boolean a(World world, Random random, int i, int j, int k) { + int l; + + for (boolean flag = false; ((l = world.getTypeId(i, j, k)) == 0 || l == Block.LEAVES.id) && j > 0; --j) { + ; + } + + for (int i1 = 0; i1 < 4; ++i1) { + int j1 = i + random.nextInt(8) - random.nextInt(8); + int k1 = j + random.nextInt(4) - random.nextInt(4); + int l1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.isEmpty(j1, k1, l1) && ((BlockFlower) Block.byId[this.a]).f(world, j1, k1, l1)) { + world.setRawTypeId(j1, k1, l1, this.a); + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenDungeons.java b/src/main/java/net/minecraft/server/WorldGenDungeons.java new file mode 100644 index 0000000..f398ea1 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenDungeons.java @@ -0,0 +1,134 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenDungeons extends WorldGenerator { + + public WorldGenDungeons() {} + + public boolean a(World world, Random random, int i, int j, int k) { + byte b0 = 3; + int l = random.nextInt(2) + 2; + int i1 = random.nextInt(2) + 2; + int j1 = 0; + + int k1; + int l1; + int i2; + + for (k1 = i - l - 1; k1 <= i + l + 1; ++k1) { + for (l1 = j - 1; l1 <= j + b0 + 1; ++l1) { + for (i2 = k - i1 - 1; i2 <= k + i1 + 1; ++i2) { + Material material = world.getMaterial(k1, l1, i2); + + if (l1 == j - 1 && !material.isBuildable()) { + return false; + } + + if (l1 == j + b0 + 1 && !material.isBuildable()) { + return false; + } + + if ((k1 == i - l - 1 || k1 == i + l + 1 || i2 == k - i1 - 1 || i2 == k + i1 + 1) && l1 == j && world.isEmpty(k1, l1, i2) && world.isEmpty(k1, l1 + 1, i2)) { + ++j1; + } + } + } + } + + if (j1 >= 1 && j1 <= 5) { + for (k1 = i - l - 1; k1 <= i + l + 1; ++k1) { + for (l1 = j + b0; l1 >= j - 1; --l1) { + for (i2 = k - i1 - 1; i2 <= k + i1 + 1; ++i2) { + if (k1 != i - l - 1 && l1 != j - 1 && i2 != k - i1 - 1 && k1 != i + l + 1 && l1 != j + b0 + 1 && i2 != k + i1 + 1) { + world.setTypeId(k1, l1, i2, 0); + } else if (l1 >= 0 && !world.getMaterial(k1, l1 - 1, i2).isBuildable()) { + world.setTypeId(k1, l1, i2, 0); + } else if (world.getMaterial(k1, l1, i2).isBuildable()) { + if (l1 == j - 1 && random.nextInt(4) != 0) { + world.setTypeId(k1, l1, i2, Block.MOSSY_COBBLESTONE.id); + } else { + world.setTypeId(k1, l1, i2, Block.COBBLESTONE.id); + } + } + } + } + } + + k1 = 0; + + while (k1 < 2) { + l1 = 0; + + while (true) { + if (l1 < 3) { + label204: { + i2 = i + random.nextInt(l * 2 + 1) - l; + int j2 = k + random.nextInt(i1 * 2 + 1) - i1; + + if (world.isEmpty(i2, j, j2)) { + int k2 = 0; + + if (world.getMaterial(i2 - 1, j, j2).isBuildable()) { + ++k2; + } + + if (world.getMaterial(i2 + 1, j, j2).isBuildable()) { + ++k2; + } + + if (world.getMaterial(i2, j, j2 - 1).isBuildable()) { + ++k2; + } + + if (world.getMaterial(i2, j, j2 + 1).isBuildable()) { + ++k2; + } + + if (k2 == 1) { + world.setTypeId(i2, j, j2, Block.CHEST.id); + TileEntityChest tileentitychest = (TileEntityChest) world.getTileEntity(i2, j, j2); + + for (int l2 = 0; l2 < 8; ++l2) { + ItemStack itemstack = this.a(random); + + if (itemstack != null) { + tileentitychest.setItem(random.nextInt(tileentitychest.getSize()), itemstack); + } + } + break label204; + } + } + + ++l1; + continue; + } + } + + ++k1; + break; + } + } + + world.setTypeId(i, j, k, Block.MOB_SPAWNER.id); + TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner) world.getTileEntity(i, j, k); + + tileentitymobspawner.a(this.b(random)); + return true; + } else { + return false; + } + } + + private ItemStack a(Random random) { + int i = random.nextInt(11); + + return i == 0 ? new ItemStack(Item.SADDLE) : (i == 1 ? new ItemStack(Item.IRON_INGOT, random.nextInt(4) + 1) : (i == 2 ? new ItemStack(Item.BREAD) : (i == 3 ? new ItemStack(Item.WHEAT, random.nextInt(4) + 1) : (i == 4 ? new ItemStack(Item.SULPHUR, random.nextInt(4) + 1) : (i == 5 ? new ItemStack(Item.STRING, random.nextInt(4) + 1) : (i == 6 ? new ItemStack(Item.BUCKET) : (i == 7 && random.nextInt(100) == 0 ? new ItemStack(Item.GOLDEN_APPLE) : (i == 8 && random.nextInt(2) == 0 ? new ItemStack(Item.REDSTONE, random.nextInt(4) + 1) : (i == 9 && random.nextInt(10) == 0 ? new ItemStack(Item.byId[Item.GOLD_RECORD.id + random.nextInt(2)]) : (i == 10 ? new ItemStack(Item.INK_SACK, 1, 3) : null)))))))))); + } + + private String b(Random random) { + int i = random.nextInt(4); + + return i == 0 ? "Skeleton" : (i == 1 ? "Zombie" : (i == 2 ? "Zombie" : (i == 3 ? "Spider" : ""))); + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenFire.java b/src/main/java/net/minecraft/server/WorldGenFire.java new file mode 100644 index 0000000..75b01de --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenFire.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenFire extends WorldGenerator { + + public WorldGenFire() {} + + public boolean a(World world, Random random, int i, int j, int k) { + for (int l = 0; l < 64; ++l) { + int i1 = i + random.nextInt(8) - random.nextInt(8); + int j1 = j + random.nextInt(4) - random.nextInt(4); + int k1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.isEmpty(i1, j1, k1) && world.getTypeId(i1, j1 - 1, k1) == Block.NETHERRACK.id) { + world.setTypeId(i1, j1, k1, Block.FIRE.id); + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenFlowers.java b/src/main/java/net/minecraft/server/WorldGenFlowers.java new file mode 100644 index 0000000..673eff5 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenFlowers.java @@ -0,0 +1,26 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenFlowers extends WorldGenerator { + + private int a; + + public WorldGenFlowers(int i) { + this.a = i; + } + + public boolean a(World world, Random random, int i, int j, int k) { + for (int l = 0; l < 64; ++l) { + int i1 = i + random.nextInt(8) - random.nextInt(8); + int j1 = j + random.nextInt(4) - random.nextInt(4); + int k1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.isEmpty(i1, j1, k1) && ((BlockFlower) Block.byId[this.a]).f(world, i1, j1, k1)) { + world.setRawTypeId(i1, j1, k1, this.a); + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenForest.java b/src/main/java/net/minecraft/server/WorldGenForest.java new file mode 100644 index 0000000..6a7543a --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenForest.java @@ -0,0 +1,98 @@ +package net.minecraft.server; + +import org.bukkit.BlockChangeDelegate; + +import java.util.Random; + +public class WorldGenForest extends WorldGenerator { + + public WorldGenForest() {} + + public boolean a(World world, Random random, int i, int j, int k) { + // CraftBukkit start + // sk: The idea is to have (our) WorldServer implement + // BlockChangeDelegate and then we can implicitly cast World to + // WorldServer (a safe cast, AFAIK) and no code will be broken. This + // then allows plugins to catch manually-invoked generation events + return this.generate((BlockChangeDelegate) world, random, i, j, k); + } + + public boolean generate(BlockChangeDelegate world, Random random, int i, int j, int k) { + // CraftBukkit end + int l = random.nextInt(3) + 5; + boolean flag = true; + + if (j >= 1 && j + l + 1 <= 128) { + int i1; + int j1; + int k1; + int l1; + + for (i1 = j; i1 <= j + 1 + l; ++i1) { + byte b0 = 1; + + if (i1 == j) { + b0 = 0; + } + + if (i1 >= j + 1 + l - 2) { + b0 = 2; + } + + for (j1 = i - b0; j1 <= i + b0 && flag; ++j1) { + for (k1 = k - b0; k1 <= k + b0 && flag; ++k1) { + if (i1 >= 0 && i1 < 128) { + l1 = world.getTypeId(j1, i1, k1); + if (l1 != 0 && l1 != Block.LEAVES.id) { + flag = false; + } + } else { + flag = false; + } + } + } + } + + if (!flag) { + return false; + } else { + i1 = world.getTypeId(i, j - 1, k); + if ((i1 == Block.GRASS.id || i1 == Block.DIRT.id) && j < 128 - l - 1) { + world.setRawTypeId(i, j - 1, k, Block.DIRT.id); + + int i2; + + for (i2 = j - 3 + l; i2 <= j + l; ++i2) { + j1 = i2 - (j + l); + k1 = 1 - j1 / 2; + + for (l1 = i - k1; l1 <= i + k1; ++l1) { + int j2 = l1 - i; + + for (int k2 = k - k1; k2 <= k + k1; ++k2) { + int l2 = k2 - k; + + if ((Math.abs(j2) != k1 || Math.abs(l2) != k1 || random.nextInt(2) != 0 && j1 != 0) && !Block.o[world.getTypeId(l1, i2, k2)]) { + world.setRawTypeIdAndData(l1, i2, k2, Block.LEAVES.id, 2); + } + } + } + } + + for (i2 = 0; i2 < l; ++i2) { + j1 = world.getTypeId(i, j + i2, k); + if (j1 == 0 || j1 == Block.LEAVES.id) { + world.setRawTypeIdAndData(i, j + i2, k, Block.LOG.id, 2); + } + } + + return true; + } else { + return false; + } + } + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenGrass.java b/src/main/java/net/minecraft/server/WorldGenGrass.java new file mode 100644 index 0000000..1e5f700 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenGrass.java @@ -0,0 +1,34 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenGrass extends WorldGenerator { + + private int a; + private int b; + + public WorldGenGrass(int i, int j) { + this.a = i; + this.b = j; + } + + public boolean a(World world, Random random, int i, int j, int k) { + int l; + + for (boolean flag = false; ((l = world.getTypeId(i, j, k)) == 0 || l == Block.LEAVES.id) && j > 0; --j) { + ; + } + + for (int i1 = 0; i1 < 128; ++i1) { + int j1 = i + random.nextInt(8) - random.nextInt(8); + int k1 = j + random.nextInt(4) - random.nextInt(4); + int l1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.isEmpty(j1, k1, l1) && ((BlockFlower) Block.byId[this.a]).f(world, j1, k1, l1)) { + world.setRawTypeIdAndData(j1, k1, l1, this.a, this.b); + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenHellLava.java b/src/main/java/net/minecraft/server/WorldGenHellLava.java new file mode 100644 index 0000000..2e0cf65 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenHellLava.java @@ -0,0 +1,73 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenHellLava extends WorldGenerator { + + private int a; + + public WorldGenHellLava(int i) { + this.a = i; + } + + public boolean a(World world, Random random, int i, int j, int k) { + if (world.getTypeId(i, j + 1, k) != Block.NETHERRACK.id) { + return false; + } else if (world.getTypeId(i, j, k) != 0 && world.getTypeId(i, j, k) != Block.NETHERRACK.id) { + return false; + } else { + int l = 0; + + if (world.getTypeId(i - 1, j, k) == Block.NETHERRACK.id) { + ++l; + } + + if (world.getTypeId(i + 1, j, k) == Block.NETHERRACK.id) { + ++l; + } + + if (world.getTypeId(i, j, k - 1) == Block.NETHERRACK.id) { + ++l; + } + + if (world.getTypeId(i, j, k + 1) == Block.NETHERRACK.id) { + ++l; + } + + if (world.getTypeId(i, j - 1, k) == Block.NETHERRACK.id) { + ++l; + } + + int i1 = 0; + + if (world.isEmpty(i - 1, j, k)) { + ++i1; + } + + if (world.isEmpty(i + 1, j, k)) { + ++i1; + } + + if (world.isEmpty(i, j, k - 1)) { + ++i1; + } + + if (world.isEmpty(i, j, k + 1)) { + ++i1; + } + + if (world.isEmpty(i, j - 1, k)) { + ++i1; + } + + if (l == 4 && i1 == 1) { + world.setTypeId(i, j, k, this.a); + world.a = true; + Block.byId[this.a].a(world, i, j, k, random); + world.a = false; + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenLakes.java b/src/main/java/net/minecraft/server/WorldGenLakes.java new file mode 100644 index 0000000..9df6a09 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenLakes.java @@ -0,0 +1,108 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenLakes extends WorldGenerator { + + private int a; + + public WorldGenLakes(int i) { + this.a = i; + } + + public boolean a(World world, Random random, int i, int j, int k) { + i -= 8; + + for (k -= 8; j > 0 && world.isEmpty(i, j, k); --j) { + ; + } + + j -= 4; + boolean[] aboolean = new boolean[2048]; + int l = random.nextInt(4) + 4; + + int i1; + + for (i1 = 0; i1 < l; ++i1) { + double d0 = random.nextDouble() * 6.0D + 3.0D; + double d1 = random.nextDouble() * 4.0D + 2.0D; + double d2 = random.nextDouble() * 6.0D + 3.0D; + double d3 = random.nextDouble() * (16.0D - d0 - 2.0D) + 1.0D + d0 / 2.0D; + double d4 = random.nextDouble() * (8.0D - d1 - 4.0D) + 2.0D + d1 / 2.0D; + double d5 = random.nextDouble() * (16.0D - d2 - 2.0D) + 1.0D + d2 / 2.0D; + + for (int j1 = 1; j1 < 15; ++j1) { + for (int k1 = 1; k1 < 15; ++k1) { + for (int l1 = 1; l1 < 7; ++l1) { + double d6 = ((double) j1 - d3) / (d0 / 2.0D); + double d7 = ((double) l1 - d4) / (d1 / 2.0D); + double d8 = ((double) k1 - d5) / (d2 / 2.0D); + double d9 = d6 * d6 + d7 * d7 + d8 * d8; + + if (d9 < 1.0D) { + aboolean[(j1 * 16 + k1) * 8 + l1] = true; + } + } + } + } + } + + boolean flag; + int i2; + int j2; + + for (i1 = 0; i1 < 16; ++i1) { + for (i2 = 0; i2 < 16; ++i2) { + for (j2 = 0; j2 < 8; ++j2) { + flag = !aboolean[(i1 * 16 + i2) * 8 + j2] && (i1 < 15 && aboolean[((i1 + 1) * 16 + i2) * 8 + j2] || i1 > 0 && aboolean[((i1 - 1) * 16 + i2) * 8 + j2] || i2 < 15 && aboolean[(i1 * 16 + i2 + 1) * 8 + j2] || i2 > 0 && aboolean[(i1 * 16 + (i2 - 1)) * 8 + j2] || j2 < 7 && aboolean[(i1 * 16 + i2) * 8 + j2 + 1] || j2 > 0 && aboolean[(i1 * 16 + i2) * 8 + (j2 - 1)]); + if (flag) { + Material material = world.getMaterial(i + i1, j + j2, k + i2); + + if (j2 >= 4 && material.isLiquid()) { + return false; + } + + if (j2 < 4 && !material.isBuildable() && world.getTypeId(i + i1, j + j2, k + i2) != this.a) { + return false; + } + } + } + } + } + + for (i1 = 0; i1 < 16; ++i1) { + for (i2 = 0; i2 < 16; ++i2) { + for (j2 = 0; j2 < 8; ++j2) { + if (aboolean[(i1 * 16 + i2) * 8 + j2]) { + world.setRawTypeId(i + i1, j + j2, k + i2, j2 >= 4 ? 0 : this.a); + } + } + } + } + + for (i1 = 0; i1 < 16; ++i1) { + for (i2 = 0; i2 < 16; ++i2) { + for (j2 = 4; j2 < 8; ++j2) { + if (aboolean[(i1 * 16 + i2) * 8 + j2] && world.getTypeId(i + i1, j + j2 - 1, k + i2) == Block.DIRT.id && world.a(EnumSkyBlock.SKY, i + i1, j + j2, k + i2) > 0) { + world.setRawTypeId(i + i1, j + j2 - 1, k + i2, Block.GRASS.id); + } + } + } + } + + if (Block.byId[this.a].material == Material.LAVA) { + for (i1 = 0; i1 < 16; ++i1) { + for (i2 = 0; i2 < 16; ++i2) { + for (j2 = 0; j2 < 8; ++j2) { + flag = !aboolean[(i1 * 16 + i2) * 8 + j2] && (i1 < 15 && aboolean[((i1 + 1) * 16 + i2) * 8 + j2] || i1 > 0 && aboolean[((i1 - 1) * 16 + i2) * 8 + j2] || i2 < 15 && aboolean[(i1 * 16 + i2 + 1) * 8 + j2] || i2 > 0 && aboolean[(i1 * 16 + (i2 - 1)) * 8 + j2] || j2 < 7 && aboolean[(i1 * 16 + i2) * 8 + j2 + 1] || j2 > 0 && aboolean[(i1 * 16 + i2) * 8 + (j2 - 1)]); + if (flag && (j2 < 4 || random.nextInt(2) != 0) && world.getMaterial(i + i1, j + j2, k + i2).isBuildable()) { + world.setRawTypeId(i + i1, j + j2, k + i2, Block.STONE.id); + } + } + } + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenLightStone1.java b/src/main/java/net/minecraft/server/WorldGenLightStone1.java new file mode 100644 index 0000000..2706436 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenLightStone1.java @@ -0,0 +1,66 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenLightStone1 extends WorldGenerator { + + public WorldGenLightStone1() {} + + public boolean a(World world, Random random, int i, int j, int k) { + if (!world.isEmpty(i, j, k)) { + return false; + } else if (world.getTypeId(i, j + 1, k) != Block.NETHERRACK.id) { + return false; + } else { + world.setTypeId(i, j, k, Block.GLOWSTONE.id); + + for (int l = 0; l < 1500; ++l) { + int i1 = i + random.nextInt(8) - random.nextInt(8); + int j1 = j - random.nextInt(12); + int k1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.getTypeId(i1, j1, k1) == 0) { + int l1 = 0; + + for (int i2 = 0; i2 < 6; ++i2) { + int j2 = 0; + + if (i2 == 0) { + j2 = world.getTypeId(i1 - 1, j1, k1); + } + + if (i2 == 1) { + j2 = world.getTypeId(i1 + 1, j1, k1); + } + + if (i2 == 2) { + j2 = world.getTypeId(i1, j1 - 1, k1); + } + + if (i2 == 3) { + j2 = world.getTypeId(i1, j1 + 1, k1); + } + + if (i2 == 4) { + j2 = world.getTypeId(i1, j1, k1 - 1); + } + + if (i2 == 5) { + j2 = world.getTypeId(i1, j1, k1 + 1); + } + + if (j2 == Block.GLOWSTONE.id) { + ++l1; + } + } + + if (l1 == 1) { + world.setTypeId(i1, j1, k1, Block.GLOWSTONE.id); + } + } + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenLightStone2.java b/src/main/java/net/minecraft/server/WorldGenLightStone2.java new file mode 100644 index 0000000..97eeeac --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenLightStone2.java @@ -0,0 +1,66 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenLightStone2 extends WorldGenerator { + + public WorldGenLightStone2() {} + + public boolean a(World world, Random random, int i, int j, int k) { + if (!world.isEmpty(i, j, k)) { + return false; + } else if (world.getTypeId(i, j + 1, k) != Block.NETHERRACK.id) { + return false; + } else { + world.setTypeId(i, j, k, Block.GLOWSTONE.id); + + for (int l = 0; l < 1500; ++l) { + int i1 = i + random.nextInt(8) - random.nextInt(8); + int j1 = j - random.nextInt(12); + int k1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.getTypeId(i1, j1, k1) == 0) { + int l1 = 0; + + for (int i2 = 0; i2 < 6; ++i2) { + int j2 = 0; + + if (i2 == 0) { + j2 = world.getTypeId(i1 - 1, j1, k1); + } + + if (i2 == 1) { + j2 = world.getTypeId(i1 + 1, j1, k1); + } + + if (i2 == 2) { + j2 = world.getTypeId(i1, j1 - 1, k1); + } + + if (i2 == 3) { + j2 = world.getTypeId(i1, j1 + 1, k1); + } + + if (i2 == 4) { + j2 = world.getTypeId(i1, j1, k1 - 1); + } + + if (i2 == 5) { + j2 = world.getTypeId(i1, j1, k1 + 1); + } + + if (j2 == Block.GLOWSTONE.id) { + ++l1; + } + } + + if (l1 == 1) { + world.setTypeId(i1, j1, k1, Block.GLOWSTONE.id); + } + } + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenLiquids.java b/src/main/java/net/minecraft/server/WorldGenLiquids.java new file mode 100644 index 0000000..e5dc2d6 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenLiquids.java @@ -0,0 +1,67 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenLiquids extends WorldGenerator { + + private int a; + + public WorldGenLiquids(int i) { + this.a = i; + } + + public boolean a(World world, Random random, int i, int j, int k) { + if (world.getTypeId(i, j + 1, k) != Block.STONE.id) { + return false; + } else if (world.getTypeId(i, j - 1, k) != Block.STONE.id) { + return false; + } else if (world.getTypeId(i, j, k) != 0 && world.getTypeId(i, j, k) != Block.STONE.id) { + return false; + } else { + int l = 0; + + if (world.getTypeId(i - 1, j, k) == Block.STONE.id) { + ++l; + } + + if (world.getTypeId(i + 1, j, k) == Block.STONE.id) { + ++l; + } + + if (world.getTypeId(i, j, k - 1) == Block.STONE.id) { + ++l; + } + + if (world.getTypeId(i, j, k + 1) == Block.STONE.id) { + ++l; + } + + int i1 = 0; + + if (world.isEmpty(i - 1, j, k)) { + ++i1; + } + + if (world.isEmpty(i + 1, j, k)) { + ++i1; + } + + if (world.isEmpty(i, j, k - 1)) { + ++i1; + } + + if (world.isEmpty(i, j, k + 1)) { + ++i1; + } + + if (l == 3 && i1 == 1) { + world.setTypeId(i, j, k, this.a); + world.a = true; + Block.byId[this.a].a(world, i, j, k, random); + world.a = false; + } + + return true; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenMinable.java b/src/main/java/net/minecraft/server/WorldGenMinable.java new file mode 100644 index 0000000..bf58044 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenMinable.java @@ -0,0 +1,61 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenMinable extends WorldGenerator { + + private int a; + private int b; + + public WorldGenMinable(int i, int j) { + this.a = i; + this.b = j; + } + + public boolean a(World world, Random random, int i, int j, int k) { + float f = random.nextFloat() * 3.1415927F; + double d0 = (double) ((float) (i + 8) + MathHelper.sin(f) * (float) this.b / 8.0F); + double d1 = (double) ((float) (i + 8) - MathHelper.sin(f) * (float) this.b / 8.0F); + double d2 = (double) ((float) (k + 8) + MathHelper.cos(f) * (float) this.b / 8.0F); + double d3 = (double) ((float) (k + 8) - MathHelper.cos(f) * (float) this.b / 8.0F); + double d4 = (double) (j + random.nextInt(3) + 2); + double d5 = (double) (j + random.nextInt(3) + 2); + + for (int l = 0; l <= this.b; ++l) { + double d6 = d0 + (d1 - d0) * (double) l / (double) this.b; + double d7 = d4 + (d5 - d4) * (double) l / (double) this.b; + double d8 = d2 + (d3 - d2) * (double) l / (double) this.b; + double d9 = random.nextDouble() * (double) this.b / 16.0D; + double d10 = (double) (MathHelper.sin((float) l * 3.1415927F / (float) this.b) + 1.0F) * d9 + 1.0D; + double d11 = (double) (MathHelper.sin((float) l * 3.1415927F / (float) this.b) + 1.0F) * d9 + 1.0D; + int i1 = MathHelper.floor(d6 - d10 / 2.0D); + int j1 = MathHelper.floor(d7 - d11 / 2.0D); + int k1 = MathHelper.floor(d8 - d10 / 2.0D); + int l1 = MathHelper.floor(d6 + d10 / 2.0D); + int i2 = MathHelper.floor(d7 + d11 / 2.0D); + int j2 = MathHelper.floor(d8 + d10 / 2.0D); + + for (int k2 = i1; k2 <= l1; ++k2) { + double d12 = ((double) k2 + 0.5D - d6) / (d10 / 2.0D); + + if (d12 * d12 < 1.0D) { + for (int l2 = j1; l2 <= i2; ++l2) { + double d13 = ((double) l2 + 0.5D - d7) / (d11 / 2.0D); + + if (d12 * d12 + d13 * d13 < 1.0D) { + for (int i3 = k1; i3 <= j2; ++i3) { + double d14 = ((double) i3 + 0.5D - d8) / (d10 / 2.0D); + + if (d12 * d12 + d13 * d13 + d14 * d14 < 1.0D && world.getTypeId(k2, l2, i3) == Block.STONE.id) { + world.setRawTypeId(k2, l2, i3, this.a); + } + } + } + } + } + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenPumpkin.java b/src/main/java/net/minecraft/server/WorldGenPumpkin.java new file mode 100644 index 0000000..c489393 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenPumpkin.java @@ -0,0 +1,22 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenPumpkin extends WorldGenerator { + + public WorldGenPumpkin() {} + + public boolean a(World world, Random random, int i, int j, int k) { + for (int l = 0; l < 64; ++l) { + int i1 = i + random.nextInt(8) - random.nextInt(8); + int j1 = j + random.nextInt(4) - random.nextInt(4); + int k1 = k + random.nextInt(8) - random.nextInt(8); + + if (world.isEmpty(i1, j1, k1) && world.getTypeId(i1, j1 - 1, k1) == Block.GRASS.id && Block.PUMPKIN.canPlace(world, i1, j1, k1)) { + world.setRawTypeIdAndData(i1, j1, k1, Block.PUMPKIN.id, random.nextInt(4)); + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenReed.java b/src/main/java/net/minecraft/server/WorldGenReed.java new file mode 100644 index 0000000..02691f7 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenReed.java @@ -0,0 +1,28 @@ +package net.minecraft.server; + +import java.util.Random; + +public class WorldGenReed extends WorldGenerator { + + public WorldGenReed() {} + + public boolean a(World world, Random random, int i, int j, int k) { + for (int l = 0; l < 20; ++l) { + int i1 = i + random.nextInt(4) - random.nextInt(4); + int j1 = j; + int k1 = k + random.nextInt(4) - random.nextInt(4); + + if (world.isEmpty(i1, j, k1) && (world.getMaterial(i1 - 1, j - 1, k1) == Material.WATER || world.getMaterial(i1 + 1, j - 1, k1) == Material.WATER || world.getMaterial(i1, j - 1, k1 - 1) == Material.WATER || world.getMaterial(i1, j - 1, k1 + 1) == Material.WATER)) { + int l1 = 2 + random.nextInt(random.nextInt(3) + 1); + + for (int i2 = 0; i2 < l1; ++i2) { + if (Block.SUGAR_CANE_BLOCK.f(world, i1, j1 + i2, k1)) { + world.setRawTypeId(i1, j1 + i2, k1, Block.SUGAR_CANE_BLOCK.id); + } + } + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenTaiga1.java b/src/main/java/net/minecraft/server/WorldGenTaiga1.java new file mode 100644 index 0000000..a892009 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenTaiga1.java @@ -0,0 +1,103 @@ +package net.minecraft.server; + +import org.bukkit.BlockChangeDelegate; + +import java.util.Random; + +public class WorldGenTaiga1 extends WorldGenerator { + + public WorldGenTaiga1() { + } + + public boolean a(World world, Random random, int i, int j, int k) { + // CraftBukkit start + // sk: The idea is to have (our) WorldServer implement + // BlockChangeDelegate and then we can implicitly cast World to + // WorldServer (a safe cast, AFAIK) and no code will be broken. This + // then allows plugins to catch manually-invoked generation events + return this.generate((BlockChangeDelegate) world, random, i, j, k); + } + + public boolean generate(BlockChangeDelegate world, Random random, int i, int j, int k) { + // CraftBukkit end + int l = random.nextInt(5) + 7; + int i1 = l - random.nextInt(2) - 3; + int j1 = l - i1; + int k1 = 1 + random.nextInt(j1 + 1); + boolean flag = true; + + if (j >= 1 && j + l + 1 <= 128) { + int l1; + int i2; + int j2; + int k2; + int l2; + + for (l1 = j; l1 <= j + 1 + l && flag; ++l1) { + boolean flag1 = true; + + if (l1 - j < i1) { + l2 = 0; + } else { + l2 = k1; + } + + for (i2 = i - l2; i2 <= i + l2 && flag; ++i2) { + for (j2 = k - l2; j2 <= k + l2 && flag; ++j2) { + if (l1 >= 0 && l1 < 128) { + k2 = world.getTypeId(i2, l1, j2); + if (k2 != 0 && k2 != Block.LEAVES.id) { + flag = false; + } + } else { + flag = false; + } + } + } + } + + if (!flag) { + return false; + } else { + l1 = world.getTypeId(i, j - 1, k); + if ((l1 == Block.GRASS.id || l1 == Block.DIRT.id) && j < 128 - l - 1) { + world.setRawTypeId(i, j - 1, k, Block.DIRT.id); + l2 = 0; + + for (i2 = j + l; i2 >= j + i1; --i2) { + for (j2 = i - l2; j2 <= i + l2; ++j2) { + k2 = j2 - i; + + for (int i3 = k - l2; i3 <= k + l2; ++i3) { + int j3 = i3 - k; + + if ((Math.abs(k2) != l2 || Math.abs(j3) != l2 || l2 <= 0) && !Block.o[world.getTypeId(j2, i2, i3)] && !Block.leafDecayBlacklist.contains(world.getTypeId(l1, i2, k2))) { + world.setRawTypeIdAndData(j2, i2, i3, Block.LEAVES.id, 1); + } + } + } + + if (l2 >= 1 && i2 == j + i1 + 1) { + --l2; + } else if (l2 < k1) { + ++l2; + } + } + + for (i2 = 0; i2 < l - 1; ++i2) { + j2 = world.getTypeId(i, j + i2, k); + if (j2 == 0 || j2 == Block.LEAVES.id) { + world.setRawTypeIdAndData(i, j + i2, k, Block.LOG.id, 1); + } + } + + return true; + } else { + return false; + } + } + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenTaiga2.java b/src/main/java/net/minecraft/server/WorldGenTaiga2.java new file mode 100644 index 0000000..aa54c6d --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenTaiga2.java @@ -0,0 +1,115 @@ +package net.minecraft.server; + +import org.bukkit.BlockChangeDelegate; + +import java.util.Random; + +public class WorldGenTaiga2 extends WorldGenerator { + + public WorldGenTaiga2() {} + + public boolean a(World world, Random random, int i, int j, int k) { + // CraftBukkit start + // sk: The idea is to have (our) WorldServer implement + // BlockChangeDelegate and then we can implicitly cast World to + // WorldServer (a safe cast, AFAIK) and no code will be broken. This + // then allows plugins to catch manually-invoked generation events + return this.generate((BlockChangeDelegate) world, random, i, j, k); + } + + public boolean generate(BlockChangeDelegate world, Random random, int i, int j, int k) { + // CraftBukkit end + int l = random.nextInt(4) + 6; + int i1 = 1 + random.nextInt(2); + int j1 = l - i1; + int k1 = 2 + random.nextInt(2); + boolean flag = true; + + if (j >= 1 && j + l + 1 <= 128) { + int l1; + int i2; + int j2; + int k2; + + for (l1 = j; l1 <= j + 1 + l && flag; ++l1) { + boolean flag1 = true; + + if (l1 - j < i1) { + k2 = 0; + } else { + k2 = k1; + } + + for (i2 = i - k2; i2 <= i + k2 && flag; ++i2) { + for (int l2 = k - k2; l2 <= k + k2 && flag; ++l2) { + if (l1 >= 0 && l1 < 128) { + j2 = world.getTypeId(i2, l1, l2); + if (j2 != 0 && j2 != Block.LEAVES.id) { + flag = false; + } + } else { + flag = false; + } + } + } + } + + if (!flag) { + return false; + } else { + l1 = world.getTypeId(i, j - 1, k); + if ((l1 == Block.GRASS.id || l1 == Block.DIRT.id) && j < 128 - l - 1) { + world.setRawTypeId(i, j - 1, k, Block.DIRT.id); + k2 = random.nextInt(2); + i2 = 1; + byte b0 = 0; + + int i3; + int j3; + + for (j2 = 0; j2 <= j1; ++j2) { + j3 = j + l - j2; + + for (i3 = i - k2; i3 <= i + k2; ++i3) { + int k3 = i3 - i; + + for (int l3 = k - k2; l3 <= k + k2; ++l3) { + int i4 = l3 - k; + + if ((Math.abs(k3) != k2 || Math.abs(i4) != k2 || k2 <= 0) && !Block.o[world.getTypeId(i3, j3, l3)] && !Block.leafDecayBlacklist.contains(world.getTypeId(l1, i2, k2))) { + world.setRawTypeIdAndData(i3, j3, l3, Block.LEAVES.id, 1); + } + } + } + + if (k2 >= i2) { + k2 = b0; + b0 = 1; + ++i2; + if (i2 > k1) { + i2 = k1; + } + } else { + ++k2; + } + } + + j2 = random.nextInt(3); + + for (j3 = 0; j3 < l - j2; ++j3) { + i3 = world.getTypeId(i, j + j3, k); + if (i3 == 0 || i3 == Block.LEAVES.id) { + world.setRawTypeIdAndData(i, j + j3, k, Block.LOG.id, 1); + } + } + + return true; + } else { + return false; + } + } + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenTrees.java b/src/main/java/net/minecraft/server/WorldGenTrees.java new file mode 100644 index 0000000..0629dbb --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenTrees.java @@ -0,0 +1,98 @@ +package net.minecraft.server; + +import org.bukkit.BlockChangeDelegate; + +import java.util.Random; + +public class WorldGenTrees extends WorldGenerator { + + public WorldGenTrees() {} + + public boolean a(World world, Random random, int i, int j, int k) { + // CraftBukkit start + // sk: The idea is to have (our) WorldServer implement + // BlockChangeDelegate and then we can implicitly cast World to + // WorldServer (a safe cast, AFAIK) and no code will be broken. This + // then allows plugins to catch manually-invoked generation events + return this.generate((BlockChangeDelegate) world, random, i, j, k); + } + + public boolean generate(BlockChangeDelegate world, Random random, int i, int j, int k) { + // CraftBukkit end + int l = random.nextInt(3) + 4; + boolean flag = true; + + if (j >= 1 && j + l + 1 <= 128) { + int i1; + int j1; + int k1; + int l1; + + for (i1 = j; i1 <= j + 1 + l; ++i1) { + byte b0 = 1; + + if (i1 == j) { + b0 = 0; + } + + if (i1 >= j + 1 + l - 2) { + b0 = 2; + } + + for (j1 = i - b0; j1 <= i + b0 && flag; ++j1) { + for (k1 = k - b0; k1 <= k + b0 && flag; ++k1) { + if (i1 >= 0 && i1 < 128) { + l1 = world.getTypeId(j1, i1, k1); + if (l1 != 0 && l1 != Block.LEAVES.id) { + flag = false; + } + } else { + flag = false; + } + } + } + } + + if (!flag) { + return false; + } else { + i1 = world.getTypeId(i, j - 1, k); + if ((i1 == Block.GRASS.id || i1 == Block.DIRT.id) && j < 128 - l - 1) { + world.setRawTypeId(i, j - 1, k, Block.DIRT.id); + + int i2; + + for (i2 = j - 3 + l; i2 <= j + l; ++i2) { + j1 = i2 - (j + l); + k1 = 1 - j1 / 2; + + for (l1 = i - k1; l1 <= i + k1; ++l1) { + int j2 = l1 - i; + + for (int k2 = k - k1; k2 <= k + k1; ++k2) { + int l2 = k2 - k; + + if ((Math.abs(j2) != k1 || Math.abs(l2) != k1 || random.nextInt(2) != 0 && j1 != 0) && !Block.o[world.getTypeId(l1, i2, k2)] && !Block.leafDecayBlacklist.contains(world.getTypeId(l1, i2, k2))) { + world.setRawTypeId(l1, i2, k2, Block.LEAVES.id); + } + } + } + } + + for (i2 = 0; i2 < l; ++i2) { + j1 = world.getTypeId(i, j + i2, k); + if (j1 == 0 || j1 == Block.LEAVES.id) { + world.setRawTypeId(i, j + i2, k, Block.LOG.id); + } + } + + return true; + } else { + return false; + } + } + } else { + return false; + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldGenerator.java b/src/main/java/net/minecraft/server/WorldGenerator.java new file mode 100644 index 0000000..7d65908 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldGenerator.java @@ -0,0 +1,12 @@ +package net.minecraft.server; + +import java.util.Random; + +public abstract class WorldGenerator { + + public WorldGenerator() {} + + public abstract boolean a(World world, Random random, int i, int j, int k); + + public void a(double d0, double d1, double d2) {} +} diff --git a/src/main/java/net/minecraft/server/WorldLoader.java b/src/main/java/net/minecraft/server/WorldLoader.java new file mode 100644 index 0000000..e006789 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldLoader.java @@ -0,0 +1,75 @@ +package net.minecraft.server; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +public class WorldLoader implements Convertable { + + protected final File a; + + public WorldLoader(File file1) { + if (!file1.exists()) { + file1.mkdirs(); + } + + this.a = file1; + } + + public WorldData b(String s) { + File file1 = new File(this.a, s); + + if (!file1.exists()) { + return null; + } else { + File file2 = new File(file1, "level.dat"); + NBTTagCompound nbttagcompound; + NBTTagCompound nbttagcompound1; + + if (file2.exists()) { + try { + nbttagcompound = CompressedStreamTools.a((InputStream) (new FileInputStream(file2))); + nbttagcompound1 = nbttagcompound.k("Data"); + return new WorldData(nbttagcompound1); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + file2 = new File(file1, "level.dat_old"); + if (file2.exists()) { + try { + nbttagcompound = CompressedStreamTools.a((InputStream) (new FileInputStream(file2))); + nbttagcompound1 = nbttagcompound.k("Data"); + return new WorldData(nbttagcompound1); + } catch (Exception exception1) { + exception1.printStackTrace(); + } + } + + return null; + } + } + + protected static void a(File[] afile) { + for (int i = 0; i < afile.length; ++i) { + if (afile[i].isDirectory()) { + a(afile[i].listFiles()); + } + + afile[i].delete(); + } + } + + public IDataManager a(String s, boolean flag) { + return new PlayerNBTManager(this.a, s, flag); + } + + public boolean isConvertable(String s) { + return false; + } + + public boolean convert(String s, IProgressUpdate iprogressupdate) { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/WorldLoaderServer.java b/src/main/java/net/minecraft/server/WorldLoaderServer.java new file mode 100644 index 0000000..0db19db --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldLoaderServer.java @@ -0,0 +1,143 @@ +package net.minecraft.server; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.zip.GZIPInputStream; + +public class WorldLoaderServer extends WorldLoader { + + public WorldLoaderServer(File file1) { + super(file1); + } + + public IDataManager a(String s, boolean flag) { + return new ServerNBTManager(this.a, s, flag); + } + + public boolean isConvertable(String s) { + WorldData worlddata = this.b(s); + + return worlddata != null && worlddata.i() == 0; + } + + public boolean convert(String s, IProgressUpdate iprogressupdate) { + iprogressupdate.a(0); + ArrayList arraylist = new ArrayList(); + ArrayList arraylist1 = new ArrayList(); + ArrayList arraylist2 = new ArrayList(); + ArrayList arraylist3 = new ArrayList(); + File file1 = new File(this.a, s); + File file2 = new File(file1, "DIM-1"); + + System.out.println("Scanning folders..."); + this.a(file1, arraylist, arraylist1); + if (file2.exists()) { + this.a(file2, arraylist2, arraylist3); + } + + int i = arraylist.size() + arraylist2.size() + arraylist1.size() + arraylist3.size(); + + System.out.println("Total conversion count is " + i); + this.a(file1, arraylist, 0, i, iprogressupdate); + this.a(file2, arraylist2, arraylist.size(), i, iprogressupdate); + WorldData worlddata = this.b(s); + + worlddata.a(19132); + IDataManager idatamanager = this.a(s, false); + + idatamanager.a(worlddata); + this.a(arraylist1, arraylist.size() + arraylist2.size(), i, iprogressupdate); + if (file2.exists()) { + this.a(arraylist3, arraylist.size() + arraylist2.size() + arraylist1.size(), i, iprogressupdate); + } + + return true; + } + + private void a(File file1, ArrayList arraylist, ArrayList arraylist1) { + ChunkFileFilter chunkfilefilter = new ChunkFileFilter((EmptyClass2) null); + ChunkFilenameFilter chunkfilenamefilter = new ChunkFilenameFilter((EmptyClass2) null); + File[] afile = file1.listFiles(chunkfilefilter); + File[] afile1 = afile; + int i = afile.length; + + for (int j = 0; j < i; ++j) { + File file2 = afile1[j]; + + arraylist1.add(file2); + File[] afile2 = file2.listFiles(chunkfilefilter); + File[] afile3 = afile2; + int k = afile2.length; + + for (int l = 0; l < k; ++l) { + File file3 = afile3[l]; + File[] afile4 = file3.listFiles(chunkfilenamefilter); + File[] afile5 = afile4; + int i1 = afile4.length; + + for (int j1 = 0; j1 < i1; ++j1) { + File file4 = afile5[j1]; + + arraylist.add(new ChunkFile(file4)); + } + } + } + } + + private void a(File file1, ArrayList arraylist, int i, int j, IProgressUpdate iprogressupdate) { + Collections.sort(arraylist); + byte[] abyte = new byte[4096]; + Iterator iterator = arraylist.iterator(); + + while (iterator.hasNext()) { + ChunkFile chunkfile = (ChunkFile) iterator.next(); + int k = chunkfile.b(); + int l = chunkfile.c(); + RegionFile regionfile = RegionFileCache.a(file1, k, l); + + if (!regionfile.c(k & 31, l & 31)) { + try { + DataInputStream datainputstream = new DataInputStream(new GZIPInputStream(new FileInputStream(chunkfile.a()))); + DataOutputStream dataoutputstream = regionfile.b(k & 31, l & 31); + boolean flag = false; + + int i1; + + while ((i1 = datainputstream.read(abyte)) != -1) { + dataoutputstream.write(abyte, 0, i1); + } + + dataoutputstream.close(); + datainputstream.close(); + } catch (IOException ioexception) { + ioexception.printStackTrace(); + } + } + + ++i; + int j1 = (int) Math.round(100.0D * (double) i / (double) j); + + iprogressupdate.a(j1); + } + + RegionFileCache.a(); + } + + private void a(ArrayList arraylist, int i, int j, IProgressUpdate iprogressupdate) { + Iterator iterator = arraylist.iterator(); + + while (iterator.hasNext()) { + File file1 = (File) iterator.next(); + File[] afile = file1.listFiles(); + + a(afile); + file1.delete(); + ++i; + int k = (int) Math.round(100.0D * (double) i / (double) j); + + iprogressupdate.a(k); + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldManager.java b/src/main/java/net/minecraft/server/WorldManager.java new file mode 100644 index 0000000..8c6c992 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldManager.java @@ -0,0 +1,42 @@ +package net.minecraft.server; + +public class WorldManager implements IWorldAccess { + + private MinecraftServer server; + public WorldServer world; // CraftBukkit - private -> public + + public WorldManager(MinecraftServer minecraftserver, WorldServer worldserver) { + this.server = minecraftserver; + this.world = worldserver; + } + + public void a(String s, double d0, double d1, double d2, double d3, double d4, double d5) {} + + public void a(Entity entity) { + this.server.getTracker(this.world.dimension).track(entity); // CraftBukkit + } + + public void b(Entity entity) { + this.server.getTracker(this.world.dimension).untrackEntity(entity); // CraftBukkit + } + + public void a(String s, double d0, double d1, double d2, float f, float f1) {} + + public void a(int i, int j, int k, int l, int i1, int j1) {} + + public void a() {} + + public void a(int i, int j, int k) { + this.server.serverConfigurationManager.flagDirty(i, j, k, this.world.dimension); // CraftBukkit + } + + public void a(String s, int i, int j, int k) {} + + public void a(int i, int j, int k, TileEntity tileentity) { + this.server.serverConfigurationManager.a(i, j, k, tileentity); + } + + public void a(EntityHuman entityhuman, int i, int j, int k, int l, int i1) { + this.server.serverConfigurationManager.sendPacketNearby(entityhuman, (double) j, (double) k, (double) l, 64.0D, this.world.dimension, new Packet61(i, j, k, l, i1)); // CraftBukkit + } +} diff --git a/src/main/java/net/minecraft/server/WorldMap.java b/src/main/java/net/minecraft/server/WorldMap.java new file mode 100644 index 0000000..5237cac --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldMap.java @@ -0,0 +1,202 @@ +package net.minecraft.server; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.map.CraftMapView; + +import java.util.*; + +// CraftBukkit start +// CraftBukkit end + +public class WorldMap extends WorldMapBase { + + public int b; + public int c; + public byte map; + public byte e; + public byte[] f = new byte[16384]; + public int g; + public List h = new ArrayList(); + private Map j = new HashMap(); + public List i = new ArrayList(); + + // CraftBukkit start + public final CraftMapView mapView; + private CraftServer server; + private UUID uniqueId = null; + // CraftBukkit end + + public WorldMap(String s) { + super(s); + // CraftBukkit start + mapView = new CraftMapView(this); + server = (CraftServer) Bukkit.getServer(); + // CraftBukkit end + } + + public void a(NBTTagCompound nbttagcompound) { + // CraftBukkit start + byte dimension = nbttagcompound.c("dimension"); + + if (dimension >= 10) { + long least = nbttagcompound.getLong("UUIDLeast"); + long most = nbttagcompound.getLong("UUIDMost"); + + if (least != 0L && most != 0L) { + this.uniqueId = new UUID(most, least); + + CraftWorld world = (CraftWorld) server.getWorld(this.uniqueId); + // Check if the stored world details are correct. + if (world == null) { + /* All Maps which do not have their valid world loaded are set to a dimension which hopefully won't be reached. + This is to prevent them being corrupted with the wrong map data. */ + dimension = 127; + } else { + dimension = (byte) world.getHandle().dimension; + } + } + } + + this.map = dimension; + // CraftBukkit end + this.b = nbttagcompound.e("xCenter"); + this.c = nbttagcompound.e("zCenter"); + this.e = nbttagcompound.c("scale"); + if (this.e < 0) { + this.e = 0; + } + + if (this.e > 4) { + this.e = 4; + } + + short short1 = nbttagcompound.d("width"); + short short2 = nbttagcompound.d("height"); + + if (short1 == 128 && short2 == 128) { + this.f = nbttagcompound.j("colors"); + } else { + byte[] abyte = nbttagcompound.j("colors"); + + this.f = new byte[16384]; + int i = (128 - short1) / 2; + int j = (128 - short2) / 2; + + for (int k = 0; k < short2; ++k) { + int l = k + j; + + if (l >= 0 || l < 128) { + for (int i1 = 0; i1 < short1; ++i1) { + int j1 = i1 + i; + + if (j1 >= 0 || j1 < 128) { + this.f[j1 + l * 128] = abyte[i1 + k * short1]; + } + } + } + } + } + } + + public void b(NBTTagCompound nbttagcompound) { + // CraftBukkit start + if (this.map >= 10) { + if (this.uniqueId == null) { + for (org.bukkit.World world : server.getWorlds()) { + CraftWorld cWorld = (CraftWorld) world; + if (cWorld.getHandle().dimension == this.map) { + this.uniqueId = cWorld.getUID(); + break; + } + } + } + /* Perform a second check to see if a matching world was found, this is a necessary + change incase Maps are forcefully unlinked from a World and lack a UID.*/ + if (this.uniqueId != null) { + nbttagcompound.setLong("UUIDLeast", this.uniqueId.getLeastSignificantBits()); + nbttagcompound.setLong("UUIDMost", this.uniqueId.getMostSignificantBits()); + } + } + // CraftBukkit end + nbttagcompound.a("dimension", this.map); + nbttagcompound.a("xCenter", this.b); + nbttagcompound.a("zCenter", this.c); + nbttagcompound.a("scale", this.e); + nbttagcompound.a("width", (short) 128); + nbttagcompound.a("height", (short) 128); + nbttagcompound.a("colors", this.f); + } + + public void a(EntityHuman entityhuman, ItemStack itemstack) { + if (!this.j.containsKey(entityhuman)) { + WorldMapHumanTracker worldmaphumantracker = new WorldMapHumanTracker(this, entityhuman); + + this.j.put(entityhuman, worldmaphumantracker); + this.h.add(worldmaphumantracker); + } + + this.i.clear(); + + for (int i = 0; i < this.h.size(); ++i) { + WorldMapHumanTracker worldmaphumantracker1 = (WorldMapHumanTracker) this.h.get(i); + + if (!worldmaphumantracker1.trackee.dead && worldmaphumantracker1.trackee.inventory.c(itemstack)) { + float f = (float) (worldmaphumantracker1.trackee.locX - (double) this.b) / (float) (1 << this.e); + float f1 = (float) (worldmaphumantracker1.trackee.locZ - (double) this.c) / (float) (1 << this.e); + byte b0 = 64; + byte b1 = 64; + + if (f >= (float) (-b0) && f1 >= (float) (-b1) && f <= (float) b0 && f1 <= (float) b1) { + byte b2 = 0; + byte b3 = (byte) ((int) ((double) (f * 2.0F) + 0.5D)); + byte b4 = (byte) ((int) ((double) (f1 * 2.0F) + 0.5D)); + // CraftBukkit + byte b5 = (byte) ((int) ((double) (worldmaphumantracker1.trackee.yaw * 16.0F / 360.0F) + 0.5D)); + + if (this.map < 0) { + int j = this.g / 10; + + b5 = (byte) (j * j * 34187121 + j * 121 >> 15 & 15); + } + + if (worldmaphumantracker1.trackee.dimension == this.map) { + this.i.add(new WorldMapOrienter(this, b2, b3, b4, b5)); + } + } + } else { + this.j.remove(worldmaphumantracker1.trackee); + this.h.remove(worldmaphumantracker1); + } + } + } + + public byte[] a(ItemStack itemstack, World world, EntityHuman entityhuman) { + WorldMapHumanTracker worldmaphumantracker = (WorldMapHumanTracker) this.j.get(entityhuman); + + if (worldmaphumantracker == null) { + return null; + } else { + byte[] abyte = worldmaphumantracker.a(itemstack); + + return abyte; + } + } + + public void a(int i, int j, int k) { + super.a(); + + for (int l = 0; l < this.h.size(); ++l) { + WorldMapHumanTracker worldmaphumantracker = (WorldMapHumanTracker) this.h.get(l); + + if (worldmaphumantracker.b[i] < 0 || worldmaphumantracker.b[i] > j) { + worldmaphumantracker.b[i] = j; + } + + if (worldmaphumantracker.c[i] < 0 || worldmaphumantracker.c[i] < k) { + worldmaphumantracker.c[i] = k; + } + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldMapBase.java b/src/main/java/net/minecraft/server/WorldMapBase.java new file mode 100644 index 0000000..d275be0 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldMapBase.java @@ -0,0 +1,27 @@ +package net.minecraft.server; + +public abstract class WorldMapBase { + + public final String a; + private boolean b; + + public WorldMapBase(String s) { + this.a = s; + } + + public abstract void a(NBTTagCompound nbttagcompound); + + public abstract void b(NBTTagCompound nbttagcompound); + + public void a() { + this.a(true); + } + + public void a(boolean flag) { + this.b = flag; + } + + public boolean b() { + return this.b; + } +} diff --git a/src/main/java/net/minecraft/server/WorldMapCollection.java b/src/main/java/net/minecraft/server/WorldMapCollection.java new file mode 100644 index 0000000..1155604 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldMapCollection.java @@ -0,0 +1,174 @@ +package net.minecraft.server; + +import java.io.*; +import java.util.*; + +public class WorldMapCollection { + + private IDataManager a; + private Map b = new HashMap(); + private List c = new ArrayList(); + private Map d = new HashMap(); + + public WorldMapCollection(IDataManager idatamanager) { + this.a = idatamanager; + this.b(); + } + + public WorldMapBase a(Class oclass, String s) { + WorldMapBase worldmapbase = (WorldMapBase) this.b.get(s); + + if (worldmapbase != null) { + return worldmapbase; + } else { + if (this.a != null) { + try { + File file1 = this.a.b(s); + + if (file1 != null && file1.exists()) { + try { + worldmapbase = (WorldMapBase) oclass.getConstructor(new Class[] { String.class}).newInstance(new Object[] { s}); + } catch (Exception exception) { + throw new RuntimeException("Failed to instantiate " + oclass.toString(), exception); + } + + FileInputStream fileinputstream = new FileInputStream(file1); + NBTTagCompound nbttagcompound = CompressedStreamTools.a((InputStream) fileinputstream); + + fileinputstream.close(); + worldmapbase.a(nbttagcompound.k("data")); + } + } catch (Exception exception1) { + exception1.printStackTrace(); + } + } + + if (worldmapbase != null) { + this.b.put(s, worldmapbase); + this.c.add(worldmapbase); + } + + return worldmapbase; + } + } + + public void a(String s, WorldMapBase worldmapbase) { + if (worldmapbase == null) { + throw new RuntimeException("Can\'t set null data"); + } else { + if (this.b.containsKey(s)) { + this.c.remove(this.b.remove(s)); + } + + this.b.put(s, worldmapbase); + this.c.add(worldmapbase); + } + } + + public void a() { + for (int i = 0; i < this.c.size(); ++i) { + WorldMapBase worldmapbase = (WorldMapBase) this.c.get(i); + + if (worldmapbase.b()) { + this.a(worldmapbase); + worldmapbase.a(false); + } + } + } + + private void a(WorldMapBase worldmapbase) { + if (this.a != null) { + try { + File file1 = this.a.b(worldmapbase.a); + + if (file1 != null) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + + worldmapbase.b(nbttagcompound); + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.a("data", nbttagcompound); + FileOutputStream fileoutputstream = new FileOutputStream(file1); + + CompressedStreamTools.a(nbttagcompound1, (OutputStream) fileoutputstream); + fileoutputstream.close(); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } + } + + private void b() { + try { + this.d.clear(); + if (this.a == null) { + return; + } + + File file1 = this.a.b("idcounts"); + + if (file1 != null && file1.exists()) { + DataInputStream datainputstream = new DataInputStream(new FileInputStream(file1)); + NBTTagCompound nbttagcompound = CompressedStreamTools.a((DataInput) datainputstream); + + datainputstream.close(); + Iterator iterator = nbttagcompound.c().iterator(); + + while (iterator.hasNext()) { + NBTBase nbtbase = (NBTBase) iterator.next(); + + if (nbtbase instanceof NBTTagShort) { + NBTTagShort nbttagshort = (NBTTagShort) nbtbase; + String s = nbttagshort.b(); + short short1 = nbttagshort.a; + + this.d.put(s, Short.valueOf(short1)); + } + } + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public int a(String s) { + Short oshort = (Short) this.d.get(s); + + if (oshort == null) { + oshort = Short.valueOf((short) 0); + } else { + oshort = Short.valueOf((short) (oshort.shortValue() + 1)); + } + + this.d.put(s, oshort); + if (this.a == null) { + return oshort.shortValue(); + } else { + try { + File file1 = this.a.b("idcounts"); + + if (file1 != null) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + Iterator iterator = this.d.keySet().iterator(); + + while (iterator.hasNext()) { + String s1 = (String) iterator.next(); + short short1 = ((Short) this.d.get(s1)).shortValue(); + + nbttagcompound.a(s1, short1); + } + + DataOutputStream dataoutputstream = new DataOutputStream(new FileOutputStream(file1)); + + CompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream); + dataoutputstream.close(); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + + return oshort.shortValue(); + } + } +} diff --git a/src/main/java/net/minecraft/server/WorldMapHumanTracker.java b/src/main/java/net/minecraft/server/WorldMapHumanTracker.java new file mode 100644 index 0000000..5582af5 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldMapHumanTracker.java @@ -0,0 +1,102 @@ +package net.minecraft.server; + +// CraftBukkit start + +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.map.RenderData; +import org.bukkit.map.MapCursor; +// CraftBukkit end + +public class WorldMapHumanTracker { + + public final EntityHuman trackee; + public int[] b; + public int[] c; + private int e; + private int f; + private byte[] g; + + final WorldMap d; + + public WorldMapHumanTracker(WorldMap worldmap, EntityHuman entityhuman) { + this.d = worldmap; + this.b = new int[128]; + this.c = new int[128]; + this.e = 0; + this.f = 0; + this.trackee = entityhuman; + + for (int i = 0; i < this.b.length; ++i) { + this.b[i] = 0; + this.c[i] = 127; + } + } + + public byte[] a(ItemStack itemstack) { + int i; + int j; + + RenderData render = this.d.mapView.render((CraftPlayer) trackee.getBukkitEntity()); // CraftBukkit + + if (--this.f < 0) { + this.f = 4; + byte[] abyte = new byte[render.cursors.size() * 3 + 1]; // CraftBukkit + + abyte[0] = 1; + + // CraftBukkit start + for (i = 0; i < render.cursors.size(); ++i) { + MapCursor cursor = render.cursors.get(i); + if (!cursor.isVisible()) continue; + + byte value = (byte) (((cursor.getRawType() == 0 || cursor.getDirection() < 8 ? cursor.getDirection() : cursor.getDirection() - 1) & 15) * 16); + abyte[i * 3 + 1] = (byte) (value | (cursor.getRawType() != 0 && value < 0 ? 16 - cursor.getRawType() : cursor.getRawType())); + abyte[i * 3 + 2] = (byte) cursor.getX(); + abyte[i * 3 + 3] = (byte) cursor.getY(); + } + // CraftBukkit end + + boolean flag = true; + + if (this.g != null && this.g.length == abyte.length) { + for (j = 0; j < abyte.length; ++j) { + if (abyte[j] != this.g[j]) { + flag = false; + break; + } + } + } else { + flag = false; + } + + if (!flag) { + this.g = abyte; + return abyte; + } + } + + for (int k = 0; k < 10; ++k) { + i = this.e * 11 % 128; + ++this.e; + if (this.b[i] >= 0) { + j = this.c[i] - this.b[i] + 1; + int l = this.b[i]; + byte[] abyte1 = new byte[j + 3]; + + abyte1[0] = 0; + abyte1[1] = (byte) i; + abyte1[2] = (byte) l; + + for (int i1 = 0; i1 < abyte1.length - 3; ++i1) { + abyte1[i1 + 3] = render.buffer[(i1 + l) * 128 + i]; // CraftBukkit + } + + this.c[i] = -1; + this.b[i] = -1; + return abyte1; + } + } + + return null; + } +} diff --git a/src/main/java/net/minecraft/server/WorldMapOrienter.java b/src/main/java/net/minecraft/server/WorldMapOrienter.java new file mode 100644 index 0000000..72ebd95 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldMapOrienter.java @@ -0,0 +1,19 @@ +package net.minecraft.server; + +public class WorldMapOrienter { + + public byte a; + public byte b; + public byte c; + public byte d; + + final WorldMap e; + + public WorldMapOrienter(WorldMap worldmap, byte b0, byte b1, byte b2, byte b3) { + this.e = worldmap; + this.a = b0; + this.b = b1; + this.c = b2; + this.d = b3; + } +} diff --git a/src/main/java/net/minecraft/server/WorldProvider.java b/src/main/java/net/minecraft/server/WorldProvider.java new file mode 100644 index 0000000..f6ea42f --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldProvider.java @@ -0,0 +1,72 @@ +package net.minecraft.server; + +public abstract class WorldProvider { + + public World a; + public WorldChunkManager b; + public boolean c = false; + public boolean d = false; + public boolean e = false; + public float[] f = new float[16]; + public int dimension = 0; + private float[] h = new float[4]; + + public WorldProvider() {} + + public final void a(World world) { + this.a = world; + this.a(); + this.c(); + } + + protected void c() { + float f = 0.05F; + + for (int i = 0; i <= 15; ++i) { + float f1 = 1.0F - (float) i / 15.0F; + + this.f[i] = (1.0F - f1) / (f1 * 3.0F + 1.0F) * (1.0F - f) + f; + } + } + + protected void a() { + this.b = new WorldChunkManager(this.a); + } + + public IChunkProvider getChunkProvider() { + return new ChunkProviderGenerate(this.a, this.a.getSeed()); + } + + public boolean canSpawn(int i, int j) { + int k = this.a.a(i, j); + + return k == Block.SAND.id; + } + + public float a(long i, float f) { + int j = (int) (i % 24000L); + float f1 = ((float) j + f) / 24000.0F - 0.25F; + + if (f1 < 0.0F) { + ++f1; + } + + if (f1 > 1.0F) { + --f1; + } + + float f2 = f1; + + f1 = 1.0F - (float) ((Math.cos((double) f1 * 3.141592653589793D) + 1.0D) / 2.0D); + f1 = f2 + (f1 - f2) / 3.0F; + return f1; + } + + public boolean d() { + return true; + } + + public static WorldProvider byDimension(int i) { + return (WorldProvider) (i == -1 ? new WorldProviderHell() : (i == 0 ? new WorldProviderNormal() : (i == 1 ? new WorldProviderSky() : null))); + } +} diff --git a/src/main/java/net/minecraft/server/WorldProviderHell.java b/src/main/java/net/minecraft/server/WorldProviderHell.java new file mode 100644 index 0000000..47570f6 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldProviderHell.java @@ -0,0 +1,42 @@ +package net.minecraft.server; + +public class WorldProviderHell extends WorldProvider { + + public WorldProviderHell() {} + + public void a() { + this.b = new WorldChunkManagerHell(BiomeBase.HELL, 1.0D, 0.0D); + this.c = true; + this.d = true; + this.e = true; + this.dimension = -1; + } + + protected void c() { + float f = 0.1F; + + for (int i = 0; i <= 15; ++i) { + float f1 = 1.0F - (float) i / 15.0F; + + this.f[i] = (1.0F - f1) / (f1 * 3.0F + 1.0F) * (1.0F - f) + f; + } + } + + public IChunkProvider getChunkProvider() { + return new ChunkProviderHell(this.a, this.a.getSeed()); + } + + public boolean canSpawn(int i, int j) { + int k = this.a.a(i, j); + + return k == Block.BEDROCK.id ? false : (k == 0 ? false : Block.o[k]); + } + + public float a(long i, float f) { + return 0.5F; + } + + public boolean d() { + return false; + } +} diff --git a/src/main/java/net/minecraft/server/WorldProviderNormal.java b/src/main/java/net/minecraft/server/WorldProviderNormal.java new file mode 100644 index 0000000..497e89d --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldProviderNormal.java @@ -0,0 +1,6 @@ +package net.minecraft.server; + +public class WorldProviderNormal extends WorldProvider { + + public WorldProviderNormal() {} +} diff --git a/src/main/java/net/minecraft/server/WorldProviderSky.java b/src/main/java/net/minecraft/server/WorldProviderSky.java new file mode 100644 index 0000000..b9de10c --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldProviderSky.java @@ -0,0 +1,25 @@ +package net.minecraft.server; + +public class WorldProviderSky extends WorldProvider { + + public WorldProviderSky() {} + + public void a() { + this.b = new WorldChunkManagerHell(BiomeBase.SKY, 0.5D, 0.0D); + this.dimension = 1; + } + + public IChunkProvider getChunkProvider() { + return new ChunkProviderSky(this.a, this.a.getSeed()); + } + + public float a(long i, float f) { + return 0.0F; + } + + public boolean canSpawn(int i, int j) { + int k = this.a.a(i, j); + + return k == 0 ? false : Block.byId[k].material.isSolid(); + } +} diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java new file mode 100644 index 0000000..e2ccf97 --- /dev/null +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -0,0 +1,201 @@ +package net.minecraft.server; + +import org.bukkit.BlockChangeDelegate; +import org.bukkit.craftbukkit.generator.*; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.weather.LightningStrikeEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.util.ArrayList; +import java.util.List; + +// CraftBukkit start + +public class WorldServer extends World implements BlockChangeDelegate { + // CraftBukkit end + + public ChunkProviderServer chunkProviderServer; + public boolean weirdIsOpCache = false; + public boolean canSave; + public final MinecraftServer server; // CraftBukkit - private -> public final + private EntityList G = new EntityList(); + + // CraftBukkit start - change signature + public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, String s, int i, long j, org.bukkit.World.Environment env, ChunkGenerator gen) { + super(idatamanager, s, j, WorldProvider.byDimension(env.getId()), gen, env); + this.server = minecraftserver; + + this.dimension = i; + this.pvpMode = minecraftserver.pvpMode; + this.manager = new PlayerManager(minecraftserver, this.dimension, minecraftserver.propertyManager.getInt("view-distance", 10)); + } + + public final int dimension; + public EntityTracker tracker; + public PlayerManager manager; + // CraftBukkit end + + public void entityJoinedWorld(Entity entity, boolean flag) { + /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed + if (!this.server.spawnAnimals && (entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal)) { + entity.die(); + } + // CraftBukkit end */ + + if (entity.passenger == null || !(entity.passenger instanceof EntityHuman)) { + super.entityJoinedWorld(entity, flag); + } + } + + public void vehicleEnteredWorld(Entity entity, boolean flag) { + super.entityJoinedWorld(entity, flag); + } + + protected IChunkProvider b() { + IChunkLoader ichunkloader = this.w.a(this.worldProvider); + + // CraftBukkit start + InternalChunkGenerator gen; + + if (this.generator != null) { + gen = new CustomChunkGenerator(this, this.getSeed(), this.generator); + } else if (this.worldProvider instanceof WorldProviderHell) { + gen = new NetherChunkGenerator(this, this.getSeed()); + } else if (this.worldProvider instanceof WorldProviderSky) { + gen = new SkyLandsChunkGenerator(this, this.getSeed()); + } else { + gen = new NormalChunkGenerator(this, this.getSeed()); + } + + this.chunkProviderServer = new ChunkProviderServer(this, ichunkloader, gen); + // CraftBukkit end + + return this.chunkProviderServer; + } + + public List getTileEntities(int i, int j, int k, int l, int i1, int j1) { + ArrayList arraylist = new ArrayList(); + + for (int k1 = 0; k1 < this.c.size(); ++k1) { + TileEntity tileentity = (TileEntity) this.c.get(k1); + + if (tileentity.x >= i && tileentity.y >= j && tileentity.z >= k && tileentity.x < l && tileentity.y < i1 && tileentity.z < j1) { + arraylist.add(tileentity); + } + } + + return arraylist; + } + + public boolean a(EntityHuman entityhuman, int i, int j, int k) { + int l = (int) MathHelper.abs((float) (i - this.worldData.c())); + int i1 = (int) MathHelper.abs((float) (k - this.worldData.e())); + + if (l > i1) { + i1 = l; + } + + // CraftBukkit - Configurable spawn protection + return i1 > this.getServer().getSpawnRadius() || this.server.serverConfigurationManager.isOp(entityhuman.name); + } + + protected void c(Entity entity) { + super.c(entity); + this.G.a(entity.id, entity); + } + + protected void d(Entity entity) { + super.d(entity); + this.G.d(entity.id); + } + + public Entity getEntity(int i) { + return (Entity) this.G.a(i); + } + + public boolean strikeLightning(Entity entity) { + // CraftBukkit start + LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) entity.getBukkitEntity()); + this.getServer().getPluginManager().callEvent(lightning); + + if (lightning.isCancelled()) { + return false; + } + + if (super.strikeLightning(entity)) { + this.server.serverConfigurationManager.sendPacketNearby(entity.locX, entity.locY, entity.locZ, 512.0D, this.dimension, new Packet71Weather(entity)); + // CraftBukkit end + return true; + } else { + return false; + } + } + + public void a(Entity entity, byte b0) { + Packet38EntityStatus packet38entitystatus = new Packet38EntityStatus(entity.id, b0); + + // CraftBukkit + this.server.getTracker(this.dimension).sendPacketToEntity(entity, packet38entitystatus); + } + + //Project Poseidon Start + public Explosion createExplosion(Entity entity, double d0, double d1, double d2, float f, boolean flag, EntityDamageEvent.DamageCause customDamageCause) { + Explosion explosion = super.createExplosion(entity, d0, d1, d2, f, flag, customDamageCause); + + if (explosion.wasCanceled) { + return explosion; + } + this.server.serverConfigurationManager.sendPacketNearby(d0, d1, d2, 64.0D, this.dimension, new Packet60Explosion(d0, d1, d2, f, explosion.blocks)); + + return explosion; + } + //Project Poseidon End + + public Explosion createExplosion(Entity entity, double d0, double d1, double d2, float f, boolean flag) { + // CraftBukkit start + Explosion explosion = super.createExplosion(entity, d0, d1, d2, f, flag); + + if (explosion.wasCanceled) { + return explosion; + } + + /* Remove + explosion.a = flag; + explosion.a(); + explosion.a(false); + */ + this.server.serverConfigurationManager.sendPacketNearby(d0, d1, d2, 64.0D, this.dimension, new Packet60Explosion(d0, d1, d2, f, explosion.blocks)); + // CraftBukkit end + return explosion; + } + + public void playNote(int i, int j, int k, int l, int i1) { + super.playNote(i, j, k, l, i1); + // CraftBukkit + this.server.serverConfigurationManager.sendPacketNearby((double) i, (double) j, (double) k, 64.0D, this.dimension, new Packet54PlayNoteBlock(i, j, k, l, i1)); + } + + public void saveLevel() { + this.w.e(); + } + + protected void i() { + boolean flag = this.v(); + + super.i(); + if (flag != this.v()) { + // CraftBukkit start - only sending weather packets to those affected + for (int i = 0; i < this.players.size(); ++i) { + if (((EntityPlayer) this.players.get(i)).world == this) { + ((EntityPlayer) this.players.get(i)).netServerHandler.sendPacket(new Packet70Bed(flag ? 2 : 1)); + } + } + // CraftBukkit end + } + } + + // Poseidon + public PlayerManager getPlayerManager() { + return this.manager; + } +} diff --git a/src/main/java/org/bukkit/Achievement.java b/src/main/java/org/bukkit/Achievement.java new file mode 100644 index 0000000..4fcffa6 --- /dev/null +++ b/src/main/java/org/bukkit/Achievement.java @@ -0,0 +1,66 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents an achievement, which may be given to players + */ +public enum Achievement { + OPEN_INVENTORY(0), + MINE_WOOD(1), + BUILD_WORKBENCH(2), + BUILD_PICKAXE(3), + BUILD_FURNACE(4), + ACQUIRE_IRON(5), + BUILD_HOE(6), + MAKE_BREAD(7), + BAKE_CAKE(8), + BUILD_BETTER_PICKAXE(9), + COOK_FISH(10), + ON_A_RAIL(11), + BUILD_SWORD(12), + KILL_ENEMY(13), + KILL_COW(14), + FLY_PIG(15); + + /** + * The offset used to distinguish Achievements and Statistics + */ + public final static int STATISTIC_OFFSET = 5242880; + private final static Map achievements = new HashMap(); + private final int id; + + private Achievement(int id) { + this.id = STATISTIC_OFFSET + id; + } + + /** + * Gets the ID for this achievement. + * + * Note that this is offset using {@link #STATISTIC_OFFSET} + * + * @return ID of this achievement + */ + public int getId() { + return id; + } + + /** + * Gets the achievement associated with the given ID. + * + * Note that the ID must already be offset using {@link #STATISTIC_OFFSET} + * + * @param id ID of the achievement to return + * @return Achievement with the given ID + */ + public static Achievement getAchievement(int id) { + return achievements.get(id); + } + + static { + for (Achievement ach : values()) { + achievements.put(ach.getId(), ach); + } + } +} diff --git a/src/main/java/org/bukkit/BlockChangeDelegate.java b/src/main/java/org/bukkit/BlockChangeDelegate.java new file mode 100644 index 0000000..1ec3177 --- /dev/null +++ b/src/main/java/org/bukkit/BlockChangeDelegate.java @@ -0,0 +1,43 @@ +package org.bukkit; + +/** + * A delegate for handling block changes. This serves as a direct interface + * between generation algorithms in the server implementation and utilizing + * code. + * + * @author sk89q + */ +public interface BlockChangeDelegate { + + /** + * Set a block type at the specified coordinates. + * + * @param x + * @param y + * @param z + * @param typeId + * @return true if the block was set successfully + */ + public boolean setRawTypeId(int x, int y, int z, int typeId); + + /** + * Set a block type and data at the specified coordinates. + * + * @param x + * @param y + * @param z + * @param typeId + * @param data + * @return true if the block was set successfully + */ + public boolean setRawTypeIdAndData(int x, int y, int z, int typeId, int data); + + /** + * Get the block type at the location. + * @param x + * @param y + * @param z + * @return + */ + public int getTypeId(int x, int y, int z); +} diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java new file mode 100644 index 0000000..4cadef3 --- /dev/null +++ b/src/main/java/org/bukkit/Bukkit.java @@ -0,0 +1,266 @@ +package org.bukkit; + +import com.avaje.ebean.config.ServerConfig; +import org.bukkit.World.Environment; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Player; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.Recipe; +import org.bukkit.map.MapView; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.ServicesManager; +import org.bukkit.scheduler.BukkitScheduler; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Logger; + +/** + * Represents the Bukkit core, for version and Server singleton handling + */ +public final class Bukkit { + private static Server server; + + /** + * Static class cannot be initialized. + */ + private Bukkit() {} + + /** + * Gets the current {@link Server} singleton + * + * @return Server instance being ran + */ + public static Server getServer() { + return server; + } + + /** + * Attempts to set the {@link Server} singleton. + * + * This cannot be done if the Server is already set. + * + * @param server Server instance + */ + public static void setServer(Server server) { + if (Bukkit.server != null) { + throw new UnsupportedOperationException("Cannot redefine singleton Server"); + } + + Bukkit.server = server; + server.getLogger().info("This server is running " + getName() + " version " + getVersion() + " - A fork of CB1060-1092"); + } + + public static String getName() { + return server.getName(); + } + + public static String getVersion() { + return server.getVersion(); + } + + public static Player[] getOnlinePlayers() { + return server.getOnlinePlayers(); + } + + public static int getMaxPlayers() { + return server.getMaxPlayers(); + } + + public static int getPort() { + return server.getPort(); + } + + public static int getViewDistance() { + return server.getViewDistance(); + } + + public static String getIp() { + return server.getIp(); + } + + public static String getServerName() { + return server.getServerName(); + } + + public static String getServerId() { + return server.getServerId(); + } + + public static boolean getAllowNether() { + return server.getAllowNether(); + } + + public static boolean hasWhitelist() { + return server.hasWhitelist(); + } + + public static int broadcastMessage(String message) { + return server.broadcastMessage(message); + } + + public static String getUpdateFolder() { + return server.getUpdateFolder(); + } + + public static Player getPlayer(String name) { + return server.getPlayer(name); + } + + public static Player getPlayer(UUID uuid) {return server.getPlayer(uuid);} + + public static List matchPlayer(String name) { + return server.matchPlayer(name); + } + + public static PluginManager getPluginManager() { + return server.getPluginManager(); + } + + public static BukkitScheduler getScheduler() { + return server.getScheduler(); + } + + public static ServicesManager getServicesManager() { + return server.getServicesManager(); + } + + public static List getWorlds() { + return server.getWorlds(); + } + + public static World createWorld(String name, Environment environment) { + return server.createWorld(name, environment); + } + + public static World createWorld(String name, Environment environment, long seed) { + return server.createWorld(name, environment, seed); + } + + public static World createWorld(String name, Environment environment, ChunkGenerator generator) { + return server.createWorld(name, environment, generator); + } + + public static World createWorld(String name, Environment environment, long seed, ChunkGenerator generator) { + return server.createWorld(name, environment, seed, generator); + } + + public static boolean unloadWorld(String name, boolean save) { + return server.unloadWorld(name, save); + } + + public static boolean unloadWorld(World world, boolean save) { + return server.unloadWorld(world, save); + } + + public static World getWorld(String name) { + return server.getWorld(name); + } + + public static World getWorld(UUID uid) { + return server.getWorld(uid); + } + + public static MapView getMap(short id) { + return server.getMap(id); + } + + public static MapView createMap(World world) { + return server.createMap(world); + } + + public static void reload() { + server.reload(); + } + + public static Logger getLogger() { + return server.getLogger(); + } + + public static PluginCommand getPluginCommand(String name) { + return server.getPluginCommand(name); + } + + public static void savePlayers() { + server.savePlayers(); + } + + public static boolean dispatchCommand(CommandSender sender, String commandLine) { + return server.dispatchCommand(sender, commandLine); + } + + public static void configureDbConfig(ServerConfig config) { + server.configureDbConfig(config); + } + + public static boolean addRecipe(Recipe recipe) { + return server.addRecipe(recipe); + } + + public static Map getCommandAliases() { + return server.getCommandAliases(); + } + + public static int getSpawnRadius() { + return server.getSpawnRadius(); + } + + public static void setSpawnRadius(int value) { + server.setSpawnRadius(value); + } + + public static boolean getOnlineMode() { + return server.getOnlineMode(); + } + + public static boolean getAllowFlight() { + return server.getAllowFlight(); + } + + public static void shutdown() { + server.shutdown(); + } + + public static int broadcast(String message, String permission) { + return server.broadcast(message, permission); + } + + public static OfflinePlayer getOfflinePlayer(String name) { + return server.getOfflinePlayer(name); + } + + public static Player getPlayerExact(String name) { + return server.getPlayerExact(name); + } + + public static Set getIPBans() { + return server.getIPBans(); + } + + public static void banIP(String address) { + server.banIP(address); + } + + public static void unbanIP(String address) { + server.unbanIP(address); + } + + public static Set getBannedPlayers() { + return server.getBannedPlayers(); + } + + public static void setWhitelist(boolean value) { + server.setWhitelist(value); + } + + public static Set getWhitelistedPlayers() { + return server.getWhitelistedPlayers(); + } + + public static void reloadWhitelist() { + server.reloadWhitelist(); + } +} diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java new file mode 100644 index 0000000..768bb4b --- /dev/null +++ b/src/main/java/org/bukkit/ChatColor.java @@ -0,0 +1,144 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * All supported color values for chat + */ +public enum ChatColor { + + /** + * Represents black + */ + BLACK(0x0), + /** + * Represents dark blue + */ + DARK_BLUE(0x1), + /** + * Represents dark green + */ + DARK_GREEN(0x2), + /** + * Represents dark blue (aqua) + */ + DARK_AQUA(0x3), + /** + * Represents dark red + */ + DARK_RED(0x4), + /** + * Represents dark purple + */ + DARK_PURPLE(0x5), + /** + * Represents gold + */ + GOLD(0x6), + /** + * Represents gray + */ + GRAY(0x7), + /** + * Represents dark gray + */ + DARK_GRAY(0x8), + /** + * Represents blue + */ + BLUE(0x9), + /** + * Represents green + */ + GREEN(0xA), + /** + * Represents aqua + */ + AQUA(0xB), + /** + * Represents red + */ + RED(0xC), + /** + * Represents light purple + */ + LIGHT_PURPLE(0xD), + /** + * Represents yellow + */ + YELLOW(0xE), + /** + * Represents white + */ + WHITE(0xF); + + private final int code; + private final static Map colors = new HashMap(); + + private ChatColor(final int code) { + this.code = code; + } + + /** + * Gets the data value associated with this color + * + * @return An integer value of this color code + */ + public int getCode() { + return code; + } + + @Override + public String toString() { + return String.format("\u00A7%x", code); + } + + /** + * Gets the color represented by the specified color code + * + * @param code Code to check + * @return Associative {@link Color} with the given code, or null if it doesn't exist + */ + public static ChatColor getByCode(final int code) { + return colors.get(code); + } + + /** + * Strips the given message of all color codes + * + * @param input String to strip of color + * @return A copy of the input string, without any coloring + */ + public static String stripColor(final String input) { + if (input == null) { + return null; + } + + return input.replaceAll("(?i)\u00A7[0-F]", ""); + } + + static { + for (ChatColor color : ChatColor.values()) { + colors.put(color.getCode(), color); + } + } + + /** + * Translates alternate color codes in the given text to Minecraft color codes. + * + * @param altColorChar The character used to denote color codes '&'. + * @param textToTranslate The text containing the alternate color codes. + * @return The text with the alternate color codes replaced by Minecraft color codes. + */ + public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) { + char[] charArray = textToTranslate.toCharArray(); + for (int i = 0; i < charArray.length - 1; i++) { + if (charArray[i] == altColorChar && "0123456789AaBbCcDdEeFf".indexOf(charArray[i + 1]) > -1) { + charArray[i] = '\u00A7'; + charArray[i + 1] = Character.toLowerCase(charArray[i + 1]); + } + } + return new String(charArray); + } +} diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java new file mode 100644 index 0000000..f45a2c9 --- /dev/null +++ b/src/main/java/org/bukkit/Chunk.java @@ -0,0 +1,107 @@ +package org.bukkit; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Entity; + +/** + * Represents a chunk of blocks + */ +public interface Chunk { + + /** + * Gets the X-coordinate of this chunk + * + * @return X-coordinate + */ + int getX(); + + /** + * Gets the Z-coordinate of this chunk + * + * @return Z-coordinate + */ + int getZ(); + + /** + * Gets the world containing this chunk + * + * @return Parent World + */ + World getWorld(); + + /** + * Gets a block from this chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return the Block + */ + Block getBlock(int x, int y, int z); + + /** + * Capture thread-safe read-only snapshot of chunk data + * @return ChunkSnapshot + */ + ChunkSnapshot getChunkSnapshot(); + + /** + * Capture thread-safe read-only snapshot of chunk data + * @param includeMaxblocky - if true, snapshot includes per-coordinate maximum Y values + * @param includeBiome - if true, snapshot includes per-coordinate biome type + * @param includeBiomeTempRain - if true, snapshot includes per-coordinate raw biome temperature and rainfall + * @return ChunkSnapshot + */ + ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain); + + Entity[] getEntities(); + + BlockState[] getTileEntities(); + + /** + * Checks if the chunk is loaded. + * + * @return + */ + boolean isLoaded(); + + /** + * Loads the chunk. + * + * @param generate Whether or not to generate a chunk if it doesn't already exist + * @return true if the chunk has loaded successfully, otherwise false + */ + boolean load(boolean generate); + + /** + * Loads the chunk. + * + * @return true if the chunk has loaded successfully, otherwise false + */ + boolean load(); + + /** + * Unloads and optionally saves the Chunk + * + * @param save Controls whether the chunk is saved + * @param safe Controls whether to unload the chunk when players are nearby + * @return true if the chunk has unloaded successfully, otherwise false + */ + boolean unload(boolean save, boolean safe); + + /** + * Unloads and optionally saves the Chunk + * + * @param save Controls whether the chunk is saved + * @return true if the chunk has unloaded successfully, otherwise false + */ + boolean unload(boolean save); + + /** + * Unloads and optionally saves the Chunk + * + * @return true if the chunk has unloaded successfully, otherwise false + */ + boolean unload(); +} diff --git a/src/main/java/org/bukkit/ChunkSnapshot.java b/src/main/java/org/bukkit/ChunkSnapshot.java new file mode 100644 index 0000000..e54b5e6 --- /dev/null +++ b/src/main/java/org/bukkit/ChunkSnapshot.java @@ -0,0 +1,112 @@ +package org.bukkit; + +import org.bukkit.block.Biome; +/** + * Represents a static, thread-safe snapshot of chunk of blocks + * Purpose is to allow clean, efficient copy of a chunk data to be made, and then handed off for processing in another thread (e.g. map rendering) + */ +public interface ChunkSnapshot { + + /** + * Gets the X-coordinate of this chunk + * + * @return X-coordinate + */ + int getX(); + + /** + * Gets the Z-coordinate of this chunk + * + * @return Z-coordinate + */ + int getZ(); + + /** + * Gets name of the world containing this chunk + * + * @return Parent World Name + */ + String getWorldName(); + + /** + * Get block type for block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-255 + */ + int getBlockTypeId(int x, int y, int z); + + /** + * Get block data for block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-15 + */ + int getBlockData(int x, int y, int z); + + /** + * Get sky light level for block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-15 + */ + int getBlockSkyLight(int x, int y, int z); + + /** + * Get light level emitted by block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-15 + */ + int getBlockEmittedLight(int x, int y, int z); + + /** + * Gets the highest non-air coordinate at the given coordinates + * + * @param x X-coordinate of the blocks + * @param z Z-coordinate of the blocks + * @return Y-coordinate of the highest non-air block + */ + int getHighestBlockYAt(int x, int z); + + /** + * Get biome at given coordinates + * + * @param x X-coordinate + * @param z Z-coordinate + * @return Biome at given coordinate + */ + Biome getBiome(int x, int z); + + /** + * Get raw biome temperature (0.0-1.0) at given coordinate + * + * @param x X-coordinate + * @param z Z-coordinate + * @return temperature at given coordinate + */ + double getRawBiomeTemperature(int x, int z); + + /** + * Get raw biome rainfall (0.0-1.0) at given coordinate + * + * @param x X-coordinate + * @param z Z-coordinate + * @return rainfall at given coordinate + */ + double getRawBiomeRainfall(int x, int z); + + /** + * Get world full time when chunk snapshot was captured + * @return time in ticks + */ + long getCaptureFullTime(); +} diff --git a/src/main/java/org/bukkit/CoalType.java b/src/main/java/org/bukkit/CoalType.java new file mode 100644 index 0000000..32a84e9 --- /dev/null +++ b/src/main/java/org/bukkit/CoalType.java @@ -0,0 +1,47 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the two types of coal + * @author sunkid + */ +public enum CoalType { + COAL((byte) 0x0), + CHARCOAL((byte) 0x1); + + private final byte data; + private final static Map types = new HashMap(); + + private CoalType(byte data) { + this.data = data; + } + + /** + * Gets the associated data value representing this type of coal + * + * @return A byte containing the data value of this coal type + */ + public byte getData() { + return data; + } + + /** + * Gets the type of coal with the given data value + * + * @param data + * Data value to fetch + * @return The {@link CoalType} representing the given value, or null if + * it doesn't exist + */ + public static CoalType getByData(final byte data) { + return types.get(data); + } + + static { + for (CoalType type : CoalType.values()) { + types.put(type.getData(), type); + } + } +} diff --git a/src/main/java/org/bukkit/CropState.java b/src/main/java/org/bukkit/CropState.java new file mode 100644 index 0000000..5c17364 --- /dev/null +++ b/src/main/java/org/bukkit/CropState.java @@ -0,0 +1,78 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the different growth states of crops + * @author sunkid + */ +public enum CropState { + + /** + * State when first seeded + */ + SEEDED((byte) 0x0), + /** + * First growth stage + */ + GERMINATED((byte) 0x1), + /** + * Second growth stage + */ + VERY_SMALL((byte) 0x2), + /** + * Third growth stage + */ + SMALL((byte) 0x3), + /** + * Fourth growth stage + */ + MEDIUM((byte) 0x4), + /** + * Fifth growth stage + */ + TALL((byte) 0x5), + /** + * Almost ripe stage + */ + VERY_TALL((byte) 0x6), + /** + * Ripe stage + */ + RIPE((byte) 0x7); + + private final byte data; + private final static Map states = new HashMap(); + + private CropState(final byte data) { + this.data = data; + } + + /** + * Gets the associated data value representing this growth state + * + * @return A byte containing the data value of this growth state + */ + public byte getData() { + return data; + } + + /** + * Gets the CropState with the given data value + * + * @param data + * Data value to fetch + * @return The {@link CropState} representing the given value, or null if + * it doesn't exist + */ + public static CropState getByData(final byte data) { + return states.get(data); + } + + static { + for (CropState s : CropState.values()) { + states.put(s.getData(), s); + } + } +} diff --git a/src/main/java/org/bukkit/DyeColor.java b/src/main/java/org/bukkit/DyeColor.java new file mode 100644 index 0000000..b216dd8 --- /dev/null +++ b/src/main/java/org/bukkit/DyeColor.java @@ -0,0 +1,107 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * All supported color values for dyes and cloth + */ +public enum DyeColor { + + /** + * Represents white dye + */ + WHITE((byte) 0x0), + /** + * Represents orange dye + */ + ORANGE((byte) 0x1), + /** + * Represents magenta dye + */ + MAGENTA((byte) 0x2), + /** + * Represents light blue dye + */ + LIGHT_BLUE((byte) 0x3), + /** + * Represents yellow dye + */ + YELLOW((byte) 0x4), + /** + * Represents lime dye + */ + LIME((byte) 0x5), + /** + * Represents pink dye + */ + PINK((byte) 0x6), + /** + * Represents gray dye + */ + GRAY((byte) 0x7), + /** + * Represents silver dye + */ + SILVER((byte) 0x8), + /** + * Represents cyan dye + */ + CYAN((byte) 0x9), + /** + * Represents purple dye + */ + PURPLE((byte) 0xA), + /** + * Represents blue dye + */ + BLUE((byte) 0xB), + /** + * Represents brown dye + */ + BROWN((byte) 0xC), + /** + * Represents green dye + */ + GREEN((byte) 0xD), + /** + * Represents red dye + */ + RED((byte) 0xE), + /** + * Represents black dye + */ + BLACK((byte) 0xF); + + private final byte data; + private final static Map colors = new HashMap(); + + private DyeColor(final byte data) { + this.data = data; + } + + /** + * Gets the associated data value representing this color + * + * @return A byte containing the data value of this color + */ + public byte getData() { + return data; + } + + /** + * Gets the DyeColor with the given data value + * + * @param data Data value to fetch + * @return The {@link DyeColor} representing the given value, or null if it doesn't exist + */ + public static DyeColor getByData(final byte data) { + return colors.get(data); + } + + static { + for (DyeColor color : DyeColor.values()) { + colors.put(color.getData(), color); + } + } +} diff --git a/src/main/java/org/bukkit/Effect.java b/src/main/java/org/bukkit/Effect.java new file mode 100644 index 0000000..05921e1 --- /dev/null +++ b/src/main/java/org/bukkit/Effect.java @@ -0,0 +1,25 @@ +package org.bukkit; + +/** + * A list of effects that the server is able to send to players. + */ +public enum Effect { + BOW_FIRE(1002), + CLICK1(1001), + CLICK2(1000), + DOOR_TOGGLE(1003), + EXTINGUISH(1004), + RECORD_PLAY(1005), + SMOKE(2000), + STEP_SOUND(2001); + + private final int id; + + Effect(int id) { + this.id = id; + } + + public int getId() { + return this.id; + } +} diff --git a/src/main/java/org/bukkit/GrassSpecies.java b/src/main/java/org/bukkit/GrassSpecies.java new file mode 100644 index 0000000..d738751 --- /dev/null +++ b/src/main/java/org/bukkit/GrassSpecies.java @@ -0,0 +1,57 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the different types of grass. + */ +public enum GrassSpecies { + + /** + * Represents the dead looking grass. + */ + DEAD((byte) 0x0), + /** + * Represents the normal grass species. + */ + NORMAL((byte) 0x1), + /** + * Represents the fern-looking grass species. + */ + FERN_LIKE((byte) 0x2); + + private final byte data; + private final static Map species = new HashMap(); + + private GrassSpecies(final byte data) { + this.data = data; + } + + /** + * Gets the associated data value representing this species + * + * @return A byte containing the data value of this grass species + */ + public byte getData() { + return data; + } + + /** + * Gets the GrassSpecies with the given data value + * + * @param data + * Data value to fetch + * @return The {@link GrassSpecies} representing the given value, or null if + * it doesn't exist + */ + public static GrassSpecies getByData(final byte data) { + return species.get(data); + } + + static { + for (GrassSpecies s : GrassSpecies.values()) { + species.put(s.getData(), s); + } + } +} diff --git a/src/main/java/org/bukkit/Instrument.java b/src/main/java/org/bukkit/Instrument.java new file mode 100644 index 0000000..e54d0a2 --- /dev/null +++ b/src/main/java/org/bukkit/Instrument.java @@ -0,0 +1,34 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +public enum Instrument { + + PIANO((byte) 0x0), // All other + BASS_DRUM((byte) 0x1), // Stone + SNARE_DRUM((byte) 0x2), // Sand + STICKS((byte) 0x3), // Glass + BASS_GUITAR((byte) 0x4); // Wood + + private final byte type; + private final static Map types = new HashMap(); + + private Instrument(byte type) { + this.type = type; + } + + public byte getType() { + return this.type; + } + + public static Instrument getByType(final byte type) { + return types.get(type); + } + + static { + for (Instrument instrument : Instrument.values()) { + types.put(instrument.getType(), instrument); + } + } +} diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java new file mode 100644 index 0000000..9b9f475 --- /dev/null +++ b/src/main/java/org/bukkit/Location.java @@ -0,0 +1,462 @@ +package org.bukkit; + +import org.bukkit.block.Block; +import org.bukkit.util.Vector; + +/** + * Represents a 3-dimensional position in a world + */ +public class Location implements Cloneable { + private World world; + private double x; + private double y; + private double z; + private float pitch; + private float yaw; + + /** + * Constructs a new Location with the given coordinates + * + * @param world The world in which this location resides + * @param x The x-coordinate of this new location + * @param y The y-coordinate of this new location + * @param z The z-coordinate of this new location + */ + public Location(final World world, final double x, final double y, final double z) { + this(world, x, y, z, 0, 0); + } + + /** + * Constructs a new Location with the given coordinates and direction + * + * @param world The world in which this location resides + * @param x The x-coordinate of this new location + * @param y The y-coordinate of this new location + * @param z The z-coordinate of this new location + * @param yaw The absolute rotation on the x-plane, in degrees + * @param pitch The absolute rotation on the y-plane, in degrees + */ + public Location(final World world, final double x, final double y, final double z, final float yaw, final float pitch) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.pitch = pitch; + this.yaw = yaw; + } + + /** + * Sets the world that this location resides in + * + * @param world New world that this location resides in + */ + public void setWorld(World world) { + this.world = world; + } + + /** + * Gets the world that this location resides in + * + * @return World that contains this location + */ + public World getWorld() { + return world; + } + + /** + * Gets the block at the represented location + * + * @return Block at the represented location + */ + public Block getBlock() { + return world.getBlockAt(this); + } + + /** + * Sets the x-coordinate of this location + * + * @param x X-coordinate + */ + public void setX(double x) { + this.x = x; + } + + /** + * Gets the x-coordinate of this location + * + * @return x-coordinate + */ + public double getX() { + return x; + } + + /** + * Gets the floored value of the X component, indicating the block that + * this location is contained with. + * + * @return block X + */ + public int getBlockX() { + return locToBlock(x); + } + + /** + * Sets the y-coordinate of this location + * + * @param y y-coordinate + */ + public void setY(double y) { + this.y = y; + } + + /** + * Gets the y-coordinate of this location + * + * @return y-coordinate + */ + public double getY() { + return y; + } + + /** + * Gets the floored value of the Y component, indicating the block that + * this location is contained with. + * + * @return block y + */ + public int getBlockY() { + return locToBlock(y); + } + + /** + * Sets the z-coordinate of this location + * + * @param z z-coordinate + */ + public void setZ(double z) { + this.z = z; + } + + /** + * Gets the z-coordinate of this location + * + * @return z-coordinate + */ + public double getZ() { + return z; + } + + /** + * Gets the floored value of the Z component, indicating the block that + * this location is contained with. + * + * @return block z + */ + public int getBlockZ() { + return locToBlock(z); + } + + /** + * Sets the yaw of this location + * + * @param yaw New yaw + */ + public void setYaw(float yaw) { + this.yaw = yaw; + } + + /** + * Gets the yaw of this location + * + * @return Yaw + */ + public float getYaw() { + return yaw; + } + + /** + * Sets the pitch of this location + * + * @param pitch New pitch + */ + public void setPitch(float pitch) { + this.pitch = pitch; + } + + /** + * Gets the pitch of this location + * + * @return Pitch + */ + public float getPitch() { + return pitch; + } + + /** + * Gets a Vector pointing in the direction that this Location is facing + * + * @return Vector + */ + public Vector getDirection() { + Vector vector = new Vector(); + + double rotX = this.getYaw(); + double rotY = this.getPitch(); + + vector.setY(-Math.sin(Math.toRadians(rotY))); + + double h = Math.cos(Math.toRadians(rotY)); + + vector.setX(-h * Math.sin(Math.toRadians(rotX))); + vector.setZ(h * Math.cos(Math.toRadians(rotX))); + + return vector; + } + + /** + * Adds the location by another. + * + * @see Vector + * @param vec + * @return the same location + * @throws IllegalArgumentException for differing worlds + */ + public Location add(Location vec) { + if (vec == null || vec.getWorld() != getWorld()) { + throw new IllegalArgumentException("Cannot add Locations of differing worlds"); + } + + x += vec.x; + y += vec.y; + z += vec.z; + return this; + } + + /** + * Adds the location by another. Not world-aware. + * + * @see Vector + * @param x + * @param y + * @param z + * @return the same location + */ + public Location add(double x, double y, double z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + /** + * Subtracts the location by another. + * + * @see Vector + * @param vec + * @return the same location + * @throws IllegalArgumentException for differing worlds + */ + public Location subtract(Location vec) { + if (vec == null || vec.getWorld() != getWorld()) { + throw new IllegalArgumentException("Cannot add Locations of differing worlds"); + } + + x -= vec.x; + y -= vec.y; + z -= vec.z; + return this; + } + + /** + * Subtracts the location by another. Not world-aware and + * orientation independent. + * + * @see Vector + * @param x + * @param y + * @param z + * @return the same location + */ + public Location subtract(double x, double y, double z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + + /** + * Gets the magnitude of the location, defined as sqrt(x^2+y^2+z^2). The value + * of this method is not cached and uses a costly square-root function, so + * do not repeatedly call this method to get the location's magnitude. NaN + * will be returned if the inner result of the sqrt() function overflows, + * which will be caused if the length is too long. Not world-aware and + * orientation independent. + * + * @see Vector + * @return the magnitude + */ + public double length() { + return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)); + } + + /** + * Gets the magnitude of the location squared. Not world-aware and + * orientation independent. + * + * @see Vector + * @return the magnitude + */ + public double lengthSquared() { + return Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2); + } + + /** + * Get the distance between this location and another. The value + * of this method is not cached and uses a costly square-root function, so + * do not repeatedly call this method to get the location's magnitude. NaN + * will be returned if the inner result of the sqrt() function overflows, + * which will be caused if the distance is too long. + * + * @see Vector + * @param o + * @return the distance + * @throws IllegalArgumentException for differing worlds + */ + public double distance(Location o) { + if (o == null || o.getWorld() != getWorld()) { + throw new IllegalArgumentException("Cannot measure distance between worlds or to null"); + } + + return Math.sqrt(Math.pow(x - o.x, 2) + Math.pow(y - o.y, 2) + Math.pow(z - o.z, 2)); + } + + /** + * Get the squared distance between this location and another. + * + * @see Vector + * @param o + * @return the distance + * @throws IllegalArgumentException for differing worlds + */ + public double distanceSquared(Location o) { + if (o == null || o.getWorld() != getWorld()) { + throw new IllegalArgumentException("Cannot measure distance between worlds or to null"); + } + + return Math.pow(x - o.x, 2) + Math.pow(y - o.y, 2) + Math.pow(z - o.z, 2); + } + + /** + * Performs scalar multiplication, multiplying all components with a scalar. + * Not world-aware. + * + * @param m + * @see Vector + * @return the same location + */ + public Location multiply(double m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Zero this location's components. Not world-aware. + * + * @see Vector + * @return the same location + */ + public Location zero() { + x = 0; + y = 0; + z = 0; + return this; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Location other = (Location) obj; + + if (this.world != other.world && (this.world == null || !this.world.equals(other.world))) { + return false; + } + if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) { + return false; + } + if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) { + return false; + } + if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z)) { + return false; + } + if (Float.floatToIntBits(this.pitch) != Float.floatToIntBits(other.pitch)) { + return false; + } + if (Float.floatToIntBits(this.yaw) != Float.floatToIntBits(other.yaw)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 3; + + hash = 19 * hash + (this.world != null ? this.world.hashCode() : 0); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32)); + hash = 19 * hash + Float.floatToIntBits(this.pitch); + hash = 19 * hash + Float.floatToIntBits(this.yaw); + return hash; + } + + @Override + public String toString() { + return "Location{" + "world=" + world + "x=" + x + "y=" + y + "z=" + z + "pitch=" + pitch + "yaw=" + yaw + '}'; + } + + /** + * Constructs a new {@link Vector} based on this Location + * + * @return New Vector containing the coordinates represented by this Location + */ + public Vector toVector() { + return new Vector(x, y, z); + } + + @Override + public Location clone() { + try { + Location l = (Location) super.clone(); + + l.world = world; + l.x = x; + l.y = y; + l.z = z; + l.yaw = yaw; + l.pitch = pitch; + return l; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Safely converts a double (location coordinate) to an int (block coordinate) + * + * @param loc Precise coordinate + * @return Block coordinate + */ + public static int locToBlock(double loc) { + return (int) Math.floor(loc); + } +} diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java new file mode 100644 index 0000000..c849816 --- /dev/null +++ b/src/main/java/org/bukkit/Material.java @@ -0,0 +1,386 @@ +package org.bukkit; + +import org.bukkit.material.*; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An enum of all material ids accepted by the official server + client + */ +public enum Material { + AIR(0), + STONE(1), + GRASS(2), + DIRT(3), + COBBLESTONE(4), + WOOD(5), + SAPLING(6, Tree.class), + BEDROCK(7), + WATER(8, MaterialData.class), + STATIONARY_WATER(9, MaterialData.class), + LAVA(10, MaterialData.class), + STATIONARY_LAVA(11, MaterialData.class), + SAND(12), + GRAVEL(13), + GOLD_ORE(14), + IRON_ORE(15), + COAL_ORE(16), + LOG(17, Tree.class), + LEAVES(18, Tree.class), + SPONGE(19), + GLASS(20), + LAPIS_ORE(21), + LAPIS_BLOCK(22), + DISPENSER(23, Dispenser.class), + SANDSTONE(24), + NOTE_BLOCK(25), + BED_BLOCK(26, Bed.class), + POWERED_RAIL(27, PoweredRail.class), + DETECTOR_RAIL(28, DetectorRail.class), + PISTON_STICKY_BASE(29, PistonBaseMaterial.class), + WEB(30), + LONG_GRASS(31, LongGrass.class), + DEAD_BUSH(32), + PISTON_BASE(33, PistonBaseMaterial.class), + PISTON_EXTENSION(34, PistonExtensionMaterial.class), + WOOL(35, Wool.class), + PISTON_MOVING_PIECE(36), + YELLOW_FLOWER(37), + RED_ROSE(38), + BROWN_MUSHROOM(39), + RED_MUSHROOM(40), + GOLD_BLOCK(41), + IRON_BLOCK(42), + DOUBLE_STEP(43, Step.class), + STEP(44, Step.class), + BRICK(45), + TNT(46), + BOOKSHELF(47), + MOSSY_COBBLESTONE(48), + OBSIDIAN(49), + TORCH(50, Torch.class), + FIRE(51), + MOB_SPAWNER(52), + WOOD_STAIRS(53, Stairs.class), + CHEST(54), + REDSTONE_WIRE(55, RedstoneWire.class), + DIAMOND_ORE(56), + DIAMOND_BLOCK(57), + WORKBENCH(58), + CROPS(59, Crops.class), + SOIL(60, MaterialData.class), + FURNACE(61, Furnace.class), + BURNING_FURNACE(62, Furnace.class), + SIGN_POST(63, 1, Sign.class), + WOODEN_DOOR(64, Door.class), + LADDER(65, Ladder.class), + RAILS(66, Rails.class), + COBBLESTONE_STAIRS(67, Stairs.class), + WALL_SIGN(68, 1, Sign.class), + LEVER(69, Lever.class), + STONE_PLATE(70, PressurePlate.class), + IRON_DOOR_BLOCK(71, Door.class), + WOOD_PLATE(72, PressurePlate.class), + REDSTONE_ORE(73), + GLOWING_REDSTONE_ORE(74), + REDSTONE_TORCH_OFF(75, RedstoneTorch.class), + REDSTONE_TORCH_ON(76, RedstoneTorch.class), + STONE_BUTTON(77, Button.class), + SNOW(78), + ICE(79), + SNOW_BLOCK(80), + CACTUS(81, MaterialData.class), + CLAY(82), + SUGAR_CANE_BLOCK(83, MaterialData.class), + JUKEBOX(84, Jukebox.class), + FENCE(85), + PUMPKIN(86, Pumpkin.class), + NETHERRACK(87), + SOUL_SAND(88), + GLOWSTONE(89), + PORTAL(90), + JACK_O_LANTERN(91, Pumpkin.class), + CAKE_BLOCK(92, 1, Cake.class), + DIODE_BLOCK_OFF(93, Diode.class), + DIODE_BLOCK_ON(94, Diode.class), + LOCKED_CHEST(95), + TRAP_DOOR(96, TrapDoor.class), + // ----- Item Separator ----- + IRON_SPADE(256, 1, 250), + IRON_PICKAXE(257, 1, 250), + IRON_AXE(258, 1, 250), + FLINT_AND_STEEL(259, 1, 64), + APPLE(260, 1), + BOW(261, 1), + ARROW(262), + COAL(263, Coal.class), + DIAMOND(264), + IRON_INGOT(265), + GOLD_INGOT(266), + IRON_SWORD(267, 1, 250), + WOOD_SWORD(268, 1, 59), + WOOD_SPADE(269, 1, 59), + WOOD_PICKAXE(270, 1, 59), + WOOD_AXE(271, 1, 59), + STONE_SWORD(272, 1, 131), + STONE_SPADE(273, 1, 131), + STONE_PICKAXE(274, 1, 131), + STONE_AXE(275, 1, 131), + DIAMOND_SWORD(276, 1, 1561), + DIAMOND_SPADE(277, 1, 1561), + DIAMOND_PICKAXE(278, 1, 1561), + DIAMOND_AXE(279, 1, 1561), + STICK(280), + BOWL(281), + MUSHROOM_SOUP(282, 1), + GOLD_SWORD(283, 1, 32), + GOLD_SPADE(284, 1, 32), + GOLD_PICKAXE(285, 1, 32), + GOLD_AXE(286, 1, 32), + STRING(287), + FEATHER(288), + SULPHUR(289), + WOOD_HOE(290, 1, 59), + STONE_HOE(291, 1, 131), + IRON_HOE(292, 1, 250), + DIAMOND_HOE(293, 1, 1561), + GOLD_HOE(294, 1, 32), + SEEDS(295), + WHEAT(296), + BREAD(297, 1), + LEATHER_HELMET(298, 1, 33), + LEATHER_CHESTPLATE(299, 1, 47), + LEATHER_LEGGINGS(300, 1, 45), + LEATHER_BOOTS(301, 1, 39), + CHAINMAIL_HELMET(302, 1, 66), + CHAINMAIL_CHESTPLATE(303, 1, 95), + CHAINMAIL_LEGGINGS(304, 1, 91), + CHAINMAIL_BOOTS(305, 1, 78), + IRON_HELMET(306, 1, 135), + IRON_CHESTPLATE(307, 1, 191), + IRON_LEGGINGS(308, 1, 183), + IRON_BOOTS(309, 1, 159), + DIAMOND_HELMET(310, 1, 271), + DIAMOND_CHESTPLATE(311, 1, 383), + DIAMOND_LEGGINGS(312, 1, 367), + DIAMOND_BOOTS(313, 1, 319), + GOLD_HELMET(314, 1, 67), + GOLD_CHESTPLATE(315, 1, 95), + GOLD_LEGGINGS(316, 1, 91), + GOLD_BOOTS(317, 1, 79), + FLINT(318), + PORK(319, 1), + GRILLED_PORK(320, 1), + PAINTING(321), + GOLDEN_APPLE(322, 1), + SIGN(323, 1), + WOOD_DOOR(324, 1), + BUCKET(325, 1), + WATER_BUCKET(326, 1), + LAVA_BUCKET(327, 1), + MINECART(328, 1), + SADDLE(329, 1), + IRON_DOOR(330, 1), + REDSTONE(331), + SNOW_BALL(332, 16), + BOAT(333, 1), + LEATHER(334), + MILK_BUCKET(335, 1), + CLAY_BRICK(336), + CLAY_BALL(337), + SUGAR_CANE(338), + PAPER(339), + BOOK(340), + SLIME_BALL(341), + STORAGE_MINECART(342, 1), + POWERED_MINECART(343, 1), + EGG(344, 16), + COMPASS(345), + FISHING_ROD(346, 1, 64), + WATCH(347), + GLOWSTONE_DUST(348), + RAW_FISH(349, 1), + COOKED_FISH(350, 1), + INK_SACK(351, Dye.class), + BONE(352), + SUGAR(353), + CAKE(354, 1), + BED(355, 1), + DIODE(356), + COOKIE(357, 8), + MAP(358, 1, MaterialData.class), + SHEARS(359, 1, 238), + GOLD_RECORD(2256, 1), + GREEN_RECORD(2257, 1); + + private final int id; + private final Class data; + private static final Map lookupId = new HashMap(); + private static final Map lookupName = new HashMap(); + private final int maxStack; + private final short durability; + + private Material(final int id) { + this(id, 64); + } + + private Material(final int id, final int stack) { + this(id, stack, null); + } + + private Material(final int id, final int stack, final int durability) { + this(id, stack, durability, null); + } + + private Material(final int id, final Class data) { + this(id, 64, data); + } + + private Material(final int id, final int stack, final Class data) { + this(id, stack, -1, data); + } + + private Material(final int id, final int stack, final int durability, final Class data) { + this.id = id; + this.durability = (short) durability; + this.maxStack = stack; + this.data = data; + } + + /** + * Gets the item ID or block ID of this Material + * + * @return ID of this material + */ + public int getId() { + return id; + } + + /** + * Gets the maximum amount of this material that can be held in a stack + * + * @return Maximum stack size for this material + */ + public int getMaxStackSize() { + return maxStack; + } + + /** + * Gets the maximum durability of this material + * + * @return Maximum durability for this material + */ + public short getMaxDurability() { + return durability; + } + + /** + * Gets the MaterialData class associated with this Material + * + * @return MaterialData associated with this Material + */ + public Class getData() { + return data; + } + + /** + * Constructs a new MaterialData relevant for this Material, with the given + * initial data + * + * @param raw Initial data to construct the MaterialData with + * @return New MaterialData with the given data + */ + public MaterialData getNewData(final byte raw) { + if (data == null) { + return null; + } + + try { + Constructor ctor = data.getConstructor(int.class, byte.class); + + return ctor.newInstance(id, raw); + } catch (InstantiationException ex) { + Logger.getLogger(Material.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + Logger.getLogger(Material.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalArgumentException ex) { + Logger.getLogger(Material.class.getName()).log(Level.SEVERE, null, ex); + } catch (InvocationTargetException ex) { + Logger.getLogger(Material.class.getName()).log(Level.SEVERE, null, ex); + } catch (NoSuchMethodException ex) { + Logger.getLogger(Material.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(Material.class.getName()).log(Level.SEVERE, null, ex); + } + + return null; + } + + /** + * Checks if this Material is a placable block + * + * @return true if this material is a block + */ + public boolean isBlock() { + return id < 256; + } + + /** + * Attempts to get the Material with the given ID + * + * @param id ID of the material to get + * @return Material if found, or null + */ + public static Material getMaterial(final int id) { + return lookupId.get(id); + } + + /** + * Attempts to get the Material with the given name. + * This is a normal lookup, names must be the precise name they are given + * in the enum. + * + * @param name Name of the material to get + * @return Material if found, or null + */ + public static Material getMaterial(final String name) { + return lookupName.get(name); + } + + /** + * Attempts to match the Material with the given name. + * This is a match lookup; names will be converted to uppercase, then stripped + * of special characters in an attempt to format it like the enum + * + * @param name Name of the material to get + * @return Material if found, or null + */ + public static Material matchMaterial(final String name) { + Material result = null; + + try { + result = getMaterial(Integer.parseInt(name)); + } catch (NumberFormatException ex) {} + + if (result == null) { + String filtered = name.toUpperCase(); + + filtered = filtered.replaceAll("\\s+", "_").replaceAll("\\W", ""); + result = lookupName.get(filtered); + } + + return result; + } + + static { + for (Material material : values()) { + lookupId.put(material.getId(), material); + lookupName.put(material.name(), material); + } + } +} diff --git a/src/main/java/org/bukkit/Note.java b/src/main/java/org/bukkit/Note.java new file mode 100644 index 0000000..d8b8812 --- /dev/null +++ b/src/main/java/org/bukkit/Note.java @@ -0,0 +1,202 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * A note class to store a specific note. + */ +public class Note { + + /** + * An enum holding tones. + */ + public enum Tone { + F((byte) -0x1, true), + G((byte) 0x1, true), + A((byte) 0x3, true), + B((byte) 0x5, false), + C((byte) 0x6, true), + D((byte) 0x8, true), + E((byte) 0xA, false); + + private final boolean sharpable; + private final byte id; + private static final Map tones = new HashMap(); + /** The number of tones including sharped tones. */ + public static final byte TONES_COUNT; + + private Tone(byte id, boolean sharpable) { + this.id = id; + this.sharpable = sharpable; + } + + /** + * Returns the not sharped id of this tone. + * + * @return the not sharped id of this tone. + */ + public byte getId() { + return getId(false); + } + + /** + * Returns the id of this tone. These method allows to return the + * sharped id of the tone. If the tone couldn't be sharped it always + * return the not sharped id of this tone. + * + * @param sharped + * Set to true to return the sharped id. + * @return the id of this tone. + */ + public byte getId(boolean sharped) { + byte tempId = (byte) (sharped && sharpable ? id + 1 : id); + + while (tempId < 0) { + tempId += TONES_COUNT; + } + return (byte) (tempId % TONES_COUNT); + } + + /** + * Returns if this tone could be sharped. + * + * @return if this tone could be sharped. + */ + public boolean isSharpable() { + return sharpable; + } + + /** + * Returns if this tone id is the sharped id of the tone. + * + * @param id + * the id of the tone. + * @return if the tone id is the sharped id of the tone. + * @throws IllegalArgumentException + * if neither the tone nor the semitone have the id. + */ + public boolean isSharped(byte id) { + if (id == getId(false)) { + return false; + } else if (id == getId(true)) { + return true; + } else { + // The id isn't matching to the tone! + throw new IllegalArgumentException("The id isn't matching to the tone."); + } + } + + /** + * Returns the tone to id. Also returning the semitones. + * + * @param id + * the id of the tone. + * @return the tone to id. + */ + public static Tone getToneById(byte id) { + return tones.get(id); + } + + static { + byte lowest = F.id; + byte highest = F.id; + for (Tone tone : Tone.values()) { + byte id = tone.id; + tones.put(id, tone); + if (id < lowest) { + lowest = id; + } + if (tone.isSharpable()) { + id++; + tones.put(id, tone); + } + if (id > highest) { + highest = id; + } + } + + TONES_COUNT = (byte) (highest - lowest + 1); + tones.put((byte) (TONES_COUNT - 1), F); + } + } + + private final byte note; + + /** + * Creates a new note. + * + * @param note + * Internal note id. {@link #getId()} always return this value. + * The value has to be in the interval [0; 24]. + */ + public Note(byte note) { + if (note < 0 || note > 24) { + throw new IllegalArgumentException("The note value has to be between 0 and 24."); + } + this.note = note; + } + + /** + * Creates a new note. + * + * @param octave + * The octave where the note is in. Has to be 0 - 2. + * @param note + * The tone within the octave. If the octave is 2 the note has to + * be F#. + * @param sharped + * Set it the tone is sharped (e.g. for F#). + */ + public Note(byte octave, Tone note, boolean sharped) { + if (sharped && !note.isSharpable()) { + throw new IllegalArgumentException("This tone could not be sharped."); + } + if (octave < 0 || octave > 2 || (octave == 2 && !(note == Tone.F && sharped))) { + throw new IllegalArgumentException("Tone and octave have to be between F#0 and F#2"); + } + this.note = (byte) (octave * Tone.TONES_COUNT + note.getId(sharped)); + } + + /** + * Returns the internal id of this note. + * + * @return the internal id of this note. + */ + public byte getId() { + return note; + } + + /** + * Returns the octave of this note. + * + * @return the octave of this note. + */ + public int getOctave() { + return note / Tone.TONES_COUNT; + } + + private byte getToneByte() { + return (byte) (note % Tone.TONES_COUNT); + } + + /** + * Returns the tone of this note. + * + * @return the tone of this note. + */ + public Tone getTone() { + return Tone.getToneById(getToneByte()); + } + + /** + * Returns if this note is sharped. + * + * @return if this note is sharped. + */ + public boolean isSharped() { + byte note = getToneByte(); + return Tone.getToneById(note).isSharped(note); + } + +} diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java new file mode 100644 index 0000000..fff8aa8 --- /dev/null +++ b/src/main/java/org/bukkit/OfflinePlayer.java @@ -0,0 +1,47 @@ +package org.bukkit; + +import org.bukkit.permissions.ServerOperator; + +public interface OfflinePlayer extends ServerOperator { + /** + * Checks if this player is currently online + * + * @return true if they are online + */ + public boolean isOnline(); + + /** + * Returns the name of this player + * + * @return Player name + */ + public String getName(); + + /** + * Checks if this player is banned or not + * + * @return true if banned, otherwise false + */ + public boolean isBanned(); + + /** + * Bans or unbans this player + * + * @param banned true if banned + */ + public void setBanned(boolean banned); + + /** + * Checks if this player is whitelisted or not + * + * @return true if whitelisted + */ + public boolean isWhitelisted(); + + /** + * Sets if this player is whitelisted or not + * + * @param value true if whitelisted + */ + public void setWhitelisted(boolean value); +} diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java new file mode 100644 index 0000000..3f62950 --- /dev/null +++ b/src/main/java/org/bukkit/Server.java @@ -0,0 +1,471 @@ +package org.bukkit; + +import com.avaje.ebean.config.ServerConfig; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Player; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.Recipe; +import org.bukkit.map.MapView; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.ServicesManager; +import org.bukkit.scheduler.BukkitScheduler; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Logger; + +/** + * Represents a server implementation + */ +public interface Server { + + + /** + * Gets the name of this server game version + * + * @return server game version + */ + public String getGameVersion(); + /** + * Used for all administrative messages, such as an operator using a command. + * + * For use in {@link #broadcast(java.lang.String, java.lang.String)} + */ + public static final String BROADCAST_CHANNEL_ADMINISTRATIVE = "bukkit.broadcast.admin"; + + /** + * Used for all announcement messages, such as informing users that a player has joined. + * + * For use in {@link #broadcast(java.lang.String, java.lang.String)} + */ + public static final String BROADCAST_CHANNEL_USERS = "bukkit.broadcast.user"; + + /** + * Gets the name of this server implementation + * + * @return name of this server implementation + */ + public String getName(); + + /** + * Gets the name of this server environment + * + * @return name of this server environment + */ + public String getServerEnvironment(); + + /** + * Gets the version string of Poseidon. + * + * @return version of Poseidon + */ + public String getPoseidonVersion(); + + + public String getPoseidonReleaseType(); + /** + * Gets the version string of this server enviroment. + * + * @return version of this server implementation + */ + public String getVersion(); + + /** + * Gets a list of all currently logged in players + * + * @return An array of Players that are currently online + */ + public Player[] getOnlinePlayers(); + + /** + * Get the maximum amount of players which can login to this server + * + * @return The amount of players this server allows + */ + public int getMaxPlayers(); + + /** + * Get the game port that the server runs on + * + * @return The port number of this server + */ + public int getPort(); + + /** + * Get the view distance from this server. + * + * @return The view distance from this server. + */ + public int getViewDistance(); + + /** + * Get the IP that this server is bound to or empty string if not specified + * + * @return The IP string that this server is bound to, otherwise empty string + */ + public String getIp(); + + /** + * Get the name of this server + * + * @return The name of this server + */ + public String getServerName(); + + /** + * Get an ID of this server. The ID is a simple generally alphanumeric + * ID that can be used for uniquely identifying this server. + * + * @return The ID of this server + */ + public String getServerId(); + + /** + * Gets whether this server allows the Nether or not. + * + * @return Whether this server allows the Nether or not. + */ + public boolean getAllowNether(); + + /** + * Gets whether this server has a whitelist or not. + * + * @return Whether this server has a whitelist or not. + */ + public boolean hasWhitelist(); + + /** + * Sets the whitelist on or off + * + * @param value true if whitelist is on, otherwise false + */ + public void setWhitelist(boolean value); + + /** + * Gets a list of whitelisted players + * + * @return Set containing all whitelisted players + */ + public Set getWhitelistedPlayers(); + + /** + * Reloads the whitelist from disk + */ + public void reloadWhitelist(); + + /** + * Broadcast a message to all players. + * + * This is the same as calling {@link #broadcast(java.lang.String, java.lang.String)} to {@link #BROADCAST_CHANNEL_USERS} + * + * @param message the message + * @return the number of players + */ + public int broadcastMessage(String message); + + /** + * Gets the name of the update folder. The update folder is used to safely update + * plugins at the right moment on a plugin load. + * + * @return The name of the update folder + */ + public String getUpdateFolder(); + + /** + * Gets a player object by the given username + * + * This method may not return objects for offline players + * + * @param name Name to look up + * @return Player if it was found, otherwise null + */ + public Player getPlayer(String name); + + //TODO: Javadoc + public Player getPlayer(UUID uuid); + + /** + * Gets the player with the exact given name, case insensitive + * + * @param name Exact name of the player to retrieve + * @return Player object or null if not found + */ + public Player getPlayerExact(String name); + + /** + * Attempts to match any players with the given name, and returns a list + * of all possibly matches + * + * This list is not sorted in any particular order. If an exact match is found, + * the returned list will only contain a single result. + * + * @param name Name to match + * @return List of all possible players + */ + public List matchPlayer(String name); + + /** + * Gets the PluginManager for interfacing with plugins + * + * @return PluginManager for this Server instance + */ + public PluginManager getPluginManager(); + + /** + * Gets the Scheduler for managing scheduled events + * + * @return Scheduler for this Server instance + */ + public BukkitScheduler getScheduler(); + + /** + * Gets a services manager + * + * @return Services manager + */ + public ServicesManager getServicesManager(); + + /** + * Gets a list of all worlds on this server + * + * @return A list of worlds + */ + public List getWorlds(); + + /** + * Creates or loads a world with the given name. + * If the world is already loaded, it will just return the equivalent of + * getWorld(name) + * + * @param name Name of the world to load + * @param environment Environment type of the world + * @return Newly created or loaded World + */ + public World createWorld(String name, World.Environment environment); + + /** + * Creates or loads a world with the given name. + * If the world is already loaded, it will just return the equivalent of + * getWorld(name) + * + * @param name Name of the world to load + * @param environment Environment type of the world + * @param seed Seed value to create the world with + * @return Newly created or loaded World + */ + public World createWorld(String name, World.Environment environment, long seed); + + /** + * Creates or loads a world with the given name. + * If the world is already loaded, it will just return the equivalent of + * getWorld(name) + * + * @param name Name of the world to load + * @param environment Environment type of the world + * @param generator ChunkGenerator to use in the construction of the new world + * @return Newly created or loaded World + */ + public World createWorld(String name, World.Environment environment, ChunkGenerator generator); + + /** + * Creates or loads a world with the given name. + * If the world is already loaded, it will just return the equivalent of + * getWorld(name) + * + * @param name Name of the world to load + * @param environment Environment type of the world + * @param seed Seed value to create the world with + * @param generator ChunkGenerator to use in the construction of the new world + * @return Newly created or loaded World + */ + public World createWorld(String name, World.Environment environment, long seed, ChunkGenerator generator); + + /** + * Unloads a world with the given name. + * + * @param name Name of the world to unload + * @param save Whether to save the chunks before unloading. + * @return Whether the action was Successful + */ + public boolean unloadWorld(String name, boolean save); + + /** + * Unloads the given world. + * + * @param world The world to unload + * @param save Whether to save the chunks before unloading. + * @return Whether the action was Successful + */ + public boolean unloadWorld(World world, boolean save); + + /** + * Gets the world with the given name + * + * @param name Name of the world to retrieve + * @return World with the given name, or null if none exists + */ + public World getWorld(String name); + + /** + * Gets the world from the given Unique ID + * + * @param uid Unique ID of the world to retrieve. + * @return World with the given Unique ID, or null if none exists. + */ + public World getWorld(UUID uid); + + /** + * Gets the map from the given item ID. + * + * @param id ID of the map to get. + * @return The MapView if it exists, or null otherwise. + */ + public MapView getMap(short id); + + /** + * Create a new map with an automatically assigned ID. + * + * @param world The world the map will belong to. + * @return The MapView just created. + */ + public MapView createMap(World world); + + /** + * Reloads the server, refreshing settings and plugin information + */ + public void reload(); + + /** + * Returns the primary logger associated with this server instance + * + * @return Logger associated with this server + */ + public Logger getLogger(); + + /** + * Gets a {@link PluginCommand} with the given name or alias + * + * @param name Name of the command to retrieve + * @return PluginCommand if found, otherwise null + */ + public PluginCommand getPluginCommand(String name); + + /** + * Writes loaded players to disk + */ + public void savePlayers(); + + /** + * Dispatches a command on the server, and executes it if found. + * + * @param cmdLine command + arguments. Example: "test abc 123" + * @return targetFound returns false if no target is found. + * @throws CommandException Thrown when the executor for the given command fails with an unhandled exception + */ + public boolean dispatchCommand(CommandSender sender, String commandLine); + + /** + * Populates a given {@link ServerConfig} with values attributes to this server + * + * @param config ServerConfig to populate + */ + public void configureDbConfig(ServerConfig config); + + /** + * Adds a recipe to the crafting manager. + * @param recipe The recipe to add. + * @return True to indicate that the recipe was added. + */ + public boolean addRecipe(Recipe recipe); + + /** + * Gets a list of command aliases defined in the server properties. + * + * @return Map of aliases to command names + */ + public Map getCommandAliases(); + + /** + * Gets the radius, in blocks, around each worlds spawn point to protect + * + * @return Spawn radius, or 0 if none + */ + public int getSpawnRadius(); + + /** + * Sets the radius, in blocks, around each worlds spawn point to protect + * + * @param value New spawn radius, or 0 if none + */ + public void setSpawnRadius(int value); + + /** + * Gets whether the Server is in online mode or not. + * + * @return Whether the server is in online mode. + */ + public boolean getOnlineMode(); + + /** + * Gets whether this server allows flying or not. + * + * @return Whether this server allows flying or not. + */ + public boolean getAllowFlight(); + + /** + * Shutdowns the server, stopping everything. + */ + public void shutdown(); + + /** + * Broadcasts the specified message to every user with the given permission + * + * @param message Message to broadcast + * @param permission Permission the users must have to receive the broadcast + * @return Amount of users who received the message + */ + public int broadcast(String message, String permission); + + /** + * Gets the player by the given name, regardless if they are offline or online. + * + * This will return an object even if the player does not exist. To this method, all players will exist. + * + * @param name Name of the player to retrieve + * @return OfflinePlayer object + */ + public OfflinePlayer getOfflinePlayer(String name); + + /** + * Gets a set containing all current IPs that are banned + * + * @return Set containing banned IP addresses + */ + public Set getIPBans(); + + /** + * Bans the specified address from the server + * + * @param address IP address to ban + */ + public void banIP(String address); + + /** + * Unbans the specified address from the server + * + * @param address IP address to unban + */ + public void unbanIP(String address); + + /** + * Gets a set containing all banned players + * + * @return Set containing banned players + */ + public Set getBannedPlayers(); + +} diff --git a/src/main/java/org/bukkit/Statistic.java b/src/main/java/org/bukkit/Statistic.java new file mode 100644 index 0000000..97923b8 --- /dev/null +++ b/src/main/java/org/bukkit/Statistic.java @@ -0,0 +1,83 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents a countable statistic, which is collected by the client + */ +public enum Statistic { + DAMAGE_DEALT(2020), + DAMAGE_TAKEN(2021), + DEATHS(2022), + MOB_KILLS(2023), + PLAYER_KILLS(2024), + FISH_CAUGHT(2025), + MINE_BLOCK(16777216, true), + USE_ITEM(6908288, false), + BREAK_ITEM(16973824, true); + + private final static Map statistics = new HashMap(); + private final int id; + private final boolean isSubstat; + private final boolean isBlock; + + private Statistic(int id) { + this(id, false, false); + } + + private Statistic(int id, boolean isBlock) { + this(id, true, isBlock); + } + + private Statistic(int id, boolean isSubstat, boolean isBlock) { + this.id = id; + this.isSubstat = isSubstat; + this.isBlock = isBlock; + } + + /** + * Gets the ID for this statistic. + * + * @return ID of this statistic + */ + public int getId() { + return id; + } + + /** + * Checks if this is a substatistic. + * + * A substatistic exists in mass for each block or item, depending on {@link #isBlock()} + * + * @return true if this is a substatistic + */ + public boolean isSubstatistic() { + return isSubstat; + } + + /** + * Checks if this is a substatistic dealing with blocks (As opposed to items) + * + * @return true if this deals with blocks, false if with items + */ + public boolean isBlock() { + return isSubstat && isBlock; + } + + /** + * Gets the statistic associated with the given ID. + * + * @param id ID of the statistic to return + * @return statistic with the given ID + */ + public static Statistic getStatistic(int id) { + return statistics.get(id); + } + + static { + for (Statistic stat : values()) { + statistics.put(stat.getId(), stat); + } + } +} diff --git a/src/main/java/org/bukkit/TravelAgent.java b/src/main/java/org/bukkit/TravelAgent.java new file mode 100644 index 0000000..25beb09 --- /dev/null +++ b/src/main/java/org/bukkit/TravelAgent.java @@ -0,0 +1,70 @@ +package org.bukkit; + +public interface TravelAgent { + + /** + * Set the Block radius to search in for available portals. + * + * @param radius The radius in which to search for a portal from the location. + * @return + */ + public TravelAgent setSearchRadius(int radius); + + /** + * Gets the search radius value for finding an available portal. + * + * @return Returns the currently set search radius. + */ + public int getSearchRadius(); + + /** + * Sets the maximum radius from the given location to create a portal. + * + * @param radius The radius in which to create a portal from the location. + * @return + */ + public TravelAgent setCreationRadius(int radius); + + /** + * Gets the maximum radius from the given location to create a portal. + * + * @return Returns the currently set creation radius. + */ + public int getCreationRadius(); + + /** + * Returns whether the TravelAgent will attempt to create a destination portal or not. + * + * @return Return whether the TravelAgent should create a destination portal or not. + */ + public boolean getCanCreatePortal(); + + /** + * Sets whether the TravelAgent should attempt to create a destination portal or not. + * + * @param create Sets whether the TravelAgent should create a destination portal or not. + */ + public void setCanCreatePortal(boolean create); + + /** + * Attempt to find a portal near the given location, if a portal is not found it will attempt to create one. + * + * @param location The location where the search for a portal should begin. + * @return Returns the location of a portal which has been found or returns the location passed to the method if unsuccessful. + */ + public Location findOrCreate(Location location); + + /** + * Attempt to find a portal near the given location. + * + * @return Returns the location of the nearest portal to the location. + */ + public Location findPortal(Location location); + + /** + * Attempt to create a portal near the given location. + * + * @return True if a nether portal was successfully created. + */ + public boolean createPortal(Location location); +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/TreeSpecies.java b/src/main/java/org/bukkit/TreeSpecies.java new file mode 100644 index 0000000..3764bd9 --- /dev/null +++ b/src/main/java/org/bukkit/TreeSpecies.java @@ -0,0 +1,58 @@ +package org.bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the different species of trees regardless of size. + * @author sunkid + */ +public enum TreeSpecies { + + /** + * Represents the common tree species. + */ + GENERIC((byte) 0x0), + /** + * Represents the darker barked/leaved tree species. + */ + REDWOOD((byte) 0x1), + /** + * Represents birches. + */ + BIRCH((byte) 0x2); + + private final byte data; + private final static Map species = new HashMap(); + + private TreeSpecies(final byte data) { + this.data = data; + } + + /** + * Gets the associated data value representing this species + * + * @return A byte containing the data value of this tree species + */ + public byte getData() { + return data; + } + + /** + * Gets the TreeSpecies with the given data value + * + * @param data + * Data value to fetch + * @return The {@link TreeSpecies} representing the given value, or null if + * it doesn't exist + */ + public static TreeSpecies getByData(final byte data) { + return species.get(data); + } + + static { + for (TreeSpecies s : TreeSpecies.values()) { + species.put(s.getData(), s); + } + } +} diff --git a/src/main/java/org/bukkit/TreeType.java b/src/main/java/org/bukkit/TreeType.java new file mode 100644 index 0000000..c0d9e3f --- /dev/null +++ b/src/main/java/org/bukkit/TreeType.java @@ -0,0 +1,14 @@ +package org.bukkit; + +/** + * Tree type. + * + * @author sk89q + */ +public enum TreeType { + TREE, + BIG_TREE, + REDWOOD, + TALL_REDWOOD, + BIRCH +} diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java new file mode 100644 index 0000000..91877eb --- /dev/null +++ b/src/main/java/org/bukkit/World.java @@ -0,0 +1,803 @@ +package org.bukkit; + +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.entity.*; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Represents a world, which may contain entities, chunks and blocks + */ +public interface World { + + /** + * Gets the {@link Block} at the given coordinates + * + * @param x X-coordinate of the block + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @return Block at the given coordinates + * @see #getBlockTypeIdAt(int, int, int) Returns the current type ID of the block + */ + public Block getBlockAt(int x, int y, int z); + + /** + * Gets the {@link Block} at the given {@link Location} + * + * @param location Location of the block + * @return Block at the given location + * @see #getBlockTypeIdAt(org.bukkit.Location) Returns the current type ID of the block + */ + public Block getBlockAt(Location location); + + /** + * Gets the block type ID at the given coordinates + * + * @param x X-coordinate of the block + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @return Type ID of the block at the given coordinates + * @see #getBlockAt(int, int, int) Returns a live Block object at the given location + */ + public int getBlockTypeIdAt(int x, int y, int z); + + /** + * Gets the block type ID at the given {@link Location} + * + * @param location Location of the block + * @return Type ID of the block at the given location + * @see #getBlockAt(org.bukkit.Location) Returns a live Block object at the given location + */ + public int getBlockTypeIdAt(Location location); + + /** + * Gets the highest non-air coordinate at the given coordinates + * + * @param x X-coordinate of the blocks + * @param z Z-coordinate of the blocks + * @return Y-coordinate of the highest non-air block + */ + public int getHighestBlockYAt(int x, int z); + + /** + * Gets the highest non-air coordinate at the given {@link Location} + * + * @param location Location of the blocks + * @return Y-coordinate of the highest non-air block + */ + public int getHighestBlockYAt(Location location); + + /** + * Gets the highest non-empty block at the given coordinates + * + * @param x X-coordinate of the block + * @param z Z-coordinate of the block + * + * @return Highest non-empty block + */ + public Block getHighestBlockAt(int x, int z); + + /** + * Gets the highest non-empty block at the given coordinates + * + * @param location Coordinates to get the highest block + * + * @return Highest non-empty block + */ + public Block getHighestBlockAt(Location location); + + /** + * Gets the {@link Chunk} at the given coordinates + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @return Chunk at the given coordinates + */ + public Chunk getChunkAt(int x, int z); + + /** + * Gets the {@link Chunk} at the given {@link Location} + * + * @param location Location of the chunk + * @return Chunk at the given location + */ + public Chunk getChunkAt(Location location); + + /** + * Gets the {@link Chunk} that contains the given {@link Block} + * + * @param block Block to get the containing chunk from + * @return The chunk that contains the given block + */ + public Chunk getChunkAt(Block block); + + /** + * Checks if the specified {@link Chunk} is loaded + * + * @param chunk The chunk to check + * @return true if the chunk is loaded, otherwise false + */ + public boolean isChunkLoaded(Chunk chunk); + + /** + * Gets an array of all loaded {@link Chunk}s + * + * @return Chunk[] containing all loaded chunks + */ + public Chunk[] getLoadedChunks(); + + /** + * Loads the specified {@link Chunk} + * + * @param chunk The chunk to load + */ + public void loadChunk(Chunk chunk); + + /** + * Checks if the {@link Chunk} at the specified coordinates is loaded + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @return true if the chunk is loaded, otherwise false + */ + public boolean isChunkLoaded(int x, int z); + + /** + * Loads the {@link Chunk} at the specified coordinates + * + * If the chunk does not exist, it will be generated. + * This method is analogous to {@link #loadChunk(int, int, boolean)} where generate is true. + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + */ + public void loadChunk(int x, int z); + + /** + * Loads the {@link Chunk} at the specified coordinates + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @param generate Whether or not to generate a chunk if it doesn't already exist + * @return true if the chunk has loaded successfully, otherwise false + */ + public boolean loadChunk(int x, int z, boolean generate); + + /** + * Safely unloads and saves the {@link Chunk} at the specified coordinates + * + * This method is analogous to {@link #unloadChunk(int, int, boolean, boolean)} where safe and saveis true + * + * @param chunk the chunk to unload + * @return true if the chunk has unloaded successfully, otherwise false + */ + public boolean unloadChunk(Chunk chunk); + + /** + * Safely unloads and saves the {@link Chunk} at the specified coordinates + * + * This method is analogous to {@link #unloadChunk(int, int, boolean, boolean)} where safe and saveis true + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @return true if the chunk has unloaded successfully, otherwise false + */ + public boolean unloadChunk(int x, int z); + + /** + * Safely unloads and optionally saves the {@link Chunk} at the specified coordinates + * + * This method is analogous to {@link #unloadChunk(int, int, boolean, boolean)} where save is true + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @param save Whether or not to save the chunk + * @return true if the chunk has unloaded successfully, otherwise false + */ + public boolean unloadChunk(int x, int z, boolean save); + + /** + * Unloads and optionally saves the {@link Chunk} at the specified coordinates + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @param save Controls whether the chunk is saved + * @param safe Controls whether to unload the chunk when players are nearby + * @return true if the chunk has unloaded successfully, otherwise false + */ + public boolean unloadChunk(int x, int z, boolean save, boolean safe); + + /** + * Safely queues the {@link Chunk} at the specified coordinates for unloading + * + * This method is analogous to {@link #unloadChunkRequest(int, int, boolean)} where safe is true + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @return true is the queue attempt was successful, otherwise false + */ + public boolean unloadChunkRequest(int x, int z); + + /** + * Queues the {@link Chunk} at the specified coordinates for unloading + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @param safe Controls whether to queue the chunk when players are nearby + * @return Whether the chunk was actually queued + */ + public boolean unloadChunkRequest(int x, int z, boolean safe); + + /** + * Regenerates the {@link Chunk} at the specified coordinates + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @return Whether the chunk was actually regenerated + */ + public boolean regenerateChunk(int x, int z); + + /** + * Resends the {@link Chunk} to all clients + * + * @param x X-coordinate of the chunk + * @param z Z-coordinate of the chunk + * @return Whether the chunk was actually refreshed + */ + public boolean refreshChunk(int x, int z); + + /** + * Drops an item at the specified {@link Location} + * + * @param location Location to drop the item + * @param item ItemStack to drop + * @return ItemDrop entity created as a result of this method + */ + public Item dropItem(Location location, ItemStack item); + + /** + * Drops an item at the specified {@link Location} with a random offset + * + * @param location Location to drop the item + * @param item ItemStack to drop + * @return ItemDrop entity created as a result of this method + */ + public Item dropItemNaturally(Location location, ItemStack item); + + /** + * Creates an {@link Arrow} entity at the given {@link Location} + * + * @param location Location to spawn the arrow + * @param velocity Velocity to shoot the arrow in + * @param speed Speed of the arrow. A recommend speed is 0.6 + * @param spread Spread of the arrow. A recommend spread is 12 + * @return Arrow entity spawned as a result of this method + */ + public Arrow spawnArrow(Location location, Vector velocity, float speed, float spread); + + /** + * Creates a tree at the given {@link Location} + * + * @param location Location to spawn the tree + * @param type Type of the tree to create + * @return true if the tree was created successfully, otherwise false + */ + public boolean generateTree(Location location, TreeType type); + + /** + * Creates a tree at the given {@link Location} + * + * @param loc Location to spawn the tree + * @param type Type of the tree to create + * @param delegate A class to call for each block changed as a result of this method + * @return true if the tree was created successfully, otherwise false + */ + public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate); + + /** + * Creates a creature at the given {@link Location} + * + * @param loc The location to spawn the creature + * @param type The creature to spawn + * @return Resulting LivingEntity of this method, or null if it was unsuccessful + */ + public LivingEntity spawnCreature(Location loc, CreatureType type); + + /** + * Strikes lightning at the given {@link Location} + * + * @param loc The location to strike lightning + * @return + */ + public LightningStrike strikeLightning(Location loc); + + /** + * Strikes lightning at the given {@link Location} without doing damage + * + * @param loc The location to strike lightning + * @return + */ + public LightningStrike strikeLightningEffect(Location loc); + + /** + * Get a list of all entities in this World + * + * @return A List of all Entities currently residing in this world + */ + public List getEntities(); + + /** + * Get a list of all living entities in this World + * + * @return A List of all LivingEntities currently residing in this world + */ + public List getLivingEntities(); + + /** + * Get a list of all players in this World + * + * @return A list of all Players currently residing in this world + */ + public List getPlayers(); + + /** + * Gets the unique name of this world + * + * @return Name of this world + */ + public String getName(); + + /** + * Gets the Unique ID of this world + * + * @return Unique ID of this world. + */ + public UUID getUID(); + + /** + * Gets a semi-unique identifier for this world. + * + * While it is highly unlikely that this may be shared with another World, + * it is not guaranteed to be unique + * + * @deprecated Replaced with {@link #getUID()} + * @return Id of this world + */ + @Deprecated + public long getId(); + + /** + * Gets the default spawn {@link Location} of this world + * + * @return The spawn location of this world + */ + public Location getSpawnLocation(); + + /** + * Sets the spawn location of the world + * + * @param x + * @param y + * @param z + * @return True if it was successfully set. + */ + public boolean setSpawnLocation(int x, int y, int z); + + // Poseidon start + + /** + * Sets the spawn location of the world + * + * @param x + * @param y + * @param z + * @param yaw + * @param pitch + * @return True if it was successfully set. + */ + public boolean setSpawnLocation(int x, int y, int z, float yaw, float pitch); + + // Poseidon end + + /** + * Gets the relative in-game time of this world. + * + * The relative time is analogous to hours * 1000 + * + * @return The current relative time + * @see #getFullTime() Returns an absolute time of this world + */ + public long getTime(); + + /** + * Sets the relative in-game time on the server. + * + * The relative time is analogous to hours * 1000 + *

+ * Note that setting the relative time below the current relative time will + * actually move the clock forward a day. If you require to rewind time, please + * see setFullTime + * + * @param time The new relative time to set the in-game time to (in hours*1000) + * @see #setFullTime(long) Sets the absolute time of this world + */ + public void setTime(long time); + + /** + * Gets the full in-game time on this world + * + * @return The current absolute time + * @see #getTime() Returns a relative time of this world + */ + public long getFullTime(); + + /** + * Sets the in-game time on the server + *

+ * Note that this sets the full time of the world, which may cause adverse + * effects such as breaking redstone clocks and any scheduled events + * + * @param time The new absolute time to set this world to + * @see #setTime(long) Sets the relative time of this world + */ + public void setFullTime(long time); + + /** + * Returns whether the world has an ongoing storm. + * + * @return Whether there is an ongoing storm + */ + public boolean hasStorm(); + + /** + * Set whether there is a storm. A duration will be set for the new + * current conditions. + * + * @param hasStorm Whether there is rain and snow + */ + public void setStorm(boolean hasStorm); + + /** + * Get the remaining time in ticks of the current conditions. + * + * @return Time in ticks + */ + public int getWeatherDuration(); + + /** + * Set the remaining time in ticks of the current conditions. + * + * @param duration Time in ticks + */ + public void setWeatherDuration(int duration); + + /** + * Returns whether there is thunder. + * + * @return Whether there is thunder + */ + public boolean isThundering(); + + /** + * Set whether it is thundering. + * + * @param thundering Whether it is thundering + */ + public void setThundering(boolean thundering); + + /** + * Get the thundering duration. + * + * @return Duration in ticks + */ + public int getThunderDuration(); + + /** + * Set the thundering duration. + * + * @param duration Duration in ticks + */ + public void setThunderDuration(int duration); + + /** + * Creates explosion at given coordinates with given power + * + * @param x + * @param y + * @param z + * @param power The power of explosion, where 4F is TNT + * @return false if explosion was canceled, otherwise true + */ + public boolean createExplosion(double x, double y, double z, float power); + + /** + * Creates explosion at given coordinates with given power and optionally setting + * blocks on fire. + * + * @param x + * @param y + * @param z + * @param power The power of explosion, where 4F is TNT + * @param setFire Whether or not to set blocks on fire + * @return false if explosion was canceled, otherwise true + */ + public boolean createExplosion(double x, double y, double z, float power, boolean setFire); + + /** + * Creates explosion at given coordinates with given power and DamageCause and optionally setting + * blocks on fire. + * + * @param x + * @param y + * @param z + * @param power The power of explosion, where 4F is TNT + * @param setFire Whether or not to set blocks on fire + * @param customDamageCause The DamageCause to use for the explosion + * @return false if explosion was canceled, otherwise true + */ + public boolean createExplosion(double x, double y, double z, float power, boolean setFire, EntityDamageEvent.DamageCause customDamageCause); + + /** + * Creates explosion at given coordinates with given power + * + * @param loc + * @param power The power of explosion, where 4F is TNT + * @return false if explosion was canceled, otherwise true + */ + public boolean createExplosion(Location loc, float power); + + /** + * Creates explosion at given coordinates with given power and optionally setting + * blocks on fire. + * + * @param loc + * @param power The power of explosion, where 4F is TNT + * @param setFire Whether or not to set blocks on fire + * @return false if explosion was canceled, otherwise true + */ + public boolean createExplosion(Location loc, float power, boolean setFire); + + /** + * Creates explosion at given coordinates with given power and DamageCause and optionally setting + * blocks on fire. + * + * @param loc + * @param power The power of explosion, where 4F is TNT + * @param setFire Whether or not to set blocks on fire + * @param customDamageCause The DamageCause to use for the explosion + * @return false if explosion was canceled, otherwise true + */ + public boolean createExplosion(Location loc, float power, boolean setFire, EntityDamageEvent.DamageCause customDamageCause); + + /** + * Gets the {@link Environment} type of this world + * + * @return This worlds Environment type + */ + public Environment getEnvironment(); + + /** + * Gets the Seed for this world. + * + * @return This worlds Seed + */ + public long getSeed(); + + /** + * Gets the current PVP setting for this world. + * @return + */ + public boolean getPVP(); + + /** + * Sets the PVP setting for this world. + * @param pvp True/False whether PVP should be Enabled. + */ + public void setPVP(boolean pvp); + + /** + * Gets the chunk generator for this world + * + * @return ChunkGenerator associated with this world + */ + public ChunkGenerator getGenerator(); + + /** + * Saves world to disk + */ + public void save(); + + /** + * Gets a list of all applied {@link BlockPopulator}s for this World + * + * @return List containing any or none BlockPopulators + */ + public List getPopulators(); + + /** + * Spawn an entity of a specific class at the given {@link Location} + * + * @param location the {@link Location} to spawn the entity at + * @param clazz the class of the {@link Entity} to spawn + * @return an instance of the spawned {@link Entity} + * @throws an {@link IllegalArgumentException} if either parameter is null or the {@link Entity} requested cannot be spawned + */ + public T spawn(Location location, Class clazz) throws IllegalArgumentException; + + /** + * Plays an effect to all players within a default radius around a given location. + * + * @param location the {@link Location} around which players must be to hear the sound + * @param effect the {@link Effect} + * @param data a data bit needed for the RECORD_PLAY, SMOKE, and STEP_SOUND sounds + */ + public void playEffect(Location location, Effect effect, int data); + + /** + * Plays an effect to all players within a given radius around a location. + * + * @param location the {@link Location} around which players must be to hear the effect + * @param effect the {@link Effect} + * @param data a data bit needed for the RECORD_PLAY, SMOKE, and STEP effects + * @param radius the radius around the location + */ + public void playEffect(Location location, Effect effect, int data, int radius); + + /** + * Get empty chunk snapshot (equivalent to all air blocks), optionally including valid biome + * data. Used for representing an ungenerated chunk, or for fetching only biome data without loading a chunk. + * @param x - chunk x coordinate + * @param z - chunk z coordinate + * @param includeBiome - if true, snapshot includes per-coordinate biome type + * @param includeBiomeTempRain - if true, snapshot includes per-coordinate raw biome temperature and rainfall + */ + public ChunkSnapshot getEmptyChunkSnapshot(int x, int z, boolean includeBiome, boolean includeBiomeTempRain); + + /** + * Sets the spawn flags for this. + * + * @param allowMonsters - if true, monsters are allowed to spawn in this world. + * @param allowAnimals - if true, animals are allowed to spawn in this world. + */ + public void setSpawnFlags(boolean allowMonsters, boolean allowAnimals); + + /** + * Gets whether animals can spawn in this world. + * + * @return whether animals can spawn in this world. + */ + public boolean getAllowAnimals(); + + /** + * Gets whether monsters can spawn in this world. + * + * @return whether monsters can spawn in this world. + */ + public boolean getAllowMonsters(); + + /** + * Gets the biome for the given block coordinates. + * + * It is safe to run this method when the block does not exist, it will not create the block. + * + * @param x X coordinate of the block + * @param z Z coordinate of the block + * + * @return Biome of the requested block + */ + public Biome getBiome(int x, int z); + + /** + * Gets the temperature for the given block coordinates. + * + * It is safe to run this method when the block does not exist, it will not create the block. + * + * @param x X coordinate of the block + * @param z Z coordinate of the block + * + * @return Temperature of the requested block + */ + public double getTemperature(int x, int z); + + /** + * Gets the humidity for the given block coordinates. + * + * It is safe to run this method when the block does not exist, it will not create the block. + * + * @param x X coordinate of the block + * @param z Z coordinate of the block + * + * @return Humidity of the requested block + */ + public double getHumidity(int x, int z); + + /** + * Gets the maximum height of this world. + * + * If the max height is 100, there are only blocks from y=0 to y=99. + * + * @return Maximum height of the world + */ + public int getMaxHeight(); + + /** + * Gets whether the world's spawn area should be kept loaded into memory or not. + * + * @return true if the world's spawn area will be kept loaded into memory. + */ + public boolean getKeepSpawnInMemory(); + + /** + * Sets whether the world's spawn area should be kept loaded into memory or not. + * + * @param keepLoaded if true then the world's spawn area will be kept loaded into memory. + */ + public void setKeepSpawnInMemory(boolean keepLoaded); + + /** + * Gets whether or not the world will automatically save + * + * @return true if the world will automatically save, otherwise false + */ + public boolean isAutoSave(); + + /** + * Sets whether or not the world will automatically save + * + * @param value true if the world should automatically save, otherwise false + */ + public void setAutoSave(boolean value); + + /** + * Represents various map environment types that a world may be + */ + public enum Environment { + /** + * Represents the "normal"/"surface world" map + */ + NORMAL(0), + /** + * Represents a nether based map ("hell") + */ + NETHER(-1), + /** + * Represents a sky-lands based map ("heaven") + */ + SKYLANDS(1); + + private final int id; + private static final Map lookup = new HashMap(); + + private Environment(int id) { + this.id = id; + } + + /** + * Gets the dimension ID of this environment + * + * @return dimension ID + */ + public int getId() { + return id; + } + + public static Environment getEnvironment(int id) { + return lookup.get(id); + } + + static { + for (Environment env : values()) { + lookup.put(env.getId(), env); + } + } + } +} diff --git a/src/main/java/org/bukkit/block/Biome.java b/src/main/java/org/bukkit/block/Biome.java new file mode 100644 index 0000000..7abacb1 --- /dev/null +++ b/src/main/java/org/bukkit/block/Biome.java @@ -0,0 +1,20 @@ +package org.bukkit.block; + +/** + * Holds all accepted Biomes in the default server + */ +public enum Biome { + RAINFOREST, + SWAMPLAND, + SEASONAL_FOREST, + FOREST, + SAVANNA, + SHRUBLAND, + TAIGA, + DESERT, + PLAINS, + ICE_DESERT, + TUNDRA, + HELL, + SKY +} diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java new file mode 100644 index 0000000..0cf844e --- /dev/null +++ b/src/main/java/org/bukkit/block/Block.java @@ -0,0 +1,280 @@ +package org.bukkit.block; + +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; + +/** + * Represents a block. This is a live object, and only one Block may exist for + * any given location in a world. The state of the block may change concurrently + * to your own handling of it; use block.getState() to get a snapshot state of a + * block which will not be modified. + */ +public interface Block { + + /** + * Gets the metadata for this block + * + * @return block specific metadata + */ + byte getData(); + + /** + * @deprecated use {@link #getRelative(BlockFace face)} + */ + @Deprecated Block getFace(BlockFace face); + + /** + * @deprecated use {@link #getRelative(BlockFace face, int distance)} + */ + @Deprecated Block getFace(BlockFace face, int distance); + + /** + * Gets the block at the given offsets + * + * @param modX X-coordinate offset + * @param modY Y-coordinate offset + * @param modZ Z-coordinate offset + * @return Block at the given offsets + */ + Block getRelative(int modX, int modY, int modZ); + + /** + * Gets the block at the given face
+ *
+ * This method is equal to getRelative(face, 1) + * + * @param face Face of this block to return + * @return Block at the given face + * @see Block.getRelative(BlockFace face, int distance); + */ + Block getRelative(BlockFace face); + + /** + * Gets the block at the given distance of the given face
+ *
+ * For example, the following method places water at 100,102,100; two blocks + * above 100,100,100. + *
+     * Block block = world.getBlockAt(100,100,100);
+     * Block shower = block.getFace(BlockFace.UP, 2);
+     * shower.setType(Material.WATER);
+     * 
+ * + * @param face Face of this block to return + * @param distance Distance to get the block at + * @return Block at the given face + */ + Block getRelative(BlockFace face, int distance); + + /** + * Gets the type of this block + * + * @return block type + */ + Material getType(); + + /** + * Gets the type-id of this block + * + * @return block type-id + */ + int getTypeId(); + + /** + * Gets the light level between 0-15 + * + * @return light level + */ + byte getLightLevel(); + + /** + * Gets the world which contains this Block + * + * @return World containing this block + */ + World getWorld(); + + /** + * Gets the x-coordinate of this block + * + * @return x-coordinate + */ + int getX(); + + /** + * Gets the y-coordinate of this block + * + * @return y-coordinate + */ + int getY(); + + /** + * Gets the z-coordinate of this block + * + * @return z-coordinate + */ + int getZ(); + + /** + * Gets the Location of the block + * + * @return Location of block + */ + + Location getLocation(); + + /** + * Gets the chunk which contains this block + * + * @return Containing Chunk + */ + Chunk getChunk(); + + /** + * Sets the metadata for this block + * + * @param data New block specific metadata + */ + void setData(byte data); + + void setData(byte data, boolean applyPhyiscs); + + /** + * Sets the type of this block + * + * @param type Material to change this block to + */ + void setType(Material type); + + /** + * Sets the type-id of this block + * + * @param type Type-Id to change this block to + * @return whether the block was changed + */ + boolean setTypeId(int type); + + boolean setTypeId(int type, boolean applyPhysics); + + boolean setTypeIdAndData(int type, byte data, boolean applyPhyiscs); + + /** + * Gets the face relation of this block compared to the given block
+ *
+ * For example: + *
+     * Block current = world.getBlockAt(100, 100, 100);
+     * Block target = world.getBlockAt(100, 101, 100);
+     *
+     * current.getFace(target) == BlockFace.Up;
+     * 
+ *
+ * If the given block is not connected to this block, null may be returned + * + * @param block Block to compare against this block + * @return BlockFace of this block which has the requested block, or null + */ + BlockFace getFace(Block block); + + /** + * Captures the current state of this block. You may then cast that state + * into any accepted type, such as Furnace or Sign. + * + * The returned object will never be updated, and you are not guaranteed that + * (for example) a sign is still a sign after you capture its state. + * + * @return BlockState with the current state of this block. + */ + BlockState getState(); + + /** + * Returns the biome that this block resides in + * + * @return Biome type containing this block + */ + Biome getBiome(); + + /** + * Returns true if the block is being powered by Redstone. + * + * @return + */ + boolean isBlockPowered(); + + /** + * Returns true if the block is being indirectly powered by Redstone. + * + * @return + */ + boolean isBlockIndirectlyPowered(); + + /** + * Returns true if the block face is being powered by Redstone. + * + * @return + */ + boolean isBlockFacePowered(BlockFace face); + + /** + * Returns true if the block face is being indirectly powered by Redstone. + * + * @return + */ + boolean isBlockFaceIndirectlyPowered(BlockFace face); + + /** + * Returns the redstone power being provided to this block face + * + * @param face the face of the block to query or BlockFace.SELF for the block itself + * @return + */ + int getBlockPower(BlockFace face); + + /** + * Returns the redstone power being provided to this block + * + * @return + */ + int getBlockPower(); + + /** + * Checks if this block is empty. + * + * A block is considered empty when {@link #getType()} returns {@link Material#AIR}. + * + * @return true if this block is empty + */ + boolean isEmpty(); + + /** + * Checks if this block is liquid. + * + * A block is considered liquid when {@link #getType()} returns {@link Material#WATER}, {@link Material#STATIONARY_WATER}, {@link Material#LAVA} or {@link Material#STATIONARY_LAVA}. + * + * @return true if this block is liquid + */ + boolean isLiquid(); + + /** + * Gets the temperature of the biome of this block + * + * @return Temperature of this block + */ + double getTemperature(); + + /** + * Gets the humidity of the biome of this block + * + * @return Humidity of this block + */ + double getHumidity(); + + /** + * Returns the reaction of the block when moved by a piston + * + * @return reaction + */ + PistonMoveReaction getPistonMoveReaction(); +} diff --git a/src/main/java/org/bukkit/block/BlockFace.java b/src/main/java/org/bukkit/block/BlockFace.java new file mode 100644 index 0000000..1c687eb --- /dev/null +++ b/src/main/java/org/bukkit/block/BlockFace.java @@ -0,0 +1,129 @@ +package org.bukkit.block; + +/** + * Represents the face of a block + */ +public enum BlockFace { + NORTH(-1, 0, 0), + EAST(0, 0, -1), + SOUTH(1, 0, 0), + WEST(0, 0, 1), + UP(0, 1, 0), + DOWN(0, -1, 0), + NORTH_EAST(NORTH, EAST), + NORTH_WEST(NORTH, WEST), + SOUTH_EAST(SOUTH, EAST), + SOUTH_WEST(SOUTH, WEST), + WEST_NORTH_WEST(WEST, NORTH_WEST), + NORTH_NORTH_WEST(NORTH, NORTH_WEST), + NORTH_NORTH_EAST(NORTH, NORTH_EAST), + EAST_NORTH_EAST(EAST, NORTH_EAST), + EAST_SOUTH_EAST(EAST, SOUTH_EAST), + SOUTH_SOUTH_EAST(SOUTH, SOUTH_EAST), + SOUTH_SOUTH_WEST(SOUTH, SOUTH_WEST), + WEST_SOUTH_WEST(WEST, SOUTH_WEST), + SELF(0, 0, 0); + + private final int modX; + private final int modY; + private final int modZ; + + private BlockFace(final int modX, final int modY, final int modZ) { + this.modX = modX; + this.modY = modY; + this.modZ = modZ; + } + + private BlockFace(final BlockFace face1, final BlockFace face2) { + this.modX = face1.getModX() + face2.getModX(); + this.modY = face1.getModY() + face2.getModY(); + this.modZ = face1.getModZ() + face2.getModZ(); + } + + /** + * Get the amount of X-coordinates to modify to get the represented block + * @return Amount of X-coordinates to modify + */ + public int getModX() { + return modX; + } + + /** + * Get the amount of Y-coordinates to modify to get the represented block + * @return Amount of Y-coordinates to modify + */ + public int getModY() { + return modY; + } + + /** + * Get the amount of Z-coordinates to modify to get the represented block + * @return Amount of Z-coordinates to modify + */ + public int getModZ() { + return modZ; + } + + public BlockFace getOppositeFace() { + switch (this) { + case NORTH: + return BlockFace.SOUTH; + + case SOUTH: + return BlockFace.NORTH; + + case EAST: + return BlockFace.WEST; + + case WEST: + return BlockFace.EAST; + + case UP: + return BlockFace.DOWN; + + case DOWN: + return BlockFace.UP; + + case NORTH_EAST: + return BlockFace.SOUTH_WEST; + + case NORTH_WEST: + return BlockFace.SOUTH_EAST; + + case SOUTH_EAST: + return BlockFace.NORTH_WEST; + + case SOUTH_WEST: + return BlockFace.NORTH_EAST; + + case WEST_NORTH_WEST: + return BlockFace.EAST_SOUTH_EAST; + + case NORTH_NORTH_WEST: + return BlockFace.SOUTH_SOUTH_EAST; + + case NORTH_NORTH_EAST: + return BlockFace.SOUTH_SOUTH_WEST; + + case EAST_NORTH_EAST: + return BlockFace.WEST_SOUTH_WEST; + + case EAST_SOUTH_EAST: + return BlockFace.WEST_NORTH_WEST; + + case SOUTH_SOUTH_EAST: + return BlockFace.NORTH_NORTH_WEST; + + case SOUTH_SOUTH_WEST: + return BlockFace.NORTH_NORTH_EAST; + + case WEST_SOUTH_WEST: + return BlockFace.EAST_NORTH_EAST; + + case SELF: + return BlockFace.SELF; + } + + return BlockFace.SELF; + } +} diff --git a/src/main/java/org/bukkit/block/BlockState.java b/src/main/java/org/bukkit/block/BlockState.java new file mode 100644 index 0000000..70f6ab6 --- /dev/null +++ b/src/main/java/org/bukkit/block/BlockState.java @@ -0,0 +1,140 @@ +package org.bukkit.block; + +import org.bukkit.Chunk; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.material.MaterialData; + +/** + * Represents a captured state of a block, which will not change automatically. + * + * Unlike Block, which only one object can exist per coordinate, BlockState can + * exist multiple times for any given Block. Note that another plugin may change + * the state of the block and you will not know, or they may change the block to + * another type entirely, causing your BlockState to become invalid. + */ +public interface BlockState { + + /** + * Gets the block represented by this BlockState + * + * @return Block that this BlockState represents + */ + Block getBlock(); + + /** + * Gets the metadata for this block + * + * @return block specific metadata + */ + MaterialData getData(); + + /** + * Gets the type of this block + * + * @return block type + */ + Material getType(); + + /** + * Gets the type-id of this block + * + * @return block type-id + */ + int getTypeId(); + + /** + * Gets the light level between 0-15 + * + * @return light level + */ + byte getLightLevel(); + + /** + * Gets the world which contains this Block + * + * @return World containing this block + */ + World getWorld(); + + /** + * Gets the x-coordinate of this block + * + * @return x-coordinate + */ + int getX(); + + /** + * Gets the y-coordinate of this block + * + * @return y-coordinate + */ + int getY(); + + /** + * Gets the z-coordinate of this block + * + * @return z-coordinate + */ + int getZ(); + + /** + * Gets the chunk which contains this block + * + * @return Containing Chunk + */ + Chunk getChunk(); + + /** + * Sets the metadata for this block + * + * @param data New block specific metadata + */ + void setData(MaterialData data); + + /** + * Sets the type of this block + * + * @param type Material to change this block to + */ + void setType(Material type); + + /** + * Sets the type-id of this block + * + * @param type Type-Id to change this block to + */ + boolean setTypeId(int type); + + /** + * Attempts to update the block represented by this state, setting it to the + * new values as defined by this state.
+ *
+ * This has the same effect as calling update(false). That is to say, + * this will not modify the state of a block if it is no longer the same + * type as it was when this state was taken. It will return false in this + * eventuality. + * + * @return true if the update was successful, otherwise false + * @see BlockState.update(boolean force) + */ + boolean update(); + + /** + * Attempts to update the block represented by this state, setting it to the + * new values as defined by this state.
+ *
+ * Unless force is true, this will not modify the state of a block if it is + * no longer the same type as it was when this state was taken. It will return + * false in this eventuality.
+ *
+ * If force is true, it will set the type of the block to match the new state, + * set the state data and then return true. + * + * @param force true to forcefully set the state + * @return true if the update was successful, otherwise false + */ + boolean update(boolean force); + + public byte getRawData(); +} diff --git a/src/main/java/org/bukkit/block/Chest.java b/src/main/java/org/bukkit/block/Chest.java new file mode 100644 index 0000000..4d0eea2 --- /dev/null +++ b/src/main/java/org/bukkit/block/Chest.java @@ -0,0 +1,8 @@ +package org.bukkit.block; + +/** + * Represents a chest. + * + * @author sk89q + */ +public interface Chest extends BlockState, ContainerBlock {} diff --git a/src/main/java/org/bukkit/block/ContainerBlock.java b/src/main/java/org/bukkit/block/ContainerBlock.java new file mode 100644 index 0000000..9f8b744 --- /dev/null +++ b/src/main/java/org/bukkit/block/ContainerBlock.java @@ -0,0 +1,18 @@ +package org.bukkit.block; + +import org.bukkit.inventory.Inventory; + +/** + * Indicates a block type that has inventory. + * + * @author sk89q + */ +public interface ContainerBlock { + + /** + * Get the block's inventory. + * + * @return + */ + public Inventory getInventory(); +} diff --git a/src/main/java/org/bukkit/block/CreatureSpawner.java b/src/main/java/org/bukkit/block/CreatureSpawner.java new file mode 100644 index 0000000..5ba4a39 --- /dev/null +++ b/src/main/java/org/bukkit/block/CreatureSpawner.java @@ -0,0 +1,54 @@ +package org.bukkit.block; + +import org.bukkit.entity.CreatureType; + +/** + * Represents a creature spawner. + * + * @author sk89q + * @author Cogito + */ +public interface CreatureSpawner extends BlockState { + + /** + * Get the spawner's creature type. + * + * @return + */ + public CreatureType getCreatureType(); + + /** + * Set the spawner creature type. + * + * @param mobType + */ + public void setCreatureType(CreatureType creatureType); + + /** + * Get the spawner's creature type. + * + * @return + */ + public String getCreatureTypeId(); + + /** + * Set the spawner mob type. + * + * @param creatureType + */ + public void setCreatureTypeId(String creatureType); + + /** + * Get the spawner's delay. + * + * @return + */ + public int getDelay(); + + /** + * Set the spawner's delay. + * + * @param delay + */ + public void setDelay(int delay); +} diff --git a/src/main/java/org/bukkit/block/Dispenser.java b/src/main/java/org/bukkit/block/Dispenser.java new file mode 100644 index 0000000..f9f0975 --- /dev/null +++ b/src/main/java/org/bukkit/block/Dispenser.java @@ -0,0 +1,18 @@ +package org.bukkit.block; + +/** + * Represents a dispenser. + * + * @author sk89q + */ +public interface Dispenser extends BlockState, ContainerBlock { + + /** + * Attempts to dispense the contents of this block
+ *
+ * If the block is no longer a dispenser, this will return false + * + * @return true if successful, otherwise false + */ + public boolean dispense(); +} diff --git a/src/main/java/org/bukkit/block/Furnace.java b/src/main/java/org/bukkit/block/Furnace.java new file mode 100644 index 0000000..84ff2c0 --- /dev/null +++ b/src/main/java/org/bukkit/block/Furnace.java @@ -0,0 +1,37 @@ +package org.bukkit.block; + +/** + * Represents a furnace. + * + * @author sk89q + */ +public interface Furnace extends BlockState, ContainerBlock { + + /** + * Get burn time. + * + * @return + */ + public short getBurnTime(); + + /** + * Set burn time. + * + * @param burnTime + */ + public void setBurnTime(short burnTime); + + /** + * Get cook time. + * + * @return + */ + public short getCookTime(); + + /** + * Set cook time. + * + * @param cookTime + */ + public void setCookTime(short cookTime); +} diff --git a/src/main/java/org/bukkit/block/NoteBlock.java b/src/main/java/org/bukkit/block/NoteBlock.java new file mode 100644 index 0000000..c3868e9 --- /dev/null +++ b/src/main/java/org/bukkit/block/NoteBlock.java @@ -0,0 +1,61 @@ +package org.bukkit.block; + +import org.bukkit.Instrument; +import org.bukkit.Note; + +/** + * Represents a note. + */ +public interface NoteBlock extends BlockState { + + /** + * Gets the note. + * + * @return + */ + public Note getNote(); + + /** + * Gets the note. + * + * @return + */ + public byte getRawNote(); + + /** + * Set the note. + * + * @param note + */ + public void setNote(Note note); + + /** + * Set the note. + * + * @param note + */ + public void setRawNote(byte note); + + /** + * Attempts to play the note at block
+ *
+ * If the block is no longer a note block, this will return false + * + * @return true if successful, otherwise false + */ + public boolean play(); + + /** + * Plays an arbitrary note with an arbitrary instrument + * + * @return true if successful, otherwise false + */ + public boolean play(byte instrument, byte note); + + /** + * Plays an arbitrary note with an arbitrary instrument + * + * @return true if successful, otherwise false + */ + public boolean play(Instrument instrument, Note note); +} diff --git a/src/main/java/org/bukkit/block/PistonMoveReaction.java b/src/main/java/org/bukkit/block/PistonMoveReaction.java new file mode 100644 index 0000000..8306412 --- /dev/null +++ b/src/main/java/org/bukkit/block/PistonMoveReaction.java @@ -0,0 +1,30 @@ +package org.bukkit.block; + +import java.util.HashMap; +import java.util.Map; + +public enum PistonMoveReaction { + MOVE(0), + BREAK(1), + BLOCK(2); + + private int id; + private static Map byId = new HashMap(); + static { + for (PistonMoveReaction reaction: PistonMoveReaction.values()) { + byId.put(reaction.id, reaction); + } + } + + private PistonMoveReaction(int id) { + this.id = id; + } + + public int getId() { + return this.id; + } + + public static PistonMoveReaction getById(int id) { + return byId.get(id); + } +} diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit/block/Sign.java new file mode 100644 index 0000000..3773574 --- /dev/null +++ b/src/main/java/org/bukkit/block/Sign.java @@ -0,0 +1,37 @@ +package org.bukkit.block; + +/** + * Represents either a SignPost or a WallSign + */ +public interface Sign extends BlockState { + + /** + * Gets all the lines of text currently on this sign. + * + * @return Array of Strings containing each line of text + */ + public String[] getLines(); + + /** + * Gets the line of text at the specified index. + * + * For example, getLine(0) will return the first line of text. + * + * @param index Line number to get the text from, starting at 0 + * @throws IndexOutOfBoundsException Thrown when the line does not exist + * @return Text on the given line + */ + public String getLine(int index) throws IndexOutOfBoundsException; + + /** + * Sets the line of text at the specified index. + * + * For example, setLine(0, "Line One") will set the first line of text to + * "Line One". + * + * @param index Line number to set the text at, starting from 0 + * @param line New text to set at the specified index + * @throws IndexOutOfBoundsException + */ + public void setLine(int index, String line) throws IndexOutOfBoundsException; +} diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java new file mode 100644 index 0000000..3a537d5 --- /dev/null +++ b/src/main/java/org/bukkit/command/Command.java @@ -0,0 +1,269 @@ +package org.bukkit.command; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Server; +import org.bukkit.permissions.Permissible; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Represents a Command, which executes various tasks upon user input + */ +public abstract class Command { + private final String name; + private String nextLabel; + private String label; + private List aliases; + private List activeAliases; + private CommandMap commandMap = null; + protected String description = ""; + protected String usageMessage; + private String permission; + private boolean isHidden; + + protected Command(String name) { + this(name, "", "/" + name, new ArrayList()); + } + + protected Command(String name, String description, String usageMessage, List aliases) { + this.name = name; + this.nextLabel = name; + this.label = name; + this.description = description; + this.usageMessage = usageMessage; + this.aliases = aliases; + this.activeAliases = new ArrayList(aliases); + } + + /** + * Executes the command, returning its success + * + * @param sender Source object which is executing this command + * @param commandLabel The alias of the command used + * @param args All arguments passed to the command, split via ' ' + * @return true if the command was successful, otherwise false + */ + public abstract boolean execute(CommandSender sender, String commandLabel, String[] args); + + /** + * Returns the name of this command + * + * @return Name of this command + */ + public String getName() { + return name; + } + + /** + * Gets the permission required by users to be able to perform this command + * + * @return Permission name, or null if none + */ + public String getPermission() { + return permission; + } + + /** + * Sets the permission required by users to be able to perform this command + * + * @param permission Permission name or null + */ + public void setPermission(String permission) { + this.permission = permission; + } + + /** + * Tests the given {@link CommandSender} to see if they can perform this command. + * + * If they do not have permission, they will be informed that they cannot do this. + * + * @param target User to test + * @return true if they can use it, otherwise false + */ + public boolean testPermission(CommandSender target) { + if ((permission == null) || (permission.length() == 0) || (target.hasPermission(permission)) || target.isOp()) { + return true; + } + + target.sendMessage(ChatColor.RED + "I'm sorry, Dave. I'm afraid I can't do that."); + return false; + } + + /** + * Returns the current lable for this command + * + * @return Label of this command or null if not registered + */ + public String getLabel() { + return label; + } + + /** + * Sets the label of this command + * If the command is currently registered the label change will only take effect after + * its been reregistered e.g. after a /reload + * + * @return returns true if the name change happened instantly or false if it was scheduled for reregistration + */ + public boolean setLabel(String name) { + this.nextLabel = name; + if (!isRegistered()) { + this.label = name; + return true; + } + return false; + } + + /** + * Registers this command to a CommandMap + * Once called it only allows changes the registered CommandMap + * + * @param commandMap the CommandMap to register this command to + * @return true if the registration was successful (the current registered CommandMap was the passed CommandMap or null) false otherwise + */ + public boolean register(CommandMap commandMap) { + if (allowChangesFrom(commandMap)) { + this.commandMap = commandMap; + return true; + } + + return false; + } + + /** + * Unregisters this command from the passed CommandMap applying any outstanding changes + * + * @param commandMap the CommandMap to unregister + * @return true if the unregistration was successfull (the current registered CommandMap was the passed CommandMap or null) false otherwise + */ + public boolean unregister(CommandMap commandMap) { + if (allowChangesFrom(commandMap)) { + this.commandMap = null; + this.activeAliases = new ArrayList(this.aliases); + this.label = this.nextLabel; + return true; + } + + return false; + } + + + private boolean allowChangesFrom(CommandMap commandMap) { + return (null == this.commandMap || this.commandMap == commandMap); + } + + /** + * Returns the current registered state of this command + * + * @return true if this command is currently registered false otherwise + */ + public boolean isRegistered() { + return (null != this.commandMap); + } + + /** + * Returns a list of active aliases of this command + * + * @return List of aliases + */ + public List getAliases() { + return activeAliases; + } + + /** + * Gets a brief description of this command + * + * @return Description of this command + */ + public String getDescription() { + return description; + } + + /** + * Gets an example usage of this command + * + * @return One or more example usages + */ + public String getUsage() { + return usageMessage; + } + + /** + * Sets the list of aliases to request on registration for this command + * + * @param aliases Aliases to register to this command + * @return This command object, for linking + */ + public Command setAliases(List aliases) { + this.aliases = aliases; + if (!isRegistered()) { + this.activeAliases = new ArrayList(aliases); + } + return this; + } + + /** + * Sets a brief description of this command + * + * @param description New command description + * @return This command object, for linking + */ + public Command setDescription(String description) { + this.description = description; + return this; + } + + /** + * Sets the example usage of this command + * + * @param usage New example usage + * @return This command object, for linking + */ + public Command setUsage(String usage) { + this.usageMessage = usage; + return this; + } + + public static void broadcastCommandMessage(CommandSender source, String message) { + Set users = Bukkit.getPluginManager().getPermissionSubscriptions(Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + String result = source.getName() + ": " + message; + String colored = ChatColor.GRAY + "(" + result + ")"; + + if (!(source instanceof ConsoleCommandSender)) { + source.sendMessage(message); + } + + for (Permissible user : users) { + if (user instanceof CommandSender) { + CommandSender target = (CommandSender)user; + + if (target instanceof ConsoleCommandSender) { + target.sendMessage(result); + } else if (target != source) { + target.sendMessage(colored); + } + } + } + } + + /** + * Returns the current hide state of this command (Hide from console) + * + * @return True if the current command is hidden and false otherwise + */ + public boolean isHidden() { + return isHidden; + } + + /** + * Sets the current hide state of this command (Hide from console) + * + * @param hidden New hide state of this command + */ + public void setHidden(boolean hidden) { + isHidden = hidden; + } +} diff --git a/src/main/java/org/bukkit/command/CommandException.java b/src/main/java/org/bukkit/command/CommandException.java new file mode 100644 index 0000000..2ea2c6f --- /dev/null +++ b/src/main/java/org/bukkit/command/CommandException.java @@ -0,0 +1,24 @@ +package org.bukkit.command; + +/** + * Thrown when an unhandled exception occurs during the execution of a Command + */ +public class CommandException extends RuntimeException { + + /** + * Creates a new instance of CommandException without detail message. + */ + public CommandException() {} + + /** + * Constructs an instance of CommandException with the specified detail message. + * @param msg the detail message. + */ + public CommandException(String msg) { + super(msg); + } + + public CommandException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/src/main/java/org/bukkit/command/CommandExecutor.java b/src/main/java/org/bukkit/command/CommandExecutor.java new file mode 100644 index 0000000..c75586f --- /dev/null +++ b/src/main/java/org/bukkit/command/CommandExecutor.java @@ -0,0 +1,18 @@ +package org.bukkit.command; + +/** + * Represents a class which contains a single method for executing commands + */ +public interface CommandExecutor { + + /** + * Executes the given command, returning its success + * + * @param sender Source of the command + * @param command Command which was executed + * @param label Alias of the command which was used + * @param args Passed command arguments + * @return true if a valid command, otherwise false + */ + public boolean onCommand(CommandSender sender, Command command, String label, String[] args); +} diff --git a/src/main/java/org/bukkit/command/CommandMap.java b/src/main/java/org/bukkit/command/CommandMap.java new file mode 100644 index 0000000..2b92480 --- /dev/null +++ b/src/main/java/org/bukkit/command/CommandMap.java @@ -0,0 +1,64 @@ +package org.bukkit.command; + +import java.util.List; + +public interface CommandMap { + + /** + * Registers all the commands belonging to a certain plugin. + * Caller can use:- + * command.getName() to determine the label registered for this command + * command.getAliases() to determine the aliases which where registered + * + * @param fallbackPrefix a prefix which is prepended to each command with a ':' one or more times to make the command unique + * @param commands a list of commands to register + */ + public void registerAll(String fallbackPrefix, List commands); + + /** + * Registers a command. Returns true on success; false if name is already taken and fallback had to be used. + * Caller can use:- + * command.getName() to determine the label registered for this command + * command.getAliases() to determine the aliases which where registered + * + * @param label the label of the command, without the '/'-prefix. + * @param fallbackPrefix a prefix which is prepended to the command with a ':' one or more times to make the command unique + * @param command the command to register + * @return true if command was registered with the passed in label, false otherwise, which indicates the fallbackPrefix was used one or more times + */ + public boolean register(String label, String fallbackPrefix, Command command); + + /** + * Registers a command. Returns true on success; false if name is already taken and fallback had to be used. + * Caller can use:- + * command.getName() to determine the label registered for this command + * command.getAliases() to determine the aliases which where registered + * + * @param fallbackPrefix a prefix which is prepended to the command with a ':' one or more times to make the command unique + * @param command the command to register, from which label is determined from the command name + * @return true if command was registered with the passed in label, false otherwise, which indicates the fallbackPrefix was used one or more times + */ + public boolean register(String fallbackPrefix, Command command); + + /** + * Looks for the requested command and executes it if found. + * + * @param cmdLine command + arguments. Example: "/test abc 123" + * @return targetFound returns false if no target is found, true otherwise. + * @throws CommandException Thrown when the executor for the given command fails with an unhandled exception + */ + public boolean dispatch(CommandSender sender, String cmdLine) throws CommandException; + + /** + * Clears all registered commands. + */ + public void clearCommands(); + + /** + * Gets the command registered to the specified name + * + * @param name Name of the command to retrieve + * @return Command with the specified name or null if a command with that label doesn't exist + */ + public Command getCommand(String name); +} diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java new file mode 100644 index 0000000..7bc46c5 --- /dev/null +++ b/src/main/java/org/bukkit/command/CommandSender.java @@ -0,0 +1,28 @@ +package org.bukkit.command; + +import org.bukkit.Server; +import org.bukkit.permissions.Permissible; + +public interface CommandSender extends Permissible { + + /** + * Sends this sender a message + * + * @param message Message to be displayed + */ + public void sendMessage(String message); + + /** + * Returns the server instance that this command is running on + * + * @return Server instance + */ + public Server getServer(); + + /** + * Gets the name of this command sender + * + * @return Name of the sender + */ + public String getName(); +} diff --git a/src/main/java/org/bukkit/command/ConsoleCommandSender.java b/src/main/java/org/bukkit/command/ConsoleCommandSender.java new file mode 100644 index 0000000..7360f9f --- /dev/null +++ b/src/main/java/org/bukkit/command/ConsoleCommandSender.java @@ -0,0 +1,91 @@ +package org.bukkit.command; + +import org.bukkit.ChatColor; +import org.bukkit.Server; +import org.bukkit.permissions.PermissibleBase; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; + +import java.util.Set; + +/** + * Represents CLI input from a console + */ +public class ConsoleCommandSender implements CommandSender { + private final Server server; + private final PermissibleBase perm = new PermissibleBase(this); + + public ConsoleCommandSender(Server server) { + this.server = server; + } + + public void sendMessage(String message) { + System.out.println(ChatColor.stripColor(message)); + } + + public boolean isOp() { + return true; + } + + public void setOp(boolean value) { + throw new UnsupportedOperationException("Cannot change operator status of server console"); + } + + public boolean isPlayer() { + return false; + } + + public Server getServer() { + return server; + } + + public boolean isPermissionSet(String name) { + return perm.isPermissionSet(name); + } + + public boolean isPermissionSet(Permission perm) { + return this.perm.isPermissionSet(perm); + } + + public boolean hasPermission(String name) { + return perm.hasPermission(name); + } + + public boolean hasPermission(Permission perm) { + return this.perm.hasPermission(perm); + } + + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { + return perm.addAttachment(plugin, name, value); + } + + public PermissionAttachment addAttachment(Plugin plugin) { + return perm.addAttachment(plugin); + } + + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { + return perm.addAttachment(plugin, name, value, ticks); + } + + public PermissionAttachment addAttachment(Plugin plugin, int ticks) { + return perm.addAttachment(plugin, ticks); + } + + public void removeAttachment(PermissionAttachment attachment) { + perm.removeAttachment(attachment); + } + + public void recalculatePermissions() { + perm.recalculatePermissions(); + } + + public Set getEffectivePermissions() { + return perm.getEffectivePermissions(); + } + + public String getName() { + return "CONSOLE"; + } +} diff --git a/src/main/java/org/bukkit/command/MultipleCommandAlias.java b/src/main/java/org/bukkit/command/MultipleCommandAlias.java new file mode 100644 index 0000000..e147454 --- /dev/null +++ b/src/main/java/org/bukkit/command/MultipleCommandAlias.java @@ -0,0 +1,25 @@ + +package org.bukkit.command; + +/** + * Represents a command that delegates to one or more other commands + */ +public class MultipleCommandAlias extends Command { + private Command[] commands; + + public MultipleCommandAlias(String name, Command[] commands) { + super(name); + this.commands = commands; + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + boolean result = false; + + for (Command command : commands) { + result |= command.execute(sender, commandLabel, args); + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/command/PluginCommand.java b/src/main/java/org/bukkit/command/PluginCommand.java new file mode 100644 index 0000000..9ef3f7d --- /dev/null +++ b/src/main/java/org/bukkit/command/PluginCommand.java @@ -0,0 +1,79 @@ +package org.bukkit.command; + +import org.bukkit.plugin.Plugin; + +/** + * Represents a {@link Command} belonging to a plugin + */ +public final class PluginCommand extends Command { + private final Plugin owningPlugin; + private CommandExecutor executor; + + protected PluginCommand(String name, Plugin owner) { + super(name); + this.executor = owner; + this.owningPlugin = owner; + this.usageMessage = ""; + } + + /** + * Executes the command, returning its success + * + * @param sender Source object which is executing this command + * @param commandLabel The alias of the command used + * @param args All arguments passed to the command, split via ' ' + * @return true if the command was successful, otherwise false + */ + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + boolean success = false; + + if (!owningPlugin.isEnabled()) { + return false; + } + + if (!testPermission(sender)) { + return true; + } + + try { + success = executor.onCommand(sender, this, commandLabel, args); + } catch (Throwable ex) { + throw new CommandException("Unhandled exception executing command '" + commandLabel + "' in plugin " + owningPlugin.getDescription().getFullName(), ex); + } + + if (!success && usageMessage.length() > 0) { + for (String line: usageMessage.replace("", commandLabel).split("\n")) { + sender.sendMessage(line); + } + } + + return success; + } + + /** + * Sets the {@link CommandExecutor} to run when parsing this command + * + * @param executor New executor to run + */ + public void setExecutor(CommandExecutor executor) { + this.executor = executor; + } + + /** + * Gets the {@link CommandExecutor} associated with this command + * + * @return CommandExecutor object linked to this command + */ + public CommandExecutor getExecutor() { + return executor; + } + + /** + * Gets the owner of this PluginCommand + * + * @return Plugin that owns this command + */ + public Plugin getPlugin() { + return owningPlugin; + } +} diff --git a/src/main/java/org/bukkit/command/PluginCommandYamlParser.java b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java new file mode 100644 index 0000000..76b1eb8 --- /dev/null +++ b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java @@ -0,0 +1,67 @@ +package org.bukkit.command; + +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class PluginCommandYamlParser { + + @SuppressWarnings("unchecked") + public static List parse(Plugin plugin) { + List pluginCmds = new ArrayList(); + Object object = plugin.getDescription().getCommands(); + + if (object == null) { + return pluginCmds; + } + + Map> map = (Map>) object; + + if (map != null) { + for (Entry> entry : map.entrySet()) { + Command newCmd = new PluginCommand(entry.getKey(), plugin); + Object description = entry.getValue().get("description"); + Object usage = entry.getValue().get("usage"); + Object aliases = entry.getValue().get("aliases"); + Object permission = entry.getValue().get("permission"); + Object isHidden = entry.getValue().get("hidden"); + + if(isHidden != null) { + newCmd.setHidden(String.valueOf(isHidden).equalsIgnoreCase("true")); + } + + if (description != null) { + newCmd.setDescription(description.toString()); + } + + if (usage != null) { + newCmd.setUsage(usage.toString()); + } + + if (aliases != null) { + List aliasList = new ArrayList(); + + if (aliases instanceof List) { + for (Object o : (List) aliases) { + aliasList.add(o.toString()); + } + } else { + aliasList.add(aliases.toString()); + } + + newCmd.setAliases(aliasList); + } + + if (permission != null) { + newCmd.setPermission(permission.toString()); + } + + pluginCmds.add(newCmd); + } + } + return pluginCmds; + } +} diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java new file mode 100644 index 0000000..bda84c5 --- /dev/null +++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java @@ -0,0 +1,226 @@ +package org.bukkit.command; + +//Poseidon start +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.commands.PoseidonCommand; +import com.legacyminecraft.poseidon.commands.ResolveCommand; +import com.legacyminecraft.poseidon.commands.TPSCommand; +//Poseidon end +import org.bukkit.Server; +import org.bukkit.command.defaults.*; + +import java.util.*; + +import static org.bukkit.util.Java15Compat.Arrays_copyOfRange; + +public class SimpleCommandMap implements CommandMap { + protected final Map knownCommands = new HashMap(); + protected final Set aliases = new HashSet(); + private final Server server; + protected static final Set fallbackCommands = new HashSet(); + + static { + fallbackCommands.add(new ListCommand()); + fallbackCommands.add(new StopCommand()); + fallbackCommands.add(new SaveCommand()); + fallbackCommands.add(new SaveOnCommand()); + fallbackCommands.add(new SaveOffCommand()); + fallbackCommands.add(new OpCommand()); + fallbackCommands.add(new DeopCommand()); + fallbackCommands.add(new BanIpCommand()); + fallbackCommands.add(new PardonIpCommand()); + fallbackCommands.add(new BanCommand()); + fallbackCommands.add(new PardonCommand()); + fallbackCommands.add(new KickCommand()); + fallbackCommands.add(new TeleportCommand()); + fallbackCommands.add(new GiveCommand()); + fallbackCommands.add(new TimeCommand()); + fallbackCommands.add(new SayCommand()); + fallbackCommands.add(new WhitelistCommand()); + fallbackCommands.add(new TellCommand()); + fallbackCommands.add(new MeCommand()); + fallbackCommands.add(new KillCommand()); + fallbackCommands.add(new HelpCommand()); + } + + public SimpleCommandMap(final Server server) { + this.server = server; + setDefaultCommands(server); + } + + private void setDefaultCommands(final Server server) { + register("bukkit", new VersionCommand("version")); + register("bukkit", new ReloadCommand("reload")); + register("bukkit", new PluginsCommand("plugins")); + + //Poseidon Command Start + register("poseidon", new PoseidonCommand("poseidon")); + if (PoseidonConfig.getInstance().getConfigBoolean("command.tps.enabled")) + register("poseidon", new TPSCommand("tps")); + //Poseidon Command End + } + + /** + * {@inheritDoc} + */ + public void registerAll(String fallbackPrefix, List commands) { + if (commands != null) { + for (Command c : commands) { + register(fallbackPrefix, c); + } + } + } + + /** + * {@inheritDoc} + */ + public boolean register(String fallbackPrefix, Command command) { + return register(command.getName(), fallbackPrefix, command); + } + + /** + * {@inheritDoc} + */ + public boolean register(String label, String fallbackPrefix, Command command) { + boolean registeredPassedLabel = register(label, fallbackPrefix, command, false); + + Iterator iterator = command.getAliases().iterator(); + while (iterator.hasNext()) { + if (!register((String) iterator.next(), fallbackPrefix, command, true)) { + iterator.remove(); + } + } + + // Register to us so further updates of the commands label and aliases are postponed until its reregistered + command.register(this); + + return registeredPassedLabel; + } + + /** + * Registers a command with the given name is possible, otherwise uses fallbackPrefix to create a unique name if its not an alias + * @param name the name of the command, without the '/'-prefix. + * @param fallbackPrefix a prefix which is prepended to the command with a ':' one or more times to make the command unique + * @param command the command to register + * @return true if command was registered with the passed in label, false otherwise. + * If isAlias was true a return of false indicates no command was registerd + * If isAlias was false a return of false indicates the fallbackPrefix was used one or more times to create a unique name for the command + */ + private synchronized boolean register(String label, String fallbackPrefix, Command command, boolean isAlias) { + String lowerLabel = label.trim().toLowerCase(); + + if (isAlias && knownCommands.containsKey(lowerLabel)) { + // Request is for an alias and it conflicts with a existing command or previous alias ignore it + // Note: This will mean it gets removed from the commands list of active aliases + return false; + } + + String lowerPrefix = fallbackPrefix.trim().toLowerCase(); + boolean registerdPassedLabel = true; + + // If the command exists but is an alias we overwrite it, otherwise we rename it based on the fallbackPrefix + while (knownCommands.containsKey(lowerLabel) && !aliases.contains(lowerLabel)) { + lowerLabel = lowerPrefix + ":" + lowerLabel; + registerdPassedLabel = false; + } + + if (isAlias) { + aliases.add(lowerLabel); + } else { + // Ensure lowerLabel isn't listed as a alias anymore and update the commands registered name + aliases.remove(lowerLabel); + command.setLabel(lowerLabel); + } + knownCommands.put(lowerLabel, command); + + return registerdPassedLabel; + } + + protected Command getFallback(String label) { + for (VanillaCommand cmd : fallbackCommands) { + if (cmd.matches(label)) { + return cmd; + } + } + + return null; + } + + /** + * {@inheritDoc} + */ + public boolean dispatch(CommandSender sender, String commandLine) throws CommandException { + String[] args = commandLine.split(" "); + + if (args.length == 0) { + return false; + } + + String sentCommandLabel = args[0].toLowerCase(); + Command target = getCommand(sentCommandLabel); + if (target == null) { + target = getFallback(commandLine.toLowerCase()); + } + if (target == null) { + return false; + } + + try { + // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) + target.execute(sender, sentCommandLabel, Arrays_copyOfRange(args, 1, args.length)); + } catch (CommandException ex) { + throw ex; + } catch (Throwable ex) { + throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex); + } + + // return true as command was handled + return true; + } + + public synchronized void clearCommands() { + for (Map.Entry entry : knownCommands.entrySet()) { + entry.getValue().unregister(this); + } + knownCommands.clear(); + aliases.clear(); + setDefaultCommands(server); + } + + public Command getCommand(String name) { + return knownCommands.get(name.toLowerCase()); + } + + public void registerServerAliases() { + Map values = server.getCommandAliases(); + + for (String alias : values.keySet()) { + String[] targetNames = values.get(alias); + List targets = new ArrayList(); + String bad = ""; + + for (String name : targetNames) { + Command command = getCommand(name); + + if (command == null) { + bad += name + ", "; + } else { + targets.add(command); + } + } + + // We register these as commands so they have absolute priority. + + if (targets.size() > 0) { + knownCommands.put(alias.toLowerCase(), new MultipleCommandAlias(alias.toLowerCase(), targets.toArray(new Command[0]))); + } else { + knownCommands.remove(alias.toLowerCase()); + } + + if (bad.length() > 0) { + bad = bad.substring(0, bad.length() - 2); + server.getLogger().warning("The following command(s) could not be aliased under '" + alias + "' because they do not exist: " + bad); + } + } + } +} diff --git a/src/main/java/org/bukkit/command/defaults/BanCommand.java b/src/main/java/org/bukkit/command/defaults/BanCommand.java new file mode 100644 index 0000000..7d6b0ff --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/BanCommand.java @@ -0,0 +1,34 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class BanCommand extends VanillaCommand { + public BanCommand() { + super("ban"); + this.description = "Prevents the specified player from using this server"; + this.usageMessage = "/ban "; + this.setPermission("bukkit.command.ban.player"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Bukkit.getOfflinePlayer(args[0]).setBanned(true); + Command.broadcastCommandMessage(sender, "Banning " + args[0]); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("ban "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/BanIpCommand.java b/src/main/java/org/bukkit/command/defaults/BanIpCommand.java new file mode 100644 index 0000000..e03a3cb --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/BanIpCommand.java @@ -0,0 +1,34 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class BanIpCommand extends VanillaCommand { + public BanIpCommand() { + super("ban-ip"); + this.description = "Prevents the specified IP address from using this server"; + this.usageMessage = "/ban-ip
"; + this.setPermission("bukkit.command.ban.ip"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Bukkit.banIP(args[0]); + Command.broadcastCommandMessage(sender, "Banning ip " + args[0]); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("ban-ip "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/DeopCommand.java b/src/main/java/org/bukkit/command/defaults/DeopCommand.java new file mode 100644 index 0000000..29b5d95 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/DeopCommand.java @@ -0,0 +1,42 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class DeopCommand extends VanillaCommand { + public DeopCommand() { + super("deop"); + this.description = "Takes the specified player's operator status"; + this.usageMessage = "/deop "; + this.setPermission("bukkit.command.op.take"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Command.broadcastCommandMessage(sender, "De-opping " + args[0]); + + OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]); + player.setOp(false); + + if (player instanceof Player) { + ((Player)player).sendMessage(ChatColor.YELLOW + "You are no longer op!"); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("deop "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/GiveCommand.java b/src/main/java/org/bukkit/command/defaults/GiveCommand.java new file mode 100644 index 0000000..25dbd84 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/GiveCommand.java @@ -0,0 +1,61 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class GiveCommand extends VanillaCommand { + public GiveCommand() { + super("give"); + this.description = "Gives the specified player a certain amount of items"; + this.usageMessage = "/give [amount]"; + this.setPermission("bukkit.command.give"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if ((args.length < 2) || (args.length > 3)) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Player player = Bukkit.getPlayerExact(args[0]); + + if (player != null) { + Material material = Material.matchMaterial(args[1]); + + if (material != null) { + Command.broadcastCommandMessage(sender, "Giving " + player.getName() + " some " + material.getId() + "(" + material + ")"); + + int amount = 1; + + if (args.length >= 3) { + try { + amount = Integer.parseInt(args[2]); + } catch (NumberFormatException ex) {} + + if (amount < 1) amount = 1; + if (amount > 64) amount = 64; + } + + player.getInventory().addItem(new ItemStack(material, amount)); + } else { + sender.sendMessage("There's no item called " + args[1]); + } + } else { + sender.sendMessage("Can't find user " + args[0]); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("give "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/HelpCommand.java b/src/main/java/org/bukkit/command/defaults/HelpCommand.java new file mode 100644 index 0000000..7fd3993 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/HelpCommand.java @@ -0,0 +1,43 @@ +package org.bukkit.command.defaults; + +import org.bukkit.command.CommandSender; + +public class HelpCommand extends VanillaCommand { + public HelpCommand() { + super("help"); + this.description = "Shows the help menu"; + this.usageMessage = "/help"; + this.setPermission("bukkit.command.help"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + sender.sendMessage("help or ? shows this message"); + sender.sendMessage("kick removes a player from the server"); + sender.sendMessage("ban bans a player from the server"); + sender.sendMessage("pardon pardons a banned player so that they can connect again"); + sender.sendMessage("ban-ip bans an IP address from the server"); + sender.sendMessage("pardon-ip pardons a banned IP address so that they can connect again"); + sender.sendMessage("op turns a player into an op"); + sender.sendMessage("deop removes op status from a player"); + sender.sendMessage("tp moves one player to the same location as another player"); + sender.sendMessage("give [num] gives a player a resource"); + sender.sendMessage("tell sends a private message to a player"); + sender.sendMessage("stop gracefully stops the server"); + sender.sendMessage("save-all forces a server-wide level save"); + sender.sendMessage("save-off disables terrain saving (useful for backup scripts)"); + sender.sendMessage("save-on re-enables terrain saving"); + sender.sendMessage("list lists all currently connected players"); + sender.sendMessage("say broadcasts a message to all players"); + sender.sendMessage("time adds to or sets the world time (0-24000)"); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("help") || input.startsWith("?"); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/KickCommand.java b/src/main/java/org/bukkit/command/defaults/KickCommand.java new file mode 100644 index 0000000..e3b5a08 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/KickCommand.java @@ -0,0 +1,41 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class KickCommand extends VanillaCommand { + public KickCommand() { + super("kick"); + this.description = "Removes the specified player from the server"; + this.usageMessage = "/kick "; + this.setPermission("bukkit.command.kick"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length < 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Player player = Bukkit.getPlayerExact(args[0]); + + if (player != null) { + Command.broadcastCommandMessage(sender, "Kicking " + player.getName()); + player.kickPlayer("Kicked by admin"); + } else { + sender.sendMessage("Can't find user " + args[0] + ". No kick."); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("kick "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/KillCommand.java b/src/main/java/org/bukkit/command/defaults/KillCommand.java new file mode 100644 index 0000000..e6c2fa1 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/KillCommand.java @@ -0,0 +1,39 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent; + +public class KillCommand extends VanillaCommand { + public KillCommand() { + super("kill"); + this.description = "Commits suicide, only usable as a player"; + this.usageMessage = "/kill"; + this.setPermission("bukkit.command.kill"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + if (sender instanceof Player) { + Player player = (Player)sender; + + EntityDamageEvent ede = new EntityDamageEvent(player, EntityDamageEvent.DamageCause.SUICIDE, 1000); + Bukkit.getPluginManager().callEvent(ede); + if (ede.isCancelled()) return true; + + player.damage(ede.getDamage()); + } else { + sender.sendMessage("You can only perform this command as a player"); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("kill"); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/ListCommand.java b/src/main/java/org/bukkit/command/defaults/ListCommand.java new file mode 100644 index 0000000..b40ceba --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/ListCommand.java @@ -0,0 +1,42 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class ListCommand extends VanillaCommand { + public ListCommand() { + super("list"); + this.description = "Lists all online players"; + this.usageMessage = "/list"; + this.setPermission("bukkit.command.list"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + String players = ""; + + for (Player player : Bukkit.getOnlinePlayers()) { + // If a player is hidden from the sender don't show them in the list + if (sender instanceof Player && !((Player) sender).canSee(player)) + continue; + + if (players.length() > 0) { + players += ", "; + } + + players += player.getDisplayName(); + } + + sender.sendMessage("Connected players: " + players); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("list"); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/MeCommand.java b/src/main/java/org/bukkit/command/defaults/MeCommand.java new file mode 100644 index 0000000..8c07941 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/MeCommand.java @@ -0,0 +1,39 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +public class MeCommand extends VanillaCommand { + public MeCommand() { + super("me"); + this.description = "Performs the specified action in chat"; + this.usageMessage = "/me "; + this.setPermission("bukkit.command.me"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length < 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + String message = ""; + + for (int i = 0; i < args.length; i++) { + if (i > 0) message += " "; + message += args[i]; + } + + Bukkit.broadcastMessage("* " + sender.getName() + " " + message); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("me "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/OpCommand.java b/src/main/java/org/bukkit/command/defaults/OpCommand.java new file mode 100644 index 0000000..36ee25a --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/OpCommand.java @@ -0,0 +1,42 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class OpCommand extends VanillaCommand { + public OpCommand() { + super("op"); + this.description = "Gives the specified player operator status"; + this.usageMessage = "/op "; + this.setPermission("bukkit.command.op.give"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Command.broadcastCommandMessage(sender, "Oping " + args[0]); + + OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]); + player.setOp(true); + + if (player instanceof Player) { + ((Player)player).sendMessage(ChatColor.YELLOW + "You are now op!"); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("op "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/PardonCommand.java b/src/main/java/org/bukkit/command/defaults/PardonCommand.java new file mode 100644 index 0000000..866cccf --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/PardonCommand.java @@ -0,0 +1,34 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class PardonCommand extends VanillaCommand { + public PardonCommand() { + super("pardon"); + this.description = "Allows the specified player to use this server"; + this.usageMessage = "/pardon "; + this.setPermission("bukkit.command.unban.player"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Bukkit.getOfflinePlayer(args[0]).setBanned(false); + Command.broadcastCommandMessage(sender, "Pardoning " + args[0]); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("pardon "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java b/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java new file mode 100644 index 0000000..83bd2cc --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java @@ -0,0 +1,34 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class PardonIpCommand extends VanillaCommand { + public PardonIpCommand() { + super("pardon-ip"); + this.description = "Allows the specified IP address to use this server"; + this.usageMessage = "/pardon-ip
"; + this.setPermission("bukkit.command.unban.ip"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Bukkit.unbanIP(args[0]); + Command.broadcastCommandMessage(sender, "Pardoning ip " + args[0]); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("pardon-ip "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java new file mode 100644 index 0000000..74c6075 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java @@ -0,0 +1,56 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; + +import java.util.Arrays; +import java.util.Comparator; + +public class PluginsCommand extends Command { + public PluginsCommand(String name) { + super(name); + this.description = "Gets a list of plugins running on the server"; + this.usageMessage = "/plugins"; + this.setPermission("bukkit.command.plugins"); + this.setAliases(Arrays.asList("pl")); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + sender.sendMessage("Plugins" + getPluginList()); + return true; + } + + private String getPluginList() { + StringBuilder pluginList = new StringBuilder(); + Plugin[] plugins = Bukkit.getPluginManager().getPlugins(); + int enabled = 0; + int pluginCount = 0; + + Arrays.sort(plugins, Comparator.comparing(o -> o.getDescription().getFullName())); + + for (Plugin plugin : plugins) { + if (!plugin.getDescription().isVisible() && plugin.isEnabled()) { + continue; + } + pluginCount = pluginCount + 1; + + if (pluginList.length() > 0) { + pluginList.append(ChatColor.WHITE); + pluginList.append(", "); + } + + pluginList.append(plugin.isEnabled() ? ChatColor.GREEN : ChatColor.RED); + if (plugin.isEnabled()) + enabled++; + pluginList.append(plugin.getDescription().getName()); + } + + return " (" + enabled + "/" + pluginCount + "): " + pluginList.toString(); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java new file mode 100644 index 0000000..52e696d --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java @@ -0,0 +1,28 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +import java.util.Arrays; + +public class ReloadCommand extends Command { + public ReloadCommand(String name) { + super(name); + this.description = "Reloads the server configuration and plugins"; + this.usageMessage = "/reload"; + this.setPermission("bukkit.command.reload"); + this.setAliases(Arrays.asList("rl")); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + Bukkit.reload(); + sender.sendMessage(ChatColor.GREEN + "Reload complete."); + + return true; + } +} diff --git a/src/main/java/org/bukkit/command/defaults/SaveCommand.java b/src/main/java/org/bukkit/command/defaults/SaveCommand.java new file mode 100644 index 0000000..d73983d --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/SaveCommand.java @@ -0,0 +1,37 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class SaveCommand extends VanillaCommand { + public SaveCommand() { + super("save-all"); + this.description = "Saves the server to disk"; + this.usageMessage = "/save-all"; + this.setPermission("bukkit.command.save.perform"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + Command.broadcastCommandMessage(sender, "Forcing save.."); + + Bukkit.savePlayers(); + + for (World world : Bukkit.getWorlds()) { + world.save(); + } + + Command.broadcastCommandMessage(sender, "Save complete."); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("save-all"); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java b/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java new file mode 100644 index 0000000..67f9b40 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java @@ -0,0 +1,33 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class SaveOffCommand extends VanillaCommand { + public SaveOffCommand() { + super("save-off"); + this.description = "Disables server autosaving"; + this.usageMessage = "/save-off"; + this.setPermission("bukkit.command.save.disable"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + Command.broadcastCommandMessage(sender, "Disabling level saving.."); + + for (World world : Bukkit.getWorlds()) { + world.setAutoSave(false); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("save-off"); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java b/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java new file mode 100644 index 0000000..84be37f --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java @@ -0,0 +1,33 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class SaveOnCommand extends VanillaCommand { + public SaveOnCommand() { + super("save-on"); + this.description = "Enables server autosaving"; + this.usageMessage = "/save-on"; + this.setPermission("bukkit.command.save.enable"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + Command.broadcastCommandMessage(sender, "Enabling level saving.."); + + for (World world : Bukkit.getWorlds()) { + world.setAutoSave(true); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("save-on"); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/SayCommand.java b/src/main/java/org/bukkit/command/defaults/SayCommand.java new file mode 100644 index 0000000..52f3a2e --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/SayCommand.java @@ -0,0 +1,51 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; + +public class SayCommand extends VanillaCommand { + public SayCommand() { + super("say"); + this.description = "Broadcasts the given message as the console"; + this.usageMessage = "/say "; + this.setPermission("bukkit.command.say"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + try { + if (!testPermission(sender)) return true; + if (args.length == 0) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + String message = ""; + + for (int i = 0; i < args.length; i++) { + if (i > 0) message += " "; + message += args[i]; + } + + if (!(sender instanceof ConsoleCommandSender)) { + Bukkit.getLogger().info("[" + sender.getName() + "] " + message); + } + + Bukkit.broadcastMessage(ChatColor.LIGHT_PURPLE + "[Server] " + message); + + return true; + } catch (Exception e) { + System.out.println("Exception occured: " + e.getMessage()); + sender.sendMessage(ChatColor.RED + "Please read console for an error message"); + return true; + } + + } + + @Override + public boolean matches(String input) { + return input.startsWith("say "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/StopCommand.java b/src/main/java/org/bukkit/command/defaults/StopCommand.java new file mode 100644 index 0000000..491635b --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/StopCommand.java @@ -0,0 +1,50 @@ +package org.bukkit.command.defaults; + +import com.legacyminecraft.poseidon.PoseidonPlugin; +import com.legacyminecraft.poseidon.PoseidonConfig; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Player; + +public class StopCommand extends VanillaCommand { + private final String msgKickShutdown; + + public StopCommand() { + super("stop"); + this.description = "Stops the server"; + this.usageMessage = "/stop"; + this.setPermission("bukkit.command.stop"); + this.msgKickShutdown = PoseidonConfig.getInstance().getConfigString("message.kick.shutdown"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + Command.broadcastCommandMessage(sender, "Starting Server Shutdown, Saving Data."); + + ((CraftServer) Bukkit.getServer()).setShuttingdown(true); + for (Player player : Bukkit.getOnlinePlayers()) { + player.saveData(); + player.kickPlayer(this.msgKickShutdown); + } + for (World world : Bukkit.getWorlds()) { + world.save(); + } + Bukkit.getScheduler().scheduleSyncDelayedTask(new PoseidonPlugin(), () -> { + Command.broadcastCommandMessage(sender, "Stopping the server.."); + Bukkit.shutdown(); + }, 100); + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("stop"); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/TeleportCommand.java b/src/main/java/org/bukkit/command/defaults/TeleportCommand.java new file mode 100644 index 0000000..aa2321f --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/TeleportCommand.java @@ -0,0 +1,44 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class TeleportCommand extends VanillaCommand { + public TeleportCommand() { + super("tp"); + this.description = "Teleports the given player to another player"; + this.usageMessage = "/tp "; + this.setPermission("bukkit.command.teleport"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Player victim = Bukkit.getPlayerExact(args[0]); + Player target = Bukkit.getPlayerExact(args[1]); + + if (victim == null) { + sender.sendMessage("Can't find user " + args[0] + ". No tp."); + } else if (target == null) { + sender.sendMessage("Can't find user " + args[1] + ". No tp."); + } else { + Command.broadcastCommandMessage(sender, "Teleporting " + victim.getName() + " to " + target.getName()); + victim.teleport(target); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("tp "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/TellCommand.java b/src/main/java/org/bukkit/command/defaults/TellCommand.java new file mode 100644 index 0000000..c913912 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/TellCommand.java @@ -0,0 +1,54 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; + +public class TellCommand extends VanillaCommand { + public TellCommand() { + super("tell"); + this.description = "Sends a private message to the given player"; + this.usageMessage = "/tell "; + this.setPermission("bukkit.command.tell"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + if (args.length < 2) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + Player player = Bukkit.getPlayerExact(args[0]); + + if (player == null || (sender instanceof Player && !((Player) sender).canSee(player))) { + sender.sendMessage("There's no player by that name online."); + } else { + String message = ""; + + for (int i = 1; i < args.length; i++) { + if (i > 1) message += " "; + message += args[i]; + } + + String result = ChatColor.GRAY + sender.getName() + " whispers " + message; + + if (sender instanceof ConsoleCommandSender) { + Bukkit.getLogger().info("[" + sender.getName() + "->" + player.getName() + "] " + message); + Bukkit.getLogger().info(result); + } + + player.sendMessage(result); + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("tell "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/TimeCommand.java b/src/main/java/org/bukkit/command/defaults/TimeCommand.java new file mode 100644 index 0000000..63f67ba --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/TimeCommand.java @@ -0,0 +1,64 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class TimeCommand extends VanillaCommand { + public TimeCommand() { + super("time"); + this.description = "Changes the time on each world"; + this.usageMessage = "/time set \n/time add "; + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Incorrect usage. Correct usage:\n" + usageMessage); + return false; + } + + int value = 0; + + try { + value = Integer.parseInt(args[1]); + } catch (NumberFormatException ex) { + sender.sendMessage("Unable to convert time value, " + args[1]); + return true; + } + + if (args[0].equalsIgnoreCase("add")) { + if (!sender.hasPermission("bukkit.command.time.add")) { + sender.sendMessage(ChatColor.RED + "You don't have permission to add to the time"); + } else { + for (World world : Bukkit.getWorlds()) { + world.setFullTime(world.getFullTime() + value); + } + + Command.broadcastCommandMessage(sender, "Added " + value + " to time"); + } + } else if (args[0].equalsIgnoreCase("set")) { + if (!sender.hasPermission("bukkit.command.time.set")) { + sender.sendMessage(ChatColor.RED + "You don't have permission to set the time"); + } else { + for (World world : Bukkit.getWorlds()) { + world.setTime(value); + } + + Command.broadcastCommandMessage(sender, "Set time to " + value); + } + } else { + sender.sendMessage("Unknown method, use either \"add\" or \"set\""); + return true; + } + + return true; + } + + @Override + public boolean matches(String input) { + return input.startsWith("time "); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/VanillaCommand.java b/src/main/java/org/bukkit/command/defaults/VanillaCommand.java new file mode 100644 index 0000000..b00dbfa --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/VanillaCommand.java @@ -0,0 +1,17 @@ +package org.bukkit.command.defaults; + +import org.bukkit.command.Command; + +import java.util.List; + +public abstract class VanillaCommand extends Command { + protected VanillaCommand(String name) { + super(name); + } + + protected VanillaCommand(String name, String description, String usageMessage, List aliases) { + super(name, description, usageMessage, aliases); + } + + public abstract boolean matches(String input); +} diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java new file mode 100644 index 0000000..795ba62 --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java @@ -0,0 +1,91 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; + +import java.util.ArrayList; +import java.util.Arrays; + +public class VersionCommand extends Command { + public VersionCommand(String name) { + super(name); + + this.description = "Gets the version of this server including any plugins in use"; + this.usageMessage = "/version [plugin name]"; + this.setPermission("bukkit.command.version"); + this.setAliases(Arrays.asList("ver", "about")); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + if (args.length == 0) { + sender.sendMessage(ChatColor.GRAY + "This server is running " + ChatColor.AQUA + Bukkit.getName()); + sender.sendMessage(ChatColor.GRAY + "Version: " + ChatColor.RED + Bukkit.getVersion()); + } else { + StringBuilder name = new StringBuilder(); + + for (String arg : args) { + if (name.length() > 0) { + name.append(' '); + } + + name.append(arg); + } + + Plugin plugin = Bukkit.getPluginManager().getPlugin(name.toString()); + + if (plugin != null) { + PluginDescriptionFile desc = plugin.getDescription(); + sender.sendMessage(ChatColor.GREEN + desc.getName() + ChatColor.WHITE + " version " + ChatColor.GREEN + desc.getVersion()); + + if (desc.getDescription() != null) { + sender.sendMessage(desc.getDescription()); + } + + if (desc.getWebsite() != null) { + sender.sendMessage("Website: " + ChatColor.GREEN + desc.getWebsite()); + } + + if (!desc.getAuthors().isEmpty()) { + if (desc.getAuthors().size() == 1) { + sender.sendMessage("Author: " + getAuthors(desc)); + } else { + sender.sendMessage("Authors: " + getAuthors(desc)); + } + } + } else { + sender.sendMessage("This server is not running any plugin by that name."); + sender.sendMessage("Use /plugins to get a list of plugins."); + } + } + return true; + } + + private String getAuthors(final PluginDescriptionFile desc) { + StringBuilder result = new StringBuilder(); + ArrayList authors = desc.getAuthors(); + + for (int i = 0; i < authors.size(); i++) { + if (result.length() > 0) { + result.append(ChatColor.WHITE); + + if (i < authors.size() - 1) { + result.append(", "); + } else { + result.append(" and "); + } + } + + result.append(ChatColor.GREEN); + result.append(authors.get(i)); + } + + return result.toString(); + } +} diff --git a/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java b/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java new file mode 100644 index 0000000..749ccdf --- /dev/null +++ b/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java @@ -0,0 +1,90 @@ +package org.bukkit.command.defaults; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class WhitelistCommand extends VanillaCommand { + public WhitelistCommand() { + super("whitelist"); + this.description = "Prevents the specified player from using this server"; + this.usageMessage = "/whitelist (add|remove) \n/whitelist (on|off|list|reload)"; + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + if (args.length == 1) { + if (args[0].equalsIgnoreCase("reload")) { + if (badPerm(sender, "reload")) return true; + + Bukkit.reloadWhitelist(); + Command.broadcastCommandMessage(sender, "Reloaded white-list from file"); + return true; + } else if (args[0].equalsIgnoreCase("on")) { + if (badPerm(sender, "enable")) return true; + + Bukkit.setWhitelist(true); + Command.broadcastCommandMessage(sender, "Turned on white-listing"); + return true; + } else if (args[0].equalsIgnoreCase("off")) { + if (badPerm(sender, "disable")) return true; + + Bukkit.setWhitelist(false); + Command.broadcastCommandMessage(sender, "Turned off white-listing"); + return true; + } else if (args[0].equalsIgnoreCase("list")) { + if (badPerm(sender, "list")) return true; + + String result = ""; + + for (OfflinePlayer player : Bukkit.getWhitelistedPlayers()) { + if (result.length() > 0) { + result += " "; + } + + result += player.getName(); + } + + sender.sendMessage("White-listed players: " + result); + return true; + } + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("add")) { + if (badPerm(sender, "add")) return true; + + Bukkit.getOfflinePlayer(args[1]).setWhitelisted(true); + + Command.broadcastCommandMessage(sender, "Added " + args[1] + " to white-list"); + return true; + } else if (args[0].equalsIgnoreCase("remove")) { + if (badPerm(sender, "remove")) return true; + + Bukkit.getOfflinePlayer(args[1]).setWhitelisted(false); + + Command.broadcastCommandMessage(sender, "Removed " + args[1] + " from white-list"); + return true; + } + } + + sender.sendMessage(ChatColor.RED + "Correct command usage:\n" + usageMessage); + return false; + } + + private boolean badPerm(CommandSender sender, String perm) { + if (!sender.hasPermission("bukkit.command.whitelist." + perm)) { + sender.sendMessage(ChatColor.RED + "You do not have permission to perform this action."); + return true; + } + + return false; + } + + @Override + public boolean matches(String input) { + return input.startsWith("whitelist "); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/ChunkCompressionThread.java b/src/main/java/org/bukkit/craftbukkit/ChunkCompressionThread.java new file mode 100644 index 0000000..c7d2fcc --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/ChunkCompressionThread.java @@ -0,0 +1,140 @@ +package org.bukkit.craftbukkit; + +import net.minecraft.server.EntityPlayer; +import net.minecraft.server.Packet; +import net.minecraft.server.Packet51MapChunk; + +import java.util.HashMap; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.zip.Deflater; + +public final class ChunkCompressionThread implements Runnable { + + private static final ChunkCompressionThread instance = new ChunkCompressionThread(); + private static boolean isRunning = false; + + private final int QUEUE_CAPACITY = 1024 * 10; + private final HashMap queueSizePerPlayer = new HashMap(); + private final BlockingQueue packetQueue = new LinkedBlockingQueue(QUEUE_CAPACITY); + + private final int CHUNK_SIZE = 16 * 128 * 16 * 5 / 2; + private final int REDUCED_DEFLATE_THRESHOLD = CHUNK_SIZE / 4; + private final int DEFLATE_LEVEL_CHUNKS = 6; + private final int DEFLATE_LEVEL_PARTS = 1; + + private final Deflater deflater = new Deflater(); + private byte[] deflateBuffer = new byte[CHUNK_SIZE + 100]; + + public static void startThread() { + if (!isRunning) { + isRunning = true; + new Thread(instance).start(); + } + } + + public void run() { + while (true) { + try { + handleQueuedPacket(packetQueue.take()); + } catch (InterruptedException ie) { + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void handleQueuedPacket(QueuedPacket queuedPacket) { + addToPlayerQueueSize(queuedPacket.player, -1); + // Compress the packet if necessary. + if (queuedPacket.compress) { + handleMapChunk(queuedPacket); + } + sendToNetworkQueue(queuedPacket); + } + + private void handleMapChunk(QueuedPacket queuedPacket) { + Packet51MapChunk packet = (Packet51MapChunk) queuedPacket.packet; + + // If 'packet.g' is set then this packet has already been compressed. + if (packet.g != null) { + return; + } + + int dataSize = packet.rawData.length; + if (deflateBuffer.length < dataSize + 100) { + deflateBuffer = new byte[dataSize + 100]; + } + + deflater.reset(); + deflater.setLevel(dataSize < REDUCED_DEFLATE_THRESHOLD ? DEFLATE_LEVEL_PARTS : DEFLATE_LEVEL_CHUNKS); + deflater.setInput(packet.rawData); + deflater.finish(); + int size = deflater.deflate(deflateBuffer); + if (size == 0) { + size = deflater.deflate(deflateBuffer); + } + + // copy compressed data to packet + packet.g = new byte[size]; + packet.h = size; + System.arraycopy(deflateBuffer, 0, packet.g, 0, size); + } + + private void sendToNetworkQueue(QueuedPacket queuedPacket) { + queuedPacket.player.netServerHandler.networkManager.queue(queuedPacket.packet); + } + + public static void sendPacket(EntityPlayer player, Packet packet) { + if (packet instanceof Packet51MapChunk) { + // MapChunk Packets need compressing. + instance.addQueuedPacket(new QueuedPacket(player, packet, true)); + } else { + // Other Packets don't. + instance.addQueuedPacket(new QueuedPacket(player, packet, false)); + } + } + + private void addToPlayerQueueSize(EntityPlayer player, int amount) { + synchronized (queueSizePerPlayer) { + Integer count = queueSizePerPlayer.get(player); + amount += (count == null) ? 0 : count; + if (amount == 0) { + queueSizePerPlayer.remove(player); + } else { + queueSizePerPlayer.put(player, amount); + } + } + } + + public static int getPlayerQueueSize(EntityPlayer player) { + synchronized (instance.queueSizePerPlayer) { + Integer count = instance.queueSizePerPlayer.get(player); + return count == null ? 0 : count; + } + } + + private void addQueuedPacket(QueuedPacket task) { + addToPlayerQueueSize(task.player, +1); + + while (true) { + try { + packetQueue.put(task); + return; + } catch (InterruptedException e) { + } + } + } + + private static class QueuedPacket { + final EntityPlayer player; + final Packet packet; + final boolean compress; + + QueuedPacket(EntityPlayer player, Packet packet, boolean compress) { + this.player = player; + this.packet = packet; + this.compress = compress; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java new file mode 100644 index 0000000..30015ab --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -0,0 +1,226 @@ +package org.bukkit.craftbukkit; + +import com.google.common.collect.MapMaker; +import net.minecraft.server.BiomeBase; +import net.minecraft.server.ChunkPosition; +import net.minecraft.server.WorldChunkManager; +import net.minecraft.server.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.entity.Entity; + +import java.lang.ref.WeakReference; +import java.util.concurrent.ConcurrentMap; + +public class CraftChunk implements Chunk { + private WeakReference weakChunk; + private final ConcurrentMap cache = new MapMaker().softValues().makeMap(); + private WorldServer worldServer; + private int x; + private int z; + + public CraftChunk(net.minecraft.server.Chunk chunk) { + this.weakChunk = new WeakReference(chunk); + worldServer = (WorldServer) getHandle().world; + x = getHandle().x; + z = getHandle().z; + } + + public World getWorld() { + return worldServer.getWorld(); + } + + public net.minecraft.server.Chunk getHandle() { + net.minecraft.server.Chunk c = weakChunk.get(); + if (c == null) { + c = worldServer.getChunkAt(x, z); + weakChunk = new WeakReference(c); + } + return c; + } + + void breakLink() { + weakChunk.clear(); + } + + public int getX() { + return x; + } + + public int getZ() { + return z; + } + + @Override + public String toString() { + return "CraftChunk{" + "x=" + getX() + "z=" + getZ() + '}'; + } + + public Block getBlock(int x, int y, int z) { + int pos = (x & 0xF) << 11 | (z & 0xF) << 7 | (y & 0x7F); + Block block = this.cache.get(pos); + if (block == null) { + Block newBlock = new CraftBlock(this, (getX() << 4) | (x & 0xF), y & 0x7F, (getZ() << 4) | (z & 0xF)); + Block oldBlock = this.cache.put(pos, newBlock); + if (oldBlock == null) { + block = newBlock; + } else { + block = oldBlock; + } + } + return block; + } + + public Entity[] getEntities() { + int count = 0, index = 0; + net.minecraft.server.Chunk chunk = getHandle(); + for (int i = 0; i < 8; i++) { + count += chunk.entitySlices[i].size(); + } + + Entity[] entities = new Entity[count]; + for (int i = 0; i < 8; i++) { + for (Object obj: chunk.entitySlices[i].toArray()) { + if (!(obj instanceof net.minecraft.server.Entity)) { + continue; + } + entities[index++] = ((net.minecraft.server.Entity) obj).getBukkitEntity(); + } + } + return entities; + } + + public BlockState[] getTileEntities() { + int index = 0; + net.minecraft.server.Chunk chunk = getHandle(); + BlockState[] entities = new BlockState[chunk.tileEntities.size()]; + for (Object obj : chunk.tileEntities.keySet().toArray()) { + if (!(obj instanceof ChunkPosition)) { + continue; + } + ChunkPosition position = (ChunkPosition) obj; + entities[index++] = worldServer.getWorld().getBlockAt(position.x + (chunk.x << 4), position.y, position.z + (chunk.z << 4)).getState(); + } + return entities; + } + + public boolean isLoaded() { + return getWorld().isChunkLoaded(this); + } + + public boolean load() { + return getWorld().loadChunk(getX(), getZ(), true); + } + + public boolean load(boolean generate) { + return getWorld().loadChunk(getX(), getZ(), generate); + } + + public boolean unload() { + return getWorld().unloadChunk(getX(), getZ()); + } + + public boolean unload(boolean save) { + return getWorld().unloadChunk(getX(), getZ(), save); + } + + public boolean unload(boolean save, boolean safe) { + return getWorld().unloadChunk(getX(), getZ(), save, safe); + } + + public ChunkSnapshot getChunkSnapshot() { + return getChunkSnapshot(true, false, false); + } + + public ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain) { + net.minecraft.server.Chunk chunk = getHandle(); + byte[] buf = new byte[32768 + 16384 + 16384 + 16384]; // Get big enough buffer for whole chunk + chunk.getData(buf, 0, 0, 0, 16, 128, 16, 0); // Get whole chunk + byte[] hmap = null; + + if (includeMaxblocky) { + hmap = new byte[256]; // Get copy of height map + System.arraycopy(chunk.heightMap, 0, hmap, 0, 256); + } + + BiomeBase[] biome = null; + double[] biomeTemp = null; + double[] biomeRain = null; + + if (includeBiome || includeBiomeTempRain) { + WorldChunkManager wcm = chunk.world.getWorldChunkManager(); + BiomeBase[] biomeBase = wcm.getBiomeData(getX() << 4, getZ() << 4, 16, 16); + + if (includeBiome) { + biome = new BiomeBase[256]; + System.arraycopy(biomeBase, 0, biome, 0, biome.length); + } + + if (includeBiomeTempRain) { + biomeTemp = new double[256]; + biomeRain = new double[256]; + System.arraycopy(wcm.temperature, 0, biomeTemp, 0, biomeTemp.length); + System.arraycopy(wcm.rain, 0, biomeRain, 0, biomeRain.length); + } + } + World world = getWorld(); + return new CraftChunkSnapshot(getX(), getZ(), world.getName(), world.getFullTime(), buf, hmap, biome, biomeTemp, biomeRain); + } + + /** + * Empty chunk snapshot - nothing but air blocks, but can include valid biome data + */ + private static class EmptyChunkSnapshot extends CraftChunkSnapshot { + EmptyChunkSnapshot(int x, int z, String worldName, long time, BiomeBase[] biome, double[] biomeTemp, double[] biomeRain) { + super(x, z, worldName, time, null, null, biome, biomeTemp, biomeRain); + } + + public final int getBlockTypeId(int x, int y, int z) { + return 0; + } + + public final int getBlockData(int x, int y, int z) { + return 0; + } + + public final int getBlockSkyLight(int x, int y, int z) { + return 15; + } + + public final int getBlockEmittedLight(int x, int y, int z) { + return 0; + } + + public final int getHighestBlockYAt(int x, int z) { + return 0; + } + } + + public static ChunkSnapshot getEmptyChunkSnapshot(int x, int z, CraftWorld world, boolean includeBiome, boolean includeBiomeTempRain) { + BiomeBase[] biome = null; + double[] biomeTemp = null; + double[] biomeRain = null; + + if (includeBiome || includeBiomeTempRain) { + WorldChunkManager wcm = world.getHandle().getWorldChunkManager(); + BiomeBase[] biomeBase = wcm.getBiomeData(x << 4, z << 4, 16, 16); + + if (includeBiome) { + biome = new BiomeBase[256]; + System.arraycopy(biomeBase, 0, biome, 0, biome.length); + } + + if (includeBiomeTempRain) { + biomeTemp = new double[256]; + biomeRain = new double[256]; + System.arraycopy(wcm.temperature, 0, biomeTemp, 0, biomeTemp.length); + System.arraycopy(wcm.rain, 0, biomeRain, 0, biomeRain.length); + } + } + return new EmptyChunkSnapshot(x, z, world.getName(), world.getFullTime(), biome, biomeTemp, biomeRain); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java new file mode 100644 index 0000000..cd0f938 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java @@ -0,0 +1,172 @@ +package org.bukkit.craftbukkit; + +import net.minecraft.server.BiomeBase; +import org.bukkit.ChunkSnapshot; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.block.CraftBlock; +/** + * Represents a static, thread-safe snapshot of chunk of blocks + * Purpose is to allow clean, efficient copy of a chunk data to be made, and then handed off for processing in another thread (e.g. map rendering) + */ +public class CraftChunkSnapshot implements ChunkSnapshot { + private final int x, z; + private final String worldname; + private final byte[] buf; // Flat buffer in uncompressed chunk file format + private final byte[] hmap; // Height map + private final long captureFulltime; + private final BiomeBase[] biome; + private final double[] biomeTemp; + private final double[] biomeRain; + + private static final int BLOCKDATA_OFF = 32768; + private static final int BLOCKLIGHT_OFF = BLOCKDATA_OFF + 16384; + private static final int SKYLIGHT_OFF = BLOCKLIGHT_OFF + 16384; + + /** + * Constructor + */ + CraftChunkSnapshot(int x, int z, String wname, long wtime, byte[] buf, byte[] hmap, BiomeBase[] biome, double[] biomeTemp, double[] biomeRain) { + this.x = x; + this.z = z; + this.worldname = wname; + this.captureFulltime = wtime; + this.buf = buf; + this.hmap = hmap; + this.biome = biome; + this.biomeTemp = biomeTemp; + this.biomeRain = biomeRain; + } + + /** + * Gets the X-coordinate of this chunk + * + * @return X-coordinate + */ + public int getX() { + return x; + } + + /** + * Gets the Z-coordinate of this chunk + * + * @return Z-coordinate + */ + public int getZ() { + return z; + } + + /** + * Gets name of the world containing this chunk + * + * @return Parent World Name + */ + public String getWorldName() { + return worldname; + } + + /** + * Get block type for block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-255 + */ + public int getBlockTypeId(int x, int y, int z) { + return buf[x << 11 | z << 7 | y] & 255; + } + + /** + * Get block data for block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-15 + */ + public int getBlockData(int x, int y, int z) { + int off = ((x << 10) | (z << 6) | (y >> 1)) + BLOCKDATA_OFF; + + return ((y & 1) == 0) ? (buf[off] & 0xF) : ((buf[off] >> 4) & 0xF); + } + + /** + * Get sky light level for block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-15 + */ + public int getBlockSkyLight(int x, int y, int z) { + int off = ((x << 10) | (z << 6) | (y >> 1)) + SKYLIGHT_OFF; + + return ((y & 1) == 0) ? (buf[off] & 0xF) : ((buf[off] >> 4) & 0xF); + } + + /** + * Get light level emitted by block at corresponding coordinate in the chunk + * + * @param x 0-15 + * @param y 0-127 + * @param z 0-15 + * @return 0-15 + */ + public int getBlockEmittedLight(int x, int y, int z) { + int off = ((x << 10) | (z << 6) | (y >> 1)) + BLOCKLIGHT_OFF; + + return ((y & 1) == 0) ? (buf[off] & 0xF) : ((buf[off] >> 4) & 0xF); + } + + /** + * Gets the highest non-air coordinate at the given coordinates + * + * @param x X-coordinate of the blocks + * @param z Z-coordinate of the blocks + * @return Y-coordinate of the highest non-air block + */ + public int getHighestBlockYAt(int x, int z) { + return hmap[z << 4 | x] & 255; + } + + /** + * Get biome at given coordinates + * + * @param x X-coordinate + * @param z Z-coordinate + * @return Biome at given coordinate + */ + public Biome getBiome(int x, int z) { + return CraftBlock.biomeBaseToBiome(biome[x << 4 | z]); + } + + /** + * Get raw biome temperature (0.0-1.0) at given coordinate + * + * @param x X-coordinate + * @param z Z-coordinate + * @return temperature at given coordinate + */ + public double getRawBiomeTemperature(int x, int z) { + return biomeTemp[x << 4 | z]; + } + + /** + * Get raw biome rainfall (0.0-1.0) at given coordinate + * + * @param x X-coordinate + * @param z Z-coordinate + * @return rainfall at given coordinate + */ + public double getRawBiomeRainfall(int x, int z) { + return biomeRain[x << 4 | z]; + } + + /** + * Get world full time when chunk snapshot was captured + * @return time in ticks + */ + public long getCaptureFullTime() { + return captureFulltime; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java new file mode 100644 index 0000000..6e5c9c5 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -0,0 +1,64 @@ +package org.bukkit.craftbukkit; + +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; + +public class CraftOfflinePlayer implements OfflinePlayer { + private final String name; + private final CraftServer server; + + protected CraftOfflinePlayer(CraftServer server, String name) { + this.server = server; + this.name = name; + } + + public boolean isOnline() { + return false; + } + + public String getName() { + return name; + } + + public Server getServer() { + return server; + } + + public boolean isOp() { + return server.getHandle().isOp(getName().toLowerCase()); + } + + public void setOp(boolean value) { + if (value == isOp()) return; + + if (value) { + server.getHandle().e(getName().toLowerCase()); + } else { + server.getHandle().f(getName().toLowerCase()); + } + } + + public boolean isBanned() { + return server.getHandle().banByName.contains(name.toLowerCase()); + } + + public void setBanned(boolean value) { + if (value) { + server.getHandle().a(name.toLowerCase()); + } else { + server.getHandle().b(name.toLowerCase()); + } + } + + public boolean isWhitelisted() { + return server.getHandle().e().contains(name.toLowerCase()); + } + + public void setWhitelisted(boolean value) { + if (value) { + server.getHandle().k(name.toLowerCase()); + } else { + server.getHandle().l(name.toLowerCase()); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java new file mode 100644 index 0000000..cd1e1bd --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -0,0 +1,948 @@ +package org.bukkit.craftbukkit; + +import com.avaje.ebean.config.DataSourceConfig; +import com.avaje.ebean.config.ServerConfig; +import com.avaje.ebean.config.dbplatform.SQLitePlatform; +import com.avaje.ebeaninternal.server.lib.sql.TransactionIsolation; +import com.legacyminecraft.poseidon.Poseidon; +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.PoseidonPlugin; +import com.legacyminecraft.poseidon.PoseidonServer; +import com.legacyminecraft.poseidon.utility.PoseidonVersionChecker; +import jline.ConsoleReader; +import net.minecraft.server.*; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.World.Environment; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe; +import org.bukkit.craftbukkit.inventory.CraftRecipe; +import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; +import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe; +import org.bukkit.craftbukkit.map.CraftMapView; +import org.bukkit.craftbukkit.scheduler.CraftScheduler; +import org.bukkit.entity.Player; +import org.bukkit.event.world.WorldInitEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldSaveEvent; +import org.bukkit.event.world.WorldUnloadEvent; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.FurnaceRecipe; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.ShapelessRecipe; +import org.bukkit.permissions.Permission; +import org.bukkit.plugin.*; +import org.bukkit.plugin.java.JavaPluginLoader; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitWorker; +import org.bukkit.util.config.Configuration; +import org.bukkit.util.config.ConfigurationNode; +import org.bukkit.util.permissions.DefaultPermissions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.error.MarkedYAMLException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +public final class CraftServer implements Server { + private final String serverName = "Project Poseidon Craftbukkit"; + //Poseidon Versions + private final String serverEnvironment = "POSEIDON"; + private final String serverVersion = "1.1.10"; + private final String releaseType = "DEVELOPMENT"; + private final String protocolVersion = "1.7.3"; + private final String GameVersion = "b1.7.3"; + private final ServicesManager servicesManager = new SimpleServicesManager(); + private final BukkitScheduler scheduler; + private final SimpleCommandMap commandMap = new SimpleCommandMap(this); + private final PluginManager pluginManager; + protected final MinecraftServer console; + protected final ServerConfigurationManager server; + private final Map worlds = new LinkedHashMap(); + private final Configuration configuration; + private final Yaml yaml = new Yaml(new SafeConstructor()); + + // Project Poseidon - Start + private volatile boolean shuttingdown = false; + private final List hiddenCommands = new ArrayList<>(); + + // Project Poseidon - End + + public CraftServer(MinecraftServer console, ServerConfigurationManager server) { + this.console = console; + this.server = server; + //this.serverVersion = CraftServer.class.getPackage().getImplementationVersion(); //Poseidon Replace + + Bukkit.setServer(this); + + //Project Poseidon Start + PoseidonServer poseidonServer = new PoseidonServer(console, this); + Poseidon.setServer(poseidonServer); + //Project Poseidon End + + this.pluginManager = new SimplePluginManager(this, commandMap); //Project Poseidon - This must run after PoseidonServer is set + this.scheduler = new CraftScheduler(this); //Project Poseidon - This must run after PoseidonServer is set + + configuration = new Configuration((File) console.options.valueOf("bukkit-settings")); + loadConfig(); + loadPlugins(); + enablePlugins(PluginLoadOrder.STARTUP); + + ChunkCompressionThread.startThread(); + } + + private void loadConfig() { + configuration.load(); + configuration.getString("database.url", "jdbc:sqlite:{DIR}{NAME}.db"); + configuration.getString("database.username", "bukkit"); + configuration.getString("database.password", "walrus"); + configuration.getString("database.driver", "org.sqlite.JDBC"); + configuration.getString("database.isolation", "SERIALIZABLE"); + + configuration.getString("settings.update-folder", "update"); + configuration.getInt("settings.spawn-radius", 16); + + configuration.getString("settings.permissions-file", "permissions.yml"); + + if (configuration.getNode("aliases") == null) { + List icanhasbukkit = new ArrayList(); + icanhasbukkit.add("version"); + configuration.setProperty("aliases.icanhasbukkit", icanhasbukkit); + } + configuration.save(); + } + + public void loadPlugins() { + pluginManager.registerInterface(JavaPluginLoader.class); + + File pluginFolder = (File) console.options.valueOf("plugins"); + + if (pluginFolder.exists()) { + Plugin[] plugins = pluginManager.loadPlugins(pluginFolder); + for (Plugin plugin : plugins) { + try { + plugin.onLoad(); + } catch (Throwable ex) { + Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, ex.getMessage() + " initializing " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); + } + } + } else { + pluginFolder.mkdir(); + } + } + + public void enablePlugins(PluginLoadOrder type) { + Plugin[] plugins = pluginManager.getPlugins(); + + // Enable startup plugins first, then postworld plugins later. + // If a plugin depends on another plugin from the current phase, enable that dependency first. + // Dependencies from a later phase stay disabled until that phase runs. + for (Plugin plugin : plugins) { + // Re-evaluate every disabled plugin on each phase so deferred dependencies can come alive later. + if (!plugin.isEnabled() && shouldAttemptEnable(plugin, type)) { + enablePlugin(plugin, type, new LinkedHashSet()); + } + } + + if (type == PluginLoadOrder.POSTWORLD) { + commandMap.registerServerAliases(); + loadCustomPermissions(); + DefaultPermissions.registerCorePermissions(); + } + } + + public void disablePlugins() { + pluginManager.disablePlugins(); + } + + private boolean shouldAttemptEnable(Plugin plugin, PluginLoadOrder type) { + // Startup plugins are eligible during both passes. Postworld plugins only become eligible later. + //TODO Reevaluate if this should be allowed + return plugin.getDescription().getLoad().ordinal() <= type.ordinal(); + } + + private boolean enablePlugin(Plugin plugin, PluginLoadOrder type, Set enabling) { + if (plugin.isEnabled()) { + return true; + } + + if (!shouldAttemptEnable(plugin, type)) { + return false; + } + + String pluginName = plugin.getDescription().getName(); + // Guard against recursive dependency loops during the current enable chain. + if (!enabling.add(pluginName)) { + getLogger().log(Level.SEVERE, "Circular plugin dependency detected while enabling " + plugin.getDescription().getFullName()); + return false; + } + + try { + Object dependObject = plugin.getDescription().getDepend(); + if (dependObject instanceof Collection) { + for (Object dependencyNameObject : (Collection) dependObject) { + String dependencyName = String.valueOf(dependencyNameObject); + Plugin dependency = pluginManager.getPlugin(dependencyName); + + if (dependency == null) { + getLogger().log(Level.SEVERE, "Could not enable " + plugin.getDescription().getFullName() + ": missing required dependency " + dependencyName); + return false; + } + + // A dependency scheduled for a later phase will be retried when that phase runs. + if (!shouldAttemptEnable(dependency, type)) { + return false; + } + + // Hard dependencies must be fully enabled before this plugin can start. + if (!enablePlugin(dependency, type, enabling)) { + return false; + } + } + } + + Object softDependObject = plugin.getDescription().getSoftDepend(); + if (softDependObject instanceof Collection) { + for (Object dependencyNameObject : (Collection) softDependObject) { + String dependencyName = String.valueOf(dependencyNameObject); + Plugin dependency = pluginManager.getPlugin(dependencyName); + // Soft dependencies are enabled first when possible, but do not block startup. + if (dependency != null && !dependency.isEnabled() && shouldAttemptEnable(dependency, type)) { + enablePlugin(dependency, type, enabling); + } + } + } + + // The actual enable call stays in one place so permission registration behavior is unchanged. + loadPlugin(plugin); + return plugin.isEnabled(); + } finally { + enabling.remove(pluginName); + } + } + + private void loadPlugin(Plugin plugin) { + try { + pluginManager.enablePlugin(plugin); + + List perms = plugin.getDescription().getPermissions(); + + for (Permission perm : perms) { + try { + pluginManager.addPermission(perm); + } catch (IllegalArgumentException ex) { + getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex); + } + } + } catch (Throwable ex) { + Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, ex.getMessage() + " loading " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); + } + } + + @Override + public String getGameVersion() { + return getGameVersion(); + } + + @Override + public String getName() { + return serverName; + } + + public String getPoseidonVersion() { + return serverVersion; + } + + public String getPoseidonReleaseType() { + return releaseType; + } + + public String getServerEnvironment() { + return serverEnvironment; + } + + public String getVersion() { + return serverVersion + " (MC: " + protocolVersion + ")"; + } + + @SuppressWarnings("unchecked") + public Player[] getOnlinePlayers() { + List online = server.players; + Player[] players = new Player[online.size()]; + + for (int i = 0; i < players.length; i++) { + players[i] = online.get(i).netServerHandler.getPlayer(); + } + + return players; + } + + public Player getPlayer(final String name) { + Player[] players = getOnlinePlayers(); + + Player found = null; + String lowerName = name.toLowerCase(); + int delta = Integer.MAX_VALUE; + for (Player player : players) { + if (player.getName().toLowerCase().startsWith(lowerName)) { + int curDelta = player.getName().length() - lowerName.length(); + if (curDelta < delta) { + found = player; + delta = curDelta; + } + if (curDelta == 0) break; + } + } + return found; + } + + //Project Poseidon Start + @Override + public Player getPlayer(final UUID uuid) { + for (Player p : Bukkit.getOnlinePlayers()) { + if (p.getUniqueId().equals(uuid)) { + return p; + } + } + return null; + } + + //Project Poseidon End + + + public Player getPlayerExact(String name) { + String lname = name.toLowerCase(); + + for (Player player : getOnlinePlayers()) { + if (player.getName().equalsIgnoreCase(lname)) { + return player; + } + } + + return null; + } + + public int broadcastMessage(String message) { + return broadcast(message, BROADCAST_CHANNEL_USERS); + } + + public Player getPlayer(final EntityPlayer entity) { + return entity.netServerHandler.getPlayer(); + } + + public List matchPlayer(String partialName) { + List matchedPlayers = new ArrayList(); + + for (Player iterPlayer : this.getOnlinePlayers()) { + String iterPlayerName = iterPlayer.getName(); + + if (partialName.equalsIgnoreCase(iterPlayerName)) { + // Exact match + matchedPlayers.clear(); + matchedPlayers.add(iterPlayer); + break; + } + if (iterPlayerName.toLowerCase().indexOf(partialName.toLowerCase()) != -1) { + // Partial match + matchedPlayers.add(iterPlayer); + } + } + + return matchedPlayers; + } + + public int getMaxPlayers() { + return server.maxPlayers; + } + + // NOTE: These are dependent on the corrisponding call in MinecraftServer + // so if that changes this will need to as well + public int getPort() { + return this.getConfigInt("server-port", 25565); + } + + public int getViewDistance() { + return this.getConfigInt("view-distance", 10); + } + + public String getIp() { + return this.getConfigString("server-ip", ""); + } + + public String getServerName() { + return this.getConfigString("server-name", "Unknown Server"); + } + + public String getServerId() { + return this.getConfigString("server-id", "unnamed"); + } + + public boolean getAllowNether() { + return this.getConfigBoolean("allow-nether", true); + } + + public boolean hasWhitelist() { + return this.getConfigBoolean("white-list", false); + } + + // NOTE: Temporary calls through to server.properies until its replaced + private String getConfigString(String variable, String defaultValue) { + return this.console.propertyManager.getString(variable, defaultValue); + } + + private int getConfigInt(String variable, int defaultValue) { + return this.console.propertyManager.getInt(variable, defaultValue); + } + + private boolean getConfigBoolean(String variable, boolean defaultValue) { + return this.console.propertyManager.getBoolean(variable, defaultValue); + } + + // End Temporary calls + + public String getUpdateFolder() { + return this.configuration.getString("settings.update-folder", "update"); + } + + public PluginManager getPluginManager() { + return pluginManager; + } + + public BukkitScheduler getScheduler() { + return scheduler; + } + + public ServicesManager getServicesManager() { + return servicesManager; + } + + public List getWorlds() { + return new ArrayList(worlds.values()); + } + + public ServerConfigurationManager getHandle() { + return server; + } + + + // NOTE: Should only be called from MinecraftServer.b() + public boolean dispatchCommand(CommandSender sender, ServerCommand serverCommand) { + return dispatchCommand(sender, serverCommand.command); + } + + public boolean dispatchCommand(CommandSender sender, String commandLine) { + if (commandMap.dispatch(sender, commandLine)) { + return true; + } + + sender.sendMessage("Unknown command. Type \"help\" for help."); + + return false; + } + + public void reload() { + loadConfig(); + PropertyManager config = new PropertyManager(console.options); + + console.propertyManager = config; + + boolean animals = config.getBoolean("spawn-animals", console.spawnAnimals); + boolean monsters = config.getBoolean("spawn-monsters", console.worlds.get(0).spawnMonsters > 0); + + console.onlineMode = config.getBoolean("online-mode", console.onlineMode); + console.spawnAnimals = config.getBoolean("spawn-animals", console.spawnAnimals); + console.pvpMode = config.getBoolean("pvp", console.pvpMode); + console.allowFlight = config.getBoolean("allow-flight", console.allowFlight); + + for (WorldServer world : console.worlds) { + world.spawnMonsters = monsters ? 1 : 0; + world.setSpawnFlags(monsters, animals); + } + + pluginManager.clearPlugins(); + commandMap.clearCommands(); + + int pollCount = 0; + + // Wait for at most 2.5 seconds for plugins to close their threads + while (pollCount < 50 && getScheduler().getActiveWorkers().size() > 0) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + } + pollCount++; + } + + List overdueWorkers = getScheduler().getActiveWorkers(); + for (BukkitWorker worker : overdueWorkers) { + Plugin plugin = worker.getOwner(); + String author = ""; + if (plugin.getDescription().getAuthors().size() > 0) { + author = plugin.getDescription().getAuthors().get(0); + } + getLogger().log(Level.SEVERE, String.format( + "Nag author: '%s' of '%s' about the following: %s", + author, + plugin.getDescription().getName(), + "This plugin is not properly shutting down its async tasks when it is being reloaded. This may cause conflicts with the newly loaded version of the plugin" + )); + } + loadPlugins(); + enablePlugins(PluginLoadOrder.STARTUP); + enablePlugins(PluginLoadOrder.POSTWORLD); + } + + private void loadCustomPermissions() { + File file = new File(configuration.getString("settings.permissions-file")); + FileInputStream stream; + + try { + stream = new FileInputStream(file); + } catch (FileNotFoundException ex) { + try { + file.createNewFile(); + } finally { + return; + } + } + + Map> perms; + + try { + perms = (Map>) yaml.load(stream); + } catch (MarkedYAMLException ex) { + getLogger().log(Level.WARNING, "Server permissions file " + file + " is not valid YAML: " + ex.toString()); + return; + } catch (Throwable ex) { + getLogger().log(Level.WARNING, "Server permissions file " + file + " is not valid YAML.", ex); + return; + } finally { + try { + stream.close(); + } catch (IOException ex) { + } + } + + if (perms == null) { + getLogger().log(Level.INFO, "Server permissions file " + file + " is empty, ignoring it"); + return; + } + + Set keys = perms.keySet(); + + for (String name : keys) { + try { + pluginManager.addPermission(Permission.loadPermission(name, perms.get(name))); + } catch (Throwable ex) { + Bukkit.getServer().getLogger().log(Level.SEVERE, "Permission node '" + name + "' in server config is invalid", ex); + } + } + } + + @Override + public String toString() { + return "CraftServer{" + "serverName=" + serverName + ",serverVersion=" + serverVersion + ",protocolVersion=" + protocolVersion + '}'; + } + + public World createWorld(String name, World.Environment environment) { + return createWorld(name, environment, (new Random()).nextLong()); + } + + public World createWorld(String name, World.Environment environment, long seed) { + return createWorld(name, environment, seed, null); + } + + public World createWorld(String name, Environment environment, ChunkGenerator generator) { + return createWorld(name, environment, (new Random()).nextLong(), generator); + } + + public World createWorld(String name, Environment environment, long seed, ChunkGenerator generator) { + File folder = new File(name); + World world = getWorld(name); + + if (world != null) { + return world; + } + + if ((folder.exists()) && (!folder.isDirectory())) { + throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder"); + } + + if (generator == null) { + generator = getGenerator(name); + } + + Convertable converter = new WorldLoaderServer(folder); + if (converter.isConvertable(name)) { + getLogger().info("Converting world '" + name + "'"); + converter.convert(name, new ConvertProgressUpdater(console)); + } + + int dimension = 10 + console.worlds.size(); + WorldServer internal = new WorldServer(console, new ServerNBTManager(new File("."), name, true), name, dimension, seed, environment, generator); + + if (!(worlds.containsKey(name.toLowerCase()))) { + return null; + } + + internal.worldMaps = console.worlds.get(0).worldMaps; + + internal.tracker = new EntityTracker(console, dimension); + internal.addIWorldAccess((IWorldAccess) new WorldManager(console, internal)); + internal.spawnMonsters = 1; + internal.setSpawnFlags(true, true); + console.worlds.add(internal); + + if (generator != null) { + internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld())); + } + + pluginManager.callEvent(new WorldInitEvent(internal.getWorld())); + System.out.print("Preparing start region for level " + (console.worlds.size() - 1) + " (Seed: " + internal.getSeed() + ")"); + + if (internal.getWorld().getKeepSpawnInMemory()) { + short short1 = 196; + long i = System.currentTimeMillis(); + for (int j = -short1; j <= short1; j += 16) { + for (int k = -short1; k <= short1; k += 16) { + long l = System.currentTimeMillis(); + + if (l < i) { + i = l; + } + + if (l > i + 1000L) { + int i1 = (short1 * 2 + 1) * (short1 * 2 + 1); + int j1 = (j + short1) * (short1 * 2 + 1) + k + 1; + + System.out.println("Preparing spawn area for " + name + ", " + (j1 * 100 / i1) + "%"); + i = l; + } + + ChunkCoordinates chunkcoordinates = internal.getSpawn(); + internal.chunkProviderServer.getChunkAt(chunkcoordinates.x + j >> 4, chunkcoordinates.z + k >> 4); + + while (internal.doLighting()) { + ; + } + } + } + } + pluginManager.callEvent(new WorldLoadEvent(internal.getWorld())); + return internal.getWorld(); + } + + public boolean unloadWorld(String name, boolean save) { + return unloadWorld(getWorld(name), save); + } + + public boolean unloadWorld(World world, boolean save) { + if (world == null) { + return false; + } + + WorldServer handle = ((CraftWorld) world).getHandle(); + + if (!(console.worlds.contains(handle))) { + return false; + } + + if (!(handle.dimension > 1)) { + return false; + } + + if (handle.players.size() > 0) { + return false; + } + + WorldUnloadEvent e = new WorldUnloadEvent(handle.getWorld()); + + if (e.isCancelled()) { + return false; + } + + if (save) { + handle.save(true, (IProgressUpdate) null); + handle.saveLevel(); + WorldSaveEvent event = new WorldSaveEvent(handle.getWorld()); + getPluginManager().callEvent(event); + } + + worlds.remove(world.getName().toLowerCase()); + console.worlds.remove(console.worlds.indexOf(handle)); + + return true; + } + + public MinecraftServer getServer() { + return console; + } + + public World getWorld(String name) { + return worlds.get(name.toLowerCase()); + } + + public World getWorld(UUID uid) { + for (World world : worlds.values()) { + if (world.getUID().equals(uid)) { + return world; + } + } + return null; + } + + public void addWorld(World world) { + // Check if a World already exists with the UID. + if (getWorld(world.getUID()) != null) { + System.out.println("World " + world.getName() + " is a duplicate of another world and has been prevented from loading. Please delete the uid.dat file from " + world.getName() + "'s world directory if you want to be able to load the duplicate world."); + return; + } + worlds.put(world.getName().toLowerCase(), world); + } + + public Logger getLogger() { + return MinecraftServer.log; + } + + public ConsoleReader getReader() { + return console.reader; + } + + public PluginCommand getPluginCommand(String name) { + Command command = commandMap.getCommand(name); + + if (command instanceof PluginCommand) { + return (PluginCommand) command; + } else { + return null; + } + } + + public void savePlayers() { + server.savePlayers(); + } + + public void configureDbConfig(ServerConfig config) { + DataSourceConfig ds = new DataSourceConfig(); + ds.setDriver(configuration.getString("database.driver")); + ds.setUrl(configuration.getString("database.url")); + ds.setUsername(configuration.getString("database.username")); + ds.setPassword(configuration.getString("database.password")); + ds.setIsolationLevel(TransactionIsolation.getLevel(configuration.getString("database.isolation"))); + + if (ds.getDriver().contains("sqlite")) { + config.setDatabasePlatform(new SQLitePlatform()); + config.getDatabasePlatform().getDbDdlSyntax().setIdentity(""); + } + + config.setDataSourceConfig(ds); + } + + public boolean addRecipe(Recipe recipe) { + CraftRecipe toAdd; + if (recipe instanceof CraftRecipe) { + toAdd = (CraftRecipe) recipe; + } else { + if (recipe instanceof ShapedRecipe) { + toAdd = CraftShapedRecipe.fromBukkitRecipe((ShapedRecipe) recipe); + } else if (recipe instanceof ShapelessRecipe) { + toAdd = CraftShapelessRecipe.fromBukkitRecipe((ShapelessRecipe) recipe); + } else if (recipe instanceof FurnaceRecipe) { + toAdd = CraftFurnaceRecipe.fromBukkitRecipe((FurnaceRecipe) recipe); + } else { + return false; + } + } + toAdd.addToCraftingManager(); + return true; + } + + public Map getCommandAliases() { + ConfigurationNode node = configuration.getNode("aliases"); + Map result = new LinkedHashMap(); + + if (node != null) { + for (String key : node.getKeys()) { + List commands = new ArrayList(); + + if (node.getProperty(key) instanceof List) { + commands = node.getStringList(key, null); + } else { + commands.add(node.getString(key)); + } + + result.put(key, commands.toArray(new String[0])); + } + } + + return result; + } + + public int getSpawnRadius() { + return configuration.getInt("settings.spawn-radius", 16); + } + + public void setSpawnRadius(int value) { + configuration.setProperty("settings.spawn-radius", value); + configuration.save(); + } + + public boolean getOnlineMode() { + return this.console.onlineMode; + } + + public boolean getAllowFlight() { + return this.console.allowFlight; + } + + public ChunkGenerator getGenerator(String world) { + ConfigurationNode node = configuration.getNode("worlds"); + ChunkGenerator result = null; + + if (node != null) { + node = node.getNode(world); + + if (node != null) { + String name = node.getString("generator"); + + if ((name != null) && (!name.equals(""))) { + String[] split = name.split(":", 2); + String id = (split.length > 1) ? split[1] : null; + Plugin plugin = pluginManager.getPlugin(split[0]); + + if (plugin == null) { + getLogger().severe("Could not set generator for default world '" + world + "': Plugin '" + split[0] + "' does not exist"); + } else if (!plugin.isEnabled()) { + getLogger().severe("Could not set generator for default world '" + world + "': Plugin '" + split[0] + "' is not enabled yet (is it load:STARTUP?)"); + } else { + result = plugin.getDefaultWorldGenerator(world, id); + } + } + } + } + + return result; + } + + public CraftMapView getMap(short id) { + WorldMapCollection collection = console.worlds.get(0).worldMaps; + WorldMap worldmap = (WorldMap) collection.a(WorldMap.class, "map_" + id); + if (worldmap == null) { + return null; + } + return worldmap.mapView; + } + + public CraftMapView createMap(World world) { + ItemStack stack = new ItemStack(Item.MAP, 1, -1); + WorldMap worldmap = Item.MAP.a(stack, ((CraftWorld) world).getHandle()); + return worldmap.mapView; + } + + public void shutdown() { + setShuttingdown(true); + console.a(); + } + + public int broadcast(String message, String permission) { +// int count = 0; +// Set permissibles = getPluginManager().getPermissionSubscriptions(permission); +// +// for (Permissible permissible : permissibles) { +// if (permissible instanceof CommandSender) { +// CommandSender user = (CommandSender)permissible; +// user.sendMessage(message); +// count++; +// } +// } +// +// return count; + Player[] players = getOnlinePlayers(); + + for (Player player : players) { + player.sendMessage(message); + } + + return players.length; + } + + public OfflinePlayer getOfflinePlayer(String name) { + OfflinePlayer result = getPlayerExact(name); + + if (result == null) { + result = new CraftOfflinePlayer(this, name); + } + + return result; + } + + public Set getIPBans() { + return new HashSet(server.banByIP); + } + + public void banIP(String address) { + server.c(address); + } + + public void unbanIP(String address) { + server.d(address); + } + + public Set getBannedPlayers() { + Set result = new HashSet(); + + for (Object name : server.banByName) { + result.add(getOfflinePlayer((String) name)); + } + + return result; + } + + public void setWhitelist(boolean value) { + server.o = value; + console.propertyManager.b("white-list", value); + console.propertyManager.savePropertiesFile(); + } + + public Set getWhitelistedPlayers() { + Set result = new HashSet(); + + for (Object name : server.e()) { + result.add(getOfflinePlayer((String) name)); + } + + return result; + } + + public void reloadWhitelist() { + server.f(); + } + + public boolean isShuttingdown() { + return shuttingdown; + } + + public void setShuttingdown(boolean shuttingdown) { + this.shuttingdown = shuttingdown; + } + +// public GameMode getDefaultGameMode() { +// return GameMode.SURVIVAL; +// } +// +// public void setDefaultGameMode(GameMode mode) { +// throw new UnsupportedOperationException("Not supported yet."); +// } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java new file mode 100644 index 0000000..0dc6a98 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -0,0 +1,832 @@ +package org.bukkit.craftbukkit; + +import com.google.common.collect.MapMaker; +import net.minecraft.server.*; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.*; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.entity.*; +import org.bukkit.entity.Entity; +import org.bukkit.entity.*; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.weather.ThunderChangeEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.bukkit.event.world.SpawnChangeEvent; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ConcurrentMap; + +public class CraftWorld implements World { + private final WorldServer world; + private Environment environment; + private final CraftServer server = (CraftServer)Bukkit.getServer(); +// private ConcurrentMap unloadedChunks = new MapMaker().weakValues().makeMap(); + private final ChunkGenerator generator; + private final List populators = new ArrayList(); + + private static final Random rand = new Random(); + + public CraftWorld(WorldServer world, ChunkGenerator gen, Environment env) { + this.world = world; + this.generator = gen; + + environment = env; + } + +// public void preserveChunk(CraftChunk chunk) { +// chunk.breakLink(); +// unloadedChunks.put((chunk.getX() << 16) + chunk.getZ(), chunk); +// } +// +// public Chunk popPreservedChunk(int x, int z) { +// return unloadedChunks.remove((x << 16) + z); +// } + + public Block getBlockAt(int x, int y, int z) { + return getChunkAt(x >> 4, z >> 4).getBlock(x & 0xF, y & 0x7F, z & 0xF); + } + + public int getBlockTypeIdAt(int x, int y, int z) { + return world.getTypeId(x, y, z); + } + + public int getHighestBlockYAt(int x, int z) { + return world.getHighestBlockYAt(x, z); + } + + public Location getSpawnLocation() { + ChunkCoordinates spawn = world.getSpawn(); + float yaw = world.worldData.getYaw(); // Poseidon + float pitch = world.worldData.getPitch(); // Poseidon + return new Location(this, spawn.x, spawn.y, spawn.z, yaw, pitch); + } + + public boolean setSpawnLocation(int x, int y, int z) { + return setSpawnLocation(x, y, z, 0f, 0f); // Poseidon - moved to overloaded method + } + + // Poseidon start + public boolean setSpawnLocation(int x, int y, int z, float yaw, float pitch) { + try { + Location previousLocation = getSpawnLocation(); + world.worldData.setSpawn(x, y, z, yaw, pitch); + + // Notify anyone who's listening. + SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); + server.getPluginManager().callEvent(event); + + return true; + } catch (Exception e) { + return false; + } + } + + // Poseidon end + + public Chunk getChunkAt(int x, int z) { + return this.world.chunkProviderServer.getChunkAt(x, z).bukkitChunk; + } + + public Chunk getChunkAt(Block block) { + return getChunkAt(block.getX() >> 4, block.getZ() >> 4); + } + + public boolean isChunkLoaded(int x, int z) { + return world.chunkProviderServer.isChunkLoaded(x, z); + } + + public Chunk[] getLoadedChunks() { + Object[] chunks = world.chunkProviderServer.chunks.values().toArray(); + org.bukkit.Chunk[] craftChunks = new CraftChunk[chunks.length]; + + for (int i = 0; i < chunks.length; i++) { + net.minecraft.server.Chunk chunk = (net.minecraft.server.Chunk) chunks[i]; + craftChunks[i] = chunk.bukkitChunk; + } + + return craftChunks; + } + + public void loadChunk(int x, int z) { + loadChunk(x, z, true); + } + + public boolean unloadChunk(Chunk chunk) { + return unloadChunk(chunk.getX(), chunk.getZ()); + } + + public boolean unloadChunk(int x, int z) { + return unloadChunk(x, z, true); + } + + public boolean unloadChunk(int x, int z, boolean save) { + return unloadChunk(x, z, save, false); + } + + public boolean unloadChunkRequest(int x, int z) { + return unloadChunkRequest(x, z, true); + } + + public boolean unloadChunkRequest(int x, int z, boolean safe) { + if (safe && isChunkInUse(x, z)) { + return false; + } + + world.chunkProviderServer.queueUnload(x, z); + + return true; + } + + public boolean unloadChunk(int x, int z, boolean save, boolean safe) { + if (safe && isChunkInUse(x, z)) { + return false; + } + + net.minecraft.server.Chunk chunk = world.chunkProviderServer.getOrCreateChunk(x, z); + + if (save && !chunk.isEmpty()) { + chunk.removeEntities(); + world.chunkProviderServer.saveChunk(chunk); + world.chunkProviderServer.saveChunkNOP(chunk); + } + +// preserveChunk((CraftChunk) chunk.bukkitChunk); + world.chunkProviderServer.unloadQueue.remove(x, z); + world.chunkProviderServer.chunks.remove(x, z); + world.chunkProviderServer.chunkList.remove(chunk); + + return true; + } + + public boolean regenerateChunk(int x, int z) { + unloadChunk(x, z, false, false); + + world.chunkProviderServer.unloadQueue.remove(x, z); + + net.minecraft.server.Chunk chunk = null; + + if (world.chunkProviderServer.chunkProvider == null) { + chunk = world.chunkProviderServer.emptyChunk; + } else { + chunk = world.chunkProviderServer.chunkProvider.getOrCreateChunk(x, z); + } + + chunkLoadPostProcess(chunk, x, z); + + refreshChunk(x, z); + + return chunk != null; + } + + public boolean refreshChunk(int x, int z) { + if (!isChunkLoaded(x, z)) { + return false; + } + + int px = x << 4; + int pz = z << 4; + + // If there are more than 10 updates to a chunk at once, it carries out the update as a cuboid + // This flags 16 blocks in a line along the bottom for update and then flags a block at the opposite corner at the top + // The cuboid that contains these 17 blocks covers the entire chunk + // The server will compress the chunk and send it to all clients + + for (int xx = px; xx < (px + 16); xx++) { + world.notify(xx, 0, pz); + } + world.notify(px, 127, pz + 15); + + return true; + } + + + public boolean isChunkInUse(int x, int z) { + Player[] players = server.getOnlinePlayers(); + + for (Player player : players) { + Location loc = player.getLocation(); + if (loc.getWorld() != world.chunkProviderServer.world.getWorld()) { + continue; + } + + // If the chunk is within 256 blocks of a player, refuse to accept the unload request + // This is larger than the distance of loaded chunks that actually surround a player + // The player is the center of a 21x21 chunk grid, so the edge is 10 chunks (160 blocks) away from the player + if (Math.abs(loc.getBlockX() - (x << 4)) <= 256 && Math.abs(loc.getBlockZ() - (z << 4)) <= 256) { + return true; + } + } + return false; + } + + public boolean loadChunk(int x, int z, boolean generate) { + if (generate) { + // Use the default variant of loadChunk when generate == true. + return world.chunkProviderServer.getChunkAt(x, z) != null; + } + + world.chunkProviderServer.unloadQueue.remove(x, z); + net.minecraft.server.Chunk chunk = (net.minecraft.server.Chunk) world.chunkProviderServer.chunks.get(x, z); + + if (chunk == null) { + chunk = world.chunkProviderServer.loadChunk(x, z); + + chunkLoadPostProcess(chunk, x, z); + } + return chunk != null; + } + + @SuppressWarnings("unchecked") + private void chunkLoadPostProcess(net.minecraft.server.Chunk chunk, int x, int z) { + if (chunk != null) { + world.chunkProviderServer.chunks.put(x, z, chunk); + world.chunkProviderServer.chunkList.add(chunk); + + chunk.loadNOP(); + chunk.addEntities(); + + if (!chunk.done && world.chunkProviderServer.isChunkLoaded(x + 1, z + 1) && world.chunkProviderServer.isChunkLoaded(x, z + 1) && world.chunkProviderServer.isChunkLoaded(x + 1, z)) { + world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x, z); + } + + if (world.chunkProviderServer.isChunkLoaded(x - 1, z) && !world.chunkProviderServer.getOrCreateChunk(x - 1, z).done && world.chunkProviderServer.isChunkLoaded(x - 1, z + 1) && world.chunkProviderServer.isChunkLoaded(x, z + 1) && world.chunkProviderServer.isChunkLoaded(x - 1, z)) { + world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x - 1, z); + } + + if (world.chunkProviderServer.isChunkLoaded(x, z - 1) && !world.chunkProviderServer.getOrCreateChunk(x, z - 1).done && world.chunkProviderServer.isChunkLoaded(x + 1, z - 1) && world.chunkProviderServer.isChunkLoaded(x, z - 1) && world.chunkProviderServer.isChunkLoaded(x + 1, z)) { + world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x, z - 1); + } + + if (world.chunkProviderServer.isChunkLoaded(x - 1, z - 1) && !world.chunkProviderServer.getOrCreateChunk(x - 1, z - 1).done && world.chunkProviderServer.isChunkLoaded(x - 1, z - 1) && world.chunkProviderServer.isChunkLoaded(x, z - 1) && world.chunkProviderServer.isChunkLoaded(x - 1, z)) { + world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x - 1, z - 1); + } + } + } + + public boolean isChunkLoaded(Chunk chunk) { + return isChunkLoaded(chunk.getX(), chunk.getZ()); + } + + public void loadChunk(Chunk chunk) { + loadChunk(chunk.getX(), chunk.getZ()); + ((CraftChunk) getChunkAt(chunk.getX(), chunk.getZ())).getHandle().bukkitChunk = chunk; + } + + public WorldServer getHandle() { + return world; + } + + public org.bukkit.entity.Item dropItem(Location loc, ItemStack item) { + net.minecraft.server.ItemStack stack = new net.minecraft.server.ItemStack( + item.getTypeId(), + item.getAmount(), + item.getDurability() + ); + EntityItem entity = new EntityItem(world, loc.getX(), loc.getY(), loc.getZ(), stack); + entity.pickupDelay = 10; + world.addEntity(entity); + // TODO this is inconsistent with how Entity.getBukkitEntity() works. + // However, this entity is not at the moment backed by a server entity class so it may be left. + return new CraftItem(world.getServer(), entity); + } + + public org.bukkit.entity.Item dropItemNaturally(Location loc, ItemStack item) { + double xs = world.random.nextFloat() * 0.7F + (1.0F - 0.7F) * 0.5D; + double ys = world.random.nextFloat() * 0.7F + (1.0F - 0.7F) * 0.5D; + double zs = world.random.nextFloat() * 0.7F + (1.0F - 0.7F) * 0.5D; + loc = loc.clone(); + loc.setX(loc.getX() + xs); + loc.setY(loc.getY() + ys); + loc.setZ(loc.getZ() + zs); + return dropItem(loc, item); + } + + public Arrow spawnArrow(Location loc, Vector velocity, float speed, float spread) { + EntityArrow arrow = new EntityArrow(world); + arrow.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), 0, 0); + world.addEntity(arrow); + arrow.a(velocity.getX(), velocity.getY(), velocity.getZ(), speed, spread); + return (Arrow) arrow.getBukkitEntity(); + } + + public LivingEntity spawnCreature(Location loc, CreatureType creatureType) { + LivingEntity creature; + try { + EntityLiving entityCreature = (EntityLiving) EntityTypes.a(creatureType.getName(), world); + entityCreature.setPosition(loc.getX(), loc.getY(), loc.getZ()); + creature = (LivingEntity) CraftEntity.getEntity(server, entityCreature); + world.addEntity(entityCreature, SpawnReason.CUSTOM); + } catch (Exception e) { + // if we fail, for any reason, return null. + creature = null; + } + return creature; + } + + public LightningStrike strikeLightning(Location loc) { + EntityWeatherStorm lightning = new EntityWeatherStorm(world, loc.getX(), loc.getY(), loc.getZ()); + world.strikeLightning(lightning); + return new CraftLightningStrike(server, lightning); + } + + public LightningStrike strikeLightningEffect(Location loc) { + EntityWeatherStorm lightning = new EntityWeatherStorm(world, loc.getX(), loc.getY(), loc.getZ(), true); + world.strikeLightning(lightning); + return new CraftLightningStrike(server, lightning); + } + + public boolean generateTree(Location loc, TreeType type) { + return generateTree(loc, type, world); + } + + public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { + switch (type) { + case BIG_TREE: + return new WorldGenBigTree().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + case BIRCH: + return new WorldGenForest().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + case REDWOOD: + return new WorldGenTaiga2().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + case TALL_REDWOOD: + return new WorldGenTaiga1().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + case TREE: + default: + return new WorldGenTrees().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + } + } + + public TileEntity getTileEntityAt(final int x, final int y, final int z) { + return world.getTileEntity(x, y, z); + } + + public String getName() { + return world.worldData.name; + } + + @Deprecated + public long getId() { + return world.worldData.getSeed(); + } + + public UUID getUID() { + return world.getUUID(); + } + + @Override + public String toString() { + return "CraftWorld{name=" + getName() + '}'; + } + + public long getTime() { + long time = getFullTime() % 24000; + if (time < 0) time += 24000; + return time; + } + + public void setTime(long time) { + long margin = (time - getFullTime()) % 24000; + if (margin < 0) margin += 24000; + setFullTime(getFullTime() + margin); + } + + public long getFullTime() { + return world.getTime(); + } + + public void setFullTime(long time) { + world.setTime(time); + + // Forces the client to update to the new time immediately + for (Player p: getPlayers()) { + CraftPlayer cp = (CraftPlayer) p; + cp.getHandle().netServerHandler.sendPacket(new Packet4UpdateTime(cp.getHandle().getPlayerTime())); + } + } + + public boolean createExplosion(double x, double y, double z, float power) { + return createExplosion(x, y, z, power, false); + } + + public boolean createExplosion(double x, double y, double z, float power, boolean setFire) { + return createExplosion(x, y, z, power, setFire, EntityDamageEvent.DamageCause.PLUGIN_EXPLOSION); + } + + public boolean createExplosion(double x, double y, double z, float power, boolean setFire, EntityDamageEvent.DamageCause customDamageCause){ + return world.createExplosion(null, x, y, z, power, setFire, customDamageCause).wasCanceled ? false : true; + } + + public boolean createExplosion(Location loc, float power) { + return createExplosion(loc, power, false); + } + + public boolean createExplosion(Location loc, float power, boolean setFire) { + return createExplosion(loc.getX(), loc.getY(), loc.getZ(), power, setFire); + } + + public boolean createExplosion(Location loc, float power, boolean setFire, EntityDamageEvent.DamageCause customDamageCause){ + return createExplosion(loc.getX(), loc.getY(), loc.getZ(), power, setFire, customDamageCause); + } + + public Environment getEnvironment() { + return environment; + } + + public void setEnvironment(Environment env) { + if (environment != env) { + environment = env; + world.worldProvider = WorldProvider.byDimension(environment.getId()); + } + } + + public Block getBlockAt(Location location) { + return getBlockAt(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + public int getBlockTypeIdAt(Location location) { + return getBlockTypeIdAt(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + public int getHighestBlockYAt(Location location) { + return getHighestBlockYAt(location.getBlockX(), location.getBlockZ()); + } + + public Chunk getChunkAt(Location location) { + return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4); + } + + public ChunkGenerator getGenerator() { + return generator; + } + + public List getPopulators() { + return populators; + } + + public Block getHighestBlockAt(int x, int z) { + return getBlockAt(x, getHighestBlockYAt(x, z), z); + } + + public Block getHighestBlockAt(Location location) { + return getHighestBlockAt(location.getBlockX(), location.getBlockZ()); + } + + public Biome getBiome(int x, int z) { + BiomeBase base = getHandle().getWorldChunkManager().getBiome(x, z); + + if (base == BiomeBase.RAINFOREST) { + return Biome.RAINFOREST; + } else if (base == BiomeBase.SWAMPLAND) { + return Biome.SWAMPLAND; + } else if (base == BiomeBase.SEASONAL_FOREST) { + return Biome.SEASONAL_FOREST; + } else if (base == BiomeBase.FOREST) { + return Biome.FOREST; + } else if (base == BiomeBase.SAVANNA) { + return Biome.SAVANNA; + } else if (base == BiomeBase.SHRUBLAND) { + return Biome.SHRUBLAND; + } else if (base == BiomeBase.TAIGA) { + return Biome.TAIGA; + } else if (base == BiomeBase.DESERT) { + return Biome.DESERT; + } else if (base == BiomeBase.PLAINS) { + return Biome.PLAINS; + } else if (base == BiomeBase.ICE_DESERT) { + return Biome.ICE_DESERT; + } else if (base == BiomeBase.TUNDRA) { + return Biome.TUNDRA; + } else if (base == BiomeBase.HELL) { + return Biome.HELL; + } else if (base == BiomeBase.SKY) { + return Biome.SKY; + } + + return null; + } + + public double getTemperature(int x, int z) { + return getHandle().getWorldChunkManager().a((double[])null, x, z, 1, 1)[0]; + } + + public double getHumidity(int x, int z) { + return getHandle().getWorldChunkManager().getHumidity(x, z); + } + + public List getEntities() { + List list = new ArrayList(); + + for (Object o: world.entityList) { + if (o instanceof net.minecraft.server.Entity) { + net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o; + Entity bukkitEntity = mcEnt.getBukkitEntity(); + + // Assuming that bukkitEntity isn't null + if (bukkitEntity != null) { + list.add(bukkitEntity); + } + } + } + + return list; + } + + public List getLivingEntities() { + List list = new ArrayList(); + + for (Object o: world.entityList) { + if (o instanceof net.minecraft.server.Entity) { + net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o; + Entity bukkitEntity = mcEnt.getBukkitEntity(); + + // Assuming that bukkitEntity isn't null + if (bukkitEntity != null && bukkitEntity instanceof LivingEntity) { + list.add((LivingEntity) bukkitEntity); + } + } + } + + return list; + } + + public List getPlayers() { + List list = new ArrayList(); + + for (Object o : world.entityList) { + if (o instanceof net.minecraft.server.Entity) { + net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o; + Entity bukkitEntity = mcEnt.getBukkitEntity(); + + if ((bukkitEntity != null) && (bukkitEntity instanceof Player)) { + list.add((Player) bukkitEntity); + } + } + } + + return list; + } + + public void save() { + boolean oldSave = world.canSave; + + world.canSave = false; + world.save(true, null); + + world.canSave = oldSave; + } + + public boolean isAutoSave() { + return !world.canSave; + } + + public void setAutoSave(boolean value) { + world.canSave = !value; + } + + public boolean hasStorm() { + return world.worldData.hasStorm(); + } + + public void setStorm(boolean hasStorm) { + CraftServer server = world.getServer(); + + WeatherChangeEvent weather = new WeatherChangeEvent((org.bukkit.World) this, hasStorm); + server.getPluginManager().callEvent(weather); + if (!weather.isCancelled()) { + world.worldData.setStorm(hasStorm); + + // These numbers are from Minecraft + if (hasStorm) { + setWeatherDuration(rand.nextInt(12000) + 12000); + } else { + setWeatherDuration(rand.nextInt(168000) + 12000); + } + } + } + + public int getWeatherDuration() { + return world.worldData.getWeatherDuration(); + } + + public void setWeatherDuration(int duration) { + world.worldData.setWeatherDuration(duration); + } + + public boolean isThundering() { + return world.worldData.isThundering(); + } + + public void setThundering(boolean thundering) { + CraftServer server = world.getServer(); + + ThunderChangeEvent thunder = new ThunderChangeEvent((org.bukkit.World) this, thundering); + server.getPluginManager().callEvent(thunder); + if (!thunder.isCancelled()) { + world.worldData.setThundering(thundering); + + // These numbers are from Minecraft + if (thundering) { + setThunderDuration(rand.nextInt(12000) + 3600); + } else { + setThunderDuration(rand.nextInt(168000) + 12000); + } + } + } + + public int getThunderDuration() { + return world.worldData.getThunderDuration(); + } + + public void setThunderDuration(int duration) { + world.worldData.setThunderDuration(duration); + } + + public long getSeed() { + return world.worldData.getSeed(); + } + + public boolean getPVP() { + return world.pvpMode; + } + + public void setPVP(boolean pvp) { + world.pvpMode = pvp; + } + + public void playEffect(Player player, Effect effect, int data) { + playEffect(player.getLocation(), effect, data, 0); + } + + public void playEffect(Location location, Effect effect, int data) { + playEffect(location, effect, data, 64); + } + + public void playEffect(Location location, Effect effect, int data, int radius) { + int packetData = effect.getId(); + Packet61 packet = new Packet61(packetData, location.getBlockX(), location.getBlockY(), location.getBlockZ(), data); + int distance; + for (Player player : getPlayers()) { + distance = (int) player.getLocation().distance(location); + if (distance <= radius) { + ((CraftPlayer) player).getHandle().netServerHandler.sendPacket(packet); + } + } + } + + @SuppressWarnings("unchecked") + public T spawn(Location location, Class clazz) throws IllegalArgumentException { + if (location == null || clazz == null) { + throw new IllegalArgumentException("Location or entity class cannot be null"); + } + + net.minecraft.server.Entity entity = null; + + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + float pitch = location.getPitch(); + float yaw = location.getYaw(); + + // order is important for some of these + if (Boat.class.isAssignableFrom(clazz)) { + entity = new EntityBoat(world, x, y, z); + } else if (Egg.class.isAssignableFrom(clazz)) { + entity = new EntityEgg(world, x, y, z); + } else if (FallingSand.class.isAssignableFrom(clazz)) { + entity = new EntityFallingSand(world, x, y, z, 0); + } else if (Fireball.class.isAssignableFrom(clazz)) { + entity = new EntityFireball(world); + ((EntityFireball) entity).setPositionRotation(x, y, z, yaw, pitch); + Vector direction = location.getDirection().multiply(10); + ((EntityFireball) entity).setDirection(direction.getX(), direction.getY(), direction.getZ()); + } else if (Snowball.class.isAssignableFrom(clazz)) { + entity = new EntitySnowball(world, x, y, z); + } else if (Minecart.class.isAssignableFrom(clazz)) { + + if (PoweredMinecart.class.isAssignableFrom(clazz)) { + entity = new EntityMinecart(world, x, y, z, CraftMinecart.Type.PoweredMinecart.getId()); + } else if (StorageMinecart.class.isAssignableFrom(clazz)) { + entity = new EntityMinecart(world, x, y, z, CraftMinecart.Type.StorageMinecart.getId()); + } else { + entity = new EntityMinecart(world, x, y, z, CraftMinecart.Type.Minecart.getId()); + } + + } else if (Arrow.class.isAssignableFrom(clazz)) { + entity = new EntityArrow(world); + entity.setPositionRotation(x, y, z, 0, 0); + } else if (LivingEntity.class.isAssignableFrom(clazz)) { + + if (Chicken.class.isAssignableFrom(clazz)) { + entity = new EntityChicken(world); + } else if (Cow.class.isAssignableFrom(clazz)) { + entity = new EntityCow(world); + } else if (Creeper.class.isAssignableFrom(clazz)) { + entity = new EntityCreeper(world); + } else if (Ghast.class.isAssignableFrom(clazz)) { + entity = new EntityGhast(world); + } else if (Pig.class.isAssignableFrom(clazz)) { + entity = new EntityPig(world); + } else if (Player.class.isAssignableFrom(clazz)) { + // need a net server handler for this one + } else if (Sheep.class.isAssignableFrom(clazz)) { + entity = new EntitySheep(world); + } else if (Skeleton.class.isAssignableFrom(clazz)) { + entity = new EntitySkeleton(world); + } else if (Slime.class.isAssignableFrom(clazz)) { + entity = new EntitySlime(world); + } else if (Spider.class.isAssignableFrom(clazz)) { + entity = new EntitySpider(world); + } else if (Squid.class.isAssignableFrom(clazz)) { + entity = new EntitySquid(world); + } else if (Wolf.class.isAssignableFrom(clazz)) { + entity = new EntityWolf(world); + } else if (PigZombie.class.isAssignableFrom(clazz)) { + entity = new EntityPigZombie(world); + } else if (Zombie.class.isAssignableFrom(clazz)) { + entity = new EntityZombie(world); + } + + if (entity != null) { + entity.setLocation(x, y, z, pitch, yaw); + } + + } else if (Painting.class.isAssignableFrom(clazz)) { + // negative + } else if (TNTPrimed.class.isAssignableFrom(clazz)) { + entity = new EntityTNTPrimed(world, x, y, z); + } else if (Weather.class.isAssignableFrom(clazz)) { + // not sure what this can do + entity = new EntityWeatherStorm(world, x, y, z); + } else if (LightningStrike.class.isAssignableFrom(clazz)) { + // what is this, I don't even + } else if (Fish.class.isAssignableFrom(clazz)) { + // this is not a fish, it's a bobber, and it's probably useless + entity = new EntityFish(world); + entity.setLocation(x, y, z, pitch, yaw); + } + + if (entity != null) { + world.addEntity(entity); + return (T) entity.getBukkitEntity(); + } + + throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName()); + } + + public ChunkSnapshot getEmptyChunkSnapshot(int x, int z, boolean includeBiome, boolean includeBiomeTempRain) { + return CraftChunk.getEmptyChunkSnapshot(x, z, this, includeBiome, includeBiomeTempRain); + } + + public void setSpawnFlags(boolean allowMonsters, boolean allowAnimals) { + world.setSpawnFlags(allowMonsters, allowAnimals); + } + + public boolean getAllowAnimals() { + return world.allowAnimals; + } + + public boolean getAllowMonsters() { + return world.allowMonsters; + } + + public int getMaxHeight() { + return 128; + } + + public boolean getKeepSpawnInMemory() { + return world.keepSpawnInMemory; + } + + public void setKeepSpawnInMemory(boolean keepLoaded) { + world.keepSpawnInMemory = keepLoaded; + // Grab the worlds spawn chunk + ChunkCoordinates chunkcoordinates = this.world.getSpawn(); + int chunkCoordX = chunkcoordinates.x >> 4; + int chunkCoordZ = chunkcoordinates.z >> 4; + // Cycle through the 25x25 Chunks around it to load/unload the chunks. + for (int x = -12; x <= 12; x++) { + for (int z = -12; z <= 12; z++) { + if (keepLoaded) { + loadChunk(chunkCoordX + x, chunkCoordZ + z); + } else { + if (isChunkLoaded(chunkCoordX + x, chunkCoordZ + z)) { + if (this.getHandle().getChunkAt(chunkCoordX + x, chunkCoordZ + z).isEmpty()) { + unloadChunk(chunkCoordX + x, chunkCoordZ + z, false); + } else { + unloadChunk(chunkCoordX + x, chunkCoordZ + z); + } + } + } + } + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/LoggerOutputStream.java b/src/main/java/org/bukkit/craftbukkit/LoggerOutputStream.java new file mode 100644 index 0000000..d2637ad --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/LoggerOutputStream.java @@ -0,0 +1,32 @@ + +package org.bukkit.craftbukkit; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class LoggerOutputStream extends ByteArrayOutputStream { + private final String separator = System.getProperty("line.separator"); + private final Logger logger; + private final Level level; + + public LoggerOutputStream(Logger logger, Level level) { + super(); + this.logger = logger; + this.level = level; + } + + @Override + public void flush() throws IOException { + synchronized (this) { + super.flush(); + String record = this.toString(); + super.reset(); + + if ((record.length() > 0) && (!record.equals(separator))) { + logger.logp(level, "", "", record); + } + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java new file mode 100644 index 0000000..52222f5 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/Main.java @@ -0,0 +1,142 @@ +package org.bukkit.craftbukkit; + +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import net.minecraft.server.MinecraftServer; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Main { + public static boolean useJline = true; + + public static void main(String[] args) { + // Todo: Installation script + OptionParser parser = new OptionParser() { + { + acceptsAll(asList("?", "help"), "Show the help"); + + acceptsAll(asList("c", "config"), "Properties file to use") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File("server.properties")) + .describedAs("Properties file"); + + acceptsAll(asList("P", "plugins"), "Plugin directory to use") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File("plugins")) + .describedAs("Plugin directory"); + + acceptsAll(asList("h", "host", "server-ip"), "Host to listen on") + .withRequiredArg() + .ofType(String.class) + .describedAs("Hostname or IP"); + + acceptsAll(asList("w", "world", "level-name"), "World directory") + .withRequiredArg() + .ofType(String.class) + .describedAs("World dir"); + + acceptsAll(asList("p", "port", "server-port"), "Port to listen on") + .withRequiredArg() + .ofType(Integer.class) + .describedAs("Port"); + + acceptsAll(asList("o", "online-mode"), "Whether to use online authentication") + .withRequiredArg() + .ofType(Boolean.class) + .describedAs("Authentication"); + + acceptsAll(asList("s", "size", "max-players"), "Maximum amount of players") + .withRequiredArg() + .ofType(Integer.class) + .describedAs("Server size"); + + acceptsAll(asList("d", "date-format"), "Format of the date to display in the console (for log entries)") + .withRequiredArg() + .ofType(SimpleDateFormat.class) + .describedAs("Log date format"); + + acceptsAll(asList("log-pattern"), "Specfies the log filename pattern") + .withRequiredArg() + .ofType(String.class) + .defaultsTo("server.log") + .describedAs("Log filename"); + + acceptsAll(asList("log-limit"), "Limits the maximum size of the log file (0 = unlimited)") + .withRequiredArg() + .ofType(Integer.class) + .defaultsTo(0) + .describedAs("Max log size"); + + acceptsAll(asList("log-count"), "Specified how many log files to cycle through") + .withRequiredArg() + .ofType(Integer.class) + .defaultsTo(1) + .describedAs("Log count"); + + acceptsAll(asList("log-append"), "Whether to append to the log file") + .withRequiredArg() + .ofType(Boolean.class) + .defaultsTo(true) + .describedAs("Log append"); + + acceptsAll(asList("b", "bukkit-settings"), "File for bukkit settings") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File("bukkit.yml")) + .describedAs("Yml file"); + + acceptsAll(asList("debug-config"), "Don't load Poseidon.yml, but generate a new one with all the default values"); + + acceptsAll(asList("nojline"), "Disables jline and emulates the vanilla console"); + + acceptsAll(asList("nogui"), "Some modern panels like to pass this thru. Just ignore it"); + + acceptsAll(asList("v", "version"), "Show the CraftBukkit Version"); + } + }; + + OptionSet options = null; + + try { + options = parser.parse(args); + } catch (joptsimple.OptionException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage()); + } + + if ((options == null) || (options.has("?"))) { + try { + parser.printHelpOn(System.out); + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } else if (options.has("v")) { + System.out.println(CraftServer.class.getPackage().getImplementationVersion()); + } else { + try { + useJline = !"jline.UnsupportedTerminal".equals(System.getProperty("jline.terminal")); + + if (options.has("nojline")) { + System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); + System.setProperty("user.language", "en"); + useJline = false; + } + + MinecraftServer.main(options); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + + private static List asList(String... params) { + return Arrays.asList(params); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/PortalTravelAgent.java b/src/main/java/org/bukkit/craftbukkit/PortalTravelAgent.java new file mode 100644 index 0000000..643cc33 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/PortalTravelAgent.java @@ -0,0 +1,378 @@ +package org.bukkit.craftbukkit; + +import net.minecraft.server.Block; +import net.minecraft.server.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.TravelAgent; +import org.bukkit.event.world.PortalCreateEvent; + +import java.util.Random; + +public class PortalTravelAgent implements TravelAgent { + + private Random random = new Random(); + + private int searchRadius = 128; + private int creationRadius = 14; // 16 -> 14 + private boolean canCreatePortal = true; + + public PortalTravelAgent() { } + + public Location findOrCreate(Location location) { + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + worldServer.chunkProviderServer.forceChunkLoad = true; + // Attempt to find a Portal. + Location resultLocation = this.findPortal(location); + // If a Portal cannot be found we will attempt to create one. + if (resultLocation == null) { + // Attempt to create a portal, return if it was successful or not. + if (this.canCreatePortal && this.createPortal(location)) { + // Now find that portals location. + resultLocation = this.findPortal(location); + } else { + // Fallback onto the original location. + resultLocation = location; + } + } + worldServer.chunkProviderServer.forceChunkLoad = false; + // Return our resulting portal location. + return resultLocation; + } + + public Location findPortal(Location location) { + net.minecraft.server.World world = ((CraftWorld) location.getWorld()).getHandle(); + // short short1 = 128; + double d0 = -1.0D; + int i = 0; + int j = 0; + int k = 0; + int l = location.getBlockX(); + int i1 = location.getBlockZ(); + + double d1; + + for (int j1 = l - this.searchRadius; j1 <= l + this.searchRadius; ++j1) { + double d2 = (double) j1 + 0.5D - location.getX(); + + for (int k1 = i1 - this.searchRadius; k1 <= i1 + this.searchRadius; ++k1) { + double d3 = (double) k1 + 0.5D - location.getZ(); + + for (int l1 = 127; l1 >= 0; --l1) { + if (world.getTypeId(j1, l1, k1) == Block.PORTAL.id) { + while (world.getTypeId(j1, l1 - 1, k1) == Block.PORTAL.id) { + --l1; + } + + d1 = (double) l1 + 0.5D - location.getY(); + double d4 = d2 * d2 + d1 * d1 + d3 * d3; + + if (d0 < 0.0D || d4 < d0) { + d0 = d4; + i = j1; + j = l1; + k = k1; + } + } + } + } + } + + if (d0 >= 0.0D) { + double d5 = (double) i + 0.5D; + double d6 = (double) j + 0.5D; + + d1 = (double) k + 0.5D; + if (world.getTypeId(i - 1, j, k) == Block.PORTAL.id) { + d5 -= 0.5D; + } + + if (world.getTypeId(i + 1, j, k) == Block.PORTAL.id) { + d5 += 0.5D; + } + + if (world.getTypeId(i, j, k - 1) == Block.PORTAL.id) { + d1 -= 0.5D; + } + + if (world.getTypeId(i, j, k + 1) == Block.PORTAL.id) { + d1 += 0.5D; + } + + return new Location(location.getWorld(), d5, d6, d1, location.getYaw(), location.getPitch()); + } else { + return null; + } + } + + public boolean createPortal(Location location) { + net.minecraft.server.World world = ((CraftWorld) location.getWorld()).getHandle(); + // byte b0 = 16; + double d0 = -1.0D; + int i = location.getBlockX(); + int j = location.getBlockY(); + int k = location.getBlockZ(); + int l = i; + int i1 = j; + int j1 = k; + int k1 = 0; + int l1 = this.random.nextInt(4); + + int i2; + double d1; + int j2; + double d2; + int k2; + int l2; + int i3; + int j3; + int k3; + int l3; + int i4; + int j4; + int k4; + double d3; + double d4; + + for (i2 = i - this.creationRadius; i2 <= i + this.creationRadius; ++i2) { + d1 = (double) i2 + 0.5D - location.getX(); + + for (j2 = k - this.creationRadius; j2 <= k + this.creationRadius; ++j2) { + d2 = (double) j2 + 0.5D - location.getZ(); + + label271: + for (l2 = 127; l2 >= 0; --l2) { + if (world.isEmpty(i2, l2, j2)) { + while (l2 > 0 && world.isEmpty(i2, l2 - 1, j2)) { + --l2; + } + + for (k2 = l1; k2 < l1 + 4; ++k2) { + j3 = k2 % 2; + i3 = 1 - j3; + if (k2 % 4 >= 2) { + j3 = -j3; + i3 = -i3; + } + + for (l3 = 0; l3 < 3; ++l3) { + for (k3 = 0; k3 < 4; ++k3) { + for (j4 = -1; j4 < 5; ++j4) { + i4 = i2 + (k3 - 1) * j3 + l3 * i3; + k4 = l2 + j4; + int l4 = j2 + (k3 - 1) * i3 - l3 * j3; + + if (j4 < 0 && !world.getMaterial(i4, k4, l4).isBuildable() || j4 >= 0 && !world.isEmpty(i4, k4, l4)) { + continue label271; + } + } + } + } + + d3 = (double) l2 + 0.5D - location.getY(); + d4 = d1 * d1 + d3 * d3 + d2 * d2; + if (d0 < 0.0D || d4 < d0) { + d0 = d4; + l = i2; + i1 = l2 + 1; + j1 = j2; + k1 = k2 % 4; + } + } + } + } + } + } + + if (d0 < 0.0D) { + for (i2 = i - this.creationRadius; i2 <= i + this.creationRadius; ++i2) { + d1 = (double) i2 + 0.5D - location.getX(); + + for (j2 = k - this.creationRadius; j2 <= k + this.creationRadius; ++j2) { + d2 = (double) j2 + 0.5D - location.getZ(); + + label219: + for (l2 = 127; l2 >= 0; --l2) { + if (world.isEmpty(i2, l2, j2)) { + while (l2 > 0 && world.isEmpty(i2, l2 - 1, j2)) { + --l2; + } + + for (k2 = l1; k2 < l1 + 2; ++k2) { + j3 = k2 % 2; + i3 = 1 - j3; + + for (l3 = 0; l3 < 4; ++l3) { + for (k3 = -1; k3 < 5; ++k3) { + j4 = i2 + (l3 - 1) * j3; + i4 = l2 + k3; + k4 = j2 + (l3 - 1) * i3; + if (k3 < 0 && !world.getMaterial(j4, i4, k4).isBuildable() || k3 >= 0 && !world.isEmpty(j4, i4, k4)) { + continue label219; + } + } + } + + d3 = (double) l2 + 0.5D - location.getY(); + d4 = d1 * d1 + d3 * d3 + d2 * d2; + if (d0 < 0.0D || d4 < d0) { + d0 = d4; + l = i2; + i1 = l2 + 1; + j1 = j2; + k1 = k2 % 2; + } + } + } + } + } + } + } + + int i5 = l; + int j5 = i1; + + j2 = j1; + int k5 = k1 % 2; + int l5 = 1 - k5; + + if (k1 % 4 >= 2) { + k5 = -k5; + l5 = -l5; + } + + boolean flag; + + // CraftBukkit start - portal create event + java.util.ArrayList blocks = new java.util.ArrayList(); + // Find out what blocks the portal is going to modify, duplicated from below + CraftWorld craftWorld = ((WorldServer) world).getWorld(); + + if (d0 < 0.0D) { + if (i1 < 70) { + i1 = 70; + } + + if (i1 > 118) { + i1 = 118; + } + + j5 = i1; + + for (l2 = -1; l2 <= 1; ++l2) { + for (k2 = 1; k2 < 3; ++k2) { + for (j3 = -1; j3 < 3; ++j3) { + i3 = i5 + (k2 - 1) * k5 + l2 * l5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5 - l2 * k5; + org.bukkit.block.Block b = craftWorld.getBlockAt(i3, l3, k3); + if (!blocks.contains(b)) { + blocks.add(b); + } + } + } + } + } + + for (l2 = 0; l2 < 4; ++l2) { + for (k2 = 0; k2 < 4; ++k2) { + for (j3 = -1; j3 < 4; ++j3) { + i3 = i5 + (k2 - 1) * k5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5; + org.bukkit.block.Block b = craftWorld.getBlockAt(i3, l3, k3); + if (!blocks.contains(b)) { + blocks.add(b); + } + } + } + } + + PortalCreateEvent event = new PortalCreateEvent(blocks, (org.bukkit.World) craftWorld); + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return false; + } + // CraftBukkit end + + if (d0 < 0.0D) { + if (i1 < 70) { + i1 = 70; + } + + if (i1 > 118) { + i1 = 118; + } + + j5 = i1; + + for (l2 = -1; l2 <= 1; ++l2) { + for (k2 = 1; k2 < 3; ++k2) { + for (j3 = -1; j3 < 3; ++j3) { + i3 = i5 + (k2 - 1) * k5 + l2 * l5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5 - l2 * k5; + flag = j3 < 0; + world.setTypeId(i3, l3, k3, flag ? Block.OBSIDIAN.id : 0); + } + } + } + } + + for (l2 = 0; l2 < 4; ++l2) { + world.suppressPhysics = true; + + for (k2 = 0; k2 < 4; ++k2) { + for (j3 = -1; j3 < 4; ++j3) { + i3 = i5 + (k2 - 1) * k5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5; + flag = k2 == 0 || k2 == 3 || j3 == -1 || j3 == 3; + world.setTypeId(i3, l3, k3, flag ? Block.OBSIDIAN.id : Block.PORTAL.id); + } + } + + world.suppressPhysics = false; + + for (k2 = 0; k2 < 4; ++k2) { + for (j3 = -1; j3 < 4; ++j3) { + i3 = i5 + (k2 - 1) * k5; + l3 = j5 + j3; + k3 = j2 + (k2 - 1) * l5; + world.applyPhysics(i3, l3, k3, world.getTypeId(i3, l3, k3)); + } + } + } + + return true; + } + + + + + public TravelAgent setSearchRadius(int radius) { + this.searchRadius = radius; + return this; + } + + public int getSearchRadius() { + return this.searchRadius; + } + + public TravelAgent setCreationRadius(int radius) { + this.creationRadius = radius < 2 ? 0 : radius - 2; + return this; + } + + public int getCreationRadius() { + return this.creationRadius; + } + + public boolean getCanCreatePortal() { + return this.canCreatePortal; + } + + public void setCanCreatePortal(boolean create) { + this.canCreatePortal = create; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/TextWrapper.java b/src/main/java/org/bukkit/craftbukkit/TextWrapper.java new file mode 100644 index 0000000..d219402 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/TextWrapper.java @@ -0,0 +1,122 @@ +package org.bukkit.craftbukkit; + +public class TextWrapper { + private static final int[] characterWidths = new int[] { + 1, 9, 9, 8, 8, 8, 8, 7, 9, 8, 9, 9, 8, 9, 9, 9, + 8, 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8, 9, 9, 9, + 4, 2, 5, 6, 6, 6, 6, 3, 5, 5, 5, 6, 2, 6, 2, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 5, 6, 5, 6, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 6, 6, + 3, 6, 6, 6, 6, 6, 5, 6, 6, 2, 6, 5, 3, 6, 6, 6, + 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 5, 2, 5, 7, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 3, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, + 6, 3, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 2, 6, 6, + 8, 9, 9, 6, 6, 6, 8, 8, 6, 8, 8, 8, 8, 8, 6, 6, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 5, 9, 9, + 8, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 9, 9, 6, 7, + 7, 7, 7, 7, 9, 6, 7, 8, 7, 6, 6, 9, 7, 6, 7, 1 + }; + public static final char COLOR_CHAR = '\u00A7'; + public static final int CHAT_WINDOW_WIDTH = 320; + public static final int CHAT_STRING_LENGTH = 119; + public static final String allowedChars = net.minecraft.server.FontAllowedCharacters.allowedCharacters; + + public static String[] wrapText(final String text) { + final StringBuilder out = new StringBuilder(); + char colorChar = 'f'; + int lineWidth = 0; + int lineLength = 0; + + // Go over the message char by char. + for (int i = 0; i < text.length(); i++) { + char ch = text.charAt(i); + + // Get the color + if (ch == COLOR_CHAR && i < text.length() - 1) { + // We might need a linebreak ... so ugly ;( + if (lineLength + 2 > CHAT_STRING_LENGTH) { + out.append('\n'); + lineLength = 0; + if (colorChar != 'f' && colorChar != 'F') { + out.append(COLOR_CHAR).append(colorChar); + lineLength += 2; + } + } + colorChar = text.charAt(++i); + out.append(COLOR_CHAR).append(colorChar); + lineLength += 2; + continue; + } + + // Figure out if it's allowed + int index = allowedChars.indexOf(ch); + if (index == -1) { + // Invalid character .. skip it. + continue; + } else { + // Sadly needed as the allowedChars string misses the first + index += 32; + } + + // Find the width + final int width = characterWidths[index]; + + // See if we need a linebreak + if (lineLength + 1 > CHAT_STRING_LENGTH || lineWidth + width >= CHAT_WINDOW_WIDTH) { + out.append('\n'); + lineLength = 0; + + // Re-apply the last color if it isn't the default + if (colorChar != 'f' && colorChar != 'F') { + out.append(COLOR_CHAR).append(colorChar); + lineLength += 2; + } + lineWidth = width; + } else { + lineWidth += width; + } + out.append(ch); + lineLength++; + } + + // Return it split + return out.toString().split("\n"); + } + + /** + * Calculates the width of a string in pixels based on Minecraft's character widths. + * The maximum width for chat is 320 pixels (Use CHAT_WINDOW_WIDTH). + * + * @param string The input string. + * @return The width of the string in pixels. + */ + public static int widthInPixels(final String text) { + if (text == null || text.isEmpty()) + return 0; + + int output = 0; + + // literally yoinked from above and removed unnecessary components. + for (int i = 0; i < text.length(); i++) { + char ch = text.charAt(i); + + if (ch == COLOR_CHAR && i < text.length() - 1) { + i++; + continue; + } + + int index = allowedChars.indexOf(ch); + if (index == -1) + continue; + + index += 32; // compensate for gap in allowed characters + + output += characterWidths[index]; + } + + return output; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/TrigMath.java b/src/main/java/org/bukkit/craftbukkit/TrigMath.java new file mode 100644 index 0000000..8e7147a --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/TrigMath.java @@ -0,0 +1,47 @@ +package org.bukkit.craftbukkit; +/** + * Credits for this class goes to user aioobe on stackoverflow.com + * Source: http://stackoverflow.com/questions/4454630/j2me-calculate-the-the-distance-between-2-latitude-and-longitude + * + */ +public class TrigMath { + + static final double sq2p1 = 2.414213562373095048802e0; + static final double sq2m1 = .414213562373095048802e0; + static final double p4 = .161536412982230228262e2; + static final double p3 = .26842548195503973794141e3; + static final double p2 = .11530293515404850115428136e4; + static final double p1 = .178040631643319697105464587e4; + static final double p0 = .89678597403663861959987488e3; + static final double q4 = .5895697050844462222791e2; + static final double q3 = .536265374031215315104235e3; + static final double q2 = .16667838148816337184521798e4; + static final double q1 = .207933497444540981287275926e4; + static final double q0 = .89678597403663861962481162e3; + static final double PIO2 = 1.5707963267948966135E0; + + private static double mxatan(double arg) { + double argsq = arg * arg, value; + + value = ((((p4 * argsq + p3) * argsq + p2) * argsq + p1) * argsq + p0); + value = value / (((((argsq + q4) * argsq + q3) * argsq + q2) * argsq + q1) * argsq + q0); + return value * arg; + } + + private static double msatan(double arg) { + return arg < sq2m1 ? mxatan(arg) + : arg > sq2p1 ? PIO2 - mxatan(1 / arg) + : PIO2 / 2 + mxatan((arg - 1) / (arg + 1)); + } + + public static double atan(double arg) { + return arg > 0 ? msatan(arg) : -msatan(-arg); + } + + public static double atan2(double arg1, double arg2) { + if (arg1 + arg2 == arg1) + return arg1 >= 0 ? PIO2 : -PIO2; + arg1 = atan(arg1 / arg2); + return arg2 < 0 ? arg1 <= 0 ? arg1 + Math.PI : arg1 - Math.PI : arg1; + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java new file mode 100644 index 0000000..419d84f --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -0,0 +1,312 @@ +package org.bukkit.craftbukkit.block; + +import net.minecraft.server.BiomeBase; +import net.minecraft.server.BlockRedstoneWire; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.*; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.util.BlockVector; + +public class CraftBlock implements Block { + private final CraftChunk chunk; + private final int x; + private final int y; + private final int z; + + public CraftBlock(CraftChunk chunk, int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + this.chunk = chunk; + } + + public World getWorld() { + return chunk.getWorld(); + } + + public Location getLocation() { + return new Location(getWorld(), x, y, z); + } + + public BlockVector getVector() { + return new BlockVector(x, y, z); + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } + + public Chunk getChunk() { + return chunk; + } + + public void setData(final byte data) { + chunk.getHandle().world.setData(x, y, z, data); + } + + public void setData(final byte data, boolean applyPhysics) { + if (applyPhysics) { + chunk.getHandle().world.setData(x, y, z, data); + } else { + chunk.getHandle().world.setRawData(x, y, z, data); + } + } + + public byte getData() { + return (byte) chunk.getHandle().getData(this.x & 0xF, this.y & 0x7F, this.z & 0xF); + } + + public void setType(final Material type) { + setTypeId(type.getId()); + } + + public boolean setTypeId(final int type) { + return chunk.getHandle().world.setTypeId(x, y, z, type); + } + + public boolean setTypeId(final int type, final boolean applyPhysics) { + if (applyPhysics) { + return setTypeId(type); + } else { + return chunk.getHandle().world.setRawTypeId(x, y, z, type); + } + } + + public boolean setTypeIdAndData(final int type, final byte data, final boolean applyPhysics) { + if (applyPhysics) { + return chunk.getHandle().world.setTypeIdAndData(x, y, z, type, data); + } else { + boolean success = chunk.getHandle().world.setRawTypeIdAndData(x, y, z, type, data); + if (success) { + chunk.getHandle().world.notify(x, y, z); + } + return success; + } + } + + public Material getType() { + return Material.getMaterial(getTypeId()); + } + + public int getTypeId() { + return chunk.getHandle().getTypeId(this.x & 0xF, this.y & 0x7F, this.z & 0xF); + } + + public byte getLightLevel() { + return (byte) chunk.getHandle().world.getLightLevel(this.x, this.y, this.z); + } + + public Block getFace(final BlockFace face) { + return getRelative(face, 1); + } + + public Block getFace(final BlockFace face, final int distance) { + return getRelative(face, distance); + } + + public Block getRelative(final int modX, final int modY, final int modZ) { + return getWorld().getBlockAt(getX() + modX, getY() + modY, getZ() + modZ); + } + + public Block getRelative(BlockFace face) { + return getRelative(face, 1); + } + + public Block getRelative(BlockFace face, int distance) { + return getRelative(face.getModX() * distance, face.getModY() * distance, face.getModZ() * distance); + } + + public BlockFace getFace(final Block block) { + BlockFace[] values = BlockFace.values(); + + for (BlockFace face : values) { + if ((this.getX() + face.getModX() == block.getX()) && + (this.getY() + face.getModY() == block.getY()) && + (this.getZ() + face.getModZ() == block.getZ()) + ) { + return face; + } + } + + return null; + } + + @Override + public String toString() { + return "CraftBlock{" + "chunk=" + chunk + "x=" + x + "y=" + y + "z=" + z + '}'; + } + + /** + * Notch uses a 0-5 to mean DOWN, UP, EAST, WEST, NORTH, SOUTH + * in that order all over. This method is convenience to convert for us. + * + * @return BlockFace the BlockFace represented by this number + */ + public static BlockFace notchToBlockFace(int notch) { + switch (notch) { + case 0: + return BlockFace.DOWN; + case 1: + return BlockFace.UP; + case 2: + return BlockFace.EAST; + case 3: + return BlockFace.WEST; + case 4: + return BlockFace.NORTH; + case 5: + return BlockFace.SOUTH; + default: + return BlockFace.SELF; + } + } + + public static int blockFaceToNotch(BlockFace face) { + switch(face) { + case DOWN: + return 0; + case UP: + return 1; + case EAST: + return 2; + case WEST: + return 3; + case NORTH: + return 4; + case SOUTH: + return 5; + default: + return 7; // Good as anything here, but technically invalid + } + } + + public BlockState getState() { + Material material = getType(); + + switch (material) { + case SIGN: + case SIGN_POST: + case WALL_SIGN: + return new CraftSign(this); + case CHEST: + return new CraftChest(this); + case BURNING_FURNACE: + case FURNACE: + return new CraftFurnace(this); + case DISPENSER: + return new CraftDispenser(this); + case MOB_SPAWNER: + return new CraftCreatureSpawner(this); + case NOTE_BLOCK: + return new CraftNoteBlock(this); + default: + return new CraftBlockState(this); + } + } + + public Biome getBiome() { + return biomeBaseToBiome(chunk.getHandle().world.getWorldChunkManager().getBiome(x, z)); + } + + public static final Biome biomeBaseToBiome(BiomeBase base) { + if (base == BiomeBase.RAINFOREST) { + return Biome.RAINFOREST; + } else if (base == BiomeBase.SWAMPLAND) { + return Biome.SWAMPLAND; + } else if (base == BiomeBase.SEASONAL_FOREST) { + return Biome.SEASONAL_FOREST; + } else if (base == BiomeBase.FOREST) { + return Biome.FOREST; + } else if (base == BiomeBase.SAVANNA) { + return Biome.SAVANNA; + } else if (base == BiomeBase.SHRUBLAND) { + return Biome.SHRUBLAND; + } else if (base == BiomeBase.TAIGA) { + return Biome.TAIGA; + } else if (base == BiomeBase.DESERT) { + return Biome.DESERT; + } else if (base == BiomeBase.PLAINS) { + return Biome.PLAINS; + } else if (base == BiomeBase.ICE_DESERT) { + return Biome.ICE_DESERT; + } else if (base == BiomeBase.TUNDRA) { + return Biome.TUNDRA; + } else if (base == BiomeBase.HELL) { + return Biome.HELL; + } else if (base == BiomeBase.SKY) { + return Biome.SKY; + } + + return null; + } + + public double getTemperature() { + return getWorld().getTemperature(x, z); + } + + public double getHumidity() { + return getWorld().getHumidity(x, z); + } + + public boolean isBlockPowered() { + return chunk.getHandle().world.isBlockPowered(x, y, z); + } + + public boolean isBlockIndirectlyPowered() { + return chunk.getHandle().world.isBlockIndirectlyPowered(x, y, z); + } + + @Override + public boolean equals(Object o) { + return this == o; + } + + public boolean isBlockFacePowered(BlockFace face) { + return chunk.getHandle().world.isBlockFacePowered(x, y, z, blockFaceToNotch(face)); + } + + public boolean isBlockFaceIndirectlyPowered(BlockFace face) { + return chunk.getHandle().world.isBlockFaceIndirectlyPowered(x, y, z, blockFaceToNotch(face)); + } + + public int getBlockPower(BlockFace face) { + int power = 0; + BlockRedstoneWire wire = (BlockRedstoneWire) net.minecraft.server.Block.REDSTONE_WIRE; + net.minecraft.server.World world = chunk.getHandle().world; + if ((face == BlockFace.DOWN || face == BlockFace.SELF) && world.isBlockFacePowered(x, y - 1, z, 0)) power = wire.getPower(world, x, y - 1, z, power); + if ((face == BlockFace.UP || face == BlockFace.SELF) && world.isBlockFacePowered(x, y + 1, z, 1)) power = wire.getPower(world, x, y + 1, z, power); + if ((face == BlockFace.EAST || face == BlockFace.SELF) && world.isBlockFacePowered(x, y, z - 1, 2)) power = wire.getPower(world, x, y, z - 1, power); + if ((face == BlockFace.WEST || face == BlockFace.SELF) && world.isBlockFacePowered(x, y, z + 1, 3)) power = wire.getPower(world, x, y, z + 1, power); + if ((face == BlockFace.NORTH || face == BlockFace.SELF) && world.isBlockFacePowered(x - 1, y, z, 4)) power = wire.getPower(world, x - 1, y, z, power); + if ((face == BlockFace.SOUTH || face == BlockFace.SELF) && world.isBlockFacePowered(x + 1, y, z, 5)) power = wire.getPower(world, x + 1, y, z, power); + return power > 0 ? power : (face == BlockFace.SELF ? isBlockIndirectlyPowered() : isBlockFaceIndirectlyPowered(face)) ? 15 : 0; + } + + public int getBlockPower() { + return getBlockPower(BlockFace.SELF); + } + + public boolean isEmpty() { + return getType() == Material.AIR; + } + + public boolean isLiquid() { + return (getType() == Material.WATER) || (getType() == Material.STATIONARY_WATER) || (getType() == Material.LAVA) || (getType() == Material.STATIONARY_LAVA); + } + + public PistonMoveReaction getPistonMoveReaction() { + return PistonMoveReaction.getById(net.minecraft.server.Block.byId[this.getTypeId()].material.j()); + + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java new file mode 100644 index 0000000..f17ab0e --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java @@ -0,0 +1,208 @@ + +package org.bukkit.craftbukkit.block; + +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.material.MaterialData; + +public class CraftBlockState implements BlockState { + private final CraftWorld world; + private final CraftChunk chunk; + private final int x; + private final int y; + private final int z; + protected int type; + protected MaterialData data; + protected byte light; + + public CraftBlockState(final Block block) { + this.world = (CraftWorld) block.getWorld(); + this.x = block.getX(); + this.y = block.getY(); + this.z = block.getZ(); + this.type = block.getTypeId(); + this.light = block.getLightLevel(); + this.chunk = (CraftChunk) block.getChunk(); + + createData(block.getData()); + } + + public static CraftBlockState getBlockState(net.minecraft.server.World world, int x, int y, int z) { + return new CraftBlockState(world.getWorld().getBlockAt(x, y, z)); + } + + /** + * Gets the world which contains this Block + * + * @return World containing this block + */ + public World getWorld() { + return world; + } + + /** + * Gets the x-coordinate of this block + * + * @return x-coordinate + */ + public int getX() { + return x; + } + + /** + * Gets the y-coordinate of this block + * + * @return y-coordinate + */ + public int getY() { + return y; + } + + /** + * Gets the z-coordinate of this block + * + * @return z-coordinate + */ + public int getZ() { + return z; + } + + /** + * Gets the chunk which contains this block + * + * @return Containing Chunk + */ + public Chunk getChunk() { + return chunk; + } + + /** + * Sets the metadata for this block + * + * @param data New block specific metadata + */ + public void setData(final MaterialData data) { + Material mat = getType(); + + if ((mat == null) || (mat.getData() == null)) { + this.data = data; + } else { + if ((data.getClass() == mat.getData()) || (data.getClass() == MaterialData.class)) { + this.data = data; + } else { + throw new IllegalArgumentException("Provided data is not of type " + + mat.getData().getName() + ", found " + data.getClass().getName()); + } + } + } + + /** + * Gets the metadata for this block + * + * @return block specific metadata + */ + public MaterialData getData() { + return data; + } + + /** + * Sets the type of this block + * + * @param type Material to change this block to + */ + public void setType(final Material type) { + setTypeId(type.getId()); + } + + /** + * Sets the type-id of this block + * + * @param type Type-Id to change this block to + */ + public boolean setTypeId(final int type) { + this.type = type; + + createData((byte) 0); + return true; + } + + /** + * Gets the type of this block + * + * @return block type + */ + public Material getType() { + return Material.getMaterial(getTypeId()); + } + + /** + * Gets the type-id of this block + * + * @return block type-id + */ + public int getTypeId() { + return type; + } + + /** + * Gets the light level between 0-15 + * + * @return light level + */ + public byte getLightLevel() { + return light; + } + + public Block getBlock() { + return world.getBlockAt(x, y, z); + } + + public boolean update() { + return update(false); + } + + public boolean update(boolean force) { + Block block = getBlock(); + + synchronized (block) { + if (block.getType() != this.getType()) { + if (force) { + block.setTypeId(this.getTypeId()); + } else { + return false; + } + } + + block.setData(getRawData()); + } + + return true; + } + + private void createData(final byte data) { + Material mat = Material.getMaterial(type); + if (mat == null || mat.getData() == null) { + this.data = new MaterialData(type, data); + } else { + this.data = mat.getNewData(data); + } + } + + public byte getRawData() { + return data.getData(); + } + + public Location getLocation() { + return new Location(world, x, y, z); + } + + public void setData(byte data) { + createData(data); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java new file mode 100644 index 0000000..f5f7fa6 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java @@ -0,0 +1,35 @@ +package org.bukkit.craftbukkit.block; + +import net.minecraft.server.TileEntityChest; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.inventory.Inventory; + +public class CraftChest extends CraftBlockState implements Chest { + private final CraftWorld world; + private final TileEntityChest chest; + + public CraftChest(final Block block) { + super(block); + + world = (CraftWorld) block.getWorld(); + chest = (TileEntityChest) world.getTileEntityAt(getX(), getY(), getZ()); + } + + public Inventory getInventory() { + return new CraftInventory(chest); + } + + @Override + public boolean update(boolean force) { + boolean result = super.update(force); + + if (result) { + chest.update(); + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java new file mode 100644 index 0000000..2960e6f --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java @@ -0,0 +1,49 @@ +package org.bukkit.craftbukkit.block; + +import net.minecraft.server.TileEntityMobSpawner; +import org.bukkit.block.Block; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.CreatureType; + +public class CraftCreatureSpawner extends CraftBlockState implements CreatureSpawner { + private final CraftWorld world; + private final TileEntityMobSpawner spawner; + + public CraftCreatureSpawner(final Block block) { + super(block); + + world = (CraftWorld) block.getWorld(); + spawner = (TileEntityMobSpawner) world.getTileEntityAt(getX(), getY(), getZ()); + } + + public CreatureType getCreatureType() { + return CreatureType.fromName(spawner.mobName); + } + + public void setCreatureType(CreatureType creatureType) { + spawner.mobName = creatureType.getName(); + } + + public String getCreatureTypeId() { + return spawner.mobName; + } + + public void setCreatureTypeId(String creatureType) { + // Verify input + CreatureType type = CreatureType.fromName(creatureType); + if (type == null) { + return; + } + spawner.mobName = type.getName(); + } + + public int getDelay() { + return spawner.spawnDelay; + } + + public void setDelay(int delay) { + spawner.spawnDelay = delay; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java new file mode 100644 index 0000000..faf7a75 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java @@ -0,0 +1,54 @@ +package org.bukkit.craftbukkit.block; + +import net.minecraft.server.BlockDispenser; +import net.minecraft.server.TileEntityDispenser; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Dispenser; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.inventory.Inventory; + +import java.util.Random; + +public class CraftDispenser extends CraftBlockState implements Dispenser { + private final CraftWorld world; + private final TileEntityDispenser dispenser; + + public CraftDispenser(final Block block) { + super(block); + + world = (CraftWorld) block.getWorld(); + dispenser = (TileEntityDispenser) world.getTileEntityAt(getX(), getY(), getZ()); + } + + public Inventory getInventory() { + return new CraftInventory(dispenser); + } + + public boolean dispense() { + Block block = getBlock(); + + synchronized (block) { + if (block.getType() == Material.DISPENSER) { + BlockDispenser dispense = (BlockDispenser) net.minecraft.server.Block.DISPENSER; + + dispense.dispense(world.getHandle(), getX(), getY(), getZ(), new Random()); + return true; + } else { + return false; + } + } + } + + @Override + public boolean update(boolean force) { + boolean result = super.update(force); + + if (result) { + dispenser.update(); + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java new file mode 100644 index 0000000..dcf0fe1 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java @@ -0,0 +1,51 @@ +package org.bukkit.craftbukkit.block; + +import net.minecraft.server.TileEntityFurnace; +import org.bukkit.block.Block; +import org.bukkit.block.Furnace; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.inventory.Inventory; + +public class CraftFurnace extends CraftBlockState implements Furnace { + private final CraftWorld world; + private final TileEntityFurnace furnace; + + public CraftFurnace(final Block block) { + super(block); + + world = (CraftWorld) block.getWorld(); + furnace = (TileEntityFurnace) world.getTileEntityAt(getX(), getY(), getZ()); + } + + public Inventory getInventory() { + return new CraftInventory(furnace); + } + + @Override + public boolean update(boolean force) { + boolean result = super.update(force); + + if (result) { + furnace.update(); + } + + return result; + } + + public short getBurnTime() { + return (short) furnace.burnTime; + } + + public void setBurnTime(short burnTime) { + furnace.burnTime = burnTime; + } + + public short getCookTime() { + return (short) furnace.cookTime; + } + + public void setCookTime(short cookTime) { + furnace.cookTime = cookTime; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java new file mode 100644 index 0000000..445bbda --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java @@ -0,0 +1,76 @@ +package org.bukkit.craftbukkit.block; + +import net.minecraft.server.TileEntityNote; +import org.bukkit.Instrument; +import org.bukkit.Material; +import org.bukkit.Note; +import org.bukkit.block.Block; +import org.bukkit.block.NoteBlock; +import org.bukkit.craftbukkit.CraftWorld; + +public class CraftNoteBlock extends CraftBlockState implements NoteBlock { + private final CraftWorld world; + private final TileEntityNote note; + + public CraftNoteBlock(final Block block) { + super(block); + + world = (CraftWorld) block.getWorld(); + note = (TileEntityNote) world.getTileEntityAt(getX(), getY(), getZ()); + } + + public Note getNote() { + return new Note(note.note); + } + + public byte getRawNote() { + return note.note; + } + + public void setNote(Note n) { + note.note = n.getId(); + } + + public void setRawNote(byte n) { + note.note = n; + } + + public boolean play() { + Block block = getBlock(); + + synchronized (block) { + if (block.getType() == Material.NOTE_BLOCK) { + note.play(world.getHandle(), getX(), getY(), getZ()); + return true; + } else { + return false; + } + } + } + + public boolean play(byte instrument, byte note) { + Block block = getBlock(); + + synchronized (block) { + if (block.getType() == Material.NOTE_BLOCK) { + world.getHandle().playNote(getX(), getY(), getZ(), instrument, note); + return true; + } else { + return false; + } + } + } + + public boolean play(Instrument instrument, Note note) { + Block block = getBlock(); + + synchronized (block) { + if (block.getType() == Material.NOTE_BLOCK) { + world.getHandle().playNote(getX(), getY(), getZ(), instrument.getType(), note.getId()); + return true; + } else { + return false; + } + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java new file mode 100644 index 0000000..4923887 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java @@ -0,0 +1,41 @@ +package org.bukkit.craftbukkit.block; + +import net.minecraft.server.TileEntitySign; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.craftbukkit.CraftWorld; + +public class CraftSign extends CraftBlockState implements Sign { + private final CraftWorld world; + private final TileEntitySign sign; + + public CraftSign(final Block block) { + super(block); + + world = (CraftWorld) block.getWorld(); + sign = (TileEntitySign) world.getTileEntityAt(getX(), getY(), getZ()); + } + + public String[] getLines() { + return sign.lines; + } + + public String getLine(int index) throws IndexOutOfBoundsException { + return sign.lines[index]; + } + + public void setLine(int index, String line) throws IndexOutOfBoundsException { + sign.lines[index] = line; + } + + @Override + public boolean update(boolean force) { + boolean result = super.update(force); + + if (result) { + sign.update(); + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java b/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java new file mode 100644 index 0000000..76e1af3 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java @@ -0,0 +1,59 @@ +package org.bukkit.craftbukkit.command; + +import jline.ANSIBuffer.ANSICodes; +import jline.ConsoleReader; +import jline.Terminal; +import org.bukkit.ChatColor; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.craftbukkit.CraftServer; + +import java.util.EnumMap; +import java.util.Map; + +public class ColouredConsoleSender extends ConsoleCommandSender { + private final ConsoleReader reader; + private final Terminal terminal; + private final Map replacements = new EnumMap(ChatColor.class); + private final ChatColor[] colors = ChatColor.values(); + + public ColouredConsoleSender(CraftServer server) { + super(server); + this.reader = server.getReader(); + this.terminal = reader.getTerminal(); + + replacements.put(ChatColor.BLACK, ANSICodes.attrib(0)); + replacements.put(ChatColor.DARK_BLUE, ANSICodes.attrib(34)); + replacements.put(ChatColor.DARK_GREEN, ANSICodes.attrib(32)); + replacements.put(ChatColor.DARK_AQUA, ANSICodes.attrib(36)); + replacements.put(ChatColor.DARK_RED, ANSICodes.attrib(31)); + replacements.put(ChatColor.DARK_PURPLE, ANSICodes.attrib(35)); + replacements.put(ChatColor.GOLD, ANSICodes.attrib(33)); + replacements.put(ChatColor.GRAY, ANSICodes.attrib(37)); + replacements.put(ChatColor.DARK_GRAY, ANSICodes.attrib(0)); + replacements.put(ChatColor.BLUE, ANSICodes.attrib(34)); + replacements.put(ChatColor.GREEN, ANSICodes.attrib(32)); + replacements.put(ChatColor.AQUA, ANSICodes.attrib(36)); + replacements.put(ChatColor.RED, ANSICodes.attrib(31)); + replacements.put(ChatColor.LIGHT_PURPLE, ANSICodes.attrib(35)); + replacements.put(ChatColor.YELLOW, ANSICodes.attrib(33)); + replacements.put(ChatColor.WHITE, ANSICodes.attrib(37)); + } + + @Override + public void sendMessage(String message) { + if (terminal.isANSISupported()) { + String result = message; + + for (ChatColor color : colors) { + if (replacements.containsKey(color)) { + result = result.replaceAll(color.toString(), replacements.get(color)); + } else { + result = result.replaceAll(color.toString(), ""); + } + } + System.out.println(result + ANSICodes.attrib(0)); + } else { + super.sendMessage(message); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/command/ServerCommandListener.java b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandListener.java new file mode 100644 index 0000000..32738c2 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandListener.java @@ -0,0 +1,35 @@ +package org.bukkit.craftbukkit.command; + +import net.minecraft.server.ICommandListener; +import org.bukkit.command.CommandSender; + +import java.lang.reflect.Method; + +public class ServerCommandListener implements ICommandListener { + private final CommandSender commandSender; + private final String prefix; + + public ServerCommandListener(CommandSender commandSender) { + this.commandSender = commandSender; + String[] parts = commandSender.getClass().getName().split("\\."); + this.prefix = parts[parts.length-1]; + } + + public void sendMessage(String msg) { + this.commandSender.sendMessage(msg); + } + + public CommandSender getSender() { + return commandSender; + } + + public String getName() { + try { + Method getName = commandSender.getClass().getMethod("getName"); + + return (String) getName.invoke(commandSender); + } catch (Exception e) {} + + return this.prefix; + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java new file mode 100644 index 0000000..7c16255 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java @@ -0,0 +1,23 @@ +package org.bukkit.craftbukkit.entity; + +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Projectile; + +public abstract class AbstractProjectile extends CraftEntity implements Projectile { + + private boolean doesBounce; + + public AbstractProjectile(CraftServer server, net.minecraft.server.Entity entity) { + super(server, entity); + doesBounce = false; + } + + public boolean doesBounce() { + return doesBounce; + } + + public void setBounce(boolean doesBounce) { + this.doesBounce = doesBounce; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAnimals.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAnimals.java new file mode 100644 index 0000000..4f9264c --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAnimals.java @@ -0,0 +1,22 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityAnimal; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Animals; + +public class CraftAnimals extends CraftCreature implements Animals { + + public CraftAnimals(CraftServer server, EntityAnimal entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftAnimals"; + } + + @Override + public EntityAnimal getHandle() { + return (EntityAnimal) entity; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java new file mode 100644 index 0000000..aa8f82e --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java @@ -0,0 +1,34 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityArrow; +import net.minecraft.server.EntityLiving; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.LivingEntity; + +public class CraftArrow extends AbstractProjectile implements Arrow { + + public CraftArrow(CraftServer server, EntityArrow entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftArrow"; + } + + public LivingEntity getShooter() { + if (((EntityArrow) getHandle()).shooter != null) { + return (LivingEntity) ((EntityArrow) getHandle()).shooter.getBukkitEntity(); + } + + return null; + + } + + public void setShooter(LivingEntity shooter) { + if (shooter instanceof CraftLivingEntity) { + ((EntityArrow) getHandle()).shooter = (EntityLiving) ((CraftLivingEntity) shooter).entity; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java new file mode 100644 index 0000000..284fdd7 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java @@ -0,0 +1,29 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityBoat; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Boat; + +public class CraftBoat extends CraftVehicle implements Boat { + protected EntityBoat boat; + + public CraftBoat(CraftServer server, EntityBoat entity) { + super(server, entity); + boat = entity; + } + + public double getMaxSpeed() { + return boat.maxSpeed; + } + + public void setMaxSpeed(double speed) { + if (speed >= 0D) { + boat.maxSpeed = speed; + } + } + + @Override + public String toString() { + return "CraftBoat"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java new file mode 100644 index 0000000..84d01e1 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java @@ -0,0 +1,17 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityChicken; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Chicken; + +public class CraftChicken extends CraftAnimals implements Chicken { + + public CraftChicken(CraftServer server, EntityChicken entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftChicken"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCow.java new file mode 100644 index 0000000..4136c99 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCow.java @@ -0,0 +1,17 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityCow; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Cow; + +public class CraftCow extends CraftAnimals implements Cow { + + public CraftCow(CraftServer server, EntityCow entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftCow"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCreature.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCreature.java new file mode 100644 index 0000000..e4f2636 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCreature.java @@ -0,0 +1,40 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityCreature; +import net.minecraft.server.EntityLiving; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Creature; +import org.bukkit.entity.LivingEntity; + +public class CraftCreature extends CraftLivingEntity implements Creature { + public CraftCreature(CraftServer server, EntityCreature entity) { + super(server, entity); + } + + public void setTarget(LivingEntity target) { + EntityCreature entity = getHandle(); + if (target == null) { + entity.target = null; + } else if (target instanceof CraftLivingEntity) { + EntityLiving victim = ((CraftLivingEntity) target).getHandle(); + entity.target = victim; + entity.pathEntity = entity.world.findPath(entity, entity.target, 16.0F); + } + } + + public CraftLivingEntity getTarget() { + if (getHandle().target == null) return null; + + return (CraftLivingEntity) getHandle().target.getBukkitEntity(); + } + + @Override + public EntityCreature getHandle() { + return (EntityCreature) entity; + } + + @Override + public String toString() { + return "CraftCreature"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCreeper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCreeper.java new file mode 100644 index 0000000..764212d --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCreeper.java @@ -0,0 +1,53 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityCreeper; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Creeper; +import org.bukkit.event.entity.CreeperPowerEvent; + +public class CraftCreeper extends CraftMonster implements Creeper { + + public CraftCreeper(CraftServer server, EntityCreeper entity) { + super(server, entity); + } + + @Override + public EntityCreeper getHandle() { + return (EntityCreeper) super.getHandle(); + } + + @Override + public String toString() { + return "CraftCreeper"; + } + + public boolean isPowered() { + return getHandle().isPowered(); + } + + public void setPowered(boolean powered) { + // CraftBukkit start + CraftServer server = this.server; + org.bukkit.entity.Entity entity = this.getHandle().getBukkitEntity(); + + if (powered) { + CreeperPowerEvent event = new CreeperPowerEvent(entity, CreeperPowerEvent.PowerCause.SET_ON); + server.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + getHandle().setPowered(true); + } + } else { + CreeperPowerEvent event = new CreeperPowerEvent(entity, CreeperPowerEvent.PowerCause.SET_OFF); + server.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + getHandle().setPowered(false); + } + } + + // CraftBukkit end + + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEgg.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEgg.java new file mode 100644 index 0000000..c65f96b --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEgg.java @@ -0,0 +1,34 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityEgg; +import net.minecraft.server.EntityLiving; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Egg; +import org.bukkit.entity.LivingEntity; + +public class CraftEgg extends AbstractProjectile implements Egg { + + public CraftEgg(CraftServer server, EntityEgg entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftEgg"; + } + + public LivingEntity getShooter() { + if (((EntityEgg) getHandle()).thrower != null) { + return (LivingEntity) ((EntityEgg) getHandle()).thrower.getBukkitEntity(); + } + + return null; + + } + + public void setShooter(LivingEntity shooter) { + if (shooter instanceof CraftLivingEntity) { + ((EntityEgg) getHandle()).thrower = (EntityLiving) ((CraftLivingEntity) shooter).entity; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java new file mode 100644 index 0000000..509b9d8 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -0,0 +1,281 @@ +package org.bukkit.craftbukkit.entity; + +import com.google.common.collect.MapMaker; +import net.minecraft.server.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.util.Vector; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public abstract class CraftEntity implements org.bukkit.entity.Entity { + private static final Map players = new MapMaker().softValues().makeMap(); + protected final CraftServer server; + protected Entity entity; + private EntityDamageEvent lastDamageEvent; + + public CraftEntity(final CraftServer server, final Entity entity) { + this.server = server; + this.entity = entity; + } + + public static CraftEntity getEntity(CraftServer server, Entity entity) { + /** + * Order is *EXTREMELY* important -- keep it right! =D + */ + if (entity instanceof EntityLiving) { + // Players + if (entity instanceof EntityHuman) { + if (entity instanceof EntityPlayer) { return getPlayer((EntityPlayer)entity); } + else { return new CraftHumanEntity(server, (EntityHuman) entity); } + } + else if (entity instanceof EntityCreature) { + // Animals + if (entity instanceof EntityAnimal) { + if (entity instanceof EntityChicken) { return new CraftChicken(server, (EntityChicken) entity); } + else if (entity instanceof EntityCow) { return new CraftCow(server, (EntityCow) entity); } + else if (entity instanceof EntityPig) { return new CraftPig(server, (EntityPig) entity); } + else if (entity instanceof EntityWolf) { return new CraftWolf(server, (EntityWolf) entity); } + else if (entity instanceof EntitySheep) { return new CraftSheep(server, (EntitySheep) entity); } + else { return new CraftAnimals(server, (EntityAnimal) entity); } + } + // Monsters + else if (entity instanceof EntityMonster) { + if (entity instanceof EntityZombie) { + if (entity instanceof EntityPigZombie) { return new CraftPigZombie(server, (EntityPigZombie) entity); } + else { return new CraftZombie(server, (EntityZombie) entity); } + } + else if (entity instanceof EntityCreeper) { return new CraftCreeper(server, (EntityCreeper) entity); } + else if (entity instanceof EntityGiantZombie) { return new CraftGiant(server, (EntityGiantZombie) entity); } + else if (entity instanceof EntitySkeleton) { return new CraftSkeleton(server, (EntitySkeleton) entity); } + else if (entity instanceof EntitySpider) { return new CraftSpider(server, (EntitySpider) entity); } + + else { return new CraftMonster(server, (EntityMonster) entity); } + } + // Water Animals + else if (entity instanceof EntityWaterAnimal) { + if (entity instanceof EntitySquid) { return new CraftSquid(server, (EntitySquid) entity); } + else { return new CraftWaterMob(server, (EntityWaterAnimal) entity); } + } + else { return new CraftCreature(server, (EntityCreature) entity); } + } + // Slimes are a special (and broken) case + else if (entity instanceof EntitySlime) { return new CraftSlime(server, (EntitySlime) entity); } + // Flying + else if (entity instanceof EntityFlying) { + if (entity instanceof EntityGhast) { return new CraftGhast(server, (EntityGhast) entity); } + else { return new CraftFlying(server, (EntityFlying) entity); } + } + else { return new CraftLivingEntity(server, (EntityLiving) entity); } + } + else if (entity instanceof EntityArrow) { return new CraftArrow(server, (EntityArrow) entity); } + else if (entity instanceof EntityBoat) { return new CraftBoat(server, (EntityBoat) entity); } + else if (entity instanceof EntityEgg) { return new CraftEgg(server, (EntityEgg) entity); } + else if (entity instanceof EntityFallingSand) { return new CraftFallingSand(server, (EntityFallingSand) entity); } + else if (entity instanceof EntityFireball) { return new CraftFireball(server, (EntityFireball) entity); } + else if (entity instanceof EntityFish) { return new CraftFish(server, (EntityFish) entity); } + else if (entity instanceof EntityItem) { return new CraftItem(server, (EntityItem) entity); } + else if (entity instanceof EntityWeather) { + if (entity instanceof EntityWeatherStorm) { + return new CraftLightningStrike(server, (EntityWeatherStorm)entity); + } else { + return new CraftWeather(server, (EntityWeather)entity); + } + } + else if (entity instanceof EntityMinecart) { + EntityMinecart mc = (EntityMinecart) entity; + if (mc.type == CraftMinecart.Type.StorageMinecart.getId()) { + return new CraftStorageMinecart(server, mc); + } else if (mc.type == CraftMinecart.Type.PoweredMinecart.getId()) { + return new CraftPoweredMinecart(server, mc); + } else { + return new CraftMinecart(server, mc); + } + } + else if (entity instanceof EntityPainting) { return new CraftPainting(server, (EntityPainting) entity); } + else if (entity instanceof EntitySnowball) { return new CraftSnowball(server, (EntitySnowball) entity); } + else if (entity instanceof EntityTNTPrimed) { return new CraftTNTPrimed(server, (EntityTNTPrimed) entity); } + else throw new IllegalArgumentException("Unknown entity"); + } + + public Location getLocation() { + return new Location(getWorld(), entity.locX, entity.locY, entity.locZ, entity.yaw, entity.pitch); + } + + public Vector getVelocity() { + return new Vector(entity.motX, entity.motY, entity.motZ); + } + + public void setVelocity(Vector vel) { + entity.motX = vel.getX(); + entity.motY = vel.getY(); + entity.motZ = vel.getZ(); + entity.velocityChanged = true; + } + + public World getWorld() { + return ((WorldServer) entity.world).getWorld(); + } + + public boolean teleport(Location location) { + entity.world = ((CraftWorld) location.getWorld()).getHandle(); + entity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + // entity.setLocation() throws no event, and so cannot be cancelled + return true; + } + + public boolean teleport(org.bukkit.entity.Entity destination) { + return teleport(destination.getLocation()); + } + + public List getNearbyEntities(double x, double y, double z) { + @SuppressWarnings("unchecked") + List notchEntityList = entity.world.b(entity, entity.boundingBox.b(x, y, z)); + List bukkitEntityList = new java.util.ArrayList(notchEntityList.size()); + + for (Entity e: notchEntityList) { + bukkitEntityList.add(e.getBukkitEntity()); + } + return bukkitEntityList; + } + + public int getEntityId() { + return entity.id; + } + + public int getFireTicks() { + return entity.fireTicks; + } + + public int getMaxFireTicks() { + return entity.maxFireTicks; + } + + public void setFireTicks(int ticks) { + entity.fireTicks = ticks; + } + + public void remove() { + entity.dead = true; + } + + public boolean isDead() { + return entity.dead; + } + + public Entity getHandle() { + return entity; + } + + public void setHandle(final Entity entity) { + this.entity = entity; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CraftEntity other = (CraftEntity) obj; + if (this.server != other.server && (this.server == null || !this.server.equals(other.server))) { + return false; + } + if (this.entity != other.entity && (this.entity == null || !this.entity.equals(other.entity))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 89 * hash + (this.server != null ? this.server.hashCode() : 0); + hash = 89 * hash + (this.entity != null ? this.entity.hashCode() : 0); + return hash; + } + + @Override + public String toString() { + return "CraftEntity{" + "id=" + getEntityId() + '}'; + } + + public Server getServer() { + return server; + } + + public Vector getMomentum() { + return getVelocity(); + } + + public void setMomentum(Vector value) { + setVelocity(value); + } + + public org.bukkit.entity.Entity getPassenger() { + return isEmpty() ? null : (CraftEntity) getHandle().passenger.getBukkitEntity(); + } + + public boolean setPassenger(org.bukkit.entity.Entity passenger) { + if (passenger instanceof CraftEntity) { + ((CraftEntity) passenger).getHandle().setPassengerOf(getHandle()); + return true; + } else { + return false; + } + } + + public boolean isEmpty() { + return getHandle().passenger == null; + } + + public boolean eject() { + if (getHandle().passenger == null) { + return false; + } + + getHandle().passenger.setPassengerOf(null); + return true; + } + + public float getFallDistance() { + return getHandle().fallDistance; + } + + public void setFallDistance(float distance) { + getHandle().fallDistance = distance; + } + + public void setLastDamageCause(EntityDamageEvent event) { + lastDamageEvent = event; + } + + public EntityDamageEvent getLastDamageCause() { + return lastDamageEvent; + } + + public UUID getUniqueId() { + return getHandle().uniqueId; + } + private static CraftPlayer getPlayer(EntityPlayer entity) { + CraftPlayer result = players.get(entity.name); + + if (result == null) { + result = new CraftPlayer((CraftServer) Bukkit.getServer(), entity); + players.put(entity.name, result); + } else { + result.setHandle(entity); + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingSand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingSand.java new file mode 100644 index 0000000..0913ba1 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingSand.java @@ -0,0 +1,17 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityFallingSand; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.FallingSand; + +public class CraftFallingSand extends CraftEntity implements FallingSand { + + public CraftFallingSand(CraftServer server, EntityFallingSand entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftFallingSand"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java new file mode 100644 index 0000000..f488e3a --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java @@ -0,0 +1,58 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityFireball; +import net.minecraft.server.EntityLiving; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Fireball; +import org.bukkit.entity.LivingEntity; +import org.bukkit.util.Vector; + +public class CraftFireball extends AbstractProjectile implements Fireball { + public CraftFireball(CraftServer server, EntityFireball entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftFireball"; + } + + public float getYield() { + return ((EntityFireball) getHandle()).yield; + } + + public boolean isIncendiary() { + return ((EntityFireball) getHandle()).isIncendiary; + } + + public void setIsIncendiary(boolean isIncendiary) { + ((EntityFireball) getHandle()).isIncendiary = isIncendiary; + } + + public void setYield(float yield) { + ((EntityFireball) getHandle()).yield = yield; + } + + public LivingEntity getShooter() { + if (((EntityFireball) getHandle()).shooter != null) { + return (LivingEntity) ((EntityFireball) getHandle()).shooter.getBukkitEntity(); + } + + return null; + + } + + public void setShooter(LivingEntity shooter) { + if (shooter instanceof CraftLivingEntity) { + ((EntityFireball) getHandle()).shooter = (EntityLiving) ((CraftLivingEntity) shooter).entity; + } + } + + public Vector getDirection() { + return new Vector(((EntityFireball) getHandle()).c, ((EntityFireball) getHandle()).d, ((EntityFireball) getHandle()).e); + } + + public void setDirection(Vector direction) { + ((EntityFireball) getHandle()).setDirection(direction.getX(), direction.getY(), direction.getZ()); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java new file mode 100644 index 0000000..fd93e4c --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java @@ -0,0 +1,34 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityFish; +import net.minecraft.server.EntityHuman; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Fish; +import org.bukkit.entity.LivingEntity; + +public class CraftFish extends AbstractProjectile implements Fish { + public CraftFish(CraftServer server, EntityFish entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftFish"; + } + + public LivingEntity getShooter() { + if (((EntityFish) getHandle()).owner != null) { + return (LivingEntity) ((EntityFish) getHandle()).owner.getBukkitEntity(); + } + + return null; + + } + + public void setShooter(LivingEntity shooter) { + if (shooter instanceof CraftHumanEntity) { + ((EntityFish) getHandle()).owner = (EntityHuman) ((CraftHumanEntity) shooter).entity; + } + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFlying.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFlying.java new file mode 100644 index 0000000..3426590 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFlying.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityFlying; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Flying; + +public class CraftFlying extends CraftLivingEntity implements Flying { + + public CraftFlying(CraftServer server, EntityFlying entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftFlying"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java new file mode 100644 index 0000000..3d0e70f --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityGhast; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Ghast; + +public class CraftGhast extends CraftFlying implements Ghast { + + public CraftGhast(CraftServer server, EntityGhast entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftGhast"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftGiant.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftGiant.java new file mode 100644 index 0000000..5b5ea20 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftGiant.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityGiantZombie; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Giant; + +public class CraftGiant extends CraftMonster implements Giant { + + public CraftGiant(CraftServer server, EntityGiantZombie entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftGiant"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java new file mode 100644 index 0000000..fea69d3 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -0,0 +1,130 @@ + +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityHuman; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.permissions.PermissibleBase; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; + +import java.util.Set; + +//import org.bukkit.GameMode; + +public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + private CraftInventoryPlayer inventory; + protected final PermissibleBase perm = new PermissibleBase(this); + private boolean op; + + public CraftHumanEntity(final CraftServer server, final EntityHuman entity) { + super(server, entity); + this.inventory = new CraftInventoryPlayer(entity.inventory); + } + + public String getName() { + return getHandle().name; + } + + @Override + public EntityHuman getHandle() { + return (EntityHuman) entity; + } + + public void setHandle(final EntityHuman entity) { + super.setHandle((EntityHuman) entity); + this.entity = entity; + this.inventory = new CraftInventoryPlayer(entity.inventory); + } + + public PlayerInventory getInventory() { + return inventory; + } + + public ItemStack getItemInHand() { + return getInventory().getItemInHand(); + } + + public void setItemInHand(ItemStack item) { + getInventory().setItemInHand(item); + } + + @Override + public String toString() { + return "CraftHumanEntity{" + "id=" + getEntityId() + "name=" + getName() + '}'; + } + + public boolean isSleeping() { + return getHandle().sleeping; + } + + public int getSleepTicks() { + return getHandle().sleepTicks; + } + + public boolean isOp() { + return op; + } + + public boolean isPermissionSet(String name) { + return perm.isPermissionSet(name); + } + + public boolean isPermissionSet(Permission perm) { + return this.perm.isPermissionSet(perm); + } + + public boolean hasPermission(String name) { + return perm.hasPermission(name); + } + + public boolean hasPermission(Permission perm) { + return this.perm.hasPermission(perm); + } + + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { + return perm.addAttachment(plugin, name, value); + } + + public PermissionAttachment addAttachment(Plugin plugin) { + return perm.addAttachment(plugin); + } + + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { + return perm.addAttachment(plugin, name, value, ticks); + } + + public PermissionAttachment addAttachment(Plugin plugin, int ticks) { + return perm.addAttachment(plugin, ticks); + } + + public void removeAttachment(PermissionAttachment attachment) { + perm.removeAttachment(attachment); + } + + public void recalculatePermissions() { + perm.recalculatePermissions(); + } + + public void setOp(boolean value) { + this.op = value; + perm.recalculatePermissions(); + } + + public Set getEffectivePermissions() { + return perm.getEffectivePermissions(); + } + +// public GameMode getGameMode() { +// return GameMode.SURVIVAL; +// } +// +// public void setGameMode(GameMode mode) { +// throw new UnsupportedOperationException("Not supported yet."); +// } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java new file mode 100644 index 0000000..922a885 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java @@ -0,0 +1,30 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityItem; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Item; +import org.bukkit.inventory.ItemStack; + +public class CraftItem extends CraftEntity implements Item { + private EntityItem item; + + public CraftItem(CraftServer server, EntityItem entity) { + super(server, entity); + this.item = entity; + } + + public ItemStack getItemStack() { + return new CraftItemStack(item.itemStack); + } + + public void setItemStack(ItemStack stack) { + item.itemStack = new net.minecraft.server.ItemStack(stack.getTypeId(), stack.getAmount(), stack.getDurability()); + } + + @Override + public String toString() { + return "CraftItem"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java new file mode 100644 index 0000000..7e37b39 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java @@ -0,0 +1,20 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityWeatherStorm; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.LightningStrike; + +public class CraftLightningStrike extends CraftEntity implements LightningStrike { + public CraftLightningStrike(final CraftServer server, final EntityWeatherStorm entity) { + super(server, entity); + } + + @Override + public EntityWeatherStorm getHandle() { + return (EntityWeatherStorm) super.getHandle(); + } + + public boolean isEffect() { + return ((EntityWeatherStorm) super.getHandle()).isEffect; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java new file mode 100644 index 0000000..4e5dceb --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -0,0 +1,203 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.Entity; +import net.minecraft.server.*; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.*; +import org.bukkit.util.BlockIterator; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +public class CraftLivingEntity extends CraftEntity implements LivingEntity { + public CraftLivingEntity(final CraftServer server, final EntityLiving entity) { + super(server, entity); + } + + public int getHealth() { + return getHandle().health; + } + + public void setHealth(int health) { + if ((health < 0) || (health > 200)) { + throw new IllegalArgumentException("Health must be between 0 and 200"); + } + + if (entity instanceof EntityPlayer && health == 0) { + ((EntityPlayer) entity).die((Entity) null); + } + + getHandle().health = health; + } + + @Override + public EntityLiving getHandle() { + return (EntityLiving) entity; + } + + public void setHandle(final EntityLiving entity) { + super.setHandle((Entity) entity); + this.entity = entity; + } + + @Override + public String toString() { + return "CraftLivingEntity{" + "id=" + getEntityId() + '}'; + } + + public Egg throwEgg() { + net.minecraft.server.World world = ((CraftWorld) getWorld()).getHandle(); + EntityEgg egg = new EntityEgg(world, getHandle()); + + world.addEntity(egg); + return (Egg) egg.getBukkitEntity(); + } + + public Snowball throwSnowball() { + net.minecraft.server.World world = ((CraftWorld) getWorld()).getHandle(); + EntitySnowball snowball = new EntitySnowball(world, getHandle()); + + world.addEntity(snowball); + return (Snowball) snowball.getBukkitEntity(); + } + + public double getEyeHeight() { + return 1.0D; + } + + public double getEyeHeight(boolean ignoreSneaking) { + return getEyeHeight(); + } + + private List getLineOfSight(HashSet transparent, int maxDistance, int maxLength) { + if (maxDistance > 120) { + maxDistance = 120; + } + ArrayList blocks = new ArrayList(); + Iterator itr = new BlockIterator(this, maxDistance); + while (itr.hasNext()) { + Block block = itr.next(); + blocks.add(block); + if (maxLength != 0 && blocks.size() > maxLength) { + blocks.remove(0); + } + int id = block.getTypeId(); + if (transparent == null) { + if (id != 0) { + break; + } + } else { + if (!transparent.contains((byte) id)) { + break; + } + } + } + return blocks; + } + + public List getLineOfSight(HashSet transparent, int maxDistance) { + return getLineOfSight(transparent, maxDistance, 0); + } + + public Block getTargetBlock(HashSet transparent, int maxDistance) { + List blocks = getLineOfSight(transparent, maxDistance, 1); + return blocks.get(0); + } + + public List getLastTwoTargetBlocks(HashSet transparent, int maxDistance) { + return getLineOfSight(transparent, maxDistance, 2); + } + + public Arrow shootArrow() { + net.minecraft.server.World world = ((CraftWorld) getWorld()).getHandle(); + EntityArrow arrow = new EntityArrow(world, getHandle()); + + world.addEntity(arrow); + return (Arrow) arrow.getBukkitEntity(); + } + + public boolean isInsideVehicle() { + return getHandle().vehicle != null; + } + + public boolean leaveVehicle() { + if (getHandle().vehicle == null) { + return false; + } + + getHandle().setPassengerOf(null); + return true; + } + + public Vehicle getVehicle() { + if (getHandle().vehicle == null) { + return null; + } + + org.bukkit.entity.Entity vehicle = (getHandle().vehicle.getBukkitEntity()); + if (vehicle instanceof Vehicle) { + return (Vehicle) vehicle; + } + + return null; + } + + public int getRemainingAir() { + return getHandle().airTicks; + } + + public void setRemainingAir(int ticks) { + getHandle().airTicks = ticks; + } + + public int getMaximumAir() { + return getHandle().maxAirTicks; + } + + public void setMaximumAir(int ticks) { + getHandle().maxAirTicks = ticks; + } + + public void damage(int amount) { + entity.damageEntity((Entity) null, amount); + } + + public void damage(int amount, org.bukkit.entity.Entity source) { + entity.damageEntity(((CraftEntity) source).getHandle(), amount); + } + + public Location getEyeLocation() { + Location loc = getLocation(); + loc.setY(loc.getY() + getEyeHeight()); + return loc; + } + + public int getMaximumNoDamageTicks() { + return getHandle().maxNoDamageTicks; + } + + public void setMaximumNoDamageTicks(int ticks) { + getHandle().maxNoDamageTicks = ticks; + } + + public int getLastDamage() { + return getHandle().lastDamage; + } + + public void setLastDamage(int damage) { + getHandle().lastDamage = damage; + } + + public int getNoDamageTicks() { + return getHandle().noDamageTicks; + } + + public void setNoDamageTicks(int ticks) { + getHandle().noDamageTicks = ticks; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java new file mode 100644 index 0000000..35ba962 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java @@ -0,0 +1,87 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityMinecart; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Minecart; +import org.bukkit.util.Vector; + +public class CraftMinecart extends CraftVehicle implements Minecart { + /** + * Stores the minecart type id, which is used by Minecraft to differentiate + * minecart types. Here we use subclasses. + */ + public enum Type { + Minecart(0), + StorageMinecart(1), + PoweredMinecart(2); + + private final int id; + + private Type(int id) { + this.id = id; + } + + public int getId() { + return id; + } + } + + protected EntityMinecart minecart; + + public CraftMinecart(CraftServer server, EntityMinecart entity) { + super(server, entity); + minecart = entity; + } + + public void setDamage(int damage) { + minecart.damage = damage; + } + + public int getDamage() { + return minecart.damage; + } + + public double getMaxSpeed() { + return minecart.maxSpeed; + } + + public void setMaxSpeed(double speed) { + if (speed >= 0D) { + minecart.maxSpeed = speed; + } + } + + public boolean isSlowWhenEmpty() { + return minecart.slowWhenEmpty; + } + + public void setSlowWhenEmpty(boolean slow) { + minecart.slowWhenEmpty = slow; + } + + public Vector getFlyingVelocityMod() { + return new Vector(minecart.flyingX, minecart.flyingY, minecart.flyingZ); + } + + public void setFlyingVelocityMod(Vector flying) { + minecart.flyingX = flying.getX(); + minecart.flyingY = flying.getY(); + minecart.flyingZ = flying.getZ(); + } + + public Vector getDerailedVelocityMod() { + return new Vector(minecart.derailedX, minecart.derailedY, minecart.derailedZ); + } + + public void setDerailedVelocityMod(Vector derailed) { + minecart.derailedX = derailed.getX(); + minecart.derailedY = derailed.getY(); + minecart.derailedZ = derailed.getZ(); + } + + @Override + public String toString() { + return "CraftMinecart"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMonster.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMonster.java new file mode 100644 index 0000000..dd7bcd0 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMonster.java @@ -0,0 +1,22 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityMonster; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Monster; + +public class CraftMonster extends CraftCreature implements Monster { + + public CraftMonster(CraftServer server, EntityMonster entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftMonster"; + } + + @Override + public EntityMonster getHandle() { + return (EntityMonster) entity; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java new file mode 100644 index 0000000..a5f20ea --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityPainting; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Painting; + +public class CraftPainting extends CraftEntity implements Painting { + + public CraftPainting(CraftServer server, EntityPainting entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftPainting"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java new file mode 100644 index 0000000..78d5b87 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java @@ -0,0 +1,28 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityPig; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Pig; + +public class CraftPig extends CraftAnimals implements Pig { + public CraftPig(CraftServer server, EntityPig entity) { + super(server, entity); + } + + public boolean hasSaddle() { + return getHandle().hasSaddle(); + } + + public void setSaddle(boolean saddled) { + getHandle().setSaddle(saddled); + } + + public EntityPig getHandle() { + return (EntityPig) super.getHandle(); + } + + @Override + public String toString() { + return "CraftPig"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPigZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPigZombie.java new file mode 100644 index 0000000..115ae76 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPigZombie.java @@ -0,0 +1,39 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityPigZombie; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.PigZombie; + +public class CraftPigZombie extends CraftZombie implements PigZombie { + + public CraftPigZombie(CraftServer server, EntityPigZombie entity) { + super(server, entity); + } + + @Override + public EntityPigZombie getHandle() { + return (EntityPigZombie) super.getHandle(); + } + + @Override + public String toString() { + return "CraftPigZombie"; + } + + public int getAnger() { + return getHandle().angerLevel; + } + + public void setAnger(int level) { + getHandle().angerLevel = level; + } + + public void setAngry(boolean angry) { + setAnger(angry ? 400 : 0); + } + + public boolean isAngry() { + return getAnger() > 0; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java new file mode 100644 index 0000000..4e59da2 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -0,0 +1,440 @@ +package org.bukkit.craftbukkit.entity; + +import com.projectposeidon.ConnectionType; +import net.minecraft.server.*; +import org.bukkit.Achievement; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.*; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.map.CraftMapView; +import org.bukkit.craftbukkit.map.RenderData; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.map.MapView; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class CraftPlayer extends CraftHumanEntity implements Player { + private Set hiddenPlayers = new HashSet(); + + public CraftPlayer(CraftServer server, EntityPlayer entity) { + super(server, entity); + } + + @Override + public boolean isOp() { + return server.getHandle().isOp(getName()); + } + + @Override + public void setOp(boolean value) { + if (value == isOp()) return; + + if (value) { + server.getHandle().e(getName()); + } else { + server.getHandle().f(getName()); + } + + perm.recalculatePermissions(); + } + + public boolean isPlayer() { + return true; + } + + public boolean isOnline() { + for (Object obj : server.getHandle().players) { + EntityPlayer player = (EntityPlayer) obj; + if (player.name.equalsIgnoreCase(getName())) { + return true; + } + } + return false; + } + + public InetSocketAddress getAddress() { + SocketAddress addr = getHandle().netServerHandler.networkManager.getSocketAddress(); + if (addr instanceof InetSocketAddress) { + return (InetSocketAddress) addr; + } else { + return null; + } + } + + @Override + public EntityPlayer getHandle() { + return (EntityPlayer) entity; + } + + public double getEyeHeight() { + return getEyeHeight(false); + } + + public double getEyeHeight(boolean ignoreSneaking) { + if (ignoreSneaking) { + return 1.62D; + } else { + if (isSneaking()) { + return 1.42D; + } else { + return 1.62D; + } + } + } + + public void setHandle(final EntityPlayer entity) { + super.setHandle((EntityHuman) entity); + this.entity = entity; + } + + public void sendRawMessage(String message) { + try { + getHandle().netServerHandler.sendPacket(new Packet3Chat(message)); + } catch (NullPointerException exception) { + System.out.println("[Poseidon] Exception thrown when attempting to send packet to " + getName() + ". Does this player exist, or are they a phantom?????"); + exception.printStackTrace(); + } + } + + public void sendMessage(String message) { + this.sendRawMessage(message); + } + + public String getDisplayName() { + return getHandle().displayName; + } + + public void setDisplayName(final String name) { + getHandle().displayName = name; + } + + @Override + public String toString() { + return "CraftPlayer{" + "name=" + getName() + '}'; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CraftPlayer other = (CraftPlayer) obj; + if ((this.getName() == null) ? (other.getName() != null) : !this.getName().equals(other.getName())) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 97 * hash + (this.getName() != null ? this.getName().hashCode() : 0); + return hash; + } + + public void kickPlayer(String message) { + if (this.isOnline() && !getHandle().netServerHandler.disconnected) // Poseidon: Kick/Disconnect spam fix + getHandle().netServerHandler.disconnect(message == null ? "" : message); + } + + public void setCompassTarget(Location loc) { + // Do not directly assign here, from the packethandler we'll assign it. + getHandle().netServerHandler.sendPacket(new Packet6SpawnPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + } + + //Project Poseidon Start + public UUID getUniqueId() { + //return UUIDPlayerStorage.getInstance().getPlayerUUID(getName()); + return getHandle().playerUUID; + } + //Project Poseidon End + + public UUID getPlayerUUID() { + return getUniqueId(); + } + + public Location getCompassTarget() { + return getHandle().compassTarget; + } + + public void chat(String msg) { + getHandle().netServerHandler.chat(msg); + } + + public boolean performCommand(String command) { + return server.dispatchCommand(this, command); + } + + public void playNote(Location loc, byte instrument, byte note) { + getHandle().netServerHandler.sendPacket(new Packet54PlayNoteBlock(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), instrument, note)); + } + + public void playNote(Location loc, Instrument instrument, Note note) { + getHandle().netServerHandler.sendPacket(new Packet54PlayNoteBlock(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), instrument.getType(), note.getId())); + } + + public void playEffect(Location loc, Effect effect, int data) { + int packetData = effect.getId(); + Packet61 packet = new Packet61(packetData, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), data); + getHandle().netServerHandler.sendPacket(packet); + } + + public void sendBlockChange(Location loc, Material material, byte data) { + sendBlockChange(loc, material.getId(), data); + } + + public void sendBlockChange(Location loc, int material, byte data) { + Packet53BlockChange packet = new Packet53BlockChange(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), ((CraftWorld) loc.getWorld()).getHandle()); + + packet.material = material; + packet.data = data; + getHandle().netServerHandler.sendPacket(packet); + } + + public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) { + int x = loc.getBlockX(); + int y = loc.getBlockY(); + int z = loc.getBlockZ(); + + int cx = x >> 4; + int cz = z >> 4; + + if (sx <= 0 || sy <= 0 || sz <= 0) { + return false; + } + + if ((x + sx - 1) >> 4 != cx || (z + sz - 1) >> 4 != cz || y < 0 || y + sy > 128) { + return false; + } + + if (data.length != (sx * sy * sz * 5) / 2) { + return false; + } + + Packet51MapChunk packet = new Packet51MapChunk(x, y, z, sx, sy, sz, data); + + getHandle().netServerHandler.sendPacket(packet); + + return true; + } + + public void sendMap(MapView map) { + RenderData data = ((CraftMapView) map).render(this); + for (int x = 0; x < 128; ++x) { + byte[] bytes = new byte[131]; + bytes[1] = (byte) x; + for (int y = 0; y < 128; ++y) { + bytes[y + 3] = data.buffer[y * 128 + x]; + } + Packet131 packet = new Packet131((short) Material.MAP.getId(), map.getId(), bytes); + getHandle().netServerHandler.sendPacket(packet); + } + } + + @Override + public boolean teleport(Location location) { + // From = Players current Location + Location from = this.getLocation(); + // To = Players new Location if Teleport is Successful + Location to = location; + // Create & Call the Teleport Event. + PlayerTeleportEvent event = new PlayerTeleportEvent((Player) this, from, to); + server.getPluginManager().callEvent(event); + // Return False to inform the Plugin that the Teleport was unsuccessful/cancelled. + if (event.isCancelled() == true) { + return false; + } + // Update the From Location + from = event.getFrom(); + // Grab the new To Location dependent on whether the event was cancelled. + to = event.getTo(); + // Grab the To and From World Handles. + WorldServer fromWorld = ((CraftWorld) from.getWorld()).getHandle(); + WorldServer toWorld = ((CraftWorld) to.getWorld()).getHandle(); + // Grab the EntityPlayer + EntityPlayer entity = getHandle(); + + // Check if the fromWorld and toWorld are the same. + if (fromWorld == toWorld) { + entity.netServerHandler.teleport(to); + } else { + server.getHandle().moveToWorld(entity, toWorld.dimension, to); + } + return true; + } + + public void setSneaking(boolean sneak) { + getHandle().setSneak(sneak); + } + + public boolean isSneaking() { + return getHandle().isSneaking(); + } + + public void loadData() { + server.getHandle().playerFileData.b(getHandle()); + } + + public void saveData() { + server.getHandle().playerFileData.a(getHandle()); + } + + public void updateInventory() { + getHandle().updateInventory(getHandle().activeContainer); + } + + public void setSleepingIgnored(boolean isSleeping) { + getHandle().fauxSleeping = isSleeping; + ((CraftWorld) getWorld()).getHandle().checkSleepStatus(); + } + + public boolean isSleepingIgnored() { + return getHandle().fauxSleeping; + } + + public void awardAchievement(Achievement achievement) { + sendStatistic(achievement.getId(), 1); + } + + public void incrementStatistic(Statistic statistic) { + incrementStatistic(statistic, 1); + } + + public void incrementStatistic(Statistic statistic, int amount) { + sendStatistic(statistic.getId(), amount); + } + + public void incrementStatistic(Statistic statistic, Material material) { + incrementStatistic(statistic, material, 1); + } + + public void incrementStatistic(Statistic statistic, Material material, int amount) { + if (!statistic.isSubstatistic()) { + throw new IllegalArgumentException("Given statistic is not a substatistic"); + } + if (statistic.isBlock() != material.isBlock()) { + throw new IllegalArgumentException("Given material is not valid for this substatistic"); + } + + int mat = material.getId(); + + if (!material.isBlock()) { + mat -= 255; + } + + sendStatistic(statistic.getId() + mat, amount); + } + + private void sendStatistic(int id, int amount) { + while (amount > Byte.MAX_VALUE) { + sendStatistic(id, Byte.MAX_VALUE); + amount -= Byte.MAX_VALUE; + } + + getHandle().netServerHandler.sendPacket(new Packet200Statistic(id, amount)); + } + + public void setPlayerTime(long time, boolean relative) { + getHandle().timeOffset = time; + getHandle().relativeTime = relative; + } + + public long getPlayerTimeOffset() { + return getHandle().timeOffset; + } + + public long getPlayerTime() { + return getHandle().getPlayerTime(); + } + + public boolean isPlayerTimeRelative() { + return getHandle().relativeTime; + } + + public ConnectionType getConnectionType() { + return getHandle().netServerHandler.getConnectionType(); + } + + public boolean hasReceivedPacket0() { + return getHandle().netServerHandler.isReceivedKeepAlive(); + } + + public boolean isUsingReleaseToBeta() { + return getHandle().netServerHandler.isUsingReleaseToBeta(); + } + + public void resetPlayerTime() { + setPlayerTime(0, true); + } + + public boolean isBanned() { + return server.getHandle().banByName.contains(getName().toLowerCase()); + } + + public void setBanned(boolean value) { + if (value) { + server.getHandle().a(getName().toLowerCase()); + } else { + server.getHandle().b(getName().toLowerCase()); + } + } + + public boolean isWhitelisted() { + return server.getHandle().e().contains(getName().toLowerCase()); + } + + public void setWhitelisted(boolean value) { + if (value) { + server.getHandle().k(getName().toLowerCase()); + } else { + server.getHandle().l(getName().toLowerCase()); + } + } + + public void hidePlayer(Player player) { + + hiddenPlayers.add(player.getUniqueId()); + + //remove this player from the hidden player's EntityTrackerEntry + EntityTracker tracker = ((WorldServer) entity.world).tracker; + EntityPlayer other = ((CraftPlayer) player).getHandle(); + EntityTrackerEntry entry = (EntityTrackerEntry) tracker.b.a(other.id); + if (entry != null) { + entry.c(getHandle()); + } + + } + + public void showPlayer(Player player) { + hiddenPlayers.remove(player.getUniqueId()); + + EntityTracker tracker = ((WorldServer) entity.world).tracker; + EntityPlayer other = ((CraftPlayer) player).getHandle(); + EntityTrackerEntry entry = (EntityTrackerEntry) tracker.b.a(other.id); + if (entry != null && !entry.trackedPlayers.contains(getHandle())) { + entry.b(getHandle()); + } + + } + + public boolean canSee(Player player) { + return !hiddenPlayers.contains(player.getUniqueId()); + } + + public void sendPacket(final Player player, final Packet packet) { + if(player.isOnline()) { + NetServerHandler nsh = getHandle().netServerHandler; + nsh.sendPacket(packet); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPoweredMinecart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPoweredMinecart.java new file mode 100644 index 0000000..89f8206 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPoweredMinecart.java @@ -0,0 +1,17 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityMinecart; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.PoweredMinecart; + +public class CraftPoweredMinecart extends CraftMinecart implements PoweredMinecart { + public CraftPoweredMinecart(CraftServer server, EntityMinecart entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftPoweredMinecart"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java new file mode 100644 index 0000000..cf6c7ba --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java @@ -0,0 +1,39 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntitySheep; +import org.bukkit.DyeColor; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Sheep; + +public class CraftSheep extends CraftAnimals implements Sheep { + public CraftSheep(CraftServer server, EntitySheep entity) { + super(server, entity); + } + + @Override + public EntitySheep getHandle() { + return (EntitySheep) entity; + } + + @Override + public String toString() { + return "CraftSheep"; + } + + public DyeColor getColor() { + return DyeColor.getByData((byte) getHandle().getColor()); + } + + public void setColor(DyeColor color) { + getHandle().setColor(color.getData()); + } + + public boolean isSheared() { + return getHandle().isSheared(); + } + + public void setSheared(boolean flag) { + getHandle().setSheared(flag); + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java new file mode 100644 index 0000000..8f837dc --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntitySkeleton; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Skeleton; + +public class CraftSkeleton extends CraftMonster implements Skeleton { + + public CraftSkeleton(CraftServer server, EntitySkeleton entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftSkeleton"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java new file mode 100644 index 0000000..db654b3 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java @@ -0,0 +1,29 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntitySlime; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Slime; + +public class CraftSlime extends CraftLivingEntity implements Slime { + + public CraftSlime(CraftServer server, EntitySlime entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftSlime"; + } + + public EntitySlime getHandle() { + return (EntitySlime) super.getHandle(); + } + + public int getSize() { + return getHandle().getSize(); + } + + public void setSize(int size) { + getHandle().setSize(size); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowball.java new file mode 100644 index 0000000..42d5a57 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowball.java @@ -0,0 +1,32 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityLiving; +import net.minecraft.server.EntitySnowball; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Snowball; + +public class CraftSnowball extends AbstractProjectile implements Snowball { + public CraftSnowball(CraftServer server, EntitySnowball entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftSnowball"; + } + + public LivingEntity getShooter() { + if (((EntitySnowball) getHandle()).shooter != null) { + return (LivingEntity) ((EntitySnowball) getHandle()).shooter.getBukkitEntity(); + } + + return null; + } + + public void setShooter(LivingEntity shooter) { + if (shooter instanceof CraftLivingEntity) { + ((EntitySnowball) getHandle()).shooter = (EntityLiving) ((CraftLivingEntity) shooter).entity; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSpider.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSpider.java new file mode 100644 index 0000000..fb03f51 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSpider.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntitySpider; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Spider; + +public class CraftSpider extends CraftMonster implements Spider { + + public CraftSpider(CraftServer server, EntitySpider entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftSpider"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSquid.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSquid.java new file mode 100644 index 0000000..f81356a --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSquid.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntitySquid; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Squid; + +public class CraftSquid extends CraftWaterMob implements Squid { + + public CraftSquid(CraftServer server, EntitySquid entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftSquid"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftStorageMinecart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftStorageMinecart.java new file mode 100644 index 0000000..0f9f9d1 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftStorageMinecart.java @@ -0,0 +1,25 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityMinecart; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.entity.StorageMinecart; +import org.bukkit.inventory.Inventory; + +public class CraftStorageMinecart extends CraftMinecart implements StorageMinecart { + private CraftInventory inventory; + + public CraftStorageMinecart(CraftServer server, EntityMinecart entity) { + super(server, entity); + inventory = new CraftInventory(entity); + } + + public Inventory getInventory() { + return inventory; + } + + @Override + public String toString() { + return "CraftStorageMinecart{" + "inventory=" + inventory + '}'; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java new file mode 100644 index 0000000..167eb9f --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java @@ -0,0 +1,47 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityTNTPrimed; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.TNTPrimed; + +public class CraftTNTPrimed extends CraftEntity implements TNTPrimed { + + public CraftTNTPrimed(CraftServer server, EntityTNTPrimed entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftTNTPrimed"; + } + + @Override + public EntityTNTPrimed getHandle() { + return (EntityTNTPrimed) super.getHandle(); + } + + public float getYield() { + return getHandle().yield; + } + + public boolean isIncendiary() { + return getHandle().isIncendiary; + } + + public void setIsIncendiary(boolean isIncendiary) { + getHandle().isIncendiary = isIncendiary; + } + + public void setYield(float yield) { + getHandle().yield = yield; + } + + public int getFuseTicks() { + return getHandle().fuseTicks; + } + + public void setFuseTicks(int fuseTicks) { + getHandle().fuseTicks = fuseTicks; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVehicle.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVehicle.java new file mode 100644 index 0000000..8e4af46 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVehicle.java @@ -0,0 +1,15 @@ +package org.bukkit.craftbukkit.entity; + +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Vehicle; + +public abstract class CraftVehicle extends CraftEntity implements Vehicle { + public CraftVehicle(CraftServer server, net.minecraft.server.Entity entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftVehicle{passenger=" + getPassenger() + '}'; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWaterMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWaterMob.java new file mode 100644 index 0000000..d6a30e9 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWaterMob.java @@ -0,0 +1,18 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityWaterAnimal; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.WaterMob; + +public class CraftWaterMob extends CraftCreature implements WaterMob { + + public CraftWaterMob(CraftServer server, EntityWaterAnimal entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftWaterMob"; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWeather.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWeather.java new file mode 100644 index 0000000..671394e --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWeather.java @@ -0,0 +1,17 @@ + +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityWeather; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Weather; + +public class CraftWeather extends CraftEntity implements Weather { + public CraftWeather(final CraftServer server, final EntityWeather entity) { + super(server, entity); + } + + @Override + public EntityWeather getHandle() { + return (EntityWeather) super.getHandle(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java new file mode 100644 index 0000000..d65ffc6 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java @@ -0,0 +1,112 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityWolf; +import net.minecraft.server.PathEntity; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.AnimalTamer; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; + +public class CraftWolf extends CraftAnimals implements Wolf { + private AnimalTamer owner; + + public CraftWolf(CraftServer server, EntityWolf wolf) { + super(server, wolf); + } + + public boolean isAngry() { + return getHandle().isAngry(); + } + + public void setAngry(boolean angry) { + getHandle().setAngry(angry); + } + + public boolean isSitting() { + return getHandle().isSitting(); + } + + public void setSitting(boolean sitting) { + getHandle().setSitting(sitting); + // TODO determine what the following would do - it is affected every time a player makes their wolf sit or stand + // getHandle().ay = false; + setPath((PathEntity) null); + } + + public boolean isTamed() { + return getHandle().isTamed(); + } + + public void setTamed(boolean tame) { + getHandle().setTamed(tame); + } + + public AnimalTamer getOwner() { + // If the wolf has a previously set owner use that, otherwise try and find the player who owns it + if (owner == null) { + // TODO try and recover owner from persistence store before defaulting to playername + owner = getServer().getPlayer(getOwnerName()); + } + return owner; + } + + public void setOwner(AnimalTamer tamer) { + owner = tamer; + if (owner != null) { + setTamed(true); /* Make him tame */ + setPath((PathEntity) null); /* Clear path */ + /* Set owner */ + // TODO persist owner to the persistence store + if (owner instanceof Player) { + setOwnerName(((Player) owner).getName()); + } else { + setOwnerName(""); + } + } else { + setTamed(false); /* Make him not tame */ + setOwnerName(""); /* Clear owner */ + } + } + + /** + * The owner's name is how MC knows and persists the Wolf's owner. Since we choose to instead use an AnimalTamer, this functionality + * is used only as a backup. If the animal tamer is a player, we will store their name, otherwise we store an empty string. + * @return the owner's name, if they are a player; otherwise, the empty string or null. + */ + String getOwnerName() { + return getHandle().getOwnerName(); + } + + void setOwnerName(String ownerName) { + getHandle().setOwnerName(ownerName); + } + + /** + * Only used internally at the moment, and there to set the path to null (that is stop the thing from running around) + * TODO use this later to extend the API, when we have Path classes in Bukkit + * @param pathentity currently the MC defined PathEntity class. Should be replaced with an API interface at some point. + */ + private void setPath(PathEntity pathentity) { + getHandle().setPathEntity(pathentity); + } + + /* + * This method requires a(boolean) to be made visible. It will allow for hearts to be animated on a successful taming. + * TODO add this to the API, and make it visible + private void playTamingAnimation(boolean successful){ + getHandle().a(successful); + } + */ + + @Override + public EntityWolf getHandle() { + // It's somewhat easier to override this here, as many internal methods rely on EntityWolf specific methods. + // Doing this has no impact on anything outside this class. + return (EntityWolf) entity; + } + + @Override + public String toString() { + return "CraftWolf[anger=" + isAngry() + ",owner=" + getOwner() + ",tame=" + isTamed() + ",sitting=" + isSitting() + "]"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java new file mode 100644 index 0000000..cfc7d1c --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java @@ -0,0 +1,17 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityZombie; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Zombie; + +public class CraftZombie extends CraftMonster implements Zombie { + + public CraftZombie(CraftServer server, EntityZombie entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftZombie"; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java new file mode 100644 index 0000000..25f19d2 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -0,0 +1,266 @@ +package org.bukkit.craftbukkit.event; + +import net.minecraft.server.*; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.AnimalTamer; +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Type; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockFadeEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.event.entity.EntityTameEvent; +import org.bukkit.event.entity.ItemDespawnEvent; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.event.player.PlayerInteractEvent; + +public class CraftEventFactory { + private static boolean canBuild(CraftWorld world, Player player, int x, int z) { + WorldServer worldServer = world.getHandle(); + int spawnSize = Bukkit.getServer().getSpawnRadius(); + + if (spawnSize <= 0) return true; + if (player.isOp()) return true; + + ChunkCoordinates chunkcoordinates = worldServer.getSpawn(); + + int distanceFromSpawn = (int) Math.max(Math.abs(x - chunkcoordinates.x), Math.abs(z - chunkcoordinates.z)); + return distanceFromSpawn > spawnSize; + } + + /** + * Block place methods + */ + public static BlockPlaceEvent callBlockPlaceEvent(World world, EntityHuman who, BlockState replacedBlockState, int clickedX, int clickedY, int clickedZ, int type) { + return callBlockPlaceEvent(world, who, replacedBlockState, clickedX, clickedY, clickedZ, net.minecraft.server.Block.byId[type]); + } + + public static BlockPlaceEvent callBlockPlaceEvent(World world, EntityHuman who, BlockState replacedBlockState, int clickedX, int clickedY, int clickedZ, net.minecraft.server.Block block) { + return callBlockPlaceEvent(world, who, replacedBlockState, clickedX, clickedY, clickedZ, new ItemStack(block)); + } + + public static BlockPlaceEvent callBlockPlaceEvent(World world, EntityHuman who, BlockState replacedBlockState, int clickedX, int clickedY, int clickedZ, ItemStack itemstack) { + CraftWorld craftWorld = ((WorldServer) world).getWorld(); + CraftServer craftServer = ((WorldServer) world).getServer(); + + Player player = (who == null) ? null : (Player) who.getBukkitEntity(); + CraftItemStack itemInHand = new CraftItemStack(itemstack); + + Block blockClicked = craftWorld.getBlockAt(clickedX, clickedY, clickedZ); + Block placedBlock = replacedBlockState.getBlock(); + + boolean canBuild = canBuild(craftWorld, player, placedBlock.getX(), placedBlock.getZ()); + + BlockPlaceEvent event = new BlockPlaceEvent(placedBlock, replacedBlockState, blockClicked, itemInHand, player, canBuild); + craftServer.getPluginManager().callEvent(event); + + return event; + } + + /** + * Bucket methods + */ + public static PlayerBucketEmptyEvent callPlayerBucketEmptyEvent(EntityHuman who, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemInHand) { + return (PlayerBucketEmptyEvent) getPlayerBucketEvent(Type.PLAYER_BUCKET_EMPTY, who, clickedX, clickedY, clickedZ, clickedFace, itemInHand, Item.BUCKET); + } + + public static PlayerBucketFillEvent callPlayerBucketFillEvent(EntityHuman who, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemInHand, net.minecraft.server.Item bucket) { + return (PlayerBucketFillEvent) getPlayerBucketEvent(Type.PLAYER_BUCKET_FILL, who, clickedX, clickedY, clickedZ, clickedFace, itemInHand, bucket); + } + + private static PlayerEvent getPlayerBucketEvent(Type type, EntityHuman who, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemstack, net.minecraft.server.Item item) { + Player player = (who == null) ? null : (Player) who.getBukkitEntity(); + CraftItemStack itemInHand = new CraftItemStack(new ItemStack(item)); + Material bucket = Material.getMaterial(itemstack.id); + + CraftWorld craftWorld = (CraftWorld) player.getWorld(); + CraftServer craftServer = (CraftServer) player.getServer(); + + Block blockClicked = craftWorld.getBlockAt(clickedX, clickedY, clickedZ); + BlockFace blockFace = CraftBlock.notchToBlockFace(clickedFace); + + PlayerEvent event = null; + if (type == Type.PLAYER_BUCKET_EMPTY) { + event = new PlayerBucketEmptyEvent(player, blockClicked, blockFace, bucket, itemInHand); + ((PlayerBucketEmptyEvent) event).setCancelled(!canBuild(craftWorld, player, clickedX, clickedZ)); + } else if (type == Type.PLAYER_BUCKET_FILL) { + event = new PlayerBucketFillEvent(player, blockClicked, blockFace, bucket, itemInHand); + ((PlayerBucketFillEvent) event).setCancelled(!canBuild(craftWorld, player, clickedX, clickedZ)); + } + + craftServer.getPluginManager().callEvent(event); + + return event; + } + + /** + * Player Interact event + */ + + public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, ItemStack itemstack) { + if (action != Action.LEFT_CLICK_AIR && action != Action.RIGHT_CLICK_AIR) { + throw new IllegalArgumentException(); + } + return callPlayerInteractEvent(who, action, 0, 255, 0, 0, itemstack); + } + public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemstack) { + Player player = (who == null) ? null : (Player) who.getBukkitEntity(); + CraftItemStack itemInHand = new CraftItemStack(itemstack); + + CraftWorld craftWorld = (CraftWorld) player.getWorld(); + CraftServer craftServer = (CraftServer) player.getServer(); + + Block blockClicked = craftWorld.getBlockAt(clickedX, clickedY, clickedZ); + BlockFace blockFace = CraftBlock.notchToBlockFace(clickedFace); + + if (clickedY == 255) { + blockClicked = null; + switch (action) { + case LEFT_CLICK_BLOCK: + action = Action.LEFT_CLICK_AIR; + break; + case RIGHT_CLICK_BLOCK: + action = Action.RIGHT_CLICK_AIR; + break; + } + } + + if (itemInHand.getType() == Material.AIR || itemInHand.getAmount() == 0) { + itemInHand = null; + } + + PlayerInteractEvent event = new PlayerInteractEvent(player, action, itemInHand, blockClicked, blockFace); + craftServer.getPluginManager().callEvent(event); + + return event; + } + + /** + * BlockDamageEvent + */ + public static BlockDamageEvent callBlockDamageEvent(EntityHuman who, int x, int y, int z, ItemStack itemstack, boolean instaBreak) { + Player player = (who == null) ? null : (Player) who.getBukkitEntity(); + CraftItemStack itemInHand = new CraftItemStack(itemstack); + + CraftWorld craftWorld = (CraftWorld) player.getWorld(); + CraftServer craftServer = (CraftServer) player.getServer(); + + Block blockClicked = craftWorld.getBlockAt(x, y, z); + + BlockDamageEvent event = new BlockDamageEvent(player, blockClicked, itemInHand, instaBreak); + craftServer.getPluginManager().callEvent(event); + + return event; + } + + /** + * CreatureSpawnEvent + */ + public static CreatureSpawnEvent callCreatureSpawnEvent(EntityLiving entityliving, SpawnReason spawnReason) { + org.bukkit.entity.Entity entity = entityliving.getBukkitEntity(); + CraftServer craftServer = (CraftServer) entity.getServer(); + + CreatureType type = null; + + if (entityliving instanceof EntityChicken) { + type = CreatureType.CHICKEN; + } else if (entityliving instanceof EntityCow) { + type = CreatureType.COW; + } else if (entityliving instanceof EntityCreeper) { + type = CreatureType.CREEPER; + } else if (entityliving instanceof EntityGhast) { + type = CreatureType.GHAST; + } else if (entityliving instanceof EntityGiantZombie) { + type = CreatureType.GIANT; + } else if (entityliving instanceof EntityWolf) { + type = CreatureType.WOLF; + } else if (entityliving instanceof EntityPig) { + type = CreatureType.PIG; + } else if (entityliving instanceof EntityPigZombie) { + type = CreatureType.PIG_ZOMBIE; + } else if (entityliving instanceof EntitySheep) { + type = CreatureType.SHEEP; + } else if (entityliving instanceof EntitySkeleton) { + type = CreatureType.SKELETON; + } else if (entityliving instanceof EntitySlime) { + type = CreatureType.SLIME; + } else if (entityliving instanceof EntitySpider) { + type = CreatureType.SPIDER; + } else if (entityliving instanceof EntitySquid) { + type = CreatureType.SQUID; + } else if (entityliving instanceof EntityZombie) { + type = CreatureType.ZOMBIE; + // Supertype of many, last! + } else if (entityliving instanceof EntityMonster) { + type = CreatureType.MONSTER; + } + + CreatureSpawnEvent event = new CreatureSpawnEvent(entity, type, entity.getLocation(), spawnReason); + craftServer.getPluginManager().callEvent(event); + return event; + } + + /** + * EntityTameEvent + */ + public static EntityTameEvent callEntityTameEvent(EntityLiving entity, EntityHuman tamer) { + org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); + org.bukkit.entity.AnimalTamer bukkitTamer = (tamer != null ? (AnimalTamer) tamer.getBukkitEntity() : null); + CraftServer craftServer = (CraftServer) bukkitEntity.getServer(); + + EntityTameEvent event = new EntityTameEvent(bukkitEntity, bukkitTamer); + craftServer.getPluginManager().callEvent(event); + return event; + } + + /** + * ItemSpawnEvent + */ + public static ItemSpawnEvent callItemSpawnEvent(EntityItem entityitem) { + org.bukkit.entity.Entity entity = entityitem.getBukkitEntity(); + CraftServer craftServer = (CraftServer) entity.getServer(); + + ItemSpawnEvent event = new ItemSpawnEvent(entity, entity.getLocation()); + + craftServer.getPluginManager().callEvent(event); + return event; + } + + /** + * BlockFadeEvent + */ + public static BlockFadeEvent callBlockFadeEvent(Block block, int type) { + BlockState state = block.getState(); + state.setTypeId(type); + + BlockFadeEvent event = new BlockFadeEvent(block, state); + Bukkit.getPluginManager().callEvent(event); + return event; + } + + /** + * ItemDespawnEvent + */ + public static ItemDespawnEvent callItemDespawnEvent(EntityItem entityitem) { + org.bukkit.entity.Entity entity = entityitem.getBukkitEntity(); + + ItemDespawnEvent event = new ItemDespawnEvent(entity, entity.getLocation()); + + ((CraftServer) entity.getServer()).getPluginManager().callEvent(event); + return event; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java new file mode 100644 index 0000000..3fe80dc --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -0,0 +1,68 @@ +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.*; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; + +import java.util.List; +import java.util.Random; + +public class CustomChunkGenerator extends InternalChunkGenerator { + private final ChunkGenerator generator; + private final WorldServer world; + private final Random random; + + public CustomChunkGenerator(World world, long seed, ChunkGenerator generator) { + this.world = (WorldServer) world; + this.generator = generator; + + this.random = new Random(seed); + } + + public boolean isChunkLoaded(int x, int z) { + return true; + } + + public Chunk getOrCreateChunk(int x, int z) { + random.setSeed((long) x * 341873128712L + (long) z * 132897987541L); + byte[] types = generator.generate(world.getWorld(), random, x, z); + + Chunk chunk = new Chunk(world, types, x, z); + + chunk.initLighting(); + + return chunk; + } + + public void getChunkAt(IChunkProvider icp, int i, int i1) { + // Nothing! + } + + public boolean saveChunks(boolean bln, IProgressUpdate ipu) { + return true; + } + + public boolean unloadChunks() { + return false; + } + + public boolean canSave() { + return true; + } + + public byte[] generate(org.bukkit.World world, Random random, int x, int z) { + return generator.generate(world, random, x, z); + } + + public Chunk getChunkAt(int x, int z) { + return getOrCreateChunk(x, z); + } + + public boolean canSpawn(org.bukkit.World world, int x, int z) { + return generator.canSpawn(world, x, z); + } + + public List getDefaultPopulators(org.bukkit.World world) { + return generator.getDefaultPopulators(world); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/InternalChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/InternalChunkGenerator.java new file mode 100644 index 0000000..e5ee52b --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/InternalChunkGenerator.java @@ -0,0 +1,9 @@ + +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.IChunkProvider; +import org.bukkit.generator.ChunkGenerator; + +public abstract class InternalChunkGenerator extends ChunkGenerator implements IChunkProvider { + +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/NetherChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/NetherChunkGenerator.java new file mode 100644 index 0000000..59d7bbe --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/NetherChunkGenerator.java @@ -0,0 +1,12 @@ +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.World; + +/** + * This class is useless. Just fyi. + */ +public class NetherChunkGenerator extends NormalChunkGenerator { + public NetherChunkGenerator(World world, long seed) { + super(world, seed); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java new file mode 100644 index 0000000..2f590c0 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java @@ -0,0 +1,60 @@ +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.Chunk; +import net.minecraft.server.IChunkProvider; +import net.minecraft.server.IProgressUpdate; +import net.minecraft.server.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.generator.BlockPopulator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class NormalChunkGenerator extends InternalChunkGenerator { + private final IChunkProvider provider; + + public NormalChunkGenerator(World world, long seed) { + provider = world.worldProvider.getChunkProvider(); + } + + public byte[] generate(org.bukkit.World world, Random random, int x, int z) { + throw new UnsupportedOperationException("Not supported."); + } + + public boolean canSpawn(org.bukkit.World world, int x, int z) { + return ((CraftWorld) world).getHandle().worldProvider.canSpawn(x, z); + } + + public List getDefaultPopulators(org.bukkit.World world) { + return new ArrayList(); + } + + public boolean isChunkLoaded(int i, int i1) { + return provider.isChunkLoaded(i, i1); + } + + public Chunk getOrCreateChunk(int i, int i1) { + return provider.getOrCreateChunk(i, i1); + } + + public Chunk getChunkAt(int i, int i1) { + return provider.getChunkAt(i, i1); + } + + public void getChunkAt(IChunkProvider icp, int i, int i1) { + provider.getChunkAt(icp, i, i1); + } + + public boolean saveChunks(boolean bln, IProgressUpdate ipu) { + return provider.saveChunks(bln, ipu); + } + + public boolean unloadChunks() { + return provider.unloadChunks(); + } + + public boolean canSave() { + return provider.canSave(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/SkyLandsChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/SkyLandsChunkGenerator.java new file mode 100644 index 0000000..e327996 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/SkyLandsChunkGenerator.java @@ -0,0 +1,12 @@ +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.World; + +/** + * This class is useless. Just fyi. + */ +public class SkyLandsChunkGenerator extends NormalChunkGenerator { + public SkyLandsChunkGenerator(World world, long seed) { + super(world, seed); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java new file mode 100644 index 0000000..6dfe617 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java @@ -0,0 +1,33 @@ +package org.bukkit.craftbukkit.inventory; + +import net.minecraft.server.FurnaceRecipes; +import org.bukkit.Material; +import org.bukkit.inventory.FurnaceRecipe; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; + +public class CraftFurnaceRecipe extends FurnaceRecipe implements CraftRecipe { + public CraftFurnaceRecipe(ItemStack result, Material source) { + super(result, source); + } + + public CraftFurnaceRecipe(ItemStack result, MaterialData source) { + super(result, source); + } + + public static CraftFurnaceRecipe fromBukkitRecipe(FurnaceRecipe recipe) { + if (recipe instanceof CraftFurnaceRecipe) { + return (CraftFurnaceRecipe) recipe; + } + return new CraftFurnaceRecipe(recipe.getResult(), recipe.getInput()); + } + + public void addToCraftingManager() { + ItemStack result = this.getResult(); + MaterialData input = this.getInput(); + int id = result.getTypeId(); + int amount = result.getAmount(); + int dmg = result.getDurability(); + FurnaceRecipes.getInstance().registerRecipe(input.getItemTypeId(), new net.minecraft.server.ItemStack(id, amount, dmg)); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java new file mode 100644 index 0000000..a698cc7 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java @@ -0,0 +1,365 @@ +package org.bukkit.craftbukkit.inventory; + +import net.minecraft.server.IInventory; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.event.inventory.InventoryTransactionEvent; +import org.bukkit.event.inventory.InventoryTransactionType; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; + +public class CraftInventory implements org.bukkit.inventory.Inventory { + protected IInventory inventory; + + public CraftInventory(IInventory inventory) { + this.inventory = inventory; + } + + public IInventory getInventory() { + return inventory; + } + + public int getSize() { + return getInventory().getSize(); + } + + public String getName() { + return getInventory().getName(); + } + + public ItemStack getItem(int index) { + return new CraftItemStack(getInventory().getItem(index)); + } + + public ItemStack[] getContents() { + ItemStack[] items = new ItemStack[getSize()]; + net.minecraft.server.ItemStack[] mcItems = getInventory().getContents(); + + for (int i = 0; i < mcItems.length; i++) { + items[i] = mcItems[i] == null ? null : new CraftItemStack(mcItems[i]); + } + + return items; + } + + public void setContents(ItemStack[] items) { + if (getInventory().getContents().length != items.length) { + throw new IllegalArgumentException("Invalid inventory size; expected " + getInventory().getContents().length + " and got " + items.length); // Poseidon + } + + net.minecraft.server.ItemStack[] mcItems = getInventory().getContents(); + + for (int i = 0; i < items.length; i++) { + ItemStack item = items[i]; + if (item == null || item.getTypeId() <= 0) { + mcItems[i] = null; + } else { + mcItems[i] = new net.minecraft.server.ItemStack(item.getTypeId(), item.getAmount(), item.getDurability()); + } + } + } + + public void setItem(int index, ItemStack item) { + getInventory().setItem(index, (item == null ? null : new net.minecraft.server.ItemStack(item.getTypeId(), item.getAmount(), item.getDurability()))); + } + + public boolean contains(int materialId) { + for (ItemStack item: getContents()) { + if (item != null && item.getTypeId() == materialId) { + return true; + } + } + return false; + } + + public boolean contains(Material material) { + return contains(material.getId()); + } + + public boolean contains(ItemStack item) { + if (item == null) { + return false; + } + for (ItemStack i: getContents()) { + if (item.equals(i)) { + return true; + } + } + return false; + } + + public boolean contains(int materialId, int amount) { + int amt = 0; + for (ItemStack item: getContents()) { + if (item != null && item.getTypeId() == materialId) { + amt += item.getAmount(); + } + } + return amt >= amount; + } + + public boolean contains(Material material, int amount) { + return contains(material.getId(), amount); + } + + public boolean contains(ItemStack item, int amount) { + if (item == null) { + return false; + } + int amt = 0; + for (ItemStack i: getContents()) { + if (item.equals(i)) { + amt += item.getAmount(); + } + } + return amt >= amount; + } + + public HashMap all(int materialId) { + HashMap slots = new HashMap(); + + ItemStack[] inventory = getContents(); + for (int i = 0; i < inventory.length; i++) { + ItemStack item = inventory[i]; + if (item != null && item.getTypeId() == materialId) { + slots.put(i, item); + } + } + return slots; + } + + public HashMap all(Material material) { + return all(material.getId()); + } + + public HashMap all(ItemStack item) { + HashMap slots = new HashMap(); + if (item != null) { + ItemStack[] inventory = getContents(); + for (int i = 0; i < inventory.length; i++) { + if (item.equals(inventory[i])) { + slots.put(i, inventory[i]); + } + } + } + return slots; + } + + public int first(int materialId) { + ItemStack[] inventory = getContents(); + for (int i = 0; i < inventory.length; i++) { + ItemStack item = inventory[i]; + if (item != null && item.getTypeId() == materialId) { + return i; + } + } + return -1; + } + + public int first(Material material) { + return first(material.getId()); + } + + public int first(ItemStack item) { + if (item == null) { + return -1; + } + ItemStack[] inventory = getContents(); + for (int i = 0; i < inventory.length; i++) { + if (item.equals(inventory[i])) { + return i; + } + } + return -1; + } + + public int firstEmpty() { + ItemStack[] inventory = getContents(); + for (int i = 0; i < inventory.length; i++) { + if (inventory[i] == null) { + return i; + } + } + return -1; + } + + public int firstPartial(int materialId) { + ItemStack[] inventory = getContents(); + for (int i = 0; i < inventory.length; i++) { + ItemStack item = inventory[i]; + if (item != null && item.getTypeId() == materialId && item.getAmount() < item.getMaxStackSize()) { + return i; + } + } + return -1; + } + + public int firstPartial(Material material) { + return firstPartial(material.getId()); + } + + public int firstPartial(ItemStack item) { + ItemStack[] inventory = getContents(); + if (item == null) { + return -1; + } + for (int i = 0; i < inventory.length; i++) { + ItemStack cItem = inventory[i]; + if (cItem != null && cItem.getTypeId() == item.getTypeId() && cItem.getAmount() < cItem.getMaxStackSize() && cItem.getDurability() == item.getDurability()) { + return i; + } + } + return -1; + } + + public HashMap addItem(ItemStack... items) { + HashMap leftover = new HashMap(); + + /* TODO: some optimization + * - Create a 'firstPartial' with a 'fromIndex' + * - Record the lastPartial per Material + * - Cache firstEmpty result + */ + + for (int i = 0; i < items.length; i++) { + ItemStack item = items[i]; + + // Poseidon + InventoryTransactionEvent event = new InventoryTransactionEvent(InventoryTransactionType.ITEM_ADDED, this, item); + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) + continue; + + while (true) { + // Do we already have a stack of it? + int firstPartial = firstPartial(item); + + // Drat! no partial stack + if (firstPartial == -1) { + // Find a free spot! + int firstFree = firstEmpty(); + + if (firstFree == -1) { + // No space at all! + leftover.put(i, item); + break; + } else { + // More than a single stack! + if (item.getAmount() > getMaxItemStack()) { + setItem(firstFree, new CraftItemStack(item.getTypeId(), getMaxItemStack(), item.getDurability())); + item.setAmount(item.getAmount() - getMaxItemStack()); + } else { + // Just store it + setItem(firstFree, item); + break; + } + } + } else { + // So, apparently it might only partially fit, well lets do just that + ItemStack partialItem = getItem(firstPartial); + + int amount = item.getAmount(); + int partialAmount = partialItem.getAmount(); + int maxAmount = partialItem.getMaxStackSize(); + + // Check if it fully fits + if (amount + partialAmount <= maxAmount) { + partialItem.setAmount(amount + partialAmount); + break; + } + + // It fits partially + partialItem.setAmount(maxAmount); + item.setAmount(amount + partialAmount - maxAmount); + } + } + } + return leftover; + } + + public HashMap removeItem(ItemStack... items) { + HashMap leftover = new HashMap(); + + // TODO: optimization + + for (int i = 0; i < items.length; i++) { + ItemStack item = items[i]; + + // Poseidon + InventoryTransactionEvent event = new InventoryTransactionEvent(InventoryTransactionType.ITEM_REMOVED, this, item); + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) + continue; + + int toDelete = item.getAmount(); + + while (true) { + int first = first(item.getType()); + + // Drat! we don't have this type in the inventory + if (first == -1) { + item.setAmount(toDelete); + leftover.put(i, item); + break; + } else { + ItemStack itemStack = getItem(first); + int amount = itemStack.getAmount(); + + if (amount <= toDelete) { + toDelete -= amount; + // clear the slot, all used up + clear(first); + } else { + // split the stack and store + itemStack.setAmount(amount - toDelete); + setItem(first, itemStack); + toDelete = 0; + } + } + + // Bail when done + if (toDelete <= 0) { + break; + } + } + } + return leftover; + } + + private int getMaxItemStack() { + return getInventory().getMaxStackSize(); + } + + public void remove(int materialId) { + ItemStack[] items = getContents(); + for (int i = 0; i < items.length; i++) { + if (items[i] != null && items[i].getTypeId() == materialId) { + clear(i); + } + } + } + + public void remove(Material material) { + remove(material.getId()); + } + + public void remove(ItemStack item) { + ItemStack[] items = getContents(); + for (int i = 0; i < items.length; i++) { + if (items[i] != null && items[i].equals(item)) { + clear(i); + } + } + } + + public void clear(int index) { + setItem(index, null); + } + + public void clear() { + for (int i = 0; i < getSize(); i++) { + clear(i); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java new file mode 100644 index 0000000..5a0b644 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java @@ -0,0 +1,88 @@ +package org.bukkit.craftbukkit.inventory; + +import net.minecraft.server.InventoryPlayer; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +public class CraftInventoryPlayer extends CraftInventory implements PlayerInventory { + public CraftInventoryPlayer(net.minecraft.server.InventoryPlayer inventory) { + super(inventory); + } + + public InventoryPlayer getInventory() { + return (InventoryPlayer) inventory; + } + + public int getSize() { + return super.getSize() - 4; + } + + public ItemStack getItemInHand() { + return new CraftItemStack(getInventory().getItemInHand()); + } + + public void setItemInHand(ItemStack stack) { + setItem(getHeldItemSlot(), stack); + } + + public int getHeldItemSlot() { + return getInventory().itemInHandIndex; + } + + public ItemStack getHelmet() { + return getItem(getSize() + 3); + } + + public ItemStack getChestplate() { + return getItem(getSize() + 2); + } + + public ItemStack getLeggings() { + return getItem(getSize() + 1); + } + + public ItemStack getBoots() { + return getItem(getSize() + 0); + } + + public void setHelmet(ItemStack helmet) { + setItem(getSize() + 3, helmet); + } + + public void setChestplate(ItemStack chestplate) { + setItem(getSize() + 2, chestplate); + } + + public void setLeggings(ItemStack leggings) { + setItem(getSize() + 1, leggings); + } + + public void setBoots(ItemStack boots) { + setItem(getSize() + 0, boots); + } + + public CraftItemStack[] getArmorContents() { + net.minecraft.server.ItemStack[] mcItems = getInventory().getArmorContents(); + CraftItemStack[] ret = new CraftItemStack[mcItems.length]; + + for (int i = 0; i < mcItems.length; i++) { + ret[i] = new CraftItemStack(mcItems[i]); + } + return ret; + } + + public void setArmorContents(ItemStack[] items) { + int cnt = getSize(); + + if (items == null) { + items = new ItemStack[4]; + } + for (ItemStack item : items) { + if (item == null || item.getTypeId() == 0) { + clear(cnt++); + } else { + setItem(cnt++, item); + } + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java new file mode 100644 index 0000000..dcebead --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -0,0 +1,126 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +public class CraftItemStack extends ItemStack { + protected net.minecraft.server.ItemStack item; + + public CraftItemStack(net.minecraft.server.ItemStack item) { + super( + item != null ? item.id: 0, + item != null ? item.count : 0, + (short)(item != null ? item.damage : 0) + ); + this.item = item; + } + + /* 'Overwritten' constructors from ItemStack, yay for Java sucking */ + public CraftItemStack(final int type) { + this(type, 0); + } + + public CraftItemStack(final Material type) { + this(type, 0); + } + + public CraftItemStack(final int type, final int amount) { + this(type, amount, (byte) 0); + } + + public CraftItemStack(final Material type, final int amount) { + this(type.getId(), amount); + } + + public CraftItemStack(final int type, final int amount, final short damage) { + this(type, amount, damage, null); + } + + public CraftItemStack(final Material type, final int amount, final short damage) { + this(type.getId(), amount, damage); + } + + public CraftItemStack(final Material type, final int amount, final short damage, final Byte data) { + this(type.getId(), amount, damage, data); + } + + public CraftItemStack(int type, int amount, short damage, Byte data) { + this(new net.minecraft.server.ItemStack(type, amount, data != null ? data : damage)); + } + + /* + * Unsure if we have to sync before each of these calls the values in 'item' + * are all public. + */ + + @Override + public Material getType() { + super.setTypeId(item != null ? item.id : 0); // sync, needed? + return super.getType(); + } + + @Override + public int getTypeId() { + super.setTypeId(item != null ? item.id : 0); // sync, needed? + return item != null ? item.id : 0; + } + + @Override + public void setTypeId(int type) { + if (type == 0) { + super.setTypeId(0); + super.setAmount(0); + item = null; + } else { + if (item == null) { + item = new net.minecraft.server.ItemStack(type, 1, 0); + super.setAmount(1); + } else { + item.id = type; + super.setTypeId(item.id); + } + } + } + + @Override + public int getAmount() { + super.setAmount(item != null ? item.count : 0); // sync, needed? + return (item != null ? item.count : 0); + } + + @Override + public void setAmount(int amount) { + if (amount == 0) { + super.setTypeId(0); + super.setAmount(0); + item = null; + } else { + super.setAmount(amount); + item.count = amount; + } + } + + @Override + public void setDurability(final short durability) { + // Ignore damage if item is null + if (item != null) { + super.setDurability(durability); + item.damage = durability; + } + } + + @Override + public short getDurability() { + if (item != null) { + super.setDurability((short) item.damage); // sync, needed? + return (short) item.damage; + } else { + return -1; + } + } + + @Override + public int getMaxStackSize() { + return item.getItem().getMaxStackSize(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java new file mode 100644 index 0000000..d3e03e2 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java @@ -0,0 +1,7 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.inventory.Recipe; + +public interface CraftRecipe extends Recipe { + void addToCraftingManager(); +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java new file mode 100644 index 0000000..446bba9 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java @@ -0,0 +1,53 @@ +package org.bukkit.craftbukkit.inventory; + +import net.minecraft.server.CraftingManager; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.material.MaterialData; + +import java.util.HashMap; + +public class CraftShapedRecipe extends ShapedRecipe implements CraftRecipe { + public CraftShapedRecipe(ItemStack result) { + super(result); + } + + public static CraftShapedRecipe fromBukkitRecipe(ShapedRecipe recipe) { + if (recipe instanceof CraftShapedRecipe) { + return (CraftShapedRecipe) recipe; + } + CraftShapedRecipe ret = new CraftShapedRecipe(recipe.getResult()); + String[] shape = recipe.getShape(); + ret.shape(shape); + for (char c : recipe.getIngredientMap().keySet()) { + ret.setIngredient(c, recipe.getIngredientMap().get(c)); + } + return ret; + } + + public void addToCraftingManager() { + Object[] data; + String[] shape = this.getShape(); + HashMap ingred = this.getIngredientMap(); + int datalen = shape.length; + datalen += ingred.size() * 2; + int i = 0; + data = new Object[datalen]; + for (; i < shape.length; i++) { + data[i] = shape[i]; + } + for (char c : ingred.keySet()) { + data[i] = c; + i++; + MaterialData mdata = ingred.get(c); + int id = mdata.getItemTypeId(); + byte dmg = mdata.getData(); + data[i] = new net.minecraft.server.ItemStack(id, 1, dmg); + i++; + } + int id = this.getResult().getTypeId(); + int amount = this.getResult().getAmount(); + short durability = this.getResult().getDurability(); + CraftingManager.getInstance().registerShapedRecipe(new net.minecraft.server.ItemStack(id, amount, durability), data); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java new file mode 100644 index 0000000..f2d61d5 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java @@ -0,0 +1,41 @@ +package org.bukkit.craftbukkit.inventory; + +import net.minecraft.server.CraftingManager; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapelessRecipe; +import org.bukkit.material.MaterialData; + +import java.util.ArrayList; + +public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe { + public CraftShapelessRecipe(ItemStack result) { + super(result); + } + + public static CraftShapelessRecipe fromBukkitRecipe(ShapelessRecipe recipe) { + if (recipe instanceof CraftShapelessRecipe) { + return (CraftShapelessRecipe) recipe; + } + CraftShapelessRecipe ret = new CraftShapelessRecipe(recipe.getResult()); + for (MaterialData ingred : recipe.getIngredientList()) { + ret.addIngredient(ingred); + } + return ret; + } + + public void addToCraftingManager() { + ArrayList ingred = this.getIngredientList(); + Object[] data = new Object[ingred.size()]; + int i = 0; + for (MaterialData mdata : ingred) { + int id = mdata.getItemTypeId(); + byte dmg = mdata.getData(); + data[i] = new net.minecraft.server.ItemStack(id, 1, dmg); + i++; + } + int id = this.getResult().getTypeId(); + int amount = this.getResult().getAmount(); + short durability = this.getResult().getDurability(); + CraftingManager.getInstance().registerShapelessRecipe(new net.minecraft.server.ItemStack(id, amount, durability), data); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java new file mode 100644 index 0000000..40b46e5 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java @@ -0,0 +1,25 @@ +package org.bukkit.craftbukkit.inventory; + +import net.minecraft.server.Slot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class CraftSlot implements org.bukkit.inventory.Slot { + private final Slot slot; + + public CraftSlot(Slot slot) { + this.slot = slot; + } + + public Inventory getInventory() { + return new CraftInventory(slot.inventory); + } + + public int getIndex() { + return slot.index; + } + + public ItemStack getItem() { + return new CraftItemStack(slot.getItem()); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java new file mode 100644 index 0000000..eae4114 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java @@ -0,0 +1,108 @@ +package org.bukkit.craftbukkit.map; + +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapCursorCollection; +import org.bukkit.map.MapFont; +import org.bukkit.map.MapFont.CharacterSprite; +import org.bukkit.map.MapPalette; + +import java.awt.*; +import java.util.Arrays; + +public class CraftMapCanvas implements MapCanvas { + + private final byte[] buffer = new byte[128 * 128]; + private final CraftMapView mapView; + private byte[] base; + private MapCursorCollection cursors = new MapCursorCollection(); + + protected CraftMapCanvas(CraftMapView mapView) { + this.mapView = mapView; + Arrays.fill(buffer, (byte) -1); + } + + public CraftMapView getMapView() { + return mapView; + } + + public MapCursorCollection getCursors() { + return cursors; + } + + public void setCursors(MapCursorCollection cursors) { + this.cursors = cursors; + } + + public void setPixel(int x, int y, byte color) { + if (x < 0 || y < 0 || x >= 128 || y >= 128) return; + if (buffer[y * 128 + x] != color) { + buffer[y * 128 + x] = color; + mapView.worldMap.a(x, y, y); + } + } + + public byte getPixel(int x, int y) { + if (x < 0 || y < 0 || x >= 128 || y >= 128) return 0; + return buffer[y * 128 + x]; + } + + public byte getBasePixel(int x, int y) { + if (x < 0 || y < 0 || x >= 128 || y >= 128) return 0; + return base[y * 128 + x]; + } + + protected void setBase(byte[] base) { + this.base = base; + } + + protected byte[] getBuffer() { + return buffer; + } + + public void drawImage(int x, int y, Image image) { + byte[] bytes = MapPalette.imageToBytes(image); + for (int x2 = 0; x2 < image.getWidth(null); ++x2) { + for (int y2 = 0; y2 < image.getHeight(null); ++y2) { + setPixel(x + x2, y + y2, bytes[y2 * image.getWidth(null) + x2]); + } + } + } + + public void drawText(int x, int y, MapFont font, String text) { + int xStart = x; + byte color = MapPalette.DARK_GRAY; + if (!font.isValid(text)) { + throw new IllegalArgumentException("text contains invalid characters"); + } + + for (int i = 0; i < text.length(); ++i) { + char ch = text.charAt(i); + if (ch == '\n') { + x = xStart; + y += font.getHeight() + 1; + continue; + } else if (ch == '\u00A7') { + int j = text.indexOf(';', i); + if (j >= 0) { + try { + color = Byte.parseByte(text.substring(i + 1, j)); + i = j; + continue; + } + catch (NumberFormatException ex) {} + } + } + + CharacterSprite sprite = font.getChar(text.charAt(i)); + for (int r = 0; r < font.getHeight(); ++r) { + for (int c = 0; c < sprite.getWidth(); ++c) { + if (sprite.get(r, c)) { + setPixel(x + c, y + r, color); + } + } + } + x += sprite.getWidth() + 1; + } + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java new file mode 100644 index 0000000..4caf6a3 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java @@ -0,0 +1,42 @@ +package org.bukkit.craftbukkit.map; + +import net.minecraft.server.WorldMap; +import net.minecraft.server.WorldMapOrienter; +import org.bukkit.entity.Player; +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapCursorCollection; +import org.bukkit.map.MapRenderer; +import org.bukkit.map.MapView; + +public class CraftMapRenderer extends MapRenderer { + + private final CraftMapView mapView; + private final WorldMap worldMap; + + public CraftMapRenderer(CraftMapView mapView, WorldMap worldMap) { + super(false); + this.mapView = mapView; + this.worldMap = worldMap; + } + + @Override + public void render(MapView map, MapCanvas canvas, Player player) { + // Map + for (int x = 0; x < 128; ++x) { + for (int y = 0; y < 128; ++y) { + canvas.setPixel(x, y, worldMap.f[y * 128 + x]); + } + } + + // Cursors + MapCursorCollection cursors = canvas.getCursors(); + while (cursors.size() > 0) { + cursors.removeCursor(cursors.getCursor(0)); + } + for (int i = 0; i < worldMap.i.size(); ++i) { + WorldMapOrienter orienter = (WorldMapOrienter) worldMap.i.get(i); + cursors.addCursor(orienter.b, orienter.c, (byte)(orienter.d & 15), (byte)(orienter.a)); + } + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java new file mode 100644 index 0000000..dc0dc4a --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java @@ -0,0 +1,156 @@ +package org.bukkit.craftbukkit.map; + +import net.minecraft.server.WorldMap; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.map.MapRenderer; +import org.bukkit.map.MapView; + +import java.util.*; + +public final class CraftMapView implements MapView { + + private final Map renderCache = new HashMap(); + private final List renderers = new ArrayList(); + private final Map> canvases = new HashMap>(); + protected final WorldMap worldMap; + + public CraftMapView(WorldMap worldMap) { + this.worldMap = worldMap; + addRenderer(new CraftMapRenderer(this, worldMap)); + } + + public short getId() { + String text = worldMap.a; + if (text.startsWith("map_")) { + try { + return Short.parseShort(text.substring("map_".length())); + } + catch (NumberFormatException ex) { + throw new IllegalStateException("Map has non-numeric ID"); + } + } else { + throw new IllegalStateException("Map has invalid ID"); + } + } + + public boolean isVirtual() { + return renderers.size() > 0 && !(renderers.get(0) instanceof CraftMapRenderer); + } + + public Scale getScale() { + return Scale.valueOf(worldMap.e); + } + + public void setScale(Scale scale) { + worldMap.e = scale.getValue(); + } + + public World getWorld() { + byte dimension = worldMap.map; + for (World world : Bukkit.getServer().getWorlds()) { + if (((CraftWorld) world).getHandle().dimension == dimension) { + return world; + } + } + return null; + } + + public void setWorld(World world) { + worldMap.map = (byte) ((CraftWorld) world).getHandle().dimension; + } + + public int getCenterX() { + return worldMap.b; + } + + public int getCenterZ() { + return worldMap.c; + } + + public void setCenterX(int x) { + worldMap.b = x; + } + + public void setCenterZ(int z) { + worldMap.c = z; + } + + public List getRenderers() { + return new ArrayList(renderers); + } + + public void addRenderer(MapRenderer renderer) { + if (!renderers.contains(renderer)) { + renderers.add(renderer); + canvases.put(renderer, new HashMap()); + renderer.initialize(this); + } + } + + public boolean removeRenderer(MapRenderer renderer) { + if (renderers.contains(renderer)) { + renderers.remove(renderer); + for (Map.Entry entry : canvases.get(renderer).entrySet()) { + for (int x = 0; x < 128; ++x) { + for (int y = 0; y < 128; ++y) { + entry.getValue().setPixel(x, y, (byte) -1); + } + } + } + canvases.remove(renderer); + return true; + } else { + return false; + } + } + + private boolean isContextual() { + for (MapRenderer renderer : renderers) { + if (renderer.isContextual()) return true; + } + return false; + } + + public RenderData render(CraftPlayer player) { + boolean context = isContextual(); + RenderData render = renderCache.get(context ? player : null); + + if (render == null) { + render = new RenderData(); + renderCache.put(context ? player : null, render); + } + + if (context && renderCache.containsKey(null)) { + renderCache.remove(null); + } + + Arrays.fill(render.buffer, (byte) 0); + render.cursors.clear(); + + for (MapRenderer renderer : renderers) { + CraftMapCanvas canvas = canvases.get(renderer).get(renderer.isContextual() ? player : null); + if (canvas == null) { + canvas = new CraftMapCanvas(this); + canvases.get(renderer).put(renderer.isContextual() ? player : null, canvas); + } + + canvas.setBase(render.buffer); + renderer.render(this, canvas, player); + + byte[] buf = canvas.getBuffer(); + for (int i = 0; i < buf.length; ++i) { + if (buf[i] >= 0) render.buffer[i] = buf[i]; + } + + for (int i = 0; i < canvas.getCursors().size(); ++i) { + render.cursors.add(canvas.getCursors().getCursor(i)); + } + } + + return render; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java new file mode 100644 index 0000000..bfe044d --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java @@ -0,0 +1,17 @@ +package org.bukkit.craftbukkit.map; + +import org.bukkit.map.MapCursor; + +import java.util.ArrayList; + +public class RenderData { + + public final byte[] buffer; + public final ArrayList cursors; + + public RenderData() { + this.buffer = new byte[128 * 128]; + this.cursors = new ArrayList(); + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftFuture.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftFuture.java new file mode 100644 index 0000000..ecb0bac --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftFuture.java @@ -0,0 +1,101 @@ +package org.bukkit.craftbukkit.scheduler; + +import java.util.concurrent.*; + +public class CraftFuture implements Runnable, Future { + + private final CraftScheduler craftScheduler; + private final Callable callable; + private final ObjectContainer returnStore = new ObjectContainer(); + private boolean done = false; + private boolean running = false; + private boolean cancelled = false; + private Exception e = null; + private int taskId = -1; + + CraftFuture(CraftScheduler craftScheduler, Callable callable) { + this.callable = callable; + this.craftScheduler = craftScheduler; + } + + public void run() { + synchronized (this) { + if (cancelled) { + return; + } + running = true; + } + try { + returnStore.setObject(callable.call()); + } catch (Exception e) { + this.e = e; + } + synchronized (this) { + running = false; + done = true; + this.notify(); + } + } + + public T get() throws InterruptedException, ExecutionException { + try { + return get(0L, TimeUnit.MILLISECONDS); + } catch (TimeoutException te) {} + return null; + } + + public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + synchronized (this) { + if (isDone()) { + return getResult(); + } + this.wait(TimeUnit.MILLISECONDS.convert(timeout, unit)); + return getResult(); + } + } + + public T getResult() throws ExecutionException { + if (cancelled) { + throw new CancellationException(); + } + if (e != null) { + throw new ExecutionException(e); + } + return returnStore.getObject(); + } + + public boolean isDone() { + synchronized (this) { + return done; + } + } + + public boolean isCancelled() { + synchronized (this) { + return cancelled; + } + } + + public boolean cancel(boolean mayInterruptIfRunning) { + synchronized (this) { + if (cancelled) { + return false; + } + cancelled = true; + if (taskId != -1) { + craftScheduler.cancelTask(taskId); + } + if (!running && !done) { + return true; + } else { + return false; + } + } + } + + public void setTaskId(int taskId) { + synchronized (this) { + this.taskId = taskId; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java new file mode 100644 index 0000000..2e33a91 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -0,0 +1,430 @@ +package org.bukkit.craftbukkit.scheduler; + +import com.legacyminecraft.poseidon.Poseidon; +import com.legacyminecraft.poseidon.utility.PerformanceStatistic; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitWorker; + +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class CraftScheduler implements BukkitScheduler, Runnable { + + private static final Logger logger = Logger.getLogger("Minecraft"); + + private final CraftServer server; + + private final CraftThreadManager craftThreadManager = new CraftThreadManager(); + + private final LinkedList mainThreadQueue = new LinkedList(); + private final LinkedList syncedTasks = new LinkedList(); + + private final TreeMap schedulerQueue = new TreeMap(); + + private final Object currentTickSync = new Object(); + private Long currentTick = 0L; + + // This lock locks the mainThreadQueue and the currentTick value + private final Lock mainThreadLock = new ReentrantLock(); + private final Lock syncedTasksLock = new ReentrantLock(); + + public void run() { + + while (true) { + boolean stop = false; + long firstTick = -1; + long currentTick = -1; + CraftTask first = null; + do { + synchronized (schedulerQueue) { + first = null; + if (!schedulerQueue.isEmpty()) { + first = schedulerQueue.firstKey(); + if (first != null) { + currentTick = getCurrentTick(); + + firstTick = first.getExecutionTick(); + + if (currentTick >= firstTick) { + schedulerQueue.remove(first); + processTask(first); + if (first.getPeriod() >= 0) { + first.updateExecution(); + schedulerQueue.put(first, first.isSync()); + } + } else { + stop = true; + } + } else { + stop = true; + } + } else { + stop = true; + } + } + } while (!stop); + + long sleepTime = 0; + if (first == null) { + sleepTime = 60000L; + } else { + currentTick = getCurrentTick(); + sleepTime = (firstTick - currentTick) * 50 + 25; + } + + if (sleepTime < 50L) { + sleepTime = 50L; + } else if (sleepTime > 60000L) { + sleepTime = 60000L; + } + + synchronized (schedulerQueue) { + try { + schedulerQueue.wait(sleepTime); + } catch (InterruptedException ie) {} + } + } + } + + void processTask(CraftTask task) { + if (task.isSync()) { + addToMainThreadQueue(task); + } else { + craftThreadManager.executeTask(task.getTask(), task.getOwner(), task.getIdNumber()); + } + } + + public CraftScheduler(CraftServer server) { + this.server = server; + + Thread t = new Thread(this); + t.start(); + + // Project Poseidon - Start - Synchronous task performance reporting + this.taskPerformanceEnabled = Poseidon.getServer().getConfig().getConfigBoolean("settings.performance-monitoring.task-reporting.enabled"); + this.printOnSlowTask = Poseidon.getServer().getConfig().getConfigBoolean("settings.performance-monitoring.task-reporting.print-on-slow-tasks.enabled"); + this.printOnSlowTaskThreshold = Poseidon.getServer().getConfig().getConfigInteger("settings.performance-monitoring.task-reporting.print-on-slow-tasks.value"); + + this.taskPerformance = Poseidon.getServer().getTaskPerformance(); + // Project Poseidon - End - Synchronous task performance reporting + } + + // Project Poseidon - Start - Synchronous task performance reporting + private final boolean taskPerformanceEnabled; // Project Poseidon + private final Map taskPerformance; // Project Poseidon + + private final boolean printOnSlowTask; + private final int printOnSlowTaskThreshold; + + // Project Poseidon - End - Synchronous task performance reporting + + + // If the main thread cannot obtain the lock, it doesn't wait + public void mainThreadHeartbeat(long currentTick) { + if (syncedTasksLock.tryLock()) { + try { + if (mainThreadLock.tryLock()) { + try { + this.currentTick = currentTick; + while (!mainThreadQueue.isEmpty()) { + syncedTasks.addLast(mainThreadQueue.removeFirst()); + } + } finally { + mainThreadLock.unlock(); + } + } + long breakTime = System.currentTimeMillis() + 35; // max time spent in loop = 35ms + while (!syncedTasks.isEmpty() && System.currentTimeMillis() <= breakTime) { + CraftTask task = syncedTasks.removeFirst(); + long startTime = System.currentTimeMillis(); // Poseidon - Synchronous task performance reporting + try { + task.getTask().run(); + + // Poseidon - Start - Synchronous task performance reporting + if(taskPerformanceEnabled) { + long duration = System.currentTimeMillis() - startTime; // Calculate duration in milliseconds + + String taskKey = (task == null || task.getOwner() == null || task.getOwner().getDescription() == null || task.getOwner().getDescription().getName() == null) + ? "Unknown" + : task.getOwner().getDescription().getName(); + + taskPerformance.computeIfAbsent(taskKey, k -> new PerformanceStatistic()).update(duration); + + // If task took longer than the threshold, print the performance statistics for the listener + if (printOnSlowTask && duration > printOnSlowTaskThreshold) { + server.getLogger().log(Level.WARNING, String.format( + "[Poseidon] Synchronous task from plugin %s took %d milliseconds. Statistics: %s", + taskKey, + duration, + taskPerformance.get(taskKey).printStats() + )); + } + } + // Poseidon - End - Synchronous task performance reporting + } catch (Throwable t) { + // Bad plugin! + logger.log(Level.WARNING, "Task of '" + task.getOwner().getDescription().getName() + "' generated an exception", t); + synchronized (schedulerQueue) { + schedulerQueue.remove(task); + } + } + } + } finally { + syncedTasksLock.unlock(); + } + } + } + + long getCurrentTick() { + mainThreadLock.lock(); + long tempTick = 0; + try { + tempTick = currentTick; + } finally { + mainThreadLock.unlock(); + } + return tempTick; + } + + void addToMainThreadQueue(CraftTask task) { + mainThreadLock.lock(); + try { + mainThreadQueue.addLast(task); + } finally { + mainThreadLock.unlock(); + } + } + + void wipeSyncedTasks() { + syncedTasksLock.lock(); + try { + syncedTasks.clear(); + } finally { + syncedTasksLock.unlock(); + } + } + + void wipeMainThreadQueue() { + mainThreadLock.lock(); + try { + mainThreadQueue.clear(); + } finally { + mainThreadLock.unlock(); + } + } + + public int scheduleSyncDelayedTask(Plugin plugin, Runnable task, long delay) { + return scheduleSyncRepeatingTask(plugin, task, delay, -1); + } + + public int scheduleSyncDelayedTask(Plugin plugin, Runnable task) { + return scheduleSyncDelayedTask(plugin, task, 0L); + } + + public int scheduleSyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } + if (task == null) { + throw new IllegalArgumentException("Task cannot be null"); + } + if (delay < 0) { + throw new IllegalArgumentException("Delay cannot be less than 0"); + } + + CraftTask newTask = new CraftTask(plugin, task, true, getCurrentTick() + delay, period); + + synchronized (schedulerQueue) { + schedulerQueue.put(newTask, true); + schedulerQueue.notify(); + } + return newTask.getIdNumber(); + } + + public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task, long delay) { + return scheduleAsyncRepeatingTask(plugin, task, delay, -1); + } + + public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task) { + return scheduleAsyncDelayedTask(plugin, task, 0L); + } + + public int scheduleAsyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } + if (task == null) { + throw new IllegalArgumentException("Task cannot be null"); + } + if (delay < 0) { + throw new IllegalArgumentException("Delay cannot be less than 0"); + } + + CraftTask newTask = new CraftTask(plugin, task, false, getCurrentTick() + delay, period); + + synchronized (schedulerQueue) { + schedulerQueue.put(newTask, false); + schedulerQueue.notify(); + } + return newTask.getIdNumber(); + } + + public Future callSyncMethod(Plugin plugin, Callable task) { + CraftFuture craftFuture = new CraftFuture(this, task); + synchronized (craftFuture) { + int taskId = scheduleSyncDelayedTask(plugin, craftFuture); + craftFuture.setTaskId(taskId); + } + return craftFuture; + } + + public void cancelTask(int taskId) { + syncedTasksLock.lock(); + try { + synchronized (schedulerQueue) { + mainThreadLock.lock(); + try { + Iterator itr = schedulerQueue.keySet().iterator(); + while (itr.hasNext()) { + CraftTask current = itr.next(); + if (current.getIdNumber() == taskId) { + itr.remove(); + } + } + itr = mainThreadQueue.iterator(); + while (itr.hasNext()) { + CraftTask current = itr.next(); + if (current.getIdNumber() == taskId) { + itr.remove(); + } + } + itr = syncedTasks.iterator(); + while (itr.hasNext()) { + CraftTask current = itr.next(); + if (current.getIdNumber() == taskId) { + itr.remove(); + } + } + } finally { + mainThreadLock.unlock(); + } + } + } finally { + syncedTasksLock.unlock(); + } + + craftThreadManager.interruptTask(taskId); + } + + public void cancelTasks(Plugin plugin) { + syncedTasksLock.lock(); + try { + synchronized (schedulerQueue) { + mainThreadLock.lock(); + try { + Iterator itr = schedulerQueue.keySet().iterator(); + while (itr.hasNext()) { + CraftTask current = itr.next(); + if (current.getOwner().equals(plugin)) { + itr.remove(); + } + } + itr = mainThreadQueue.iterator(); + while (itr.hasNext()) { + CraftTask current = itr.next(); + if (current.getOwner().equals(plugin)) { + itr.remove(); + } + } + itr = syncedTasks.iterator(); + while (itr.hasNext()) { + CraftTask current = itr.next(); + if (current.getOwner().equals(plugin)) { + itr.remove(); + } + } + } finally { + mainThreadLock.unlock(); + } + } + } finally { + syncedTasksLock.unlock(); + } + + craftThreadManager.interruptTasks(plugin); + } + + public void cancelAllTasks() { + synchronized (schedulerQueue) { + schedulerQueue.clear(); + } + wipeMainThreadQueue(); + wipeSyncedTasks(); + + craftThreadManager.interruptAllTasks(); + } + + public boolean isCurrentlyRunning(int taskId) { + return craftThreadManager.isAlive(taskId); + } + + public boolean isQueued(int taskId) { + synchronized (schedulerQueue) { + Iterator itr = schedulerQueue.keySet().iterator(); + while (itr.hasNext()) { + CraftTask current = itr.next(); + if (current.getIdNumber() == taskId) { + return true; + } + } + return false; + } + } + + public List getActiveWorkers() { + synchronized (craftThreadManager.workers) { + List workerList = new ArrayList(craftThreadManager.workers.size()); + Iterator itr = craftThreadManager.workers.iterator(); + + while (itr.hasNext()) { + workerList.add((BukkitWorker) itr.next()); + } + return workerList; + } + } + + public List getPendingTasks() { + List taskList = null; + syncedTasksLock.lock(); + try { + synchronized (schedulerQueue) { + mainThreadLock.lock(); + try { + taskList = new ArrayList(mainThreadQueue.size() + syncedTasks.size() + schedulerQueue.size()); + taskList.addAll(mainThreadQueue); + taskList.addAll(syncedTasks); + taskList.addAll(schedulerQueue.keySet()); + } finally { + mainThreadLock.unlock(); + } + } + } finally { + syncedTasksLock.unlock(); + } + List newTaskList = new ArrayList(taskList.size()); + + for (CraftTask craftTask : taskList) { + newTaskList.add((BukkitTask) craftTask); + } + return newTaskList; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java new file mode 100644 index 0000000..d2c6777 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java @@ -0,0 +1,110 @@ +package org.bukkit.craftbukkit.scheduler; + +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; + +public class CraftTask implements Comparable, BukkitTask { + + private final Runnable task; + private final boolean syncTask; + private long executionTick; + private final long period; + private final Plugin owner; + private final int idNumber; + + private static Integer idCounter = 1; + private static Object idCounterSync = new Object(); + + CraftTask(Plugin owner, Runnable task, boolean syncTask) { + this(owner, task, syncTask, -1, -1); + } + + CraftTask(Plugin owner, Runnable task, boolean syncTask, long executionTick) { + this(owner, task, syncTask, executionTick, -1); + } + + CraftTask(Plugin owner, Runnable task, boolean syncTask, long executionTick, long period) { + this.task = task; + this.syncTask = syncTask; + this.executionTick = executionTick; + this.period = period; + this.owner = owner; + this.idNumber = CraftTask.getNextId(); + } + + static int getNextId() { + synchronized (idCounterSync) { + idCounter++; + return idCounter; + } + } + + Runnable getTask() { + return task; + } + + public boolean isSync() { + return syncTask; + } + + long getExecutionTick() { + return executionTick; + } + + long getPeriod() { + return period; + } + + public Plugin getOwner() { + return owner; + } + + void updateExecution() { + executionTick += period; + } + + public int getTaskId() { + return getIdNumber(); + } + + int getIdNumber() { + return idNumber; + } + + public int compareTo(Object other) { + if (!(other instanceof CraftTask)) { + return 0; + } else { + CraftTask o = (CraftTask) other; + long timeDiff = executionTick - o.getExecutionTick(); + if (timeDiff > 0) { + return 1; + } else if (timeDiff < 0) { + return -1; + } else { + CraftTask otherCraftTask = (CraftTask) other; + return getIdNumber() - otherCraftTask.getIdNumber(); + } + } + } + + @Override + public boolean equals(Object other) { + + if (other == null) { + return false; + } + + if (!(other instanceof CraftTask)) { + return false; + } + + CraftTask otherCraftTask = (CraftTask) other; + return otherCraftTask.getIdNumber() == getIdNumber(); + } + + @Override + public int hashCode() { + return getIdNumber(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftThreadManager.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftThreadManager.java new file mode 100644 index 0000000..ca09cc1 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftThreadManager.java @@ -0,0 +1,68 @@ +package org.bukkit.craftbukkit.scheduler; + +import org.bukkit.plugin.Plugin; + +import java.util.HashSet; +import java.util.Iterator; + +public class CraftThreadManager { + + final HashSet workers = new HashSet(); + + void executeTask(Runnable task, Plugin owner, int taskId) { + + CraftWorker craftWorker = new CraftWorker(this, task, owner, taskId); + synchronized (workers) { + workers.add(craftWorker); + } + + } + + void interruptTask(int taskId) { + synchronized (workers) { + Iterator itr = workers.iterator(); + while (itr.hasNext()) { + CraftWorker craftWorker = itr.next(); + if (craftWorker.getTaskId() == taskId) { + craftWorker.interrupt(); + } + } + } + } + + void interruptTasks(Plugin owner) { + synchronized (workers) { + Iterator itr = workers.iterator(); + while (itr.hasNext()) { + CraftWorker craftWorker = itr.next(); + if (craftWorker.getOwner().equals(owner)) { + craftWorker.interrupt(); + } + } + } + } + + void interruptAllTasks() { + synchronized (workers) { + Iterator itr = workers.iterator(); + while (itr.hasNext()) { + CraftWorker craftWorker = itr.next(); + craftWorker.interrupt(); + } + } + } + + boolean isAlive(int taskId) { + synchronized (workers) { + Iterator itr = workers.iterator(); + while (itr.hasNext()) { + CraftWorker craftWorker = itr.next(); + if (craftWorker.getTaskId() == taskId) { + return craftWorker.isAlive(); + } + } + // didn't find it, so it must have been removed + return false; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java new file mode 100644 index 0000000..94aa411 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java @@ -0,0 +1,90 @@ +package org.bukkit.craftbukkit.scheduler; + +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitWorker; + +public class CraftWorker implements Runnable, BukkitWorker { + + private static int hashIdCounter = 1; + private static Object hashIdCounterSync = new Object(); + + private final int hashId; + + private final Plugin owner; + private final int taskId; + + private final Thread t; + private final CraftThreadManager parent; + + private final Runnable task; + + CraftWorker(CraftThreadManager parent, Runnable task, Plugin owner, int taskId) { + this.parent = parent; + this.taskId = taskId; + this.task = task; + this.owner = owner; + this.hashId = CraftWorker.getNextHashId(); + t = new Thread(this); + t.start(); + } + + public void run() { + + try { + task.run(); + } catch (Exception e) { + e.printStackTrace(); + } + + synchronized (parent.workers) { + parent.workers.remove(this); + } + + } + + public int getTaskId() { + return taskId; + } + + public Plugin getOwner() { + return owner; + } + + public Thread getThread() { + return t; + } + + public void interrupt() { + t.interrupt(); + } + + public boolean isAlive() { + return t.isAlive(); + } + + private static int getNextHashId() { + synchronized (hashIdCounterSync) { + return hashIdCounter++; + } + } + + @Override + public int hashCode() { + return hashId; + } + + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } + + if (!(other instanceof CraftWorker)) { + return false; + } + + CraftWorker otherCraftWorker = (CraftWorker) other; + return otherCraftWorker.hashCode() == hashId; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/ObjectContainer.java b/src/main/java/org/bukkit/craftbukkit/scheduler/ObjectContainer.java new file mode 100644 index 0000000..c0fa37c --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/ObjectContainer.java @@ -0,0 +1,15 @@ +package org.bukkit.craftbukkit.scheduler; + +public class ObjectContainer { + + T object; + + public void setObject(T object) { + this.object = object; + } + + public T getObject() { + return object; + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/ConcurrentSoftMap.java b/src/main/java/org/bukkit/craftbukkit/util/ConcurrentSoftMap.java new file mode 100644 index 0000000..029c668 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/ConcurrentSoftMap.java @@ -0,0 +1,267 @@ +package org.bukkit.craftbukkit.util; + +import com.google.common.collect.MapMaker; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Creates a map that uses soft reference. This indicates to the garbage collector + * that they can be removed if necessary + * + * A minimum number of strong references can be set. These most recent N objects added + * to the map will not be removed by the garbage collector. + * + * Objects will never be removed if they are referenced strongly from somewhere else + + * Note: While data corruption won't happen, the garbage collector is potentially async + * This could lead to the return values from containsKey() and similar methods being + * out of date by the time they are used. The class could return null when the object + * is retrieved by a .get() call directly after a .containsKey() call returned true + * + * @deprecated Use {@link MapMaker} to create a concurrent soft-reference map, this class is inefficient and will be removed + * @author raphfrk + */ + +@Deprecated +public class ConcurrentSoftMap { + + private final ConcurrentHashMap> map = new ConcurrentHashMap>(); + private final ReferenceQueue queue = new ReferenceQueue(); + private final LinkedList strongReferenceQueue = new LinkedList(); + private final int strongReferenceSize; + + public ConcurrentSoftMap() { + this(20); + } + + public ConcurrentSoftMap(int size) { + strongReferenceSize = size; + } + + // When a soft reference is deleted by the garbage collector, it is set to reference null + // and added to the queue + // + // However, these null references still exist in the ConcurrentHashMap as keys. This method removes these keys. + // + // It is called whenever there is a method call of the map. + + private void emptyQueue() { + SoftMapReference ref; + + while ((ref = (SoftMapReference) queue.poll()) != null) { + map.remove(ref.key); + } + } + + public void clear() { + synchronized (strongReferenceQueue) { + strongReferenceQueue.clear(); + } + map.clear(); + emptyQueue(); + } + + // Shouldn't support this, since the garbage collection is async + + public boolean containsKey(K key) { + emptyQueue(); + return map.containsKey(key); + } + + // Shouldn't support this, since the garbage collection is async + + public boolean containsValue(V value) { + emptyQueue(); + return map.containsValue(value); + } + + // Shouldn't support this since it would create strong references to all the entries + + public Set entrySet() { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap does not support this operation, since it creates potentially stong references"); + } + + // Doesn't support these either + + public boolean equals(Object o) { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap doesn't support equals checks"); + } + + // This operation returns null if the entry is not in the map + + public V get(K key) { + emptyQueue(); + return fastGet(key); + } + + private V fastGet(K key) { + SoftMapReference ref = map.get(key); + + if (ref == null) { + return null; + } + V value = ref.get(); + + if (value != null) { + synchronized (strongReferenceQueue) { + strongReferenceQueue.addFirst(value); + if (strongReferenceQueue.size() > strongReferenceSize) { + strongReferenceQueue.removeLast(); + } + } + } + return value; + } + + // Doesn't support this either + + public int hashCode() { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap doesn't support hashCode"); + } + + // This is another risky method, since again, garbage collection is async + + public boolean isEmpty() { + emptyQueue(); + return map.isEmpty(); + } + + // Return all the keys, again could go out of date + + public Set keySet() { + emptyQueue(); + return map.keySet(); + } + + // Adds the mapping to the map + + public V put(K key, V value) { + emptyQueue(); + V old = fastGet(key); + fastPut(key, value); + return old; + } + + private void fastPut(K key, V value) { + map.put(key, new SoftMapReference(key, value, queue)); + synchronized (strongReferenceQueue) { + strongReferenceQueue.addFirst(value); + if (strongReferenceQueue.size() > strongReferenceSize) { + strongReferenceQueue.removeLast(); + } + } + } + + public V putIfAbsent(K key, V value) { + emptyQueue(); + return fastPutIfAbsent(key, value); + } + + private V fastPutIfAbsent(K key, V value) { + V ret = null; + + if (map.containsKey(key)) { + SoftMapReference current = map.get(key); + + if (current != null) { + ret = current.get(); + } + } + + if (ret == null) { + SoftMapReference newValue = new SoftMapReference(key, value, queue); + boolean success = false; + + while (!success) { + SoftMapReference oldValue = map.putIfAbsent(key, newValue); + + if (oldValue == null) { // put was successful (key didn't exist) + ret = null; + success = true; + } else { + ret = oldValue.get(); + if (ret == null) { // key existed, but referenced null + success = map.replace(key, oldValue, newValue); // try to swap old for new + } else { // key existed, and referenced a valid object + success = true; + } + } + } + } + + if (ret == null) { + synchronized (strongReferenceQueue) { + strongReferenceQueue.addFirst(value); + if (strongReferenceQueue.size() > strongReferenceSize) { + strongReferenceQueue.removeLast(); + } + } + } + + return ret; + } + + // Adds the mappings to the map + + public void putAll(Map other) { + emptyQueue(); + Iterator itr = other.keySet().iterator(); + while (itr.hasNext()) { + K key = itr.next(); + fastPut(key, (V) other.get(key)); + } + } + + // Remove object + + public V remove(K key) { + emptyQueue(); + SoftMapReference ref = map.remove(key); + + if (ref != null) { + return ref.get(); + } + return null; + } + + // Returns size, could go out of date + + public int size() { + emptyQueue(); + return map.size(); + } + + // Shouldn't support this since it would create strong references to all the entries + + public Collection values() { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap does not support this operation, since it creates potentially stong references"); + } + + private static class SoftMapReference extends SoftReference { + K key; + + SoftMapReference(K key, V value, ReferenceQueue queue) { + super(value, queue); + this.key = key; + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } + if (!(o instanceof SoftMapReference)) { + return false; + } + SoftMapReference other = (SoftMapReference) o; + return other.get() == get(); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/Java15Compat.java b/src/main/java/org/bukkit/craftbukkit/util/Java15Compat.java new file mode 100644 index 0000000..c9c5f28 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/Java15Compat.java @@ -0,0 +1,34 @@ +package org.bukkit.craftbukkit.util; + +import java.lang.reflect.Array; + +public class Java15Compat { + public static T[] Arrays_copyOf(T[] original, int newLength) { + if (0 <= newLength) { + return org.bukkit.util.Java15Compat.Arrays_copyOfRange(original, 0, newLength); + } + throw new NegativeArraySizeException(); + } + + public static long[] Arrays_copyOf(long[] original, int newLength) { + if (0 <= newLength) { + return Arrays_copyOfRange(original, 0, newLength); + } + throw new NegativeArraySizeException(); + } + + private static long[] Arrays_copyOfRange(long[] original, int start, int end) { + if (original.length >= start && 0 <= start) { + if (start <= end) { + int length = end - start; + int copyLength = Math.min(length, original.length - start); + long[] copy = (long[]) Array.newInstance(original.getClass().getComponentType(), length); + System.arraycopy(original, start, copy, 0, copyLength); + return copy; + } + throw new IllegalArgumentException(); + } + throw new ArrayIndexOutOfBoundsException(); + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHash.java b/src/main/java/org/bukkit/craftbukkit/util/LongHash.java new file mode 100644 index 0000000..f3fc7d1 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/LongHash.java @@ -0,0 +1,36 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.bukkit.craftbukkit.util; + +/** + * + * @author Nathan + */ +public abstract class LongHash { + static long toLong(int msw, int lsw) { + return ((long) msw << 32) + lsw - Integer.MIN_VALUE; + } + + static int msw(long l) { + return (int) (l >> 32); + } + + static int lsw(long l) { + return (int) (l & 0xFFFFFFFF) + Integer.MIN_VALUE; + } + + public boolean containsKey(int msw, int lsw) { + return containsKey(toLong(msw, lsw)); + } + + public void remove(int msw, int lsw) { + remove(toLong(msw, lsw)); + } + + public abstract boolean containsKey(long key); + + public abstract void remove(long key); +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHashset.java b/src/main/java/org/bukkit/craftbukkit/util/LongHashset.java new file mode 100644 index 0000000..28aab11 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/LongHashset.java @@ -0,0 +1,150 @@ +package org.bukkit.craftbukkit.util; + +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +import static org.bukkit.craftbukkit.util.Java15Compat.Arrays_copyOf; + +public class LongHashset extends LongHash { + long[][][] values = new long[256][][]; + int count = 0; + ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + ReadLock rl = rwl.readLock(); + WriteLock wl = rwl.writeLock(); + + public boolean isEmpty() { + rl.lock(); + try { + return this.count == 0; + } finally { + rl.unlock(); + } + } + + public void add(int msw, int lsw) { + add(toLong(msw, lsw)); + } + + public void add(long key) { + wl.lock(); + try { + int mainIdx = (int) (key & 255); + long outer[][] = this.values[mainIdx]; + if (outer == null) this.values[mainIdx] = outer = new long[256][]; + + int outerIdx = (int) ((key >> 32) & 255); + long inner[] = outer[outerIdx]; + + if (inner == null) { + synchronized (this) { + outer[outerIdx] = inner = new long[1]; + inner[0] = key; + this.count++; + } + } else { + int i; + for (i = 0; i < inner.length; i++) { + if (inner[i] == key) { + return; + } + } + inner = Arrays_copyOf(inner, i + 1); + outer[outerIdx] = inner; + inner[i] = key; + this.count++; + } + } finally { + wl.unlock(); + } + } + + public boolean containsKey(long key) { + rl.lock(); + try { + long[][] outer = this.values[(int) (key & 255)]; + if (outer == null) return false; + + long[] inner = outer[(int) ((key >> 32) & 255)]; + if (inner == null) return false; + + for (long entry: inner) { + if (entry == key) return true; + } + return false; + } finally { + rl.unlock(); + } + } + + public void remove(long key) { + wl.lock(); + try { + long[][] outer = this.values[(int) (key & 255)]; + if (outer == null) return; + + long[] inner = outer[(int) ((key >> 32) & 255)]; + if (inner == null) return; + + int max = inner.length - 1; + for (int i = 0; i <= max; i++) { + if (inner[i] == key) { + this.count--; + if (i != max) { + inner[i] = inner[max]; + } + + outer[(int) ((key >> 32) & 255)] = (max == 0 ? null : Arrays_copyOf(inner, max)); + return; + } + } + } finally { + wl.unlock(); + } + } + + public long popFirst() { + wl.lock(); + try { + for (long[][] outer: this.values) { + if (outer == null) continue; + + for (int i = 0; i < outer.length; i++) { + long[] inner = outer[i]; + if (inner == null || inner.length == 0) continue; + + this.count--; + long ret = inner[inner.length - 1]; + outer[i] = Arrays_copyOf(inner, inner.length - 1); + + return ret; + } + } + } finally { + wl.unlock(); + } + return 0; + } + + public long[] keys() { + int index = 0; + rl.lock(); + try { + long[] ret = new long[this.count]; + for (long[][] outer: this.values) { + if (outer == null) continue; + + for (long[] inner: outer) { + if (inner == null) continue; + + for (long entry: inner) { + ret[index++] = entry; + } + } + } + return ret; + } finally { + rl.unlock(); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHashtable.java b/src/main/java/org/bukkit/craftbukkit/util/LongHashtable.java new file mode 100644 index 0000000..79d8304 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/LongHashtable.java @@ -0,0 +1,143 @@ +package org.bukkit.craftbukkit.util; + +import net.minecraft.server.Chunk; +import net.minecraft.server.MinecraftServer; + +import java.util.ArrayList; + +import static org.bukkit.craftbukkit.util.Java15Compat.Arrays_copyOf; + +public class LongHashtable extends LongHash { + Object[][][] values = new Object[256][][]; + Entry cache = null; + + public void put(int msw, int lsw, V value) { + put(toLong(msw, lsw), value); + if (value instanceof Chunk) { + Chunk c = (Chunk) value; + if (msw != c.x || lsw != c.z) { + MinecraftServer.log.info("Chunk (" + c.x + ", " + c.z + ") stored at (" + msw + ", " + lsw + ")"); + Throwable x = new Throwable(); + x.fillInStackTrace(); + x.printStackTrace(); + } + } + } + + public V get(int msw, int lsw) { + V value = get(toLong(msw, lsw)); + if (value instanceof Chunk) { + Chunk c = (Chunk) value; + if (msw != c.x || lsw != c.z) { + MinecraftServer.log.info("Chunk (" + c.x + ", " + c.z + ") stored at (" + msw + ", " + lsw + ")"); + Throwable x = new Throwable(); + x.fillInStackTrace(); + x.printStackTrace(); + } + } + return value; + } + + public synchronized void put(long key, V value) { + int mainIdx = (int) (key & 255); + Object[][] outer = this.values[mainIdx]; + if (outer == null) this.values[mainIdx] = outer = new Object[256][]; + + int outerIdx = (int) ((key >> 32) & 255); + Object[] inner = outer[outerIdx]; + + if (inner == null) { + outer[outerIdx] = inner = new Object[5]; + inner[0] = this.cache = new Entry(key, value); + } else { + int i; + for (i = 0; i < inner.length; i++) { + if (inner[i] == null || ((Entry) inner[i]).key == key) { + inner[i] = this.cache = new Entry(key, value); + return; + } + } + + outer[outerIdx] = inner = Arrays_copyOf(inner, i + i); + inner[i] = new Entry(key, value); + } + } + + public synchronized V get(long key) { + return containsKey(key) ? (V) cache.value : null; + } + + public synchronized boolean containsKey(long key) { + if (this.cache != null && cache.key == key) return true; + + int outerIdx = (int) ((key >> 32) & 255); + Object[][] outer = this.values[(int) (key & 255)]; + if (outer == null) return false; + + Object[] inner = outer[outerIdx]; + if (inner == null) return false; + + for (int i = 0; i < inner.length; i++) { + Entry e = (Entry) inner[i]; + if (e == null) { + return false; + } else if (e.key == key) { + this.cache = e; + return true; + } + } + return false; + } + + public synchronized void remove(long key) { + Object[][] outer = this.values[(int) (key & 255)]; + if (outer == null) return; + + Object[] inner = outer[(int) ((key >> 32) & 255)]; + if (inner == null) return; + + for (int i = 0; i < inner.length; i++) { + if (inner[i] == null) continue; + + if (((Entry) inner[i]).key == key) { + for (i++; i < inner.length; i++) { + if (inner[i] == null) break; + inner[i-1] = inner[i]; + } + + inner[i-1] = null; + this.cache = null; + return; + } + } + } + + public synchronized ArrayList values() { + ArrayList ret = new ArrayList(); + + for (Object[][] outer: this.values) { + if (outer == null) continue; + + for (Object[] inner: outer) { + if (inner == null) continue; + + for (Object entry: inner) { + if (entry == null) break; + + ret.add((V) ((Entry) entry).value); + } + } + } + return ret; + } + + private class Entry { + long key; + Object value; + + Entry(long k, Object v) { + this.key = k; + this.value = v; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java new file mode 100644 index 0000000..5e555d6 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java @@ -0,0 +1,17 @@ + +package org.bukkit.craftbukkit.util; + +import net.minecraft.server.MinecraftServer; + +public class ServerShutdownThread extends Thread { + private final MinecraftServer server; + + public ServerShutdownThread(MinecraftServer server) { + this.server = server; + } + + @Override + public void run() { + server.stop(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/ShortConsoleLogFormatter.java b/src/main/java/org/bukkit/craftbukkit/util/ShortConsoleLogFormatter.java new file mode 100644 index 0000000..392626b --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/ShortConsoleLogFormatter.java @@ -0,0 +1,62 @@ +package org.bukkit.craftbukkit.util; + +import joptsimple.OptionException; +import joptsimple.OptionSet; +import net.minecraft.server.MinecraftServer; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.SimpleDateFormat; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +public class ShortConsoleLogFormatter extends Formatter { + private final SimpleDateFormat date; + + public ShortConsoleLogFormatter(MinecraftServer server) { + OptionSet options = server.options; + SimpleDateFormat date = null; + + if (options.has("date-format")) { + try { + Object object = options.valueOf("date-format"); + + if ((object != null) && (object instanceof SimpleDateFormat)) { + date = (SimpleDateFormat) object; + } + } catch (OptionException ex) { + System.err.println("Given date format is not valid. Falling back to default."); + } + } else if (options.has("nojline")) { + date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + + if (date == null) { + date = new SimpleDateFormat("HH:mm:ss"); + } + + this.date = date; + } + + @Override + public String format(LogRecord record) { + StringBuilder builder = new StringBuilder(); + Throwable ex = record.getThrown(); + + builder.append(date.format(record.getMillis())); + builder.append(" ["); + builder.append(record.getLevel().getLocalizedName().toUpperCase()); + builder.append("] "); + builder.append(record.getMessage()); + builder.append('\n'); + + if (ex != null) { + StringWriter writer = new StringWriter(); + ex.printStackTrace(new PrintWriter(writer)); + builder.append(writer); + } + + return builder.toString(); + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleHandler.java b/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleHandler.java new file mode 100644 index 0000000..b3a0264 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleHandler.java @@ -0,0 +1,39 @@ +package org.bukkit.craftbukkit.util; + +import jline.ConsoleReader; +import org.bukkit.craftbukkit.Main; + +import java.io.IOException; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TerminalConsoleHandler extends ConsoleHandler { + private final ConsoleReader reader; + + public TerminalConsoleHandler(ConsoleReader reader) { + super(); + this.reader = reader; + } + + @Override + public synchronized void flush() { + try { + if (Main.useJline) { + reader.printString(ConsoleReader.RESET_LINE + ""); + reader.flushConsole(); + super.flush(); + try { + reader.drawLine(); + } catch (Throwable ex) { + reader.getCursorBuffer().clearBuffer(); + } + reader.flushConsole(); + } else { + super.flush(); + } + } catch (IOException ex) { + Logger.getLogger(TerminalConsoleHandler.class.getName()).log(Level.SEVERE, null, ex); + } + } +} diff --git a/src/main/java/org/bukkit/entity/AnimalTamer.java b/src/main/java/org/bukkit/entity/AnimalTamer.java new file mode 100644 index 0000000..058f857 --- /dev/null +++ b/src/main/java/org/bukkit/entity/AnimalTamer.java @@ -0,0 +1,3 @@ +package org.bukkit.entity; + +public interface AnimalTamer {} diff --git a/src/main/java/org/bukkit/entity/Animals.java b/src/main/java/org/bukkit/entity/Animals.java new file mode 100644 index 0000000..82736f2 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Animals.java @@ -0,0 +1,9 @@ +package org.bukkit.entity; + +/** + * Represents an Animal. + * + * @author Cogito + * + */ +public interface Animals extends Creature {} diff --git a/src/main/java/org/bukkit/entity/Arrow.java b/src/main/java/org/bukkit/entity/Arrow.java new file mode 100644 index 0000000..26d3473 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Arrow.java @@ -0,0 +1,6 @@ +package org.bukkit.entity; + +/** + * Represents an arrow. + */ +public interface Arrow extends Projectile {} diff --git a/src/main/java/org/bukkit/entity/Boat.java b/src/main/java/org/bukkit/entity/Boat.java new file mode 100644 index 0000000..b781b02 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Boat.java @@ -0,0 +1,23 @@ +package org.bukkit.entity; + +/** + * Represents a boat entity. + * + * @author sk89q + */ +public interface Boat extends Vehicle { + + /** + * Gets the maximum speed of a boat. The speed is unrelated to the velocity. + * + * @param speed + */ + public double getMaxSpeed(); + + /** + * Sets the maximum speed of a boat. Must be nonnegative. Default is 0.4D. + * + * @param speed + */ + public void setMaxSpeed(double speed); +} diff --git a/src/main/java/org/bukkit/entity/Chicken.java b/src/main/java/org/bukkit/entity/Chicken.java new file mode 100644 index 0000000..26e9c71 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Chicken.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Chicken. + * + * @author Cogito + * + */ +public interface Chicken extends Animals {} diff --git a/src/main/java/org/bukkit/entity/Cow.java b/src/main/java/org/bukkit/entity/Cow.java new file mode 100644 index 0000000..ccec6de --- /dev/null +++ b/src/main/java/org/bukkit/entity/Cow.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Cow. + * + * @author Cogito + * + */ +public interface Cow extends Animals {} diff --git a/src/main/java/org/bukkit/entity/Creature.java b/src/main/java/org/bukkit/entity/Creature.java new file mode 100644 index 0000000..3a3912d --- /dev/null +++ b/src/main/java/org/bukkit/entity/Creature.java @@ -0,0 +1,24 @@ +package org.bukkit.entity; + +/** + * Represents a Creature. Creatures are non-intelligent monsters or animals which + * have very simple abilities. + */ +public interface Creature extends LivingEntity { + + /** + * Instructs this Creature to set the specified LivingEntity as its target. + * Hostile creatures may attack their target, and friendly creatures may + * follow their target. + * + * @param target New LivingEntity to target, or null to clear the target + */ + public void setTarget(LivingEntity target); + + /** + * Gets the current target of this Creature + * + * @return Current target of this creature, or null if none exists + */ + public LivingEntity getTarget(); +} diff --git a/src/main/java/org/bukkit/entity/CreatureType.java b/src/main/java/org/bukkit/entity/CreatureType.java new file mode 100644 index 0000000..dfe351a --- /dev/null +++ b/src/main/java/org/bukkit/entity/CreatureType.java @@ -0,0 +1,45 @@ +package org.bukkit.entity; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +public enum CreatureType { + CHICKEN("Chicken"), + COW("Cow"), + CREEPER("Creeper"), + GHAST("Ghast"), + GIANT("Giant"), + MONSTER("Monster"), + PIG("Pig"), + PIG_ZOMBIE("PigZombie"), + SHEEP("Sheep"), + SKELETON("Skeleton"), + SLIME("Slime"), + SPIDER("Spider"), + SQUID("Squid"), + ZOMBIE("Zombie"), + WOLF("Wolf"); + + private String name; + + private static final Map mapping = new HashMap(); + + static { + for (CreatureType type : EnumSet.allOf(CreatureType.class)) { + mapping.put(type.name, type); + } + } + + private CreatureType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public static CreatureType fromName(String name) { + return mapping.get(name); + } +} diff --git a/src/main/java/org/bukkit/entity/Creeper.java b/src/main/java/org/bukkit/entity/Creeper.java new file mode 100644 index 0000000..a2f7809 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Creeper.java @@ -0,0 +1,21 @@ +package org.bukkit.entity; + +/** + * Represents a Creeper + */ +public interface Creeper extends Monster { + + /** + * Checks if this Creeper is powered (Electrocuted) + * + * @return true if this creeper is powered + */ + public boolean isPowered(); + + /** + * Sets the Powered status of this Creeper + * + * @param value New Powered status + */ + public void setPowered(boolean value); +} diff --git a/src/main/java/org/bukkit/entity/Egg.java b/src/main/java/org/bukkit/entity/Egg.java new file mode 100644 index 0000000..e60c802 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Egg.java @@ -0,0 +1,6 @@ +package org.bukkit.entity; + +/** + * Represents an egg. + */ +public interface Egg extends Projectile {} diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java new file mode 100644 index 0000000..6ae2a78 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Entity.java @@ -0,0 +1,175 @@ +package org.bukkit.entity; + +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.util.Vector; + +import java.util.List; +import java.util.UUID; + +/** + * Represents a base entity in the world + */ +public interface Entity { + + /** + * Gets the entity's current position + * + * @return Location containing the position of this entity + */ + public Location getLocation(); + + /** + * Sets this entity's velocity + * + * @param velocity New velocity to travel with + */ + public void setVelocity(Vector velocity); + + /** + * Gets this entity's current velocity + * + * @return Current travelling velocity of this entity + */ + public Vector getVelocity(); + + /** + * Gets the current world this entity resides in + * + * @return World + */ + public World getWorld(); + + /** + * Teleports this entity to the given location + * + * @param location New location to teleport this entity to + * @return true if the teleport was successful + */ + public boolean teleport(Location location); + + /** + * Teleports this entity to the target Entity + * + * @param destination Entity to teleport this entity to + * @return true if the teleport was successful + */ + public boolean teleport(Entity destination); + + /** + * Returns a list of entities within a bounding box defined by x,y,z centered around player + * + * @param x Size of the box along x axis + * @param y Size of the box along y axis + * @param z Size of the box along z axis + * @return List List of entities nearby + */ + public List getNearbyEntities(double x, double y, double z); + + /** + * Returns a unique id for this entity + * + * @return Entity id + */ + public int getEntityId(); + + /** + * Returns the entity's current fire ticks (ticks before the entity stops being on fire). + * + * @return int fireTicks + */ + public int getFireTicks(); + + /** + * Returns the entity's maximum fire ticks. + * + * @return int maxFireTicks + */ + public int getMaxFireTicks(); + + /** + * Sets the entity's current fire ticks (ticks before the entity stops being on fire). + * + * @param ticks + */ + public void setFireTicks(int ticks); + + /** + * Mark the entity's removal. + */ + public void remove(); + + /** + * Returns true if this entity has been marked for removal. + */ + public boolean isDead(); + + /** + * Gets the {@link Server} that contains this Entity + * + * @return Server instance running this Entity + */ + public Server getServer(); + + /** + * Gets the primary passenger of a vehicle. For vehicles that could have + * multiple passengers, this will only return the primary passenger. + * + * @return an entity + */ + public abstract Entity getPassenger(); + + /** + * Set the passenger of a vehicle. + * + * @param passenger + * @return false if it could not be done for whatever reason + */ + public abstract boolean setPassenger(Entity passenger); + + /** + * Returns true if the vehicle has no passengers. + * + * @return + */ + public abstract boolean isEmpty(); + + /** + * Eject any passenger. True if there was a passenger. + * + * @return + */ + public abstract boolean eject(); + + /** + * Returns the distance this entity has fallen + * @return + */ + public float getFallDistance(); + + /** + * Sets the fall distance for this entity + * @param distance + */ + public void setFallDistance(float distance); + + /** + * Record the last {@link EntityDamageEvent} inflicted on this entity + * @param event a {@link EntityDamageEvent} + */ + public void setLastDamageCause(EntityDamageEvent event); + + /** + * Retrieve the last {@link EntityDamageEvent} inflicted on this entity. This event may have been cancelled. + * @return the last known {@link EntityDamageEvent} or null if hitherto unharmed + */ + public EntityDamageEvent getLastDamageCause(); + + /** + * Returns a unique and persistent id for this entity + * @return unique id + */ + public UUID getUniqueId(); +} diff --git a/src/main/java/org/bukkit/entity/Explosive.java b/src/main/java/org/bukkit/entity/Explosive.java new file mode 100644 index 0000000..f140f31 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Explosive.java @@ -0,0 +1,30 @@ +package org.bukkit.entity; + +/** + * A representation of an explosive entity + */ +public interface Explosive extends Entity { + /** + * Set the radius affected by this explosive's explosion + * @param yield + */ + public void setYield(float yield); + + /** + * Return the radius or yield of this explosive's explosion + * @return the radius of blocks affected + */ + public float getYield(); + + /** + * Set whether or not this explosive's explosion causes fire + * @param isIncendiary + */ + public void setIsIncendiary(boolean isIncendiary); + + /** + * Return whether or not this explosive creates a fire when exploding + * @return true if the explosive creates fire, false otherwise + */ + public boolean isIncendiary(); +} diff --git a/src/main/java/org/bukkit/entity/FallingSand.java b/src/main/java/org/bukkit/entity/FallingSand.java new file mode 100644 index 0000000..3f7a7bb --- /dev/null +++ b/src/main/java/org/bukkit/entity/FallingSand.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents Falling Sand. + * + * @author Cogito + * + */ +public interface FallingSand extends Entity {} diff --git a/src/main/java/org/bukkit/entity/Fireball.java b/src/main/java/org/bukkit/entity/Fireball.java new file mode 100644 index 0000000..95c60f8 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Fireball.java @@ -0,0 +1,24 @@ +package org.bukkit.entity; + +import org.bukkit.util.Vector; + +/** + * Represents a Fireball. + */ +public interface Fireball extends Projectile, Explosive { + /** + * Fireballs fly straight and do not take setVelocity(...) well. + * + * @param direction + * the direction this fireball is flying toward + */ + public void setDirection(Vector direction); + + /** + * Retrieve the direction this fireball is heading toward + * + * @return the direction + */ + public Vector getDirection(); + +} diff --git a/src/main/java/org/bukkit/entity/Fish.java b/src/main/java/org/bukkit/entity/Fish.java new file mode 100644 index 0000000..5010805 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Fish.java @@ -0,0 +1,6 @@ +package org.bukkit.entity; + +/** + * Represents a Fish. + */ +public interface Fish extends Projectile {} diff --git a/src/main/java/org/bukkit/entity/Flying.java b/src/main/java/org/bukkit/entity/Flying.java new file mode 100644 index 0000000..e9684c9 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Flying.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Flying Entity. + * + * @author Cogito + * + */ +public interface Flying extends LivingEntity {} diff --git a/src/main/java/org/bukkit/entity/Ghast.java b/src/main/java/org/bukkit/entity/Ghast.java new file mode 100644 index 0000000..edd1eb8 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Ghast.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Ghast. + * + * @author Cogito + * + */ +public interface Ghast extends Flying {} diff --git a/src/main/java/org/bukkit/entity/Giant.java b/src/main/java/org/bukkit/entity/Giant.java new file mode 100644 index 0000000..4fece45 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Giant.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Giant. + * + * @author Cogito + * + */ +public interface Giant extends Monster {} diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java new file mode 100644 index 0000000..8c6efae --- /dev/null +++ b/src/main/java/org/bukkit/entity/HumanEntity.java @@ -0,0 +1,63 @@ +package org.bukkit.entity; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.permissions.Permissible; + +/** + * Represents a human entity, such as an NPC or a player + */ +public interface HumanEntity extends LivingEntity, AnimalTamer, Permissible { + + /** + * Returns the name of this player + * + * @return Player name + */ + public String getName(); + + /** + * Get the player's inventory. + * + * @return The inventory of the player, this also contains the armor slots. + */ + public PlayerInventory getInventory(); + + /** + * Returns the ItemStack currently in your hand, can be empty. + * + * @return The ItemStack of the item you are currently holding. + */ + public ItemStack getItemInHand(); + + /** + * Sets the item to the given ItemStack, this will replace whatever the + * user was holding. + * + * @param item The ItemStack which will end up in the hand + * @return + */ + public void setItemInHand(ItemStack item); + + /** + * Changes the item in hand to another of your 'action slots'. + * + * @param index The new index to use, only valid ones are 0-8. + * + public void selectItemInHand(int index); + */ + + /** + * Returns whether this player is slumbering. + * + * @return slumber state + */ + public boolean isSleeping(); + + /** + * Get the sleep ticks of the player. This value may be capped. + * + * @return slumber ticks + */ + public int getSleepTicks(); +} diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java new file mode 100644 index 0000000..619b92b --- /dev/null +++ b/src/main/java/org/bukkit/entity/Item.java @@ -0,0 +1,26 @@ +package org.bukkit.entity; + +import org.bukkit.inventory.ItemStack; + +/** + * Represents an Item. + * + * @author Cogito + * + */ +public interface Item extends Entity { + + /** + * Gets the item stack associated with this item drop. + * + * @return + */ + public ItemStack getItemStack(); + + /** + * Sets the item stack associated with this item drop. + * + * @param stack + */ + public void setItemStack(ItemStack stack); +} diff --git a/src/main/java/org/bukkit/entity/LightningStrike.java b/src/main/java/org/bukkit/entity/LightningStrike.java new file mode 100644 index 0000000..46eb09a --- /dev/null +++ b/src/main/java/org/bukkit/entity/LightningStrike.java @@ -0,0 +1,17 @@ +package org.bukkit.entity; + +/** + * Represents an instance of a lightning strike. May or may not do damage. + * + * @author sk89q + */ +public interface LightningStrike extends Weather { + + /** + * Returns whether the strike is an effect that does no damage. + * + * @return whether the strike is an effect + */ + public boolean isEffect(); + +} diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java new file mode 100644 index 0000000..7e555ea --- /dev/null +++ b/src/main/java/org/bukkit/entity/LivingEntity.java @@ -0,0 +1,208 @@ +package org.bukkit.entity; + +import org.bukkit.Location; +import org.bukkit.block.Block; + +import java.util.HashSet; +import java.util.List; + +/** + * Represents a living entity, such as a monster or player + */ +public interface LivingEntity extends Entity { + + /** + * Gets the entity's health from 0-20, where 0 is dead and 20 is full + * + * @return Health represented from 0-20 + */ + public int getHealth(); + + /** + * Sets the entity's health from 0-20, where 0 is dead and 20 is full + * + * @param health New health represented from 0-20 + */ + public void setHealth(int health); + + /** + * Gets the height of the entity's head above its Location + * + * @return Height of the entity's eyes above its Location + */ + public double getEyeHeight(); + + /** + * Gets the height of the entity's head above its Location + * + * @param boolean If set to true, the effects of sneaking will be ignored + * @return Height of the entity's eyes above its Location + */ + public double getEyeHeight(boolean ignoreSneaking); + + /** + * Get a Location detailing the current eye position of the LivingEntity. + * + * @return a Location at the eyes of the LivingEntity. + */ + public Location getEyeLocation(); + + /** + * Gets all blocks along the player's line of sight + * List iterates from player's position to target inclusive + * + * @param HashSet HashSet containing all transparent block IDs. If set to null only air is considered transparent. + * @param int This is the maximum distance to scan. This may be further limited by the server, but never to less than 100 blocks. + * @return List containing all blocks along the player's line of sight + */ + public List getLineOfSight(HashSet transparent, int maxDistance); + + /** + * Gets the block that the player has targeted + * + * @param HashSet HashSet containing all transparent block IDs. If set to null only air is considered transparent. + * @param int This is the maximum distance to scan. This may be further limited by the server, but never to less than 100 blocks. + * @return Block that the player has targeted + */ + public Block getTargetBlock(HashSet transparent, int maxDistance); + + /** + * Gets the last two blocks along the player's line of sight. + * The target block will be the last block in the list. + * + * @param HashSet HashSet containing all transparent block IDs. If set to null only air is considered transparent. + * @param int This is the maximum distance to scan. This may be further limited by the server, but never to less than 100 blocks + * @return List containing the last 2 blocks along the player's line of sight + */ + public List getLastTwoTargetBlocks(HashSet transparent, int maxDistance); + + /** + * Throws an egg from the entity. + */ + public Egg throwEgg(); + + /** + * Throws a snowball from the entity. + */ + public Snowball throwSnowball(); + + /** + * Shoots an arrow from the entity. + * + * @return + */ + public Arrow shootArrow(); + + /** + * Returns whether this entity is inside a vehicle. + * + * @return + */ + public boolean isInsideVehicle(); + + /** + * Leave the current vehicle. If the entity is currently in a vehicle + * (and is removed from it), true will be returned, otherwise false will + * be returned. + * + * @return + */ + public boolean leaveVehicle(); + + /** + * Get the vehicle that this player is inside. If there is no vehicle, + * null will be returned. + * + * @return + */ + public Vehicle getVehicle(); + + /** + * Returns the amount of air that this entity has remaining, in ticks + * + * @return Amount of air remaining + */ + public int getRemainingAir(); + + /** + * Sets the amount of air that this entity has remaining, in ticks + * + * @param ticks Amount of air remaining + */ + public void setRemainingAir(int ticks); + + /** + * Returns the maximum amount of air this entity can have, in ticks + * + * @return Maximum amount of air + */ + public int getMaximumAir(); + + /** + * Sets the maximum amount of air this entity can have, in ticks + * + * @param ticks Maximum amount of air + */ + public void setMaximumAir(int ticks); + + /** + * Deals the given amount of damage to this entity + * + * @param amount Amount of damage to deal + */ + public void damage(int amount); + + /** + * Deals the given amount of damage to this entity, from a specified entity + * + * @param amount Amount of damage to deal + * @param source Entity which to attribute this damage from + */ + public void damage(int amount, Entity source); + + /** + * Returns the entities current maximum noDamageTicks + * This is the time in ticks the entity will become unable to take + * equal or less damage than the lastDamage + * + * @return noDamageTicks + */ + public int getMaximumNoDamageTicks(); + + /** + * Sets the entities current maximum noDamageTicks + * + * @param ticks maximumNoDamageTicks + */ + public void setMaximumNoDamageTicks(int ticks); + + /** + * Returns the entities lastDamage taken in the current noDamageTicks time. + * Only damage higher than this amount will further damage the entity. + * + * @return lastDamage + */ + public int getLastDamage(); + + /** + * Sets the entities current maximum noDamageTicks + * + * @param damage last damage + */ + public void setLastDamage(int damage); + + /** + * Returns the entities current noDamageTicks + * + * @return noDamageTicks + */ + public int getNoDamageTicks(); + + /** + * Sets the entities current noDamageTicks + * + * @param ticks NoDamageTicks + */ + public void setNoDamageTicks(int ticks); + +} diff --git a/src/main/java/org/bukkit/entity/Minecart.java b/src/main/java/org/bukkit/entity/Minecart.java new file mode 100644 index 0000000..66b9fbf --- /dev/null +++ b/src/main/java/org/bukkit/entity/Minecart.java @@ -0,0 +1,84 @@ +package org.bukkit.entity; + +import org.bukkit.util.Vector; + +/** + * Represents a minecart entity. + * + * @author sk89q + */ +public interface Minecart extends Vehicle { + + /** + * Sets a minecart's damage. + * + * @param damage over 40 to "kill" a minecart + */ + public void setDamage(int damage); + + /** + * Gets a minecart's damage. + * + * @param damage + */ + public int getDamage(); + + /** + * Gets the maximum speed of a minecart. The speed is unrelated to the velocity. + * + * @param speed + */ + public double getMaxSpeed(); + + /** + * Sets the maximum speed of a minecart. Must be nonnegative. Default is 0.4D. + * + * @param speed + */ + public void setMaxSpeed(double speed); + + /** + * Returns whether this minecart will slow down faster without a passenger occupying it + * + */ + public boolean isSlowWhenEmpty(); + + /** + * Sets whether this minecart will slow down faster without a passenger occupying it + * + * @param slow + */ + public void setSlowWhenEmpty(boolean slow); + + /** + * Gets the flying velocity modifier. Used for minecarts that are in mid-air. + * A flying minecart's velocity is multiplied by this factor each tick. + * + * @param flying velocity modifier + */ + public Vector getFlyingVelocityMod(); + + /** + * Sets the flying velocity modifier. Used for minecarts that are in mid-air. + * A flying minecart's velocity is multiplied by this factor each tick. + * + * @param flying velocity modifier + */ + public void setFlyingVelocityMod(Vector flying); + + /** + * Gets the derailed velocity modifier. Used for minecarts that are on the ground, but not on rails. + * + * A derailed minecart's velocity is multiplied by this factor each tick. + * @param visible speed + */ + public Vector getDerailedVelocityMod(); + + /** + * Sets the derailed velocity modifier. Used for minecarts that are on the ground, but not on rails. + * A derailed minecart's velocity is multiplied by this factor each tick. + * + * @param visible speed + */ + public void setDerailedVelocityMod(Vector derailed); +} diff --git a/src/main/java/org/bukkit/entity/Monster.java b/src/main/java/org/bukkit/entity/Monster.java new file mode 100644 index 0000000..3acffba --- /dev/null +++ b/src/main/java/org/bukkit/entity/Monster.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Monster. + * + * @author Cogito + * + */ +public interface Monster extends Creature {} diff --git a/src/main/java/org/bukkit/entity/Painting.java b/src/main/java/org/bukkit/entity/Painting.java new file mode 100644 index 0000000..3b12c35 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Painting.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Painting. + * + * @author Cogito + * + */ +public interface Painting extends Entity {} diff --git a/src/main/java/org/bukkit/entity/Pig.java b/src/main/java/org/bukkit/entity/Pig.java new file mode 100644 index 0000000..fe1b0f4 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Pig.java @@ -0,0 +1,21 @@ +package org.bukkit.entity; + +/** + * Represents a Pig. + */ +public interface Pig extends Animals, Vehicle { + + /** + * Check if the pig has a saddle. + * + * @return if the pig has been saddled. + */ + public boolean hasSaddle(); + + /** + * Sets if the pig has a saddle or not + * + * @param saddled set if the pig has a saddle or not. + */ + public void setSaddle(boolean saddled); +} diff --git a/src/main/java/org/bukkit/entity/PigZombie.java b/src/main/java/org/bukkit/entity/PigZombie.java new file mode 100644 index 0000000..f8b1fb7 --- /dev/null +++ b/src/main/java/org/bukkit/entity/PigZombie.java @@ -0,0 +1,34 @@ +package org.bukkit.entity; + +/** + * Represents a Pig Zombie. + */ +public interface PigZombie extends Zombie { + /** + * Get the pig zombie's current anger level. + * + * @return The anger level. + */ + int getAnger(); + + /** + * Set the pig zombie's current anger level. + * + * @param level The anger level. Higher levels of anger take longer to wear off. + */ + void setAnger(int level); + + /** + * Shorthand; sets to either 0 or the default level. + * + * @param angry Whether the zombie should be angry. + */ + void setAngry(boolean angry); + + /** + * Shorthand; gets whether the zombie is angry. + * + * @return True if the zombie is angry, otherwise false. + */ + boolean isAngry(); +} diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java new file mode 100644 index 0000000..1e4ac85 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Player.java @@ -0,0 +1,353 @@ +package org.bukkit.entity; + +import com.projectposeidon.ConnectionType; +import net.minecraft.server.Packet; +import org.bukkit.*; +import org.bukkit.command.CommandSender; +import org.bukkit.map.MapView; + +import java.net.InetSocketAddress; +import java.util.UUID; + +/** + * Represents a player, connected or not + */ +public interface Player extends HumanEntity, CommandSender, OfflinePlayer { + /** + * Gets the "friendly" name to display of this player. This may include color. + *

+ * Note that this name will not be displayed in game, only in chat and places + * defined by plugins + * + * @return the friendly name + */ + public String getDisplayName(); + + /** + * Sets the "friendly" name to display of this player. This may include color. + *

+ * Note that this name will not be displayed in game, only in chat and places + * defined by plugins + * + * @param name + */ + public void setDisplayName(String name); + + /** + * Set the target of the player's compass. + * + * @param loc + */ + public void setCompassTarget(Location loc); + //Project Poseidon Start + + /** + * Get the players Mojang UUID. + * + * @return Player UUID + */ + public UUID getUniqueId(); + + + /** + * Get the players Mojang UUID. + * + * @return Player UUID + */ + @Deprecated + public UUID getPlayerUUID(); + //Project Poseidon End + + /** + * Get the previously set compass target. + * + * @return location of the target + */ + public Location getCompassTarget(); + + /** + * Gets the socket address of this player + * + * @return the player's address + */ + public InetSocketAddress getAddress(); + + /** + * Sends this sender a message raw + * + * @param message Message to be displayed + */ + public void sendRawMessage(String message); + + /** + * Kicks player with custom kick message. + * + * @param message kick message + */ + public void kickPlayer(String message); + + /** + * Says a message (or runs a command). + * + * @param msg message to print + */ + public void chat(String msg); + + /** + * Makes the player perform the given command + * + * @param command Command to perform + * @return true if the command was successful, otherwise false + */ + public boolean performCommand(String command); + + /** + * Returns if the player is in sneak mode + * + * @return true if player is in sneak mode + */ + public boolean isSneaking(); + + /** + * Sets the sneak mode the player + * + * @param sneak true if player should appear sneaking + */ + public void setSneaking(boolean sneak); + + /** + * Saves the players current location, health, inventory, motion, and other information into the username.dat file, in the world/player folder + */ + public void saveData(); + + /** + * Loads the players current location, health, inventory, motion, and other information from the username.dat file, in the world/player folder + *

+ * Note: This will overwrite the players current inventory, health, motion, etc, with the state from the saved dat file. + */ + public void loadData(); + + /** + * Sets whether the player is ignored as not sleeping. If everyone is + * either sleeping or has this flag set, then time will advance to the + * next day. If everyone has this flag set but no one is actually in bed, + * then nothing will happen. + * + * @param isSleeping + */ + public void setSleepingIgnored(boolean isSleeping); + + /** + * Returns whether the player is sleeping ignored. + * + * @return + */ + public boolean isSleepingIgnored(); + + /** + * Play a note for a player at a location. This requires a note block + * at the particular location (as far as the client is concerned). This + * will not work without a note block. This will not work with cake. + * + * @param loc + * @param instrument + * @param note + */ + public void playNote(Location loc, byte instrument, byte note); + + /** + * Play a note for a player at a location. This requires a note block + * at the particular location (as far as the client is concerned). This + * will not work without a note block. This will not work with cake. + * + * @param loc + * @param instrument + * @param note + */ + public void playNote(Location loc, Instrument instrument, Note note); + + /** + * Plays an effect to just this player. + * + * @param loc the player to play the effect for + * @param effect the {@link Effect} + * @param data a data bit needed for the RECORD_PLAY, SMOKE, and STEP_SOUND sounds + */ + public void playEffect(Location loc, Effect effect, int data); + + /** + * Send a block change. This fakes a block change packet for a user at + * a certain location. This will not actually change the world in any way. + * + * @param loc + * @param material + * @param data + */ + public void sendBlockChange(Location loc, Material material, byte data); + + /** + * Send a chunk change. This fakes a chunk change packet for a user at + * a certain location. The updated cuboid must be entirely within a single + * chunk. This will not actually change the world in any way. + *

+ * At least one of the dimensions of the cuboid must be even. The size of the + * data buffer must be 2.5*sx*sy*sz and formatted in accordance with the Packet51 + * format. + * + * @param loc The location of the cuboid + * @param sx The x size of the cuboid + * @param sy The y size of the cuboid + * @param sz The z size of the cuboid + * @param data The data to be sent + * @return true if the chunk change packet was sent + */ + public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data); + + /** + * Send a block change. This fakes a block change packet for a user at + * a certain location. This will not actually change the world in any way. + * + * @param loc + * @param material + * @param data + */ + public void sendBlockChange(Location loc, int material, byte data); + + /** + * Render a map and send it to the player in its entirety. This may be used + * when streaming the map in the normal manner is not desirbale. + * + * @pram map The map to be sent + */ + public void sendMap(MapView map); + + /** + * Forces an update of the player's entire inventory. + * + * @deprecated This method should not be relied upon as it is a temporary work-around for a larger, more complicated issue. + */ + @Deprecated + public void updateInventory(); + + /** + * Awards this player the given achievement + * + * @param achievement Achievement to award + */ + public void awardAchievement(Achievement achievement); + + /** + * Increments the given statistic for this player + * + * @param statistic Statistic to increment + */ + public void incrementStatistic(Statistic statistic); + + /** + * Increments the given statistic for this player + * + * @param statistic Statistic to increment + * @param amount Amount to increment this statistic by + */ + public void incrementStatistic(Statistic statistic, int amount); + + /** + * Increments the given statistic for this player for the given material + * + * @param statistic Statistic to increment + * @param material Material to offset the statistic with + */ + public void incrementStatistic(Statistic statistic, Material material); + + /** + * Increments the given statistic for this player for the given material + * + * @param statistic Statistic to increment + * @param material Material to offset the statistic with + * @param amount Amount to increment this statistic by + */ + public void incrementStatistic(Statistic statistic, Material material, int amount); + + /** + * Sets the current time on the player's client. When relative is true the player's time + * will be kept synchronized to its world time with the specified offset. + *

+ * When using non relative time the player's time will stay fixed at the specified time parameter. It's up to + * the caller to continue updating the player's time. To restore player time to normal use resetPlayerTime(). + * + * @param time The current player's perceived time or the player's time offset from the server time. + * @param relative When true the player time is kept relative to its world time. + */ + public void setPlayerTime(long time, boolean relative); + + /** + * Returns the player's current timestamp. + * + * @return + */ + public long getPlayerTime(); + + /** + * Returns the player's current time offset relative to server time, or the current player's fixed time + * if the player's time is absolute. + * + * @return + */ + public long getPlayerTimeOffset(); + + /** + * Returns true if the player's time is relative to the server time, otherwise the player's time is absolute and + * will not change its current time unless done so with setPlayerTime(). + * + * @return true if the player's time is relative to the server time. + */ + public boolean isPlayerTimeRelative(); + + /** + * Returns connection type which allows for a plugin to know if a user is using a proxy, and if IP Forwarding is enabled. + * + * @return ConntionType enum + */ + public ConnectionType getConnectionType(); + + public boolean hasReceivedPacket0(); + + /** + * Returns whether the player is using a Release2Beta proxy + * + * @return true if the player is using a Release2Beta proxy + */ + @Deprecated + public boolean isUsingReleaseToBeta(); + + /** + * Restores the normal condition where the player's time is synchronized with the server time. + * Equivalent to calling setPlayerTime(0, true). + */ + public void resetPlayerTime(); + + /** + * Hides a player from this player + * + * @param player Player to hide + */ + public void hidePlayer(Player player); + + /** + * Allows this player to see a player that was previously hidden + * + * @param player Player to show + */ + public void showPlayer(Player player); + + /** + * Checks to see if a player has been hidden from this player + * + * @param player Player to check + * @return True if the provided player is not being hidden from this player + */ + public boolean canSee(Player player); + + public void sendPacket(final Player player, final Packet packet); + +} diff --git a/src/main/java/org/bukkit/entity/PoweredMinecart.java b/src/main/java/org/bukkit/entity/PoweredMinecart.java new file mode 100644 index 0000000..deb21d4 --- /dev/null +++ b/src/main/java/org/bukkit/entity/PoweredMinecart.java @@ -0,0 +1,8 @@ +package org.bukkit.entity; + +/** + * Represents a powered minecart. + * + * @author sk89q + */ +public interface PoweredMinecart extends Minecart {} diff --git a/src/main/java/org/bukkit/entity/Projectile.java b/src/main/java/org/bukkit/entity/Projectile.java new file mode 100644 index 0000000..1595062 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Projectile.java @@ -0,0 +1,36 @@ +package org.bukkit.entity; + +/** + * Represents a shootable entity + */ +public interface Projectile extends Entity { + + /** + * Retrieve the shooter of this projectile. The returned value can be null + * for projectiles shot from a {@link Dispenser} for example. + * + * @return the {@link LivingEntity} that shot this projectile + */ + public LivingEntity getShooter(); + + /** + * Set the shooter of this projectile + * + * @param shooter the {@link LivingEntity} that shot this projectile + */ + public void setShooter(LivingEntity shooter); + + /** + * Determine if this projectile should bounce or not when it hits. + * + * @return true if it should bounce. + */ + public boolean doesBounce(); + + /** + * Set whether or not this projectile should bounce or not when it hits something. + * + * @param doesBounce whether or not it should bounce. + */ + public void setBounce(boolean doesBounce); +} diff --git a/src/main/java/org/bukkit/entity/Sheep.java b/src/main/java/org/bukkit/entity/Sheep.java new file mode 100644 index 0000000..2cdb7fc --- /dev/null +++ b/src/main/java/org/bukkit/entity/Sheep.java @@ -0,0 +1,27 @@ +/** + * + */ +package org.bukkit.entity; + +import org.bukkit.material.Colorable; + +/** + * Represents a Sheep. + * + * @author Cogito + * + */ +public interface Sheep extends Animals, Colorable { + + /** + * @author Celtic Minstrel + * @return Whether the sheep is sheared. + */ + public boolean isSheared(); + + /** + * @author Celtic Minstrel + * @param flag Whether to shear the sheep + */ + public void setSheared(boolean flag); +} diff --git a/src/main/java/org/bukkit/entity/Skeleton.java b/src/main/java/org/bukkit/entity/Skeleton.java new file mode 100644 index 0000000..fd14bde --- /dev/null +++ b/src/main/java/org/bukkit/entity/Skeleton.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Skeleton. + * + * @author Cogito + * + */ +public interface Skeleton extends Monster {} diff --git a/src/main/java/org/bukkit/entity/Slime.java b/src/main/java/org/bukkit/entity/Slime.java new file mode 100644 index 0000000..52fa8da --- /dev/null +++ b/src/main/java/org/bukkit/entity/Slime.java @@ -0,0 +1,25 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Slime. + * + * @author Cogito + * + */ +public interface Slime extends LivingEntity { + + /** + * @author Celtic Minstrel + * @return The size of the slime + */ + public int getSize(); + + /** + * @author Celtic Minstrel + * @param sz The new size of the slime. + */ + public void setSize(int sz); +} diff --git a/src/main/java/org/bukkit/entity/Snowball.java b/src/main/java/org/bukkit/entity/Snowball.java new file mode 100644 index 0000000..47a86c4 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Snowball.java @@ -0,0 +1,6 @@ +package org.bukkit.entity; + +/** + * Implements a snowball. + */ +public interface Snowball extends Projectile {} diff --git a/src/main/java/org/bukkit/entity/Spider.java b/src/main/java/org/bukkit/entity/Spider.java new file mode 100644 index 0000000..aa36d07 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Spider.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Spider. + * + * @author Cogito + * + */ +public interface Spider extends Monster {} diff --git a/src/main/java/org/bukkit/entity/Squid.java b/src/main/java/org/bukkit/entity/Squid.java new file mode 100644 index 0000000..bb4764b --- /dev/null +++ b/src/main/java/org/bukkit/entity/Squid.java @@ -0,0 +1,12 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Squid. + * + * @author Cogito + * + */ +public interface Squid extends WaterMob {} diff --git a/src/main/java/org/bukkit/entity/StorageMinecart.java b/src/main/java/org/bukkit/entity/StorageMinecart.java new file mode 100644 index 0000000..ee973c5 --- /dev/null +++ b/src/main/java/org/bukkit/entity/StorageMinecart.java @@ -0,0 +1,18 @@ +package org.bukkit.entity; + +import org.bukkit.inventory.Inventory; + +/** + * Represents a storage minecart. + * + * @author sk89q + */ +public interface StorageMinecart extends Minecart { + + /** + * Return the inventory object for this StorageMinecart. + * + * @return The inventory for this Minecart + */ + public Inventory getInventory(); +} diff --git a/src/main/java/org/bukkit/entity/TNTPrimed.java b/src/main/java/org/bukkit/entity/TNTPrimed.java new file mode 100644 index 0000000..e1a7bae --- /dev/null +++ b/src/main/java/org/bukkit/entity/TNTPrimed.java @@ -0,0 +1,18 @@ +package org.bukkit.entity; + +/** + * Represents a Primed TNT. + */ +public interface TNTPrimed extends Explosive { + /** + * Set the number of ticks until the TNT blows up after being primed. + * @param fuseTicks + */ + public void setFuseTicks(int fuseTicks); + + /** + * Retrieve the number of ticks until the explosion of this TNTPrimed entity + * @return the number of ticks until this TNTPrimed explodes + */ + public int getFuseTicks(); +} diff --git a/src/main/java/org/bukkit/entity/Tameable.java b/src/main/java/org/bukkit/entity/Tameable.java new file mode 100644 index 0000000..a9dd866 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Tameable.java @@ -0,0 +1,39 @@ +package org.bukkit.entity; + +public interface Tameable { + + /** + * Check if this is tamed + * + * If something is tamed then a player can not tame it through normal methods, even if it does not belong to anyone in particular. + * + * @return true if this has been tamed + */ + public boolean isTamed(); + + /** + * Sets if this has been tamed. Not necessary if the method setOwner has been used, as it tames automatically. + * + * If something is tamed then a player can not tame it through normal methods, even if it does not belong to anyone in particular. + * + * @param tame true if tame + */ + public void setTamed(boolean tame); + + /** + * Gets the current owning AnimalTamer + * + * @return the owning AnimalTamer, or null if not owned + */ + public AnimalTamer getOwner(); + + /** + * Set this to be owned by given AnimalTamer. + * If the owner is not null, this will be tamed and will have any current path it is following removed. + * If the owner is set to null, this will be untamed, and the current owner removed. + * + * @param tamer the AnimalTamer who should own this + */ + public void setOwner(AnimalTamer tamer); + +} diff --git a/src/main/java/org/bukkit/entity/Vehicle.java b/src/main/java/org/bukkit/entity/Vehicle.java new file mode 100644 index 0000000..750b244 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Vehicle.java @@ -0,0 +1,25 @@ +package org.bukkit.entity; + +import org.bukkit.util.Vector; + +/** + * Represents a vehicle entity. + * + * @author sk89q + */ +public interface Vehicle extends Entity { + + /** + * Gets the vehicle's velocity. + * + * @return velocity vector + */ + public Vector getVelocity(); + + /** + * Sets the vehicle's velocity. + * + * @param vel velocity vector + */ + public void setVelocity(Vector vel); +} diff --git a/src/main/java/org/bukkit/entity/WaterMob.java b/src/main/java/org/bukkit/entity/WaterMob.java new file mode 100644 index 0000000..19a6d86 --- /dev/null +++ b/src/main/java/org/bukkit/entity/WaterMob.java @@ -0,0 +1,11 @@ +/** + * + */ +package org.bukkit.entity; + +/** + * Represents a Water Mob + * @author Cogito + * + */ +public interface WaterMob extends Creature {} diff --git a/src/main/java/org/bukkit/entity/Weather.java b/src/main/java/org/bukkit/entity/Weather.java new file mode 100644 index 0000000..6d77851 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Weather.java @@ -0,0 +1,6 @@ +package org.bukkit.entity; + +/** + * Represents a Weather related entity, such as a storm + */ +public interface Weather extends Entity {} diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java new file mode 100644 index 0000000..455a2e2 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Wolf.java @@ -0,0 +1,38 @@ +package org.bukkit.entity; + +/** + * Represents a Wolf + */ +public interface Wolf extends Animals, Tameable { + + /** + * Checks if this wolf is angry + * + * @return Anger true if angry + */ + public boolean isAngry(); + + /** + * Sets the anger of this wolf + * An angry wolf can not be fed or tamed, and will actively look for targets to attack. + * + * @param angry true if angry + */ + public void setAngry(boolean angry); + + /** + * Checks if this wolf is sitting + * + * @return true if sitting + */ + public boolean isSitting(); + + /** + * Sets if this wolf is sitting + * Will remove any path that the wolf was following beforehand. + * + * @param sitting true if sitting + */ + public void setSitting(boolean sitting); + +} diff --git a/src/main/java/org/bukkit/entity/Zombie.java b/src/main/java/org/bukkit/entity/Zombie.java new file mode 100644 index 0000000..122b4a6 --- /dev/null +++ b/src/main/java/org/bukkit/entity/Zombie.java @@ -0,0 +1,9 @@ +package org.bukkit.entity; + +/** + * Represents a Zombie. + * + * @author Cogito + * + */ +public interface Zombie extends Monster {} diff --git a/src/main/java/org/bukkit/event/Cancellable.java b/src/main/java/org/bukkit/event/Cancellable.java new file mode 100644 index 0000000..3fc13fc --- /dev/null +++ b/src/main/java/org/bukkit/event/Cancellable.java @@ -0,0 +1,19 @@ +package org.bukkit.event; + +public interface Cancellable { + /** + * Gets the cancellation state of this event. A cancelled event will not + * be executed in the server, but will still pass to other plugins + * + * @return true if this event is cancelled + */ + public boolean isCancelled(); + + /** + * Sets the cancellation state of this event. A cancelled event will not + * be executed in the server, but will still pass to other plugins. + * + * @param cancel true if you wish to cancel this event + */ + public void setCancelled(boolean cancel); +} diff --git a/src/main/java/org/bukkit/event/CustomEventListener.java b/src/main/java/org/bukkit/event/CustomEventListener.java new file mode 100644 index 0000000..2adfba5 --- /dev/null +++ b/src/main/java/org/bukkit/event/CustomEventListener.java @@ -0,0 +1,15 @@ +package org.bukkit.event; + +/** + * Handles all custom events + */ +public class CustomEventListener implements Listener { + public CustomEventListener() {} + + /** + * Called when a custom event is fired + * + * @param event Relevant event details + */ + public void onCustomEvent(Event event) {} +} diff --git a/src/main/java/org/bukkit/event/Event.java b/src/main/java/org/bukkit/event/Event.java new file mode 100644 index 0000000..3d73d80 --- /dev/null +++ b/src/main/java/org/bukkit/event/Event.java @@ -0,0 +1,870 @@ +package org.bukkit.event; + +import org.bukkit.entity.Projectile; + +import java.io.Serializable; + +/** + * Represents an event + */ +public abstract class Event implements Serializable { + private final Type type; + private final String name; + + protected Event(final Type type) { + exAssert(type != null, "type is null"); + exAssert(type != Type.CUSTOM_EVENT, "use Event(String) to make custom events"); + this.type = type; + this.name = null; + } + + protected Event(final String name) { + exAssert(name != null, "name is null"); + this.type = Type.CUSTOM_EVENT; + this.name = name; + } + + /** + * Gets the Type of this event + * + * @return Event type that this object represents + */ + public final Type getType() { + return type; + } + + private void exAssert(boolean b, String s) { + if (!b) { + throw new IllegalArgumentException(s); + } + } + + /** + * Gets the event's name. Should only be used if getType() == Type.CUSTOM + * + * @return Name of this event + */ + public final String getEventName() { + return (type != Type.CUSTOM_EVENT) ? type.toString() : name; + } + + /** + * Represents an events priority in execution + */ + public enum Priority { + + /** + * Event call is of very low importance and should be ran first, to allow + * other plugins to further customise the outcome + */ + Lowest, + /** + * Event call is of low importance + */ + Low, + /** + * Event call is neither important or unimportant, and may be ran normally + */ + Normal, + /** + * Event call is of high importance + */ + High, + /** + * Event call is critical and must have the final say in what happens + * to the event + */ + Highest, + /** + * Event is listened to purely for monitoring the outcome of an event. + *

+ * No modifications to the event should be made under this priority + */ + Monitor + } + + /** + * Represents a category used by Type + */ + public enum Category { + + /** + * POSEIDON CATEGORIES + */ + PACKET, + + /** + * Represents Player-based events + * + * @see Category.LIVING_ENTITY + */ + PLAYER, + /** + * Represents Entity-based events + */ + ENTITY, + /** + * Represents Block-based events + */ + BLOCK, + /** + * Represents LivingEntity-based events + */ + LIVING_ENTITY, + /** + * Represents Weather-based events + */ + WEATHER, + /** + * Represents Vehicle-based events + */ + VEHICLE, + /** + * Represents World-based events + */ + WORLD, + /** + * Represents Server and Plugin based events + */ + SERVER, + /** + * Represents Inventory-based events + */ + INVENTORY, + /** + * Represents any miscellaneous events + */ + MISCELLANEOUS; + } + + /** + * Provides a lookup for all core events + * + * @see org.bukkit.event + */ + public enum Type { + + /** + * POSEIDON EVENTS + */ + + PLAYER_RECEIVE_PACKET(Category.PACKET), + + PLAYER_SEND_PACKET(Category.PACKET), + + PACKET_RECEIVED(Category.PACKET), + + CHEST_OPENED(Category.BLOCK), + + /** + * Called when a player first starts their connection. Called before UUID is known. + * + * @see org.bukkit.event.player.PlayerConnectionInitializationEvent + */ + Player_Connection_Initialization(Category.PLAYER), + + + /** + * PLAYER EVENTS + */ + + /** + * Called when a player enters the world on a server + * + * @see org.bukkit.event.player.PlayerJoinEvent + */ + PLAYER_JOIN(Category.PLAYER), + /** + * Called when a player is attempting to connect to the server + * + * @see org.bukkit.event.player.PlayerLoginEvent + */ + PLAYER_LOGIN(Category.PLAYER), + /** + * Called when a player has just been authenticated + * + * @see org.bukkit.event.player.PlayerPreLoginEvent + */ + PLAYER_PRELOGIN(Category.PLAYER), + /** + * Called when a player respawns + * + * @see org.bukkit.event.player.PlayerRespawnEvent + */ + PLAYER_RESPAWN(Category.PLAYER), + /** + * Called when a player gets kicked from the server + * + * @see org.bukkit.event.player.PlayerKickEvent + */ + PLAYER_KICK(Category.PLAYER), + /** + * Called when a player sends a chat message + * + * @see org.bukkit.event.player.PlayerChatEvent + */ + PLAYER_CHAT(Category.PLAYER), + /** + * Called when a player uses a command (early in the command handling process) + * + * @see org.bukkit.event.player.PlayerCommandPreprocessEvent + */ + PLAYER_COMMAND_PREPROCESS(Category.PLAYER), + /** + * Called when a player leaves the server + * + * @see org.bukkit.event.player.PlayerQuitEvent + */ + PLAYER_QUIT(Category.PLAYER), + /** + * Called when a player moves position in the world + * + * @see org.bukkit.event.player.PlayerMoveEvent + */ + PLAYER_MOVE(Category.PLAYER), + /** + * Called before a player gets a velocity vector sent, which will instruct him to + * get "pushed" into a specific direction, e.g. after an explosion + * + * @see org.bukkit.event.player.PlayerVelocityEvent + */ + PLAYER_VELOCITY(Category.PLAYER), + /** + * Called when a player undergoes an animation (Arm Swing is the only animation currently supported) + * + * @see org.bukkit.event.player.PlayerAnimationEvent + */ + PLAYER_ANIMATION(Category.PLAYER), + /** + * Called when a player toggles sneak mode + * + * @see org.bukkit.event.player.PlayerToggleSneakEvent + */ + PLAYER_TOGGLE_SNEAK(Category.PLAYER), + /** + * Called when a player interacts with an object or air + * + * @see org.bukkit.event.player.PlayerInteractEvent + */ + PLAYER_INTERACT(Category.PLAYER), + /** + * Called when a player right clicks an entity + * + * @see org.bukkit.event.player.PlayerInteractEntityEvent + */ + PLAYER_INTERACT_ENTITY(Category.PLAYER), + /** + * Called when a player throws an egg + * + * @see org.bukkit.event.player.PlayerEggThrowEvent + */ + PLAYER_EGG_THROW(Category.PLAYER), + /** + * Called when a player teleports from one position to another + * + * @see org.bukkit.event.player.PlayerTeleportEvent + */ + PLAYER_TELEPORT(Category.PLAYER), + /** + * Called when a player completes the portaling process by standing in a portal + * + * @see org.bukkit.event.player.PlayerPortalEvent + */ + PLAYER_PORTAL(Category.PLAYER), + /** + * Called when a player changes their held item + * + * @see org.bukkit.event.player.PlayerItemHeldEvent + */ + PLAYER_ITEM_HELD(Category.PLAYER), + /** + * Called when a player drops an item + * + * @see org.bukkit.event.player.PlayerDropItemEvent + */ + PLAYER_DROP_ITEM(Category.PLAYER), + /** + * Called when a player picks an item up off the ground + * + * @see org.bukkit.event.player.PlayerPickupItemEvent + */ + PLAYER_PICKUP_ITEM(Category.PLAYER), + /** + * Called after a player has changed to a new world + * + * @see org.bukkit.event.player.PlayerChangedWorldEvent + */ + PLAYER_CHANGED_WORLD(Category.PLAYER), + /** + * Called when a player empties a bucket + * + * @see org.bukkit.event.player.PlayerBucketEmptyEvent + */ + PLAYER_BUCKET_EMPTY(Category.PLAYER), + /** + * Called when a player fills a bucket + * + * @see org.bukkit.event.player.PlayerBucketFillEvent + */ + PLAYER_BUCKET_FILL(Category.PLAYER), + /** + * Called when a player interacts with the inventory + * + * @see org.bukkit.event.player.PlayerInventoryEvent + */ + PLAYER_INVENTORY(Category.PLAYER), + /** + * Called when a player enter a bed + * + * @see org.bukkit.event.player.PlayerBedEnterEvent + */ + PLAYER_BED_ENTER(Category.PLAYER), + /** + * Called when a player leaves a bed + * + * @see org.bukkit.event.player.PlayerBedLeaveEvent + */ + PLAYER_BED_LEAVE(Category.PLAYER), + /** + * Called when a player is fishing + * + * @see org.bukkit.event.player.PlayerFishEvent + */ + PLAYER_FISH(Category.PLAYER), + /** + * Called when a player used item is damaged + * + * @see org.bukkit.event.player.PlayerItemDamageEvent + */ + PLAYER_ITEM_DAMAGE(Category.PLAYER), + + /** + * BLOCK EVENTS + */ + + /** + * Called when a block is damaged (hit by a player) + * + * @see org.bukkit.event.block.BlockDamageEvent + */ + BLOCK_DAMAGE(Category.BLOCK), + /** + * Called when a block is undergoing a universe physics + * check on whether it can be built + *

+ * For example, cacti cannot be built on grass unless overridden here + * + * @see org.bukkit.event.block.BlockCanBuildEvent + */ + BLOCK_CANBUILD(Category.BLOCK), + /** + * Called when a block of water or lava attempts to flow into another + * block + * + * @see org.bukkit.event.block.BlockFromToEvent + */ + BLOCK_FROMTO(Category.BLOCK), + /** + * Called when a block is being set on fire from another block, such as + * an adjacent block of fire attempting to set fire to wood + * + * @see org.bukkit.event.block.BlockIgniteEvent + */ + BLOCK_IGNITE(Category.BLOCK), + /** + * Called when a block undergoes a physics check + *

+ * A physics check is commonly called when an adjacent block changes + * type + * + * @see org.bukkit.event.block.BlockPhysicsEvent + */ + BLOCK_PHYSICS(Category.BLOCK), + /** + * Called when a player is attempting to place a block + * + * @see org.bukkit.event.block.BlockPlaceEvent + */ + BLOCK_PLACE(Category.BLOCK), + /** + * Called when a block dispenses something + * + * @see org.bukkit.event.block.BlockDispenseEvent + */ + BLOCK_DISPENSE(Category.BLOCK), + /** + * Called when a block is destroyed from being burnt by fire + * + * @see org.bukkit.event.block.BlockBurnEvent + */ + BLOCK_BURN(Category.BLOCK), + /** + * Called when leaves are decaying naturally + * + * @see org.bukkit.event.block.LeavesDecayEvent + */ + LEAVES_DECAY(Category.BLOCK), + /** + * Called when a sign is changed + * + * @see org.bukkit.event.block.SignChangeEvent + */ + SIGN_CHANGE(Category.BLOCK), + /** + * Called when a block changes redstone current. Only triggered on blocks + * that are actually capable of transmitting or carrying a redstone + * current + * + * @see org.bukkit.event.block.BlockRedstoneEvent + */ + REDSTONE_CHANGE(Category.BLOCK), + /** + * Called when a block is broken by a player + * + * @see org.bukkit.event.block.BlockBreakEvent + */ + BLOCK_BREAK(Category.BLOCK), + /** + * Called when a block is formed based on world conditions + * + * @see org.bukkit.event.block.BlockFormEvent + */ + BLOCK_FORM(Category.BLOCK), + /** + * Called when a block spreads based on world conditions + * + * @see org.bukkit.event.block.BlockSpreadEvent + */ + BLOCK_SPREAD(Category.BLOCK), + /** + * Called when a block fades, melts or disappears based on world conditions + * + * @see org.bukkit.event.block.BlockFadeEvent + */ + BLOCK_FADE(Category.BLOCK), + /** + * Called when a piston extends + * + * @see org.bukkit.event.block.PistonExtendEvent + */ + BLOCK_PISTON_EXTEND(Category.BLOCK), + /** + * Called when a piston retracts + * + * @see org.bukkit.event.block.PistonRetractEvent + */ + BLOCK_PISTON_RETRACT(Category.BLOCK), + + /** + * INVENTORY EVENTS + */ + + /** + * Called when a player opens an inventory + * + * @todo: add javadoc see comment + */ + INVENTORY_OPEN(Category.INVENTORY), + /** + * Called when a player closes an inventory + * + * @todo: add javadoc see comment + */ + INVENTORY_CLOSE(Category.INVENTORY), + /** + * Called when a player clicks on an inventory slot + * + * @todo: add javadoc see comment + */ + INVENTORY_CLICK(Category.INVENTORY), + /** + * Called when an inventory slot changes values or type + * + * @todo: add javadoc see comment + */ + INVENTORY_CHANGE(Category.INVENTORY), + /** + * Called when a player is attempting to perform an inventory transaction + * + * @todo: add javadoc see comment + */ + INVENTORY_TRANSACTION(Category.INVENTORY), + /** + * Called when an ItemStack is successfully smelted in a furnace. + * + * @see org.bukkit.event.inventory.FurnaceSmeltEvent + */ + FURNACE_SMELT(Category.INVENTORY), + /** + * Called when an ItemStack is successfully burned as fuel in a furnace. + * + * @see org.bukkit.event.inventory.FurnaceBurnEvent + */ + FURNACE_BURN(Category.INVENTORY), + + /** + * SERVER EVENTS + */ + + /** + * Called when a plugin is enabled + * + * @see org.bukkit.event.server.PluginEnableEvent + */ + PLUGIN_ENABLE(Category.SERVER), + /** + * Called when a plugin is disabled + * + * @see org.bukkit.event.server.PluginDisableEvent + */ + PLUGIN_DISABLE(Category.SERVER), + /** + * Called when a server command is called + * + * @see org.bukkit.event.server.ServerCommandEvent + */ + SERVER_COMMAND(Category.SERVER), + /** + * Called when a map is initialized (created or loaded into memory) + * + * @see org.bukkit.event.server.MapInitializeEvent + */ + MAP_INITIALIZE(Category.SERVER), + + /** + * WORLD EVENTS + */ + + /** + * Called when a chunk is loaded + *

+ * If a new chunk is being generated for loading, it will call + * Type.CHUNK_GENERATION and then Type.CHUNK_LOADED upon completion + * + * @see org.bukkit.event.world.ChunkLoadEvent + */ + CHUNK_LOAD(Category.WORLD), + /** + * Called when a chunk is unloaded + * + * @see org.bukkit.event.world.ChunkUnloadEvent + */ + CHUNK_UNLOAD(Category.WORLD), + /** + * Called when a newly created chunk has been populated. + *

+ * If your intent is to populate the chunk using this event, please see {@link BlockPopulator} + * + * @see org.bukkit.event.world.ChunkPopulateEvent + */ + CHUNK_POPULATED(Category.WORLD), + /** + * Called when an ItemEntity spawns in the world + * + * @see org.bukkit.event.entity.ItemSpawnEvent + */ + ITEM_SPAWN(Category.WORLD), + /** + * Called when a World's spawn is changed + * + * @see org.bukkit.event.world.SpawnChangeEvent + */ + SPAWN_CHANGE(Category.WORLD), + /** + * Called when a world is saved + * + * @see org.bukkit.event.world.WorldSaveEvent + */ + WORLD_SAVE(Category.WORLD), + /** + * Called when a World is initializing + * + * @see org.bukkit.event.world.WorldInitEvent + */ + WORLD_INIT(Category.WORLD), + /** + * Called when a World is loaded + * + * @see org.bukkit.event.world.WorldLoadEvent + */ + WORLD_LOAD(Category.WORLD), + /** + * Called when a World is unloaded + * + * @see org.bukkit.event.world.WorldUnloadEvent + */ + WORLD_UNLOAD(Category.WORLD), + /** + * Called when world attempts to create a matching end to a portal + * + * @see org.bukkit.event.world.PortalCreateEvent + */ + PORTAL_CREATE(Category.WORLD), + + /** + * ENTITY EVENTS + */ + + /** + * Called when an item despawns + * + * @see org.bukkit.event.entity.ItemDespawnEvent + */ + ITEM_DESPAWN(Category.ENTITY), + /** + * Called when a painting is placed by player + * + * @see org.bukkit.event.painting.PaintingPlaceEvent + */ + PAINTING_PLACE(Category.ENTITY), + /** + * Called when a painting is removed + * + * @see org.bukkit.event.painting.PaintingBreakEvent + */ + PAINTING_BREAK(Category.ENTITY), + /** + * Called when an entity touches a portal block + * + * @see org.bukkit.event.entity.EntityPortalEnterEvent + */ + ENTITY_PORTAL_ENTER(Category.ENTITY), + + /** + * LIVING_ENTITY EVENTS + */ + + /** + * Called when a creature, either hostile or neutral, attempts to spawn + * in the world "naturally" + * + * @see org.bukkit.event.entity.CreatureSpawnEvent + */ + CREATURE_SPAWN(Category.LIVING_ENTITY), + /** + * Called when a LivingEntity is damaged with no source. + * + * @see org.bukkit.event.entity.EntityDamageEvent + */ + ENTITY_DAMAGE(Category.LIVING_ENTITY), + // Project Poseidon Start + ENTITY_DAMAGE_BY_ENTITY(Category.LIVING_ENTITY), + ENTITY_DAMAGE_BY_BLOCK(Category.LIVING_ENTITY), + // Project Poseidon End + /** + * Called when a LivingEntity dies + * + * @see org.bukkit.event.entity.EntityDeathEvent + */ + ENTITY_DEATH(Category.LIVING_ENTITY), + /** + * Called when a Skeleton or Zombie catch fire due to the sun + * + * @see org.bukkit.event.entity.EntityCombustEvent + */ + ENTITY_COMBUST(Category.LIVING_ENTITY), + /** + * Called when an entity explodes, either TNT, Creeper, or Ghast Fireball + * + * @see org.bukkit.event.entity.EntityExplodeEvent + */ + ENTITY_EXPLODE(Category.LIVING_ENTITY), + /** + * Called when an entity has made a decision to explode. + *

+ * Provides an opportunity to act on the entity, change the explosion radius, + * or to change the fire-spread flag. + *

+ * Canceling the event negates the entity's decision to explode. + * For EntityCreeper, this resets the fuse but does not kill the Entity. + * For EntityFireball and EntityTNTPrimed....? + * + * @see org.bukkit.event.entity.ExplosionPrimeEvent + */ + EXPLOSION_PRIME(Category.LIVING_ENTITY), + /** + * Called when an entity targets another entity + * + * @see org.bukkit.event.entity.EntityTargetEvent + */ + ENTITY_TARGET(Category.LIVING_ENTITY), + /** + * Called when an entity interacts with a block + * This event specifically excludes player entities + * + * @see org.bukkit.event.entity.EntityInteractEvent + */ + ENTITY_INTERACT(Category.LIVING_ENTITY), + /** + * Called when a creeper gains or loses a power shell + * + * @see org.bukkit.event.entity.CreeperPowerEvent + */ + CREEPER_POWER(Category.LIVING_ENTITY), + /** + * Called when a pig is zapped, zombifying it + * + * @see org.bukkit.event.entity.PigZapEvent + */ + PIG_ZAP(Category.LIVING_ENTITY), + /** + * Called when a LivingEntity is tamed + * + * @see org.bukkit.event.entity.EntityTameEvent + */ + ENTITY_TAME(Category.LIVING_ENTITY), + /** + * Called when a {@link Projectile} hits something + * + * @see org.bukkit.event.entity.ProjectileHitEvent + */ + PROJECTILE_HIT(Category.ENTITY), + + /** + * Called when a LivingEntity is regains health + * + * @see org.bukkit.event.entity.EntityRegainHealthEvent + */ + ENTITY_REGAIN_HEALTH(Category.LIVING_ENTITY), + + /** + * WEATHER EVENTS + */ + + /** + * Called when a lightning entity strikes somewhere + * + * @see org.bukkit.event.weather.LightningStrikeEvent + */ + LIGHTNING_STRIKE(Category.WEATHER), + /** + * Called when the weather in a world changes + * + * @see org.bukkit.event.weather.WeatherChangeEvent + */ + WEATHER_CHANGE(Category.WEATHER), + /** + * Called when the thunder state in a world changes + * + * @see org.bukkit.event.weather.ThunderChangeEvent + */ + THUNDER_CHANGE(Category.WEATHER), + + /** + * VEHICLE EVENTS + */ + + /** + * Called when a vehicle is placed by a player + * + * @see org.bukkit.event.vehicle.VehicleCreateEvent + */ + VEHICLE_CREATE(Category.VEHICLE), + /** + * Called when a vehicle is destroyed + * + * @see org.bukkit.event.vehicle.VehicleDestroyEvent + */ + VEHICLE_DESTROY(Category.VEHICLE), + /** + * Called when a vehicle is damaged by a LivingEntity + * + * @see org.bukkit.event.vehicle.VehicleDamageEvent + */ + VEHICLE_DAMAGE(Category.VEHICLE), + /** + * Called when a vehicle collides with an Entity + * + * @see org.bukkit.event.vehicle.VehicleCollisionEvent + */ + VEHICLE_COLLISION_ENTITY(Category.VEHICLE), + /** + * Called when a vehicle collides with a Block + * + * @see org.bukkit.event.vehicle.VehicleBlockCollisionEvent + */ + VEHICLE_COLLISION_BLOCK(Category.VEHICLE), + /** + * Called when a vehicle is entered by a LivingEntity + * + * @see org.bukkit.event.vehicle.VehicleEnterEvent + */ + VEHICLE_ENTER(Category.VEHICLE), + /** + * Called when a vehicle is exited by a LivingEntity + * + * @see org.bukkit.event.vehicle.VehicleExitEvent + */ + VEHICLE_EXIT(Category.VEHICLE), + /** + * Called when a vehicle moves position in the world + * + * @see org.bukkit.event.vehicle.VehicleMoveEvent + */ + VEHICLE_MOVE(Category.VEHICLE), + /** + * Called when a vehicle is going through an update cycle, rechecking itself + * + * @see org.bukkit.event.vehicle.VehicleUpdateEvent + */ + VEHICLE_UPDATE(Category.VEHICLE), + /** + * MISCELLANEOUS EVENTS + */ + + /** + * Represents a custom event, isn't actually used + */ + CUSTOM_EVENT(Category.MISCELLANEOUS); + + private final Category category; + + private Type(Category category) { + this.category = category; + } + + // Project Poseidon Start + public static Type getTypeByName(String name) { + for (Type type : Type.values()) { + String typeName = type.name(); + String typeName_ = typeName.replace("_", ""); + if (name.equalsIgnoreCase(typeName)) + return type; + if (name.equalsIgnoreCase(typeName_)) + return type; + } + return null; + } + // Project Poseidon End + + /** + * Gets the Category assigned to this event + * + * @return Category of this Event.Type + */ + public Category getCategory() { + return category; + } + } + + public enum Result { + + /** + * Deny the event. + * Depending on the event, the action indicated by the event will either not take place or will be reverted. + * Some actions may not be denied. + */ + DENY, + /** + * Neither deny nor allow the event. + * The server will proceed with its normal handling. + */ + DEFAULT, + /** + * Allow / Force the event. + * The action indicated by the event will take place if possible, even if the server would not normally allow the action. + * Some actions may not be allowed. + */ + ALLOW; + } +} diff --git a/src/main/java/org/bukkit/event/EventException.java b/src/main/java/org/bukkit/event/EventException.java new file mode 100644 index 0000000..2084e98 --- /dev/null +++ b/src/main/java/org/bukkit/event/EventException.java @@ -0,0 +1,48 @@ +package org.bukkit.event; + +public class EventException extends Exception { + private static final long serialVersionUID = 3532808232324183999L; + private final Throwable cause; + + /** + * Constructs a new EventException based on the given Exception + * + * @param throwable Exception that triggered this Exception + */ + public EventException(Throwable throwable) { + cause = throwable; + } + + /** + * Constructs a new EventException + */ + public EventException() { + cause = null; + } + + /** + * Constructs a new EventException with the given message + */ + public EventException(Throwable cause, String message) { + super(message); + this.cause = cause; + } + + /** + * Constructs a new EventException with the given message + */ + public EventException(String message) { + super(message); + cause = null; + } + + /** + * If applicable, returns the Exception that triggered this Exception + * + * @return Inner exception, or null if one does not exist + */ + @Override + public Throwable getCause() { + return cause; + } +} diff --git a/src/main/java/org/bukkit/event/EventHandler.java b/src/main/java/org/bukkit/event/EventHandler.java new file mode 100644 index 0000000..8fbd0f0 --- /dev/null +++ b/src/main/java/org/bukkit/event/EventHandler.java @@ -0,0 +1,38 @@ +package org.bukkit.event; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface EventHandler { + + /** + * Define the priority of the event. + *

+ * First priority to the last priority executed: + *

    + *
  1. LOWEST + *
  2. LOW + *
  3. NORMAL + *
  4. HIGH + *
  5. HIGHEST + *
  6. MONITOR + *
+ * + * @return the priority + */ + Event.Priority priority() default Event.Priority.Normal; + + /** + * Define if the handler ignores a cancelled event. + *

+ * If ignoreCancelled is true and the event is cancelled, the method is + * not called. Otherwise, the method is always called. + * + * @return whether cancelled events should be ignored + */ + boolean ignoreCancelled() default false; +} diff --git a/src/main/java/org/bukkit/event/EventPriority.java b/src/main/java/org/bukkit/event/EventPriority.java new file mode 100644 index 0000000..61ffa50 --- /dev/null +++ b/src/main/java/org/bukkit/event/EventPriority.java @@ -0,0 +1,47 @@ +package org.bukkit.event; + +/** + * Represents an event's priority in execution + */ +public enum EventPriority { + + /** + * Event call is of very low importance and should be ran first, to allow + * other plugins to further customise the outcome + */ + LOWEST(0), + /** + * Event call is of low importance + */ + LOW(1), + /** + * Event call is neither important nor unimportant, and may be ran + * normally + */ + NORMAL(2), + /** + * Event call is of high importance + */ + HIGH(3), + /** + * Event call is critical and must have the final say in what happens + * to the event + */ + HIGHEST(4), + /** + * Event is listened to purely for monitoring the outcome of an event. + *

+ * No modifications to the event should be made under this priority + */ + MONITOR(5); + + private final int slot; + + private EventPriority(int slot) { + this.slot = slot; + } + + public int getSlot() { + return slot; + } +} diff --git a/src/main/java/org/bukkit/event/Listener.java b/src/main/java/org/bukkit/event/Listener.java new file mode 100644 index 0000000..ff083e6 --- /dev/null +++ b/src/main/java/org/bukkit/event/Listener.java @@ -0,0 +1,6 @@ +package org.bukkit.event; + +/** + * Simple interface for tagging all EventListeners + */ +public interface Listener {} diff --git a/src/main/java/org/bukkit/event/block/Action.java b/src/main/java/org/bukkit/event/block/Action.java new file mode 100644 index 0000000..b8d2bcb --- /dev/null +++ b/src/main/java/org/bukkit/event/block/Action.java @@ -0,0 +1,25 @@ +package org.bukkit.event.block; + +public enum Action { + + /** + * Left-clicking a block + */ + LEFT_CLICK_BLOCK, + /** + * Right-clicking a block + */ + RIGHT_CLICK_BLOCK, + /** + * Left-clicking the air + */ + LEFT_CLICK_AIR, + /** + * Right-clicking the air + */ + RIGHT_CLICK_AIR, + /** + * Ass-pressure + */ + PHYSICAL, +} diff --git a/src/main/java/org/bukkit/event/block/BlockBreakEvent.java b/src/main/java/org/bukkit/event/block/BlockBreakEvent.java new file mode 100644 index 0000000..5563f40 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockBreakEvent.java @@ -0,0 +1,43 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Called when a block is broken by a player. + *

+ * Note: + * Plugins wanting to simulate a traditional block drop should set the block to air and utilise their own methods for determining + * what the default drop for the block being broken is and what to do about it, if anything. + *

+ * If a Block Break event is cancelled, the block will not break. + */ +public class BlockBreakEvent extends BlockEvent implements Cancellable { + + private Player player; + private boolean cancel; + + public BlockBreakEvent(final Block theBlock, Player player) { + super(Type.BLOCK_BREAK, theBlock); + this.player = player; + this.cancel = false; + } + + /** + * Gets the Player that is breaking the block involved in this event. + * + * @return The Player that is breaking the block involved in this event + */ + public Player getPlayer() { + return player; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockBurnEvent.java b/src/main/java/org/bukkit/event/block/BlockBurnEvent.java new file mode 100644 index 0000000..f0567e1 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockBurnEvent.java @@ -0,0 +1,26 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; + +/** + * Called when a block is destroyed as a result of being burnt by fire. + *

+ * If a Block Burn event is cancelled, the block will not be destroyed as a result of being burnt by fire. + */ +public class BlockBurnEvent extends BlockEvent implements Cancellable { + private boolean cancelled; + + public BlockBurnEvent(Block block) { + super(Type.BLOCK_BURN, block); + this.cancelled = false; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java b/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java new file mode 100644 index 0000000..3c195da --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java @@ -0,0 +1,61 @@ +package org.bukkit.event.block; + +import org.bukkit.Material; +import org.bukkit.block.Block; + +/** + * Called when we try to place a block, to see if we can build it here or not. + *

+ * Note: + *

    + *
  • The Block returned by getBlock() is the block we are trying to place on, not the block we are trying to place.
  • + *
  • If you want to figure out what is being placed, use {@link #getMaterial()} or {@link #getMaterialId()} instead.
  • + *
+ */ +public class BlockCanBuildEvent extends BlockEvent { + protected boolean buildable; + protected int material; + + public BlockCanBuildEvent(Block block, int id, boolean canBuild) { + super(Type.BLOCK_CANBUILD, block); + buildable = canBuild; + material = id; + } + + /** + * Gets whether or not the block can be built here. + * By default, returns Minecraft's answer on whether the block can be built here or not. + * + * @return boolean whether or not the block can be built + */ + public boolean isBuildable() { + return buildable; + } + + /** + * Sets whether the block can be built here or not. + * + * @param cancel true if you want to allow the block to be built here despite Minecraft's default behaviour + */ + public void setBuildable(boolean cancel) { + this.buildable = cancel; + } + + /** + * Gets the Material that we are trying to place. + * + * @return The Material that we are trying to place + */ + public Material getMaterial() { + return Material.getMaterial(material); + } + + /** + * Gets the Material ID for the Material that we are trying to place. + * + * @return The Material ID for the Material that we are trying to place + */ + public int getMaterialId() { + return material; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockDamageEvent.java b/src/main/java/org/bukkit/event/block/BlockDamageEvent.java new file mode 100644 index 0000000..e2d8cd8 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockDamageEvent.java @@ -0,0 +1,70 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.inventory.ItemStack; + +/** + * Called when a block is damaged by a player. + *

+ * If a Block Damage event is cancelled, the block will not be damaged. + */ +public class BlockDamageEvent extends BlockEvent implements Cancellable { + private Player player; + private boolean instaBreak; + private boolean cancel; + private ItemStack itemstack; + + public BlockDamageEvent(Player player, Block block, ItemStack itemInHand, boolean instaBreak) { + super(Type.BLOCK_DAMAGE, block); + this.instaBreak = instaBreak; + this.player = player; + this.itemstack = itemInHand; + this.cancel = false; + } + + /** + * Gets the player damaging the block involved in this event. + * + * @return The player damaging the block involved in this event + */ + public Player getPlayer() { + return player; + } + + /** + * Gets if the block is set to instantly break when damaged by the player. + * + * @return true if the block should instantly break when damaged by the player + */ + public boolean getInstaBreak() { + return instaBreak; + } + + /** + * Sets if the block should instantly break when damaged by the player. + * + * @param bool true if you want the block to instantly break when damaged by the player + */ + public void setInstaBreak(boolean bool) { + this.instaBreak = bool; + } + + /** + * Gets the ItemStack for the item currently in the player's hand. + * + * @return The ItemStack for the item currently in the player's hand + */ + public ItemStack getItemInHand() { + return itemstack; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockDispenseEvent.java b/src/main/java/org/bukkit/event/block/BlockDispenseEvent.java new file mode 100644 index 0000000..84ffc7d --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockDispenseEvent.java @@ -0,0 +1,71 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +/** + * Called when an item is dispensed from a block. + *

+ * If a Block Dispense event is cancelled, the block will not dispense the item. + */ +public class BlockDispenseEvent extends BlockEvent implements Cancellable { + + private boolean cancelled = false; + private ItemStack item; + private Vector velocity; + + public BlockDispenseEvent(Block block, ItemStack dispensed, Vector velocity) { + super(Type.BLOCK_DISPENSE, block); + this.item = dispensed; + this.velocity = velocity; + } + + /** + * Gets the item that is being dispensed. Modifying the returned item + * will have no effect, you must use {@link #setItem(org.bukkit.inventory.ItemStack)} instead. + * + * @return An ItemStack for the item being dispensed + */ + public ItemStack getItem() { + return item.clone(); + } + + /** + * Sets the item being dispensed. + * + * @param item the item being dispensed + */ + public void setItem(ItemStack item) { + this.item = item; + } + + /** + * Gets the velocity. + *

+ * Note: Modifying the returned Vector will not change the velocity, you must use {@link #setVelocity(org.bukkit.util.Vector)} instead. + * + * @return A Vector for the dispensed item's velocity + */ + public Vector getVelocity() { + return velocity.clone(); + } + + /** + * Sets the velocity of the item being dispensed. + * + * @param vel the velocity of the item being dispensed + */ + public void setVelocity(Vector vel) { + velocity = vel; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockEvent.java b/src/main/java/org/bukkit/event/block/BlockEvent.java new file mode 100644 index 0000000..ab7de90 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.event.Event; + +/** + * Represents a block related event. + */ +public class BlockEvent extends Event { + protected Block block; + + public BlockEvent(final Event.Type type, final Block theBlock) { + super(type); + block = theBlock; + } + + /** + * Gets the block involved in this event. + * + * @return The Block which block is involved in this event + */ + public final Block getBlock() { + return block; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockFadeEvent.java b/src/main/java/org/bukkit/event/block/BlockFadeEvent.java new file mode 100644 index 0000000..21d97ba --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockFadeEvent.java @@ -0,0 +1,43 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.event.Cancellable; +/** + * Called when a block fades, melts or disappears based on world conditions + *

+ * Examples: + *

    + *
  • Snow melting due to being near a light source.
  • + *
  • Ice melting due to being near a light source.
  • + *
+ *

+ * If a Block Fade event is cancelled, the block will not fade, melt or disappear. + */ +public class BlockFadeEvent extends BlockEvent implements Cancellable { + private boolean cancelled; + private BlockState newState; + + public BlockFadeEvent(Block block, BlockState newState) { + super(Type.BLOCK_FADE, block); + this.newState = newState; + this.cancelled = false; + } + + /** + * Gets the state of the block that will be fading, melting or disappearing. + * + * @return The block state of the block that will be fading, melting or disappearing + */ + public BlockState getNewState() { + return newState; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockFormEvent.java b/src/main/java/org/bukkit/event/block/BlockFormEvent.java new file mode 100644 index 0000000..8717713 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockFormEvent.java @@ -0,0 +1,54 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.event.Cancellable; + +/** + * Called when a block is formed or spreads based on world conditions. + * Use {@link BlockSpreadEvent} to catch blocks that actually spread and don't just "randomly" form. + *

+ * Examples: + *

    + *
  • Snow forming due to a snow storm.
  • + *
  • Ice forming in a snowy Biome like Tiga or Tundra.
  • + *
+ *

+ * If a Block Form event is cancelled, the block will not be formed. + * @see BlockSpreadEvent + */ +public class BlockFormEvent extends BlockEvent implements Cancellable { + private boolean cancelled; + private BlockState newState; + + public BlockFormEvent(Block block, BlockState newState) { + super(Type.BLOCK_FORM, block); + this.block = block; + this.newState = newState; + this.cancelled = false; + } + + public BlockFormEvent(Type type, Block block, BlockState newState) { + super(type, block); + this.block = block; + this.newState = newState; + this.cancelled = false; + } + + /** + * Gets the state of the block where it will form or spread to. + * + * @return The block state of the block where it will form or spread to + */ + public BlockState getNewState() { + return newState; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockFromToEvent.java b/src/main/java/org/bukkit/event/block/BlockFromToEvent.java new file mode 100644 index 0000000..3671083 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockFromToEvent.java @@ -0,0 +1,51 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.event.Cancellable; + +/** + * Represents events with a source block and a destination block, currently only applies to liquid (lava and water). + *

+ * If a Block From To event is cancelled, the block will not move (the liquid will not flow). + */ +public class BlockFromToEvent extends BlockEvent implements Cancellable { + protected Block to; + protected BlockFace face; + protected boolean cancel; + + public BlockFromToEvent(final Block block, final BlockFace face) { + super(Type.BLOCK_FROMTO, block); + this.face = face; + this.cancel = false; + } + + /** + * Gets the BlockFace that the block is moving to. + * + * @return The BlockFace that the block is moving to + */ + public BlockFace getFace() { + return face; + } + + /** + * Convenience method for getting the faced Block. + * + * @return The faced Block + */ + public Block getToBlock() { + if (to == null) { + to = block.getRelative(face.getModX(), face.getModY(), face.getModZ()); + } + return to; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java b/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java new file mode 100644 index 0000000..6bcf2e8 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java @@ -0,0 +1,73 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +/** + * Called when a block is ignited. If you want to catch when a Player places fire, you need to use {@link BlockPlaceEvent}. + *

+ * If a Block Ignite event is cancelled, the block will not be ignited. + */ +public class BlockIgniteEvent extends BlockEvent implements Cancellable { + private IgniteCause cause; + private boolean cancel; + private Player thePlayer; + + public BlockIgniteEvent(Block theBlock, IgniteCause cause, Player thePlayer) { + super(Event.Type.BLOCK_IGNITE, theBlock); + this.cause = cause; + this.thePlayer = thePlayer; + this.cancel = false; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Gets the cause of block ignite. + * + * @return An IgniteCause value detailing the cause of block ignition + */ + public IgniteCause getCause() { + return cause; + } + + /** + * Gets the player who ignited this block + * + * @return The Player who placed the fire block, if not ignited by a player returns null + */ + public Player getPlayer() { + return thePlayer; + } + + /** + * An enum to specify the cause of the ignite + */ + public enum IgniteCause { + + /** + * Block ignition caused by lava. + */ + LAVA, + /** + * Block ignition caused by a player using flint-and-steel. + */ + FLINT_AND_STEEL, + /** + * Block ignition caused by dynamic spreading of fire. + */ + SPREAD, + /** + * Block ignition caused by lightning. + */ + LIGHTNING, + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockListener.java b/src/main/java/org/bukkit/event/block/BlockListener.java new file mode 100644 index 0000000..237ec8f --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockListener.java @@ -0,0 +1,190 @@ +package org.bukkit.event.block; + +import org.bukkit.event.Listener; + +/** + * Handles all events thrown in relation to Blocks + */ +public class BlockListener implements Listener { + + /** + * Default Constructor + */ + public BlockListener() {} + + /** + * Called when a block is damaged by a player. + *

+ * If a Block Damage event is cancelled, the block will not be damaged. + * + * @param event Relevant event details + */ + public void onBlockDamage(BlockDamageEvent event) {} + + /** + * Called when we try to place a block, to see if we can build it here or not. + *

+ * Note: + *

    + *
  • The Block returned by getBlock() is the block we are trying to place on, not the block we are trying to place.
  • + *
  • If you want to figure out what is being placed, use {@link BlockCanBuildEvent#getMaterial()} or {@link BlockCanBuildEvent#getMaterialId()} instead.
  • + *
+ * + * @param event Relevant event details + */ + public void onBlockCanBuild(BlockCanBuildEvent event) {} + + /** + * Represents events with a source block and a destination block, currently only applies to liquid (lava and water). + *

+ * If a Block From To event is cancelled, the block will not move (the liquid will not flow). + * + * @param event Relevant event details + */ + public void onBlockFromTo(BlockFromToEvent event) {} + + /** + * Called when a block is ignited. If you want to catch when a Player places fire, you need to use {@link BlockPlaceEvent}. + *

+ * If a Block Ignite event is cancelled, the block will not be ignited. + * + * @param event Relevant event details + */ + public void onBlockIgnite(BlockIgniteEvent event) {} + + /** + * Called when block physics occurs. + * + * @param event Relevant event details + */ + public void onBlockPhysics(BlockPhysicsEvent event) {} + + /** + * Called when a block is placed by a player. + *

+ * If a Block Place event is cancelled, the block will not be placed. + * + * @param event Relevant event details + */ + public void onBlockPlace(BlockPlaceEvent event) {} + + /** + * Called when redstone changes.
+ * From: the source of the redstone change.
+ * To: The redstone dust that changed. + * + * @param event Relevant event details + */ + public void onBlockRedstoneChange(BlockRedstoneEvent event) {} + + /** + * Called when leaves are decaying naturally. + *

+ * If a Leaves Decay event is cancelled, the leaves will not decay. + * + * @param event Relevant event details + */ + public void onLeavesDecay(LeavesDecayEvent event) {} + + /** + * Called when a sign is changed by a player. + *

+ * If a Sign Change event is cancelled, the sign will not be changed. + * + * @param event Relevant event details + */ + public void onSignChange(SignChangeEvent event) {} + + /** + * Called when a block is destroyed as a result of being burnt by fire. + *

+ * If a Block Burn event is cancelled, the block will not be destroyed as a result of being burnt by fire. + * + * @param event Relevant event details + */ + public void onBlockBurn(BlockBurnEvent event) {} + + /** + * Called when a block is broken by a player. + *

+ * Note: + * Plugins wanting to simulate a traditional block drop should set the block to air and utilise their own methods for determining + * what the default drop for the block being broken is and what to do about it, if anything. + *

+ * If a Block Break event is cancelled, the block will not break. + * + * @param event Relevant event details + */ + public void onBlockBreak(BlockBreakEvent event) {} + + /** + * Called when a block is formed or spreads based on world conditions. + * Use {@link BlockSpreadEvent} to catch blocks that actually spread and don't just "randomly" form. + *

+ * Examples: + *

    + *
  • Snow forming due to a snow storm.
  • + *
  • Ice forming in a snowy Biome like Tiga or Tundra.
  • + *
+ *

+ * If a Block Form event is cancelled, the block will not be formed or will not spread. + * + * @see BlockSpreadEvent + * @param event Relevant event details + */ + public void onBlockForm(BlockFormEvent event) {} + + /** + * Called when a block spreads based on world conditions. + * Use {@link BlockFormEvent} to catch blocks that "randomly" form instead of actually spread. + *

+ * Examples: + *

    + *
  • Mushrooms spreading.
  • + *
  • Fire spreading.
  • + *
+ *

+ * If a Block Spread event is cancelled, the block will not spread. + * + * @param event Relevant event details + */ + public void onBlockSpread(BlockSpreadEvent event) {} + + /** + * Called when a block fades, melts or disappears based on world conditions + *

+ * Examples: + *

    + *
  • Snow melting due to being near a light source.
  • + *
  • Ice melting due to being near a light source.
  • + *
+ *

+ * If a Block Fade event is cancelled, the block will not fade, melt or disappear. + * + * @param event Relevant event details + */ + public void onBlockFade(BlockFadeEvent event) {} + + /** + * Called when an item is dispensed from a block. + *

+ * If a Block Dispense event is cancelled, the block will not dispense the item. + * + * @param event Relevant event details + */ + public void onBlockDispense(BlockDispenseEvent event) {} + + /** + * Called when a piston retracts + * + * @param event Relevant event details + */ + public void onBlockPistonRetract(BlockPistonRetractEvent event) {} + + /** + * Called when a piston extends + * + * @param event Relevant event details + */ + public void onBlockPistonExtend(BlockPistonExtendEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java b/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java new file mode 100644 index 0000000..683c85b --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java @@ -0,0 +1,44 @@ +package org.bukkit.event.block; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; + +/** + * Thrown when a block physics check is called + */ +public class BlockPhysicsEvent extends BlockEvent implements Cancellable { + private final int changed; + private boolean cancel = false; + + public BlockPhysicsEvent(final Block block, final int changed) { + super(Type.BLOCK_PHYSICS, block); + this.changed = changed; + } + + /** + * Gets the type of block that changed, causing this event + * + * @return Changed block's type id + */ + public int getChangedTypeId() { + return changed; + } + + /** + * Gets the type of block that changed, causing this event + * + * @return Changed block's type + */ + public Material getChangedType() { + return Material.getMaterial(changed); + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockPistonEvent.java b/src/main/java/org/bukkit/event/block/BlockPistonEvent.java new file mode 100644 index 0000000..3ffaea7 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockPistonEvent.java @@ -0,0 +1,43 @@ +package org.bukkit.event.block; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.event.Cancellable; +import org.bukkit.material.PistonBaseMaterial; + +public abstract class BlockPistonEvent extends BlockEvent implements Cancellable { + private boolean cancelled; + + public BlockPistonEvent(Type type, Block block) { + super(type, block); + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + /** + * Returns true if the Piston in the event is sticky. + * + * @return stickiness of the piston + */ + public boolean isSticky() { + return block.getType() == Material.PISTON_STICKY_BASE; + } + + /** + * Return the direction in which the piston will operate. + * + * @return direction of the piston + */ + public BlockFace getDirection() { + // Both are meh! + // return ((PistonBaseMaterial) block.getType().getNewData(block.getData ())).getFacing(); + return ((PistonBaseMaterial) block.getState().getData()).getFacing(); + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockPistonExtendEvent.java b/src/main/java/org/bukkit/event/block/BlockPistonExtendEvent.java new file mode 100644 index 0000000..5bb1136 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockPistonExtendEvent.java @@ -0,0 +1,43 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class BlockPistonExtendEvent extends BlockPistonEvent { + private int length; + private List blocks; + + public BlockPistonExtendEvent(Block block, int length) { + super(Type.BLOCK_PISTON_EXTEND, block); + + this.length = length; + } + + /** + * Get the amount of blocks which will be moved while extending. + * + * @return the amount of moving blocks + */ + public int getLength() { + return this.length; + } + + /** + * Get an immutable list of the blocks which will be moved by the extending. + * + * @return Immutable list of the moved blocks. + */ + public List getBlocks() { + if (blocks == null) { + ArrayList tmp = new ArrayList(); + for (int i = 0; i < this.getLength(); i++) { + tmp.add(block.getRelative(getDirection(), i + 1)); + } + blocks = Collections.unmodifiableList(tmp); + } + return blocks; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockPistonRetractEvent.java b/src/main/java/org/bukkit/event/block/BlockPistonRetractEvent.java new file mode 100644 index 0000000..d57fc6b --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockPistonRetractEvent.java @@ -0,0 +1,20 @@ +package org.bukkit.event.block; + +import org.bukkit.Location; +import org.bukkit.block.Block; + +public class BlockPistonRetractEvent extends BlockPistonEvent { + public BlockPistonRetractEvent(Block block) { + super(Type.BLOCK_PISTON_RETRACT, block); + } + + /** + * Gets the location where the possible moving block might be if the retracting + * piston is sticky. + * + * @return The possible location of the possibly moving block. + */ + public Location getRetractLocation() { + return getBlock().getRelative(getDirection(), 2).getLocation(); + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java b/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java new file mode 100644 index 0000000..ea143ca --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java @@ -0,0 +1,108 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.inventory.ItemStack; + +/** + * Called when a block is placed by a player. + *

+ * If a Block Place event is cancelled, the block will not be placed. + */ +public class BlockPlaceEvent extends BlockEvent implements Cancellable { + protected boolean cancel; + protected boolean canBuild; + protected Block placedAgainst; + protected BlockState replacedBlockState; + protected ItemStack itemInHand; + protected Player player; + + public BlockPlaceEvent(Block placedBlock, BlockState replacedBlockState, Block placedAgainst, ItemStack itemInHand, Player thePlayer, boolean canBuild) { + super(Type.BLOCK_PLACE, placedBlock); + this.placedAgainst = placedAgainst; + this.itemInHand = itemInHand; + this.player = thePlayer; + this.replacedBlockState = replacedBlockState; + this.canBuild = canBuild; + cancel = false; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Gets the player who placed the block involved in this event. + * + * @return The Player who placed the block involved in this event + */ + public Player getPlayer() { + return player; + } + + /** + * Clarity method for getting the placed block. Not really needed + * except for reasons of clarity. + * + * @return The Block that was placed + */ + public Block getBlockPlaced() { + return getBlock(); + } + + /** + * Gets the BlockState for the block which was replaced. Material type air mostly. + * + * @return The BlockState for the block which was replaced. + */ + public BlockState getBlockReplacedState() { + return this.replacedBlockState; + } + + /** + * Gets the block that this block was placed against + * + * @return Block the block that the new block was placed against + */ + public Block getBlockAgainst() { + return placedAgainst; + } + + /** + * Gets the item in the player's hand when they placed the block. + * + * @return The ItemStack for the item in the player's hand when they placed the block + */ + public ItemStack getItemInHand() { + return itemInHand; + } + + /** + * Gets the value whether the player would be allowed to build here. + * Defaults to spawn if the server was going to stop them (such as, the + * player is in Spawn). Note that this is an entirely different check + * than BLOCK_CANBUILD, as this refers to a player, not universe-physics + * rule like cactus on dirt. + * + * @return boolean whether the server would allow a player to build here + */ + public boolean canBuild() { + return this.canBuild; + } + + /** + * Sets the canBuild state of this event. Set to true if you want the + * player to be able to build. + * + * @param canBuild true if you want the player to be able to build + */ + public void setBuild(boolean canBuild) { + this.canBuild = canBuild; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockRedstoneEvent.java b/src/main/java/org/bukkit/event/block/BlockRedstoneEvent.java new file mode 100644 index 0000000..9691a6b --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockRedstoneEvent.java @@ -0,0 +1,44 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; + +/** + * Called when a redstone current changes + */ +public class BlockRedstoneEvent extends BlockEvent { + private int oldCurrent; + private int newCurrent; + + public BlockRedstoneEvent(Block block, int oldCurrent, int newCurrent) { + super(Type.REDSTONE_CHANGE, block); + this.oldCurrent = oldCurrent; + this.newCurrent = newCurrent; + } + + /** + * Gets the old current of this block + * + * @return The previous current + */ + public int getOldCurrent() { + return oldCurrent; + } + + /** + * Gets the new current of this block + * + * @return The new current + */ + public int getNewCurrent() { + return newCurrent; + } + + /** + * Sets the new current of this block + * + * @param newCurrent The new current to set + */ + public void setNewCurrent(int newCurrent) { + this.newCurrent = newCurrent; + } +} diff --git a/src/main/java/org/bukkit/event/block/BlockSpreadEvent.java b/src/main/java/org/bukkit/event/block/BlockSpreadEvent.java new file mode 100644 index 0000000..9e56ae7 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/BlockSpreadEvent.java @@ -0,0 +1,34 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +/** + * Called when a block spreads based on world conditions. + * Use {@link BlockFormEvent} to catch blocks that "randomly" form instead of actually spread. + *

+ * Examples: + *

    + *
  • Mushrooms spreading.
  • + *
  • Fire spreading.
  • + *
+ *

+ * If a Block Spread event is cancelled, the block will not spread. + * @see BlockFormEvent + */ +public class BlockSpreadEvent extends BlockFormEvent { + private Block source; + + public BlockSpreadEvent(Block block, Block source, BlockState newState) { + super(Type.BLOCK_SPREAD, block, newState); + this.source = source; + } + + /** + * Gets the source block involved in this event. + * + * @return the Block for the source block involved in this event. + */ + public Block getSource() { + return source; + } +} diff --git a/src/main/java/org/bukkit/event/block/LeavesDecayEvent.java b/src/main/java/org/bukkit/event/block/LeavesDecayEvent.java new file mode 100644 index 0000000..4757bb0 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/LeavesDecayEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; + +/** + * Called when leaves are decaying naturally. + *

+ * If a Leaves Decay event is cancelled, the leaves will not decay. + */ +public class LeavesDecayEvent extends BlockEvent implements Cancellable { + private boolean cancel = false; + + public LeavesDecayEvent(final Block block) { + super(Type.LEAVES_DECAY, block); + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/block/SignChangeEvent.java b/src/main/java/org/bukkit/event/block/SignChangeEvent.java new file mode 100644 index 0000000..03b6958 --- /dev/null +++ b/src/main/java/org/bukkit/event/block/SignChangeEvent.java @@ -0,0 +1,70 @@ +package org.bukkit.event.block; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Called when a sign is changed by a player. + *

+ * If a Sign Change event is cancelled, the sign will not be changed. + */ +public class SignChangeEvent extends BlockEvent implements Cancellable { + private boolean cancel = false; + private Player player; + private String[] lines; + + public SignChangeEvent(final Block theBlock, final Player thePlayer, String[] theLines) { + super(Type.SIGN_CHANGE, theBlock); + this.player = thePlayer; + this.lines = theLines; + } + + /** + * Gets the player changing the sign involved in this event. + * + * @return The Player involved in this event. + */ + public Player getPlayer() { + return player; + } + + /** + * Gets all of the lines of text from the sign involved in this event. + * + * @return A String[] of the sign's lines of text + */ + public String[] getLines() { + return lines; + } + + /** + * Gets a single line of text from the sign involved in this event. + * + * @param index index of the line to get + * @return The String containing the line of text associated with the provided index + * @throws IndexOutOfBoundsException thrown when the provided index is > 4 and < 0 + */ + public String getLine(int index) throws IndexOutOfBoundsException { + return lines[index]; + } + + /** + * Sets a single line for the sign involved in this event + * + * @param index index of the line to set + * @param line text to set + * @throws IndexOutOfBoundsException thrown when the provided index is > 4 and < 0 + */ + public void setLine(int index, String line) throws IndexOutOfBoundsException { + lines[index] = line; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java new file mode 100644 index 0000000..ead5cc6 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java @@ -0,0 +1,92 @@ +package org.bukkit.event.entity; + +import org.bukkit.Location; +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when a creature is spawned into a world. + *

+ * If a Creature Spawn event is cancelled, the creature will not spawn. + */ +public class CreatureSpawnEvent extends EntityEvent implements Cancellable { + + private Location location; + private boolean canceled; + private CreatureType creatureType; + private SpawnReason spawnReason; + + public CreatureSpawnEvent(Entity spawnee, CreatureType mobtype, Location loc, SpawnReason spawnReason) { + super(Type.CREATURE_SPAWN, spawnee); + this.creatureType = mobtype; + this.location = loc; + this.spawnReason = spawnReason; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the location at which the creature is spawning. + * + * @return The location at which the creature is spawning + */ + public Location getLocation() { + return location; + } + + /** + * Gets the type of creature being spawned. + * + * @return A CreatureType value detailing the type of creature being spawned + */ + public CreatureType getCreatureType() { + return creatureType; + } + + /** + * Gets the reason for why the creature is being spawned. + * + * @return A SpawnReason value detailing the reason for the creature being spawned + */ + public SpawnReason getSpawnReason() { + return spawnReason; + } + + /** + * An enum to specify the type of spawning + */ + public enum SpawnReason { + + /** + * When something spawns from natural means + */ + NATURAL, + /** + * When a creature spawns from a spawner + */ + SPAWNER, + /** + * When a creature spawns from an egg + */ + EGG, + /** + * When a creature spawns because of a lightning strike + */ + LIGHTNING, + /** + * When a creature is spawned by a player that is sleeping + */ + BED, + /** + * When a creature is manually spawned + */ + CUSTOM + } +} diff --git a/src/main/java/org/bukkit/event/entity/CreeperPowerEvent.java b/src/main/java/org/bukkit/event/entity/CreeperPowerEvent.java new file mode 100644 index 0000000..1d9021a --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/CreeperPowerEvent.java @@ -0,0 +1,79 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when a Creeper is struck by lightning. + *

+ * If a Creeper Power event is cancelled, the Creeper will not be powered. + */ +public class CreeperPowerEvent extends EntityEvent implements Cancellable { + + private boolean canceled; + private Entity creeper; + private PowerCause cause; + private Entity bolt; + + public CreeperPowerEvent(Entity creeper, Entity bolt, PowerCause cause) { + super(Type.CREEPER_POWER, creeper); + this.creeper = creeper; + this.bolt = bolt; + this.cause = cause; + } + + public CreeperPowerEvent(Entity creeper, PowerCause cause) { + super(Type.CREEPER_POWER, creeper); + this.creeper = creeper; + this.cause = cause; + this.bolt = null; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the lightning bolt which is striking the Creeper. + * + * @return The Entity for the lightning bolt which is striking the Creeper + */ + public Entity getLightning() { + return bolt; + } + + /** + * Gets the cause of the creeper being (un)powered. + * + * @return A PowerCause value detailing the cause of change in power. + */ + public PowerCause getCause() { + return cause; + } + + /** + * An enum to specify the cause of the change in power + */ + public enum PowerCause { + + /** + * Power change caused by a lightning bolt + * Powered state: true + */ + LIGHTNING, + /** + * Power change caused by something else (probably a plugin) + * Powered state: true + */ + SET_ON, + /** + * Power change caused by something else (probably a plugin) + * Powered state: false + */ + SET_OFF + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityCombustEvent.java b/src/main/java/org/bukkit/event/entity/EntityCombustEvent.java new file mode 100644 index 0000000..0587576 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityCombustEvent.java @@ -0,0 +1,26 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when an entity combusts due to the sun. + *

+ * If an Entity Combust event is cancelled, the entity will not combust. + */ +public class EntityCombustEvent extends EntityEvent implements Cancellable { + private boolean cancel; + + public EntityCombustEvent(Entity what) { + super(Type.ENTITY_COMBUST, what); + this.cancel = false; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java new file mode 100644 index 0000000..b2c267c --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java @@ -0,0 +1,27 @@ +package org.bukkit.event.entity; + +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when an entity is damaged by a block + */ +public class EntityDamageByBlockEvent extends EntityDamageEvent implements Cancellable { + + private Block damager; + + public EntityDamageByBlockEvent(Block damager, Entity damagee, DamageCause cause, int damage) { + super(Type.ENTITY_DAMAGE, damagee, cause, damage); + this.damager = damager; + } + + /** + * Returns the block that damaged the player. + * + * @return Block that damaged the player + */ + public Block getDamager() { + return damager; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java new file mode 100644 index 0000000..9431f56 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java @@ -0,0 +1,26 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when an entity is damaged by an entity + */ +public class EntityDamageByEntityEvent extends EntityDamageEvent implements Cancellable { + + private Entity damager; + + public EntityDamageByEntityEvent(Entity damager, Entity damagee, DamageCause cause, int damage) { + super(Type.ENTITY_DAMAGE, damagee, cause, damage); + this.damager = damager; + } + + /** + * Returns the entity that damaged the defender. + * + * @return Entity that damaged the defender. + */ + public Entity getDamager() { + return damager; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByProjectileEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByProjectileEvent.java new file mode 100644 index 0000000..5419b01 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityDamageByProjectileEvent.java @@ -0,0 +1,41 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Projectile; + +/** + * Called when an entity is damaged by a projectile + * + * @deprecated use {@link EntityDamageByEntityEvent} instead, where {@link EntityDamageByEntityEvent#getDamager()} will return the {@link Projectile} + */ +@Deprecated +public class EntityDamageByProjectileEvent extends EntityDamageByEntityEvent { + + private Projectile projectile; + + public EntityDamageByProjectileEvent(Entity damagee, Projectile projectile, DamageCause cause, int damage) { + this(projectile.getShooter(), damagee, projectile, cause, damage); + } + + public EntityDamageByProjectileEvent(Entity damager, Entity damagee, Projectile projectile, DamageCause cause, int damage) { + super(damager, projectile, DamageCause.PROJECTILE, damage); + this.projectile = projectile; + } + + /** + * The projectile used to cause the event + * + * @return the projectile + */ + public Projectile getProjectile() { + return projectile; + } + + public void setBounce(boolean bounce) { + projectile.setBounce(bounce); + } + + public boolean getBounce() { + return projectile.doesBounce(); + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java new file mode 100644 index 0000000..f78424c --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java @@ -0,0 +1,171 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +/** + * Stores data for damage events + */ +public class EntityDamageEvent extends EntityEvent implements Cancellable { + + private int damage; + private boolean cancelled; + private DamageCause cause; + + public EntityDamageEvent(Entity damagee, DamageCause cause, int damage) { + this(Event.Type.ENTITY_DAMAGE, damagee, cause, damage); + } + + protected EntityDamageEvent(Event.Type type, Entity damagee, DamageCause cause, int damage) { + super(type, damagee); + this.cause = cause; + this.damage = damage; + + damagee.setLastDamageCause(this); + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + /** + * Gets the amount of damage caused by the Block + * + * @return The amount of damage caused by the Block + */ + public int getDamage() { + return damage; + } + + /** + * Sets the amount of damage caused by the Block + * + * @param damage The amount of damage caused by the Block + */ + public void setDamage(int damage) { + this.damage = damage; + } + + /** + * Gets the cause of the damage. + * + * @return A DamageCause value detailing the cause of the damage. + */ + public DamageCause getCause() { + return cause; + } + + /** + * An enum to specify the cause of the damage + */ + public enum DamageCause { + + /** + * Damage caused when an entity contacts a block such as a Cactus. + * + * Damage: 1 (Cactus) + */ + CONTACT, + /** + * Damage caused when an entity attacks another entity. + * + * Damage: variable + */ + ENTITY_ATTACK, + /** + * Damage caused when attacked by a projectile. + * + * Damage: variable + */ + PROJECTILE, + /** + * Damage caused by being put in a block + * + * Damage: 1 + */ + SUFFOCATION, + /** + * Damage caused when an entity falls a distance greater than 3 blocks + * + * Damage: fall height - 3.0 + */ + FALL, + /** + * Damage caused by direct exposure to fire + * + * Damage: 1 + */ + FIRE, + /** + * Damage caused due to burns caused by fire + * + * Damage: 1 + */ + FIRE_TICK, + /** + * Damage caused by direct exposure to lava + * + * Damage: 4 + */ + LAVA, + /** + * Damage caused by running out of air while in water + * + * Damage: 2 + */ + DROWNING, + /** + * Damage caused by being in the area when a block explodes. + * + * Damage: variable + */ + BLOCK_EXPLOSION, + /** + * Damage caused by being in the area when a block of TNT explodes. + */ + TNT_EXPLOSION, + /** + * Damage caused by being in the area when a bed explodes. + */ + BED_EXPLOSION, + /** + * Damage caused by being in the area when a plugin causes an explosion + */ + PLUGIN_EXPLOSION, + /** + * Damage caused by being in the area when an entity, such as a Creeper, explodes. + * + * Damage: variable + */ + ENTITY_EXPLOSION, + /** + * Damage caused by falling into the void + * + * Damage: 4 for players + */ + VOID, + /** + * Damage caused by being struck by lightning + * + * Damage: 5 + */ + LIGHTNING, + /** + * Damage caused by committing suicide using the command "/kill" + * + * Damage: 1000 + */ + SUICIDE, + /** + * Custom damage. + * + * Damage: variable + */ + CUSTOM + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java new file mode 100644 index 0000000..2181b8e --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java @@ -0,0 +1,27 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +/** + * Thrown whenever a LivingEntity dies + */ +public class EntityDeathEvent extends EntityEvent { + private List drops; + + public EntityDeathEvent(final Entity what, final List drops) { + super(Type.ENTITY_DEATH, what); + this.drops = drops; + } + + /** + * Gets all the items which will drop when the entity dies + * + * @return Items to drop when the entity dies + */ + public List getDrops() { + return drops; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityEvent.java new file mode 100644 index 0000000..ef35d00 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Event; + +/** + * Represents an Entity-related event + */ +public class EntityEvent extends Event { + protected Entity entity; + + public EntityEvent(final Event.Type type, final Entity what) { + super(type); + entity = what; + } + + /** + * Returns the Entity involved in this event + * + * @return Entity who is involved in this event + */ + public final Entity getEntity() { + return entity; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java b/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java new file mode 100644 index 0000000..bff1900 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java @@ -0,0 +1,66 @@ +package org.bukkit.event.entity; + +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +import java.util.List; + +/** + * Called when an entity explodes + */ +public class EntityExplodeEvent extends EntityEvent implements Cancellable { + private boolean cancel; + private Location location; + private List blocks; + private float yield = 0.3F; + + public EntityExplodeEvent(Entity what, Location location, List blocks) { + super(Type.ENTITY_EXPLODE, what); + this.location = location; + this.cancel = false; + this.blocks = blocks; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Returns the list of blocks that would have been removed or were + * removed from the explosion event. + */ + public List blockList() { + return blocks; + } + + /** + * Returns the location where the explosion happened. + * It is not possible to get this value from the Entity as + * the Entity no longer exists in the world. + */ + public Location getLocation() { + return location; + } + + /** + * Returns the percentage of blocks to drop from this explosion + * + * @return + */ + public float getYield() { + return yield; + } + + /** + * Sets the percentage of blocks to drop from this explosion + */ + public void setYield(float yield) { + this.yield = yield; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityInteractEvent.java b/src/main/java/org/bukkit/event/entity/EntityInteractEvent.java new file mode 100644 index 0000000..0fec15b --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityInteractEvent.java @@ -0,0 +1,36 @@ +package org.bukkit.event.entity; + +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when an entity interacts with an object + */ +public class EntityInteractEvent extends EntityEvent implements Cancellable { + protected Block block; + + private boolean cancelled; + + public EntityInteractEvent(Entity entity, Block block) { + super(Type.ENTITY_INTERACT, entity); + this.block = block; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + /** + * Returns the involved block + * + * @return the block clicked with this item. + */ + public Block getBlock() { + return block; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityListener.java b/src/main/java/org/bukkit/event/entity/EntityListener.java new file mode 100644 index 0000000..ec4c46a --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityListener.java @@ -0,0 +1,148 @@ +package org.bukkit.event.entity; + +import org.bukkit.event.Listener; +import org.bukkit.event.painting.PaintingBreakEvent; +import org.bukkit.event.painting.PaintingPlaceEvent; + +/** + * Handles all events fired in relation to entities + */ +public class EntityListener implements Listener { + public EntityListener() {} + + /** + * Called when a creature is spawned into a world. + *

+ * If a Creature Spawn event is cancelled, the creature will not spawn. + * + * @param event Relevant event details + */ + public void onCreatureSpawn(CreatureSpawnEvent event) {} + + /** + * Called when an item is spawned into a world + * + * @param event Relevant event details + */ + public void onItemSpawn(ItemSpawnEvent event) {} + + /** + * Called when an entity combusts due to the sun. + *

+ * If an Entity Combust event is cancelled, the entity will not combust. + * + * @param event Relevant event details + */ + public void onEntityCombust(EntityCombustEvent event) {} + + /** + * Called when an entity is damaged + * + * @param event Relevant event details + */ + public void onEntityDamage(EntityDamageEvent event) {} + // Project Poseidon Start + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {} + public void onEntityDamageByBlock(EntityDamageByBlockEvent event) {} + // Project Poseidon End + + /** + * Called when an entity explodes + * + * @param event Relevant event details + */ + public void onEntityExplode(EntityExplodeEvent event) {} + + /** + * Called when an entity's fuse is lit + * + * @param event Relevant event details + */ + public void onExplosionPrime(ExplosionPrimeEvent event) {} + + /** + * Called when an entity dies + * + * @param event Relevant event details + */ + public void onEntityDeath(EntityDeathEvent event) {} + + /** + * Called when a creature targets another entity + * + * @param event Relevant event details + */ + public void onEntityTarget(EntityTargetEvent event) {} + + /** + * Called when an entity interacts with an object + * + * @param event Relevant event details + */ + public void onEntityInteract(EntityInteractEvent event) {} + + /** + * Called when an entity enters a portal + * + * @param event Relevant event details + */ + public void onEntityPortalEnter(EntityPortalEnterEvent event) {} + + /** + * Called when a painting is placed + * + * @param event Relevant event details + */ + public void onPaintingPlace(PaintingPlaceEvent event) {} + + /** + * Called when a painting is broken + * + * @param event Relevant event details + */ + public void onPaintingBreak(PaintingBreakEvent event) {} + + /** + * Called when a Pig is struck by lightning + * + * @param event Relevant event details + */ + public void onPigZap(PigZapEvent event) {} + + /** + * Called when a Creeper is struck by lightning. + *

+ * If a Creeper Power event is cancelled, the Creeper will not be powered. + * + * @param event Relevant event details + */ + public void onCreeperPower(CreeperPowerEvent event) {} + + /** + * Called when an entity is tamed (currently only applies to Wolves) + * + * @param event Relevant event details + */ + public void onEntityTame(EntityTameEvent event) {} + + /** + * Called when an entity regains health (currently only applies to Players) + * + * @param event Relevant event details + */ + public void onEntityRegainHealth(EntityRegainHealthEvent event) {} + + /** + * Called when a project hits an object + * + * @param event Relevant event details + */ + public void onProjectileHit(ProjectileHitEvent event) {} + + /** + * Called when an item despawns from a world + * + * @param event Relevant event details + */ + public void onItemDespawn(ItemDespawnEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java new file mode 100644 index 0000000..eced0cf --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java @@ -0,0 +1,27 @@ +package org.bukkit.event.entity; + + +import org.bukkit.Location; +import org.bukkit.entity.Entity; + +/** + * Stores data for entities standing inside a portal block + */ +public class EntityPortalEnterEvent extends EntityEvent { + + private Location location; + + public EntityPortalEnterEvent(Entity entity, Location location) { + super(Type.ENTITY_PORTAL_ENTER, entity); + this.location = location; + } + + /** + * Gets the portal block the entity is touching + * + * @return The portal block the entity is touching + */ + public Location getLocation() { + return location; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java b/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java new file mode 100644 index 0000000..5c6685b --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java @@ -0,0 +1,75 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +/** + * Stores data for health-regain events + */ +public class EntityRegainHealthEvent extends EntityEvent implements Cancellable { + + private boolean cancelled; + private int amount; + private RegainReason regainReason; + + public EntityRegainHealthEvent(Entity entity, int amount, RegainReason regainReason) { + super(Event.Type.ENTITY_REGAIN_HEALTH, entity); + this.amount = amount; + this.regainReason = regainReason; + } + + /** + * Gets the amount of regained health + * + * @return The amount of health regained + */ + public int getAmount() { + return amount; + } + + /** + * Sets the amount of regained health + * + * @param amount the amount of health the entity will regain + */ + public void setAmount(int amount) { + this.amount = amount; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + /** + * Gets the reason for why the entity is regaining health + * + * @return A RegainReason detailing the reason for the entity regaining health + */ + public RegainReason getRegainReason() { + return regainReason; + } + + /** + * An enum to specify the type of health regaining that is occurring + */ + public enum RegainReason { + + /** + * When a player regains health from regenerating due to Peaceful mode (spawn-monsters=false) + */ + REGEN, + /** + * When a player regains health from eating consumables + */ + EATING, + /** + * Any other reason not covered by the reasons above + */ + CUSTOM + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityTameEvent.java b/src/main/java/org/bukkit/event/entity/EntityTameEvent.java new file mode 100644 index 0000000..af7363d --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityTameEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.AnimalTamer; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Thrown when a LivingEntity is tamed + */ +public class EntityTameEvent extends EntityEvent implements Cancellable { + private boolean cancelled; + private AnimalTamer owner; + + public EntityTameEvent(Entity entity, AnimalTamer owner) { + super(Type.ENTITY_TAME, entity); + this.owner = owner; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + /** + * Gets the owning AnimalTamer + * + * @return the owning AnimalTamer + */ + public AnimalTamer getOwner() { + return owner; + } +} diff --git a/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java new file mode 100644 index 0000000..a198f62 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java @@ -0,0 +1,105 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when a creature targets another entity + */ +public class EntityTargetEvent extends EntityEvent implements Cancellable { + private boolean cancel; + private Entity target; + private TargetReason reason; + + public EntityTargetEvent(Entity entity, Entity target, TargetReason reason) { + super(Type.ENTITY_TARGET, entity); + this.target = target; + this.cancel = false; + this.reason = reason; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Returns the reason for the targeting + */ + public TargetReason getReason() { + return reason; + } + + /** + * Get the entity that this is target. + * This is possible to be null in the case that the event is called when + * the mob forgets its target. + */ + public Entity getTarget() { + return target; + } + + /** + * Set the entity that you want the mob to target instead. + * It is possible to be null, null will cause the entity to be + * target-less. + * + * This is different from cancelling the event. Cancelling the event + * will cause the entity to keep an original target, while setting to be + * null will cause the entity to be reset + * + * @param target The entity to target + */ + public void setTarget(Entity target) { + this.target = target; + } + + /** + * An enum to specify the reason for the targeting + */ + public enum TargetReason { + + /** + * When the entity's target has died, and so it no longer targets it + */ + TARGET_DIED, + /** + * When the entity doesn't have a target, so it attacks the nearest + * player + */ + CLOSEST_PLAYER, + /** + * When the target attacks the entity, so entity targets it + */ + TARGET_ATTACKED_ENTITY, + /** + * When the target attacks a fellow pig zombie, so the whole group + * will target him with this reason. + */ + PIG_ZOMBIE_TARGET, + /** + * When the target is forgotten for whatever reason. + * Currently only occurs in with spiders when there is a high brightness + */ + FORGOT_TARGET, + /** + * When the target attacks the owner of the entity, so the entity targets it. + */ + TARGET_ATTACKED_OWNER, + /** + * When the owner of the entity attacks the target attacks, so the entity targets it. + */ + OWNER_ATTACKED_TARGET, + /** + * When the entity has no target, so the entity randomly chooses one. + */ + RANDOM_TARGET, + /** + * For custom calls to the event + */ + CUSTOM + } +} diff --git a/src/main/java/org/bukkit/event/entity/ExplosionPrimeEvent.java b/src/main/java/org/bukkit/event/entity/ExplosionPrimeEvent.java new file mode 100644 index 0000000..2fd3853 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/ExplosionPrimeEvent.java @@ -0,0 +1,69 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Explosive; +import org.bukkit.event.Cancellable; + +/** + * Called when an entity has made a decision to explode. + */ +public class ExplosionPrimeEvent extends EntityEvent implements Cancellable { + private boolean cancel; + private float radius; + private boolean fire; + + public ExplosionPrimeEvent(Entity what, float radius, boolean fire) { + super(Type.EXPLOSION_PRIME, what); + this.cancel = false; + this.radius = radius; + this.fire = fire; + } + + public ExplosionPrimeEvent(Explosive explosive) { + this(explosive, explosive.getYield(), explosive.isIncendiary()); + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Gets the radius of the explosion + * + * @return returns the radius of the explosion + */ + public float getRadius() { + return radius; + } + + /** + * Sets the radius of the explosion + * + * @param radius the radius of the explosion + */ + public void setRadius(float radius) { + this.radius = radius; + } + + /** + * Gets whether this explosion will create fire or not + * + * @return true if this explosion will create fire + */ + public boolean getFire() { + return fire; + } + + /** + * Sets whether this explosion will create fire or not + * + * @param fire true if you want this explosion to create fire + */ + public void setFire(boolean fire) { + this.fire = fire; + } +} diff --git a/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java b/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java new file mode 100644 index 0000000..0c2aa39 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java @@ -0,0 +1,32 @@ +package org.bukkit.event.entity; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +public class ItemDespawnEvent extends EntityEvent implements Cancellable { + private boolean canceled; + private Location location; + + public ItemDespawnEvent(Entity spawnee, Location loc) { + super(Type.ITEM_DESPAWN, spawnee); + location = loc; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the location at which the item is despawning. + * + * @return The location at which the item is despawning + */ + public Location getLocation() { + return location; + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/event/entity/ItemSpawnEvent.java b/src/main/java/org/bukkit/event/entity/ItemSpawnEvent.java new file mode 100644 index 0000000..4128c09 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/ItemSpawnEvent.java @@ -0,0 +1,36 @@ +package org.bukkit.event.entity; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Called when an item is spawned into a world + */ +public class ItemSpawnEvent extends EntityEvent implements Cancellable { + + private Location location; + private boolean canceled; + + public ItemSpawnEvent(Entity spawnee, Location loc) { + super(Type.ITEM_SPAWN, spawnee); + this.location = loc; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the location at which the item is spawning. + * + * @return The location at which the item is spawning + */ + public Location getLocation() { + return location; + } +} diff --git a/src/main/java/org/bukkit/event/entity/PigZapEvent.java b/src/main/java/org/bukkit/event/entity/PigZapEvent.java new file mode 100644 index 0000000..7d191f2 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/PigZapEvent.java @@ -0,0 +1,49 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; + +/** + * Stores data for pigs being zapped + */ +public class PigZapEvent extends EntityEvent implements Cancellable { + + private boolean canceled; + private Entity pig; + private Entity pigzombie; + private Entity bolt; + + public PigZapEvent(Entity pig, Entity bolt, Entity pigzombie) { + super(Type.PIG_ZAP, pig); + this.pig = pig; + this.bolt = bolt; + this.pigzombie = pigzombie; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the bolt which is striking the pig. + * + * @return lightning entity + */ + public Entity getLightning() { + return bolt; + } + + /** + * Gets the zombie pig that will replace the pig, + * provided the event is not cancelled first. + * + * @return resulting entity + */ + public Entity getPigZombie() { + return pigzombie; + } +} diff --git a/src/main/java/org/bukkit/event/entity/ProjectileHitEvent.java b/src/main/java/org/bukkit/event/entity/ProjectileHitEvent.java new file mode 100644 index 0000000..b1e21f9 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/ProjectileHitEvent.java @@ -0,0 +1,14 @@ +package org.bukkit.event.entity; + +import org.bukkit.entity.Projectile; + +/** + * Called when a projectile hits an object + */ +public class ProjectileHitEvent extends EntityEvent { + + public ProjectileHitEvent(Projectile projectile) { + super(Type.PROJECTILE_HIT, projectile); + } + +} diff --git a/src/main/java/org/bukkit/event/inventory/ChestOpenedEvent.java b/src/main/java/org/bukkit/event/inventory/ChestOpenedEvent.java new file mode 100644 index 0000000..1ac1496 --- /dev/null +++ b/src/main/java/org/bukkit/event/inventory/ChestOpenedEvent.java @@ -0,0 +1,34 @@ +package org.bukkit.event.inventory; + +import net.minecraft.server.ItemStack; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class ChestOpenedEvent extends Event implements Cancellable { + private boolean cancelled; + private Player player; + private ItemStack[] contents; + + public ChestOpenedEvent(Player player, ItemStack[] contents) { + super(Type.CHEST_OPENED); + this.player = player; + this.contents = contents; + } + + public Player getPlayer() { + return player; + } + + public ItemStack[] getContents() { + return contents; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java new file mode 100644 index 0000000..d455864 --- /dev/null +++ b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java @@ -0,0 +1,88 @@ +package org.bukkit.event.inventory; + +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; +/** + * Called when an ItemStack is successfully burned as fuel in a furnace. + */ +public class FurnaceBurnEvent extends Event implements Cancellable { + private Block furnace; + private ItemStack fuel; + private int burnTime; + private boolean cancelled; + private boolean burning; + + public FurnaceBurnEvent(Block furnace, ItemStack fuel, int burnTime) { + super(Type.FURNACE_BURN); + + this.furnace = furnace; + this.fuel = fuel; + this.burnTime = burnTime; + this.cancelled = false; + this.burning = true; + } + + /** + * Gets the block for the furnace involved in this event + * + * @return the block of the furnace + */ + public Block getFurnace() { + return furnace; + } + + /** + * Gets the fuel ItemStack for this event + * + * @return the fuel ItemStack + */ + public ItemStack getFuel() { + return fuel; + } + + /** + * Gets the burn time for this fuel + * + * @return the burn time for this fuel + */ + public int getBurnTime() { + return burnTime; + } + + /** + * Sets the burn time for this fuel + * + * @param burnTime the burn time for this fuel + */ + public void setBurnTime(int burnTime) { + this.burnTime = burnTime; + } + + /** + * Gets whether the furnace's fuel is burning or not. + * + * @return whether the furnace's fuel is burning or not. + */ + public boolean isBurning() { + return this.burning; + } + + /** + * Sets whether the furnace's fuel is burning or not. + * + * @param burning true if the furnace's fuel is burning + */ + public void setBurning(boolean burning) { + this.burning = burning; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java new file mode 100644 index 0000000..4b42b46 --- /dev/null +++ b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java @@ -0,0 +1,69 @@ +package org.bukkit.event.inventory; + +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; + +/** + * Called when an ItemStack is successfully smelted in a furnace. + */ +public class FurnaceSmeltEvent extends Event implements Cancellable{ + private Block furnace; + private ItemStack source; + private ItemStack result; + private boolean cancelled; + + public FurnaceSmeltEvent(Block furnace, ItemStack source, ItemStack result) { + super(Type.FURNACE_SMELT); + + this.furnace = furnace; + this.source = source; + this.result = result; + this.cancelled = false; + } + + /** + * Gets the block for the furnace involved in this event + * + * @return the block of the furnace + */ + public Block getFurnace() { + return furnace; + } + + /** + * Gets the smelted ItemStack for this event + * + * @return smelting source ItemStack + */ + public ItemStack getSource() { + return source; + } + + /** + * Gets the resultant ItemStack for this event + * + * @return smelting result ItemStack + */ + public ItemStack getResult() { + return result; + } + + /** + * Sets the resultant ItemStack for this event + * + * @param result new result ItemStack + */ + public void setResult(ItemStack result) { + this.result = result; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/inventory/InventoryListener.java b/src/main/java/org/bukkit/event/inventory/InventoryListener.java new file mode 100644 index 0000000..16a042b --- /dev/null +++ b/src/main/java/org/bukkit/event/inventory/InventoryListener.java @@ -0,0 +1,28 @@ +package org.bukkit.event.inventory; + +import org.bukkit.event.Listener; +/** +* Handles all events thrown in relation to Blocks + */ +public class InventoryListener implements Listener { + public InventoryListener() {} + + /** + * Called when an ItemStack is successfully smelted in a furnace. + * + * @param event Relevant event details + */ + public void onFurnaceSmelt(FurnaceSmeltEvent event) {} + + /** + * Called when an ItemStack is successfully burned as fuel in a furnace. + * + * @param event Relevant event details + */ + public void onFurnaceBurn(FurnaceBurnEvent event) {} + + /** + * @author moderator_man + */ + public void onInventoryTransaction(InventoryTransactionEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/inventory/InventoryTransactionEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryTransactionEvent.java new file mode 100644 index 0000000..4d5bb01 --- /dev/null +++ b/src/main/java/org/bukkit/event/inventory/InventoryTransactionEvent.java @@ -0,0 +1,43 @@ +package org.bukkit.event.inventory; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class InventoryTransactionEvent extends Event implements Cancellable +{ + private static final long serialVersionUID = 1L; + + private boolean cancelled; + private InventoryTransactionType transactionType; + private Inventory inventory; + private ItemStack stack; + + public InventoryTransactionEvent(InventoryTransactionType transactionType, Inventory inventory, ItemStack stack) + { + super(Type.INVENTORY_TRANSACTION); + + this.transactionType = transactionType; + this.inventory = inventory; + this.stack = stack; + } + + public InventoryTransactionType getTransactionType() + { + return transactionType; + } + + public Inventory getInventory() + { + return inventory; + } + + public ItemStack getStack() + { + return stack; + } + + public boolean isCancelled() { return cancelled; } + public void setCancelled(boolean cancel) { this.cancelled = cancel; } +} diff --git a/src/main/java/org/bukkit/event/inventory/InventoryTransactionType.java b/src/main/java/org/bukkit/event/inventory/InventoryTransactionType.java new file mode 100644 index 0000000..4ff228e --- /dev/null +++ b/src/main/java/org/bukkit/event/inventory/InventoryTransactionType.java @@ -0,0 +1,7 @@ +package org.bukkit.event.inventory; + +public enum InventoryTransactionType +{ + ITEM_ADDED, + ITEM_REMOVED +} diff --git a/src/main/java/org/bukkit/event/packet/PacketListener.java b/src/main/java/org/bukkit/event/packet/PacketListener.java new file mode 100644 index 0000000..5b90cb6 --- /dev/null +++ b/src/main/java/org/bukkit/event/packet/PacketListener.java @@ -0,0 +1,11 @@ +package org.bukkit.event.packet; + +import org.bukkit.event.Listener; + +/** + * @author moderator_man + */ +public class PacketListener implements Listener +{ + public void onPacketReceived(PacketReceivedEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/packet/PacketReceivedEvent.java b/src/main/java/org/bukkit/event/packet/PacketReceivedEvent.java new file mode 100644 index 0000000..b68a6a2 --- /dev/null +++ b/src/main/java/org/bukkit/event/packet/PacketReceivedEvent.java @@ -0,0 +1,48 @@ +package org.bukkit.event.packet; + +import net.minecraft.server.Packet; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; + +/** + * @author moderator_man + */ +public class PacketReceivedEvent extends Event +{ + private static final long serialVersionUID = 1L; + + private Player player; + private Packet packet; + private boolean cancelled; + + public PacketReceivedEvent(Player player, Packet packet) + { + super(Type.PACKET_RECEIVED); + + this.player = player; + this.packet = packet; + } + + /** + * THIS CAN RETURN NULL + */ + public Player getPlayer() + { + return player; + } + + public Packet getPacket() + { + return packet; + } + + public boolean isCancelled() + { + return cancelled; + } + + public void setCancelled(boolean cancelled) + { + this.cancelled = cancelled; + } +} diff --git a/src/main/java/org/bukkit/event/painting/PaintingBreakByEntityEvent.java b/src/main/java/org/bukkit/event/painting/PaintingBreakByEntityEvent.java new file mode 100644 index 0000000..2826d8f --- /dev/null +++ b/src/main/java/org/bukkit/event/painting/PaintingBreakByEntityEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.painting; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Painting; + +/** + * Triggered when a painting is removed by an entity + */ +public class PaintingBreakByEntityEvent extends PaintingBreakEvent { + private Entity remover; + + public PaintingBreakByEntityEvent(final Painting painting, final Entity remover) { + super(painting, RemoveCause.ENTITY); + this.remover = remover; + } + + /** + * Gets the entity that removed the painting + * + * @return the entity that removed the painting. + */ + public Entity getRemover() { + return remover; + } +} diff --git a/src/main/java/org/bukkit/event/painting/PaintingBreakByWorldEvent.java b/src/main/java/org/bukkit/event/painting/PaintingBreakByWorldEvent.java new file mode 100644 index 0000000..483988e --- /dev/null +++ b/src/main/java/org/bukkit/event/painting/PaintingBreakByWorldEvent.java @@ -0,0 +1,12 @@ +package org.bukkit.event.painting; + +import org.bukkit.entity.Painting; + +/** + * Triggered when a painting is removed by the world (water flowing over it, block damaged behind it) + */ +public class PaintingBreakByWorldEvent extends PaintingBreakEvent { + public PaintingBreakByWorldEvent(final Painting painting) { + super(painting, RemoveCause.WORLD); + } +} diff --git a/src/main/java/org/bukkit/event/painting/PaintingBreakEvent.java b/src/main/java/org/bukkit/event/painting/PaintingBreakEvent.java new file mode 100644 index 0000000..154c1d2 --- /dev/null +++ b/src/main/java/org/bukkit/event/painting/PaintingBreakEvent.java @@ -0,0 +1,50 @@ +package org.bukkit.event.painting; + +import org.bukkit.entity.Painting; +import org.bukkit.event.Cancellable; + +/** + * Triggered when a painting is removed + */ +public class PaintingBreakEvent extends PaintingEvent implements Cancellable { + + private boolean cancelled; + private RemoveCause cause; + + public PaintingBreakEvent(final Painting painting, RemoveCause cause) { + super(Type.PAINTING_BREAK, painting); + this.cause = cause; + } + + /** + * Gets the cause for the painting's removal + * + * @return the RemoveCause for the painting's removal + */ + public RemoveCause getCause() { + return cause; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + /** + * An enum to specify the cause of the removal + */ + public enum RemoveCause { + /** + * Removed by an entity + */ + ENTITY, + /** + * Removed by the world - block the painting is on is destroyed, water flowing over etc + */ + WORLD + + } +} diff --git a/src/main/java/org/bukkit/event/painting/PaintingEvent.java b/src/main/java/org/bukkit/event/painting/PaintingEvent.java new file mode 100644 index 0000000..bf576c6 --- /dev/null +++ b/src/main/java/org/bukkit/event/painting/PaintingEvent.java @@ -0,0 +1,26 @@ +package org.bukkit.event.painting; + +import org.bukkit.entity.Painting; +import org.bukkit.event.Event; + +/** + * Represents a painting-related event. + */ +public class PaintingEvent extends Event { + + protected Painting painting; + + protected PaintingEvent(final Type type, final Painting painting) { + super(type); + this.painting = painting; + } + + /** + * Gets the painting involved in this event. + * + * @return the painting + */ + public Painting getPainting() { + return painting; + } +} diff --git a/src/main/java/org/bukkit/event/painting/PaintingPlaceEvent.java b/src/main/java/org/bukkit/event/painting/PaintingPlaceEvent.java new file mode 100644 index 0000000..c56ec23 --- /dev/null +++ b/src/main/java/org/bukkit/event/painting/PaintingPlaceEvent.java @@ -0,0 +1,62 @@ +package org.bukkit.event.painting; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Painting; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +/** + * Triggered when a painting is created in the world + */ +public class PaintingPlaceEvent extends PaintingEvent implements Cancellable { + + private boolean cancelled; + + private Player player; + private Block block; + private BlockFace blockFace; + + public PaintingPlaceEvent(final Painting painting, final Player player, Block block, BlockFace blockFace) { + super(Event.Type.PAINTING_PLACE, painting); + this.player = player; + this.block = block; + this.blockFace = blockFace; + } + + /** + * Returns the player placing the painting + * + * @return Entity returns the player placing the painting + */ + public Player getPlayer() { + return player; + } + + /** + * Returns the block that the painting was placed on + * + * @return Block returns the block painting placed on + */ + public Block getBlock() { + return block; + } + + /** + * Returns the face of the block that the painting was placed on + * + * @return BlockFace returns the face of the block the painting was placed on + */ + public BlockFace getBlockFace() { + return blockFace; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java b/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java new file mode 100644 index 0000000..93a3f75 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java @@ -0,0 +1,42 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Represents a player animation event + */ +public class PlayerAnimationEvent extends PlayerEvent implements Cancellable { + + private PlayerAnimationType animationType; + private boolean isCancelled = false; + + /** + * Construct a new PlayerAnimation event + * + * @param player The player instance + */ + public PlayerAnimationEvent(final Player player) { + super(Type.PLAYER_ANIMATION, player); + + // Only supported animation type for now: + animationType = PlayerAnimationType.ARM_SWING; + } + + /** + * Get the type of this animation event + * + * @return the animation type + */ + public PlayerAnimationType getAnimationType() { + return animationType; + } + + public boolean isCancelled() { + return this.isCancelled; + } + + public void setCancelled(boolean cancel) { + this.isCancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerAnimationType.java b/src/main/java/org/bukkit/event/player/PlayerAnimationType.java new file mode 100644 index 0000000..ea4bf26 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerAnimationType.java @@ -0,0 +1,8 @@ +package org.bukkit.event.player; + +/** + * Different types of player animations + */ +public enum PlayerAnimationType { + ARM_SWING +} diff --git a/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java b/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java new file mode 100644 index 0000000..0ba13eb --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java @@ -0,0 +1,36 @@ +package org.bukkit.event.player; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * This event is fired when the player is almost about to enter the bed. + */ +public class PlayerBedEnterEvent extends PlayerEvent implements Cancellable { + + private boolean cancel = false; + private Block bed; + + public PlayerBedEnterEvent(Player who, Block bed) { + super(Type.PLAYER_BED_ENTER, who); + this.bed = bed; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Returns the bed block involved in this event. + * + * @return the bed block involved in this event + */ + public Block getBed() { + return bed; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java b/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java new file mode 100644 index 0000000..8e91f2a --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java @@ -0,0 +1,26 @@ +package org.bukkit.event.player; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +/** + * This event is fired when the player is leaving a bed. + */ +public class PlayerBedLeaveEvent extends PlayerEvent { + + private Block bed; + + public PlayerBedLeaveEvent(Player who, Block bed) { + super(Type.PLAYER_BED_LEAVE, who); + this.bed = bed; + } + + /** + * Returns the bed block involved in this event. + * + * @return the bed block involved in this event + */ + public Block getBed() { + return bed; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerBucketEmptyEvent.java b/src/main/java/org/bukkit/event/player/PlayerBucketEmptyEvent.java new file mode 100644 index 0000000..b7ddc92 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerBucketEmptyEvent.java @@ -0,0 +1,17 @@ +package org.bukkit.event.player; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +/** + * Called when a player empties a bucket + */ +public class PlayerBucketEmptyEvent extends PlayerBucketEvent { + public PlayerBucketEmptyEvent(Player who, Block blockClicked, BlockFace blockFace, Material bucket, ItemStack itemInHand) { + super(Type.PLAYER_BUCKET_EMPTY, who, blockClicked, blockFace, bucket, itemInHand); + + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerBucketEvent.java b/src/main/java/org/bukkit/event/player/PlayerBucketEvent.java new file mode 100644 index 0000000..ec45668 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerBucketEvent.java @@ -0,0 +1,79 @@ +package org.bukkit.event.player; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.inventory.ItemStack; + +public abstract class PlayerBucketEvent extends PlayerEvent implements Cancellable { + + private ItemStack itemStack; + private boolean cancelled = false; + private Block blockClicked; + private BlockFace blockFace; + private Material bucket; + + public PlayerBucketEvent(Type type, Player who, Block blockClicked, BlockFace blockFace, Material bucket, ItemStack itemInHand) { + super(type, who); + this.blockClicked = blockClicked; + this.blockFace = blockFace; + this.itemStack = itemInHand; + this.bucket = bucket; + } + + /** + * Returns the bucket used in this event + * + * @return the used bucket + */ + public Material getBucket() { + return bucket; + } + + /** + * Get the resulting item in hand after the bucket event + * + * @return Itemstack hold in hand after the event. + */ + public ItemStack getItemStack() { + return itemStack; + } + + /** + * Set the item in hand after the event + * + * @param itemStack the new held itemstack after the bucket event. + */ + public void setItemStack(ItemStack itemStack) { + this.itemStack = itemStack; + } + + + /** + * Return the block clicked + * + * @return the blicked block + */ + public Block getBlockClicked() { + return blockClicked; + } + + /** + * Get the face on the clicked block + * + * @return the clicked face + */ + public BlockFace getBlockFace() { + return blockFace; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/event/player/PlayerBucketFillEvent.java b/src/main/java/org/bukkit/event/player/PlayerBucketFillEvent.java new file mode 100644 index 0000000..5f1ff0d --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerBucketFillEvent.java @@ -0,0 +1,16 @@ +package org.bukkit.event.player; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +/** + * Called when a player fills a bucket + */ +public class PlayerBucketFillEvent extends PlayerBucketEvent { + public PlayerBucketFillEvent(Player who, Block blockClicked, BlockFace blockFace, Material bucket, ItemStack itemInHand) { + super(Type.PLAYER_BUCKET_FILL, who, blockClicked, blockFace, bucket, itemInHand); + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerChangedWorldEvent.java b/src/main/java/org/bukkit/event/player/PlayerChangedWorldEvent.java new file mode 100644 index 0000000..5876fe6 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerChangedWorldEvent.java @@ -0,0 +1,19 @@ + +package org.bukkit.event.player; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +public class PlayerChangedWorldEvent extends PlayerEvent { + + private final World from; + + public PlayerChangedWorldEvent(Player player, World from) { + super(Type.PLAYER_CHANGED_WORLD, player); + this.from = from; + } + + public World getFrom() { + return from; + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java new file mode 100644 index 0000000..85bee89 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java @@ -0,0 +1,99 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Holds information for player chat and commands + */ +public class PlayerChatEvent extends PlayerEvent implements Cancellable { + private boolean cancel = false; + private String message; + private String format = "<%1$s> %2$s"; + private final Set recipients; + + public PlayerChatEvent(final Player player, final String message) { + this(Type.PLAYER_CHAT, player, message); + } + + protected PlayerChatEvent(final Type type, final Player player, final String message) { + super(type, player); + recipients = new HashSet(Arrays.asList(player.getServer().getOnlinePlayers())); + this.message = message; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Gets the message that the player is attempting to send + * + * @return Message the player is attempting to send + */ + public String getMessage() { + return message; + } + + /** + * Sets the message that the player will send + * + * @param message New message that the player will send + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * Sets the player that this message will display as, or command will be + * executed as + * + * @param player New player which this event will execute as + */ + public void setPlayer(final Player player) { + this.player = player; + } + + /** + * Gets the format to use to display this chat message + * + * @return String.Format compatible format string + */ + public String getFormat() { + return format; + } + + /** + * Sets the format to use to display this chat message + * + * @param format String.Format compatible format string + */ + public void setFormat(final String format) { + // Oh for a better way to do this! + try { + String.format(format, player, message); + } catch (RuntimeException ex) { + ex.fillInStackTrace(); + throw ex; + } + + this.format = format; + } + + /** + * Gets a set of recipients that this chat message will be displayed to + * + * @return All Players who will see this chat message + */ + public Set getRecipients() { + return recipients; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java b/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java new file mode 100644 index 0000000..2979edb --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java @@ -0,0 +1,13 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; + +/** + * Called early in the command handling process. This event is only + * for very exceptional cases and you should not normally use it. + */ +public class PlayerCommandPreprocessEvent extends PlayerChatEvent { + public PlayerCommandPreprocessEvent(final Player player, final String message) { + super(Type.PLAYER_COMMAND_PREPROCESS, player, message); + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerConnectionInitializationEvent.java b/src/main/java/org/bukkit/event/player/PlayerConnectionInitializationEvent.java new file mode 100644 index 0000000..71b910e --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerConnectionInitializationEvent.java @@ -0,0 +1,44 @@ +package org.bukkit.event.player; + +import com.projectposeidon.johnymuffin.LoginProcessHandler; +import org.bukkit.event.Event; + +import java.net.InetAddress; + +public class PlayerConnectionInitializationEvent extends Event { + private String username; + private InetAddress ipAddress; + private LoginProcessHandler loginProcessHandler; + private boolean connecting = true; + + + public PlayerConnectionInitializationEvent(String username, InetAddress ipAddress, LoginProcessHandler loginProcessHandler) { + super(Type.Player_Connection_Initialization); + this.username = username; + this.ipAddress = ipAddress; + this.loginProcessHandler = loginProcessHandler; + } + + public void disconnectPlayer(String kickReason) { + loginProcessHandler.cancelLoginProcess(kickReason); + } + + /** + * Gets the player's name. + * + * @return the player's name + */ + public String getName() { + return username; + } + + /** + * Gets the player IP address. + * + * @return + */ + public InetAddress getAddress() { + return ipAddress; + } + +} diff --git a/src/main/java/org/bukkit/event/player/PlayerDropItemEvent.java b/src/main/java/org/bukkit/event/player/PlayerDropItemEvent.java new file mode 100644 index 0000000..926d09d --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerDropItemEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Thrown when a player drops an item from their inventory + */ +public class PlayerDropItemEvent extends PlayerEvent implements Cancellable { + private final Item drop; + private boolean cancel = false; + + public PlayerDropItemEvent(final Player player, final Item drop) { + super(Type.PLAYER_DROP_ITEM, player); + this.drop = drop; + } + + /** + * Gets the ItemDrop created by the player + * + * @return ItemDrop created by the player + */ + public Item getItemDrop() { + return drop; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerEggThrowEvent.java b/src/main/java/org/bukkit/event/player/PlayerEggThrowEvent.java new file mode 100644 index 0000000..6b2a8ea --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerEggThrowEvent.java @@ -0,0 +1,96 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.Egg; +import org.bukkit.entity.Player; + +/** + * Called when a player throws an egg and it might hatch + */ +public class PlayerEggThrowEvent extends PlayerEvent { + private Egg egg; + private boolean hatching; + private CreatureType hatchType; + private byte numHatches; + + public PlayerEggThrowEvent(Player player, Egg egg, boolean hatching, byte numHatches, CreatureType hatchType) { + super(Type.PLAYER_EGG_THROW, player); + this.egg = egg; + this.hatching = hatching; + this.numHatches = numHatches; + this.hatchType = hatchType; + } + + /** + * Gets the egg involved in this event. + * + * @return the egg involved in this event + */ + public Egg getEgg() { + return egg; + } + + /** + * Gets whether the egg is hatching or not. Will be what the server + * would've done without interaction. + * + * @return boolean Whether the egg is going to hatch or not + */ + public boolean isHatching() { + return hatching; + } + + /** + * Sets whether the egg will hatch or not. + * + * @param hatching true if you want the egg to hatch + * false if you want it not to + */ + public void setHatching(boolean hatching) { + this.hatching = hatching; + } + + /** + * Get the type of the mob being hatched (CreatureType.CHICKEN by default) + * + * @return The type of the mob being hatched by the egg + */ + public CreatureType getHatchType() { + return CreatureType.fromName(hatchType.getName()); + } + + /** + * Change the type of mob being hatched by the egg + * + * @param hatchType The type of the mob being hatched by the egg + */ + public void setHatchType(CreatureType hatchType) { + this.hatchType = hatchType; + } + + /** + * Get the number of mob hatches from the egg. By default the number + * will be he number the server would've done + * + * 7/8 chance of being 0 + * 31/256 ~= 1/8 chance to be 1 + * 1/256 chance to be 4 + * + * @return The number of mobs going to be hatched by the egg + */ + public byte getNumHatches() { + return numHatches; + } + + /** + * Change the number of mobs coming out of the hatched egg + * + * The boolean hatching will override this number. + * Ie. If hatching = false, this number will not matter + * + * @param numHatches The number of mobs coming out of the egg + */ + public void setNumHatches(byte numHatches) { + this.numHatches = numHatches; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerEvent.java b/src/main/java/org/bukkit/event/player/PlayerEvent.java new file mode 100644 index 0000000..f426bc1 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; + +/** + * Represents a player related event + */ +public class PlayerEvent extends Event { + protected Player player; + + public PlayerEvent(final Event.Type type, final Player who) { + super(type); + player = who; + } + + /** + * Returns the player involved in this event + * + * @return Player who is involved in this event + */ + public final Player getPlayer() { + return player; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerFishEvent.java b/src/main/java/org/bukkit/event/player/PlayerFishEvent.java new file mode 100644 index 0000000..7be0a5d --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerFishEvent.java @@ -0,0 +1,73 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Thrown when a player is fishing + */ +public class PlayerFishEvent extends PlayerEvent implements Cancellable { + private final Entity entity; + private boolean cancel = false; + private State state; + + public PlayerFishEvent(final Player player, final Entity entity, State state) { + super(Type.PLAYER_FISH, player); + this.entity = entity; + this.state = state; + } + + /** + * Gets the entity caught by the player + * + * @return Entity caught by the player, null if fishing, bobber has gotten stuck in the ground or nothing has been caught + */ + public Entity getCaught() { + return entity; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Gets the state of the fishing + * + * @return A State detailing the state of the fishing + */ + public State getState() { + return state; + } + + /** + * An enum to specify the state of the fishing + */ + public enum State { + + /** + * When a player is fishing + */ + FISHING, + /** + * When a player has successfully caught a fish + */ + CAUGHT_FISH, + /** + * When a player has successfully caught an entity + */ + CAUGHT_ENTITY, + /** + * When a bobber is stuck in the grund + */ + IN_GROUND, + /** + * When a player fails to catch anything while fishing usually due to poor aiming or timing + */ + FAILED_ATTEMPT, + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerInteractEntityEvent.java b/src/main/java/org/bukkit/event/player/PlayerInteractEntityEvent.java new file mode 100644 index 0000000..07663db --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerInteractEntityEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Represents an event that is called when a player right clicks an entity. + */ +public class PlayerInteractEntityEvent extends PlayerEvent implements Cancellable { + protected Entity clickedEntity; + boolean cancelled = false; + + public PlayerInteractEntityEvent(Player who, Entity clickedEntity) { + super(Type.PLAYER_INTERACT_ENTITY, who); + this.clickedEntity = clickedEntity; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + /** + * Gets the entity that was rightclicked by the player. + * + * @return entity right clicked by player + */ + public Entity getRightClicked() { + return this.clickedEntity; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java b/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java new file mode 100644 index 0000000..b0b440b --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java @@ -0,0 +1,173 @@ +package org.bukkit.event.player; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.block.Action; +import org.bukkit.inventory.ItemStack; + +/** + * Called when a player interacts with an object or air. + */ +public class PlayerInteractEvent extends PlayerEvent implements Cancellable { + protected ItemStack item; + protected Action action; + protected Block blockClicked; + protected BlockFace blockFace; + + private Result useClickedBlock; + private Result useItemInHand; + + public PlayerInteractEvent(Player who, Action action, ItemStack item, Block clickedBlock, BlockFace clickedFace) { + super(Type.PLAYER_INTERACT, who); + this.action = action; + this.item = item; + this.blockClicked = clickedBlock; + this.blockFace = clickedFace; + + useItemInHand = Result.DEFAULT; + useClickedBlock = clickedBlock == null ? Result.DENY : Result.ALLOW; + } + + /** + * Returns the action type + * + * @return Action returns the type of interaction + */ + public Action getAction() { + return action; + } + + /** + * Gets the cancellation state of this event. Set to true if you + * want to prevent buckets from placing water and so forth + * + * @return boolean cancellation state + */ + public boolean isCancelled() { + return useInteractedBlock() == Result.DENY; + } + + /** + * Sets the cancellation state of this event. A canceled event will not + * be executed in the server, but will still pass to other plugins + * + * Canceling this event will prevent use of food (player won't lose the + * food item), prevent bows/snowballs/eggs from firing, etc. (player won't + * lose the ammo) + * + * @param cancel true if you wish to cancel this event + */ + public void setCancelled(boolean cancel) { + setUseInteractedBlock(cancel ? Result.DENY : useInteractedBlock() == Result.DENY ? Result.DEFAULT : useInteractedBlock()); + setUseItemInHand(cancel ? Result.DENY : useItemInHand() == Result.DENY ? Result.DEFAULT : useItemInHand()); + } + + /** + * Returns the item in hand represented by this event + * + * @return ItemStack the item used + */ + public ItemStack getItem() { + return this.item; + } + + /** + * Convenience method. Returns the material of the item represented by this + * event + * + * @return Material the material of the item used + */ + public Material getMaterial() { + if (!hasItem()) { + return Material.AIR; + } + + return item.getType(); + } + + /** + * Check if this event involved a block + * + * @return boolean true if it did + */ + public boolean hasBlock() { + return this.blockClicked != null; + } + + /** + * Check if this event involved an item + * + * @return boolean true if it did + */ + public boolean hasItem() { + return this.item != null; + } + + /** + * Convenience method to inform the user whether this was a block placement + * event. + * + * @return boolean true if the item in hand was a block + */ + public boolean isBlockInHand() { + if (!hasItem()) { + return false; + } + + return item.getType().isBlock(); + } + + /** + * Returns the clicked block + * + * @return Block returns the block clicked with this item. + */ + public Block getClickedBlock() { + return blockClicked; + } + + /** + * Returns the face of the block that was clicked + * + * @return BlockFace returns the face of the block that was clicked + */ + public BlockFace getBlockFace() { + return blockFace; + } + + /** + * This controls the action to take with the block (if any) that was clicked on + * This event gets processed for all blocks, but most don't have a default action + * @return the action to take with the interacted block + */ + public Result useInteractedBlock() { + return useClickedBlock; + } + + /** + * @param useInteractedBlock the action to take with the interacted block + */ + public void setUseInteractedBlock(Result useInteractedBlock) { + this.useClickedBlock = useInteractedBlock; + } + + /** + * This controls the action to take with the item the player is holding + * This includes both blocks and items (such as flint and steel or records) + * When this is set to default, it will be allowed if no action is taken on the interacted block + * @return the action to take with the item in hand + */ + public Result useItemInHand() { + return useItemInHand; + } + + /** + * @param useItemInHand the action to take with the item in hand + */ + public void setUseItemInHand(Result useItemInHand) { + this.useItemInHand = useItemInHand; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerInventoryEvent.java b/src/main/java/org/bukkit/event/player/PlayerInventoryEvent.java new file mode 100644 index 0000000..f75e2b5 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerInventoryEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; + +/** + * Represents a player related inventory event + */ +public class PlayerInventoryEvent extends PlayerEvent { + protected Inventory inventory; + + public PlayerInventoryEvent(final Player player, final Inventory inventory) { + super(Type.PLAYER_INVENTORY, player); + this.inventory = inventory; + } + + /** + * Gets the Inventory involved in this event + * + * @return Inventory + */ + public Inventory getInventory() { + return inventory; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerItemDamageEvent.java b/src/main/java/org/bukkit/event/player/PlayerItemDamageEvent.java new file mode 100644 index 0000000..7d800bd --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerItemDamageEvent.java @@ -0,0 +1,54 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.inventory.ItemStack; + +/** + * Called when an item used by the player takes durability damage as a result of + * being used. + */ +public class PlayerItemDamageEvent extends PlayerEvent implements Cancellable { + + private final ItemStack item; + private int damage; + private boolean cancelled = false; + + public PlayerItemDamageEvent(Player player, ItemStack what, int damage) { + super(Type.PLAYER_ITEM_DAMAGE, player); + this.item = what; + this.damage = damage; + } + + /** + * Gets the item being damaged. + * + * @return the item + */ + public ItemStack getItem() { + return item; + } + + /** + * Gets the amount of durability damage this item will be taking. + * + * @return durability change + */ + public int getDamage() { + return damage; + } + + public void setDamage(int damage) { + this.damage = damage; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerItemHeldEvent.java b/src/main/java/org/bukkit/event/player/PlayerItemHeldEvent.java new file mode 100644 index 0000000..3f5adba --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerItemHeldEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; + +/** + * Fired when a player changes their currently held item + */ +public class PlayerItemHeldEvent extends PlayerEvent { + private int previous; + private int current; + + public PlayerItemHeldEvent(final Player player, final int previous, final int current) { + super(Type.PLAYER_ITEM_HELD, player); + this.previous = previous; + this.current = current; + } + + /** + * Gets the previous held slot index + * + * @return Previous slot index + */ + public int getPreviousSlot() { + return previous; + } + + /** + * Gets the new held slot index + * + * @return New slot index + */ + public int getNewSlot() { + return current; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java new file mode 100644 index 0000000..179abc2 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java @@ -0,0 +1,33 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; + +/** + * Called when a player joins a server + */ +public class PlayerJoinEvent extends PlayerEvent { + private String joinMessage; + + public PlayerJoinEvent(Player playerJoined, String joinMessage) { + super(Type.PLAYER_JOIN, playerJoined); + this.joinMessage = joinMessage; + } + + /** + * Gets the join message to send to all online players + * + * @return string join message + */ + public String getJoinMessage() { + return joinMessage; + } + + /** + * Sets the join message to send to all online players + * + * @param joinMessage join message + */ + public void setJoinMessage(String joinMessage) { + this.joinMessage = joinMessage; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java new file mode 100644 index 0000000..927594f --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java @@ -0,0 +1,64 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Called when a player gets kicked from the server + */ +public class PlayerKickEvent extends PlayerEvent implements Cancellable { + private String leaveMessage; + private String kickReason; + private Boolean cancel; + + public PlayerKickEvent(Player playerKicked, String kickReason, String leaveMessage) { + super(Type.PLAYER_KICK, playerKicked); + this.kickReason = kickReason; + this.leaveMessage = leaveMessage; + this.cancel = false; + } + + /** + * Gets the reason why the player is getting kicked + * + * @return string kick reason + */ + public String getReason() { + return kickReason; + } + + /** + * Gets the leave message send to all online players + * + * @return string kick reason + */ + public String getLeaveMessage() { + return leaveMessage; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Sets the reason why the player is getting kicked + * + * @param kickReason kick reason + */ + public void setReason(String kickReason) { + this.kickReason = kickReason; + } + + /** + * Sets the leave message send to all online players + * + * @param leaveMessage leave message + */ + public void setLeaveMessage(String leaveMessage) { + this.leaveMessage = leaveMessage; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerListener.java b/src/main/java/org/bukkit/event/player/PlayerListener.java new file mode 100644 index 0000000..b7fce6c --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerListener.java @@ -0,0 +1,208 @@ +package org.bukkit.event.player; + +import org.bukkit.event.Listener; + +/** + * Handles all events thrown in relation to a Player + */ +public class PlayerListener implements Listener { + public PlayerListener() {} + + /** + * Called when a player joins a server + * + * @param event Relevant event details + */ + public void onPlayerJoin(PlayerJoinEvent event) {} + + /** + * Called when a player leaves a server + * + * @param event Relevant event details + */ + public void onPlayerQuit(PlayerQuitEvent event) {} + + /** + * Called after a player changes to a new world + * + * @param event Relevant event details + */ + public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {} + + /** + * Called when a player gets kicked from the server + * + * @param event Relevant event details + */ + public void onPlayerKick(PlayerKickEvent event) {} + + /** + * Called when a player sends a chat message + * + * @param event Relevant event details + */ + public void onPlayerChat(PlayerChatEvent event) {} + + /** + * Called early in the command handling process. This event is only + * for very exceptional cases and you should not normally use it. + * + * @param event Relevant event details + */ + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {} + + /** + * Called when a player attempts to move location in a world + * + * @param event Relevant event details + */ + public void onPlayerMove(PlayerMoveEvent event) {} + + /** + * Called before a player gets a velocity vector sent, which will "push" + * the player in a certain direction + * + * @param event Relevant event details + */ + public void onPlayerVelocity(PlayerVelocityEvent event) {} + + /** + * Called when a player attempts to teleport to a new location in a world + * + * @param event Relevant event details + */ + public void onPlayerTeleport(PlayerTeleportEvent event) {} + + /** + * Called when a player respawns + * + * @param event Relevant event details + */ + public void onPlayerRespawn(PlayerRespawnEvent event) {} + + /** + * Called when a player interacts with an object or air. + * + * @param event Relevant event details + */ + public void onPlayerInteract(PlayerInteractEvent event) {} + + /** + * Called when a player right clicks an entity. + * + * @param event Relevant event details + */ + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {} + + /** + * Called when a player attempts to log in to the server + * + * @param event Relevant event details + */ + public void onPlayerLogin(PlayerLoginEvent event) {} + + /** + * Called when a player has just been authenticated + * + * @param event Relevant event details + */ + public void onPlayerPreLogin(PlayerPreLoginEvent event) {} + + /** + * Called when a player throws an egg and it might hatch + * + * @param event Relevant event details + */ + public void onPlayerEggThrow(PlayerEggThrowEvent event) {} + + /** + * Called when a player plays an animation, such as an arm swing + * + * @param event Relevant event details + */ + public void onPlayerAnimation(PlayerAnimationEvent event) {} + + /** + * Called when a player opens an inventory + * + * @param event Relevant event details + */ + public void onInventoryOpen(PlayerInventoryEvent event) {} + + /** + * Called when a player changes their held item + * + * @param event Relevant event details + */ + public void onItemHeldChange(PlayerItemHeldEvent event) {} + + /** + * Called when a player drops an item from their inventory + * + * @param event Relevant event details + */ + public void onPlayerDropItem(PlayerDropItemEvent event) {} + + /** + * Called when a player picks an item up off the ground + * + * @param event Relevant event details + */ + public void onPlayerPickupItem(PlayerPickupItemEvent event) {} + + /** + * Called when a player toggles sneak mode + * + * @param event Relevant event details + */ + public void onPlayerToggleSneak(PlayerToggleSneakEvent event) {} + + /** + * Called when a player fills a bucket + * + * @param event Relevant event details + */ + public void onPlayerBucketFill(PlayerBucketFillEvent event) {} + + /** + * Called when a player empties a bucket + * + * @param event Relevant event details + */ + public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {} + + /** + * Called when a player enters a bed + * + * @param event Relevant event details + */ + public void onPlayerBedEnter(PlayerBedEnterEvent event) {} + + /** + * Called when a player leaves a bed + * + * @param event Relevant event details + */ + public void onPlayerBedLeave(PlayerBedLeaveEvent event) {} + + /** + * Called when a player is teleporting in a portal (after the animation) + * + * @param event Relevant event details + */ + public void onPlayerPortal(PlayerPortalEvent event) {} + + /** + * Called when a player is fishing + * + * @param event Relevant event details + */ + public void onPlayerFish(PlayerFishEvent event) {} + + /** + * Called when a player used item is damaged + * + * @param event Relevant event details + */ + public void onPlayerItemDamage(PlayerItemDamageEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java new file mode 100644 index 0000000..5a960d4 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java @@ -0,0 +1,127 @@ +package org.bukkit.event.player; + +import net.minecraft.server.NetLoginHandler; +import org.bukkit.entity.Player; + +import java.net.InetAddress; +import java.net.InetSocketAddress; + +/** + * Stores details for players attempting to log in + */ +public class PlayerLoginEvent extends PlayerEvent { + private Result result; + private String message; + private InetAddress playerAddress; //Project Poseidon + private InetAddress localAddress; + + public PlayerLoginEvent(final Player player, final NetLoginHandler netLoginHandler) { + super(Type.PLAYER_LOGIN, player); + this.playerAddress = ((InetSocketAddress) netLoginHandler.networkManager.getSocketAddress()).getAddress(); + this.localAddress = netLoginHandler.networkManager.socket.getLocalAddress(); + this.result = Result.ALLOWED; + this.message = ""; + } + + public PlayerLoginEvent(final Type type, final Player player, final Result result, final String message) { + super(type, player); + this.result = result; + this.message = message; + } + + //TODO: JavaDoc + public InetAddress getAddress() { + return playerAddress; + } + + public InetAddress getLocalAddress() { + return localAddress; + } + + + /** + * Gets the current result of the login, as an enum + * + * @return Current Result of the login + */ + public Result getResult() { + return result; + } + + /** + * Sets the new result of the login, as an enum + * + * @param result New result to set + */ + public void setResult(final Result result) { + this.result = result; + } + + /** + * Gets the current kick message that will be used if getResult() != Result.ALLOWED + * + * @return Current kick message + */ + public String getKickMessage() { + return message; + } + + /** + * Sets the kick message to display if getResult() != Result.ALLOWED + * + * @param message New kick message + */ + public void setKickMessage(final String message) { + this.message = message; + } + + /** + * Allows the player to log in + */ + public void allow() { + result = Result.ALLOWED; + message = ""; + } + + /** + * Disallows the player from logging in, with the given reason + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user + */ + public void disallow(final Result result, final String message) { + this.result = result; + this.message = message; + } + + /** + * Basic kick reasons for communicating to plugins + */ + public enum Result { + + /** + * The player is allowed to log in + */ + ALLOWED, + /** + * The player is not allowed to log in, due to the server being full + */ + KICK_FULL, + /** + * The player is not allowed to log in, due to them being banned + */ + KICK_BANNED, + /** + * The player is not allowed to log in, due to their ip being banned + */ + KICK_BANNED_IP, + /** + * The player is not allowed to log in, due to them not being on the white list + */ + KICK_WHITELIST, + /** + * The player is not allowed to log in, for reasons undefined + */ + KICK_OTHER + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java b/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java new file mode 100644 index 0000000..de421a0 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java @@ -0,0 +1,91 @@ +package org.bukkit.event.player; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +/** + * Holds information for player movement events + */ +public class PlayerMoveEvent extends PlayerEvent implements Cancellable { + private boolean cancel = false; + private Location from; + private Location to; + + public PlayerMoveEvent(final Player player, final Location from, final Location to) { + super(Type.PLAYER_MOVE, player); + this.from = from; + this.to = to; + } + + PlayerMoveEvent(final Event.Type type, final Player player, final Location from, final Location to) { + super(type, player); + this.from = from; + this.to = to; + } + + /** + * Gets the cancellation state of this event. A cancelled event will not + * be executed in the server, but will still pass to other plugins + * + * If a move or teleport event is cancelled, the player will be moved or + * teleported back to the Location as defined by getFrom(). This will not + * fire an event + * + * @return true if this event is cancelled + */ + public boolean isCancelled() { + return cancel; + } + + /** + * Sets the cancellation state of this event. A cancelled event will not + * be executed in the server, but will still pass to other plugins + * + * If a move or teleport event is cancelled, the player will be moved or + * teleported back to the Location as defined by getFrom(). This will not + * fire an event + * + * @param cancel true if you wish to cancel this event + */ + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Gets the location this player moved from + * + * @return Location the player moved from + */ + public Location getFrom() { + return from; + } + + /** + * Sets the location to mark as where the player moved from + * + * @param from New location to mark as the players previous location + */ + public void setFrom(Location from) { + this.from = from; + } + + /** + * Gets the location this player moved to + * + * @return Location the player moved to + */ + public Location getTo() { + return to; + } + + /** + * Sets the location that this player will move to + * + * @param to New Location this player will move to + */ + public void setTo(Location to) { + this.to = to; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java b/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java new file mode 100644 index 0000000..3148e14 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java @@ -0,0 +1,46 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Thrown when a player picks an item up from the ground + */ +public class PlayerPickupItemEvent extends PlayerEvent implements Cancellable { + private final Item item; + private boolean cancel = false; + private int remaining; + + public PlayerPickupItemEvent(final Player player, final Item item, int remaining) { + super(Type.PLAYER_PICKUP_ITEM, player); + this.item = item; + this.remaining = remaining; + } + + /** + * Gets the ItemDrop created by the player + * + * @return Item + */ + public Item getItem() { + return item; + } + + /** + * Gets the amount remaining on the ground, if any + * + * @return amount remaining on the ground + */ + public int getRemaining() { + return remaining; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java b/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java new file mode 100644 index 0000000..01f6436 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java @@ -0,0 +1,37 @@ +package org.bukkit.event.player; + +import org.bukkit.Location; +import org.bukkit.TravelAgent; +import org.bukkit.entity.Player; + +/** + * Called when a player completes the portaling process by standing in a portal + */ +public class PlayerPortalEvent extends PlayerTeleportEvent { + + protected boolean useTravelAgent = true; + + protected Player player; + protected TravelAgent travelAgent; + + public PlayerPortalEvent(Player player, Location from, Location to, TravelAgent pta) { + super(Type.PLAYER_PORTAL, player, from, to); + this.travelAgent = pta; + } + + public void useTravelAgent(boolean useTravelAgent) { + this.useTravelAgent = useTravelAgent; + } + + public boolean useTravelAgent() { + return useTravelAgent; + } + + public TravelAgent getPortalTravelAgent() { + return this.travelAgent; + } + + public void setPortalTravelAgent(TravelAgent travelAgent) { + this.travelAgent = travelAgent; + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java new file mode 100644 index 0000000..1ba303c --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java @@ -0,0 +1,175 @@ +package org.bukkit.event.player; + +import com.projectposeidon.johnymuffin.ConnectionPause; +import com.projectposeidon.johnymuffin.LoginProcessHandler; +import org.bukkit.event.Event; +import org.bukkit.plugin.Plugin; + +import java.net.InetAddress; + +/** + * Stores details for players attempting to log in + */ +public class PlayerPreLoginEvent extends Event { + private Result result; + private String message; + private String name; + private InetAddress ipAddress; + private LoginProcessHandler loginProcessHandler; // Project Poseidon + + public PlayerPreLoginEvent(String name, InetAddress ipAddress, LoginProcessHandler loginProcessHandler) { + super(Type.PLAYER_PRELOGIN); + this.loginProcessHandler = loginProcessHandler; + this.result = Result.ALLOWED; + this.message = ""; + this.name = name; + this.ipAddress = ipAddress; + } + //Project Poseidon Start + + /** + * Set a pause for your plugin + * Connection pauses are for fetching data for a player before they MIGHT be allowed to join + * + * @param plugin Instance of plugin + * @param connectionPauseName Name of connection pause (Ensure no duplicates) + * @return ConnectionPause Object, used to remove a connection pause + */ + public ConnectionPause addConnectionPause(Plugin plugin, String connectionPauseName) { + return loginProcessHandler.addConnectionInterrupt(plugin, connectionPauseName); + } + + /** + * Remove a pause for your plugin by the returned ConnectionPause object + */ + public void removeConnectionPause(ConnectionPause connectionPause) { + loginProcessHandler.removeConnectionPause(connectionPause); + } + + /** + * Cancel a players login before join or login events if a connection pause is still active + */ + public void cancelPlayerLogin(String kickMessage) { + loginProcessHandler.cancelLoginProcess(kickMessage); + } + + /** + * See if the players connection currently paused + */ + public boolean isPlayerConnectionPaused() { + return loginProcessHandler.isPlayerConnectionPaused(); + } + + /** + * Gets the LoginProcessHandler instance for the connection + * + * @return Gets the LoginProcessHandler + */ + @Deprecated + public LoginProcessHandler getLoginProcessHandler() { + return loginProcessHandler; + } + + //Project Poseidon End + + + /** + * Gets the current result of the login, as an enum + * + * @return Current Result of the login + */ + public Result getResult() { + return result; + } + + /** + * Sets the new result of the login, as an enum + * + * @param result New result to set + */ + public void setResult(final Result result) { + this.result = result; + } + + /** + * Gets the current kick message that will be used if getResult() != Result.ALLOWED + * + * @return Current kick message + */ + public String getKickMessage() { + return message; + } + + /** + * Sets the kick message to display if getResult() != Result.ALLOWED + * + * @param message New kick message + */ + public void setKickMessage(final String message) { + this.message = message; + } + + /** + * Allows the player to log in + */ + public void allow() { + result = Result.ALLOWED; + message = ""; + } + + /** + * Disallows the player from logging in, with the given reason + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user + */ + public void disallow(final Result result, final String message) { + this.result = result; + this.message = message; + } + + /** + * Gets the player's name. + * + * @return the player's name + */ + public String getName() { + return name; + } + + /** + * Gets the player IP address. + * + * @return + */ + public InetAddress getAddress() { + return ipAddress; + } + + /** + * Basic kick reasons for communicating to plugins + */ + public enum Result { + + /** + * The player is allowed to log in + */ + ALLOWED, + /** + * The player is not allowed to log in, due to the server being full + */ + KICK_FULL, + /** + * The player is not allowed to log in, due to them being banned + */ + KICK_BANNED, + /** + * The player is not allowed to log in, due to them not being on the white list + */ + KICK_WHITELIST, + /** + * The player is not allowed to log in, for reasons undefined + */ + KICK_OTHER + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java new file mode 100644 index 0000000..fa012ad --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java @@ -0,0 +1,34 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; + +/** + * Called when a player leaves a server + */ +public class PlayerQuitEvent extends PlayerEvent { + + private String quitMessage; + + public PlayerQuitEvent(Player who, String quitMessage) { + super(Type.PLAYER_QUIT, who); + this.quitMessage = quitMessage; + } + + /** + * Gets the quit message to send to all online players + * + * @return string quit message + */ + public String getQuitMessage() { + return quitMessage; + } + + /** + * Sets the quit message to send to all online players + * + * @param quitMessage quit message + */ + public void setQuitMessage(String quitMessage) { + this.quitMessage = quitMessage; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java new file mode 100644 index 0000000..819e379 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java @@ -0,0 +1,42 @@ +package org.bukkit.event.player; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class PlayerRespawnEvent extends PlayerEvent { + private Location respawnLocation; + private boolean isBedSpawn; + + public PlayerRespawnEvent(Player respawnPlayer, Location respawnLocation, boolean isBedSpawn) { + super(Type.PLAYER_RESPAWN, respawnPlayer); + this.respawnLocation = respawnLocation; + this.isBedSpawn = isBedSpawn; + } + + /** + * Gets the current respawn location + * + * @return Location current respawn location + */ + public Location getRespawnLocation() { + return this.respawnLocation; + } + + /** + * Sets the new respawn location + * + * @param respawnLocation new location for the respawn + */ + public void setRespawnLocation(Location respawnLocation) { + this.respawnLocation = respawnLocation; + } + + /** + * Gets whether the respawn location is the player's bed. + * + * @return true if the respawn location is the player's bed. + */ + public boolean isBedSpawn() { + return this.isBedSpawn; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java b/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java new file mode 100644 index 0000000..727041c --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java @@ -0,0 +1,34 @@ +package org.bukkit.event.player; + +import net.minecraft.server.EntityPlayer; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; + +/** + * Holds information for player teleport events + */ +public class PlayerTeleportEvent extends PlayerMoveEvent { + public PlayerTeleportEvent(Player player, Location from, Location to) { + super(Type.PLAYER_TELEPORT, player, from, to); + blockCrossDimensionDupe(); //Poseidon + } + + public PlayerTeleportEvent(final Event.Type type, Player player, Location from, Location to) { + super(type, player, from, to); + blockCrossDimensionDupe(); //Poseidon + } + + //Poseidon - Start + private void blockCrossDimensionDupe() { + if (this.getFrom().getWorld() != this.getTo().getWorld()) { + EntityPlayer entity = ((CraftPlayer) this.getPlayer()).getHandle(); + if (entity.activeContainer == entity.defaultContainer) + return; + System.out.println("[Poseidon] Force closing " + player.getName() + "'s inventory as they have teleported to a different world. This is to prevent a dupe bug."); + entity.y(); + } + } + //Poseidon - End +} diff --git a/src/main/java/org/bukkit/event/player/PlayerToggleSneakEvent.java b/src/main/java/org/bukkit/event/player/PlayerToggleSneakEvent.java new file mode 100644 index 0000000..1e645f1 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerToggleSneakEvent.java @@ -0,0 +1,34 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +/** + * Called when a player toggles their sneaking state + */ +public class PlayerToggleSneakEvent extends PlayerEvent implements Cancellable { + private boolean isSneaking; + private boolean cancel = false; + + public PlayerToggleSneakEvent(final Player player, boolean isSneaking) { + super(Type.PLAYER_TOGGLE_SNEAK, player); + this.isSneaking = isSneaking; + } + + /** + * Returns whether the player is now sneaking or not. + * + * @return sneaking state + */ + public boolean isSneaking() { + return isSneaking; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerVelocityEvent.java b/src/main/java/org/bukkit/event/player/PlayerVelocityEvent.java new file mode 100644 index 0000000..91a7659 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerVelocityEvent.java @@ -0,0 +1,63 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.util.Vector; + +public class PlayerVelocityEvent extends PlayerEvent implements Cancellable { + + /** + * Holds information for player velocity events + */ + private boolean cancel = false; + private Vector velocity; + + public PlayerVelocityEvent(final Player player, final Vector velocity) { + super(Type.PLAYER_VELOCITY, player); + this.velocity = velocity; + } + + PlayerVelocityEvent(final Event.Type type, final Player player, final Vector velocity) { + super(type, player); + this.velocity = velocity; + } + + /** + * Gets the cancellation state of this event. A cancelled event will not + * be executed in the server, but will still pass to other plugins + * + * @return true if this event is cancelled + */ + public boolean isCancelled() { + return cancel; + } + + /** + * Sets the cancellation state of this event. A cancelled event will not + * be executed in the server, but will still pass to other plugins + * + * @param cancel true if you wish to cancel this event + */ + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * Gets the velocity vector that will be sent to the player + * + * @return Vector the player will get + */ + public Vector getVelocity() { + return velocity; + } + + /** + * Sets the velocity vector that will be sent to the player + * + * @param velocity The velocity vector that will be sent to the player + */ + public void setVelocity(Vector velocity) { + this.velocity = velocity; + } +} diff --git a/src/main/java/org/bukkit/event/server/MapInitializeEvent.java b/src/main/java/org/bukkit/event/server/MapInitializeEvent.java new file mode 100644 index 0000000..12ef178 --- /dev/null +++ b/src/main/java/org/bukkit/event/server/MapInitializeEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.server; + +import org.bukkit.event.Event; +import org.bukkit.map.MapView; + +/** + * Called when a map is initialized. + */ +public class MapInitializeEvent extends ServerEvent { + private final MapView mapView; + + public MapInitializeEvent(MapView mapView) { + super(Event.Type.MAP_INITIALIZE); + this.mapView = mapView; + } + + /** + * Gets the map initialized in this event. + * + * @return Map for this event + */ + public MapView getMap() { + return mapView; + } +} diff --git a/src/main/java/org/bukkit/event/server/PluginDisableEvent.java b/src/main/java/org/bukkit/event/server/PluginDisableEvent.java new file mode 100644 index 0000000..6e9a21e --- /dev/null +++ b/src/main/java/org/bukkit/event/server/PluginDisableEvent.java @@ -0,0 +1,12 @@ +package org.bukkit.event.server; + +import org.bukkit.plugin.Plugin; + +/** + * Called when a plugin is disabled. + */ +public class PluginDisableEvent extends PluginEvent { + public PluginDisableEvent(Plugin plugin) { + super(Type.PLUGIN_DISABLE, plugin); + } +} diff --git a/src/main/java/org/bukkit/event/server/PluginEnableEvent.java b/src/main/java/org/bukkit/event/server/PluginEnableEvent.java new file mode 100644 index 0000000..f3eaa6e --- /dev/null +++ b/src/main/java/org/bukkit/event/server/PluginEnableEvent.java @@ -0,0 +1,12 @@ +package org.bukkit.event.server; + +import org.bukkit.plugin.Plugin; + +/** + * Called when a plugin is enabled. + */ +public class PluginEnableEvent extends PluginEvent { + public PluginEnableEvent(Plugin plugin) { + super(Type.PLUGIN_ENABLE, plugin); + } +} diff --git a/src/main/java/org/bukkit/event/server/PluginEvent.java b/src/main/java/org/bukkit/event/server/PluginEvent.java new file mode 100644 index 0000000..937cf49 --- /dev/null +++ b/src/main/java/org/bukkit/event/server/PluginEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.server; + +import org.bukkit.plugin.Plugin; + +/** + * Used for plugin enable and disable events + */ +public class PluginEvent extends ServerEvent { + private final Plugin plugin; + + public PluginEvent(final Type type, final Plugin plugin) { + super(type); + + this.plugin = plugin; + } + + /** + * Gets the plugin involved in this event + * + * @return Plugin for this event + */ + public Plugin getPlugin() { + return plugin; + } +} diff --git a/src/main/java/org/bukkit/event/server/ServerCommandEvent.java b/src/main/java/org/bukkit/event/server/ServerCommandEvent.java new file mode 100644 index 0000000..661f29f --- /dev/null +++ b/src/main/java/org/bukkit/event/server/ServerCommandEvent.java @@ -0,0 +1,42 @@ +package org.bukkit.event.server; + +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; + +/** + * Server Command events + */ +public class ServerCommandEvent extends ServerEvent { + private String command; + private CommandSender sender; + public ServerCommandEvent(ConsoleCommandSender console, String message) { + super(Type.SERVER_COMMAND); + command = message; + sender = console; + } + + /** + * Gets the command that the user is attempting to execute from the console + * + * @return Command the user is attempting to execute + */ + public String getCommand() { + return command; + } + + /** + * Sets the command that the server will execute + * + * @param message New message that the server will execute + */ + public void setCommand(String message) { + this.command = message; + } + + /** + * Get the command sender. + */ + public CommandSender getSender() { + return sender; + } +} diff --git a/src/main/java/org/bukkit/event/server/ServerEvent.java b/src/main/java/org/bukkit/event/server/ServerEvent.java new file mode 100644 index 0000000..6c2b374 --- /dev/null +++ b/src/main/java/org/bukkit/event/server/ServerEvent.java @@ -0,0 +1,12 @@ +package org.bukkit.event.server; + +import org.bukkit.event.Event; + +/** + * Miscellaneous server events + */ +public class ServerEvent extends Event { + public ServerEvent(final Type type) { + super(type); + } +} diff --git a/src/main/java/org/bukkit/event/server/ServerListener.java b/src/main/java/org/bukkit/event/server/ServerListener.java new file mode 100644 index 0000000..f4bf722 --- /dev/null +++ b/src/main/java/org/bukkit/event/server/ServerListener.java @@ -0,0 +1,37 @@ +package org.bukkit.event.server; + +import org.bukkit.event.Listener; + +/** + * Handles all miscellaneous server events + */ +public class ServerListener implements Listener { + + /** + * Called when a plugin is enabled + * + * @param event Relevant event details + */ + public void onPluginEnable(PluginEnableEvent event) {} + + /** + * Called when a plugin is disabled + * + * @param event Relevant event details + */ + public void onPluginDisable(PluginDisableEvent event) {} + + /** + * Called when a server command is used + * + * @param event Relevant event details + */ + public void onServerCommand(ServerCommandEvent event) {} + + /** + * Called when a map item is initialized (created or loaded into memory) + * + * @param event Relevant event details + */ + public void onMapInitialize(MapInitializeEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java new file mode 100644 index 0000000..d29c5ea --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.block.Block; +import org.bukkit.entity.Vehicle; + +/** + * Raised when a vehicle collides with a block. + */ +public class VehicleBlockCollisionEvent extends VehicleCollisionEvent { + private Block block; + + public VehicleBlockCollisionEvent(Vehicle vehicle, Block block) { + super(Type.VEHICLE_COLLISION_BLOCK, vehicle); + this.block = block; + } + + /** + * Gets the block the vehicle collided with + * + * @return the block the vehicle collided with + */ + public Block getBlock() { + return block; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java new file mode 100644 index 0000000..5eea95c --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java @@ -0,0 +1,12 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Vehicle; + +/** + * Raised when a vehicle collides. + */ +public class VehicleCollisionEvent extends VehicleEvent { + public VehicleCollisionEvent(Type type, Vehicle vehicle) { + super(type, vehicle); + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleCreateEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleCreateEvent.java new file mode 100644 index 0000000..4ab2ab9 --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleCreateEvent.java @@ -0,0 +1,14 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Vehicle; + +/** + * Raised when a vehicle is created. + * + * @author sk89q + */ +public class VehicleCreateEvent extends VehicleEvent { + public VehicleCreateEvent(Vehicle vehicle) { + super(Type.VEHICLE_CREATE, vehicle); + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleDamageEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleDamageEvent.java new file mode 100644 index 0000000..28ff928 --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleDamageEvent.java @@ -0,0 +1,55 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.Cancellable; + +/** + * Raised when a vehicle receives damage. + */ +public class VehicleDamageEvent extends VehicleEvent implements Cancellable { + private Entity attacker; + private int damage; + private boolean cancelled; + + public VehicleDamageEvent(Vehicle vehicle, Entity attacker, int damage) { + super(Type.VEHICLE_DAMAGE, vehicle); + this.attacker = attacker; + this.damage = damage; + } + + /** + * Gets the Entity that is attacking the vehicle + * + * @return the Entity that is attacking the vehicle + */ + public Entity getAttacker() { + return attacker; + } + + /** + * Gets the damage done to the vehicle + * + * @return the damage done to the vehicle + */ + public int getDamage() { + return damage; + } + + /** + * Sets the damage done to the vehicle + * + * @param damage + */ + public void setDamage(int damage) { + this.damage = damage; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleDestroyEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleDestroyEvent.java new file mode 100644 index 0000000..99c2dd2 --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleDestroyEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.Cancellable; + +/** + * Raised when a vehicle is destroyed + */ +public class VehicleDestroyEvent extends VehicleEvent implements Cancellable { + private Entity attacker; + private boolean cancelled; + + public VehicleDestroyEvent(Vehicle vehicle, Entity attacker) { + super(Type.VEHICLE_DESTROY, vehicle); + this.attacker = attacker; + } + + /** + * Gets the Entity that has destroyed the vehicle + * + * @return the Entity that has destroyed the vehicle + */ + public Entity getAttacker() { + return attacker; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleEnterEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleEnterEvent.java new file mode 100644 index 0000000..b7600f7 --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleEnterEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.Cancellable; + +/** + * Raised when an entity enters a vehicle. + */ +public class VehicleEnterEvent extends VehicleEvent implements Cancellable { + private boolean cancelled; + private Entity entered; + + public VehicleEnterEvent(Vehicle vehicle, Entity entered) { + super(Type.VEHICLE_ENTER, vehicle); + this.entered = entered; + } + + /** + * Gets the Entity that entered the vehicle. + * + * @return the Entity that entered the vehicle + */ + public Entity getEntered() { + return entered; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java new file mode 100644 index 0000000..4263177 --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java @@ -0,0 +1,50 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.Cancellable; + +/** + * Raised when a vehicle collides with an entity. + * + * @author sk89q + */ +public class VehicleEntityCollisionEvent extends VehicleCollisionEvent implements Cancellable { + private Entity entity; + private boolean cancelled = false; + private boolean cancelledPickup = false; + private boolean cancelledCollision = false; + + public VehicleEntityCollisionEvent(Vehicle vehicle, Entity entity) { + super(Type.VEHICLE_COLLISION_ENTITY, vehicle); + this.entity = entity; + } + + public Entity getEntity() { + return entity; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + public boolean isPickupCancelled() { + return cancelledPickup; + } + + public void setPickupCancelled(boolean cancel) { + cancelledPickup = cancel; + } + + public boolean isCollisionCancelled() { + return cancelledCollision; + } + + public void setCollisionCancelled(boolean cancel) { + cancelledCollision = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleEvent.java new file mode 100644 index 0000000..8a4aa88 --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleEvent.java @@ -0,0 +1,27 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Vehicle; +import org.bukkit.event.Event; + +/** + * Represents a vehicle-related event. + * + * @author sk89q + */ +public class VehicleEvent extends Event { + protected Vehicle vehicle; + + public VehicleEvent(final Event.Type type, final Vehicle vehicle) { + super(type); + this.vehicle = vehicle; + } + + /** + * Get the vehicle. + * + * @return the vehicle + */ + public final Vehicle getVehicle() { + return vehicle; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java new file mode 100644 index 0000000..f8e30dc --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.Cancellable; + +/** + * Raised when a living entity exits a vehicle. + */ +public class VehicleExitEvent extends VehicleEvent implements Cancellable { + private boolean cancelled; + private LivingEntity exited; + + public VehicleExitEvent(Vehicle vehicle, LivingEntity exited) { + super(Type.VEHICLE_EXIT, vehicle); + this.exited = exited; + } + + /** + * Get the living entity that exited the vehicle. + * + * @return + */ + public LivingEntity getExited() { + return exited; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleListener.java b/src/main/java/org/bukkit/event/vehicle/VehicleListener.java new file mode 100644 index 0000000..9f0387a --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleListener.java @@ -0,0 +1,76 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.event.Listener; + +/** + * Listener for vehicle events. + * + * @author sk89q + */ +public class VehicleListener implements Listener { + public VehicleListener() {} + + /** + * Called when a vehicle is created by a player. This hook will be called + * for all vehicles created. + * + * @param event + */ + public void onVehicleCreate(VehicleCreateEvent event) {} + + /** + * Called when a vehicle is damaged by the player. + * + * @param event + */ + public void onVehicleDamage(VehicleDamageEvent event) {} + + /** + * Called when a vehicle collides with a block. + * + * @param event + */ + public void onVehicleBlockCollision(VehicleBlockCollisionEvent event) {} + + /** + * Called when a vehicle collides with an entity. + * + * @param event + */ + public void onVehicleEntityCollision(VehicleEntityCollisionEvent event) {} + + /** + * Called when an entity enters a vehicle. + * + * @param event + */ + public void onVehicleEnter(VehicleEnterEvent event) {} + + /** + * Called when an entity exits a vehicle. + * + * @param event + */ + public void onVehicleExit(VehicleExitEvent event) {} + + /** + * Called when an vehicle moves. + * + * @param event + */ + public void onVehicleMove(VehicleMoveEvent event) {} + + /** + * Called when a vehicle is destroyed. + * + * @param event + */ + public void onVehicleDestroy(VehicleDestroyEvent event) {} + + /** + * Called when a vehicle goes through an update cycle + * + * @param event + */ + public void onVehicleUpdate(VehicleUpdateEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleMoveEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleMoveEvent.java new file mode 100644 index 0000000..056042d --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleMoveEvent.java @@ -0,0 +1,39 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.Location; +import org.bukkit.entity.Vehicle; + +/** + * Raised when a vehicle moves. + * + * @author sk89q + */ +public class VehicleMoveEvent extends VehicleEvent { + private Location from; + private Location to; + + public VehicleMoveEvent(Vehicle vehicle, Location from, Location to) { + super(Type.VEHICLE_MOVE, vehicle); + + this.from = from; + this.to = to; + } + + /** + * Get the previous position. + * + * @return + */ + public Location getFrom() { + return from; + } + + /** + * Get the next position. + * + * @return + */ + public Location getTo() { + return to; + } +} diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleUpdateEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleUpdateEvent.java new file mode 100644 index 0000000..814e14e --- /dev/null +++ b/src/main/java/org/bukkit/event/vehicle/VehicleUpdateEvent.java @@ -0,0 +1,9 @@ +package org.bukkit.event.vehicle; + +import org.bukkit.entity.Vehicle; + +public class VehicleUpdateEvent extends VehicleEvent { + public VehicleUpdateEvent(Vehicle vehicle) { + super(Type.VEHICLE_UPDATE, vehicle); + } +} diff --git a/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java b/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java new file mode 100644 index 0000000..f38ac47 --- /dev/null +++ b/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java @@ -0,0 +1,38 @@ +package org.bukkit.event.weather; + +import org.bukkit.World; +import org.bukkit.entity.LightningStrike; +import org.bukkit.event.Cancellable; + +/** + * Stores data for lightning striking + */ +public class LightningStrikeEvent extends WeatherEvent implements Cancellable { + + private boolean canceled; + private LightningStrike bolt; + private World world; + + public LightningStrikeEvent(World world, LightningStrike bolt) { + super(Type.LIGHTNING_STRIKE, world); + this.bolt = bolt; + this.world = world; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the bolt which is striking the earth. + * + * @return lightning entity + */ + public LightningStrike getLightning() { + return bolt; + } +} diff --git a/src/main/java/org/bukkit/event/weather/ThunderChangeEvent.java b/src/main/java/org/bukkit/event/weather/ThunderChangeEvent.java new file mode 100644 index 0000000..c53f7ff --- /dev/null +++ b/src/main/java/org/bukkit/event/weather/ThunderChangeEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.weather; + +import org.bukkit.World; +import org.bukkit.event.Cancellable; + +/** + * Stores data for thunder state changing in a world + */ +public class ThunderChangeEvent extends WeatherEvent implements Cancellable { + + private boolean canceled; + private boolean to; + + public ThunderChangeEvent(World world, boolean to) { + super(Type.THUNDER_CHANGE, world); + this.to = to; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the state of thunder that the world is being set to + * + * @return true if the weather is being set to thundering, false otherwise + */ + public boolean toThunderState() { + return to; + } +} diff --git a/src/main/java/org/bukkit/event/weather/WeatherChangeEvent.java b/src/main/java/org/bukkit/event/weather/WeatherChangeEvent.java new file mode 100644 index 0000000..f6e9e2e --- /dev/null +++ b/src/main/java/org/bukkit/event/weather/WeatherChangeEvent.java @@ -0,0 +1,35 @@ +package org.bukkit.event.weather; + +import org.bukkit.World; +import org.bukkit.event.Cancellable; + +/** + * Stores data for weather changing in a world + */ +public class WeatherChangeEvent extends WeatherEvent implements Cancellable { + + private boolean canceled; + private boolean to; + + public WeatherChangeEvent(World world, boolean to) { + super(Type.WEATHER_CHANGE, world); + this.to = to; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the state of weather that the world is being set to + * + * @return true if the weather is being set to raining, false otherwise + */ + public boolean toWeatherState() { + return to; + } +} diff --git a/src/main/java/org/bukkit/event/weather/WeatherEvent.java b/src/main/java/org/bukkit/event/weather/WeatherEvent.java new file mode 100644 index 0000000..8c78f86 --- /dev/null +++ b/src/main/java/org/bukkit/event/weather/WeatherEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.weather; + +import org.bukkit.World; +import org.bukkit.event.Event; + +/** + * Represents a Weather-related event + */ +public class WeatherEvent extends Event { + protected World world; + + public WeatherEvent(final Event.Type type, final World where) { + super(type); + world = where; + } + + /** + * Returns the World where this event is occurring + * + * @return World this event is occurring in + */ + public final World getWorld() { + return world; + } +} diff --git a/src/main/java/org/bukkit/event/weather/WeatherListener.java b/src/main/java/org/bukkit/event/weather/WeatherListener.java new file mode 100644 index 0000000..1a6d6ce --- /dev/null +++ b/src/main/java/org/bukkit/event/weather/WeatherListener.java @@ -0,0 +1,31 @@ +package org.bukkit.event.weather; + +import org.bukkit.event.Listener; + +/** + * Handles all events fired in relation to weather + */ +public class WeatherListener implements Listener { + public WeatherListener() {} + + /** + * Called when a weather change occurs + * + * @param event Relevant event details + */ + public void onWeatherChange(WeatherChangeEvent event) {} + + /** + * Called when the state of thunder changes + * + * @param event Relevant event details + */ + public void onThunderChange(ThunderChangeEvent event) {} + + /** + * Called when lightning strikes + * + * @param event Relevant event details + */ + public void onLightningStrike(LightningStrikeEvent event) {} +} diff --git a/src/main/java/org/bukkit/event/world/ChunkEvent.java b/src/main/java/org/bukkit/event/world/ChunkEvent.java new file mode 100644 index 0000000..3e789b7 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/ChunkEvent.java @@ -0,0 +1,24 @@ +package org.bukkit.event.world; + +import org.bukkit.Chunk; + +/** + * Represents a Chunk related event + */ +public class ChunkEvent extends WorldEvent { + protected Chunk chunk; + + protected ChunkEvent(Type type, Chunk chunk) { + super(type, chunk.getWorld()); + this.chunk = chunk; + } + + /** + * Gets the chunk being loaded/unloaded + * + * @return Chunk that triggered this event + */ + public Chunk getChunk() { + return chunk; + } +} diff --git a/src/main/java/org/bukkit/event/world/ChunkLoadEvent.java b/src/main/java/org/bukkit/event/world/ChunkLoadEvent.java new file mode 100644 index 0000000..9eb6cc4 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/ChunkLoadEvent.java @@ -0,0 +1,25 @@ +package org.bukkit.event.world; + +import org.bukkit.Chunk; + +/** + * Called when a chunk is loaded + */ +public class ChunkLoadEvent extends ChunkEvent { + private final boolean newChunk; + + public ChunkLoadEvent(final Chunk chunk, final boolean newChunk) { + super(Type.CHUNK_LOAD, chunk); + this.newChunk = newChunk; + } + + /** + * Gets if this chunk was newly created or not. + * Note that if this chunk is new, it will not be populated at this time. + * + * @return true if the chunk is new, otherwise false + */ + public boolean isNewChunk() { + return newChunk; + } +} diff --git a/src/main/java/org/bukkit/event/world/ChunkPopulateEvent.java b/src/main/java/org/bukkit/event/world/ChunkPopulateEvent.java new file mode 100644 index 0000000..aa10a63 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/ChunkPopulateEvent.java @@ -0,0 +1,15 @@ +package org.bukkit.event.world; + +import org.bukkit.Chunk; +import org.bukkit.generator.BlockPopulator; + +/** + * Thrown when a new chunk has finished being populated. + * + * If your intent is to populate the chunk using this event, please see {@link BlockPopulator} + */ +public class ChunkPopulateEvent extends ChunkEvent { + public ChunkPopulateEvent(final Chunk chunk) { + super(Type.CHUNK_POPULATED, chunk); + } +} diff --git a/src/main/java/org/bukkit/event/world/ChunkUnloadEvent.java b/src/main/java/org/bukkit/event/world/ChunkUnloadEvent.java new file mode 100644 index 0000000..dd030eb --- /dev/null +++ b/src/main/java/org/bukkit/event/world/ChunkUnloadEvent.java @@ -0,0 +1,23 @@ +package org.bukkit.event.world; + +import org.bukkit.Chunk; +import org.bukkit.event.Cancellable; + +/** + * Called when a chunk is unloaded + */ +public class ChunkUnloadEvent extends ChunkEvent implements Cancellable { + private boolean cancel = false; + + public ChunkUnloadEvent(final Chunk chunk) { + super(Type.CHUNK_UNLOAD, chunk); + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/world/PortalCreateEvent.java b/src/main/java/org/bukkit/event/world/PortalCreateEvent.java new file mode 100644 index 0000000..3bf9e8c --- /dev/null +++ b/src/main/java/org/bukkit/event/world/PortalCreateEvent.java @@ -0,0 +1,38 @@ +package org.bukkit.event.world; + +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Called when the world attempts to create a matching end to a portal + */ +public class PortalCreateEvent extends WorldEvent implements Cancellable { + private boolean cancel = false; + private ArrayList blocks = new ArrayList(); + + public PortalCreateEvent(final Collection blocks, final World world) { + super(Type.PORTAL_CREATE, world); + this.blocks.addAll(blocks); + } + + /** + * Gets an array list of all the blocks associated with the created portal + * + * @return array list of all the blocks associated with the created portal + */ + public ArrayList getBlocks() { + return this.blocks; + } + + public boolean isCancelled() { + return cancel; + } + + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/org/bukkit/event/world/SpawnChangeEvent.java b/src/main/java/org/bukkit/event/world/SpawnChangeEvent.java new file mode 100644 index 0000000..0f11f39 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/SpawnChangeEvent.java @@ -0,0 +1,26 @@ +package org.bukkit.event.world; + +import org.bukkit.Location; +import org.bukkit.World; + +/** + * An event that is called when a world's spawn changes. The + * world's previous spawn location is included. + */ +public class SpawnChangeEvent extends WorldEvent { + private Location previousLocation; + + public SpawnChangeEvent(World world, Location previousLocation) { + super(Type.SPAWN_CHANGE, world); + this.previousLocation = previousLocation; + } + + /** + * Gets the previous spawn location + * + * @return Location that used to be spawn + */ + public Location getPreviousLocation() { + return previousLocation; + } +} diff --git a/src/main/java/org/bukkit/event/world/WorldEvent.java b/src/main/java/org/bukkit/event/world/WorldEvent.java new file mode 100644 index 0000000..5f42fb7 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/WorldEvent.java @@ -0,0 +1,26 @@ +package org.bukkit.event.world; + +import org.bukkit.World; +import org.bukkit.event.Event; + +/** + * Represents events within a world + */ +public class WorldEvent extends Event { + private final World world; + + public WorldEvent(final Type type, final World world) { + super(type); + + this.world = world; + } + + /** + * Gets the world primarily involved with this event + * + * @return World which caused this event + */ + public World getWorld() { + return world; + } +} diff --git a/src/main/java/org/bukkit/event/world/WorldInitEvent.java b/src/main/java/org/bukkit/event/world/WorldInitEvent.java new file mode 100644 index 0000000..e14e05b --- /dev/null +++ b/src/main/java/org/bukkit/event/world/WorldInitEvent.java @@ -0,0 +1,12 @@ +package org.bukkit.event.world; + +import org.bukkit.World; + +/** + * Called when a World is initializing + */ +public class WorldInitEvent extends WorldEvent { + public WorldInitEvent(World world) { + super(Type.WORLD_INIT, world); + } +} diff --git a/src/main/java/org/bukkit/event/world/WorldListener.java b/src/main/java/org/bukkit/event/world/WorldListener.java new file mode 100644 index 0000000..c6e398d --- /dev/null +++ b/src/main/java/org/bukkit/event/world/WorldListener.java @@ -0,0 +1,75 @@ +package org.bukkit.event.world; + +import org.bukkit.event.Listener; + +/** + * Handles all World related events + */ +public class WorldListener implements Listener { + + /** + * Called when a chunk is loaded + * + * @param event Relevant event details + */ + public void onChunkLoad(ChunkLoadEvent event) {} + + /** + * Called when a newly created chunk has been populated. + * + * If your intent is to populate the chunk using this event, please see {@link BlockPopulator} + * + * @param event Relevant event details + */ + public void onChunkPopulate(ChunkPopulateEvent event) {} + + /** + * Called when a chunk is unloaded + * + * @param event Relevant event details + */ + public void onChunkUnload(ChunkUnloadEvent event) {} + + /** + * Called when a World's spawn is changed + * + * @param event Relevant event details + */ + public void onSpawnChange(SpawnChangeEvent event) {} + + /** + * Called when the world generates a portal end point + * + * @param event Relevant event details + */ + public void onPortalCreate(PortalCreateEvent event) {} + + /** + * Called when a world is saved + * + * @param event Relevant event details + */ + public void onWorldSave(WorldSaveEvent event) {} + + /** + * Called when a World is initializing + * + * @param event Relevant event details + */ + public void onWorldInit(WorldInitEvent event) { + } + + /** + * Called when a World is loaded + * + * @param event Relevant event details + */ + public void onWorldLoad(WorldLoadEvent event) {} + + /** + * Called when a World is unloaded + * + * @param event Relevant event details + */ + public void onWorldUnload(WorldUnloadEvent event) { } +} diff --git a/src/main/java/org/bukkit/event/world/WorldLoadEvent.java b/src/main/java/org/bukkit/event/world/WorldLoadEvent.java new file mode 100644 index 0000000..7214ae0 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/WorldLoadEvent.java @@ -0,0 +1,12 @@ +package org.bukkit.event.world; + +import org.bukkit.World; + +/** + * Called when a World is loaded + */ +public class WorldLoadEvent extends WorldEvent { + public WorldLoadEvent(World world) { + super(Type.WORLD_LOAD, world); + } +} diff --git a/src/main/java/org/bukkit/event/world/WorldSaveEvent.java b/src/main/java/org/bukkit/event/world/WorldSaveEvent.java new file mode 100644 index 0000000..fec1e00 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/WorldSaveEvent.java @@ -0,0 +1,9 @@ +package org.bukkit.event.world; + +import org.bukkit.World; + +public class WorldSaveEvent extends WorldEvent { + public WorldSaveEvent(World world) { + super(Type.WORLD_SAVE, world); + } +} diff --git a/src/main/java/org/bukkit/event/world/WorldUnloadEvent.java b/src/main/java/org/bukkit/event/world/WorldUnloadEvent.java new file mode 100644 index 0000000..30c0f15 --- /dev/null +++ b/src/main/java/org/bukkit/event/world/WorldUnloadEvent.java @@ -0,0 +1,23 @@ +package org.bukkit.event.world; + +import org.bukkit.World; +import org.bukkit.event.Cancellable; + +/** + * Called when a World is unloaded + */ +public class WorldUnloadEvent extends WorldEvent implements Cancellable { + private boolean isCancelled; + + public WorldUnloadEvent(World world) { + super(Type.WORLD_UNLOAD, world); + } + + public boolean isCancelled() { + return this.isCancelled; + } + + public void setCancelled(boolean cancel) { + this.isCancelled = cancel; + } +} diff --git a/src/main/java/org/bukkit/generator/BlockPopulator.java b/src/main/java/org/bukkit/generator/BlockPopulator.java new file mode 100644 index 0000000..5cf3906 --- /dev/null +++ b/src/main/java/org/bukkit/generator/BlockPopulator.java @@ -0,0 +1,27 @@ +package org.bukkit.generator; + +import org.bukkit.Chunk; +import org.bukkit.World; + +import java.util.Random; + +/** + * A block populator is responsible for generating a small area of blocks. + * For example, generating glowstone inside the nether or generating dungeons full of treasure + */ +public abstract class BlockPopulator { + /** + * Populates an area of blocks at or around the given chunk. + * + * The chunks on each side of the specified chunk must already exist; that is, + * there must be one north, east, south and west of the specified chunk. + * The "corner" chunks may not exist, in which scenario the populator should + * record any changes required for those chunks and perform the changes when + * they are ready. + * + * @param world The world to generate in + * @param random The random generator to use + * @param chunk The chunk to generate for + */ + public abstract void populate(World world, Random random, Chunk source); +} diff --git a/src/main/java/org/bukkit/generator/ChunkGenerator.java b/src/main/java/org/bukkit/generator/ChunkGenerator.java new file mode 100644 index 0000000..a355f23 --- /dev/null +++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java @@ -0,0 +1,90 @@ +package org.bukkit.generator; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * A chunk generator is responsible for the initial shaping of an entire chunk. + * For example, the nether chunk generator should shape netherrack and soulsand + */ +public abstract class ChunkGenerator { + /** + * Shapes the chunk for the given coordinates.
+ *
+ * This method should return a byte[32768] in the following format: + *

+     * for (int x = 0; x < 16; x++) {
+     *     for (int z = 0; z < 16; z++) {
+     *         for (int y = 0; y < 128; y++) {
+     *             // result[(x * 16 + z) * 128 + y] = ??;
+     *         }
+     *     }
+     * }
+     * 
+ * + * Note that this method should never attempt to get the Chunk at + * the passed coordinates, as doing so may cause an infinite loop + * + * @param world The world this chunk will be used for + * @param random The random generator to use + * @param x The X-coordinate of the chunk + * @param z The Z-coordinate of the chunk + * @return byte[] containing the types for each block created by this generator + */ + public abstract byte[] generate(World world, Random random, int x, int z); + + /** + * Tests if the specified location is valid for a natural spawn position + * + * @param world The world we're testing on + * @param x X-coordinate of the block to test + * @param z Z-coordinate of the block to test + * @return true if the location is valid, otherwise false + */ + public boolean canSpawn(World world, int x, int z) { + Block highest = world.getBlockAt(x, world.getHighestBlockYAt(x, z), z); + + switch (world.getEnvironment()) { + case NETHER: + return true; + case SKYLANDS: + return highest.getType() != Material.AIR + && highest.getType() != Material.WATER + && highest.getType() != Material.LAVA; + case NORMAL: + default: + return highest.getType() == Material.SAND + || highest.getType() == Material.GRAVEL; + } + } + + /** + * Gets a list of default {@link BlockPopulator}s to apply to a given world + * + * @param world World to apply to + * @return List containing any amount of BlockPopulators + */ + public List getDefaultPopulators(World world) { + return new ArrayList(); + } + + /** + * Gets a fixed spawn location to use for a given world. + * + * A null value is returned if a world should not use a fixed spawn point, + * and will instead attempt to find one randomly. + * + * @param world The world to locate a spawn point for + * @param random Random generator to use in the calculation + * @return Location containing a new spawn point, otherwise null + */ + public Location getFixedSpawnLocation(World world, Random random) { + return null; + } +} diff --git a/src/main/java/org/bukkit/inventory/FurnaceRecipe.java b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java new file mode 100644 index 0000000..50c4cc7 --- /dev/null +++ b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java @@ -0,0 +1,73 @@ +package org.bukkit.inventory; + +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +/** + * Represents a smelting recipe. + */ +public class FurnaceRecipe implements Recipe { + private ItemStack output; + private MaterialData ingredient; + + /** + * Create a furnace recipe to craft the specified ItemStack. + * @param result The item you want the recipe to create. + * @param source The input material. + */ + public FurnaceRecipe(ItemStack result, Material source) { + this(result, source.getNewData((byte) 0)); + if (this.ingredient == null) { + setInput(new MaterialData(source)); + } + } + + /** + * Create a furnace recipe to craft the specified ItemStack. + * @param result The item you want the recipe to create. + * @param source The input material. + */ + public FurnaceRecipe(ItemStack result, MaterialData source) { + this.output = result; + this.ingredient = source; + } + + /** + * Sets the input of this furnace recipe. + * @param input The input material. + * @return The changed recipe, so you can chain calls. + */ + public FurnaceRecipe setInput(MaterialData input) { + this.ingredient = input; + return this; + } + + /** + * Sets the input of this furnace recipe. + * @param input The input material. + * @return The changed recipe, so you can chain calls. + */ + public FurnaceRecipe setInput(Material input) { + setInput(input.getNewData((byte) 0)); + if (this.ingredient == null) { + setInput(new MaterialData(input)); + } + return this; + } + + /** + * Get the input material. + * @return The input material. + */ + public MaterialData getInput() { + return (MaterialData) ingredient; + } + + /** + * Get the result of this recipe. + * @return The resulting stack. + */ + public ItemStack getResult() { + return output; + } +} diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java new file mode 100644 index 0000000..5159215 --- /dev/null +++ b/src/main/java/org/bukkit/inventory/Inventory.java @@ -0,0 +1,219 @@ +package org.bukkit.inventory; + +import org.bukkit.Material; + +import java.util.HashMap; + +/** + * Interface to the various inventories + */ +public interface Inventory { + + /** + * Returns the size of the inventory + * + * @return The inventory size + */ + public int getSize(); + + /** + * Return the name of the inventory + * + * @return The inventory name + */ + public String getName(); + + /** + * Get the ItemStack found in the slot at the given index + * + * @param index The index of the Slot's ItemStack to return + * @return The ItemStack in the slot + */ + public ItemStack getItem(int index); + + /** + * Stores the ItemStack at the given index + * + * @param index The index where to put the ItemStack + * @param item The ItemStack to set + */ + public void setItem(int index, ItemStack item); + + /** + * Stores the given ItemStacks in the inventory. + * + * This will try to fill existing stacks and empty slots as good as it can. + * It will return a HashMap of what it couldn't fit. + * + * @param items The ItemStacks to add + * @return + */ + public HashMap addItem(ItemStack... items); + + /** + * Removes the given ItemStacks from the inventory. + * + * It will try to remove 'as much as possible' from the types and amounts you + * give as arguments. It will return a HashMap of what it couldn't remove. + * + * @param items The ItemStacks to remove + * @return + */ + public HashMap removeItem(ItemStack... items); + + /** + * Get all ItemStacks from the inventory + * + * @return All the ItemStacks from all slots + */ + public ItemStack[] getContents(); + + /** + * Set the inventory's contents + * + * @return All the ItemStacks from all slots + */ + public void setContents(ItemStack[] items); + + /** + * Check if the inventory contains any ItemStacks with the given materialId + * + * @param materialId The materialId to check for + * @return If any ItemStacks were found + */ + public boolean contains(int materialId); + + /** + * Check if the inventory contains any ItemStacks with the given material + * + * @param material The material to check for + * @return If any ItemStacks were found + */ + public boolean contains(Material material); + + /** + * Check if the inventory contains any ItemStacks matching the given ItemStack + * This will only match if both the type and the amount of the stack match + * + * @param item The ItemStack to match against + * @return If any matching ItemStacks were found + */ + public boolean contains(ItemStack item); + + /** + * Check if the inventory contains any ItemStacks with the given materialId and at least the minimum amount specified + * + * @param materialId The materialId to check for + * @param amount The minimum amount to look for + * @return If any ItemStacks were found + */ + public boolean contains(int materialId, int amount); + + /** + * Check if the inventory contains any ItemStacks with the given material and at least the minimum amount specified + * + * @param material The material to check for + * @return If any ItemStacks were found + */ + public boolean contains(Material material, int amount); + + /** + * Check if the inventory contains any ItemStacks matching the given ItemStack and at least the minimum amount specified + * This will only match if both the type and the amount of the stack match + * + * @param item The ItemStack to match against + * @return If any matching ItemStacks were found + */ + public boolean contains(ItemStack item, int amount); + + /** + * Find all slots in the inventory containing any ItemStacks with the given materialId + * + * @param materialId The materialId to look for + * @return The Slots found. + */ + public HashMap all(int materialId); + + /** + * Find all slots in the inventory containing any ItemStacks with the given material + * + * @param materialId The material to look for + * @return The Slots found. + */ + public HashMap all(Material material); + + /** + * Find all slots in the inventory containing any ItemStacks with the given ItemStack + * This will only match slots if both the type and the amount of the stack match + * + * @param item The ItemStack to match against + * @return The Slots found. + */ + public HashMap all(ItemStack item); + + /** + * Find the first slot in the inventory containing an ItemStack with the given materialId + * + * @param materialId The materialId to look for + * @return The Slot found. + */ + public int first(int materialId); + + /** + * Find the first slot in the inventory containing an ItemStack with the given material + * + * @param materialId The material to look for + * @return The Slot found. + */ + public int first(Material material); + + /** + * Find the first slot in the inventory containing an ItemStack with the given stack + * This will only match a slot if both the type and the amount of the stack match + * + * @param item The ItemStack to match against + * @return The Slot found. + */ + public int first(ItemStack item); + + /** + * Find the first empty Slot. + * + * @return The first empty Slot found. + */ + public int firstEmpty(); + + /** + * Remove all stacks in the inventory matching the given materialId. + * + * @param materialId The material to remove + */ + public void remove(int materialId); + + /** + * Remove all stacks in the inventory matching the given material. + * + * @param material The material to remove + */ + public void remove(Material material); + + /** + * Remove all stacks in the inventory matching the given stack. + * This will only match a slot if both the type and the amount of the stack match + * + * @param item The ItemStack to match against + */ + public void remove(ItemStack item); + + /** + * Clear out a particular slot in the index + * + * @param index The index to empty. + */ + public void clear(int index); + + /** + * Clear out the whole index + */ + public void clear(); +} diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java new file mode 100644 index 0000000..14de5db --- /dev/null +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -0,0 +1,217 @@ +package org.bukkit.inventory; + +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +/** + * Represents a stack of items + */ +public class ItemStack { + private int type; + private int amount = 0; + private MaterialData data = null; + private short durability = 0; + + public ItemStack(final int type) { + this(type, 0); + } + + public ItemStack(final Material type) { + this(type, 0); + } + + public ItemStack(final int type, final int amount) { + this(type, amount, (short) 0); + } + + public ItemStack(final Material type, final int amount) { + this(type.getId(), amount); + } + + public ItemStack(final int type, final int amount, final short damage) { + this(type, amount, damage, null); + } + + public ItemStack(final Material type, final int amount, final short damage) { + this(type.getId(), amount, damage); + } + + public ItemStack(final int type, final int amount, final short damage, final Byte data) { + this.type = type; + this.amount = amount; + this.durability = damage; + if (data != null) { + createData(data); + this.durability = data; + } + } + + public ItemStack(final Material type, final int amount, final short damage, final Byte data) { + this(type.getId(), amount, damage, data); + } + + /** + * Gets the type of this item + * + * @return Type of the items in this stack + */ + public Material getType() { + return Material.getMaterial(type); + } + + /** + * Sets the type of this item
+ *
+ * Note that in doing so you will reset the MaterialData for this stack + * + * @param type New type to set the items in this stack to + */ + public void setType(Material type) { + setTypeId(type.getId()); + } + + /** + * Gets the type id of this item + * + * @return Type Id of the items in this stack + */ + public int getTypeId() { + return type; + } + + /** + * Sets the type id of this item
+ *
+ * Note that in doing so you will reset the MaterialData for this stack + * + * @param type New type id to set the items in this stack to + */ + public void setTypeId(int type) { + this.type = type; + createData((byte) 0); + } + + /** + * Gets the amount of items in this stack + * + * @return Amount of items in this stick + */ + public int getAmount() { + return amount; + } + + /** + * Sets the amount of items in this stack + * + * @param amount New amount of items in this stack + */ + public void setAmount(int amount) { + this.amount = amount; + } + + /** + * Gets the MaterialData for this stack of items + * + * @return MaterialData for this item + */ + public MaterialData getData() { + if (Material.getMaterial(getTypeId()).getData() != null) { + data = Material.getMaterial(getTypeId()).getNewData((byte) this.durability); + } + + return data; + } + + /** + * Sets the MaterialData for this stack of items + * + * @param amount New MaterialData for this item + */ + public void setData(MaterialData data) { + Material mat = getType(); + + if ((mat == null) || (mat.getData() == null)) { + this.data = data; + } else { + if ((data.getClass() == mat.getData()) || (data.getClass() == MaterialData.class)) { + this.data = data; + } else { + throw new IllegalArgumentException("Provided data is not of type " + mat.getData().getName() + ", found " + data.getClass().getName()); + } + } + } + + /** + * Sets the durability of this item + * + * @param durability Durability of this item + */ + public void setDurability(final short durability) { + this.durability = durability; + } + + /** + * Gets the durability of this item + * + * @return Durability of this item + */ + public short getDurability() { + return durability; + } + + /** + * Get the maximum stacksize for the material hold in this ItemStack + * Returns -1 if it has no idea. + * + * @return The maximum you can stack this material to. + */ + public int getMaxStackSize() { + return -1; + } + + private void createData(final byte data) { + Material mat = Material.getMaterial(type); + + if (mat == null) { + this.data = new MaterialData(type, data); + } else { + this.data = mat.getNewData(data); + } + } + + @Override + public String toString() { + return "ItemStack{" + getType().name() + " x " + getAmount() + "}"; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ItemStack)) { + return false; + } + + ItemStack item = (ItemStack) obj; + + return ( + item.getAmount() == getAmount() && + item.getTypeId() == getTypeId() && + item.getDurability() == getDurability() + ); + } + + @Override + public ItemStack clone() { + return new ItemStack(type, amount, durability); + } + + @Override + public int hashCode() { + int hash = 11; + + hash = hash * 19 + 7 * getTypeId(); // Overriding hashCode since equals is overridden, it's just + hash = hash * 7 + 23 * getAmount(); // too bad these are mutable values... Q_Q + hash = hash * 13 + 3 * getDurability(); + + return hash; + } +} diff --git a/src/main/java/org/bukkit/inventory/PlayerInventory.java b/src/main/java/org/bukkit/inventory/PlayerInventory.java new file mode 100644 index 0000000..db655bc --- /dev/null +++ b/src/main/java/org/bukkit/inventory/PlayerInventory.java @@ -0,0 +1,102 @@ +package org.bukkit.inventory; + +/** + * Includes interface to the 4 armor slots + */ +public interface PlayerInventory extends Inventory { + + /** + * Get all ItemStacks from the armor slots + * + * @return All the ItemStacks from the armor slots + */ + public ItemStack[] getArmorContents(); + + /** + * Return the ItemStack from the helmet slot + * + * @return The ItemStack in the helmet slot + */ + public ItemStack getHelmet(); + + /** + * Return the ItemStack from the chestplate slot + * + * @return The ItemStack in the chestplate slot + */ + public ItemStack getChestplate(); + + /** + * Return the ItemStack from the leg slot + * + * @return The ItemStack in the leg slot + */ + public ItemStack getLeggings(); + + /** + * Return the ItemStack from the boots slot + * + * @return The ItemStack in the boots slot + */ + public ItemStack getBoots(); + + /** + * Put the given ItemStacks into the armor slots + * + * @param items The ItemStacks to use as armour + */ + public void setArmorContents(ItemStack[] items); + + /** + * Put the given ItemStack into the helmet slot + * This does not check if the ItemStack is a helmet + * + * @param helmet The ItemStack to use as helmet + */ + public void setHelmet(ItemStack helmet); + + /** + * Put the given ItemStack into the chestplate slot + * This does not check if the ItemStack is a chestplate + * + * @param chestplate The ItemStack to use as chestplate + */ + public void setChestplate(ItemStack chestplate); + + /** + * Put the given ItemStack into the leg slot + * This does not check if the ItemStack is a pair of leggings + * + * @param leggings The ItemStack to use as leggings + */ + public void setLeggings(ItemStack leggings); + + /** + * Put the given ItemStack into the boots slot + * This does not check if the ItemStack is a boots + * + * @param boots The ItemStack to use as boots + */ + public void setBoots(ItemStack boots); + + /** + * Returns the ItemStack currently hold + * + * @return The currently held ItemStack + */ + public ItemStack getItemInHand(); + + /** + * Sets the item in hand + * + * @param stack Stack to set + */ + public void setItemInHand(ItemStack stack); + + /** + * Get the slot number of the currently held item + * + * @return Held item slot number + */ + public int getHeldItemSlot(); +} diff --git a/src/main/java/org/bukkit/inventory/Recipe.java b/src/main/java/org/bukkit/inventory/Recipe.java new file mode 100644 index 0000000..7a01985 --- /dev/null +++ b/src/main/java/org/bukkit/inventory/Recipe.java @@ -0,0 +1,13 @@ +package org.bukkit.inventory; + +/** + * Represents some type of crafting recipe. + */ +public interface Recipe { + + /** + * Get the result of this recipe. + * @return The result stack + */ + ItemStack getResult(); +} diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java new file mode 100644 index 0000000..59969d3 --- /dev/null +++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java @@ -0,0 +1,132 @@ +package org.bukkit.inventory; + +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +import java.util.HashMap; + +/** + * Represents a shaped (ie normal) crafting recipe. + */ +public class ShapedRecipe implements Recipe { + private ItemStack output; + private String[] rows; + private HashMap ingredients = new HashMap(); + + /** + * Create a shaped recipe to craft the specified ItemStack. The constructor merely determines the + * result and type; to set the actual recipe, you'll need to call the appropriate methods. + * @param result The item you want the recipe to create. + * @see ShapedRecipe#shape(String...) + * @see ShapedRecipe#setIngredient(char, Material) + * @see ShapedRecipe#setIngredient(char, Material, int) + * @see ShapedRecipe#setIngredient(char, MaterialData) + */ + public ShapedRecipe(ItemStack result) { + this.output = result; + } + + /** + * Set the shape of this recipe to the specified rows. Each character represents a different + * ingredient; exactly what each character represents is set separately. + * @param shape The rows of the recipe (up to 3 rows). + * @return The changed recipe, so you can chain calls. + */ + public ShapedRecipe shape(String... shape) { + if (shape == null || shape.length > 3 || shape.length < 1) { + throw new IllegalArgumentException("Crafting recipes should be 1, 2, or 3 rows."); + } + for (String row : shape) { + if (row == null || row.length() > 3 || row.length() < 1) { + throw new IllegalArgumentException("Crafting rows should be 1, 2, or 3 characters."); + } + } + this.rows = shape; + + // Remove character mappings for characters that no longer exist in the shape + HashMap ingredientsTemp = this.ingredients; + + this.ingredients = new HashMap(); + for (char key : ingredientsTemp.keySet()) { + try { + setIngredient(key, ingredientsTemp.get(key)); + } catch (IllegalArgumentException e) {} + } + return this; + } + + /** + * Sets the material that a character in the recipe shape refers to. + * @param key The character that represents the ingredient in the shape. + * @param ingredient The ingredient. + * @return The changed recipe, so you can chain calls. + */ + public ShapedRecipe setIngredient(char key, MaterialData ingredient) { + if (!hasKey(key)) { + throw new IllegalArgumentException("Symbol " + key + " does not appear in the shape."); + } + ingredients.put(key, ingredient); + return this; + } + + /** + * Sets the material that a character in the recipe shape refers to. + * @param key The character that represents the ingredient in the shape. + * @param ingredient The ingredient. + * @return The changed recipe, so you can chain calls. + */ + public ShapedRecipe setIngredient(char key, Material ingredient) { + return setIngredient(key, ingredient, 0); + } + + /** + * Sets the material that a character in the recipe shape refers to. + * @param key The character that represents the ingredient in the shape. + * @param ingredient The ingredient. + * @param raw The raw material data as an integer. + * @return The changed recipe, so you can chain calls. + */ + public ShapedRecipe setIngredient(char key, Material ingredient, int raw) { + MaterialData data = ingredient.getNewData((byte) raw); + + if (data == null) { + data = new MaterialData(ingredient, (byte) raw); + } + return setIngredient(key, data); + } + + private boolean hasKey(char c) { + String key = Character.toString(c); + + for (String row : rows) { + if (row.contains(key)) { + return true; + } + } + return false; + } + + /** + * Get the ingredients map. + * @return The mapping of character to ingredients. + */ + public HashMap getIngredientMap() { + return ingredients; + } + + /** + * Get the shape. + * @return The recipe's shape. + */ + public String[] getShape() { + return rows; + } + + /** + * Get the result. + * @return The result stack. + */ + public ItemStack getResult() { + return output; + } +} diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java new file mode 100644 index 0000000..27930c7 --- /dev/null +++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java @@ -0,0 +1,123 @@ +package org.bukkit.inventory; + +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +import java.util.ArrayList; + +/** + * Represents a shapeless recipe, where the arrangement of the ingredients on the crafting grid + * does not matter. + */ +public class ShapelessRecipe implements Recipe { + private ItemStack output; + private ArrayList ingredients = new ArrayList(); + + /** + * Create a shapeless recipe to craft the specified ItemStack. The constructor merely determines the + * result and type; to set the actual recipe, you'll need to call the appropriate methods. + * @param result The item you want the recipe to create. + * @see ShapelessRecipe#addIngredient(Material) + * @see ShapelessRecipe#addIngredient(MaterialData) + */ + public ShapelessRecipe(ItemStack result) { + this.output = result; + } + + /** + * Adds the specified ingredient. + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(MaterialData ingredient) { + return addIngredient(1, ingredient); + } + + /** + * Adds the specified ingredient. + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(Material ingredient) { + return addIngredient(1, ingredient, 0); + } + + /** + * Adds the specified ingredient. + * @param ingredient The ingredient to add. + * @param rawdata The data value. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(Material ingredient, int rawdata) { + return addIngredient(1, ingredient, rawdata); + } + + /** + * Adds multiples of the specified ingredient. + * @param count How many to add (can't be more than 9!) + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(int count, MaterialData ingredient) { + if (ingredients.size() + count > 9) { + throw new IllegalArgumentException("Shapeless recipes cannot have more than 9 ingredients"); + } + while (count-- > 0) { + ingredients.add(ingredient); + } + return this; + } + + /** + * Adds multiples of the specified ingredient. + * @param count How many to add (can't be more than 9!) + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(int count, Material ingredient) { + return addIngredient(count, ingredient, 0); + } + + /** + * Adds multiples of the specified ingredient. + * @param count How many to add (can't be more than 9!) + * @param ingredient The ingredient to add. + * @param rawdata The data value. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(int count, Material ingredient, int rawdata) { + MaterialData data = ingredient.getNewData((byte) rawdata); + + if (data == null) { + data = new MaterialData(ingredient, (byte) rawdata); + } + return addIngredient(count, data); + } + + /** + * Removes an ingredient from the list. If the ingredient occurs multiple times, + * only one instance of it is removed. + * @param ingredient The ingredient to remove + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(MaterialData ingredient) { + this.ingredients.remove(ingredient); + return this; + } + + /** + * Get the result of this recipe. + * @return The result stack. + */ + public ItemStack getResult() { + return output; + } + + /** + * Get the list of ingredients used for this recipe. + * @return The input list + */ + public ArrayList getIngredientList() { + return ingredients; + } +} diff --git a/src/main/java/org/bukkit/inventory/Slot.java b/src/main/java/org/bukkit/inventory/Slot.java new file mode 100644 index 0000000..0e546ca --- /dev/null +++ b/src/main/java/org/bukkit/inventory/Slot.java @@ -0,0 +1,28 @@ +package org.bukkit.inventory; + +/** + * Represents a slot in an inventory + */ +public interface Slot { + + /** + * Gets the inventory this slot belongs to + * + * @return The inventory + */ + public Inventory getInventory(); + + /** + * Get the index this slot belongs to + * + * @return Index of the slot + */ + public int getIndex(); + + /** + * Get the item from the slot. + * + * @return ItemStack in the slot. + */ + public ItemStack getItem(); +} diff --git a/src/main/java/org/bukkit/map/MapCanvas.java b/src/main/java/org/bukkit/map/MapCanvas.java new file mode 100644 index 0000000..28cc2ce --- /dev/null +++ b/src/main/java/org/bukkit/map/MapCanvas.java @@ -0,0 +1,75 @@ +package org.bukkit.map; + +import java.awt.*; + +/** + * Represents a canvas for drawing to a map. Each canvas is associated with a + * specific {@link MapRenderer} and represents that renderer's layer on the map. + */ +public interface MapCanvas { + + /** + * Get the map this canvas is attached to. + * @return The MapView this canvas is attached to. + */ + public MapView getMapView(); + + /** + * Get the cursor collection associated with this canvas. + * @return The MapCursorCollection associated with this canvas. + */ + public MapCursorCollection getCursors(); + + /** + * Set the cursor collection associated with this canvas. This does not + * usually need to be called since a MapCursorCollection is already + * provided. + * @param cursors The MapCursorCollection to associate with this canvas. + */ + public void setCursors(MapCursorCollection cursors); + + /** + * Draw a pixel to the canvas. + * @param x The x coordinate, from 0 to 127. + * @param y The y coordinate, from 0 to 127. + * @param color The color. See {@link MapPalette}. + */ + public void setPixel(int x, int y, byte color); + + /** + * Get a pixel from the canvas. + * @param x The x coordinate, from 0 to 127. + * @param y The y coordinate, from 0 to 127. + * @return The color. See {@link MapPalette}. + */ + public byte getPixel(int x, int y); + + /** + * Get a pixel from the layers below this canvas. + * @param x The x coordinate, from 0 to 127. + * @param y The y coordinate, from 0 to 127. + * @return The color. See {@link MapPalette}. + */ + public byte getBasePixel(int x, int y); + + /** + * Draw an image to the map. The image will be clipped if necessary. + * @param x The x coordinate of the image. + * @param y The y coordinate of the image. + * @param image The Image to draw. + */ + public void drawImage(int x, int y, Image image); + + /** + * Render text to the map using fancy formatting. Newline (\n) characters + * will move down one line and return to the original column, and the text + * color can be changed using sequences such as "§12;", replacing 12 with + * the palette index of the color (see {@link MapPalette}). + * @param map The MapInfo to render to. + * @param x The column to start rendering on. + * @param y The row to start rendering on. + * @param text The formatted text to render. + */ + public void drawText(int x, int y, MapFont font, String text); + +} diff --git a/src/main/java/org/bukkit/map/MapCursor.java b/src/main/java/org/bukkit/map/MapCursor.java new file mode 100644 index 0000000..957db93 --- /dev/null +++ b/src/main/java/org/bukkit/map/MapCursor.java @@ -0,0 +1,160 @@ +package org.bukkit.map; + +/** + * Represents a cursor on a map. + */ +public final class MapCursor { + + private byte x, y; + private byte direction, type; + private boolean visible; + + /** + * Initialize the map cursor. + * @param x The x coordinate, from -128 to 127. + * @param y The y coordinate, from -128 to 127. + * @param direction The facing of the cursor, from 0 to 15. + * @param type The type (color/style) of the map cursor. + * @param visible Whether the cursor is visible by default. + */ + public MapCursor(byte x, byte y, byte direction, byte type, boolean visible) { + this.x = x; + this.y = y; + setDirection(direction); + setRawType(type); + this.visible = visible; + } + + /** + * Get the X position of this cursor. + * @return The X coordinate. + */ + public byte getX() { + return x; + } + + /** + * Get the Y position of this cursor. + * @return The Y coordinate. + */ + public byte getY() { + return y; + } + + /** + * Get the direction of this cursor. + * @return The facing of the cursor, from 0 to 15. + */ + public byte getDirection() { + return direction; + } + + /** + * Get the type of this cursor. + * @return The type (color/style) of the map cursor. + */ + public Type getType() { + return Type.byValue(type); + } + + /** + * Get the type of this cursor. + * @return The type (color/style) of the map cursor. + */ + public byte getRawType() { + return type; + } + + /** + * Get the visibility status of this cursor. + * @return True if visible, false otherwise. + */ + public boolean isVisible() { + return visible; + } + + /** + * Set the X position of this cursor. + * @param x The X coordinate. + */ + public void setX(byte x) { + this.x = x; + } + + /** + * Set the Y position of this cursor. + * @param y The Y coordinate. + */ + public void setY(byte y) { + this.y = y; + } + + /** + * Set the direction of this cursor. + * @param direction The facing of the cursor, from 0 to 15. + */ + public void setDirection(byte direction) { + if (direction < 0 || direction > 15) { + throw new IllegalArgumentException("Direction must be in the range 0-15"); + } + this.direction = direction; + } + + /** + * Set the type of this cursor. + * @param type The type (color/style) of the map cursor. + */ + public void setType(Type type) { + setRawType(type.value); + } + + /** + * Set the type of this cursor. + * @param type The type (color/style) of the map cursor. + */ + public void setRawType(byte type) { + if (type < 0 || type > 15) { + throw new IllegalArgumentException("Type must be in the range 0-15"); + } + this.type = type; + } + + /** + * Set the visibility status of this cursor. + * @param visible True if visible. + */ + public void setVisible(boolean visible) { + this.visible = visible; + } + + /** + * Represents the standard types of map cursors. More may be made available + * by texture packs - the value is used by the client as an index in the + * file './misc/mapicons.png' from minecraft.jar or from a texture pack. + */ + public enum Type { + WHITE_POINTER(0), + GREEN_POINTER(1), + RED_POINTER(2), + BLUE_POINTER(3), + WHITE_CROSS(4); + + private byte value; + + private Type(int value) { + this.value = (byte) value; + } + + public byte getValue() { + return value; + } + + public static Type byValue(byte value) { + for (Type t : values()) { + if (t.value == value) return t; + } + return null; + } + } + +} diff --git a/src/main/java/org/bukkit/map/MapCursorCollection.java b/src/main/java/org/bukkit/map/MapCursorCollection.java new file mode 100644 index 0000000..ac5d3e3 --- /dev/null +++ b/src/main/java/org/bukkit/map/MapCursorCollection.java @@ -0,0 +1,86 @@ +package org.bukkit.map; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents all the map cursors on a {@link MapCanvas}. Like MapCanvas, a + * MapCursorCollection is linked to a specific {@link MapRenderer}. + */ +public final class MapCursorCollection { + + private List cursors = new ArrayList(); + + /** + * Get the amount of cursors in this collection. + * @return The size of this collection. + */ + public int size() { + return cursors.size(); + } + + /** + * Get a cursor from this collection. + * @param index The index of the cursor. + * @return The MapCursor. + */ + public MapCursor getCursor(int index) { + return cursors.get(index); + } + + /** + * Remove a cursor from the collection. + * @param cursor The MapCursor to remove. + * @return Whether the cursor was removed successfully. + */ + public boolean removeCursor(MapCursor cursor) { + return cursors.remove(cursor); + } + + /** + * Add a cursor to the collection. + * @param cursor The MapCursor to add. + * @return The MapCursor that was passed. + */ + public MapCursor addCursor(MapCursor cursor) { + cursors.add(cursor); + return cursor; + } + + /** + * Add a cursor to the collection. + * @param x The x coordinate, from -128 to 127. + * @param y The y coordinate, from -128 to 127. + * @param direction The facing of the cursor, from 0 to 15. + * @return The newly added MapCursor. + */ + public MapCursor addCursor(int x, int y, byte direction) { + return addCursor(x, y, direction, (byte) 0, true); + } + + /** + * Add a cursor to the collection. + * @param x The x coordinate, from -128 to 127. + * @param y The y coordinate, from -128 to 127. + * @param direction The facing of the cursor, from 0 to 15. + * @param type The type (color/style) of the map cursor. + * @return The newly added MapCursor. + */ + public MapCursor addCursor(int x, int y, byte direction, byte type) { + return addCursor(x, y, direction, type, true); + } + + /** + * Add a cursor to the collection. + * @param x The x coordinate, from -128 to 127. + * @param y The y coordinate, from -128 to 127. + * @param direction The facing of the cursor, from 0 to 15. + * @param type The type (color/style) of the map cursor. + * @param visible Whether the cursor is visible. + * @return The newly added MapCursor. + */ + public MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible) { + return addCursor(new MapCursor((byte) x, (byte) y, direction, type, visible)); + } + +} diff --git a/src/main/java/org/bukkit/map/MapFont.java b/src/main/java/org/bukkit/map/MapFont.java new file mode 100644 index 0000000..6d38d52 --- /dev/null +++ b/src/main/java/org/bukkit/map/MapFont.java @@ -0,0 +1,127 @@ +package org.bukkit.map; + +import java.util.HashMap; + +/** + * Represents a bitmap font drawable to a map. + */ +public class MapFont { + + private final HashMap chars = new HashMap(); + private int height = 0; + protected boolean malleable = true; + + /** + * Set the sprite for a given character. + * @param ch The character to set the sprite for. + * @param sprite The CharacterSprite to set. + * @throws IllegalStateException if this font is static. + */ + public void setChar(char ch, CharacterSprite sprite) { + if (!malleable) { + throw new IllegalStateException("this font is not malleable"); + } + + chars.put(ch, sprite); + if (sprite.getHeight() > height) { + height = sprite.getHeight(); + } + } + + /** + * Get the sprite for a given character. + * @param ch The character to get the sprite for. + * @return The CharacterSprite associated with the character, or null if there is none. + */ + public CharacterSprite getChar(char ch) { + return chars.get(ch); + } + + /** + * Get the width of the given text as it would be rendered using this font. + * @param text The text. + * @return The width in pixels. + */ + public int getWidth(String text) { + if (!isValid(text)) { + throw new IllegalArgumentException("text contains invalid characters"); + } + + int result = 0; + for (int i = 0; i < text.length(); ++i) { + result += chars.get(text.charAt(i)).getWidth(); + } + return result; + } + + /** + * Get the height of this font. + * @return The height of the font. + */ + public int getHeight() { + return height; + } + + /** + * Check whether the given text is valid. + * @param text The text. + * @return True if the string contains only defined characters, false otherwise. + */ + public boolean isValid(String text) { + for (int i = 0; i < text.length(); ++i) { + char ch = text.charAt(i); + if (ch == '\u00A7' || ch == '\n') continue; + if (chars.get(ch) == null) return false; + } + return true; + } + + /** + * Represents the graphics for a single character in a MapFont. + */ + public static class CharacterSprite { + + private final int width; + private final int height; + private final boolean[] data; + + public CharacterSprite(int width, int height, boolean[] data) { + this.width = width; + this.height = height; + this.data = data; + + if (data.length != width * height) { + throw new IllegalArgumentException("size of data does not match dimensions"); + } + } + + /** + * Get the value of a pixel of the character. + * @param row The row, in the range [0,8). + * @param col The column, in the range [0,8). + * @return True if the pixel is solid, false if transparent. + */ + public boolean get(int row, int col) { + if (row < 0 || col < 0 || row >= height || col >= width) return false; + return data[row * width + col]; + } + + /** + * Get the width of the character sprite. + * @return The width of the character. + */ + public int getWidth() { + return width; + } + + /** + * Get the height of the character sprite. + * @return The height of the character. + */ + public int getHeight() { + return height; + } + + } + +} diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java new file mode 100644 index 0000000..460a0f0 --- /dev/null +++ b/src/main/java/org/bukkit/map/MapPalette.java @@ -0,0 +1,148 @@ +package org.bukkit.map; + +import java.awt.*; +import java.awt.image.BufferedImage; + +/** + * Represents the palette that map items use. + */ +public final class MapPalette { + + // Internal mechanisms + + private MapPalette() {} + + private static Color c(int r, int g, int b) { + return new Color(r, g, b); + } + + private static double getDistance(Color c1, Color c2) { + double rmean = (c1.getRed() + c2.getRed()) / 2.0; + double r = c1.getRed() - c2.getRed(); + double g = c1.getGreen() - c2.getGreen(); + int b = c1.getBlue() - c2.getBlue(); + double weightR = 2 + rmean / 256.0; + double weightG = 4.0; + double weightB = 2 + (255 - rmean) / 256.0; + return weightR * r * r + weightG * g * g + weightB * b * b; + } + + private static final Color[] colors = { + new Color(0, 0, 0, 0), new Color(0, 0, 0, 0), + new Color(0, 0, 0, 0), new Color(0, 0, 0, 0), + c(89,125,39), c(109,153,48), c(27,178,56), c(109,153,48), + c(174,164,115), c(213,201,140), c(247,233,163), c(213,201,140), + c(117,117,117), c(144,144,144), c(167,167,167), c(144,144,144), + c(180,0,0), c(220,0,0), c(255,0,0), c(220,0,0), + c(112,112,180), c(138,138,220), c(160,160,255), c(138,138,220), + c(117,117,117), c(144,144,144), c(167,167,167), c(144,144,144), + c(0,87,0), c(0,106,0), c(0,124,0), c(0,106,0), + c(180,180,180), c(220,220,220), c(255,255,255), c(220,220,220), + c(115,118,129), c(141,144,158), c(164,168,184), c(141,144,158), + c(129,74,33), c(157,91,40), c(183,106,47), c(157,91,40), + c(79,79,79), c(96,96,96), c(112,112,112), c(96,96,96), + c(45,45,180), c(55,55,220), c(64,64,255), c(55,55,220), + c(73,58,35), c(89,71,43), c(104,83,50), c(89,71,43) + }; + + // Interface + + /** + * The base color ranges. Each entry corresponds to four colors of varying + * shades with values entry to entry + 3. + */ + public static final byte TRANSPARENT = 0; + public static final byte LIGHT_GREEN = 4; + public static final byte LIGHT_BROWN = 8; + public static final byte GRAY_1 = 12; + public static final byte RED = 16; + public static final byte PALE_BLUE = 20; + public static final byte GRAY_2 = 24; + public static final byte DARK_GREEN = 28; + public static final byte WHITE = 32; + public static final byte LIGHT_GRAY = 36; + public static final byte BROWN = 40; + public static final byte DARK_GRAY = 44; + public static final byte BLUE = 48; + public static final byte DARK_BROWN = 52; + /** + * Resize an image to 128x128. + * @param image The image to resize. + * @return The resized image. + */ + public static BufferedImage resizeImage(Image image) { + BufferedImage result = new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = result.createGraphics(); + graphics.drawImage(image, 0, 0, 128, 128, null); + graphics.dispose(); + return result; + } + + /** + * Convert an Image to a byte[] using the palette. + * @param image The image to convert. + * @return A byte[] containing the pixels of the image. + */ + public static byte[] imageToBytes(Image image) { + BufferedImage temp = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = temp.createGraphics(); + graphics.drawImage(image, 0, 0, null); + graphics.dispose(); + + int[] pixels = new int[temp.getWidth() * temp.getHeight()]; + temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); + + byte[] result = new byte[temp.getWidth() * temp.getHeight()]; + for (int i = 0; i < pixels.length; i++) { + result[i] = matchColor(new Color(pixels[i])); + } + return result; + } + + /** + * Get the index of the closest matching color in the palette to the given color. + * @param r The red component of the color. + * @param b The blue component of the color. + * @param g The green component of the color. + * @return The index in the palette. + */ + public static byte matchColor(int r, int g, int b) { + return matchColor(new Color(r, g, b)); + } + + /** + * Get the index of the closest matching color in the palette to the given color. + * @param color The Color to match. + * @return The index in the palette. + */ + public static byte matchColor(Color color) { + if (color.getAlpha() < 128) return 0; + + int index = 0; + double best = -1; + + for (int i = 4; i < colors.length; i++) { + double distance = getDistance(color, colors[i]); + if (distance < best || best == -1) { + best = distance; + index = i; + } + } + + return (byte) index; + } + + /** + * Get the value of the given color in the palette. + * @param index The index in the palette. + * @return The Color of the palette entry. + */ + public static Color getColor(byte index) { + if (index < 0 || index >= colors.length) { + throw new IndexOutOfBoundsException(); + } else { + return colors[index]; + } + } + +} diff --git a/src/main/java/org/bukkit/map/MapRenderer.java b/src/main/java/org/bukkit/map/MapRenderer.java new file mode 100644 index 0000000..f0ffd6b --- /dev/null +++ b/src/main/java/org/bukkit/map/MapRenderer.java @@ -0,0 +1,50 @@ +package org.bukkit.map; + +import org.bukkit.entity.Player; + +/** + * Represents a renderer for a map. + */ +public abstract class MapRenderer { + + private boolean contextual; + + /** + * Initialize the map renderer base to be non-contextual. See {@link isContextual}. + */ + public MapRenderer() { + this(false); + } + + /** + * Initialize the map renderer base with the given contextual status. + * @param contextual Whether the renderer is contextual. See {@link isContextual}. + */ + public MapRenderer(boolean contextual) { + this.contextual = contextual; + } + + /** + * Get whether the renderer is contextual, i.e. has different canvases for + * different players. + * @return True if contextual, false otherwise. + */ + final public boolean isContextual() { + return contextual; + } + + /** + * Initialize this MapRenderer for the given map. + * @param map The MapView being initialized. + */ + public void initialize(MapView map) { } + + /** + * Render to the given map. + * @param map The MapView being rendered to. + * @param canvas The canvas to use for rendering. + * @param player The player who triggered the rendering. + */ + abstract public void render(MapView map, MapCanvas canvas, Player player); + +} diff --git a/src/main/java/org/bukkit/map/MapView.java b/src/main/java/org/bukkit/map/MapView.java new file mode 100644 index 0000000..00e0aab --- /dev/null +++ b/src/main/java/org/bukkit/map/MapView.java @@ -0,0 +1,134 @@ +package org.bukkit.map; + +import org.bukkit.World; + +import java.util.List; + +/** + * Represents a map item. + */ +public interface MapView { + + /** + * An enum representing all possible scales a map can be set to. + */ + public static enum Scale { + CLOSEST(0), + CLOSE(1), + NORMAL(2), + FAR(3), + FARTHEST(4); + + private byte value; + + private Scale(int value) { + this.value = (byte) value; + } + + /** + * Get the scale given the raw value. + */ + public static Scale valueOf(byte value) { + switch(value) { + case 0: return CLOSEST; + case 1: return CLOSE; + case 2: return NORMAL; + case 3: return FAR; + case 4: return FARTHEST; + default: return null; + } + } + + /** + * Get the raw value of this scale level. + */ + public byte getValue() { + return value; + } + } + + /** + * Get the ID of this map item. Corresponds to the damage value of a map + * in an inventory. + * @return The ID of the map. + */ + public short getId(); + + /** + * Check whether this map is virtual. A map is virtual if its lowermost + * MapRenderer is plugin-provided. + * @return Whether the map is virtual. + */ + public boolean isVirtual(); + + /** + * Get the scale of this map. + * @return The scale of the map. + */ + public Scale getScale(); + + /** + * Set the scale of this map. + * @param scale The scale to set. + */ + public void setScale(Scale scale); + + /** + * Get the center X position of this map. + * @return The center X position. + */ + public int getCenterX(); + + /** + * Get the center Z position of this map. + * @return The center Z position. + */ + public int getCenterZ(); + + /** + * Set the center X position of this map. + * @param x The center X position. + */ + public void setCenterX(int x); + + /** + * Set the center Z position of this map. + * @param z The center Z position. + */ + public void setCenterZ(int z); + + /** + * Get the world that this map is associated with. Primarily used by the + * internal renderer, but may be used by external renderers. May return + * null if the world the map is associated with is not loaded. + * @return The World this map is associated with. + */ + public World getWorld(); + + /** + * Set the world that this map is associated with. The world is used by + * the internal renderer, and may also be used by external renderers. + * @param world The World to associate this map with. + */ + public void setWorld(World world); + + /** + * Get a list of MapRenderers currently in effect. + * @return A List containing each map renderer. + */ + public List getRenderers(); + + /** + * Add a renderer to this map. + * @param renderer The MapRenderer to add. + */ + public void addRenderer(MapRenderer renderer); + + /** + * Remove a renderer from this map. + * @param renderer The MapRenderer to remove. + * @return True if the renderer was successfully removed. + */ + public boolean removeRenderer(MapRenderer renderer); + +} diff --git a/src/main/java/org/bukkit/map/MinecraftFont.java b/src/main/java/org/bukkit/map/MinecraftFont.java new file mode 100644 index 0000000..d84d5c2 --- /dev/null +++ b/src/main/java/org/bukkit/map/MinecraftFont.java @@ -0,0 +1,328 @@ +package org.bukkit.map; + +/** + * Represents the built-in Minecraft font. + */ +public class MinecraftFont extends MapFont { + + private static final int spaceSize = 2; + + private static final String fontChars = + " !\"#$%&'()*+,-./0123456789:;<=>?" + + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + + "'abcdefghijklmnopqrstuvwxyz{|}~\u007F" + + "\u00C7\u00FC\u00E9\u00E2\u00E4\u00E0\u00E5\u00E7" + // Çüéâäàåç + "\u00EA\u00EB\u00E8\u00EF\u00EE\u00EC\u00C4\u00C5" + // êëèïîìÄÅ + "\u00C9\u00E6\u00C6\u00F4\u00F6\u00F2\u00FB\u00F9" + // ÉæÆôöòûù + "\u00FF\u00D6\u00DC\u00F8\u00A3\u00D8\u00D7\u0191" + // ÿÖÜø£Ø×ƒ + "\u00E1\u00ED\u00F3\u00FA\u00F1\u00D1\u00AA\u00BA" + // áíóúñѪº + "\u00BF\u00AE\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB"; // ¿®¬½¼¡«» + + private static final int[][] fontData = new int[][] { + /* null */ {0,0,0,0,0,0,0,0}, + /* 1 */ {126,129,165,129,189,153,129,126}, + /* 2 */ {126,255,219,255,195,231,255,126}, + /* 3 */ {54,127,127,127,62,28,8,0}, + /* 4 */ {8,28,62,127,62,28,8,0}, + /* 5 */ {28,62,28,127,127,62,28,62}, + /* 6 */ {8,8,28,62,127,62,28,62}, + /* 7 */ {0,0,24,60,60,24,0,0}, + /* 8 */ {255,255,231,195,195,231,255,255}, + /* 9 */ {0,60,102,66,66,102,60,0}, + /* 10 */ {255,195,153,189,189,153,195,255}, + /* 11 */ {240,224,240,190,51,51,51,30}, + /* 12 */ {60,102,102,102,60,24,126,24}, + /* 13 */ {252,204,252,12,12,14,15,7}, + /* 14 */ {254,198,254,198,198,230,103,3}, + /* 15 */ {153,90,60,231,231,60,90,153}, + /* 16 */ {1,7,31,127,31,7,1,0}, + /* 17 */ {64,112,124,127,124,112,64,0}, + /* 18 */ {24,60,126,24,24,126,60,24}, + /* 19 */ {102,102,102,102,102,0,102,0}, + /* 20 */ {254,219,219,222,216,216,216,0}, + /* 21 */ {124,198,28,54,54,28,51,30}, + /* 22 */ {0,0,0,0,126,126,126,0}, + /* 23 */ {24,60,126,24,126,60,24,255}, + /* 24 */ {24,60,126,24,24,24,24,0}, + /* 25 */ {24,24,24,24,126,60,24,0}, + /* 26 */ {0,24,48,127,48,24,0,0}, + /* 27 */ {0,12,6,127,6,12,0,0}, + /* 28 */ {0,0,3,3,3,127,0,0}, + /* 29 */ {0,36,102,255,102,36,0,0}, + /* 30 */ {0,24,60,126,255,255,0,0}, + /* 31 */ {0,255,255,126,60,24,0,0}, + /* */ {0,0,0,0,0,0,0,0}, + /* ! */ {1,1,1,1,1,0,1,0}, + /* " */ {10,10,5,0,0,0,0,0}, + /* # */ {10,10,31,10,31,10,10,0}, + /* $ */ {4,30,1,14,16,15,4,0}, + /* % */ {17,9,8,4,2,18,17,0}, + /* & */ {4,10,4,22,13,9,22,0}, + /* ' */ {2,2,1,0,0,0,0,0}, + /* ( */ {12,2,1,1,1,2,12,0}, + /* ) */ {3,4,8,8,8,4,3,0}, + /* * */ {0,0,9,6,9,0,0,0}, + /* + */ {0,4,4,31,4,4,0,0}, + /* , */ {0,0,0,0,0,1,1,1}, + /* - */ {0,0,0,31,0,0,0,0}, + /* . */ {0,0,0,0,0,1,1,0}, + /* / */ {16,8,8,4,2,2,1,0}, + /* 0 */ {14,17,25,21,19,17,14,0}, + /* 1 */ {4,6,4,4,4,4,31,0}, + /* 2 */ {14,17,16,12,2,17,31,0}, + /* 3 */ {14,17,16,12,16,17,14,0}, + /* 4 */ {24,20,18,17,31,16,16,0}, + /* 5 */ {31,1,15,16,16,17,14,0}, + /* 6 */ {12,2,1,15,17,17,14,0}, + /* 7 */ {31,17,16,8,4,4,4,0}, + /* 8 */ {14,17,17,14,17,17,14,0}, + /* 9 */ {14,17,17,30,16,8,6,0}, + /* : */ {0,1,1,0,0,1,1,0}, + /* ; */ {0,1,1,0,0,1,1,1}, + /* < */ {8,4,2,1,2,4,8,0}, + /* = */ {0,0,31,0,0,31,0,0}, + /* > */ {1,2,4,8,4,2,1,0}, + /* ? */ {14,17,16,8,4,0,4,0}, + /* @ */ {30,33,45,45,61,1,30,0}, + /* A */ {14,17,31,17,17,17,17,0}, + /* B */ {15,17,15,17,17,17,15,0}, + /* C */ {14,17,1,1,1,17,14,0}, + /* D */ {15,17,17,17,17,17,15,0}, + /* E */ {31,1,7,1,1,1,31,0}, + /* F */ {31,1,7,1,1,1,1,0}, + /* G */ {30,1,25,17,17,17,14,0}, + /* H */ {17,17,31,17,17,17,17,0}, + /* I */ {7,2,2,2,2,2,7,0}, + /* J */ {16,16,16,16,16,17,14,0}, + /* K */ {17,9,7,9,17,17,17,0}, + /* L */ {1,1,1,1,1,1,31,0}, + /* M */ {17,27,21,17,17,17,17,0}, + /* N */ {17,19,21,25,17,17,17,0}, + /* O */ {14,17,17,17,17,17,14,0}, + /* P */ {15,17,15,1,1,1,1,0}, + /* Q */ {14,17,17,17,17,9,22,0}, + /* R */ {15,17,15,17,17,17,17,0}, + /* S */ {30,1,14,16,16,17,14,0}, + /* T */ {31,4,4,4,4,4,4,0}, + /* U */ {17,17,17,17,17,17,14,0}, + /* V */ {17,17,17,17,10,10,4,0}, + /* W */ {17,17,17,17,21,27,17,0}, + /* X */ {17,10,4,10,17,17,17,0}, + /* Y */ {17,10,4,4,4,4,4,0}, + /* Z */ {31,16,8,4,2,1,31,0}, + /* [ */ {7,1,1,1,1,1,7,0}, + /* \ */ {1,2,2,4,8,8,16,0}, + /* ] */ {7,4,4,4,4,4,7,0}, + /* ^ */ {4,10,17,0,0,0,0,0}, + /* _ */ {0,0,0,0,0,0,0,31}, + /* ` */ {1,1,2,0,0,0,0,0}, + /* a */ {0,0,14,16,30,17,30,0}, + /* b */ {1,1,13,19,17,17,15,0}, + /* c */ {0,0,14,17,1,17,14,0}, + /* d */ {16,16,22,25,17,17,30,0}, + /* e */ {0,0,14,17,31,1,30,0}, + /* f */ {12,2,15,2,2,2,2,0}, + /* g */ {0,0,30,17,17,30,16,15}, + /* h */ {1,1,13,19,17,17,17,0}, + /* i */ {1,0,1,1,1,1,1,0}, + /* j */ {16,0,16,16,16,17,17,14}, + /* k */ {1,1,9,5,3,5,9,0}, + /* l */ {1,1,1,1,1,1,2,0}, + /* m */ {0,0,11,21,21,17,17,0}, + /* n */ {0,0,15,17,17,17,17,0}, + /* o */ {0,0,14,17,17,17,14,0}, + /* p */ {0,0,13,19,17,15,1,1}, + /* q */ {0,0,22,25,17,30,16,16}, + /* r */ {0,0,13,19,1,1,1,0}, + /* s */ {0,0,30,1,14,16,15,0}, + /* t */ {2,2,7,2,2,2,4,0}, + /* u */ {0,0,17,17,17,17,30,0}, + /* v */ {0,0,17,17,17,10,4,0}, + /* w */ {0,0,17,17,21,21,30,0}, + /* x */ {0,0,17,10,4,10,17,0}, + /* y */ {0,0,17,17,17,30,16,15}, + /* z */ {0,0,31,8,4,2,31,0}, + /* { */ {12,2,2,1,2,2,12,0}, + /* | */ {1,1,1,0,1,1,1,0}, + /* } */ {3,4,4,8,4,4,3,0}, + /* ~ */ {38,25,0,0,0,0,0,0}, + /* ⌂ */ {0,0,4,10,17,17,31,0}, + /* Ç */ {14,17,1,1,17,14,16,12}, + /* ü */ {10,0,17,17,17,17,30,0}, + /* é */ {24,0,14,17,31,1,30,0}, + /* â */ {14,17,14,16,30,17,30,0}, + /* ä */ {10,0,14,16,30,17,30,0}, + /* à */ {3,0,14,16,30,17,30,0}, + /* å */ {4,0,14,16,30,17,30,0}, + /* ç */ {0,14,17,1,17,14,16,12}, + /* ê */ {14,17,14,17,31,1,30,0}, + /* ë */ {10,0,14,17,31,1,30,0}, + /* è */ {3,0,14,17,31,1,30,0}, + /* ï */ {5,0,2,2,2,2,2,0}, + /* î */ {14,17,4,4,4,4,4,0}, + /* ì */ {3,0,2,2,2,2,2,0}, + /* Ä */ {17,14,17,31,17,17,17,0}, + /* Å */ {4,0,14,17,31,17,17,0}, + /* É */ {24,0,31,1,7,1,31,0}, + /* æ */ {0,0,10,20,30,5,30,0}, + /* Æ */ {30,5,15,5,5,5,29,0}, + /* ô */ {14,17,14,17,17,17,14,0}, + /* ö */ {10,0,14,17,17,17,14,0}, + /* ò */ {3,0,14,17,17,17,14,0}, + /* û */ {14,17,0,17,17,17,30,0}, + /* ù */ {3,0,17,17,17,17,30,0}, + /* ÿ */ {10,0,17,17,17,30,16,15}, + /* Ö */ {17,14,17,17,17,17,14,0}, + /* Ü */ {17,0,17,17,17,17,14,0}, + /* ø */ {0,0,14,25,21,19,14,4}, + /* £ */ {12,18,2,15,2,2,31,0}, + /* Ø */ {14,17,25,21,19,17,14,0}, + /* × */ {0,0,5,2,5,0,0,0}, + /* ƒ */ {8,20,4,14,4,4,5,2}, + /* á */ {24,0,14,16,30,17,30,0}, + /* í */ {3,0,1,1,1,1,1,0}, + /* ó */ {24,0,14,17,17,17,14,0}, + /* ú */ {24,0,17,17,17,17,30,0}, + /* ñ */ {31,0,15,17,17,17,17,0}, + /* Ñ */ {31,0,17,19,21,25,17,0}, + /* ª */ {14,16,31,30,0,31,0,0}, + /* º */ {14,17,17,14,0,31,0,0}, + /* ¿ */ {4,0,4,2,1,17,14,0}, + /* ® */ {0,30,45,37,43,30,0,0}, + /* ¬ */ {0,0,0,31,16,16,0,0}, + /* ½ */ {17,9,8,4,18,10,25,0}, + /* ¼ */ {17,9,8,4,26,26,17,0}, + /* ¡ */ {0,1,0,1,1,1,1,0}, + /* « */ {0,20,10,5,10,20,0,0}, + /* » */ {0,5,10,20,10,5,0,0}, + /* 176 */ {68,17,68,17,68,17,68,17}, + /* 177 */ {170,85,170,85,170,85,170,85}, + /* 178 */ {219,238,219,119,219,238,219,119}, + /* 179 */ {24,24,24,24,24,24,24,24}, + /* 180 */ {24,24,24,24,31,24,24,24}, + /* 181 */ {24,24,31,24,31,24,24,24}, + /* 182 */ {108,108,108,108,111,108,108,108}, + /* 183 */ {0,0,0,0,127,108,108,108}, + /* 184 */ {0,0,31,24,31,24,24,24}, + /* 185 */ {108,108,111,96,111,108,108,108}, + /* 186 */ {108,108,108,108,108,108,108,108}, + /* 187 */ {0,0,127,96,111,108,108,108}, + /* 188 */ {108,108,111,96,127,0,0,0}, + /* 189 */ {108,108,108,108,127,0,0,0}, + /* 190 */ {24,24,31,24,31,0,0,0}, + /* 191 */ {0,0,0,0,31,24,24,24}, + /* 192 */ {24,24,24,24,248,0,0,0}, + /* 193 */ {24,24,24,24,255,0,0,0}, + /* 194 */ {0,0,0,0,255,24,24,24}, + /* 195 */ {24,24,24,24,248,24,24,24}, + /* 196 */ {0,0,0,0,255,0,0,0}, + /* 197 */ {24,24,24,24,255,24,24,24}, + /* 198 */ {24,24,248,24,248,24,24,24}, + /* 199 */ {108,108,108,108,236,108,108,108}, + /* 200 */ {108,108,236,12,252,0,0,0}, + /* 201 */ {0,0,252,12,236,108,108,108}, + /* 202 */ {108,108,239,0,255,0,0,0}, + /* 203 */ {0,0,255,0,239,108,108,108}, + /* 204 */ {108,108,236,12,236,108,108,108}, + /* 205 */ {0,0,255,0,255,0,0,0}, + /* 206 */ {108,108,239,0,239,108,108,108}, + /* 207 */ {24,24,255,0,255,0,0,0}, + /* 208 */ {108,108,108,108,255,0,0,0}, + /* 209 */ {0,0,255,0,255,24,24,24}, + /* 210 */ {0,0,0,0,255,108,108,108}, + /* 211 */ {108,108,108,108,252,0,0,0}, + /* 212 */ {24,24,248,24,248,0,0,0}, + /* 213 */ {0,0,248,24,248,24,24,24}, + /* 214 */ {0,0,0,0,252,108,108,108}, + /* 215 */ {108,108,108,108,255,108,108,108}, + /* 216 */ {24,24,255,24,255,24,24,24}, + /* 217 */ {24,24,24,24,31,0,0,0}, + /* 218 */ {0,0,0,0,248,24,24,24}, + /* 219 */ {255,255,255,255,255,255,255,255}, + /* 220 */ {0,0,0,0,255,255,255,255}, + /* 221 */ {15,15,15,15,15,15,15,15}, + /* 222 */ {240,240,240,240,240,240,240,240}, + /* 223 */ {255,255,255,255,0,0,0,0}, + /* 224 */ {0,0,110,59,19,59,110,0}, + /* 225 */ {0,30,51,31,51,31,3,3}, + /* 226 */ {0,63,51,3,3,3,3,0}, + /* 227 */ {0,127,54,54,54,54,54,0}, + /* 228 */ {63,51,6,12,6,51,63,0}, + /* 229 */ {0,0,126,27,27,27,14,0}, + /* 230 */ {0,102,102,102,102,62,6,3}, + /* 231 */ {0,110,59,24,24,24,24,0}, + /* 232 */ {63,12,30,51,51,30,12,63}, + /* 233 */ {28,54,99,127,99,54,28,0}, + /* 234 */ {28,54,99,99,54,54,119,0}, + /* 235 */ {56,12,24,62,51,51,30,0}, + /* 236 */ {0,0,126,219,219,126,0,0}, + /* 237 */ {96,48,126,219,219,126,6,3}, + /* 238 */ {28,6,3,31,3,6,28,0}, + /* 239 */ {30,51,51,51,51,51,51,0}, + /* 240 */ {0,63,0,63,0,63,0,0}, + /* 241 */ {12,12,63,12,12,0,63,0}, + /* 242 */ {6,12,24,12,6,0,63,0}, + /* 243 */ {24,12,6,12,24,0,63,0}, + /* 244 */ {112,216,216,24,24,24,24,24}, + /* 245 */ {24,24,24,24,24,27,27,14}, + /* 246 */ {12,12,0,63,0,12,12,0}, + /* 247 */ {0,110,59,0,110,59,0,0}, + /* 248 */ {28,54,54,28,0,0,0,0}, + /* 249 */ {0,0,0,24,24,0,0,0}, + /* 250 */ {0,0,0,0,24,0,0,0}, + /* 251 */ {240,48,48,48,55,54,60,56}, + /* 252 */ {30,54,54,54,54,0,0,0}, + /* 253 */ {14,24,12,6,30,0,0,0}, + /* 254 */ {0,0,60,60,60,60,0,0}, + /* 255 */ {0,0,0,0,0,0,0,0}, + }; + + /** + * A static non-malleable MinecraftFont. + */ + public static final MinecraftFont Font = new MinecraftFont(false); + + /** + * Initialize a new MinecraftFont. + */ + public MinecraftFont() { + this(true); + } + + private MinecraftFont(boolean malleable) { + for (int i = 1; i < fontData.length; ++i) { + char ch = (char) i; + if (i >= 32 && i < 32 + fontChars.length()) { + ch = fontChars.charAt(i - 32); + } + + if (ch == ' ') { + setChar(ch, new CharacterSprite(spaceSize, 8, new boolean[spaceSize * 8])); + continue; + } + + int[] rows = fontData[i]; + int width = 0; + for (int r = 0; r < 8; ++r) { + for (int c = 0; c < 8; ++c) { + if ((rows[r] & (1 << c)) != 0 && c > width) { + width = c; + } + } + } + ++width; + + boolean[] data = new boolean[width * 8]; + for (int r = 0; r < 8; ++r) { + for (int c = 0; c < width; ++c) { + data[r * width + c] = (rows[r] & (1 << c)) != 0; + } + } + + setChar(ch, new CharacterSprite(width, 8, data)); + } + + this.malleable = malleable; + } + +} diff --git a/src/main/java/org/bukkit/material/Attachable.java b/src/main/java/org/bukkit/material/Attachable.java new file mode 100644 index 0000000..1d3f107 --- /dev/null +++ b/src/main/java/org/bukkit/material/Attachable.java @@ -0,0 +1,16 @@ +package org.bukkit.material; + +import org.bukkit.block.BlockFace; + +/** + * Indicates that a block can be attached to another block + */ +public interface Attachable extends Directional { + + /** + * Gets the face that this block is attached on + * + * @return BlockFace attached to + */ + public BlockFace getAttachedFace(); +} diff --git a/src/main/java/org/bukkit/material/Bed.java b/src/main/java/org/bukkit/material/Bed.java new file mode 100644 index 0000000..fd81685 --- /dev/null +++ b/src/main/java/org/bukkit/material/Bed.java @@ -0,0 +1,120 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a bed. + */ +public class Bed extends MaterialData implements Directional { + + /** + * Default constructor for a bed. + */ + public Bed() { + super(Material.BED_BLOCK); + } + + /** + * Instantiate a bed facing in a particular direction. + * @param direction the direction the bed's head is facing + */ + public Bed(BlockFace direction) { + this(); + setFacingDirection(direction); + } + + public Bed(final int type) { + super(type); + } + + public Bed(final Material type) { + super(type); + } + + public Bed(final int type, final byte data) { + super(type, data); + } + + public Bed(final Material type, final byte data) { + super(type, data); + } + + /** + * Determine if this block represents the head of the bed + * + * @return true if this is the head of the bed, false if it is the foot + */ + public boolean isHeadOfBed() { + return (getData() & 0x8) == 0x8; + } + + /** + * Configure this to be either the head or the foot of the bed + * @param isHeadOfBed + */ + public void setHeadOfBed(boolean isHeadOfBed) { + setData((byte) (isHeadOfBed ? (getData() | 0x8) : (getData() & ~0x8))); + } + + /** + * Set which direction the head of the bed is facing. Note that this will + * only affect one of the two blocks the bed is made of. + */ + public void setFacingDirection(BlockFace face) { + byte data; + + switch (face) { + case WEST: + data = 0x0; + break; + + case NORTH: + data = 0x1; + break; + + case EAST: + data = 0x2; + break; + + case SOUTH: + default: + data = 0x3; + } + + if (isHeadOfBed()) { + data |= 0x8; + } + + setData(data); + } + + /** + * Get the direction that this bed's head is facing toward + * + * @return the direction the head of the bed is facing + */ + public BlockFace getFacing() { + byte data = (byte) (getData() & 0x7); + + switch (data) { + case 0x0: + return BlockFace.WEST; + + case 0x1: + return BlockFace.NORTH; + + case 0x2: + return BlockFace.EAST; + + case 0x3: + default: + return BlockFace.SOUTH; + } + } + + @Override + public String toString() { + return (isHeadOfBed() ? "HEAD" : "FOOT") + " of " + super.toString() + " facing " + getFacing(); + } +} diff --git a/src/main/java/org/bukkit/material/Button.java b/src/main/java/org/bukkit/material/Button.java new file mode 100644 index 0000000..849fb13 --- /dev/null +++ b/src/main/java/org/bukkit/material/Button.java @@ -0,0 +1,106 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a button + */ +public class Button extends SimpleAttachableMaterialData implements Redstone { + public Button() { + super(Material.STONE_BUTTON); + } + + public Button(final int type) { + super(type); + } + + public Button(final Material type) { + super(type); + } + + public Button(final int type, final byte data) { + super(type, data); + } + + public Button(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current state of this Material, indicating if it's powered or + * unpowered + * + * @return true if powered, otherwise false + */ + public boolean isPowered() { + return (getData() & 0x8) == 0x8; + } + + /** + * Sets the current state of this button + * + * @param bool + * whether or not the button is powered + */ + public void setPowered(boolean bool) { + setData((byte) (bool ? (getData() | 0x8) : (getData() & ~0x8))); + } + + /** + * Gets the face that this block is attached on + * + * @return BlockFace attached to + */ + public BlockFace getAttachedFace() { + byte data = (byte) (getData() & 0x7); + + switch (data) { + case 0x1: + return BlockFace.NORTH; + + case 0x2: + return BlockFace.SOUTH; + + case 0x3: + return BlockFace.EAST; + + case 0x4: + return BlockFace.WEST; + } + + return null; + } + + /** + * Sets the direction this button is pointing toward + */ + public void setFacingDirection(BlockFace face) { + byte data = (byte) (getData() & 0x8); + + switch (face) { + case SOUTH: + data |= 0x1; + break; + + case NORTH: + data |= 0x2; + break; + + case WEST: + data |= 0x3; + break; + + case EAST: + data |= 0x4; + break; + } + + setData(data); + } + + @Override + public String toString() { + return super.toString() + " " + (isPowered() ? "" : "NOT ") + "POWERED"; + } +} diff --git a/src/main/java/org/bukkit/material/Cake.java b/src/main/java/org/bukkit/material/Cake.java new file mode 100644 index 0000000..c9a047d --- /dev/null +++ b/src/main/java/org/bukkit/material/Cake.java @@ -0,0 +1,71 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +public class Cake extends MaterialData { + public Cake() { + super(Material.CAKE_BLOCK); + } + + public Cake(int type) { + super(type); + } + + public Cake(Material type) { + super(type); + } + + public Cake(int type, byte data) { + super(type, data); + } + + public Cake(Material type, byte data) { + super(type, data); + } + + /** + * Gets the number of slices eaten from this cake + * + * @return The number of slices eaten + */ + public int getSlicesEaten() { + return getData(); + } + + /** + * Gets the number of slices remaining on this cake + * + * @return The number of slices remaining + */ + public int getSlicesRemaining() { + return 6 - getData(); + } + + /** + * Sets the number of slices eaten from this cake + * + * @param n The number of slices eaten + */ + public void setSlicesEaten(int n) { + if (n < 6) { + setData((byte) n); + } // TODO: else destroy the block? Probably not possible though + } + + /** + * Sets the number of slices remaining on this cake + * + * @param n The number of slices remaining + */ + public void setSlicesRemaining(int n) { + if (n > 6) { + n = 6; + } + setData((byte) (6 - n)); + } + + @Override + public String toString() { + return super.toString() + " " + getSlicesEaten() + "/" + getSlicesRemaining() + " slices eaten/remaining"; + } +} diff --git a/src/main/java/org/bukkit/material/Coal.java b/src/main/java/org/bukkit/material/Coal.java new file mode 100644 index 0000000..43dfd93 --- /dev/null +++ b/src/main/java/org/bukkit/material/Coal.java @@ -0,0 +1,57 @@ +package org.bukkit.material; + +import org.bukkit.CoalType; +import org.bukkit.Material; + +/** + * Represents the different types of coals. + */ +public class Coal extends MaterialData { + public Coal() { + super(Material.COAL); + } + + public Coal(CoalType type) { + this(); + setType(type); + } + + public Coal(final int type) { + super(type); + } + + public Coal(final Material type) { + super(type); + } + + public Coal(final int type, final byte data) { + super(type, data); + } + + public Coal(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current type of this coal + * + * @return CoalType of this coal + */ + public CoalType getType() { + return CoalType.getByData(getData()); + } + + /** + * Sets the type of this coal + * + * @param type New type of this coal + */ + public void setType(CoalType type) { + setData(type.getData()); + } + + @Override + public String toString() { + return getType() + " " + super.toString(); + } +} diff --git a/src/main/java/org/bukkit/material/Colorable.java b/src/main/java/org/bukkit/material/Colorable.java new file mode 100644 index 0000000..06cf088 --- /dev/null +++ b/src/main/java/org/bukkit/material/Colorable.java @@ -0,0 +1,27 @@ +package org.bukkit.material; + +import org.bukkit.DyeColor; + +/** + * An object that can be colored. + * + * @author Cogito + * + */ +public interface Colorable { + + /** + * Gets the color of this object. + * + * @return The DyeColor of this object. + */ + public DyeColor getColor(); + + /** + * Sets the color of this object to the specified DyeColor. + * + * @param color The color of the object, as a DyeColor. + */ + public void setColor(DyeColor color); + +} diff --git a/src/main/java/org/bukkit/material/Crops.java b/src/main/java/org/bukkit/material/Crops.java new file mode 100644 index 0000000..c477dce --- /dev/null +++ b/src/main/java/org/bukkit/material/Crops.java @@ -0,0 +1,57 @@ +package org.bukkit.material; + +import org.bukkit.CropState; +import org.bukkit.Material; + +/** + * Represents the different types of crops. + */ +public class Crops extends MaterialData { + public Crops() { + super(Material.CROPS); + } + + public Crops(CropState state) { + this(); + setState(state); + } + + public Crops(final int type) { + super(type); + } + + public Crops(final Material type) { + super(type); + } + + public Crops(final int type, final byte data) { + super(type, data); + } + + public Crops(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current growth state of this crop + * + * @return CropState of this leave + */ + public CropState getState() { + return CropState.getByData(getData()); + } + + /** + * Sets the growth state of this crop + * + * @param state New growth state of this crop + */ + public void setState(CropState state) { + setData(state.getData()); + } + + @Override + public String toString() { + return getState() + " " + super.toString(); + } +} diff --git a/src/main/java/org/bukkit/material/DetectorRail.java b/src/main/java/org/bukkit/material/DetectorRail.java new file mode 100644 index 0000000..a32317c --- /dev/null +++ b/src/main/java/org/bukkit/material/DetectorRail.java @@ -0,0 +1,36 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +/** + * Represents a detector rail + */ +public class DetectorRail extends ExtendedRails implements PressureSensor { + public DetectorRail() { + super(Material.DETECTOR_RAIL); + } + + public DetectorRail(final int type) { + super(type); + } + + public DetectorRail(final Material type) { + super(type); + } + + public DetectorRail(final int type, final byte data) { + super(type, data); + } + + public DetectorRail(final Material type, final byte data) { + super(type, data); + } + + public boolean isPressed() { + return (getData() & 0x8) == 0x8; + } + + public void setPressed(boolean isPressed) { + setData((byte) (isPressed ? (getData() | 0x8) : (getData() & ~0x8))); + } +} diff --git a/src/main/java/org/bukkit/material/Diode.java b/src/main/java/org/bukkit/material/Diode.java new file mode 100644 index 0000000..788bc48 --- /dev/null +++ b/src/main/java/org/bukkit/material/Diode.java @@ -0,0 +1,103 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +public class Diode extends MaterialData implements Directional { + public Diode() { + super(Material.DIODE_BLOCK_ON); + } + + public Diode(int type) { + super(type); + } + + public Diode(Material type) { + super(type); + } + + public Diode(int type, byte data) { + super(type, data); + } + + public Diode(Material type, byte data) { + super(type, data); + } + + /** + * Sets the delay of the repeater + * + * @param delay + * The new delay (1-4) + */ + public void setDelay(int delay) { + if (delay > 4) { + delay = 4; + } + if (delay < 1) { + delay = 1; + } + byte newData = (byte) (getData() & 0x3); + + setData((byte) (newData | ((delay - 1) << 2))); + } + + /** + * Gets the delay of the repeater in ticks + * + * @return The delay (1-4) + */ + public int getDelay() { + return (getData() >> 2) + 1; + } + + public void setFacingDirection(BlockFace face) { + int delay = getDelay(); + byte data; + + switch (face) { + case SOUTH: + data = 0x1; + break; + + case WEST: + data = 0x2; + break; + + case NORTH: + data = 0x3; + break; + + case EAST: + default: + data = 0x0; + } + + setData(data); + setDelay(delay); + } + + public BlockFace getFacing() { + byte data = (byte) (getData() & 0x3); + + switch (data) { + case 0x0: + default: + return BlockFace.EAST; + + case 0x1: + return BlockFace.SOUTH; + + case 0x2: + return BlockFace.WEST; + + case 0x3: + return BlockFace.NORTH; + } + } + + @Override + public String toString() { + return super.toString() + " facing " + getFacing() + " with " + getDelay() + " ticks delay"; + } +} diff --git a/src/main/java/org/bukkit/material/Directional.java b/src/main/java/org/bukkit/material/Directional.java new file mode 100644 index 0000000..8ad23b2 --- /dev/null +++ b/src/main/java/org/bukkit/material/Directional.java @@ -0,0 +1,18 @@ +package org.bukkit.material; + +import org.bukkit.block.BlockFace; + +public interface Directional { + + /** + * Sets the direction that this block is facing in + */ + public void setFacingDirection(BlockFace face); + + /** + * Gets the direction this block is facing + * + * @return the direction this block is facing + */ + public BlockFace getFacing(); +} diff --git a/src/main/java/org/bukkit/material/Dispenser.java b/src/main/java/org/bukkit/material/Dispenser.java new file mode 100644 index 0000000..9931450 --- /dev/null +++ b/src/main/java/org/bukkit/material/Dispenser.java @@ -0,0 +1,35 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a dispenser. + */ +public class Dispenser extends FurnaceAndDispenser { + + public Dispenser() { + super(Material.DISPENSER); + } + + public Dispenser(BlockFace direction) { + this(); + setFacingDirection(direction); + } + + public Dispenser(final int type) { + super(type); + } + + public Dispenser(final Material type) { + super(type); + } + + public Dispenser(final int type, final byte data) { + super(type, data); + } + + public Dispenser(final Material type, final byte data) { + super(type, data); + } +} diff --git a/src/main/java/org/bukkit/material/Door.java b/src/main/java/org/bukkit/material/Door.java new file mode 100644 index 0000000..40ee1e3 --- /dev/null +++ b/src/main/java/org/bukkit/material/Door.java @@ -0,0 +1,126 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a door. + */ +public class Door extends MaterialData implements Directional { + public Door() { + super(Material.WOODEN_DOOR); + } + + public Door(final int type) { + super(type); + } + + public Door(final Material type) { + super(type); + } + + public Door(final int type, final byte data) { + super(type, data); + } + + public Door(final Material type, final byte data) { + super(type, data); + } + + /** + * Check to see if the door is open. + * @return true if the door has swung counterclockwise around its hinge. + */ + public boolean isOpen() { + return ((getData() & 0x4) == 0x4); + } + + /** + * Configure this door to be either open or closed; + * @param isOpen + */ + public void setOpen(boolean isOpen) { + setData((byte) (isOpen ? (getData() | 0x4) : (getData() & ~0x4))); + } + + /** + * @return whether this is the top half of the door + */ + public boolean isTopHalf() { + return ((getData() & 0x8) == 0x8); + } + + /** + * Configure this part of the door to be either the top or the bottom half; + * @param isTopHalf + */ + public void setTopHalf(boolean isTopHalf) { + setData((byte) (isTopHalf ? (getData() | 0x8) : (getData() & ~0x8))); + } + + /** + * @return the location of the hinges + */ + public BlockFace getHingeCorner() { + byte d = getData(); + + if ((d & 0x3) == 0x3) { + return BlockFace.NORTH_WEST; + } else if ((d & 0x1) == 0x1) { + return BlockFace.SOUTH_EAST; + } else if ((d & 0x2) == 0x2) { + return BlockFace.SOUTH_WEST; + } + + return BlockFace.NORTH_EAST; + } + + @Override + public String toString() { + return (isTopHalf() ? "TOP" : "BOTTOM") + " half of " + (isOpen() ? "an OPEN " : "a CLOSED ") + super.toString() + " with hinges " + getHingeCorner(); + } + + /** + * Set the direction that this door should is facing. + * @param face the direction + */ + public void setFacingDirection(BlockFace face) { + byte data = (byte) (getData() & 0x12); + switch (face) { + case EAST: + data |= 0x1; + break; + + case SOUTH: + data |= 0x2; + break; + + case WEST: + data |= 0x3; + break; + } + setData(data); + } + + /** + * Get the direction that this door is facing. + * @return the direction + */ + public BlockFace getFacing() { + byte data = (byte) (getData() & 0x3); + switch (data) { + case 0: + return BlockFace.NORTH; + + case 1: + return BlockFace.EAST; + + case 2: + return BlockFace.SOUTH; + + case 3: + return BlockFace.WEST; + } + return null; // shouldn't happen + } +} diff --git a/src/main/java/org/bukkit/material/Dye.java b/src/main/java/org/bukkit/material/Dye.java new file mode 100644 index 0000000..347dc8e --- /dev/null +++ b/src/main/java/org/bukkit/material/Dye.java @@ -0,0 +1,52 @@ +package org.bukkit.material; + +import org.bukkit.DyeColor; +import org.bukkit.Material; + +/** + * Represents dye + */ +public class Dye extends MaterialData implements Colorable { + public Dye() { + super(Material.INK_SACK); + } + + public Dye(final int type) { + super(type); + } + + public Dye(final Material type) { + super(type); + } + + public Dye(final int type, final byte data) { + super(type, data); + } + + public Dye(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current color of this dye + * + * @return DyeColor of this dye + */ + public DyeColor getColor() { + return DyeColor.getByData((byte) (15 - getData())); + } + + /** + * Sets the color of this dye + * + * @param color New color of this dye + */ + public void setColor(DyeColor color) { + setData((byte) (15 - color.getData())); + } + + @Override + public String toString() { + return getColor() + " DYE(" + getData() + ")"; + } +} diff --git a/src/main/java/org/bukkit/material/ExtendedRails.java b/src/main/java/org/bukkit/material/ExtendedRails.java new file mode 100644 index 0000000..a86a44f --- /dev/null +++ b/src/main/java/org/bukkit/material/ExtendedRails.java @@ -0,0 +1,47 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * This is the superclass for the {@link DetectorRail} and {@link PoweredRail} classes + */ +public class ExtendedRails extends Rails { + public ExtendedRails(final int type) { + super(type); + } + + public ExtendedRails(final Material type) { + super(type); + } + + public ExtendedRails(final int type, final byte data) { + super(type, data); + } + + public ExtendedRails(final Material type, final byte data) { + super(type, data); + } + + @Override + public boolean isCurve() { + return false; + } + + @Override + protected byte getConvertedData() { + return (byte) (getData() & 0x7); + } + + @Override + public void setDirection(BlockFace face, boolean isOnSlope) { + boolean extraBitSet = (getData() & 0x8) == 0x8; + + if (face != BlockFace.NORTH && face != BlockFace.SOUTH && face != BlockFace.EAST && face != BlockFace.WEST) { + throw new IllegalArgumentException("Detector rails and powered rails cannot be set on a curve!"); + } + + super.setDirection(face, isOnSlope); + setData((byte) (extraBitSet ? (getData() | 0x8) : (getData() & ~0x8))); + } +} diff --git a/src/main/java/org/bukkit/material/Furnace.java b/src/main/java/org/bukkit/material/Furnace.java new file mode 100644 index 0000000..b80fe53 --- /dev/null +++ b/src/main/java/org/bukkit/material/Furnace.java @@ -0,0 +1,39 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a furnace. + */ +public class Furnace extends FurnaceAndDispenser { + + public Furnace() { + super(Material.FURNACE); + } + + /** + * Instantiate a furnace facing in a particular direction. + * @param direction the direction the furnace's "opening" is facing + */ + public Furnace(BlockFace direction) { + this(); + setFacingDirection(direction); + } + + public Furnace(final int type) { + super(type); + } + + public Furnace(final Material type) { + super(type); + } + + public Furnace(final int type, final byte data) { + super(type, data); + } + + public Furnace(final Material type, final byte data) { + super(type, data); + } +} diff --git a/src/main/java/org/bukkit/material/FurnaceAndDispenser.java b/src/main/java/org/bukkit/material/FurnaceAndDispenser.java new file mode 100644 index 0000000..9505fb7 --- /dev/null +++ b/src/main/java/org/bukkit/material/FurnaceAndDispenser.java @@ -0,0 +1,73 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a furnace or a dispenser. + */ +public class FurnaceAndDispenser extends MaterialData implements Directional { + public FurnaceAndDispenser(final int type) { + super(type); + } + + public FurnaceAndDispenser(final Material type) { + super(type); + } + + public FurnaceAndDispenser(final int type, final byte data) { + super(type, data); + } + + public FurnaceAndDispenser(final Material type, final byte data) { + super(type, data); + } + + public void setFacingDirection(BlockFace face) { + byte data; + + switch (face) { + case EAST: + data = 0x2; + break; + + case WEST: + data = 0x3; + break; + + case NORTH: + data = 0x4; + break; + + case SOUTH: + default: + data = 0x5; + } + + setData(data); + } + + public BlockFace getFacing() { + byte data = getData(); + + switch (data) { + case 0x2: + return BlockFace.EAST; + + case 0x3: + return BlockFace.WEST; + + case 0x4: + return BlockFace.NORTH; + + case 0x5: + default: + return BlockFace.SOUTH; + } + } + + @Override + public String toString() { + return super.toString() + " facing " + getFacing(); + } +} diff --git a/src/main/java/org/bukkit/material/Jukebox.java b/src/main/java/org/bukkit/material/Jukebox.java new file mode 100644 index 0000000..20b8404 --- /dev/null +++ b/src/main/java/org/bukkit/material/Jukebox.java @@ -0,0 +1,84 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +import java.util.HashSet; + +public class Jukebox extends MaterialData { + private static HashSet recordTypes = new HashSet(); + static { + recordTypes.add(Material.GOLD_RECORD); + recordTypes.add(Material.GREEN_RECORD); + } + + public Jukebox() { + super(Material.JUKEBOX); + } + + public Jukebox(int type) { + super(type); + } + + public Jukebox(Material type) { + super((recordTypes.contains(type)) ? Material.JUKEBOX : type); + if (recordTypes.contains(type)) { + setPlaying(type); + } + } + + public Jukebox(int type, byte data) { + super(type, data); + } + + public Jukebox(Material type, byte data) { + super(type, data); + } + + /** + * Gets the type of record currently playing + * + * @return The type of record (Material.GOLD_RECORD or Material.GREEN_RECORD), or null for none. + */ + public Material getPlaying() { + switch ((int) getData()) { + default: + case 0x0: + return null; + + case 0x1: + return Material.GOLD_RECORD; + + case 0x2: + return Material.GREEN_RECORD; + } + } + + /** + * Sets the type of record currently playing + * + * @param rec The type of record (Material.GOLD_RECORD or Material.GREEN_RECORD), or null for none. + */ + public void setPlaying(Material rec) { + if (rec == null) { + setData((byte) 0x0); + } else { + switch (rec) { + case GOLD_RECORD: + setData((byte) 0x1); + break; + + case GREEN_RECORD: + setData((byte) 0x2); + break; + + default: + setData((byte) 0x0); + } + } + } + + @Override + public String toString() { + return super.toString() + " playing " + getPlaying(); + } +} diff --git a/src/main/java/org/bukkit/material/Ladder.java b/src/main/java/org/bukkit/material/Ladder.java new file mode 100644 index 0000000..a29cb52 --- /dev/null +++ b/src/main/java/org/bukkit/material/Ladder.java @@ -0,0 +1,82 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents Ladder data + */ +public class Ladder extends SimpleAttachableMaterialData { + public Ladder() { + super(Material.LADDER); + } + + public Ladder(final int type) { + super(type); + } + + public Ladder(final Material type) { + super(type); + } + + public Ladder(final int type, final byte data) { + super(type, data); + } + + public Ladder(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the face that this block is attached on + * + * @return BlockFace attached to + */ + public BlockFace getAttachedFace() { + byte data = getData(); + + switch (data) { + case 0x2: + return BlockFace.WEST; + + case 0x3: + return BlockFace.EAST; + + case 0x4: + return BlockFace.SOUTH; + + case 0x5: + return BlockFace.NORTH; + } + + return null; + } + + /** + * Sets the direction this ladder is facing + */ + public void setFacingDirection(BlockFace face) { + byte data = (byte) 0x0; + + switch (face) { + case WEST: + data = 0x2; + break; + + case EAST: + data = 0x3; + break; + + case SOUTH: + data = 0x4; + break; + + case NORTH: + data = 0x5; + break; + } + + setData(data); + + } +} diff --git a/src/main/java/org/bukkit/material/Leaves.java b/src/main/java/org/bukkit/material/Leaves.java new file mode 100644 index 0000000..8b8e0d7 --- /dev/null +++ b/src/main/java/org/bukkit/material/Leaves.java @@ -0,0 +1,57 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.TreeSpecies; + +/** + * Represents the different types of leaves. + */ +public class Leaves extends MaterialData { + public Leaves() { + super(Material.LEAVES); + } + + public Leaves(TreeSpecies species) { + this(); + setSpecies(species); + } + + public Leaves(final int type) { + super(type); + } + + public Leaves(final Material type) { + super(type); + } + + public Leaves(final int type, final byte data) { + super(type, data); + } + + public Leaves(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current species of this leave + * + * @return TreeSpecies of this leave + */ + public TreeSpecies getSpecies() { + return TreeSpecies.getByData(getData()); + } + + /** + * Sets the species of this leave + * + * @param species New species of this leave + */ + public void setSpecies(TreeSpecies species) { + setData(species.getData()); + } + + @Override + public String toString() { + return getSpecies() + " " + super.toString(); + } +} diff --git a/src/main/java/org/bukkit/material/Lever.java b/src/main/java/org/bukkit/material/Lever.java new file mode 100644 index 0000000..a5bf384 --- /dev/null +++ b/src/main/java/org/bukkit/material/Lever.java @@ -0,0 +1,121 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a lever + */ +public class Lever extends SimpleAttachableMaterialData implements Redstone { + public Lever() { + super(Material.LEVER); + } + + public Lever(final int type) { + super(type); + } + + public Lever(final Material type) { + super(type); + } + + public Lever(final int type, final byte data) { + super(type, data); + } + + public Lever(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current state of this Material, indicating if it's powered or + * unpowered + * + * @return true if powered, otherwise false + */ + public boolean isPowered() { + return (getData() & 0x8) == 0x8; + } + + /** + * Set this lever to be powered or not. + * @param isPowered whether the lever should be powered or not + */ + public void setPowered(boolean isPowered) { + setData((byte) (isPowered ? (getData() | 0x8) : (getData() & ~0x8))); + } + + /** + * Gets the face that this block is attached on + * + * @return BlockFace attached to + */ + public BlockFace getAttachedFace() { + byte data = (byte) (getData() & 0x7); + + switch (data) { + case 0x1: + return BlockFace.NORTH; + + case 0x2: + return BlockFace.SOUTH; + + case 0x3: + return BlockFace.EAST; + + case 0x4: + return BlockFace.WEST; + + case 0x5: + case 0x6: + return BlockFace.DOWN; + } + + return null; + } + + /** + * Sets the direction this lever is pointing in + */ + public void setFacingDirection(BlockFace face) { + byte data = (byte) (getData() & 0x8); + + if (getAttachedFace() == BlockFace.DOWN) { + switch (face) { + case WEST: + case EAST: + data |= 0x5; + break; + + case SOUTH: + case NORTH: + data |= 0x6; + break; + } + } else { + switch (face) { + case SOUTH: + data |= 0x1; + break; + + case NORTH: + data |= 0x2; + break; + + case WEST: + data |= 0x3; + break; + + case EAST: + data |= 0x4; + break; + } + } + setData(data); + } + + @Override + public String toString() { + return super.toString() + " facing " + getFacing() + " " + (isPowered() ? "" : "NOT ") + "POWERED"; + } +} diff --git a/src/main/java/org/bukkit/material/LongGrass.java b/src/main/java/org/bukkit/material/LongGrass.java new file mode 100644 index 0000000..8413519 --- /dev/null +++ b/src/main/java/org/bukkit/material/LongGrass.java @@ -0,0 +1,57 @@ +package org.bukkit.material; + +import org.bukkit.GrassSpecies; +import org.bukkit.Material; + +/** + * Represents the different types of long grasses. + */ +public class LongGrass extends MaterialData { + public LongGrass() { + super(Material.LOG); + } + + public LongGrass(GrassSpecies species) { + this(); + setSpecies(species); + } + + public LongGrass(final int type) { + super(type); + } + + public LongGrass(final Material type) { + super(type); + } + + public LongGrass(final int type, final byte data) { + super(type, data); + } + + public LongGrass(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current species of this grass + * + * @return GrassSpecies of this grass + */ + public GrassSpecies getSpecies() { + return GrassSpecies.getByData(getData()); + } + + /** + * Sets the species of this grass + * + * @param species New species of this grass + */ + public void setSpecies(GrassSpecies species) { + setData(species.getData()); + } + + @Override + public String toString() { + return getSpecies() + " " + super.toString(); + } +} diff --git a/src/main/java/org/bukkit/material/MaterialData.java b/src/main/java/org/bukkit/material/MaterialData.java new file mode 100644 index 0000000..c77fb1b --- /dev/null +++ b/src/main/java/org/bukkit/material/MaterialData.java @@ -0,0 +1,104 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +/** + * Handles specific metadata for certain items or blocks + */ +public class MaterialData { + private final int type; + private byte data = 0; + + public MaterialData(final int type) { + this(type, (byte) 0); + } + + public MaterialData(final Material type) { + this(type, (byte) 0); + } + + public MaterialData(final int type, final byte data) { + this.type = type; + this.data = data; + } + + public MaterialData(final Material type, final byte data) { + this(type.getId(), data); + } + + /** + * Gets the raw data in this material + * + * @return Raw data + */ + public byte getData() { + return data; + } + + /** + * Sets the raw data of this material + * + * @param data New raw data + */ + public void setData(byte data) { + this.data = data; + } + + /** + * Gets the Material that this MaterialData represents + * + * @return Material represented by this MaterialData + */ + public Material getItemType() { + return Material.getMaterial(type); + } + + /** + * Gets the Material Id that this MaterialData represents + * + * @return Material Id represented by this MaterialData + */ + public int getItemTypeId() { + return type; + } + + /** + * Creates a new ItemStack based on this MaterialData + * + * @return New ItemStack containing a copy of this MaterialData + */ + public ItemStack toItemStack() { + return new ItemStack(type, 0, data); + } + + /** + * Creates a new ItemStack based on this MaterialData + * + * @return New ItemStack containing a copy of this MaterialData + */ + public ItemStack toItemStack(int amount) { + return new ItemStack(type, amount, data); + } + + @Override + public String toString() { + return getItemType() + "(" + getData() + ")"; + } + + @Override + public int hashCode() { + return ((getItemTypeId() << 8) ^ getData()); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof MaterialData) { + MaterialData md = (MaterialData) obj; + + return (md.getItemTypeId() == getItemTypeId() && md.getData() == getData()); + } else { + return false; + } + } +} diff --git a/src/main/java/org/bukkit/material/PistonBaseMaterial.java b/src/main/java/org/bukkit/material/PistonBaseMaterial.java new file mode 100644 index 0000000..4a219bb --- /dev/null +++ b/src/main/java/org/bukkit/material/PistonBaseMaterial.java @@ -0,0 +1,92 @@ + +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Material data for the piston base block + */ +public class PistonBaseMaterial extends MaterialData implements Directional, Redstone { + public PistonBaseMaterial(final int type) { + super(type); + } + + public PistonBaseMaterial(final Material type) { + super(type); + } + + public PistonBaseMaterial(final int type, final byte data) { + super(type, data); + } + + public PistonBaseMaterial(final Material type, final byte data) { + super(type, data); + } + + public void setFacingDirection(BlockFace face) { + byte data = (byte)(getData() & 0x8); + + switch (face) { + case UP: + data |= 1; + break; + case EAST: + data |= 2; + break; + case WEST: + data |= 3; + break; + case NORTH: + data |= 4; + break; + case SOUTH: + data |= 5; + break; + } + setData(data); + } + + public BlockFace getFacing() { + byte dir = (byte)(getData() & 7); + + switch (dir) { + case 0: + return BlockFace.DOWN; + case 1: + return BlockFace.UP; + case 2: + return BlockFace.EAST; + case 3: + return BlockFace.WEST; + case 4: + return BlockFace.NORTH; + case 5: + return BlockFace.SOUTH; + default: + return BlockFace.SELF; + } + } + + public boolean isPowered() { + return (getData() & 0x8) == 0x8; + } + + /** + * Sets the current state of this piston + * + * @param powered true if the piston is extended & powered, or false + */ + public void setPowered(boolean powered) { + setData((byte) (powered ? (getData() | 0x8) : (getData() & ~0x8))); + } + + /** + * Checks if this piston base is sticky, and returns true if so + * + * @return true if this piston is "sticky", or false + */ + public boolean isSticky() { + return this.getItemType() == Material.PISTON_STICKY_BASE; + } +} diff --git a/src/main/java/org/bukkit/material/PistonExtensionMaterial.java b/src/main/java/org/bukkit/material/PistonExtensionMaterial.java new file mode 100644 index 0000000..2d727a9 --- /dev/null +++ b/src/main/java/org/bukkit/material/PistonExtensionMaterial.java @@ -0,0 +1,92 @@ + +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Material data for the piston extension block + */ +public class PistonExtensionMaterial extends MaterialData implements Attachable { + public PistonExtensionMaterial(final int type) { + super(type); + } + + public PistonExtensionMaterial(final Material type) { + super(type); + } + + public PistonExtensionMaterial(final int type, final byte data) { + super(type, data); + } + + public PistonExtensionMaterial(final Material type, final byte data) { + super(type, data); + } + + public void setFacingDirection(BlockFace face) { + byte data = (byte)(getData() & 0x8); + + switch (face) { + case UP: + data |= 1; + break; + case EAST: + data |= 2; + break; + case WEST: + data |= 3; + break; + case NORTH: + data |= 4; + break; + case SOUTH: + data |= 5; + break; + } + setData(data); + } + + public BlockFace getFacing() { + byte dir = (byte)(getData() & 7); + + switch (dir) { + case 0: + return BlockFace.DOWN; + case 1: + return BlockFace.UP; + case 2: + return BlockFace.EAST; + case 3: + return BlockFace.WEST; + case 4: + return BlockFace.NORTH; + case 5: + return BlockFace.SOUTH; + default: + return BlockFace.SELF; + } + } + + /** + * Checks if this piston extension is sticky, and returns true if so + * + * @return true if this piston is "sticky", or false + */ + public boolean isSticky() { + return (getData() & 8) == 8; + } + + /** + * Sets whether or not this extension is sticky + * + * @param sticky true if sticky, otherwise false + */ + public void setSticky(boolean sticky) { + setData((byte) (sticky ? (getData() | 0x8) : (getData() & ~0x8))); + } + + public BlockFace getAttachedFace() { + return getFacing().getOppositeFace(); + } +} diff --git a/src/main/java/org/bukkit/material/PoweredRail.java b/src/main/java/org/bukkit/material/PoweredRail.java new file mode 100644 index 0000000..27c19c8 --- /dev/null +++ b/src/main/java/org/bukkit/material/PoweredRail.java @@ -0,0 +1,40 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +/** + * Represents a powered rail + */ +public class PoweredRail extends ExtendedRails implements Redstone { + public PoweredRail() { + super(Material.POWERED_RAIL); + } + + public PoweredRail(final int type) { + super(type); + } + + public PoweredRail(final Material type) { + super(type); + } + + public PoweredRail(final int type, final byte data) { + super(type, data); + } + + public PoweredRail(final Material type, final byte data) { + super(type, data); + } + + public boolean isPowered() { + return (getData() & 0x8) == 0x8; + } + + /** + * Set whether this PoweredRail should be powered or not. + * @param isPowered whether or not the rail is powered + */ + public void setPowered(boolean isPowered) { + setData((byte) (isPowered ? (getData() | 0x8) : (getData() & ~0x8))); + } +} diff --git a/src/main/java/org/bukkit/material/PressurePlate.java b/src/main/java/org/bukkit/material/PressurePlate.java new file mode 100644 index 0000000..3946cbc --- /dev/null +++ b/src/main/java/org/bukkit/material/PressurePlate.java @@ -0,0 +1,37 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +/** + * Represents a pressure plate + */ +public class PressurePlate extends MaterialData implements PressureSensor { + public PressurePlate() { + super(Material.WOOD_PLATE); + } + + public PressurePlate(int type) { + super(type); + } + + public PressurePlate(Material type) { + super(type); + } + + public PressurePlate(int type, byte data) { + super(type, data); + } + + public PressurePlate(Material type, byte data) { + super(type, data); + } + + public boolean isPressed() { + return getData() == 0x1; + } + + @Override + public String toString() { + return super.toString() + (isPressed() ? " PRESSED" : ""); + } +} diff --git a/src/main/java/org/bukkit/material/PressureSensor.java b/src/main/java/org/bukkit/material/PressureSensor.java new file mode 100644 index 0000000..de20bd3 --- /dev/null +++ b/src/main/java/org/bukkit/material/PressureSensor.java @@ -0,0 +1,5 @@ +package org.bukkit.material; + +public interface PressureSensor { + public boolean isPressed(); +} diff --git a/src/main/java/org/bukkit/material/Pumpkin.java b/src/main/java/org/bukkit/material/Pumpkin.java new file mode 100644 index 0000000..4e08bec --- /dev/null +++ b/src/main/java/org/bukkit/material/Pumpkin.java @@ -0,0 +1,91 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a pumpkin. + */ +public class Pumpkin extends MaterialData implements Directional { + + public Pumpkin() { + super(Material.PUMPKIN); + } + + /** + * Instantiate a pumpkin facing in a particular direction. + * @param direction the direction the pumkin's face is facing + */ + public Pumpkin(BlockFace direction) { + this(); + setFacingDirection(direction); + } + + public Pumpkin(final int type) { + super(type); + } + + public Pumpkin(final Material type) { + super(type); + } + + public Pumpkin(final int type, final byte data) { + super(type, data); + } + + public Pumpkin(final Material type, final byte data) { + super(type, data); + } + + public boolean isLit() { + return getItemType() == Material.JACK_O_LANTERN; + } + + public void setFacingDirection(BlockFace face) { + byte data; + + switch (face) { + case EAST: + data = 0x0; + break; + + case SOUTH: + data = 0x1; + break; + + case WEST: + data = 0x2; + break; + + case NORTH: + default: + data = 0x3; + } + + setData(data); + } + + public BlockFace getFacing() { + byte data = getData(); + + switch (data) { + case 0x0: + return BlockFace.EAST; + + case 0x1: + return BlockFace.SOUTH; + + case 0x2: + return BlockFace.WEST; + + case 0x3: + default: + return BlockFace.SOUTH; + } + } + + @Override + public String toString() { + return super.toString() + " facing " + getFacing() + " " + (isLit() ? "" : "NOT ") + "LIT"; + } +} diff --git a/src/main/java/org/bukkit/material/Rails.java b/src/main/java/org/bukkit/material/Rails.java new file mode 100644 index 0000000..3d6a959 --- /dev/null +++ b/src/main/java/org/bukkit/material/Rails.java @@ -0,0 +1,150 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents minecart rails. + */ +public class Rails extends MaterialData { + + public Rails() { + super(Material.RAILS); + } + + public Rails(final int type) { + super(type); + } + + public Rails(final Material type) { + super(type); + } + + public Rails(final int type, final byte data) { + super(type, data); + } + + public Rails(final Material type, final byte data) { + super(type, data); + } + + /** + * @return the whether this track is set on a slope + */ + public boolean isOnSlope() { + byte d = getConvertedData(); + + return (d == 0x2 || d == 0x3 || d == 0x4 || d == 0x5); + } + + /** + * @return the whether this track is set as a curve + */ + public boolean isCurve() { + byte d = getConvertedData(); + + return (d == 0x6 || d == 0x7 || d == 0x8 || d == 0x9); + } + + /** + * @return the direction these tracks are set
+ * Note that tracks are bidirectional and that the direction + * returned is the ascending direction if the track is set on a + * slope. If it is set as a curve, the corner of the track is + * returned. + */ + public BlockFace getDirection() { + byte d = getConvertedData(); + + switch (d) { + case 0x0: + default: + return BlockFace.WEST; + + case 0x1: + return BlockFace.SOUTH; + + case 0x2: + return BlockFace.SOUTH; + + case 0x3: + return BlockFace.NORTH; + + case 0x4: + return BlockFace.EAST; + + case 0x5: + return BlockFace.WEST; + + case 0x6: + return BlockFace.NORTH_EAST; + + case 0x7: + return BlockFace.SOUTH_EAST; + + case 0x8: + return BlockFace.SOUTH_WEST; + + case 0x9: + return BlockFace.NORTH_WEST; + } + } + + @Override + public String toString() { + return super.toString() + " facing " + getDirection() + (isCurve() ? " on a curve" : (isOnSlope() ? " on a slope" : "")); + } + + /** + * Return the data without the extended properties used by {@link PoweredRail} and {@link DetectorRail}. Overridden in {@link ExtendedRails} + * @return the data without the extended part + */ + protected byte getConvertedData() { + return getData(); + } + + /** + * Set the direction of these tracks
+ * Note that tracks are bidirectional and that the direction + * returned is the ascending direction if the track is set on a + * slope. If it is set as a curve, the corner of the track should + * be supplied. + * @param face the direction the track should be facing + * @param isOnSlope whether or not the track should be on a slope + */ + public void setDirection(BlockFace face, boolean isOnSlope) { + switch (face) { + case SOUTH: + setData((byte) (isOnSlope ? 0x2 : 0x1)); + break; + + case NORTH: + setData((byte) (isOnSlope ? 0x3 : 0x1)); + break; + + case EAST: + setData((byte) (isOnSlope ? 0x4 : 0x0)); + break; + + case WEST: + setData((byte) (isOnSlope ? 0x5 : 0x0)); + break; + + case NORTH_EAST: + setData((byte) 0x6); + break; + + case SOUTH_EAST: + setData((byte) 0x7); + break; + + case SOUTH_WEST: + setData((byte) 0x8); + break; + + case NORTH_WEST: + setData((byte) 0x9); + break; + } + } +} diff --git a/src/main/java/org/bukkit/material/Redstone.java b/src/main/java/org/bukkit/material/Redstone.java new file mode 100644 index 0000000..3e46603 --- /dev/null +++ b/src/main/java/org/bukkit/material/Redstone.java @@ -0,0 +1,15 @@ +package org.bukkit.material; + +/** + * Indicated a Material that may carry or create a Redstone current + */ +public interface Redstone { + + /** + * Gets the current state of this Material, indicating if it's powered or + * unpowered + * + * @return true if powered, otherwise false + */ + public boolean isPowered(); +} diff --git a/src/main/java/org/bukkit/material/RedstoneTorch.java b/src/main/java/org/bukkit/material/RedstoneTorch.java new file mode 100644 index 0000000..85ee722 --- /dev/null +++ b/src/main/java/org/bukkit/material/RedstoneTorch.java @@ -0,0 +1,43 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +/** + * Represents a redstone torch + */ +public class RedstoneTorch extends Torch implements Redstone { + public RedstoneTorch() { + super(Material.REDSTONE_TORCH_ON); + } + + public RedstoneTorch(final int type) { + super(type); + } + + public RedstoneTorch(final Material type) { + super(type); + } + + public RedstoneTorch(final int type, final byte data) { + super(type, data); + } + + public RedstoneTorch(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current state of this Material, indicating if it's powered or + * unpowered + * + * @return true if powered, otherwise false + */ + public boolean isPowered() { + return getItemType() == Material.REDSTONE_TORCH_ON; + } + + @Override + public String toString() { + return super.toString() + " " + (isPowered() ? "" : "NOT ") + "POWERED"; + } +} diff --git a/src/main/java/org/bukkit/material/RedstoneWire.java b/src/main/java/org/bukkit/material/RedstoneWire.java new file mode 100644 index 0000000..1b6264d --- /dev/null +++ b/src/main/java/org/bukkit/material/RedstoneWire.java @@ -0,0 +1,43 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +/** + * Represents redstone wire + */ +public class RedstoneWire extends MaterialData implements Redstone { + public RedstoneWire() { + super(Material.REDSTONE_WIRE); + } + + public RedstoneWire(final int type) { + super(type); + } + + public RedstoneWire(final Material type) { + super(type); + } + + public RedstoneWire(final int type, final byte data) { + super(type, data); + } + + public RedstoneWire(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current state of this Material, indicating if it's powered or + * unpowered + * + * @return true if powered, otherwise false + */ + public boolean isPowered() { + return getData() > 0; + } + + @Override + public String toString() { + return super.toString() + " " + (isPowered() ? "" : "NOT ") + "POWERED"; + } +} diff --git a/src/main/java/org/bukkit/material/Sign.java b/src/main/java/org/bukkit/material/Sign.java new file mode 100644 index 0000000..8068fbb --- /dev/null +++ b/src/main/java/org/bukkit/material/Sign.java @@ -0,0 +1,230 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * MaterialData for signs + */ +public class Sign extends MaterialData implements Attachable { + public Sign() { + super(Material.SIGN_POST); + } + + public Sign(final int type) { + super(type); + } + + public Sign(final Material type) { + super(type); + } + + public Sign(final int type, final byte data) { + super(type, data); + } + + public Sign(final Material type, final byte data) { + super(type, data); + } + + /** + * Check if this sign is attached to a wall + * + * @return true if this sign is attached to a wall, false if set on top of a + * block + */ + public boolean isWallSign() { + return getItemType() == Material.WALL_SIGN; + } + + /** + * Gets the face that this block is attached on + * + * @return BlockFace attached to + */ + public BlockFace getAttachedFace() { + if (isWallSign()) { + byte data = getData(); + + switch (data) { + case 0x2: + return BlockFace.WEST; + + case 0x3: + return BlockFace.EAST; + + case 0x4: + return BlockFace.SOUTH; + + case 0x5: + return BlockFace.NORTH; + } + + return null; + } else { + return BlockFace.DOWN; + } + } + + /** + * Gets the direction that this sign is currently facing + * + * @return BlockFace indicating where this sign is facing + */ + public BlockFace getFacing() { + byte data = getData(); + + if (!isWallSign()) { + switch (data) { + case 0x0: + return BlockFace.WEST; + + case 0x1: + return BlockFace.WEST_NORTH_WEST; + + case 0x2: + return BlockFace.NORTH_WEST; + + case 0x3: + return BlockFace.NORTH_NORTH_WEST; + + case 0x4: + return BlockFace.NORTH; + + case 0x5: + return BlockFace.NORTH_NORTH_EAST; + + case 0x6: + return BlockFace.NORTH_EAST; + + case 0x7: + return BlockFace.EAST_NORTH_EAST; + + case 0x8: + return BlockFace.EAST; + + case 0x9: + return BlockFace.EAST_SOUTH_EAST; + + case 0xA: + return BlockFace.SOUTH_EAST; + + case 0xB: + return BlockFace.SOUTH_SOUTH_EAST; + + case 0xC: + return BlockFace.SOUTH; + + case 0xD: + return BlockFace.SOUTH_SOUTH_WEST; + + case 0xE: + return BlockFace.SOUTH_WEST; + + case 0xF: + return BlockFace.WEST_SOUTH_WEST; + } + + return null; + } else { + return getAttachedFace().getOppositeFace(); + } + } + + public void setFacingDirection(BlockFace face) { + byte data; + + if (isWallSign()) { + switch (face) { + case EAST: + data = 0x2; + break; + + case WEST: + data = 0x3; + break; + + case NORTH: + data = 0x4; + break; + + case SOUTH: + default: + data = 0x5; + } + } else { + switch (face) { + case WEST: + data = 0x0; + break; + + case WEST_NORTH_WEST: + data = 0x1; + break; + + case NORTH_WEST: + data = 0x2; + break; + + case NORTH_NORTH_WEST: + data = 0x3; + break; + + case NORTH: + data = 0x4; + break; + + case NORTH_NORTH_EAST: + data = 0x5; + break; + + case NORTH_EAST: + data = 0x6; + break; + + case EAST_NORTH_EAST: + data = 0x7; + break; + + case EAST: + data = 0x8; + break; + + case EAST_SOUTH_EAST: + data = 0x9; + break; + + case SOUTH_EAST: + data = 0xA; + break; + + case SOUTH_SOUTH_EAST: + data = 0xB; + break; + + case SOUTH: + data = 0xC; + break; + + case SOUTH_SOUTH_WEST: + data = 0xD; + break; + + case WEST_SOUTH_WEST: + data = 0xF; + break; + + case SOUTH_WEST: + default: + data = 0xE; + } + } + + setData(data); + } + + @Override + public String toString() { + return super.toString() + " facing " + getFacing(); + } +} diff --git a/src/main/java/org/bukkit/material/SimpleAttachableMaterialData.java b/src/main/java/org/bukkit/material/SimpleAttachableMaterialData.java new file mode 100644 index 0000000..ec5778f --- /dev/null +++ b/src/main/java/org/bukkit/material/SimpleAttachableMaterialData.java @@ -0,0 +1,45 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Simple utility class for attachable MaterialData subclasses + */ +public abstract class SimpleAttachableMaterialData extends MaterialData implements Attachable { + + public SimpleAttachableMaterialData(int type) { + super(type); + } + + public SimpleAttachableMaterialData(int type, BlockFace direction) { + this(type); + setFacingDirection(direction); + } + + public SimpleAttachableMaterialData(Material type, BlockFace direction) { + this(type); + setFacingDirection(direction); + } + + public SimpleAttachableMaterialData(Material type) { + super(type); + } + + public SimpleAttachableMaterialData(int type, byte data) { + super(type, data); + } + + public SimpleAttachableMaterialData(Material type, byte data) { + super(type, data); + } + + public BlockFace getFacing() { + return getAttachedFace().getOppositeFace(); + } + + @Override + public String toString() { + return super.toString() + " facing " + getFacing(); + } +} diff --git a/src/main/java/org/bukkit/material/Stairs.java b/src/main/java/org/bukkit/material/Stairs.java new file mode 100644 index 0000000..f7e249c --- /dev/null +++ b/src/main/java/org/bukkit/material/Stairs.java @@ -0,0 +1,95 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents stairs. + */ +public class Stairs extends MaterialData implements Directional { + + public Stairs(final int type) { + super(type); + } + + public Stairs(final Material type) { + super(type); + } + + public Stairs(final int type, final byte data) { + super(type, data); + } + + public Stairs(final Material type, final byte data) { + super(type, data); + } + + /** + * @return the direction the stairs ascend towards + */ + public BlockFace getAscendingDirection() { + byte data = getData(); + + switch (data) { + case 0x0: + default: + return BlockFace.SOUTH; + + case 0x1: + return BlockFace.NORTH; + + case 0x2: + return BlockFace.WEST; + + case 0x3: + return BlockFace.EAST; + } + } + + /** + * @return the direction the stairs descend towards + */ + public BlockFace getDescendingDirection() { + return getAscendingDirection().getOppositeFace(); + } + + /** + * Set the direction the stair part of the block is facing + */ + public void setFacingDirection(BlockFace face) { + byte data; + + switch (face) { + case NORTH: + default: + data = 0x0; + break; + + case SOUTH: + data = 0x1; + break; + + case EAST: + data = 0x2; + break; + + case WEST: + data = 0x3; + break; + } + + setData(data); + } + + /** + * @return the direction the stair part of the block is facing + */ + public BlockFace getFacing() { + return getDescendingDirection(); + } + + @Override + public String toString() { + return super.toString() + " facing " + getFacing(); + } +} diff --git a/src/main/java/org/bukkit/material/Step.java b/src/main/java/org/bukkit/material/Step.java new file mode 100644 index 0000000..35d4dba --- /dev/null +++ b/src/main/java/org/bukkit/material/Step.java @@ -0,0 +1,93 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +import java.util.HashSet; + +/** + * Represents the different types of steps. + */ +public class Step extends MaterialData { + private static HashSet stepTypes = new HashSet(); + static { + stepTypes.add(Material.SANDSTONE); + stepTypes.add(Material.WOOD); + stepTypes.add(Material.COBBLESTONE); + stepTypes.add(Material.STONE); + } + + public Step() { + super(Material.STEP); + } + + public Step(final int type) { + super(type); + } + + public Step(final Material type) { + super((stepTypes.contains(type)) ? Material.STEP : type); + if (stepTypes.contains(type)) { + setMaterial(type); + } + } + + public Step(final int type, final byte data) { + super(type, data); + } + + public Step(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current Material this step is made of + * + * @return Material of this step + */ + public Material getMaterial() { + switch ((int) getData()) { + case 1: + return Material.SANDSTONE; + + case 2: + return Material.WOOD; + + case 3: + return Material.COBBLESTONE; + + case 0: + default: + return Material.STONE; + } + } + + /** + * Sets the material this step is made of + * + * @param material New material of this step + */ + public void setMaterial(Material material) { + switch (material) { + case SANDSTONE: + setData((byte) 0x1); + break; + + case WOOD: + setData((byte) 0x2); + break; + + case COBBLESTONE: + setData((byte) 0x3); + break; + + case STONE: + default: + setData((byte) 0x0); + } + } + + @Override + public String toString() { + return getMaterial() + " " + super.toString(); + } +} diff --git a/src/main/java/org/bukkit/material/Torch.java b/src/main/java/org/bukkit/material/Torch.java new file mode 100644 index 0000000..b1fac35 --- /dev/null +++ b/src/main/java/org/bukkit/material/Torch.java @@ -0,0 +1,85 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * MaterialData for torches + */ +public class Torch extends SimpleAttachableMaterialData { + public Torch() { + super(Material.TORCH); + } + + public Torch(final int type) { + super(type); + } + + public Torch(final Material type) { + super(type); + } + + public Torch(final int type, final byte data) { + super(type, data); + } + + public Torch(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the face that this block is attached on + * + * @return BlockFace attached to + */ + public BlockFace getAttachedFace() { + byte data = getData(); + + switch (data) { + case 0x1: + return BlockFace.NORTH; + + case 0x2: + return BlockFace.SOUTH; + + case 0x3: + return BlockFace.EAST; + + case 0x4: + return BlockFace.WEST; + + case 0x5: + return BlockFace.DOWN; + } + + return null; + } + + public void setFacingDirection(BlockFace face) { + byte data; + + switch (face) { + case SOUTH: + data = 0x1; + break; + + case NORTH: + data = 0x2; + break; + + case WEST: + data = 0x3; + break; + + case EAST: + data = 0x4; + break; + + case UP: + default: + data = 0x5; + } + + setData(data); + } +} diff --git a/src/main/java/org/bukkit/material/TrapDoor.java b/src/main/java/org/bukkit/material/TrapDoor.java new file mode 100644 index 0000000..b16835d --- /dev/null +++ b/src/main/java/org/bukkit/material/TrapDoor.java @@ -0,0 +1,83 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a trap door + */ +public class TrapDoor extends SimpleAttachableMaterialData { + public TrapDoor() { + super(Material.TRAP_DOOR); + } + + public TrapDoor(final int type) { + super(type); + } + + public TrapDoor(final Material type) { + super(type); + } + + public TrapDoor(final int type, final byte data) { + super(type, data); + } + + public TrapDoor(final Material type, final byte data) { + super(type, data); + } + + /** + * Check to see if the trap door is open. + * + * @return true if the trap door is open. + */ + public boolean isOpen() { + return ((getData() & 0x4) == 0x4); + } + + public BlockFace getAttachedFace() { + byte data = (byte) (getData() & 0x3); + + switch (data) { + case 0x0: + return BlockFace.WEST; + + case 0x1: + return BlockFace.EAST; + + case 0x2: + return BlockFace.SOUTH; + + case 0x3: + return BlockFace.NORTH; + } + + return null; + + } + + public void setFacingDirection(BlockFace face) { + byte data = (byte) (getData() & 0x4); + + switch (face) { + case WEST: + data |= 0x1; + break; + case NORTH: + data |= 0x2; + break; + case SOUTH: + data |= 0x3; + break; + } + + setData(data); + } + + @Override + public String toString() { + return (isOpen() ? "OPEN " : "CLOSED ") + super.toString() + " with hinges set " + getAttachedFace(); + } + +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/material/Tree.java b/src/main/java/org/bukkit/material/Tree.java new file mode 100644 index 0000000..1d4f0b5 --- /dev/null +++ b/src/main/java/org/bukkit/material/Tree.java @@ -0,0 +1,57 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.TreeSpecies; + +/** + * Represents the different types of Trees. + */ +public class Tree extends MaterialData { + public Tree() { + super(Material.LOG); + } + + public Tree(TreeSpecies species) { + this(); + setSpecies(species); + } + + public Tree(final int type) { + super(type); + } + + public Tree(final Material type) { + super(type); + } + + public Tree(final int type, final byte data) { + super(type, data); + } + + public Tree(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current species of this tree + * + * @return TreeSpecies of this tree + */ + public TreeSpecies getSpecies() { + return TreeSpecies.getByData(getData()); + } + + /** + * Sets the species of this tree + * + * @param species New species of this tree + */ + public void setSpecies(TreeSpecies species) { + setData(species.getData()); + } + + @Override + public String toString() { + return getSpecies() + " " + super.toString(); + } +} diff --git a/src/main/java/org/bukkit/material/Wool.java b/src/main/java/org/bukkit/material/Wool.java new file mode 100644 index 0000000..8f398ac --- /dev/null +++ b/src/main/java/org/bukkit/material/Wool.java @@ -0,0 +1,57 @@ +package org.bukkit.material; + +import org.bukkit.DyeColor; +import org.bukkit.Material; + +/** + * Represents a Wool/Cloth block + */ +public class Wool extends MaterialData implements Colorable { + public Wool() { + super(Material.WOOL); + } + + public Wool(DyeColor color) { + this(); + setColor(color); + } + + public Wool(final int type) { + super(type); + } + + public Wool(final Material type) { + super(type); + } + + public Wool(final int type, final byte data) { + super(type, data); + } + + public Wool(final Material type, final byte data) { + super(type, data); + } + + /** + * Gets the current color of this dye + * + * @return DyeColor of this dye + */ + public DyeColor getColor() { + return DyeColor.getByData(getData()); + } + + /** + * Sets the color of this dye + * + * @param color New color of this dye + */ + public void setColor(DyeColor color) { + setData(color.getData()); + } + + @Override + public String toString() { + return getColor() + " " + super.toString(); + } +} diff --git a/src/main/java/org/bukkit/permissions/Permissible.java b/src/main/java/org/bukkit/permissions/Permissible.java new file mode 100644 index 0000000..f73b14b --- /dev/null +++ b/src/main/java/org/bukkit/permissions/Permissible.java @@ -0,0 +1,107 @@ + +package org.bukkit.permissions; + +import org.bukkit.plugin.Plugin; + +import java.util.Set; + +/** + * Represents an object that may be assigned permissions + */ +public interface Permissible extends ServerOperator { + /** + * Checks if this object contains an override for the specified permission, by fully qualified name + * + * @param name Name of the permission + * @return true if the permission is set, otherwise false + */ + public boolean isPermissionSet(String name); + + /** + * Checks if this object contains an override for the specified {@link Permission} + * + * @param perm Permission to check + * @return true if the permission is set, otherwise false + */ + public boolean isPermissionSet(Permission perm); + + /** + * Gets the value of the specified permission, if set. + * + * If a permission override is not set on this object, the default value of the permission will be returned. + * + * @param name Name of the permission + * @return Value of the permission + */ + public boolean hasPermission(String name); + + /** + * Gets the value of the specified permission, if set. + * + * If a permission override is not set on this object, the default value of the permission will be returned + * + * @param perm Permission to get + * @return Value of the permission + */ + public boolean hasPermission(Permission perm); + + /** + * Adds a new {@link PermissionAttachment} with a single permission by name and value + * + * @param plugin Plugin responsible for this attachment, may not be null or disabled + * @param name Name of the permission to attach + * @param value Value of the permission + * @return The PermissionAttachment that was just created + */ + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value); + + /** + * Adds a new empty {@link PermissionAttachment} to this object + * + * @param plugin Plugin responsible for this attachment, may not be null or disabled + * @return The PermissionAttachment that was just created + */ + public PermissionAttachment addAttachment(Plugin plugin); + + /** + * Temporarily adds a new {@link PermissionAttachment} with a single permission by name and value + * + * @param plugin Plugin responsible for this attachment, may not be null or disabled + * @param name Name of the permission to attach + * @param value Value of the permission + * @param ticks Amount of ticks to automatically remove this attachment after + * @return The PermissionAttachment that was just created + */ + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks); + + /** + * Temporarily adds a new empty {@link PermissionAttachment} to this object + * + * @param plugin Plugin responsible for this attachment, may not be null or disabled + * @param ticks Amount of ticks to automatically remove this attachment after + * @return The PermissionAttachment that was just created + */ + public PermissionAttachment addAttachment(Plugin plugin, int ticks); + + /** + * Removes the given {@link PermissionAttachment} from this object + * + * @param attachment Attachment to remove + * @throws IllegalArgumentException Thrown when the specified attachment isn't part of this object + */ + public void removeAttachment(PermissionAttachment attachment); + + /** + * Recalculates the permissions for this object, if the attachments have changed values. + * + * This should very rarely need to be called from a plugin. + */ + public void recalculatePermissions(); + + /** + * Gets a set containing all of the permissions currently in effect by this object + * + * @return Set of currently effective permissions + */ + public Set getEffectivePermissions(); +} diff --git a/src/main/java/org/bukkit/permissions/PermissibleBase.java b/src/main/java/org/bukkit/permissions/PermissibleBase.java new file mode 100644 index 0000000..947df2f --- /dev/null +++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java @@ -0,0 +1,245 @@ +package org.bukkit.permissions; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; + +import java.util.*; +import java.util.logging.Level; + +/** + * Base Permissible for use in any Permissible object via proxy or extension + */ +public class PermissibleBase implements Permissible { + private ServerOperator opable = null; + private Permissible parent = this; + private final List attachments = new LinkedList(); + private final Map permissions = new HashMap(); + + public PermissibleBase(ServerOperator opable) { + this.opable = opable; + + if (opable instanceof Permissible) { + this.parent = (Permissible)opable; + } + + recalculatePermissions(); + } + + public boolean isOp() { + if (opable == null) { + return false; + } else { + return opable.isOp(); + } + } + + public void setOp(boolean value) { + if (opable == null) { + throw new UnsupportedOperationException("Cannot change op value as no ServerOperator is set"); + } else { + opable.setOp(value); + } + } + + public boolean isPermissionSet(String name) { + if (name == null) { + throw new IllegalArgumentException("Permission name cannot be null"); + } + + return permissions.containsKey(name.toLowerCase()); + } + + public boolean isPermissionSet(Permission perm) { + if (perm == null) { + throw new IllegalArgumentException("Permission cannot be null"); + } + + return isPermissionSet(perm.getName()); + } + + public boolean hasPermission(String inName) { + if (inName == null) { + throw new IllegalArgumentException("Permission name cannot be null"); + } + + String name = inName.toLowerCase(); + + if (isPermissionSet(name)) { + return permissions.get(name).getValue(); + } else { + Permission perm = Bukkit.getServer().getPluginManager().getPermission(name); + + if (perm != null) { + return perm.getDefault().getValue(isOp()); + } else { + return false; + } + } + } + + public boolean hasPermission(Permission perm) { + if (perm == null) { + throw new IllegalArgumentException("Permission cannot be null"); + } + + String name = perm.getName().toLowerCase(); + + if (isPermissionSet(name)) { + return permissions.get(name).getValue(); + } else if (perm != null) { + return perm.getDefault().getValue(isOp()); + } else { + return false; + } + } + + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { + if (name == null) { + throw new IllegalArgumentException("Permission name cannot be null"); + } else if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } else if (!plugin.isEnabled()) { + throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled"); + } + + PermissionAttachment result = addAttachment(plugin); + result.setPermission(name, value); + + recalculatePermissions(); + + return result; + } + + public PermissionAttachment addAttachment(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } else if (!plugin.isEnabled()) { + throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled"); + } + + PermissionAttachment result = new PermissionAttachment(plugin, parent); + + attachments.add(result); + recalculatePermissions(); + + return result; + } + + public void removeAttachment(PermissionAttachment attachment) { + if (attachment == null) { + throw new IllegalArgumentException("Attachment cannot be null"); + } + + if (attachments.contains(attachment)) { + attachments.remove(attachment); + PermissionRemovedExecutor ex = attachment.getRemovalCallback(); + + if (ex != null) { + ex.attachmentRemoved(attachment); + } + + recalculatePermissions(); + } else { + throw new IllegalArgumentException("Given attachment is not part of Permissible object " + parent); + } + } + + public void recalculatePermissions() { + clearPermissions(); + Set defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(isOp()); + Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(isOp(), parent); + + for (Permission perm : defaults) { + String name = perm.getName().toLowerCase(); + permissions.put(name, new PermissionAttachmentInfo(parent, name, null, true)); + Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent); + calculateChildPermissions(perm.getChildren(), false, null); + } + + for (PermissionAttachment attachment : attachments) { + calculateChildPermissions(attachment.getPermissions(), false, attachment); + } + } + + private synchronized void clearPermissions() { + Set perms = permissions.keySet(); + + for (String name : perms) { + Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, parent); + } + + Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, parent); + Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, parent); + + permissions.clear(); + } + + private void calculateChildPermissions(Map children, boolean invert, PermissionAttachment attachment) { + Set keys = children.keySet(); + + for (String name : keys) { + Permission perm = Bukkit.getServer().getPluginManager().getPermission(name); + boolean value = children.get(name) ^ invert; + String lname = name.toLowerCase(); + + permissions.put(lname, new PermissionAttachmentInfo(parent, lname, attachment, value)); + Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent); + + if (perm != null) { + calculateChildPermissions(perm.getChildren(), !value, attachment); + } + } + } + + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { + if (name == null) { + throw new IllegalArgumentException("Permission name cannot be null"); + } else if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } else if (!plugin.isEnabled()) { + throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled"); + } + + PermissionAttachment result = addAttachment(plugin, ticks); + + if (result != null) { + result.setPermission(name, value); + } + + return result; + } + + public PermissionAttachment addAttachment(Plugin plugin, int ticks) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } else if (!plugin.isEnabled()) { + throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled"); + } + + PermissionAttachment result = addAttachment(plugin); + + if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new RemoveAttachmentRunnable(result), ticks) == -1) { + Bukkit.getServer().getLogger().log(Level.WARNING, "Could not add PermissionAttachment to " + parent + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1"); + result.remove(); + return null; + } else { + return result; + } + } + + public Set getEffectivePermissions() { + return new HashSet(permissions.values()); + } + + private class RemoveAttachmentRunnable implements Runnable { + private PermissionAttachment attachment; + + public RemoveAttachmentRunnable(PermissionAttachment attachment) { + this.attachment = attachment; + } + + public void run() { + attachment.remove(); + } + } +} diff --git a/src/main/java/org/bukkit/permissions/Permission.java b/src/main/java/org/bukkit/permissions/Permission.java new file mode 100644 index 0000000..bcda2ab --- /dev/null +++ b/src/main/java/org/bukkit/permissions/Permission.java @@ -0,0 +1,223 @@ + +package org.bukkit.permissions; + +import org.bukkit.Bukkit; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Represents a unique permission that may be attached to a {@link Permissible} + */ +public class Permission { + private final String name; + private final Map children = new LinkedHashMap(); + private PermissionDefault defaultValue = PermissionDefault.FALSE; + private String description; + + public Permission(String name) { + this(name, null, null, null); + } + + public Permission(String name, String description) { + this(name, description, null, null); + } + + public Permission(String name, PermissionDefault defaultValue) { + this(name, null, defaultValue, null); + } + + public Permission(String name, String description, PermissionDefault defaultValue) { + this(name, description, defaultValue, null); + } + + public Permission(String name, Map children) { + this(name, null, null, children); + } + + public Permission(String name, String description, Map children) { + this(name, description, null, children); + } + + public Permission(String name, PermissionDefault defaultValue, Map children) { + this(name, null, defaultValue, children); + } + + public Permission(String name, String description, PermissionDefault defaultValue, Map children) { + this.name = name; + this.description = (description == null) ? "" : description; + this.defaultValue = (defaultValue == null) ? defaultValue.FALSE : defaultValue; + + if (children != null) { + this.children.putAll(children); + } + + recalculatePermissibles(); + } + + /** + * Returns the unique fully qualified name of this Permission + * + * @return Fully qualified name + */ + public String getName() { + return name; + } + + /** + * Gets the children of this permission. + * + * If you change this map in any form, you must call {@link #recalculatePermissibles()} to recalculate all {@link Permissible}s + * + * @return Permission children + */ + public Map getChildren() { + return children; + } + + /** + * Gets the default value of this permission. + * + * @return Default value of this permission. + */ + public PermissionDefault getDefault() { + return defaultValue; + } + + /** + * Sets the default value of this permission. + * + * This will not be saved to disk, and is a temporary operation until the server reloads permissions. + * Changing this default will cause all {@link Permissible}s that contain this permission to recalculate their permissions + * + * @param value The new default to set + */ + public void setDefault(PermissionDefault value) { + if (defaultValue == null) { + throw new IllegalArgumentException("Default value cannot be null"); + } + + defaultValue = value; + recalculatePermissibles(); + } + + /** + * Gets a brief description of this permission, if set + * + * @return Brief description of this permission + */ + public String getDescription() { + return description; + } + + /** + * Sets the description of this permission. + * + * This will not be saved to disk, and is a temporary operation until the server reloads permissions. + * + * @param value The new description to set + */ + public void setDescription(String value) { + if (value == null) { + description = ""; + } else { + description = value; + } + } + + /** + * Gets a set containing every {@link Permissible} that has this permission. + * + * This set cannot be modified. + * + * @return Set containing permissibles with this permission + */ + public Set getPermissibles() { + return Bukkit.getServer().getPluginManager().getPermissionSubscriptions(name); + } + + /** + * Recalculates all {@link Permissible}s that contain this permission. + * + * This should be called after modifying the children, and is automatically called after modifying the default value + */ + public void recalculatePermissibles() { + Set perms = getPermissibles(); + + Bukkit.getServer().getPluginManager().recalculatePermissionDefaults(this); + + for (Permissible p : perms) { + p.recalculatePermissions(); + } + } + + /** + * Loads a Permission from a map of data, usually used from retrieval from a yaml file. + * + * The data may contain the following keys: + * default: Boolean true or false. If not specified, false. + * children: Map of child permissions. If not specified, empty list. + * description: Short string containing a very small description of this description. If not specified, empty string. + * + * @param name Name of the permission + * @param data Map of keys + * @return Permission object + */ + public static Permission loadPermission(String name, Map data) { + if (name == null) { + throw new IllegalArgumentException("Name cannot be null"); + } + if (data == null) { + throw new IllegalArgumentException("Data cannot be null"); + } + String desc = null; + PermissionDefault def = null; + Map children = null; + + if (data.containsKey("default")) { + try { + PermissionDefault value = PermissionDefault.getByName(data.get("default").toString()); + if (value != null) { + def = value; + } else { + throw new IllegalArgumentException("'default' key contained unknown value"); + } + } catch (ClassCastException ex) { + throw new IllegalArgumentException("'default' key is of wrong type", ex); + } + } + + if (data.containsKey("children")) { + try { + children = extractChildren(data); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("'children' key is of wrong type", ex); + } + } + + if (data.containsKey("description")) { + try { + desc = (String)data.get("description"); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("'description' key is of wrong type", ex); + } + } + + return new Permission(name, desc, def, children); + } + + private static Map extractChildren(Map data) { + Map input = (Map)data.get("children"); + Set> entries = input.entrySet(); + + for (Map.Entry entry : entries) { + if (!(entry.getValue() instanceof Boolean)) { + throw new IllegalArgumentException("Child '" + entry.getKey() + "' contains invalid value"); + } + } + + return input; + } +} diff --git a/src/main/java/org/bukkit/permissions/PermissionAttachment.java b/src/main/java/org/bukkit/permissions/PermissionAttachment.java new file mode 100644 index 0000000..58bbb15 --- /dev/null +++ b/src/main/java/org/bukkit/permissions/PermissionAttachment.java @@ -0,0 +1,135 @@ + +package org.bukkit.permissions; + +import org.bukkit.plugin.Plugin; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Holds information about a permission attachment on a {@link Permissible} object + */ +public class PermissionAttachment { + private PermissionRemovedExecutor removed; + private final TreeMap permissions = new TreeMap(); + private final Permissible permissible; + private final Plugin plugin; + + public PermissionAttachment(Plugin plugin, Permissible Permissible) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } else if (!plugin.isEnabled()) { + throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled"); + } + + this.permissible = Permissible; + this.plugin = plugin; + } + + /** + * Gets the plugin responsible for this attachment + * + * @return Plugin responsible for this permission attachment + */ + public Plugin getPlugin() { + return plugin; + } + + /** + * Sets an object to be called for when this attachment is removed from a {@link Permissible}. May be null. + * + * @param ex Object to be called when this is removed + */ + public void setRemovalCallback(PermissionRemovedExecutor ex) { + removed = ex; + } + + /** + * Gets the class that was previously set to be called when this attachment was removed from a {@link Permissible}. May be null. + * + * @return Object to be called when this is removed + */ + public PermissionRemovedExecutor getRemovalCallback() { + return removed; + } + + /** + * Gets the Permissible that this is attached to + * + * @return Permissible containing this attachment + */ + public Permissible getPermissible() { + return permissible; + } + + /** + * Gets a copy of all set permissions and values contained within this attachment. + * + * This map may be modified but will not affect the attachment, as it is a copy. + * + * @return Copy of all permissions and values expressed by this attachment + */ + public Map getPermissions() { + return (Map)permissions.clone(); + } + + /** + * Sets a permission to the given value, by its fully qualified name + * + * @param name Name of the permission + * @param value New value of the permission + */ + public void setPermission(String name, boolean value) { + permissions.put(name.toLowerCase(), value); + permissible.recalculatePermissions(); + } + + /** + * Sets a permission to the given value + * + * @param perm Permission to set + * @param value New value of the permission + */ + public void setPermission(Permission perm, boolean value) { + setPermission(perm.getName(), value); + permissible.recalculatePermissions(); + } + + /** + * Removes the specified permission from this attachment. + * + * If the permission does not exist in this attachment, nothing will happen. + * + * @param name Name of the permission to remove + */ + public void unsetPermission(String name) { + permissions.remove(name.toLowerCase()); + permissible.recalculatePermissions(); + } + + /** + * Removes the specified permission from this attachment. + * + * If the permission does not exist in this attachment, nothing will happen. + * + * @param perm Permission to remove + */ + public void unsetPermission(Permission perm) { + unsetPermission(perm.getName()); + permissible.recalculatePermissions(); + } + + /** + * Removes this attachment from its registered {@link Permissible} + * + * @return true if the permissible was removed successfully, false if it did not exist + */ + public boolean remove() { + try { + permissible.removeAttachment(this); + return true; + } catch (IllegalArgumentException ex) { + return false; + } + } +} diff --git a/src/main/java/org/bukkit/permissions/PermissionAttachmentInfo.java b/src/main/java/org/bukkit/permissions/PermissionAttachmentInfo.java new file mode 100644 index 0000000..b43190d --- /dev/null +++ b/src/main/java/org/bukkit/permissions/PermissionAttachmentInfo.java @@ -0,0 +1,62 @@ + +package org.bukkit.permissions; + +/** + * Holds information on a permission and which {@link PermissionAttachment} provides it + */ +public class PermissionAttachmentInfo { + private final Permissible permissible; + private final String permission; + private final PermissionAttachment attachment; + private final boolean value; + + public PermissionAttachmentInfo(Permissible permissible, String permission, PermissionAttachment attachment, boolean value) { + if (permissible == null) { + throw new IllegalArgumentException("Permissible may not be null"); + } else if (permission == null) { + throw new IllegalArgumentException("Permissions may not be null"); + } + + this.permissible = permissible; + this.permission = permission; + this.attachment = attachment; + this.value = value; + } + + /** + * Gets the permissible this is attached to + * + * @return Permissible this permission is for + */ + public Permissible getPermissible() { + return permissible; + } + + /** + * Gets the permission being set + * + * @return Name of the permission + */ + public String getPermission() { + return permission; + } + + /** + * Gets the attachment providing this permission. This may be null for default + * permissions (usually parent permissions). + * + * @return Attachment + */ + public PermissionAttachment getAttachment() { + return attachment; + } + + /** + * Gets the value of this permission + * + * @return Value of the permission + */ + public boolean getValue() { + return value; + } +} diff --git a/src/main/java/org/bukkit/permissions/PermissionDefault.java b/src/main/java/org/bukkit/permissions/PermissionDefault.java new file mode 100644 index 0000000..78ff2f9 --- /dev/null +++ b/src/main/java/org/bukkit/permissions/PermissionDefault.java @@ -0,0 +1,65 @@ +package org.bukkit.permissions; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the possible default values for permissions + */ +public enum PermissionDefault { + TRUE("true"), + FALSE("false"), + OP("op", "isop", "operator", "isoperator", "admin", "isadmin"), + NOT_OP("!op", "notop", "!operator", "notoperator", "!admin", "notadmin"); + + private final String[] names; + private final static Map lookup = new HashMap(); + + private PermissionDefault(String... names) { + this.names = names; + } + + /** + * Calculates the value of this PermissionDefault for the given operator value + * + * @param op If the target is op + * @return True if the default should be true, or false + */ + public boolean getValue(boolean op) { + switch (this) { + case TRUE: + return true; + case FALSE: + return false; + case OP: + return op; + case NOT_OP: + return !op; + default: + return false; + } + } + + /** + * Looks up a PermissionDefault by name + * + * @param name Name of the default + * @return Specified value, or null if not found + */ + public static PermissionDefault getByName(String name) { + return lookup.get(name.toLowerCase().replaceAll("[^a-z!]", "")); + } + + @Override + public String toString() { + return names[0]; + } + + static { + for (PermissionDefault value : values()) { + for (String name : value.names) { + lookup.put(name, value); + } + } + } +} diff --git a/src/main/java/org/bukkit/permissions/PermissionRemovedExecutor.java b/src/main/java/org/bukkit/permissions/PermissionRemovedExecutor.java new file mode 100644 index 0000000..7dc0912 --- /dev/null +++ b/src/main/java/org/bukkit/permissions/PermissionRemovedExecutor.java @@ -0,0 +1,14 @@ + +package org.bukkit.permissions; + +/** + * Represents a class which is to be notified when a {@link PermissionAttachment} is removed from a {@link Permissible} + */ +public interface PermissionRemovedExecutor { + /** + * Called when a {@link PermissionAttachment} is removed from a {@link Permissible} + * + * @param attachment Attachment which was removed + */ + public void attachmentRemoved(PermissionAttachment attachment); +} diff --git a/src/main/java/org/bukkit/permissions/ServerOperator.java b/src/main/java/org/bukkit/permissions/ServerOperator.java new file mode 100644 index 0000000..721c42a --- /dev/null +++ b/src/main/java/org/bukkit/permissions/ServerOperator.java @@ -0,0 +1,22 @@ +package org.bukkit.permissions; + +import org.bukkit.entity.Player; + +/** + * Represents an object that may become a server operator, such as a {@link Player} + */ +public interface ServerOperator { + /** + * Checks if this object is a server operator + * + * @return true if this is an operator, otherwise false + */ + public boolean isOp(); + + /** + * Sets the operator status of this object + * + * @param value New operator value + */ + public void setOp(boolean value); +} diff --git a/src/main/java/org/bukkit/plugin/AuthorNagException.java b/src/main/java/org/bukkit/plugin/AuthorNagException.java new file mode 100644 index 0000000..d652891 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/AuthorNagException.java @@ -0,0 +1,20 @@ +package org.bukkit.plugin; + +public class AuthorNagException extends RuntimeException { + private final String message; + + /** + * Constructs a new UnknownDependencyException based on the given Exception + * + * @param message Brief message explaining the cause of the exception + * @param throwable Exception that triggered this Exception + */ + public AuthorNagException(final String message) { + this.message = message; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java new file mode 100644 index 0000000..aad7f14 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/EventExecutor.java @@ -0,0 +1,11 @@ +package org.bukkit.plugin; + +import org.bukkit.event.Event; +import org.bukkit.event.Listener; + +/** + * Interface which defines the class for event call backs to plugins + */ +public interface EventExecutor { + public void execute(Listener listener, Event event); +} diff --git a/src/main/java/org/bukkit/plugin/IllegalPluginAccessException.java b/src/main/java/org/bukkit/plugin/IllegalPluginAccessException.java new file mode 100644 index 0000000..88e6cb7 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/IllegalPluginAccessException.java @@ -0,0 +1,20 @@ +package org.bukkit.plugin; + +/** + * Thrown when a plugin attempts to interact with the server when it is not enabled + */ +public class IllegalPluginAccessException extends RuntimeException { + + /** + * Creates a new instance of IllegalPluginAccessException without detail message. + */ + public IllegalPluginAccessException() {} + + /** + * Constructs an instance of IllegalPluginAccessException with the specified detail message. + * @param msg the detail message. + */ + public IllegalPluginAccessException(String msg) { + super(msg); + } +} diff --git a/src/main/java/org/bukkit/plugin/InvalidDescriptionException.java b/src/main/java/org/bukkit/plugin/InvalidDescriptionException.java new file mode 100644 index 0000000..c2de542 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/InvalidDescriptionException.java @@ -0,0 +1,61 @@ +package org.bukkit.plugin; + +/** + * Thrown when attempting to load an invalid PluginDescriptionFile + */ +public class InvalidDescriptionException extends Exception { + private static final long serialVersionUID = 5721389122281775894L; + private final Throwable cause; + private final String message; + + /** + * Constructs a new InvalidDescriptionException based on the given Exception + * + * @param throwable Exception that triggered this Exception + */ + public InvalidDescriptionException(Throwable throwable) { + this(throwable, "Invalid plugin.yml"); + } + + /** + * Constructs a new InvalidDescriptionException with the given message + * + * @param message Brief message explaining the cause of the exception + */ + public InvalidDescriptionException(final String message) { + this(null, message); + } + + /** + * Constructs a new InvalidDescriptionException based on the given Exception + * + * @param message Brief message explaining the cause of the exception + * @param throwable Exception that triggered this Exception + */ + public InvalidDescriptionException(final Throwable throwable, final String message) { + this.cause = null; + this.message = message; + } + + /** + * Constructs a new InvalidDescriptionException + */ + public InvalidDescriptionException() { + this(null, "Invalid plugin.yml"); + } + + /** + * If applicable, returns the Exception that triggered this Exception + * + * @return Inner exception, or null if one does not exist + */ + @Override + public Throwable getCause() { + return cause; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/bukkit/plugin/InvalidPluginException.java b/src/main/java/org/bukkit/plugin/InvalidPluginException.java new file mode 100644 index 0000000..033ff92 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/InvalidPluginException.java @@ -0,0 +1,35 @@ +package org.bukkit.plugin; + +/** + * Thrown when attempting to load an invalid Plugin file + */ +public class InvalidPluginException extends Exception { + private static final long serialVersionUID = -8242141640709409542L; + private final Throwable cause; + + /** + * Constructs a new InvalidPluginException based on the given Exception + * + * @param throwable Exception that triggered this Exception + */ + public InvalidPluginException(Throwable throwable) { + cause = throwable; + } + + /** + * Constructs a new InvalidPluginException + */ + public InvalidPluginException() { + cause = null; + } + + /** + * If applicable, returns the Exception that triggered this Exception + * + * @return Inner exception, or null if one does not exist + */ + @Override + public Throwable getCause() { + return cause; + } +} diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java new file mode 100644 index 0000000..98473bd --- /dev/null +++ b/src/main/java/org/bukkit/plugin/Plugin.java @@ -0,0 +1,102 @@ +package org.bukkit.plugin; + +import com.avaje.ebean.EbeanServer; +import org.bukkit.Server; +import org.bukkit.command.CommandExecutor; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.util.config.Configuration; + +import java.io.File; + +/** + * Represents a Plugin + */ +public interface Plugin extends CommandExecutor { + + /** + * Returns the folder that the plugin data's files are located in. The + * folder may not yet exist. + * + * @return + */ + public File getDataFolder(); + + /** + * Returns the plugin.yaml file containing the details for this plugin + * + * @return Contents of the plugin.yaml file + */ + public PluginDescriptionFile getDescription(); + + /** + * Returns the main configuration file. It should be loaded. + * + * @return + */ + public Configuration getConfiguration(); + + /** + * Gets the associated PluginLoader responsible for this plugin + * + * @return PluginLoader that controls this plugin + */ + public PluginLoader getPluginLoader(); + + /** + * Returns the Server instance currently running this plugin + * + * @return Server running this plugin + */ + public Server getServer(); + + /** + * Returns a value indicating whether or not this plugin is currently enabled + * + * @return true if this plugin is enabled, otherwise false + */ + public boolean isEnabled(); + + /** + * Called when this plugin is disabled + */ + public void onDisable(); + + /** + * Called after a plugin is loaded but before it has been enabled. + * When mulitple plugins are loaded, the onLoad() for all plugins is called before any onEnable() is called. + */ + public void onLoad(); + + /** + * Called when this plugin is enabled + */ + public void onEnable(); + + /** + * Simple boolean if we can still nag to the logs about things + * @return boolean whether we can nag + */ + public boolean isNaggable(); + + /** + * Set naggable state + * @param canNag is this plugin still naggable? + */ + public void setNaggable(boolean canNag); + + /** + * Gets the {@link EbeanServer} tied to this plugin + * + * @return Ebean server instance + */ + public EbeanServer getDatabase(); + + /** + * Gets a {@link ChunkGenerator} for use in a default world, as specified in the server configuration + * + * @param worldName Name of the world that this will be applied to + * @param id Unique ID, if any, that was specified to indicate which generator was requested + * @return ChunkGenerator for use in the default world generation + */ + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id); +} diff --git a/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java new file mode 100644 index 0000000..7e77ffe --- /dev/null +++ b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java @@ -0,0 +1,331 @@ +package org.bukkit.plugin; + +import org.bukkit.Bukkit; +import org.bukkit.permissions.Permission; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; + +import java.io.InputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; + +/** + * Provides access to a Plugins description file, plugin.yaml + */ +public final class PluginDescriptionFile { + private static final Yaml yaml = new Yaml(new SafeConstructor()); + private String name = null; + private String main = null; + private ArrayList depend = null; + private ArrayList softDepend = null; + private String version = null; + private Object commands = null; + private String description = null; + private ArrayList authors = new ArrayList(); + private String website = null; + private boolean database = false; + private boolean visible = true; + private PluginLoadOrder order = PluginLoadOrder.POSTWORLD; + private ArrayList permissions = new ArrayList(); + + @SuppressWarnings("unchecked") + public PluginDescriptionFile(final InputStream stream) throws InvalidDescriptionException { + loadMap((Map) yaml.load(stream)); + } + + /** + * Loads a PluginDescriptionFile from the specified reader + * @param reader + */ + @SuppressWarnings("unchecked") + public PluginDescriptionFile(final Reader reader) throws InvalidDescriptionException { + loadMap((Map) yaml.load(reader)); + } + + /** + * Creates a new PluginDescriptionFile with the given detailed + * + * @param pluginName Name of this plugin + * @param mainClass Full location of the main class of this plugin + */ + public PluginDescriptionFile(final String pluginName, final String pluginVersion, final String mainClass) { + name = pluginName; + version = pluginVersion; + main = mainClass; + } + + /** + * Saves this PluginDescriptionFile to the given writer + * + * @param writer Writer to output this file to + */ + public void save(Writer writer) { + yaml.dump(saveMap(), writer); + } + + /** + * Returns the name of a plugin + * + * @return String name + */ + public String getName() { + return name; + } + + /** + * Returns the version of a plugin + * + * @return String name + */ + public String getVersion() { + return version; + } + + /** + * Returns the name of a plugin including the version + * + * @return String name + */ + public String getFullName() { + return name + " v" + version; + } + + /** + * Returns the main class for a plugin + * + * @return Java classpath + */ + public String getMain() { + return main; + } + + public Object getCommands() { + return commands; + } + + public Object getDepend() { + return depend; + } + + public Object getSoftDepend() { + return softDepend; + } + + public PluginLoadOrder getLoad() { + return order; + } + + /** + * Gets the description of this plugin + * + * return Description of this plugin + */ + public String getDescription() { + return description; + } + + public ArrayList getAuthors() { + return authors; + } + + public String getWebsite() { + return website; + } + + public boolean isDatabaseEnabled() { + return database; + } + + public boolean isVisible() { + return visible; + } + + public void setDatabaseEnabled(boolean database) { + this.database = database; + } + + public ArrayList getPermissions() { + return permissions; + } + + private void loadMap(Map map) throws InvalidDescriptionException { + try { + name = map.get("name").toString(); + + if (!name.matches("^[A-Za-z0-9 _.-]+$")) { + throw new InvalidDescriptionException("name '" + name + "' contains invalid characters."); + } + } catch (NullPointerException ex) { + throw new InvalidDescriptionException(ex, "name is not defined"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "name is of wrong type"); + } + + try { + version = map.get("version").toString(); + } catch (NullPointerException ex) { + throw new InvalidDescriptionException(ex, "version is not defined"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "version is of wrong type"); + } + + try { + main = map.get("main").toString(); + if (main.startsWith("org.bukkit.")) { + throw new InvalidDescriptionException("main may not be within the org.bukkit namespace"); + } + } catch (NullPointerException ex) { + throw new InvalidDescriptionException(ex, "main is not defined"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "main is of wrong type"); + } + + if (map.containsKey("commands")) { + try { + commands = map.get("commands"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "commands are of wrong type"); + } + } + + if (map.containsKey("depend")) { + try { + depend = (ArrayList) map.get("depend"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "depend is of wrong type"); + } + } + + if (map.containsKey("softdepend")) { + try { + softDepend = (ArrayList) map.get("softdepend"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "softdepend is of wrong type"); + } + } + + if (map.containsKey("database")) { + try { + database = (Boolean) map.get("database"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "database is of wrong type"); + } + } + + if (map.containsKey("website")) { + try { + website = (String) map.get("website"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "website is of wrong type"); + } + } + + if (map.containsKey("description")) { + try { + description = (String) map.get("description"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "description is of wrong type"); + } + } + + if (map.containsKey("load")) { + try { + order = PluginLoadOrder.valueOf(((String)map.get("load")).toUpperCase().replaceAll("\\W", "")); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "load is of wrong type"); + } catch (IllegalArgumentException ex) { + throw new InvalidDescriptionException(ex, "load is not a valid choice"); + } + } + + if (map.containsKey("author")) { + try { + String extra = (String) map.get("author"); + + authors.add(extra); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "author is of wrong type"); + } + } + + if (map.containsKey("authors")) { + try { + ArrayList extra = (ArrayList) map.get("authors"); + + authors.addAll(extra); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "authors are of wrong type"); + } + } + + if (map.containsKey("permissions")) { + try { + Map> perms = (Map>) map.get("permissions"); + + loadPermissions(perms); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "permissions are of wrong type"); + } + } + + if (map.containsKey("visible")) { + try { + visible = (Boolean) map.get("visible"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "visible is of wrong type"); + } + } + } + + private Map saveMap() { + Map map = new HashMap(); + + map.put("name", name); + map.put("main", main); + map.put("version", version); + map.put("database", database); + map.put("order", order.toString()); + map.put("visible", visible); + + if (commands != null) { + map.put("command", commands); + } + if (depend != null) { + map.put("depend", depend); + } + if (softDepend != null) { + map.put("softdepend", softDepend); + } + if (website != null) { + map.put("website", website); + } + if (description != null) { + map.put("description", description); + } + + if (authors.size() == 1) { + map.put("author", authors.get(0)); + } else if (authors.size() > 1) { + map.put("authors", authors); + } + + return map; + } + + private void loadPermissions(Map> perms) { + Set keys = perms.keySet(); + + for (String name : keys) { + try { + permissions.add(Permission.loadPermission(name, perms.get(name))); + } catch (Throwable ex) { + Bukkit.getServer().getLogger().log(Level.SEVERE, "Permission node '" + name + "' in plugin description file for " + getFullName() + " is invalid", ex); + } + } + } +} diff --git a/src/main/java/org/bukkit/plugin/PluginLoadOrder.java b/src/main/java/org/bukkit/plugin/PluginLoadOrder.java new file mode 100644 index 0000000..c1ae4be --- /dev/null +++ b/src/main/java/org/bukkit/plugin/PluginLoadOrder.java @@ -0,0 +1,16 @@ + +package org.bukkit.plugin; + +/** + * Represents the order in which a plugin should be initialized and enabled + */ +public enum PluginLoadOrder { + /** + * Indicates that the plugin will be loaded at startup + */ + STARTUP, + /** + * Indicates that the plugin will be loaded after the first/default world was created + */ + POSTWORLD +} diff --git a/src/main/java/org/bukkit/plugin/PluginLoader.java b/src/main/java/org/bukkit/plugin/PluginLoader.java new file mode 100644 index 0000000..14996d7 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/PluginLoader.java @@ -0,0 +1,80 @@ +package org.bukkit.plugin; + +import org.bukkit.event.Event; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Represents a plugin loader, which handles direct access to specific types + * of plugins + */ +public interface PluginLoader { + + /** + * Loads the plugin contained in the specified file + * + * @param file File to attempt to load + * @return Plugin that was contained in the specified file, or null if + * unsuccessful + * @throws InvalidPluginException Thrown when the specified file is not a plugin + */ + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException; + + // Project Poseidon Start + /** + * Creates listener map for class + * + * @param listener listener class + * @param plugin plugin + * @return Map for all the events in the class + */ + public Map, Set> createRegisteredListeners(@NotNull Listener listener, @NotNull final Plugin plugin); + // Project Poseidon End + + /** + * Loads the plugin contained in the specified file + * + * @param file File to attempt to load + * @param ignoreSoftDependencies Loader will ignore soft dependencies if this flag is set to true + * @return Plugin that was contained in the specified file, or null if + * unsuccessful + * @throws InvalidPluginException Thrown when the specified file is not a plugin + */ + public Plugin loadPlugin(File file, boolean ignoreSoftDependencies) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException; + + /** + * Returns a list of all filename filters expected by this PluginLoader + */ + public Pattern[] getPluginFileFilters(); + + /** + * Creates and returns an event executor + * + * @param type Type of the event executor to create + * @param listener the object that will handle the eventual call back + */ + public EventExecutor createExecutor(Event.Type type, Listener listener); + + /** + * Enables the specified plugin + * + * Attempting to enable a plugin that is already enabled will have no effect + * + * @param plugin Plugin to enable + */ + public void enablePlugin(Plugin plugin); + + /** + * Disables the specified plugin + * + * Attempting to disable a plugin that is not enabled will have no effect + * + * @param plugin Plugin to disable + */ + public void disablePlugin(Plugin plugin); +} diff --git a/src/main/java/org/bukkit/plugin/PluginManager.java b/src/main/java/org/bukkit/plugin/PluginManager.java new file mode 100644 index 0000000..4598d29 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/PluginManager.java @@ -0,0 +1,263 @@ +package org.bukkit.plugin; + +import org.bukkit.event.Event; +import org.bukkit.event.Event.Priority; +import org.bukkit.event.Listener; +import org.bukkit.permissions.Permissible; +import org.bukkit.permissions.Permission; + +import java.io.File; +import java.util.Set; + +/** + * Handles all plugin management from the Server + */ +public interface PluginManager { + + /** + * Registers the specified plugin loader + * + * @param loader Class name of the PluginLoader to register + * @throws IllegalArgumentException Thrown when the given Class is not a valid PluginLoader + */ + public void registerInterface(Class loader) throws IllegalArgumentException; + + /** + * Checks if the given plugin is loaded and returns it when applicable + * + * Please note that the name of the plugin is case-sensitive + * + * @param name Name of the plugin to check + * @return Plugin if it exists, otherwise null + */ + public Plugin getPlugin(String name); + + /** + * Gets a list of all currently loaded plugins + * + * @return Array of Plugins + */ + public Plugin[] getPlugins(); + + /** + * Checks if the given plugin is enabled or not + * + * Please note that the name of the plugin is case-sensitive. + * + * @param name Name of the plugin to check + * @return true if the plugin is enabled, otherwise false + */ + public boolean isPluginEnabled(String name); + + /** + * Checks if the given plugin is enabled or not + * + * @param plugin Plugin to check + * @return true if the plugin is enabled, otherwise false + */ + public boolean isPluginEnabled(Plugin plugin); + + /** + * Loads the plugin in the specified file + * + * File must be valid according to the current enabled Plugin interfaces + * + * @param file File containing the plugin to load + * @return The Plugin loaded, or null if it was invalid + * @throws InvalidPluginException Thrown when the specified file is not a valid plugin + * @throws InvalidDescriptionException Thrown when the specified file contains an invalid description + */ + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException; + + /** + * Loads the plugins contained within the specified directory + * + * @param directory Directory to check for plugins + * @return A list of all plugins loaded + */ + public Plugin[] loadPlugins(File directory); + + /** + * Disables all the loaded plugins + */ + public void disablePlugins(); + + /** + * Disables and removes all plugins + */ + public void clearPlugins(); + + /** + * Calls a player related event with the given details + * + * @param type Type of player related event to call + * @param event Event details + */ + public void callEvent(Event event); + + /** + * Registers the given event to the specified listener + * + * @param type EventType to register + * @param listener Listener to register + * @param priority Priority of this event + * @param plugin Plugin to register + */ + public void registerEvent(Event.Type type, Listener listener, Priority priority, Plugin plugin); + + /** + * Registers the given event to the specified executor + * + * @param type EventType to register + * @param listener Listener to register + * @param executor EventExecutor to register + * @param priority Priority of this event + * @param plugin Plugin to register + */ + public void registerEvent(Event.Type type, Listener listener, EventExecutor executor, Priority priority, Plugin plugin); + + /** + * Registers a listener with all events with @EventHandler + * + * @see org.bukkit.event.EventHandler + * @param listener Listener to register + * @param plugin Plugin to register + */ + public void registerEvents(Listener listener, Plugin plugin); + + /** + * Enables the specified plugin + * + * Attempting to enable a plugin that is already enabled will have no effect + * + * @param plugin Plugin to enable + */ + public void enablePlugin(Plugin plugin); + + /** + * Disables the specified plugin + * + * Attempting to disable a plugin that is not enabled will have no effect + * + * @param plugin Plugin to disable + */ + public void disablePlugin(Plugin plugin); + + /** + * Gets a {@link Permission} from its fully qualified name + * + * @param name Name of the permission + * @return Permission, or null if none + */ + public Permission getPermission(String name); + + /** + * Adds a {@link Permission} to this plugin manager. + * + * If a permission is already defined with the given name of the new permission, + * an exception will be thrown. + * + * @param perm Permission to add + * @throws IllegalArgumentException Thrown when a permission with the same name already exists + */ + public void addPermission(Permission perm); + + /** + * Removes a {@link Permission} registration from this plugin manager. + * + * If the specified permission does not exist in this plugin manager, nothing will happen. + * + * Removing a permission registration will not remove the permission from any {@link Permissible}s that have it. + * + * @param perm Permission to remove + */ + public void removePermission(Permission perm); + + /** + * Removes a {@link Permission} registration from this plugin manager. + * + * If the specified permission does not exist in this plugin manager, nothing will happen. + * + * Removing a permission registration will not remove the permission from any {@link Permissible}s that have it. + * + * @param name Permission to remove + */ + public void removePermission(String name); + + /** + * Gets the default permissions for the given op status + * + * @param op Which set of default permissions to get + */ + public Set getDefaultPermissions(boolean op); + + /** + * Recalculates the defaults for the given {@link Permission}. + * + * This will have no effect if the specified permission is not registered here. + * + * @param perm Permission to recalculate + */ + public void recalculatePermissionDefaults(Permission perm); + + /** + * Subscribes the given Permissible for information about the requested Permission, by name. + * + * If the specified Permission changes in any form, the Permissible will be asked to recalculate. + * + * @param permission Permission to subscribe to + * @param permissible Permissible subscribing + */ + public void subscribeToPermission(String permission, Permissible permissible); + + /** + * Unsubscribes the given Permissible for information about the requested Permission, by name. + * + * @param permission Permission to unsubscribe from + * @param permissible Permissible subscribing + */ + public void unsubscribeFromPermission(String permission, Permissible permissible); + + /** + * Gets a set containing all subscribed {@link Permissible}s to the given permission, by name + * + * @param permission Permission to query for + * @return Set containing all subscribed permissions + */ + public Set getPermissionSubscriptions(String permission); + + /** + * Subscribes to the given Default permissions by operator status + * + * If the specified defaults change in any form, the Permissible will be asked to recalculate. + * + * @param op Default list to subscribe to + * @param permissible Permissible subscribing + */ + public void subscribeToDefaultPerms(boolean op, Permissible permissible); + + /** + * Unsubscribes from the given Default permissions by operator status + * + * @param op Default list to unsubscribe from + * @param permissible Permissible subscribing + */ + public void unsubscribeFromDefaultPerms(boolean op, Permissible permissible); + + /** + * Gets a set containing all subscribed {@link Permissible}s to the given default list, by op status + * + * @param op Default list to query for + * @return Set containing all subscribed permissions + */ + public Set getDefaultPermSubscriptions(boolean op); + + /** + * Gets a set of all registered permissions. + * + * This set is a copy and will not be modified live. + * + * @return Set containing all current registered permissions + */ + public Set getPermissions(); +} diff --git a/src/main/java/org/bukkit/plugin/RegisteredListener.java b/src/main/java/org/bukkit/plugin/RegisteredListener.java new file mode 100644 index 0000000..8a3207f --- /dev/null +++ b/src/main/java/org/bukkit/plugin/RegisteredListener.java @@ -0,0 +1,73 @@ +package org.bukkit.plugin; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.Listener; + +/** + * Stores relevant information for plugin listeners + */ +public class RegisteredListener { + private final Listener listener; + private final Event.Priority priority; + private final Plugin plugin; + private final EventExecutor executor; + private final boolean ignoreCancelled; + + public RegisteredListener(final Listener pluginListener, final EventExecutor eventExecutor, final Event.Priority eventPriority, final Plugin registeredPlugin) { + this(pluginListener, eventExecutor, eventPriority, registeredPlugin, false); + } + + public RegisteredListener(final Listener pluginListener, final EventExecutor eventExecutor, final Event.Priority eventPriority, final Plugin registeredPlugin, final boolean ignoreCancelled) { + this.listener = pluginListener; + this.priority = eventPriority; + this.plugin = registeredPlugin; + this.executor = eventExecutor; + this.ignoreCancelled = ignoreCancelled; + } + + public RegisteredListener(final Listener pluginListener, final Event.Priority eventPriority, final Plugin registeredPlugin, Event.Type type) { + this(pluginListener, registeredPlugin.getPluginLoader().createExecutor(type, pluginListener), eventPriority, registeredPlugin, false); + } + + public void registerAll() { + + } + + /** + * Gets the listener for this registration + * @return Registered Listener + */ + public Listener getListener() { + return listener; + } + + /** + * Gets the plugin for this registration + * @return Registered Plugin + */ + public Plugin getPlugin() { + return plugin; + } + + /** + * Gets the priority for this registration + * @return Registered Priority + */ + public Event.Priority getPriority() { + return priority; + } + + /** + * Calls the event executor + * @return Registered Priority + */ + public void callEvent(Event event) { + if(event instanceof Cancellable) { + if(((Cancellable) event).isCancelled() && ignoreCancelled) { + return; + } + } + executor.execute(listener, event); + } +} diff --git a/src/main/java/org/bukkit/plugin/RegisteredServiceProvider.java b/src/main/java/org/bukkit/plugin/RegisteredServiceProvider.java new file mode 100644 index 0000000..06e12f9 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/RegisteredServiceProvider.java @@ -0,0 +1,48 @@ +package org.bukkit.plugin; + +/** + * A registered service provider. + * + * @author sk89q + * @param Service + */ +public class RegisteredServiceProvider implements Comparable> { + + private Class service; + private Plugin plugin; + private T provider; + private ServicePriority priority; + + public RegisteredServiceProvider(Class service, T provider, + ServicePriority priority, Plugin plugin) { + + this.service = service; + this.plugin = plugin; + this.provider = provider; + this.priority = priority; + } + + public Class getService() { + return service; + } + + public Plugin getPlugin() { + return plugin; + } + + public T getProvider() { + return provider; + } + + public ServicePriority getPriority() { + return priority; + } + + public int compareTo(RegisteredServiceProvider other) { + if (priority.ordinal() == other.getPriority().ordinal()) { + return 0; + } else { + return priority.ordinal() < other.getPriority().ordinal() ? 1 : -1; + } + } +} diff --git a/src/main/java/org/bukkit/plugin/ServicePriority.java b/src/main/java/org/bukkit/plugin/ServicePriority.java new file mode 100644 index 0000000..4afe0fb --- /dev/null +++ b/src/main/java/org/bukkit/plugin/ServicePriority.java @@ -0,0 +1,12 @@ +package org.bukkit.plugin; + +/** + * Represents various priorities of a provider. + */ +public enum ServicePriority { + Lowest, + Low, + Normal, + High, + Highest +} diff --git a/src/main/java/org/bukkit/plugin/ServicesManager.java b/src/main/java/org/bukkit/plugin/ServicesManager.java new file mode 100644 index 0000000..e801121 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/ServicesManager.java @@ -0,0 +1,110 @@ +package org.bukkit.plugin; + +import java.util.Collection; +import java.util.List; + +/** + * Manages services and service providers. Services are an interface specifying + * a list of methods that a provider must implement. Providers are + * implementations of these services. A provider can be queried from the + * services manager in order to use a service (if one is available). If + * multiple plugins register a service, then the service with the highest + * priority takes precedence. + * + * @author sk89q + */ +public interface ServicesManager { + + /** + * Register a provider of a service. + * + * @param Provider + * @param service service class + * @param provider provider to register + * @param plugin plugin with the provider + * @param priority priority of the provider + */ + public void register(Class service, T provider, Plugin plugin, + ServicePriority priority); + + /** + * Unregister all the providers registered by a particular plugin. + * + * @param plugin + */ + public void unregisterAll(Plugin plugin); + + /** + * Unregister a particular provider for a particular service. + * + * @param service + * @param provider + */ + public void unregister(Class service, Object provider); + + /** + * Unregister a particular provider. + * + * @param provider + */ + public void unregister(Object provider); + + /** + * Queries for a provider. This may return if no provider has been + * registered for a service. The highest priority provider is returned. + * + * @param + * @param service + * @return provider or null + */ + public T load(Class service); + + /** + * Queries for a provider registration. This may return if no provider + * has been registered for a service. + * + * @param + * @param service + * @return provider registration or null + */ + public RegisteredServiceProvider getRegistration(Class service); + + /** + * Get registrations of providers for a plugin. + * + * @param plugin + * @return provider registration or null + */ + public List> getRegistrations(Plugin plugin); + + /** + * Get registrations of providers for a service. The returned list is + * unmodifiable. + * + * @param + * @param service + * @return list of registrations + */ + public Collection> getRegistrations( + Class service); + + /** + * Get a list of known services. A service is known if it has registered + * providers for it. + * + * @return list of known services + */ + public Collection> getKnownServices(); + + /** + * Returns whether a provider has been registered for a service. Do not + * check this first only to call load(service) later, as that + * would be a non-thread safe situation. + * + * @param service + * @param service service to check + * @return whether there has been a registered provider + */ + public boolean isProvidedFor(Class service); + +} diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java new file mode 100644 index 0000000..990c374 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java @@ -0,0 +1,595 @@ +package org.bukkit.plugin; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.MapMaker; +import com.legacyminecraft.poseidon.PluginLoadPlanner; +import com.legacyminecraft.poseidon.Poseidon; +import com.legacyminecraft.poseidon.event.PoseidonCustomListener; +import com.legacyminecraft.poseidon.utility.PerformanceStatistic; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.PluginCommandYamlParser; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.event.Event; +import org.bukkit.event.Event.Priority; +import org.bukkit.event.Listener; +import org.bukkit.permissions.Permissible; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; +import org.bukkit.util.FileUtil; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.util.*; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Handles all plugin management from the Server + */ +public final class SimplePluginManager implements PluginManager { + private final Server server; + private final Map fileAssociations = new HashMap(); + private final List plugins = new ArrayList(); + private final Map lookupNames = new HashMap(); + private final Map> listeners = new EnumMap>(Event.Type.class); + private static File updateDirectory = null; + private final SimpleCommandMap commandMap; + private final Map permissions = new HashMap(); + private final Map> defaultPerms = new LinkedHashMap>(); + private final Map> permSubs = new HashMap>(); + private final Map> defSubs = new HashMap>(); + private final List enableOrder = new ArrayList<>(); + private final Comparator comparer = new Comparator() { + public int compare(RegisteredListener i, RegisteredListener j) { + int result = i.getPriority().compareTo(j.getPriority()); + + if ((result == 0) && (i != j)) { + result = 1; + } + + return result; + } + }; + + public SimplePluginManager(Server instance, SimpleCommandMap commandMap) { + server = instance; + this.commandMap = commandMap; + + defaultPerms.put(true, new HashSet()); + defaultPerms.put(false, new HashSet()); + + // Project Poseidon Start + this.listenerPerformanceEnabled = Poseidon.getServer().getConfig().getConfigBoolean("settings.performance-monitoring.listener-reporting.enabled"); + this.printOnSlowListener = Poseidon.getServer().getConfig().getConfigBoolean("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.enabled"); + this.printOnSlowListenerThreshold = Poseidon.getServer().getConfig().getConfigInteger("settings.performance-monitoring.listener-reporting.print-on-slow-listeners.value"); + + this.listenerPerformance = Poseidon.getServer().getListenerPerformance(); // Get the listener performance map from PoseidonServer for storing listener performance statistics + // Project Poseidon End + } + + // Project Poseidon Start + + private final boolean listenerPerformanceEnabled; // Project Poseidon + private final Map listenerPerformance; // Project Poseidon + + private final boolean printOnSlowListener; + private final int printOnSlowListenerThreshold; + + @Override + public void registerEvents(Listener listener, Plugin plugin) { + if (!plugin.isEnabled()) { + throw new IllegalPluginAccessException("Plugin attempted to register " + listener + " while not enabled"); + } else { + for (Map.Entry, Set> entry : plugin.getPluginLoader().createRegisteredListeners(listener, plugin).entrySet()) { + Class clazz = entry.getKey(); + Event.Type type = Event.Type.getTypeByName(clazz.getSimpleName().substring(0, clazz.getSimpleName().indexOf("Event"))); + if (type != null) { + getEventListeners(type).addAll(entry.getValue()); + } else { + //If listener implements PoseidonCustomListener, we can be sure it is probably a custom event. + if (listener instanceof PoseidonCustomListener) { + server.getLogger().log(Level.INFO, plugin.getDescription().getName() + " is utilizing event handlers to receive the custom event " + clazz.getSimpleName() + ". Please be aware this is a hacky beta feature."); + getEventListeners(Event.Type.CUSTOM_EVENT).addAll(entry.getValue()); + } else { + String cName = clazz.getName(); + server.getLogger().log(Level.SEVERE, String.format("Class %s failed to get Event.Type on @EventHandler", cName)); + } + } + + } + + } + } + // Project Poseidon End + + /** + * Registers the specified plugin loader + * + * @param loader Class name of the PluginLoader to register + * @throws IllegalArgumentException Thrown when the given Class is not a valid PluginLoader + */ + public void registerInterface(Class loader) throws IllegalArgumentException { + PluginLoader instance; + + if (PluginLoader.class.isAssignableFrom(loader)) { + Constructor constructor; + + try { + constructor = loader.getConstructor(Server.class); + instance = constructor.newInstance(server); + } catch (NoSuchMethodException ex) { + String className = loader.getName(); + + throw new IllegalArgumentException(String.format("Class %s does not have a public %s(Server) constructor", className, className), ex); + } catch (Exception ex) { + throw new IllegalArgumentException(String.format("Unexpected exception %s while attempting to construct a new instance of %s", ex.getClass().getName(), loader.getName()), ex); + } + } else { + throw new IllegalArgumentException(String.format("Class %s does not implement interface PluginLoader", loader.getName())); + } + + Pattern[] patterns = instance.getPluginFileFilters(); + + synchronized (this) { + for (Pattern pattern : patterns) { + fileAssociations.put(pattern, instance); + } + } + } + + /** + * Loads the plugins contained within the specified directory + * + * @param directory Directory to check for plugins + * @return A list of all plugins loaded + */ + public Plugin[] loadPlugins(File directory) { + List result = new ArrayList(); + File[] files = directory.listFiles(); + + if (!(server.getUpdateFolder().equals(""))) { + updateDirectory = new File(directory, server.getUpdateFolder()); + } + + PluginLoadPlanner planner = new PluginLoadPlanner(server, fileAssociations.keySet(), updateDirectory); + + for (PluginLoadPlanner.PlannedPlugin plannedPlugin : planner.plan(directory, files)) { + try { + Plugin plugin = loadPlugin(plannedPlugin.file, plannedPlugin.ignoreSoftDependencies); + if (plugin != null) { + result.add(plugin); + } + } catch (UnknownDependencyException | InvalidPluginException | InvalidDescriptionException ex) { + server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "'.", ex); + } + } + + return result.toArray(new Plugin[result.size()]); + } + + /** + * Loads the plugin in the specified file + *

+ * File must be valid according to the current enabled Plugin interfaces + * + * @param file File containing the plugin to load + * @return The Plugin loaded, or null if it was invalid + * @throws InvalidPluginException Thrown when the specified file is not a valid plugin + * @throws InvalidDescriptionException Thrown when the specified file contains an invalid description + */ + public synchronized Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException { + return loadPlugin(file, true); + } + + /** + * Loads the plugin in the specified file + *

+ * File must be valid according to the current enabled Plugin interfaces + * + * @param file File containing the plugin to load + * @param ignoreSoftDependencies Loader will ignore soft dependencies if this flag is set to true + * @return The Plugin loaded, or null if it was invalid + * @throws InvalidPluginException Thrown when the specified file is not a valid plugin + * @throws InvalidDescriptionException Thrown when the specified file contains an invalid description + */ + public synchronized Plugin loadPlugin(File file, boolean ignoreSoftDependencies) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException { + File updateFile = null; + + if (updateDirectory != null && updateDirectory.isDirectory() && (updateFile = new File(updateDirectory, file.getName())).isFile()) { + if (FileUtil.copy(updateFile, file)) { + server.getLogger().info("An updated file for \"" + file.getName() + "\" has been found in the update folder. Replacing the original file."); + updateFile.delete(); + } + } + + Set filters = fileAssociations.keySet(); + Plugin result = null; + + for (Pattern filter : filters) { + String name = file.getName(); + Matcher match = filter.matcher(name); + + if (match.find()) { + PluginLoader loader = fileAssociations.get(filter); + + result = loader.loadPlugin(file, ignoreSoftDependencies); + } + } + + if (result != null) { + plugins.add(result); + lookupNames.put(result.getDescription().getName(), result); + } + + return result; + } + + /** + * Checks if the given plugin is loaded and returns it when applicable + *

+ * Please note that the name of the plugin is case-sensitive + * + * @param name Name of the plugin to check + * @return Plugin if it exists, otherwise null + */ + public synchronized Plugin getPlugin(String name) { + return lookupNames.get(name); + } + + public synchronized Plugin[] getPlugins() { + return plugins.toArray(new Plugin[0]); + } + + /** + * Checks if the given plugin is enabled or not + *

+ * Please note that the name of the plugin is case-sensitive. + * + * @param name Name of the plugin to check + * @return true if the plugin is enabled, otherwise false + */ + public boolean isPluginEnabled(String name) { + Plugin plugin = getPlugin(name); + + return isPluginEnabled(plugin); + } + + /** + * Checks if the given plugin is enabled or not + * + * @param plugin Plugin to check + * @return true if the plugin is enabled, otherwise false + */ + public boolean isPluginEnabled(Plugin plugin) { + if ((plugin != null) && (plugins.contains(plugin))) { + return plugin.isEnabled(); + } else { + return false; + } + } + + public void enablePlugin(final Plugin plugin) { + if (!plugin.isEnabled()) { + List pluginCommands = PluginCommandYamlParser.parse(plugin); + + if (!pluginCommands.isEmpty()) { + commandMap.registerAll(plugin.getDescription().getName(), pluginCommands); + + // Project Poseidon - Start - Hide commands + for (Command c : pluginCommands) { + if (c.isHidden()) { + Poseidon.getServer().addHiddenCommand(c.getLabel()); + Poseidon.getServer().addHiddenCommands(c.getAliases()); + } + } + // Project Poseidon - End - Hide commands + } + + try { + plugin.getPluginLoader().enablePlugin(plugin); + // Record successful enables so shutdown can run in strict reverse dependency order. + if (plugin.isEnabled()) { + enableOrder.add(plugin); + } + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex); + } + } + } + + public void disablePlugins() { + // Tear down plugins in reverse successful enable order so dependents stop before their dependencies. + List enabledPlugins = new ArrayList<>(enableOrder); // Create a snapshot as disablePlugin is responsible for removing plugins + ListIterator iterator = enabledPlugins.listIterator(enabledPlugins.size()); + while (iterator.hasPrevious()) { + disablePlugin(iterator.previous()); + } + + // Fall back to any enabled plugin that was not recorded, so shutdown remains complete. This should only be needed if people are using stuff like PlugMan + for (Plugin plugin : getPlugins()) { + if (plugin.isEnabled()) { + disablePlugin(plugin); + } + } + } + + public void disablePlugin(final Plugin plugin) { + if (plugin.isEnabled()) { + try { + plugin.getPluginLoader().disablePlugin(plugin); + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex); + } + + try { + server.getScheduler().cancelTasks(plugin); + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while cancelling tasks for " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex); + } + + try { + server.getServicesManager().unregisterAll(plugin); + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering services for " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex); + } + + enableOrder.remove(plugin); + } + } + + public void clearPlugins() { + synchronized (this) { + disablePlugins(); + plugins.clear(); + lookupNames.clear(); + listeners.clear(); + fileAssociations.clear(); + enableOrder.clear(); + permissions.clear(); + defaultPerms.get(true).clear(); + defaultPerms.get(false).clear(); + } + } + + /** + * Calls a player related event with the given details and logs execution time, calling plugin, and listener class. + * + * @param event Event details + */ + public synchronized void callEvent(Event event) { + SortedSet eventListeners = listeners.get(event.getType()); + + if (eventListeners != null) { + for (RegisteredListener registration : eventListeners) { + long startTime = System.currentTimeMillis(); // Start timing before event call + + try { + registration.callEvent(event); // Call the event + + // Project Poseidon - Start - Listener Performance Reporting + if (listenerPerformanceEnabled) { + long duration = System.currentTimeMillis() - startTime; // Calculate duration in milliseconds + + String listenerKey = registration.getListener().getClass().getName() + ":" + event.getType().toString(); + + listenerPerformance.computeIfAbsent(listenerKey, k -> new PerformanceStatistic()).update(duration); + + // If event took longer than the threshold, print the performance statistics for the listener + if (printOnSlowListener && duration > printOnSlowListenerThreshold) { + server.getLogger().log(Level.WARNING, String.format( + "[Poseidon] Event %s in %s took %d milliseconds. Statistics: %s", + event.getType(), + listenerKey, + duration, + listenerPerformance.get(listenerKey).printStats() + )); + } + } + // Project Poseidon - End - Listener Performance Reporting + } catch (AuthorNagException ex) { + Plugin plugin = registration.getPlugin(); + + if (plugin.isNaggable()) { + plugin.setNaggable(false); + + String author = ""; + + if (plugin.getDescription().getAuthors().size() > 0) { + author = plugin.getDescription().getAuthors().get(0); + } + server.getLogger().log(Level.SEVERE, String.format( + "Nag author: '%s' of '%s' about the following: %s", + author, + plugin.getDescription().getName(), + ex.getMessage() + )); + } + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getType() + " to " + registration.getPlugin().getDescription().getName(), ex); + } + } + } + } + + + /** + * Registers the given event to the specified listener + * + * @param type EventType to register + * @param listener PlayerListener to register + * @param priority Priority of this event + * @param plugin Plugin to register + */ + public void registerEvent(Event.Type type, Listener listener, Priority priority, Plugin plugin) { + if (!plugin.isEnabled()) { + throw new IllegalPluginAccessException("Plugin attempted to register " + type + " while not enabled"); + } + + getEventListeners(type).add(new RegisteredListener(listener, priority, plugin, type)); + } + + /** + * Registers the given event to the specified listener using a directly passed EventExecutor + * + * @param type EventType to register + * @param listener PlayerListener to register + * @param executor EventExecutor to register + * @param priority Priority of this event + * @param plugin Plugin to register + */ + public void registerEvent(Event.Type type, Listener listener, EventExecutor executor, Priority priority, Plugin plugin) { + if (!plugin.isEnabled()) { + throw new IllegalPluginAccessException("Plugin attempted to register " + type + " while not enabled"); + } + + getEventListeners(type).add(new RegisteredListener(listener, executor, priority, plugin)); + } + + /** + * Returns a SortedSet of RegisteredListener for the specified event type creating a new queue if needed + * + * @param type EventType to lookup + * @return SortedSet the looked up or create queue matching the requested type + */ + private SortedSet getEventListeners(Event.Type type) { + SortedSet eventListeners = listeners.get(type); + + if (eventListeners != null) { + return eventListeners; + } + + eventListeners = new TreeSet(comparer); + listeners.put(type, eventListeners); + return eventListeners; + } + + public Permission getPermission(String name) { + return permissions.get(name.toLowerCase()); + } + + public void addPermission(Permission perm) { + String name = perm.getName().toLowerCase(); + + if (permissions.containsKey(name)) { + throw new IllegalArgumentException("The permission " + name + " is already defined!"); + } + + permissions.put(name, perm); + calculatePermissionDefault(perm); + } + + public Set getDefaultPermissions(boolean op) { + return ImmutableSet.copyOf(defaultPerms.get(op)); + } + + public void removePermission(Permission perm) { + removePermission(perm.getName().toLowerCase()); + } + + public void removePermission(String name) { + permissions.remove(name); + } + + public void recalculatePermissionDefaults(Permission perm) { + if (permissions.containsValue(perm)) { + defaultPerms.get(true).remove(perm); + defaultPerms.get(false).remove(perm); + + calculatePermissionDefault(perm); + } + } + + private void calculatePermissionDefault(Permission perm) { + if ((perm.getDefault() == PermissionDefault.OP) || (perm.getDefault() == PermissionDefault.TRUE)) { + defaultPerms.get(true).add(perm); + dirtyPermissibles(true); + } + if ((perm.getDefault() == PermissionDefault.NOT_OP) || (perm.getDefault() == PermissionDefault.TRUE)) { + defaultPerms.get(false).add(perm); + dirtyPermissibles(false); + } + } + + private void dirtyPermissibles(boolean op) { + Set permissibles = getDefaultPermSubscriptions(op); + + for (Permissible p : permissibles) { + p.recalculatePermissions(); + } + } + + public void subscribeToPermission(String permission, Permissible permissible) { + String name = permission.toLowerCase(); + Map map = permSubs.get(name); + + if (map == null) { + map = new MapMaker().weakKeys().makeMap(); + permSubs.put(name, map); + } + + map.put(permissible, true); + } + + public void unsubscribeFromPermission(String permission, Permissible permissible) { + String name = permission.toLowerCase(); + Map map = permSubs.get(name); + + if (map != null) { + map.remove(permissible); + + if (map.isEmpty()) { + permSubs.remove(name); + } + } + } + + public Set getPermissionSubscriptions(String permission) { + String name = permission.toLowerCase(); + Map map = permSubs.get(name); + + if (map == null) { + return ImmutableSet.of(); + } else { + return ImmutableSet.copyOf(map.keySet()); + } + } + + public void subscribeToDefaultPerms(boolean op, Permissible permissible) { + Map map = defSubs.get(op); + + if (map == null) { + map = new MapMaker().weakKeys().makeMap(); + defSubs.put(op, map); + } + + map.put(permissible, true); + } + + public void unsubscribeFromDefaultPerms(boolean op, Permissible permissible) { + Map map = defSubs.get(op); + + if (map != null) { + map.remove(permissible); + + if (map.isEmpty()) { + defSubs.remove(op); + } + } + } + + public Set getDefaultPermSubscriptions(boolean op) { + Map map = defSubs.get(op); + + if (map == null) { + return ImmutableSet.of(); + } else { + return ImmutableSet.copyOf(map.keySet()); + } + } + + public Set getPermissions() { + return new HashSet(permissions.values()); + } +} diff --git a/src/main/java/org/bukkit/plugin/SimpleServicesManager.java b/src/main/java/org/bukkit/plugin/SimpleServicesManager.java new file mode 100644 index 0000000..c42738b --- /dev/null +++ b/src/main/java/org/bukkit/plugin/SimpleServicesManager.java @@ -0,0 +1,269 @@ +package org.bukkit.plugin; + +import java.util.*; + +/** + * A simple services manager. + * + * @author sk89q + */ +public class SimpleServicesManager implements ServicesManager { + + /** + * Map of providers. + */ + private final Map, List>> providers = new HashMap, List>>(); + + /** + * Register a provider of a service. + * + * @param Provider + * @param service service class + * @param provider provider to register + * @param plugin plugin with the provider + * @param priority priority of the provider + */ + public void register(Class service, T provider, + Plugin plugin, ServicePriority priority) { + + synchronized (providers) { + List> registered = providers.get(service); + + if (registered == null) { + registered = new ArrayList>(); + providers.put(service, registered); + } + + registered.add(new RegisteredServiceProvider(service, provider, priority, plugin)); + + // Make sure that providers are in the right order in order + // for priorities to work correctly + Collections.sort(registered); + } + } + + /** + * Unregister all the providers registered by a particular plugin. + * + * @param plugin + */ + public void unregisterAll(Plugin plugin) { + synchronized (providers) { + Iterator, List>>> it = providers.entrySet().iterator(); + + try { + while (it.hasNext()) { + Map.Entry, List>> entry = it.next(); + Iterator> it2 = entry.getValue().iterator(); + + try { + // Removed entries that are from this plugin + + while (it2.hasNext()) { + if (it2.next().getPlugin() == plugin) { + it2.remove(); + } + } + } catch (NoSuchElementException e) { // Why does Java suck + } + + // Get rid of the empty list + if (entry.getValue().size() == 0) { + it.remove(); + } + } + } catch (NoSuchElementException e) {} + } + } + + /** + * Unregister a particular provider for a particular service. + * + * @param service + * @param provider + */ + public void unregister(Class service, Object provider) { + synchronized (providers) { + Iterator, List>>> it = providers.entrySet().iterator(); + + try { + while (it.hasNext()) { + Map.Entry, List>> entry = it.next(); + + // We want a particular service + if (entry.getKey() != service) { + continue; + } + + Iterator> it2 = entry.getValue().iterator(); + + try { + // Removed entries that are from this plugin + + while (it2.hasNext()) { + if (it2.next().getProvider() == provider) { + it2.remove(); + } + } + } catch (NoSuchElementException e) { // Why does Java suck + } + + // Get rid of the empty list + if (entry.getValue().size() == 0) { + it.remove(); + } + } + } catch (NoSuchElementException e) {} + } + } + + /** + * Unregister a particular provider. + * + * @param provider + */ + public void unregister(Object provider) { + synchronized (providers) { + Iterator, List>>> it = providers.entrySet().iterator(); + + try { + while (it.hasNext()) { + Map.Entry, List>> entry = it.next(); + Iterator> it2 = entry.getValue().iterator(); + + try { + // Removed entries that are from this plugin + + while (it2.hasNext()) { + if (it2.next().getProvider() == provider) { + it2.remove(); + } + } + } catch (NoSuchElementException e) { // Why does Java suck + } + + // Get rid of the empty list + if (entry.getValue().size() == 0) { + it.remove(); + } + } + } catch (NoSuchElementException e) {} + } + } + + /** + * Queries for a provider. This may return if no provider has been + * registered for a service. The highest priority provider is returned. + * + * @param + * @param service + * @return provider or null + */ + @SuppressWarnings("unchecked") + public T load(Class service) { + synchronized (providers) { + List> registered = providers.get(service); + + if (registered == null) { + return null; + } + + // This should not be null! + return (T) registered.get(0).getProvider(); + } + } + + /** + * Queries for a provider registration. This may return if no provider + * has been registered for a service. + * + * @param + * @param service + * @return provider registration or null + */ + @SuppressWarnings("unchecked") + public RegisteredServiceProvider getRegistration(Class service) { + synchronized (providers) { + List> registered = providers.get(service); + + if (registered == null) { + return null; + } + + // This should not be null! + return (RegisteredServiceProvider) registered.get(0); + } + } + + /** + * Get registrations of providers for a plugin. + * + * @param plugin + * @return provider registration or null + */ + public List> getRegistrations(Plugin plugin) { + synchronized (providers) { + List> ret = new ArrayList>(); + + for (List> registered : providers.values()) { + for (RegisteredServiceProvider provider : registered) { + if (provider.getPlugin() == plugin) { + ret.add(provider); + } + } + } + + return ret; + } + } + + /** + * Get registrations of providers for a service. The returned list is + * unmodifiable. + * + * @param + * @param service + * @return list of registrations + */ + @SuppressWarnings("unchecked") + public Collection> getRegistrations(Class service) { + synchronized (providers) { + List> registered = providers.get(service); + + if (registered == null) { + return Collections.unmodifiableList(new ArrayList>()); + } + + List> ret = new ArrayList>(); + + for (RegisteredServiceProvider provider : registered) { + ret.add((RegisteredServiceProvider) provider); + } + + return Collections.unmodifiableList(ret); + } + } + + /** + * Get a list of known services. A service is known if it has registered + * providers for it. + * + * @return list of known services + */ + public Collection> getKnownServices() { + return Collections.unmodifiableSet(providers.keySet()); + } + + /** + * Returns whether a provider has been registered for a service. Do not + * check this first only to call load(service) later, as that + * would be a non-thread safe situation. + * + * @param service + * @param service service to check + * @return whether there has been a registered provider + */ + public boolean isProvidedFor(Class service) { + return getRegistration(service) != null; + } +} diff --git a/src/main/java/org/bukkit/plugin/UnknownDependencyException.java b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java new file mode 100644 index 0000000..db476d4 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java @@ -0,0 +1,62 @@ +package org.bukkit.plugin; + +/** + * Thrown when attempting to load an invalid Plugin file + */ +public class UnknownDependencyException extends Exception { + + private static final long serialVersionUID = 5721389371901775894L; + private final Throwable cause; + private final String message; + + /** + * Constructs a new UnknownDependencyException based on the given Exception + * + * @param throwable Exception that triggered this Exception + */ + public UnknownDependencyException(Throwable throwable) { + this(throwable, "Unknown dependency"); + } + + /** + * Constructs a new UnknownDependencyException with the given message + * + * @param message Brief message explaining the cause of the exception + */ + public UnknownDependencyException(final String message) { + this(null, message); + } + + /** + * Constructs a new UnknownDependencyException based on the given Exception + * + * @param message Brief message explaining the cause of the exception + * @param throwable Exception that triggered this Exception + */ + public UnknownDependencyException(final Throwable throwable, final String message) { + this.cause = null; + this.message = message; + } + + /** + * Constructs a new UnknownDependencyException + */ + public UnknownDependencyException() { + this(null, "Unknown dependency"); + } + + /** + * If applicable, returns the Exception that triggered this Exception + * + * @return Inner exception, or null if one does not exist + */ + @Override + public Throwable getCause() { + return cause; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/bukkit/plugin/UnknownSoftDependencyException.java b/src/main/java/org/bukkit/plugin/UnknownSoftDependencyException.java new file mode 100644 index 0000000..8a39dd0 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/UnknownSoftDependencyException.java @@ -0,0 +1,44 @@ +package org.bukkit.plugin; + +/** + * Thrown when attempting to load an invalid Plugin file + */ +public class UnknownSoftDependencyException extends UnknownDependencyException { + + private static final long serialVersionUID = 5721389371901775899L; + + /** + * Constructs a new UnknownSoftDependencyException based on the given Exception + * + * @param throwable Exception that triggered this Exception + */ + public UnknownSoftDependencyException(Throwable throwable) { + this(throwable, "Unknown soft dependency"); + } + + /** + * Constructs a new UnknownSoftDependencyException with the given message + * + * @param message Brief message explaining the cause of the exception + */ + public UnknownSoftDependencyException(final String message) { + this(null, message); + } + + /** + * Constructs a new UnknownSoftDependencyException based on the given Exception + * + * @param message Brief message explaining the cause of the exception + * @param throwable Exception that triggered this Exception + */ + public UnknownSoftDependencyException(final Throwable throwable, final String message) { + super(throwable, message); + } + + /** + * Constructs a new UnknownSoftDependencyException + */ + public UnknownSoftDependencyException() { + this(null, "Unknown dependency"); + } +} diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java new file mode 100644 index 0000000..c68b7d3 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java @@ -0,0 +1,272 @@ +package org.bukkit.plugin.java; + +import com.avaje.ebean.EbeanServer; +import com.avaje.ebean.EbeanServerFactory; +import com.avaje.ebean.config.DataSourceConfig; +import com.avaje.ebean.config.ServerConfig; +import com.avaje.ebeaninternal.api.SpiEbeanServer; +import com.avaje.ebeaninternal.server.ddl.DdlGenerator; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginLoader; +import org.bukkit.util.config.Configuration; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a Java plugin + */ +public abstract class JavaPlugin implements Plugin { + private boolean isEnabled = false; + private boolean initialized = false; + private PluginLoader loader = null; + private Server server = null; + private File file = null; + private PluginDescriptionFile description = null; + private File dataFolder = null; + private ClassLoader classLoader = null; + private Configuration config = null; + private boolean naggable = true; + private EbeanServer ebean = null; + + public JavaPlugin() {} + + /** + * Returns the folder that the plugin data's files are located in. The + * folder may not yet exist. + * + * @return + */ + public File getDataFolder() { + return dataFolder; + } + + /** + * Gets the associated PluginLoader responsible for this plugin + * + * @return PluginLoader that controls this plugin + */ + public final PluginLoader getPluginLoader() { + return loader; + } + + /** + * Returns the Server instance currently running this plugin + * + * @return Server running this plugin + */ + public final Server getServer() { + return server; + } + + /** + * Returns a value indicating whether or not this plugin is currently enabled + * + * @return true if this plugin is enabled, otherwise false + */ + public final boolean isEnabled() { + return isEnabled; + } + + /** + * Returns the file which contains this plugin + * + * @return File containing this plugin + */ + protected File getFile() { + return file; + } + + /** + * Returns the plugin.yaml file containing the details for this plugin + * + * @return Contents of the plugin.yaml file + */ + public PluginDescriptionFile getDescription() { + return description; + } + + /** + * Returns the main configuration located at + * /config.yml and loads the file. If the configuration file + * does not exist and it cannot be loaded, no error will be emitted and + * the configuration file will have no values. + * + * @return + */ + public Configuration getConfiguration() { + return config; + } + + /** + * Returns the ClassLoader which holds this plugin + * + * @return ClassLoader holding this plugin + */ + protected ClassLoader getClassLoader() { + return classLoader; + } + + /** + * Sets the enabled state of this plugin + * + * @param enabled true if enabled, otherwise false + */ + protected void setEnabled(final boolean enabled) { + if (isEnabled != enabled) { + isEnabled = enabled; + + if (isEnabled) { + onEnable(); + } else { + onDisable(); + } + } + } + + /** + * Initializes this plugin with the given variables. + * + * This method should never be called manually. + * + * @param loader PluginLoader that is responsible for this plugin + * @param server Server instance that is running this plugin + * @param description PluginDescriptionFile containing metadata on this plugin + * @param dataFolder Folder containing the plugin's data + * @param file File containing this plugin + * @param classLoader ClassLoader which holds this plugin + */ + protected final void initialize(PluginLoader loader, Server server, + PluginDescriptionFile description, File dataFolder, File file, + ClassLoader classLoader) { + if (!initialized) { + this.initialized = true; + this.loader = loader; + this.server = server; + this.file = file; + this.description = description; + this.dataFolder = dataFolder; + this.classLoader = classLoader; + this.config = new Configuration(new File(dataFolder, "config.yml")); + this.config.load(); + + if (description.isDatabaseEnabled()) { + ServerConfig db = new ServerConfig(); + + db.setDefaultServer(false); + db.setRegister(false); + db.setClasses(getDatabaseClasses()); + db.setName(description.getName()); + server.configureDbConfig(db); + + DataSourceConfig ds = db.getDataSourceConfig(); + + ds.setUrl(replaceDatabaseString(ds.getUrl())); + getDataFolder().mkdirs(); + + ClassLoader previous = Thread.currentThread().getContextClassLoader(); + + Thread.currentThread().setContextClassLoader(classLoader); + ebean = EbeanServerFactory.create(db); + Thread.currentThread().setContextClassLoader(previous); + } + } + } + + /** + * Provides a list of all classes that should be persisted in the database + * + * @return List of Classes that are Ebeans + */ + public List> getDatabaseClasses() { + return new ArrayList>(); + } + + private String replaceDatabaseString(String input) { + input = input.replaceAll("\\{DIR\\}", getDataFolder().getPath().replaceAll("\\\\", "/") + "/"); + input = input.replaceAll("\\{NAME\\}", getDescription().getName().replaceAll("[^\\w_-]", "")); + return input; + } + + /** + * Gets the initialization status of this plugin + * + * @return true if this plugin is initialized, otherwise false + */ + public boolean isInitialized() { + return initialized; + } + + /** + * {@inheritDoc} + */ + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + return false; + } + + /** + * Gets the command with the given name, specific to this plugin + * + * @param name Name or alias of the command + * @return PluginCommand if found, otherwise null + */ + public PluginCommand getCommand(String name) { + String alias = name.toLowerCase(); + PluginCommand command = getServer().getPluginCommand(alias); + + if ((command != null) && (command.getPlugin() != this)) { + command = getServer().getPluginCommand(getDescription().getName().toLowerCase() + ":" + alias); + } + + if ((command != null) && (command.getPlugin() == this)) { + return command; + } else { + return null; + } + } + + public void onLoad() {} // Empty! + + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { + getServer().getLogger().severe("Plugin " + getDescription().getFullName() + " does not contain any generators that may be used in the default world!"); + return null; + } + + public final boolean isNaggable() { + return naggable; + } + + public final void setNaggable(boolean canNag) { + this.naggable = canNag; + } + + public EbeanServer getDatabase() { + return ebean; + } + + protected void installDDL() { + SpiEbeanServer serv = (SpiEbeanServer) getDatabase(); + DdlGenerator gen = serv.getDdlGenerator(); + + gen.runScript(false, gen.generateCreateDdl()); + } + + protected void removeDDL() { + SpiEbeanServer serv = (SpiEbeanServer) getDatabase(); + DdlGenerator gen = serv.getDdlGenerator(); + + gen.runScript(true, gen.generateDropDdl()); + } + + @Override + public String toString() { + return getDescription().getFullName(); + } +} diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java new file mode 100644 index 0000000..cee92c0 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java @@ -0,0 +1,1286 @@ +package org.bukkit.plugin.java; + +import com.legacyminecraft.poseidon.event.PoseidonCustomListener; +import org.bukkit.Server; +import org.bukkit.event.CustomEventListener; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; +import org.bukkit.event.entity.*; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.InventoryListener; +import org.bukkit.event.inventory.InventoryTransactionEvent; +import org.bukkit.event.packet.PacketListener; +import org.bukkit.event.packet.PacketReceivedEvent; +import org.bukkit.event.painting.PaintingBreakEvent; +import org.bukkit.event.painting.PaintingPlaceEvent; +import org.bukkit.event.player.*; +import org.bukkit.event.server.*; +import org.bukkit.event.vehicle.*; +import org.bukkit.event.weather.LightningStrikeEvent; +import org.bukkit.event.weather.ThunderChangeEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.bukkit.event.weather.WeatherListener; +import org.bukkit.event.world.*; +import org.bukkit.plugin.*; +import org.jetbrains.annotations.NotNull; +import org.yaml.snakeyaml.error.YAMLException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.regex.Pattern; + +/** + * Represents a Java plugin loader, allowing plugins in the form of .jar + */ +public class JavaPluginLoader implements PluginLoader +{ + private final Server server; + protected final Pattern[] fileFilters = new Pattern[] { Pattern.compile("\\.jar$"), }; + protected final Map> classes = new HashMap>(); + protected final Map loaders = new HashMap(); + + public JavaPluginLoader(Server instance) + { + server = instance; + } + + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException + { + return loadPlugin(file, false); + } + + public Plugin loadPlugin(File file, boolean ignoreSoftDependencies) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException + { + JavaPlugin result = null; + PluginDescriptionFile description = null; + + if (!file.exists()) + { + throw new InvalidPluginException(new FileNotFoundException(String.format("%s does not exist", file.getPath()))); + } + try + { + JarFile jar = new JarFile(file); + JarEntry entry = jar.getJarEntry("plugin.yml"); + + if (entry == null) + { + throw new InvalidPluginException(new FileNotFoundException("Jar does not contain plugin.yml")); + } + + InputStream stream = jar.getInputStream(entry); + + description = new PluginDescriptionFile(stream); + + stream.close(); + jar.close(); + } catch (IOException ex) + { + throw new InvalidPluginException(ex); + } catch (YAMLException ex) + { + throw new InvalidPluginException(ex); + } + + File dataFolder = new File(file.getParentFile(), description.getName()); + File oldDataFolder = getDataFolder(file); + + // Found old data folder + if (dataFolder.equals(oldDataFolder)) + { + // They are equal -- nothing needs to be done! + } else if (dataFolder.isDirectory() && oldDataFolder.isDirectory()) + { + server.getLogger().log(Level.INFO, String.format("While loading %s (%s) found old-data folder: %s next to the new one: %s", description.getName(), file, oldDataFolder, dataFolder)); + } else if (oldDataFolder.isDirectory() && !dataFolder.exists()) + { + if (!oldDataFolder.renameTo(dataFolder)) + { + throw new InvalidPluginException(new Exception("Unable to rename old data folder: '" + oldDataFolder + "' to: '" + dataFolder + "'")); + } + server.getLogger().log(Level.INFO, String.format("While loading %s (%s) renamed data folder: '%s' to '%s'", description.getName(), file, oldDataFolder, dataFolder)); + } + + if (dataFolder.exists() && !dataFolder.isDirectory()) + { + throw new InvalidPluginException(new Exception(String.format("Projected datafolder: '%s' for %s (%s) exists and is not a directory", dataFolder, description.getName(), file))); + } + + ArrayList depend; + + try + { + depend = (ArrayList) description.getDepend(); + if (depend == null) + { + depend = new ArrayList(); + } + } catch (ClassCastException ex) + { + throw new InvalidPluginException(ex); + } + + for (String pluginName : depend) + { + if (loaders == null) + { + throw new UnknownDependencyException(pluginName); + } + PluginClassLoader current = loaders.get(pluginName); + + if (current == null) + { + throw new UnknownDependencyException(pluginName); + } + } + + if (!ignoreSoftDependencies) + { + ArrayList softDepend; + + try + { + softDepend = (ArrayList) description.getSoftDepend(); + if (softDepend == null) + { + softDepend = new ArrayList(); + } + } catch (ClassCastException ex) + { + throw new InvalidPluginException(ex); + } + + for (String pluginName : softDepend) + { + if (loaders == null) + { + throw new UnknownSoftDependencyException(pluginName); + } + PluginClassLoader current = loaders.get(pluginName); + + if (current == null) + { + throw new UnknownSoftDependencyException(pluginName); + } + } + } + + PluginClassLoader loader = null; + + try + { + URL[] urls = new URL[1]; + + urls[0] = file.toURI().toURL(); + loader = new PluginClassLoader(this, urls, getClass().getClassLoader()); + Class jarClass = Class.forName(description.getMain(), true, loader); + Class plugin = jarClass.asSubclass(JavaPlugin.class); + + Constructor constructor = plugin.getConstructor(); + + result = constructor.newInstance(); + + result.initialize(this, server, description, dataFolder, file, loader); + } catch (Throwable ex) + { + throw new InvalidPluginException(ex); + } + + loaders.put(description.getName(), (PluginClassLoader) loader); + + return (Plugin) result; + } + + // Project Poseidon Start + private void notNull(Object object, String message) { + if (object == null) + throw new IllegalArgumentException(message); + } + @Override + @NotNull + public Map, Set> createRegisteredListeners(@NotNull Listener listener, @NotNull final Plugin plugin) { + notNull(plugin, "Plugin can not be null"); + notNull(listener, "Listener can not be null"); + + Map, Set> ret = new HashMap<>(); + Set methods; + try { + Method[] publicMethods = listener.getClass().getMethods(); + Method[] privateMethods = listener.getClass().getDeclaredMethods(); + methods = new HashSet(publicMethods.length + privateMethods.length, 1.0f); + Collections.addAll(methods, publicMethods); + Collections.addAll(methods, privateMethods); + } catch (NoClassDefFoundError e) { + if (listener instanceof PoseidonCustomListener) { + plugin.getServer().getLogger().log(Level.WARNING, "The plugin " + plugin.getDescription().getName() + " has tried to register an unknown event. Please ensure the plugin containing the event is loaded before any plugins that listen."); + } else { + plugin.getServer().getLogger().severe("Plugin " + plugin.getDescription().getFullName() + " has failed to register events for " + listener.getClass() + " because " + e.getMessage() + " does not exist."); + + } + return ret; + } + + for (final Method method : methods) { + final EventHandler eh = method.getAnnotation(EventHandler.class); + if (eh == null) + continue; + if (method.isBridge() || method.isSynthetic()) + continue; + final Class checkClass; + if (method.getParameterTypes().length != 1 || !Event.class.isAssignableFrom(checkClass = method.getParameterTypes()[0])) { + plugin.getServer().getLogger().severe(plugin.getDescription().getFullName() + " attempted to register an invalid EventHandler method signature \"" + method.toGenericString() + "\" in " + listener.getClass()); + continue; + } + final Class eventClass = checkClass.asSubclass(Event.class); + method.setAccessible(true); + Set eventSet = ret.computeIfAbsent(eventClass, k -> new HashSet<>()); + + for (Class clazz = eventClass; Event.class.isAssignableFrom(clazz); clazz = clazz.getSuperclass()) { + if (clazz.getAnnotation(Deprecated.class) != null) { + plugin.getServer().getLogger().log( + Level.WARNING, + String.format( + "\"%s\" has registered a listener for %s on method \"%s\", but the event is Deprecated." + + " \"%s\"; please notify the authors %s.", + plugin.getDescription().getFullName(), + clazz.getName(), + method.toGenericString(), + "Server performance will be affected", + Arrays.toString(plugin.getDescription().getAuthors().toArray())), + new AuthorNagException(null)); + break; + } + } + + final EventExecutor executor = (listener1, event) -> { + if (!eventClass.isAssignableFrom(event.getClass())) { + return; + } + try { + method.invoke(listener1, event); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + }; + eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); + } + return ret; + } + // Project Poseidon End + + protected File getDataFolder(File file) + { + File dataFolder = null; + + String filename = file.getName(); + int index = file.getName().lastIndexOf("."); + + if (index != -1) + { + String name = filename.substring(0, index); + + dataFolder = new File(file.getParentFile(), name); + } else + { + // This is if there is no extension, which should not happen + // Using _ to prevent name collision + + dataFolder = new File(file.getParentFile(), filename + "_"); + } + + return dataFolder; + } + + public Pattern[] getPluginFileFilters() + { + return fileFilters; + } + + public Class getClassByName(final String name) + { + Class cachedClass = classes.get(name); + + if (cachedClass != null) + { + return cachedClass; + } else + { + for (String current : loaders.keySet()) + { + PluginClassLoader loader = loaders.get(current); + + try + { + cachedClass = loader.findClass(name, false); + } catch (ClassNotFoundException cnfe) + { + } + if (cachedClass != null) + { + return cachedClass; + } + } + } + return null; + } + + public void setClass(final String name, final Class clazz) + { + if (!classes.containsKey(name)) + { + classes.put(name, clazz); + } + } + + public EventExecutor createExecutor(Event.Type type, Listener listener) + { + // TODO: remove multiple Listener type and hence casts + + switch (type) + { + // Poseidon events + case PACKET_RECEIVED: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PacketListener) listener).onPacketReceived((PacketReceivedEvent) event); + } + }; + + case INVENTORY_TRANSACTION: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((InventoryListener) listener).onInventoryTransaction((InventoryTransactionEvent) event); + } + }; + + // Player Events + + case PLAYER_JOIN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerJoin((PlayerJoinEvent) event); + } + }; + + case PLAYER_QUIT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerQuit((PlayerQuitEvent) event); + } + }; + + case PLAYER_RESPAWN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerRespawn((PlayerRespawnEvent) event); + } + }; + // Project Poseidon Start + case ITEM_DESPAWN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onItemDespawn((ItemDespawnEvent) event); + } + }; + // Project Poseidon End + case PLAYER_KICK: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerKick((PlayerKickEvent) event); + } + }; + + case PLAYER_COMMAND_PREPROCESS: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerCommandPreprocess((PlayerCommandPreprocessEvent) event); + } + }; + + case PLAYER_CHAT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerChat((PlayerChatEvent) event); + } + }; + + case PLAYER_MOVE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerMove((PlayerMoveEvent) event); + } + }; + + case PLAYER_VELOCITY: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerVelocity((PlayerVelocityEvent) event); + } + }; + + case PLAYER_TELEPORT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerTeleport((PlayerTeleportEvent) event); + } + }; + + case PLAYER_PORTAL: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerPortal((PlayerPortalEvent) event); + } + }; + + case PLAYER_INTERACT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerInteract((PlayerInteractEvent) event); + } + }; + + case PLAYER_INTERACT_ENTITY: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerInteractEntity((PlayerInteractEntityEvent) event); + } + }; + + case PLAYER_LOGIN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerLogin((PlayerLoginEvent) event); + } + }; + + case PLAYER_PRELOGIN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerPreLogin((PlayerPreLoginEvent) event); + } + }; + + case PLAYER_EGG_THROW: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerEggThrow((PlayerEggThrowEvent) event); + } + }; + + case PLAYER_ANIMATION: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerAnimation((PlayerAnimationEvent) event); + } + }; + + case INVENTORY_OPEN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onInventoryOpen((PlayerInventoryEvent) event); + } + }; + + case PLAYER_ITEM_HELD: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onItemHeldChange((PlayerItemHeldEvent) event); + } + }; + + case PLAYER_DROP_ITEM: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerDropItem((PlayerDropItemEvent) event); + } + }; + + case PLAYER_PICKUP_ITEM: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerPickupItem((PlayerPickupItemEvent) event); + } + }; + + case PLAYER_TOGGLE_SNEAK: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerToggleSneak((PlayerToggleSneakEvent) event); + } + }; + + case PLAYER_BUCKET_EMPTY: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerBucketEmpty((PlayerBucketEmptyEvent) event); + } + }; + + case PLAYER_BUCKET_FILL: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerBucketFill((PlayerBucketFillEvent) event); + } + }; + + case PLAYER_BED_ENTER: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerBedEnter((PlayerBedEnterEvent) event); + } + }; + + case PLAYER_BED_LEAVE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerBedLeave((PlayerBedLeaveEvent) event); + } + }; + + case PLAYER_FISH: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerFish((PlayerFishEvent) event); + } + }; + case PLAYER_ITEM_DAMAGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((PlayerListener) listener).onPlayerItemDamage((PlayerItemDamageEvent) event); + } + }; + case PLAYER_CHANGED_WORLD: + return new EventExecutor() { + public void execute(Listener listener, Event event) { + ((PlayerListener) listener).onPlayerChangedWorld((PlayerChangedWorldEvent) event); + } + }; + + // Block Events + case BLOCK_PHYSICS: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockPhysics((BlockPhysicsEvent) event); + } + }; + + case BLOCK_CANBUILD: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockCanBuild((BlockCanBuildEvent) event); + } + }; + + case BLOCK_PLACE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockPlace((BlockPlaceEvent) event); + } + }; + + case BLOCK_DAMAGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockDamage((BlockDamageEvent) event); + } + }; + + case BLOCK_FROMTO: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockFromTo((BlockFromToEvent) event); + } + }; + + case LEAVES_DECAY: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onLeavesDecay((LeavesDecayEvent) event); + } + }; + + case SIGN_CHANGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onSignChange((SignChangeEvent) event); + } + }; + + case BLOCK_IGNITE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockIgnite((BlockIgniteEvent) event); + } + }; + + case REDSTONE_CHANGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockRedstoneChange((BlockRedstoneEvent) event); + } + }; + + case BLOCK_BURN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockBurn((BlockBurnEvent) event); + } + }; + + case BLOCK_BREAK: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockBreak((BlockBreakEvent) event); + } + }; + + case BLOCK_FORM: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockForm((BlockFormEvent) event); + } + }; + + case BLOCK_SPREAD: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockSpread((BlockSpreadEvent) event); + } + }; + + case BLOCK_FADE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockFade((BlockFadeEvent) event); + } + }; + + case BLOCK_DISPENSE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockDispense((BlockDispenseEvent) event); + } + }; + + case BLOCK_PISTON_RETRACT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockPistonRetract((BlockPistonRetractEvent) event); + } + }; + + case BLOCK_PISTON_EXTEND: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((BlockListener) listener).onBlockPistonExtend((BlockPistonExtendEvent) event); + } + }; + + // Server Events + case PLUGIN_ENABLE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((ServerListener) listener).onPluginEnable((PluginEnableEvent) event); + } + }; + + case PLUGIN_DISABLE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((ServerListener) listener).onPluginDisable((PluginDisableEvent) event); + } + }; + + case SERVER_COMMAND: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((ServerListener) listener).onServerCommand((ServerCommandEvent) event); + } + }; + + case MAP_INITIALIZE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((ServerListener) listener).onMapInitialize((MapInitializeEvent) event); + } + }; + + // World Events + case CHUNK_LOAD: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onChunkLoad((ChunkLoadEvent) event); + } + }; + + case CHUNK_POPULATED: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onChunkPopulate((ChunkPopulateEvent) event); + } + }; + + case CHUNK_UNLOAD: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onChunkUnload((ChunkUnloadEvent) event); + } + }; + + case SPAWN_CHANGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onSpawnChange((SpawnChangeEvent) event); + } + }; + + case WORLD_SAVE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onWorldSave((WorldSaveEvent) event); + } + }; + + case WORLD_INIT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onWorldInit((WorldInitEvent) event); + } + }; + + case WORLD_LOAD: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onWorldLoad((WorldLoadEvent) event); + } + }; + + case WORLD_UNLOAD: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onWorldUnload((WorldUnloadEvent) event); + } + }; + + case PORTAL_CREATE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WorldListener) listener).onPortalCreate((PortalCreateEvent) event); + } + }; + + // Painting Events + case PAINTING_PLACE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onPaintingPlace((PaintingPlaceEvent) event); + } + }; + + case PAINTING_BREAK: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onPaintingBreak((PaintingBreakEvent) event); + } + }; + + // Entity Events + case ENTITY_DAMAGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityDamage((EntityDamageEvent) event); + } + }; + // Project Poseidon Start + case ENTITY_DAMAGE_BY_ENTITY: + return new EventExecutor() { + @Override + public void execute(Listener listener, Event event) { + ((EntityListener) listener).onEntityDamageByEntity((EntityDamageByEntityEvent) event); + } + }; + case ENTITY_DAMAGE_BY_BLOCK: + return new EventExecutor() { + @Override + public void execute(Listener listener, Event event) { + ((EntityListener) listener).onEntityDamageByBlock((EntityDamageByBlockEvent) event); + } + }; + // Project Poseidon End + + case ENTITY_DEATH: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityDeath((EntityDeathEvent) event); + } + }; + + case ENTITY_COMBUST: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityCombust((EntityCombustEvent) event); + } + }; + + case ENTITY_EXPLODE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityExplode((EntityExplodeEvent) event); + } + }; + + case EXPLOSION_PRIME: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onExplosionPrime((ExplosionPrimeEvent) event); + } + }; + + case ENTITY_TARGET: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityTarget((EntityTargetEvent) event); + } + }; + + case ENTITY_INTERACT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityInteract((EntityInteractEvent) event); + } + }; + + case ENTITY_PORTAL_ENTER: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityPortalEnter((EntityPortalEnterEvent) event); + } + }; + + case CREATURE_SPAWN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onCreatureSpawn((CreatureSpawnEvent) event); + } + }; + + case ITEM_SPAWN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onItemSpawn((ItemSpawnEvent) event); + } + }; + + case PIG_ZAP: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onPigZap((PigZapEvent) event); + } + }; + + case CREEPER_POWER: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onCreeperPower((CreeperPowerEvent) event); + } + }; + + case ENTITY_TAME: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityTame((EntityTameEvent) event); + } + }; + + case ENTITY_REGAIN_HEALTH: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onEntityRegainHealth((EntityRegainHealthEvent) event); + } + }; + + case PROJECTILE_HIT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((EntityListener) listener).onProjectileHit((ProjectileHitEvent) event); + } + }; + + // Vehicle Events + case VEHICLE_CREATE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleCreate((VehicleCreateEvent) event); + } + }; + + case VEHICLE_DAMAGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleDamage((VehicleDamageEvent) event); + } + }; + + case VEHICLE_DESTROY: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleDestroy((VehicleDestroyEvent) event); + } + }; + + case VEHICLE_COLLISION_BLOCK: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleBlockCollision((VehicleBlockCollisionEvent) event); + } + }; + + case VEHICLE_COLLISION_ENTITY: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleEntityCollision((VehicleEntityCollisionEvent) event); + } + }; + + case VEHICLE_ENTER: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleEnter((VehicleEnterEvent) event); + } + }; + + case VEHICLE_EXIT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleExit((VehicleExitEvent) event); + } + }; + + case VEHICLE_MOVE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleMove((VehicleMoveEvent) event); + } + }; + + case VEHICLE_UPDATE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((VehicleListener) listener).onVehicleUpdate((VehicleUpdateEvent) event); + } + }; + + // Weather Events + case WEATHER_CHANGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WeatherListener) listener).onWeatherChange((WeatherChangeEvent) event); + } + }; + + case THUNDER_CHANGE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WeatherListener) listener).onThunderChange((ThunderChangeEvent) event); + } + }; + + case LIGHTNING_STRIKE: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((WeatherListener) listener).onLightningStrike((LightningStrikeEvent) event); + } + }; + + // Inventory Events + case FURNACE_SMELT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((InventoryListener) listener).onFurnaceSmelt((FurnaceSmeltEvent) event); + } + }; + case FURNACE_BURN: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((InventoryListener) listener).onFurnaceBurn((FurnaceBurnEvent) event); + } + }; + + // Custom Events + case CUSTOM_EVENT: + return new EventExecutor() + { + public void execute(Listener listener, Event event) + { + ((CustomEventListener) listener).onCustomEvent(event); + } + }; + } + + throw new IllegalArgumentException("Event " + type + " is not supported"); + } + + public void enablePlugin(final Plugin plugin) + { + if (!(plugin instanceof JavaPlugin)) + { + throw new IllegalArgumentException("Plugin is not associated with this PluginLoader"); + } + + if (!plugin.isEnabled()) + { + JavaPlugin jPlugin = (JavaPlugin) plugin; + + String pluginName = jPlugin.getDescription().getName(); + + if (!loaders.containsKey(pluginName)) + { + loaders.put(pluginName, (PluginClassLoader) jPlugin.getClassLoader()); + } + + try + { + jPlugin.setEnabled(true); + } catch (Throwable ex) + { + server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex); + } + + // Perhaps abort here, rather than continue going, but as it stands, + // an abort is not possible the way it's currently written + server.getPluginManager().callEvent(new PluginEnableEvent(plugin)); + } + } + + public void disablePlugin(Plugin plugin) + { + if (!(plugin instanceof JavaPlugin)) + { + throw new IllegalArgumentException("Plugin is not associated with this PluginLoader"); + } + + if (plugin.isEnabled()) + { + JavaPlugin jPlugin = (JavaPlugin) plugin; + ClassLoader cloader = jPlugin.getClassLoader(); + + try + { + jPlugin.setEnabled(false); + } catch (Throwable ex) + { + server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex); + } + + server.getPluginManager().callEvent(new PluginDisableEvent(plugin)); + + loaders.remove(jPlugin.getDescription().getName()); + + if (cloader instanceof PluginClassLoader) + { + PluginClassLoader loader = (PluginClassLoader) cloader; + Set names = loader.getClasses(); + + for (String name : names) + { + classes.remove(name); + } + } + } + } +} diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java new file mode 100644 index 0000000..f998e30 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java @@ -0,0 +1,52 @@ +package org.bukkit.plugin.java; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * A ClassLoader for plugins, to allow shared classes across multiple plugins + */ +public class PluginClassLoader extends URLClassLoader { + private final JavaPluginLoader loader; + private final Map> classes = new HashMap>(); + + public PluginClassLoader(final JavaPluginLoader loader, final URL[] urls, final ClassLoader parent) { + super(urls, parent); + + this.loader = loader; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + return findClass(name, true); + } + + protected Class findClass(String name, boolean checkGlobal) throws ClassNotFoundException { + Class result = classes.get(name); + + if (result == null) { + if (checkGlobal) { + result = loader.getClassByName(name); + } + + if (result == null) { + result = super.findClass(name); + + if (result != null) { + loader.setClass(name, result); + } + } + + classes.put(name, result); + } + + return result; + } + + public Set getClasses() { + return classes.keySet(); + } +} diff --git a/src/main/java/org/bukkit/scheduler/BukkitScheduler.java b/src/main/java/org/bukkit/scheduler/BukkitScheduler.java new file mode 100644 index 0000000..9bc88af --- /dev/null +++ b/src/main/java/org/bukkit/scheduler/BukkitScheduler.java @@ -0,0 +1,151 @@ +package org.bukkit.scheduler; + +import org.bukkit.plugin.Plugin; + +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +public interface BukkitScheduler { + + /** + * Schedules a once off task to occur after a delay + * This task will be executed by the main server thread + * + * @param Plugin Plugin that owns the task + * @param Runnable Task to be executed + * @param long Delay in server ticks before executing task + * @return int Task id number (-1 if scheduling failed) + */ + public int scheduleSyncDelayedTask(Plugin plugin, Runnable task, long delay); + + /** + * Schedules a once off task to occur as soon as possible + * This task will be executed by the main server thread + * + * @param Plugin Plugin that owns the task + * @param Runnable Task to be executed + * @return int Task id number (-1 if scheduling failed) + */ + public int scheduleSyncDelayedTask(Plugin plugin, Runnable task); + + /** + * Schedules a repeating task + * This task will be executed by the main server thread + * + * @param Plugin Plugin that owns the task + * @param Runnable Task to be executed + * @param long Delay in server ticks before executing first repeat + * @param long Period in server ticks of the task + * @return int Task id number (-1 if scheduling failed) + */ + public int scheduleSyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period); + + /** + * Schedules a once off task to occur after a delay + * This task will be executed by a thread managed by the scheduler + * + * @param Plugin Plugin that owns the task + * @param Runnable Task to be executed + * @param long Delay in server ticks before executing task + * @return int Task id number (-1 if scheduling failed) + */ + public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task, long delay); + + /** + * Schedules a once off task to occur as soon as possible + * This task will be executed by a thread managed by the scheduler + * + * @param Plugin Plugin that owns the task + * @param Runnable Task to be executed + * @return int Task id number (-1 if scheduling failed) + */ + public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task); + + /** + * Schedules a repeating task + * This task will be executed by a thread managed by the scheduler + * + * @param Plugin Plugin that owns the task + * @param Runnable Task to be executed + * @param long Delay in server ticks before executing first repeat + * @param long Period in server ticks of the task + * @return int Task id number (-1 if scheduling failed) + */ + public int scheduleAsyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period); + + /** + * Calls a method on the main thread and returns a Future object + * This task will be executed by the main server thread + * + * Note: The Future.get() methods must NOT be called from the main thread + * Note2: There is at least an average of 10ms latency until the isDone() method returns true + * + * @param Plugin Plugin that owns the task + * @param Callable Task to be executed + * @return Future Future object related to the task + */ + public Future callSyncMethod(Plugin plugin, Callable task); + + /** + * Removes task from scheduler + * + * @param int Id number of task to be removed + */ + public void cancelTask(int taskId); + + /** + * Removes all tasks associated with a particular plugin from the scheduler + * + * @param Plugin Owner of tasks to be removed + */ + public void cancelTasks(Plugin plugin); + + /** + * Removes all tasks from the scheduler + */ + public void cancelAllTasks(); + + /** + * Check if the task currently running. + * + * A repeating task might not be running currently, but will be running in the future. + * A task that has finished, and does not repeat, will not be running ever again. + * + * Explicitly, a task is running if there exists a thread for it, and that thread is alive. + * + * @param taskId The task to check. + * + * @return If the task is currently running. + */ + public boolean isCurrentlyRunning(int taskId); + + /** + * Check if the task queued to be run later. + * + * If a repeating task is currently running, it might not be queued now but could be in the future. + * A task that is not queued, and not running, will not be queued again. + * + * @param taskId The task to check. + * + * @return If the task is queued to be run. + */ + public boolean isQueued(int taskId); + + /** + * Returns a list of all active workers. + * + * This list contains asynch tasks that are being executed by separate threads. + * + * @return Active workers + */ + public List getActiveWorkers(); + + /** + * Returns a list of all pending tasks. The ordering of the tasks is not related to their order of execution. + * + * @return Active workers + */ + public List getPendingTasks(); + +} diff --git a/src/main/java/org/bukkit/scheduler/BukkitTask.java b/src/main/java/org/bukkit/scheduler/BukkitTask.java new file mode 100644 index 0000000..f82514c --- /dev/null +++ b/src/main/java/org/bukkit/scheduler/BukkitTask.java @@ -0,0 +1,31 @@ +package org.bukkit.scheduler; + +import org.bukkit.plugin.Plugin; + +/** + * Represents a task being executed by the scheduler + */ + +public interface BukkitTask { + + /** + * Returns the taskId for the task + * + * @return Task id number + */ + public int getTaskId(); + + /** + * Returns the Plugin that owns this task + * + * @return The Plugin that owns the task + */ + public Plugin getOwner(); + + /** + * Returns true if the Task is a sync task + * + * @return true if the task is run by main thread + */ + public boolean isSync(); +} diff --git a/src/main/java/org/bukkit/scheduler/BukkitWorker.java b/src/main/java/org/bukkit/scheduler/BukkitWorker.java new file mode 100644 index 0000000..b85a01c --- /dev/null +++ b/src/main/java/org/bukkit/scheduler/BukkitWorker.java @@ -0,0 +1,35 @@ +package org.bukkit.scheduler; + +import org.bukkit.plugin.Plugin; + +/** + * Represents a worker thread for the scheduler. This gives information about + * the Thread object for the task, owner of the task and the taskId. + * + * Workers are used to execute async tasks. + */ + +public interface BukkitWorker { + + /** + * Returns the taskId for the task being executed by this worker + * + * @return Task id number + */ + public int getTaskId(); + + /** + * Returns the Plugin that owns this task + * + * @return The Plugin that owns the task + */ + public Plugin getOwner(); + + /** + * Returns the thread for the worker + * + * @return The Thread object for the worker + */ + public Thread getThread(); + +} diff --git a/src/main/java/org/bukkit/util/BlockIterator.java b/src/main/java/org/bukkit/util/BlockIterator.java new file mode 100644 index 0000000..cf0d534 --- /dev/null +++ b/src/main/java/org/bukkit/util/BlockIterator.java @@ -0,0 +1,382 @@ +package org.bukkit.util; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.LivingEntity; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * This class performs ray tracing and iterates along blocks on a line + * + * @author raphfrk + */ + +public class BlockIterator implements Iterator { + + private final World world; + private final int maxDistance; + + private static final int gridSize = 1 << 24; + + private boolean end = false; + + private Block[] blockQueue = new Block[3]; + private int currentBlock = 0; + private int currentDistance = 0; + private int maxDistanceInt; + + private int secondError; + private int thirdError; + + private int secondStep; + private int thirdStep; + + private BlockFace mainFace; + private BlockFace secondFace; + private BlockFace thirdFace; + + /** + * Constructs the BlockIterator + * + * @param world The world to use for tracing + * @param start A Vector giving the initial location for the trace + * @param direction A Vector pointing in the direction for the trace + * @param yOffset The trace begins vertically offset from the start vector by this value + * @param maxDistance This is the maximum distance in blocks for the trace. Setting this value above 140 may lead to problems with unloaded chunks. A value of 0 indicates no limit + * + */ + + public BlockIterator(World world, Vector start, Vector direction, double yOffset, int maxDistance) { + this.world = world; + this.maxDistance = maxDistance; + + Vector startClone = start.clone(); + + startClone.setY(startClone.getY() + yOffset); + + currentDistance = 0; + + double mainDirection = 0; + double secondDirection = 0; + double thirdDirection = 0; + + double mainPosition = 0; + double secondPosition = 0; + double thirdPosition = 0; + + Block startBlock = world.getBlockAt((int) Math.floor(startClone.getX()), (int) Math.floor(startClone.getY()), (int) Math.floor(startClone.getZ())); + + if (getXLength(direction) > mainDirection) { + mainFace = getXFace(direction); + mainDirection = getXLength(direction); + mainPosition = getXPosition(direction, startClone, startBlock); + + secondFace = getYFace(direction); + secondDirection = getYLength(direction); + secondPosition = getYPosition(direction, startClone, startBlock); + + thirdFace = getZFace(direction); + thirdDirection = getZLength(direction); + thirdPosition = getZPosition(direction, startClone, startBlock); + } + if (getYLength(direction) > mainDirection) { + mainFace = getYFace(direction); + mainDirection = getYLength(direction); + mainPosition = getYPosition(direction, startClone, startBlock); + + secondFace = getZFace(direction); + secondDirection = getZLength(direction); + secondPosition = getZPosition(direction, startClone, startBlock); + + thirdFace = getXFace(direction); + thirdDirection = getXLength(direction); + thirdPosition = getXPosition(direction, startClone, startBlock); + } + if (getZLength(direction) > mainDirection) { + mainFace = getZFace(direction); + mainDirection = getZLength(direction); + mainPosition = getZPosition(direction, startClone, startBlock); + + secondFace = getXFace(direction); + secondDirection = getXLength(direction); + secondPosition = getXPosition(direction, startClone, startBlock); + + thirdFace = getYFace(direction); + thirdDirection = getYLength(direction); + thirdPosition = getYPosition(direction, startClone, startBlock); + } + + // trace line backwards to find intercept with plane perpendicular to the main axis + + double d = mainPosition / mainDirection; // how far to hit face behind + double secondd = secondPosition - secondDirection * d; + double thirdd = thirdPosition - thirdDirection * d; + + // Guarantee that the ray will pass though the start block. + // It is possible that it would miss due to rounding + // This should only move the ray by 1 grid position + secondError = (int) (Math.floor(secondd * gridSize)); + secondStep = (int) (Math.round(secondDirection / mainDirection * gridSize)); + thirdError = (int) (Math.floor(thirdd * gridSize)); + thirdStep = (int) (Math.round(thirdDirection / mainDirection * gridSize)); + + if (secondError + secondStep <= 0) { + secondError = -secondStep + 1; + } + + if (thirdError + thirdStep <= 0) { + thirdError = -thirdStep + 1; + } + + Block lastBlock; + + lastBlock = startBlock.getRelative(reverseFace(mainFace)); + + if (secondError < 0) { + secondError += gridSize; + lastBlock = lastBlock.getRelative(reverseFace(secondFace)); + } + + if (thirdError < 0) { + thirdError += gridSize; + lastBlock = lastBlock.getRelative(reverseFace(thirdFace)); + } + + // This means that when the variables are positive, it means that the coord=1 boundary has been crossed + secondError -= gridSize; + thirdError -= gridSize; + + blockQueue[0] = lastBlock; + currentBlock = -1; + + scan(); + + boolean startBlockFound = false; + + for (int cnt = currentBlock; cnt >= 0; cnt--) { + if (blockEquals(blockQueue[cnt], startBlock)) { + currentBlock = cnt; + startBlockFound = true; + break; + } + } + + if (!startBlockFound) { + throw new IllegalStateException("Start block missed in BlockIterator"); + } + + // Calculate the number of planes passed to give max distance + maxDistanceInt = (int) Math.round(maxDistance / (Math.sqrt(mainDirection * mainDirection + secondDirection * secondDirection + thirdDirection * thirdDirection) / mainDirection)); + + } + + private boolean blockEquals(Block a, Block b) { + return a.getX() == b.getX() && a.getY() == b.getY() && a.getZ() == b.getZ(); + } + + private BlockFace reverseFace(BlockFace face) { + switch (face) { + case UP: + return BlockFace.DOWN; + + case DOWN: + return BlockFace.UP; + + case NORTH: + return BlockFace.SOUTH; + + case SOUTH: + return BlockFace.NORTH; + + case EAST: + return BlockFace.WEST; + + case WEST: + return BlockFace.EAST; + + default: + return null; + } + } + + private BlockFace getXFace(Vector direction) { + return ((direction.getX() > 0) ? BlockFace.SOUTH : BlockFace.NORTH); + } + + private BlockFace getYFace(Vector direction) { + return ((direction.getY() > 0) ? BlockFace.UP : BlockFace.DOWN); + } + + private BlockFace getZFace(Vector direction) { + return ((direction.getZ() > 0) ? BlockFace.WEST : BlockFace.EAST); + } + + private double getXLength(Vector direction) { + return(Math.abs(direction.getX())); + } + + private double getYLength(Vector direction) { + return(Math.abs(direction.getY())); + } + + private double getZLength(Vector direction) { + return(Math.abs(direction.getZ())); + } + + private double getPosition(double direction, double position, int blockPosition) { + return direction > 0 ? (position - blockPosition) : (blockPosition + 1 - position); + } + + private double getXPosition(Vector direction, Vector position, Block block) { + return getPosition(direction.getX(), position.getX(), block.getX()); + } + + private double getYPosition(Vector direction, Vector position, Block block) { + return getPosition(direction.getY(), position.getY(), block.getY()); + } + + private double getZPosition(Vector direction, Vector position, Block block) { + return getPosition(direction.getZ(), position.getZ(), block.getZ()); + } + + /** + * Constructs the BlockIterator + * + * @param loc The location for the start of the ray trace + * @param yOffset The trace begins vertically offset from the start vector by this value + * @param maxDistance This is the maximum distance in blocks for the trace. Setting this value above 140 may lead to problems with unloaded chunks. A value of 0 indicates no limit + * + */ + + public BlockIterator(Location loc, double yOffset, int maxDistance) { + this(loc.getWorld(), loc.toVector(), loc.getDirection(), yOffset, maxDistance); + } + + /** + * Constructs the BlockIterator. + * + * @param loc The location for the start of the ray trace + * @param yOffset The trace begins vertically offset from the start vector by this value + * + */ + + public BlockIterator(Location loc, double yOffset) { + this(loc.getWorld(), loc.toVector(), loc.getDirection(), yOffset, 0); + } + + /** + * Constructs the BlockIterator. + * + * @param loc The location for the start of the ray trace + * + */ + + public BlockIterator(Location loc) { + this(loc, 0D); + } + + /** + * Constructs the BlockIterator. + * + * @param entity Information from the entity is used to set up the trace + * @param maxDistance This is the maximum distance in blocks for the trace. Setting this value above 140 may lead to problems with unloaded chunks. A value of 0 indicates no limit + * + */ + + public BlockIterator(LivingEntity entity, int maxDistance) { + this(entity.getLocation(), entity.getEyeHeight(), maxDistance); + } + + /** + * Constructs the BlockIterator. + * + * @param entity Information from the entity is used to set up the trace + * + */ + + public BlockIterator(LivingEntity entity) { + this(entity, 0); + } + + /** + * Returns true if the iteration has more elements + * + */ + + public boolean hasNext() { + scan(); + return currentBlock != -1; + } + + /** + * Returns the next Block in the trace + * + * @return the next Block in the trace + */ + + public Block next() { + scan(); + if (currentBlock <= -1) { + throw new NoSuchElementException(); + } else { + return blockQueue[currentBlock--]; + } + } + + public void remove() { + throw new UnsupportedOperationException("[BlockIterator] doesn't support block removal"); + } + + private void scan() { + if (currentBlock >= 0) { + return; + } + if (maxDistance != 0 && currentDistance > maxDistanceInt) { + end = true; + return; + } + if (end) { + return; + } + + currentDistance++; + + secondError += secondStep; + thirdError += thirdStep; + + if (secondError > 0 && thirdError > 0) { + blockQueue[2] = blockQueue[0].getRelative(mainFace); + if (((long) secondStep) * ((long) thirdError) < ((long) thirdStep) * ((long) secondError)) { + blockQueue[1] = blockQueue[2].getRelative(secondFace); + blockQueue[0] = blockQueue[1].getRelative(thirdFace); + } else { + blockQueue[1] = blockQueue[2].getRelative(thirdFace); + blockQueue[0] = blockQueue[1].getRelative(secondFace); + } + thirdError -= gridSize; + secondError -= gridSize; + currentBlock = 2; + return; + } else if (secondError > 0) { + blockQueue[1] = blockQueue[0].getRelative(mainFace); + blockQueue[0] = blockQueue[1].getRelative(secondFace); + secondError -= gridSize; + currentBlock = 1; + return; + } else if (thirdError > 0) { + blockQueue[1] = blockQueue[0].getRelative(mainFace); + blockQueue[0] = blockQueue[1].getRelative(thirdFace); + thirdError -= gridSize; + currentBlock = 1; + return; + } else { + blockQueue[0] = blockQueue[0].getRelative(mainFace); + currentBlock = 0; + return; + } + } +} diff --git a/src/main/java/org/bukkit/util/BlockVector.java b/src/main/java/org/bukkit/util/BlockVector.java new file mode 100644 index 0000000..4bd3fdc --- /dev/null +++ b/src/main/java/org/bukkit/util/BlockVector.java @@ -0,0 +1,111 @@ +package org.bukkit.util; + +/** + * A vector with a hash function that floors the X, Y, Z components, a la + * BlockVector in WorldEdit. BlockVectors can be used in hash sets and + * hash maps. Be aware that BlockVectors are mutable, but it is important + * that BlockVectors are never changed once put into a hash set or hash map. + * + * @author sk89q + */ +public class BlockVector extends Vector { + + /** + * Construct the vector with all components as 0. + */ + public BlockVector() { + this.x = 0; + this.y = 0; + this.z = 0; + } + + /** + * Construct the vector with another vector. + */ + public BlockVector(Vector vec) { + this.x = vec.getX(); + this.y = vec.getY(); + this.z = vec.getZ(); + } + + /** + * Construct the vector with provided integer components. + * + * @param x + * @param y + * @param z + */ + public BlockVector(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Construct the vector with provided double components. + * + * @param x + * @param y + * @param z + */ + public BlockVector(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Construct the vector with provided float components. + * + * @param x + * @param y + * @param z + */ + public BlockVector(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Checks if another object is equivalent. + * + * @param obj + * @return whether the other object is equivalent + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof BlockVector)) { + return false; + } + BlockVector other = (BlockVector) obj; + + return (int) other.getX() == (int) this.x && (int) other.getY() == (int) this.y && (int) other.getZ() == (int) this.z; + + } + + /** + * Returns a hash code for this vector. + * + * @return hash code + */ + @Override + public int hashCode() { + return (Integer.valueOf((int) x).hashCode() >> 13) ^ (Integer.valueOf((int) y).hashCode() >> 7) ^ Integer.valueOf((int) z).hashCode(); + } + + /** + * Get a new block vector. + * + * @return vector + */ + @Override + public BlockVector clone() { + BlockVector v = (BlockVector) super.clone(); + + v.x = x; + v.y = y; + v.z = z; + return v; + } +} diff --git a/src/main/java/org/bukkit/util/FileUtil.java b/src/main/java/org/bukkit/util/FileUtil.java new file mode 100644 index 0000000..7fc87fa --- /dev/null +++ b/src/main/java/org/bukkit/util/FileUtil.java @@ -0,0 +1,59 @@ +package org.bukkit.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; + +/** + * Class containing file utilities + */ + +public class FileUtil { + + /** + * This method copies one file to another location + * + * @param inFile the source filename + * @param outFile the target filename + * @return true on success + */ + + public static boolean copy(File inFile, File outFile) { + if (!inFile.exists()) { + return false; + } + + FileChannel in = null; + FileChannel out = null; + + try { + in = new FileInputStream(inFile).getChannel(); + out = new FileOutputStream(outFile).getChannel(); + + long pos = 0; + long size = in.size(); + + while (pos < size) { + pos += in.transferTo(pos, 10 * 1024 * 1024, out); + } + } catch (IOException ioe) { + return false; + } finally { + try { + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } catch (IOException ioe) { + return false; + } + } + + return true; + + } +} diff --git a/src/main/java/org/bukkit/util/Java15Compat.java b/src/main/java/org/bukkit/util/Java15Compat.java new file mode 100644 index 0000000..c119742 --- /dev/null +++ b/src/main/java/org/bukkit/util/Java15Compat.java @@ -0,0 +1,21 @@ +package org.bukkit.util; + +import java.lang.reflect.Array; + +public class Java15Compat { + @SuppressWarnings("unchecked") + public static T[] Arrays_copyOfRange(T[] original, int start, int end) { + if (original.length >= start && 0 <= start) { + if (start <= end) { + int length = end - start; + int copyLength = Math.min(length, original.length - start); + T[] copy = (T[]) Array.newInstance(original.getClass().getComponentType(), length); + + System.arraycopy(original, start, copy, 0, copyLength); + return copy; + } + throw new IllegalArgumentException(); + } + throw new ArrayIndexOutOfBoundsException(); + } +} diff --git a/src/main/java/org/bukkit/util/Vector.java b/src/main/java/org/bukkit/util/Vector.java new file mode 100644 index 0000000..1b186ef --- /dev/null +++ b/src/main/java/org/bukkit/util/Vector.java @@ -0,0 +1,635 @@ +package org.bukkit.util; + +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.Random; + +/** + * Represents a mutable vector. Because the components of Vectors are mutable, + * storing Vectors long term may be dangerous if passing code modifies the + * Vector later. If you want to keep around a Vector, it may be wise to call + * clone() in order to get a copy. + * + * @author sk89q + */ +public class Vector implements Cloneable { + private static final long serialVersionUID = -2657651106777219169L; + + private static Random random = new Random(); + + /** + * Threshold for fuzzy equals(). + */ + private static final double epsilon = 0.000001; + + protected double x; + protected double y; + protected double z; + + /** + * Construct the vector with all components as 0. + */ + public Vector() { + this.x = 0; + this.y = 0; + this.z = 0; + } + + /** + * Construct the vector with provided integer components. + * + * @param x + * @param y + * @param z + */ + public Vector(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Construct the vector with provided double components. + * + * @param x + * @param y + * @param z + */ + public Vector(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Construct the vector with provided float components. + * + * @param x + * @param y + * @param z + */ + public Vector(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Adds the vector by another. + * + * @param vec + * @return the same vector + */ + public Vector add(Vector vec) { + x += vec.x; + y += vec.y; + z += vec.z; + return this; + } + + /** + * Subtracts the vector by another. + * + * @param vec + * @return the same vector + */ + public Vector subtract(Vector vec) { + x -= vec.x; + y -= vec.y; + z -= vec.z; + return this; + } + + /** + * Multiplies the vector by another. + * + * @param vec + * @return the same vector + */ + public Vector multiply(Vector vec) { + x *= vec.x; + y *= vec.y; + z *= vec.z; + return this; + } + + /** + * Divides the vector by another. + * + * @param vec + * @return the same vector + */ + public Vector divide(Vector vec) { + x /= vec.x; + y /= vec.y; + z /= vec.z; + return this; + } + + /** + * Copies another vector + * + * @param vec + * @return the same vector + */ + public Vector copy(Vector vec) { + x = vec.x; + y = vec.y; + z = vec.z; + return this; + } + + /** + * Gets the magnitude of the vector, defined as sqrt(x^2+y^2+z^2). The value + * of this method is not cached and uses a costly square-root function, so + * do not repeatedly call this method to get the vector's magnitude. NaN + * will be returned if the inner result of the sqrt() function overflows, + * which will be caused if the length is too long. + * + * @return the magnitude + */ + public double length() { + return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)); + } + + /** + * Gets the magnitude of the vector squared. + * + * @return the magnitude + */ + public double lengthSquared() { + return Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2); + } + + /** + * Get the distance between this vector and another. The value + * of this method is not cached and uses a costly square-root function, so + * do not repeatedly call this method to get the vector's magnitude. NaN + * will be returned if the inner result of the sqrt() function overflows, + * which will be caused if the distance is too long. + * + * @return the distance + */ + public double distance(Vector o) { + return Math.sqrt(Math.pow(x - o.x, 2) + Math.pow(y - o.y, 2) + Math.pow(z - o.z, 2)); + } + + /** + * Get the squared distance between this vector and another. + * + * @return the distance + */ + public double distanceSquared(Vector o) { + return Math.pow(x - o.x, 2) + Math.pow(y - o.y, 2) + Math.pow(z - o.z, 2); + } + + /** + * Gets the angle between this vector and another in radians. + * + * @param other + * @return angle in radians + */ + public float angle(Vector other) { + double dot = dot(other) / (length() * other.length()); + + return (float) Math.acos(dot); + } + + /** + * Sets this vector to the midpoint between this vector and another. + * + * @param other + * @return this same vector (now a midpoint) + */ + public Vector midpoint(Vector other) { + x = (x + other.x) / 2; + y = (y + other.y) / 2; + z = (z + other.z) / 2; + return this; + } + + /** + * Gets a new midpoint vector between this vector and another. + * + * @param other + * @return a new midpoint vector + */ + public Vector getMidpoint(Vector other) { + x = (x + other.x) / 2; + y = (y + other.y) / 2; + z = (z + other.z) / 2; + return new Vector(x, y, z); + } + + /** + * Performs scalar multiplication, multiplying all components with a scalar. + * + * @param m + * @return the same vector + */ + public Vector multiply(int m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Performs scalar multiplication, multiplying all components with a scalar. + * + * @param m + * @return the same vector + */ + public Vector multiply(double m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Performs scalar multiplication, multiplying all components with a scalar. + * + * @param m + * @return the same vector + */ + public Vector multiply(float m) { + x *= m; + y *= m; + z *= m; + return this; + } + + /** + * Calculates the dot product of this vector with another. The dot product + * is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar. + * + * @param other + * @return dot product + */ + public double dot(Vector other) { + return x * other.x + y * other.y + z * other.z; + } + + /** + * Calculates the cross product of this vector with another. The cross + * product is defined as: + * + * x = y1 * z2 - y2 * z1
+ * y = z1 * x2 - z2 * x1
+ * z = x1 * y2 - x2 * y1 + * + * @param o + * @return the same vector + */ + public Vector crossProduct(Vector o) { + double newX = y * o.z - o.y * z; + double newY = z * o.x - o.z * x; + double newZ = x * o.y - o.x * y; + + x = newX; + y = newY; + z = newZ; + return this; + } + + /** + * Converts this vector to a unit vector (a vector with length of 1). + * + * @return the same vector + */ + public Vector normalize() { + double length = length(); + + x /= length; + y /= length; + z /= length; + + return this; + } + + /** + * Zero this vector's components. + * + * @return the same vector + */ + public Vector zero() { + x = 0; + y = 0; + z = 0; + return this; + } + + /** + * Returns whether this vector is in an axis-aligned bounding box. + * The minimum and maximum vectors given must be truly the minimum and + * maximum X, Y and Z components. + * + * @param min + * @param max + * @return whether this vector is in the AABB + */ + public boolean isInAABB(Vector min, Vector max) { + return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; + } + + /** + * Returns whether this vector is within a sphere. + * + * @param origin + * @param radius + * @return whether this vector is in the sphere + */ + public boolean isInSphere(Vector origin, double radius) { + return (Math.pow(origin.x - x, 2) + Math.pow(origin.y - y, 2) + Math.pow(origin.z - z, 2)) <= Math.pow(radius, 2); + } + + /** + * Gets the X component. + * + * @return + */ + public double getX() { + return x; + } + + /** + * Gets the floored value of the X component, indicating the block that + * this vector is contained with. + * + * @return block X + */ + public int getBlockX() { + return (int) Math.floor(x); + } + + /** + * Gets the Y component. + * + * @return + */ + public double getY() { + return y; + } + + /** + * Gets the floored value of the Y component, indicating the block that + * this vector is contained with. + * + * @return block y + */ + public int getBlockY() { + return (int) Math.floor(y); + } + + /** + * Gets the Z component. + * + * @return + */ + public double getZ() { + return z; + } + + /** + * Gets the floored value of the Z component, indicating the block that + * this vector is contained with. + * + * @return block z + */ + public int getBlockZ() { + return (int) Math.floor(z); + } + + /** + * Set the X component. + * + * @param x + * @return x + */ + public Vector setX(int x) { + this.x = x; + return this; + } + + /** + * Set the X component. + * + * @param x + * @return x + */ + public Vector setX(double x) { + this.x = x; + return this; + } + + /** + * Set the X component. + * + * @param x + * @return x + */ + public Vector setX(float x) { + this.x = x; + return this; + } + + /** + * Set the Y component. + * + * @param y + * @return y + */ + public Vector setY(int y) { + this.y = y; + return this; + } + + /** + * Set the Y component. + * + * @param y + * @return y + */ + public Vector setY(double y) { + this.y = y; + return this; + } + + /** + * Set the Y component. + * + * @param y + * @return y + */ + public Vector setY(float y) { + this.y = y; + return this; + } + + /** + * Set the Z component. + * + * @param z + * @return z + */ + public Vector setZ(int z) { + this.z = z; + return this; + } + + /** + * Set the Z component. + * + * @param z + * @return z + */ + public Vector setZ(double z) { + this.z = z; + return this; + } + + /** + * Set the Z component. + * + * @param z + * @return z + */ + public Vector setZ(float z) { + this.z = z; + return this; + } + + /** + * Checks to see if two objects are equal. + * + * Only two Vectors can ever return true. This method uses a fuzzy match + * to account for floating point errors. The epsilon can be retrieved + * with epsilon. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Vector)) { + return false; + } + + Vector other = (Vector) obj; + + return Math.abs(x - other.x) < epsilon && Math.abs(y - other.y) < epsilon && Math.abs(z - other.z) < epsilon && (this.getClass().equals(obj.getClass())); + } + + /** + * Returns a hash code for this vector + * + * @return hash code + */ + @Override + public int hashCode() { + int hash = 7; + + hash = 79 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); + hash = 79 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); + hash = 79 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32)); + return hash; + } + + /** + * Get a new vector. + * + * @return vector + */ + @Override + public Vector clone() { + try { + Vector v = (Vector) super.clone(); + + v.x = x; + v.y = y; + v.z = z; + return v; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Returns this vector's components as x,y,z. + * + */ + @Override + public String toString() { + return x + "," + y + "," + z; + } + + /** + * Gets a Location version of this vector with yaw and pitch being 0. + * + * @param world + * @return the location + */ + public Location toLocation(World world) { + return new Location(world, x, y, z); + } + + /** + * Gets a Location version of this vector. + * + * @param world + * @return the location + */ + public Location toLocation(World world, float yaw, float pitch) { + return new Location(world, x, y, z, yaw, pitch); + } + + /** + * Get the block vector of this vector. + * + * @return + */ + public BlockVector toBlockVector() { + return new BlockVector(x, y, z); + } + + /** + * Get the threshold used for equals(). + * + * @return + */ + public static double getEpsilon() { + return epsilon; + } + + /** + * Gets the minimum components of two vectors. + * + * @param v1 + * @param v2 + * @return minimum + */ + public static Vector getMinimum(Vector v1, Vector v2) { + return new Vector(Math.min(v1.x, v2.x), Math.min(v1.y, v2.y), Math.min(v1.z, v2.z)); + } + + /** + * Gets the maximum components of two vectors. + * + * @param v1 + * @param v2 + * @return maximum + */ + public static Vector getMaximum(Vector v1, Vector v2) { + return new Vector(Math.max(v1.x, v2.x), Math.max(v1.y, v2.y), Math.max(v1.z, v2.z)); + } + + /** + * Gets a random vector with components having a random value between + * 0 and 1. + * + * @return + */ + public static Vector getRandom() { + return new Vector(random.nextDouble(), random.nextDouble(), random.nextDouble()); + } +} diff --git a/src/main/java/org/bukkit/util/config/Configuration.java b/src/main/java/org/bukkit/util/config/Configuration.java new file mode 100644 index 0000000..06a59aa --- /dev/null +++ b/src/main/java/org/bukkit/util/config/Configuration.java @@ -0,0 +1,222 @@ +package org.bukkit.util.config; + +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.introspector.Property; +import org.yaml.snakeyaml.nodes.*; +import org.yaml.snakeyaml.reader.UnicodeReader; +import org.yaml.snakeyaml.representer.Represent; +import org.yaml.snakeyaml.representer.Representer; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +/** + * YAML configuration loader. To use this class, construct it with path to + * a file and call its load() method. For specifying node paths in the + * various get*() methods, they support SK's path notation, allowing you to + * select child nodes by delimiting node names with periods. + * + *

+ * For example, given the following configuration file:

+ * + *
members:
+ *     - Hollie
+ *     - Jason
+ *     - Bobo
+ *     - Aya
+ *     - Tetsu
+ * worldguard:
+ *     fire:
+ *         spread: false
+ *         blocks: [cloth, rock, glass]
+ * sturmeh:
+ *     cool: false
+ *     eats:
+ *         babies: true
+ * + *

Calling code could access sturmeh's baby eating state by using + * getBoolean("sturmeh.eats.babies", false). For lists, there are + * methods such as getStringList that will return a type safe list. + * + *

This class is currently incomplete. It is not yet possible to get a node. + *

+ * + */ +public class Configuration extends ConfigurationNode { + private Yaml yaml; + private File file; + private String header = null; + + public Configuration(File file) { + super(new HashMap()); + + DumperOptions options = new DumperOptions(); + + options.setIndent(4); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + yaml = new Yaml(new SafeConstructor(), new EmptyNullRepresenter(), options); + + this.file = file; + } + + /** + * Loads the configuration file. All errors are thrown away. + */ + public void load() { + FileInputStream stream = null; + + try { + stream = new FileInputStream(file); + read(yaml.load(new UnicodeReader(stream))); + } catch (IOException e) { + root = new HashMap(); + } catch (ConfigurationException e) { + root = new HashMap(); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) {} + } + } + + /** + * Set the header for the file as a series of lines that are terminated + * by a new line sequence. + * + * @param headerLines header lines to prepend + */ + public void setHeader(String... headerLines) { + StringBuilder header = new StringBuilder(); + + for (String line : headerLines) { + if (header.length() > 0) { + header.append("\r\n"); + } + header.append(line); + } + + setHeader(header.toString()); + } + + /** + * Set the header for the file. A header can be provided to prepend the + * YAML data output on configuration save. The header is + * printed raw and so must be manually commented if used. A new line will + * be appended after the header, however, if a header is provided. + * + * @param header header to prepend + */ + public void setHeader(String header) { + this.header = header; + } + + /** + * Return the set header. + * + * @return + */ + public String getHeader() { + return header; + } + + /** + * Saves the configuration to disk. All errors are clobbered. + * + * @param header header to prepend + * @return true if it was successful + */ + public boolean save() { + FileOutputStream stream = null; + + File parent = file.getParentFile(); + + if (parent != null) { + parent.mkdirs(); + } + + try { + stream = new FileOutputStream(file); + OutputStreamWriter writer = new OutputStreamWriter(stream, "UTF-8"); + if (header != null) { + writer.append(header); + writer.append("\r\n"); + } + yaml.dump(root, writer); + return true; + } catch (IOException e) {} finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) {} + } + + return false; + } + + @SuppressWarnings("unchecked") + private void read(Object input) throws ConfigurationException { + try { + if (null == input) { + root = new HashMap(); + } else { + root = (Map) input; + } + } catch (ClassCastException e) { + throw new ConfigurationException("Root document must be an key-value structure"); + } + } + + /** + * This method returns an empty ConfigurationNode for using as a + * default in methods that select a node from a node list. + * @return + */ + public static ConfigurationNode getEmptyNode() { + return new ConfigurationNode(new HashMap()); + } +} + +class EmptyNullRepresenter extends Representer { + + public EmptyNullRepresenter() { + super(); + this.nullRepresenter = new EmptyRepresentNull(); + } + + protected class EmptyRepresentNull implements Represent { + public Node representData(Object data) { + return representScalar(Tag.NULL, ""); // Changed "null" to "" so as to avoid writing nulls + } + } + + // Code borrowed from snakeyaml (http://code.google.com/p/snakeyaml/source/browse/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBeanTest.java) + @Override + protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) { + NodeTuple tuple = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); + Node valueNode = tuple.getValueNode(); + if (valueNode instanceof CollectionNode) { + // Removed null check + if (Tag.SEQ.equals(valueNode.getTag())) { + SequenceNode seq = (SequenceNode) valueNode; + if (seq.getValue().isEmpty()) { + return null; // skip empty lists + } + } + if (Tag.MAP.equals(valueNode.getTag())) { + MappingNode seq = (MappingNode) valueNode; + if (seq.getValue().isEmpty()) { + return null; // skip empty maps + } + } + } + return tuple; + } + // End of borrowed code +} diff --git a/src/main/java/org/bukkit/util/config/ConfigurationException.java b/src/main/java/org/bukkit/util/config/ConfigurationException.java new file mode 100644 index 0000000..bad67ab --- /dev/null +++ b/src/main/java/org/bukkit/util/config/ConfigurationException.java @@ -0,0 +1,18 @@ +package org.bukkit.util.config; + +/** + * Configuration exception. + * + * @author sk89q + */ +public class ConfigurationException extends Exception { + private static final long serialVersionUID = -2442886939908724203L; + + public ConfigurationException() { + super(); + } + + public ConfigurationException(String msg) { + super(msg); + } +} diff --git a/src/main/java/org/bukkit/util/config/ConfigurationNode.java b/src/main/java/org/bukkit/util/config/ConfigurationNode.java new file mode 100644 index 0000000..a7a007f --- /dev/null +++ b/src/main/java/org/bukkit/util/config/ConfigurationNode.java @@ -0,0 +1,582 @@ +package org.bukkit.util.config; + +import java.util.*; + +/** + * Represents a configuration node. + */ +public class ConfigurationNode { + protected Map root; + + protected ConfigurationNode(Map root) { + this.root = root; + } + + /** + * Gets all of the cofiguration values within the Node as + * a key value pair, with the key being the full path and the + * value being the Object that is at the path. + * + * @return A map of key value pairs with the path as the key and the object as the value + */ + public Map getAll() { + return recursiveBuilder(root); + } + + /** + * A helper method for the getAll method that deals with the recursion + * involved in traversing the tree + * + * @param node The map for that node of the tree + * @return The fully pathed map for that point in the tree, with the path as the key + */ + @SuppressWarnings("unchecked") + protected Map recursiveBuilder(Map node) { + Map map = new TreeMap(); + + Set keys = node.keySet(); + for( String k : keys ) { + Object tmp = node.get(k); + if( tmp instanceof Map ) { + Map rec = recursiveBuilder((Map ) tmp); + + Set subkeys = rec.keySet(); + for( String sk : subkeys ) { + map.put(k + "." + sk, rec.get(sk)); + } + } + else { + map.put(k, tmp); + } + } + + return map; + } + + /** + * Gets a property at a location. This will either return an Object + * or null, with null meaning that no configuration value exists at + * that location. This could potentially return a default value (not yet + * implemented) as defined by a plugin, if this is a plugin-tied + * configuration. + * + * @param path path to node (dot notation) + * @return object or null + */ + @SuppressWarnings("unchecked") + public Object getProperty(String path) { + if (!path.contains(".")) { + Object val = root.get(path); + + if (val == null) { + return null; + } + return val; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + if (o == null) { + return null; + } + + if (i == parts.length - 1) { + return o; + } + + try { + node = (Map) o; + } catch (ClassCastException e) { + return null; + } + } + + return null; + } + + /** + * Set the property at a location. This will override existing + * configuration data to have it conform to key/value mappings. + * + * @param path + * @param value + */ + @SuppressWarnings("unchecked") + public void setProperty(String path, Object value) { + if (!path.contains(".")) { + root.put(path, value); + return; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + // Found our target! + if (i == parts.length - 1) { + node.put(parts[i], value); + return; + } + + if (o == null || !(o instanceof Map)) { + // This will override existing configuration data! + o = new HashMap(); + node.put(parts[i], o); + } + + node = (Map) o; + } + } + + /** + * Gets a string at a location. This will either return an String + * or null, with null meaning that no configuration value exists at + * that location. If the object at the particular location is not actually + * a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @return string or null + */ + public String getString(String path) { + Object o = getProperty(path); + + if (o == null) { + return null; + } + return o.toString(); + } + + /** + * Gets a string at a location. This will either return an String + * or the default value. If the object at the particular location is not + * actually a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @param def default value + * @return string or default + */ + public String getString(String path, String def) { + String o = getString(path); + + if (o == null) { + setProperty(path, def); + return def; + } + return o; + } + + /** + * Gets an integer at a location. This will either return an integer + * or the default value. If the object at the particular location is not + * actually a integer, the default value will be returned. However, other + * number types will be casted to an integer. + * + * @param path path to node (dot notation) + * @param def default value + * @return int or default + */ + public int getInt(String path, int def) { + Integer o = castInt(getProperty(path)); + + if (o == null) { + setProperty(path, def); + return def; + } else { + return o; + } + } + + /** + * Gets a double at a location. This will either return an double + * or the default value. If the object at the particular location is not + * actually a double, the default value will be returned. However, other + * number types will be casted to an double. + * + * @param path path to node (dot notation) + * @param def default value + * @return double or default + */ + public double getDouble(String path, double def) { + Double o = castDouble(getProperty(path)); + + if (o == null) { + setProperty(path, def); + return def; + } else { + return o; + } + } + + /** + * Gets a boolean at a location. This will either return an boolean + * or the default value. If the object at the particular location is not + * actually a boolean, the default value will be returned. + * + * @param path path to node (dot notation) + * @param def default value + * @return boolean or default + */ + public boolean getBoolean(String path, boolean def) { + Boolean o = castBoolean(getProperty(path)); + + if (o == null) { + setProperty(path, def); + return def; + } else { + return o; + } + } + + /** + * Get a list of keys at a location. If the map at the particular location + * does not exist or it is not a map, null will be returned. + * + * @param path path to node (dot notation) + * @return list of keys + */ + @SuppressWarnings("unchecked") + public List getKeys(String path) { + if (path == null) { + return new ArrayList(root.keySet()); + } + Object o = getProperty(path); + + if (o == null) { + return null; + } else if (o instanceof Map) { + return new ArrayList(((Map) o).keySet()); + } else { + return null; + } + } + + /** + * Returns a list of all keys at the root path + * + * @return List of keys + */ + public List getKeys() { + return new ArrayList(root.keySet()); + } + + /** + * Gets a list of objects at a location. If the list is not defined, + * null will be returned. The node must be an actual list. + * + * @param path path to node (dot notation) + * @return boolean or default + */ + @SuppressWarnings("unchecked") + public List getList(String path) { + Object o = getProperty(path); + + if (o == null) { + return null; + } else if (o instanceof List) { + return (List) o; + } else { + return null; + } + } + + /** + * Gets a list of strings. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. If an item in the list + * is not a string, it will be converted to a string. The node must be + * an actual list and not just a string. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of strings + */ + public List getStringList(String path, List def) { + List raw = getList(path); + + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + + for (Object o : raw) { + if (o == null) { + continue; + } + + list.add(o.toString()); + } + + return list; + } + + /** + * Gets a list of integers. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and not just an integer. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getIntList(String path, List def) { + List raw = getList(path); + + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + + for (Object o : raw) { + Integer i = castInt(o); + + if (i != null) { + list.add(i); + } + } + + return list; + } + + /** + * Gets a list of doubles. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and cannot be just a double. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getDoubleList(String path, List def) { + List raw = getList(path); + + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + + for (Object o : raw) { + Double i = castDouble(o); + + if (i != null) { + list.add(i); + } + } + + return list; + } + + /** + * Gets a list of booleans. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and cannot be just a boolean, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getBooleanList(String path, List def) { + List raw = getList(path); + + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + + for (Object o : raw) { + Boolean tetsu = castBoolean(o); + + if (tetsu != null) { + list.add(tetsu); + } + } + + return list; + } + + /** + * Gets a list of nodes. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual node and cannot be just a boolean, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + @SuppressWarnings("unchecked") + public List getNodeList(String path, List def) { + List raw = getList(path); + + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + + for (Object o : raw) { + if (o instanceof Map) { + list.add(new ConfigurationNode((Map) o)); + } + } + + return list; + } + + /** + * Get a configuration node at a path. If the node doesn't exist or the + * path does not lead to a node, null will be returned. A node has + * key/value mappings. + * + * @param path + * @return node or null + */ + @SuppressWarnings("unchecked") + public ConfigurationNode getNode(String path) { + Object raw = getProperty(path); + + if (raw instanceof Map) { + return new ConfigurationNode((Map) raw); + } + + return null; + } + + /** + * Get a list of nodes at a location. If the map at the particular location + * does not exist or it is not a map, null will be returned. + * + * @param path path to node (dot notation) + * @return map of nodes + */ + @SuppressWarnings("unchecked") + public Map getNodes(String path) { + Object o = getProperty(path); + + if (o == null) { + return null; + } else if (o instanceof Map) { + Map nodes = new HashMap(); + + for (Map.Entry entry : ((Map) o).entrySet()) { + if (entry.getValue() instanceof Map) { + nodes.put(entry.getKey(), new ConfigurationNode((Map) entry.getValue())); + } + } + + return nodes; + } else { + return null; + } + } + + /** + * Casts a value to an integer. May return null. + * + * @param o + * @return + */ + private static Integer castInt(Object o) { + if (o == null) { + return null; + } else if (o instanceof Byte) { + return (int) (Byte) o; + } else if (o instanceof Integer) { + return (Integer) o; + } else if (o instanceof Double) { + return (int) (double) (Double) o; + } else if (o instanceof Float) { + return (int) (float) (Float) o; + } else if (o instanceof Long) { + return (int) (long) (Long) o; + } else { + return null; + } + } + + /** + * Casts a value to a double. May return null. + * + * @param o + * @return + */ + private static Double castDouble(Object o) { + if (o == null) { + return null; + } else if (o instanceof Float) { + return (double) (Float) o; + } else if (o instanceof Double) { + return (Double) o; + } else if (o instanceof Byte) { + return (double) (Byte) o; + } else if (o instanceof Integer) { + return (double) (Integer) o; + } else if (o instanceof Long) { + return (double) (Long) o; + } else { + return null; + } + } + + /** + * Casts a value to a boolean. May return null. + * + * @param o + * @return + */ + private static Boolean castBoolean(Object o) { + if (o == null) { + return null; + } else if (o instanceof Boolean) { + return (Boolean) o; + } else { + return null; + } + } + + /** + * Remove the property at a location. This will override existing + * configuration data to have it conform to key/value mappings. + * + * @param path + */ + @SuppressWarnings("unchecked") + public void removeProperty(String path) { + if (!path.contains(".")) { + root.remove(path); + return; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + // Found our target! + if (i == parts.length - 1) { + node.remove(parts[i]); + return; + } + + node = (Map) o; + } + } +} diff --git a/src/main/java/org/bukkit/util/noise/NoiseGenerator.java b/src/main/java/org/bukkit/util/noise/NoiseGenerator.java new file mode 100644 index 0000000..10a46b0 --- /dev/null +++ b/src/main/java/org/bukkit/util/noise/NoiseGenerator.java @@ -0,0 +1,171 @@ + +package org.bukkit.util.noise; + +/** + * Base class for all noise generators + */ +public abstract class NoiseGenerator { + protected final int perm[] = new int[512]; + protected double offsetX; + protected double offsetY; + protected double offsetZ; + + /** + * Speedy floor, faster than (int)Math.floor(x) + * + * @param x Value to floor + * @return Floored value + */ + public static int floor(double x) { + return x >= 0 ? (int) x : (int) x - 1; + } + + protected static double fade(double x) { + return x * x * x * (x * (x * 6 - 15) + 10); + } + + protected static double lerp(double x, double y, double z) { + return y + x * (z - y); + } + + protected static double grad(int hash, double x, double y, double z) { + hash &= 15; + double u = hash < 8 ? x : y; + double v = hash < 4 ? y : hash == 12 || hash == 14 ? x : z; + return ((hash & 1) == 0 ? u : -u) + ((hash & 2) == 0 ? v : -v); + } + + /** + * Computes and returns the 1D noise for the given coordinate in 1D space + * + * @param x X coordinate + * @return Noise at given location, from range -1 to 1 + */ + public double noise(double x) { + return noise(x, 0, 0); + } + + /** + * Computes and returns the 2D noise for the given coordinates in 2D space + * + * @param x X coordinate + * @param y Y coordinate + * @return Noise at given location, from range -1 to 1 + */ + public double noise(double x, double y) { + return noise(x, y, 0); + } + + /** + * Computes and returns the 3D noise for the given coordinates in 3D space + * + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + * @return Noise at given location, from range -1 to 1 + */ + public abstract double noise(double x, double y, double z); + + /** + * Generates noise for the 1D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public double noise(double x, int octaves, double frequency, double amplitude) { + return noise(x, 0, 0, octaves, frequency, amplitude); + } + + /** + * Generates noise for the 1D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @param normalized If true, normalize the value to [-1, 1] + * @return Resulting noise + */ + public double noise(double x, int octaves, double frequency, double amplitude, boolean normalized) { + return noise(x, 0, 0, octaves, frequency, amplitude, normalized); + } + + /** + * Generates noise for the 2D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public double noise(double x, double y, int octaves, double frequency, double amplitude) { + return noise(x, y, 0, octaves, frequency, amplitude); + } + + /** + * Generates noise for the 2D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @param normalized If true, normalize the value to [-1, 1] + * @return Resulting noise + */ + public double noise(double x, double y, int octaves, double frequency, double amplitude, boolean normalized) { + return noise(x, y, 0, octaves, frequency, amplitude, normalized); + } + + /** + * Generates noise for the 3D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param z Z-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public double noise(double x, double y, double z, int octaves, double frequency, double amplitude) { + return noise(x, y, z, octaves, frequency, amplitude, false); + } + + /** + * Generates noise for the 3D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param z Z-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @param normalized If true, normalize the value to [-1, 1] + * @return Resulting noise + */ + public double noise(double x, double y, double z, int octaves, double frequency, double amplitude, boolean normalized) { + double result = 0; + double amp = 1; + double freq = 1; + double max = 0; + + for (int i = 0; i < octaves; i++) { + result += noise(x * freq, y * freq, z * freq) * amp; + max += amp; + freq *= frequency; + amp *= amplitude; + } + + if (normalized) { + result /= max; + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/util/noise/OctaveGenerator.java b/src/main/java/org/bukkit/util/noise/OctaveGenerator.java new file mode 100644 index 0000000..b058837 --- /dev/null +++ b/src/main/java/org/bukkit/util/noise/OctaveGenerator.java @@ -0,0 +1,193 @@ + +package org.bukkit.util.noise; + +/** + * Creates noise using unbiased octaves + */ +public abstract class OctaveGenerator { + protected final NoiseGenerator[] octaves; + protected double xScale = 1; + protected double yScale = 1; + protected double zScale = 1; + + protected OctaveGenerator(NoiseGenerator[] octaves) { + this.octaves = octaves; + } + + /** + * Sets the scale used for all coordinates passed to this generator. + * + * This is the equivalent to setting each coordinate to the specified value. + * + * @param scale New value to scale each coordinate by + */ + public void setScale(double scale) { + setXScale(scale); + setYScale(scale); + setZScale(scale); + } + + /** + * Gets the scale used for each X-coordinates passed + * + * @return X scale + */ + public double getXScale() { + return xScale; + } + + /** + * Sets the scale used for each X-coordinates passed + * + * @param scale New X scale + */ + public void setXScale(double scale) { + xScale = scale; + } + + /** + * Gets the scale used for each Y-coordinates passed + * + * @return Y scale + */ + public double getYScale() { + return yScale; + } + + /** + * Sets the scale used for each Y-coordinates passed + * + * @param scale New Y scale + */ + public void setYScale(double scale) { + yScale = scale; + } + + /** + * Gets the scale used for each Z-coordinates passed + * + * @return Z scale + */ + public double getZScale() { + return zScale; + } + + /** + * Sets the scale used for each Z-coordinates passed + * + * @param scale New Z scale + */ + public void setZScale(double scale) { + zScale = scale; + } + + /** + * Gets a clone of the individual octaves used within this generator + * + * @return Clone of the individual octaves + */ + public NoiseGenerator[] getOctaves() { + return octaves.clone(); + } + + /** + * Generates noise for the 1D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public double noise(double x, double frequency, double amplitude) { + return noise(x, 0, 0, frequency, amplitude); + } + + /** + * Generates noise for the 1D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @param normalized If true, normalize the value to [-1, 1] + * @return Resulting noise + */ + public double noise(double x, double frequency, double amplitude, boolean normalized) { + return noise(x, 0, 0, frequency, amplitude, normalized); + } + + /** + * Generates noise for the 2D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public double noise(double x, double y, double frequency, double amplitude) { + return noise(x, y, 0, frequency, amplitude); + } + + /** + * Generates noise for the 2D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @param normalized If true, normalize the value to [-1, 1] + * @return Resulting noise + */ + public double noise(double x, double y, double frequency, double amplitude, boolean normalized) { + return noise(x, y, 0, frequency, amplitude, normalized); + } + + /** + * Generates noise for the 3D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param z Z-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public double noise(double x, double y, double z, double frequency, double amplitude) { + return noise(x, y, z, frequency, amplitude, false); + } + + /** + * Generates noise for the 3D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param z Z-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @param normalized If true, normalize the value to [-1, 1] + * @return Resulting noise + */ + public double noise(double x, double y, double z, double frequency, double amplitude, boolean normalized) { + double result = 0; + double amp = 1; + double freq = 1; + double max = 0; + + x *= xScale; + y *= yScale; + z *= zScale; + + for (int i = 0; i < octaves.length; i++) { + result += octaves[i].noise(x * freq, y * freq, z * freq) * amp; + max += amp; + freq *= frequency; + amp *= amplitude; + } + + if (normalized) { + result /= max; + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/util/noise/PerlinNoiseGenerator.java b/src/main/java/org/bukkit/util/noise/PerlinNoiseGenerator.java new file mode 100644 index 0000000..9fd1711 --- /dev/null +++ b/src/main/java/org/bukkit/util/noise/PerlinNoiseGenerator.java @@ -0,0 +1,211 @@ +package org.bukkit.util.noise; + +import org.bukkit.World; + +import java.util.Random; + +/** + * Generates noise using the "classic" perlin generator + * + * @see SimplexNoiseGenerator "Improved" and faster version with slighly different results + */ +public class PerlinNoiseGenerator extends NoiseGenerator { + protected static final int grad3[][] = {{1, 1, 0}, {-1, 1, 0}, {1, -1, 0}, {-1, -1, 0}, + {1, 0, 1}, {-1, 0, 1}, {1, 0, -1}, {-1, 0, -1}, + {0, 1, 1}, {0, -1, 1}, {0, 1, -1}, {0, -1, -1}}; + private static final PerlinNoiseGenerator instance = new PerlinNoiseGenerator(); + + protected PerlinNoiseGenerator() { + int p[] = {151, 160, 137, 91, 90, 15, 131, 13, 201, + 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, + 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, + 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, + 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, + 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, + 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, + 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, + 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, + 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, + 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, + 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, + 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, + 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, + 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, + 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, + 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180}; + + for (int i = 0; i < 512; i++) { + perm[i] = p[i & 255]; + } + } + + /** + * Creates a seeded perlin noise generator for the given world + * + * @param world World to construct this generator for + */ + public PerlinNoiseGenerator(World world) { + this(new Random(world.getSeed())); + } + + /** + * Creates a seeded perlin noise generator for the given seed + * + * @param seed Seed to construct this generator for + */ + public PerlinNoiseGenerator(long seed) { + this(new Random(seed)); + } + + /** + * Creates a seeded perlin noise generator with the given Random + * + * @param rand Random to construct with + */ + public PerlinNoiseGenerator(Random rand) { + offsetX = rand.nextDouble() * 256; + offsetY = rand.nextDouble() * 256; + offsetZ = rand.nextDouble() * 256; + + for (int i = 0; i < 256; i++) { + perm[i] = rand.nextInt(256); + } + + for (int i = 0; i < 256; i++) { + int pos = rand.nextInt(256 - i) + i; + int old = perm[i]; + + perm[i] = perm[pos]; + perm[pos] = old; + perm[i + 256] = perm[i]; + } + } + + /** + * Computes and returns the 1D unseeded perlin noise for the given coordinates in 1D space + * + * @param x X coordinate + * @return Noise at given location, from range -1 to 1 + */ + public static double getNoise(double x) { + return instance.noise(x); + } + + /** + * Computes and returns the 2D unseeded perlin noise for the given coordinates in 2D space + * + * @param x X coordinate + * @param y Y coordinate + * @return Noise at given location, from range -1 to 1 + */ + public static double getNoise(double x, double y) { + return instance.noise(x, y); + } + + /** + * Computes and returns the 3D unseeded perlin noise for the given coordinates in 3D space + * + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + * @return Noise at given location, from range -1 to 1 + */ + public static double getNoise(double x, double y, double z) { + return instance.noise(x, y, z); + } + + /** + * Gets the singleton unseeded instance of this generator + * + * @return Singleton + */ + public static PerlinNoiseGenerator getInstance() { + return instance; + } + + @Override + public double noise(double x, double y, double z) { + x += offsetX; + y += offsetY; + z += offsetZ; + + int floorX = floor(x); + int floorY = floor(y); + int floorZ = floor(z); + + // Find unit cube containing the point + int X = floorX & 255; + int Y = floorY & 255; + int Z = floorZ & 255; + + // Get relative xyz coordinates of the point within the cube + x -= floorX; + y -= floorY; + z -= floorZ; + + // Compute fade curves for xyz + double fX = fade(x); + double fY = fade(y); + double fZ = fade(z); + + // Hash coordinates of the cube corners + int A = perm[X] + Y; + int AA = perm[A] + Z; + int AB = perm[A + 1] + Z; + int B = perm[X + 1] + Y; + int BA = perm[B] + Z; + int BB = perm[B + 1] + Z; + + return lerp(fZ, lerp(fY, lerp(fX, grad(perm[AA], x, y, z), + grad(perm[BA], x - 1, y, z)), + lerp(fX, grad(perm[AB], x, y - 1, z), + grad(perm[BB], x - 1, y - 1, z))), + lerp(fY, lerp(fX, grad(perm[AA + 1], x, y, z - 1), + grad(perm[BA + 1], x - 1, y, z - 1)), + lerp(fX, grad(perm[AB + 1], x, y - 1, z - 1), + grad(perm[BB + 1], x - 1, y - 1, z - 1)))); + } + + /** + * Generates noise for the 1D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public static double getNoise(double x, int octaves, double frequency, double amplitude) { + return instance.noise(x, octaves, frequency, amplitude); + } + + /** + * Generates noise for the 2D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public static double getNoise(double x, double y, int octaves, double frequency, double amplitude) { + return instance.noise(x, y, octaves, frequency, amplitude); + } + + /** + * Generates noise for the 3D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param z Z-coordinate + * @param octaves Number of octaves to use + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public static double getNoise(double x, double y, double z, int octaves, double frequency, double amplitude) { + return instance.noise(x, y, z, octaves, frequency, amplitude); + } +} diff --git a/src/main/java/org/bukkit/util/noise/PerlinOctaveGenerator.java b/src/main/java/org/bukkit/util/noise/PerlinOctaveGenerator.java new file mode 100644 index 0000000..010f2e9 --- /dev/null +++ b/src/main/java/org/bukkit/util/noise/PerlinOctaveGenerator.java @@ -0,0 +1,51 @@ + +package org.bukkit.util.noise; + +import org.bukkit.World; + +import java.util.Random; + +/** + * Creates perlin noise through unbiased octaves + */ +public class PerlinOctaveGenerator extends OctaveGenerator { + /** + * Creates a perlin octave generator for the given world + * + * @param world World to construct this generator for + * @param octaves Amount of octaves to create + */ + public PerlinOctaveGenerator(World world, int octaves) { + this(new Random(world.getSeed()), octaves); + } + + /** + * Creates a perlin octave generator for the given world + * + * @param seed Seed to construct this generator for + * @param octaves Amount of octaves to create + */ + public PerlinOctaveGenerator(long seed, int octaves) { + this(new Random(seed), octaves); + } + + /** + * Creates a perlin octave generator for the given {@link Random} + * + * @param rand Random object to construct this generator for + * @param octaves Amount of octaves to create + */ + public PerlinOctaveGenerator(Random rand, int octaves) { + super(createOctaves(rand, octaves)); + } + + private static NoiseGenerator[] createOctaves(Random rand, int octaves) { + NoiseGenerator[] result = new NoiseGenerator[octaves]; + + for (int i = 0; i < octaves; i++) { + result[i] = new PerlinNoiseGenerator(rand); + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/util/noise/SimplexNoiseGenerator.java b/src/main/java/org/bukkit/util/noise/SimplexNoiseGenerator.java new file mode 100644 index 0000000..bec419c --- /dev/null +++ b/src/main/java/org/bukkit/util/noise/SimplexNoiseGenerator.java @@ -0,0 +1,514 @@ +package org.bukkit.util.noise; + +import org.bukkit.World; + +import java.util.Random; + +/** + * Generates simplex-based noise. + * + * This is a modified version of the freely published version in the paper by + * Stefan Gustavson at http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + */ +public class SimplexNoiseGenerator extends PerlinNoiseGenerator { + protected static final double SQRT_3 = Math.sqrt(3); + protected static final double SQRT_5 = Math.sqrt(5); + protected static final double F2 = 0.5 * (SQRT_3 - 1); + protected static final double G2 = (3 - SQRT_3) / 6; + protected static final double G22 = G2 * 2.0 - 1; + protected static final double F3 = 1.0 / 3.0; + protected static final double G3 = 1.0 / 6.0; + protected static final double F4 = (SQRT_5 - 1.0) / 4.0; + protected static final double G4 = (5.0 - SQRT_5) / 20.0; + protected static final double G42 = G4 * 2.0; + protected static final double G43 = G4 * 3.0; + protected static final double G44 = G4 * 4.0 - 1.0; + protected static final int grad4[][] = {{0, 1, 1, 1}, {0, 1, 1, -1}, {0, 1, -1, 1}, {0, 1, -1, -1}, + {0, -1, 1, 1}, {0, -1, 1, -1}, {0, -1, -1, 1}, {0, -1, -1, -1}, + {1, 0, 1, 1}, {1, 0, 1, -1}, {1, 0, -1, 1}, {1, 0, -1, -1}, + {-1, 0, 1, 1}, {-1, 0, 1, -1}, {-1, 0, -1, 1}, {-1, 0, -1, -1}, + {1, 1, 0, 1}, {1, 1, 0, -1}, {1, -1, 0, 1}, {1, -1, 0, -1}, + {-1, 1, 0, 1}, {-1, 1, 0, -1}, {-1, -1, 0, 1}, {-1, -1, 0, -1}, + {1, 1, 1, 0}, {1, 1, -1, 0}, {1, -1, 1, 0}, {1, -1, -1, 0}, + {-1, 1, 1, 0}, {-1, 1, -1, 0}, {-1, -1, 1, 0}, {-1, -1, -1, 0}}; + protected static final int simplex[][] = { + {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 0, 0, 0}, {0, 2, 3, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 2, 3, 0}, + {0, 2, 1, 3}, {0, 0, 0, 0}, {0, 3, 1, 2}, {0, 3, 2, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 3, 2, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {1, 2, 0, 3}, {0, 0, 0, 0}, {1, 3, 0, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, + {1, 0, 2, 3}, {1, 0, 3, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 0, 3, 1}, {0, 0, 0, 0}, {2, 1, 3, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {2, 0, 1, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {3, 0, 1, 2}, {3, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 2, 0}, + {2, 1, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {3, 1, 0, 2}, {0, 0, 0, 0}, {3, 2, 0, 1}, {3, 2, 1, 0}}; + protected static double offsetW; + private static final SimplexNoiseGenerator instance = new SimplexNoiseGenerator(); + + protected SimplexNoiseGenerator() { + super(); + } + + /** + * Creates a seeded simplex noise generator for the given world + * + * @param world World to construct this generator for + */ + public SimplexNoiseGenerator(World world) { + this(new Random(world.getSeed())); + } + + /** + * Creates a seeded simplex noise generator for the given seed + * + * @param seed Seed to construct this generator for + */ + public SimplexNoiseGenerator(long seed) { + this(new Random(seed)); + } + + /** + * Creates a seeded simplex noise generator with the given Random + * + * @param rand Random to construct with + */ + public SimplexNoiseGenerator(Random rand) { + super(rand); + offsetW = rand.nextDouble() * 256; + } + + protected static double dot(int g[], double x, double y) { + return g[0] * x + g[1] * y; + } + + protected static double dot(int g[], double x, double y, double z) { + return g[0] * x + g[1] * y + g[2] * z; + } + + protected static double dot(int g[], double x, double y, double z, double w) { + return g[0] * x + g[1] * y + g[2] * z + g[3] * w; + } + + /** + * Computes and returns the 1D unseeded simplex noise for the given coordinates in 1D space + * + * @param xin X coordinate + * @return Noise at given location, from range -1 to 1 + */ + public static double getNoise(double xin) { + return instance.noise(xin); + } + + /** + * Computes and returns the 2D unseeded simplex noise for the given coordinates in 2D space + * + * @param xin X coordinate + * @param yin Y coordinate + * @return Noise at given location, from range -1 to 1 + */ + public static double getNoise(double xin, double yin) { + return instance.noise(xin, yin); + } + + /** + * Computes and returns the 3D unseeded simplex noise for the given coordinates in 3D space + * + * @param xin X coordinate + * @param yin Y coordinate + * @param zin Z coordinate + * @return Noise at given location, from range -1 to 1 + */ + public static double getNoise(double xin, double yin, double zin) { + return instance.noise(xin, yin, zin); + } + + /** + * Computes and returns the 4D simplex noise for the given coordinates in 4D space + * + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + * @param w W coordinate + * @return Noise at given location, from range -1 to 1 + */ + public static double getNoise(double x, double y, double z, double w) { + return instance.noise(x, y, z, w); + } + + @Override + public double noise(double xin, double yin, double zin) { + xin += offsetX; + yin += offsetY; + zin += offsetZ; + + double n0, n1, n2, n3; // Noise contributions from the four corners + + // Skew the input space to determine which simplex cell we're in + double s = (xin + yin + zin) * F3; // Very nice and simple skew factor for 3D + int i = floor(xin + s); + int j = floor(yin + s); + int k = floor(zin + s); + double t = (i + j + k) * G3; + double X0 = i - t; // Unskew the cell origin back to (x,y,z) space + double Y0 = j - t; + double Z0 = k - t; + double x0 = xin - X0; // The x,y,z distances from the cell origin + double y0 = yin - Y0; + double z0 = zin - Z0; + + // For the 3D case, the simplex shape is a slightly irregular tetrahedron. + + // Determine which simplex we are in. + int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords + int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords + if (x0 >= y0) { + if (y0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 1; + k2 = 0; + } // X Y Z order + else if (x0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 0; + k2 = 1; + } // X Z Y order + else { + i1 = 0; + j1 = 0; + k1 = 1; + i2 = 1; + j2 = 0; + k2 = 1; + } // Z X Y order + } else { // x0 y0) { + i1 = 1; + j1 = 0; + } // lower triangle, XY order: (0,0)->(1,0)->(1,1) + else { + i1 = 0; + j1 = 1; + } // upper triangle, YX order: (0,0)->(0,1)->(1,1) + + // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + // c = (3-sqrt(3))/6 + + double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + double y1 = y0 - j1 + G2; + double x2 = x0 + G22; // Offsets for last corner in (x,y) unskewed coords + double y2 = y0 + G22; + + // Work out the hashed gradient indices of the three simplex corners + int ii = i & 255; + int jj = j & 255; + int gi0 = perm[ii + perm[jj]] % 12; + int gi1 = perm[ii + i1 + perm[jj + j1]] % 12; + int gi2 = perm[ii + 1 + perm[jj + 1]] % 12; + + // Calculate the contribution from the three corners + double t0 = 0.5 - x0 * x0 - y0 * y0; + if (t0 < 0) { + n0 = 0.0; + } else { + t0 *= t0; + n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient + } + + double t1 = 0.5 - x1 * x1 - y1 * y1; + if (t1 < 0) { + n1 = 0.0; + } else { + t1 *= t1; + n1 = t1 * t1 * dot(grad3[gi1], x1, y1); + } + + double t2 = 0.5 - x2 * x2 - y2 * y2; + if (t2 < 0) { + n2 = 0.0; + } else { + t2 *= t2; + n2 = t2 * t2 * dot(grad3[gi2], x2, y2); + } + + // Add contributions from each corner to get the final noise value. + // The result is scaled to return values in the interval [-1,1]. + return 70.0 * (n0 + n1 + n2); + } + + /** + * Computes and returns the 4D simplex noise for the given coordinates in 4D space + * + * @param xin X coordinate + * @param yin Y coordinate + * @param zin Z coordinate + * @param win W coordinate + * @return Noise at given location, from range -1 to 1 + */ + public double noise(double x, double y, double z, double w) { + x += offsetX; + y += offsetY; + z += offsetZ; + w += offsetW; + + double n0, n1, n2, n3, n4; // Noise contributions from the five corners + + // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in + double s = (x + y + z + w) * F4; // Factor for 4D skewing + int i = floor(x + s); + int j = floor(y + s); + int k = floor(z + s); + int l = floor(w + s); + + double t = (i + j + k + l) * G4; // Factor for 4D unskewing + double X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space + double Y0 = j - t; + double Z0 = k - t; + double W0 = l - t; + double x0 = x - X0; // The x,y,z,w distances from the cell origin + double y0 = y - Y0; + double z0 = z - Z0; + double w0 = w - W0; + + // For the 4D case, the simplex is a 4D shape I won't even try to describe. + // To find out which of the 24 possible simplices we're in, we need to + // determine the magnitude ordering of x0, y0, z0 and w0. + // The method below is a good way of finding the ordering of x,y,z,w and + // then find the correct traversal order for the simplex we’re in. + // First, six pair-wise comparisons are performed between each possible pair + // of the four coordinates, and the results are used to add up binary bits + // for an integer index. + int c1 = (x0 > y0) ? 32 : 0; + int c2 = (x0 > z0) ? 16 : 0; + int c3 = (y0 > z0) ? 8 : 0; + int c4 = (x0 > w0) ? 4 : 0; + int c5 = (y0 > w0) ? 2 : 0; + int c6 = (z0 > w0) ? 1 : 0; + int c = c1 + c2 + c3 + c4 + c5 + c6; + int i1, j1, k1, l1; // The integer offsets for the second simplex corner + int i2, j2, k2, l2; // The integer offsets for the third simplex corner + int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner + + // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. + // Many values of c will never occur, since e.g. x>y>z>w makes x= 3 ? 1 : 0; + j1 = simplex[c][1] >= 3 ? 1 : 0; + k1 = simplex[c][2] >= 3 ? 1 : 0; + l1 = simplex[c][3] >= 3 ? 1 : 0; + + // The number 2 in the "simplex" array is at the second largest coordinate. + i2 = simplex[c][0] >= 2 ? 1 : 0; + j2 = simplex[c][1] >= 2 ? 1 : 0; + k2 = simplex[c][2] >= 2 ? 1 : 0; + l2 = simplex[c][3] >= 2 ? 1 : 0; + + // The number 1 in the "simplex" array is at the second smallest coordinate. + i3 = simplex[c][0] >= 1 ? 1 : 0; + j3 = simplex[c][1] >= 1 ? 1 : 0; + k3 = simplex[c][2] >= 1 ? 1 : 0; + l3 = simplex[c][3] >= 1 ? 1 : 0; + + // The fifth corner has all coordinate offsets = 1, so no need to look that up. + + double x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords + double y1 = y0 - j1 + G4; + double z1 = z0 - k1 + G4; + double w1 = w0 - l1 + G4; + + double x2 = x0 - i2 + G42; // Offsets for third corner in (x,y,z,w) coords + double y2 = y0 - j2 + G42; + double z2 = z0 - k2 + G42; + double w2 = w0 - l2 + G42; + + double x3 = x0 - i3 + G43; // Offsets for fourth corner in (x,y,z,w) coords + double y3 = y0 - j3 + G43; + double z3 = z0 - k3 + G43; + double w3 = w0 - l3 + G43; + + double x4 = x0 + G44; // Offsets for last corner in (x,y,z,w) coords + double y4 = y0 + G44; + double z4 = z0 + G44; + double w4 = w0 + G44; + + // Work out the hashed gradient indices of the five simplex corners + int ii = i & 255; + int jj = j & 255; + int kk = k & 255; + int ll = l & 255; + + int gi0 = perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32; + int gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32; + int gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32; + int gi3 = perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32; + int gi4 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32; + + // Calculate the contribution from the five corners + double t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; + if (t0 < 0) { + n0 = 0.0; + } else { + t0 *= t0; + n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0); + } + + double t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; + if (t1 < 0) { + n1 = 0.0; + } else { + t1 *= t1; + n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1); + } + + double t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; + if (t2 < 0) { + n2 = 0.0; + } else { + t2 *= t2; + n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2); + } + + double t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; + if (t3 < 0) { + n3 = 0.0; + } else { + t3 *= t3; + n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3); + } + + double t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; + if (t4 < 0) { + n4 = 0.0; + } else { + t4 *= t4; + n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4); + } + + // Sum up and scale the result to cover the range [-1,1] + return 27.0 * (n0 + n1 + n2 + n3 + n4); + } + + /** + * Gets the singleton unseeded instance of this generator + * + * @return Singleton + */ + public static SimplexNoiseGenerator getInstance() { + return instance; + } +} diff --git a/src/main/java/org/bukkit/util/noise/SimplexOctaveGenerator.java b/src/main/java/org/bukkit/util/noise/SimplexOctaveGenerator.java new file mode 100644 index 0000000..6faf4ec --- /dev/null +++ b/src/main/java/org/bukkit/util/noise/SimplexOctaveGenerator.java @@ -0,0 +1,129 @@ + +package org.bukkit.util.noise; + +import org.bukkit.World; + +import java.util.Random; + +/** + * Creates simplex noise through unbiased octaves + */ +public class SimplexOctaveGenerator extends OctaveGenerator { + private double wScale = 1; + + /** + * Creates a simplex octave generator for the given world + * + * @param world World to construct this generator for + * @param octaves Amount of octaves to create + */ + public SimplexOctaveGenerator(World world, int octaves) { + this(new Random(world.getSeed()), octaves); + } + + /** + * Creates a simplex octave generator for the given world + * + * @param seed Seed to construct this generator for + * @param octaves Amount of octaves to create + */ + public SimplexOctaveGenerator(long seed, int octaves) { + this(new Random(seed), octaves); + } + + /** + * Creates a simplex octave generator for the given {@link Random} + * + * @param rand Random object to construct this generator for + * @param octaves Amount of octaves to create + */ + public SimplexOctaveGenerator(Random rand, int octaves) { + super(createOctaves(rand, octaves)); + } + + @Override + public void setScale(double scale) { + super.setScale(scale); + setWScale(scale); + } + + /** + * Gets the scale used for each W-coordinates passed + * + * @return W scale + */ + public double getWScale() { + return wScale; + } + + /** + * Sets the scale used for each W-coordinates passed + * + * @param scale New W scale + */ + public void setWScale(double scale) { + wScale = scale; + } + + /** + * Generates noise for the 3D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param z Z-coordinate + * @para, w W-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @return Resulting noise + */ + public double noise(double x, double y, double z, double w, double frequency, double amplitude) { + return noise(x, y, z, w, frequency, amplitude, false); + } + + /** + * Generates noise for the 3D coordinates using the specified number of octaves and parameters + * + * @param x X-coordinate + * @param y Y-coordinate + * @param z Z-coordinate + * @para, w W-coordinate + * @param frequency How much to alter the frequency by each octave + * @param amplitude How much to alter the amplitude by each octave + * @param normalized If true, normalize the value to [-1, 1] + * @return Resulting noise + */ + public double noise(double x, double y, double z, double w, double frequency, double amplitude, boolean normalized) { + double result = 0; + double amp = 1; + double freq = 1; + double max = 0; + + x *= xScale; + y *= yScale; + z *= zScale; + w *= wScale; + + for (int i = 0; i < octaves.length; i++) { + result += ((SimplexNoiseGenerator)octaves[i]).noise(x * freq, y * freq, z * freq, w * freq) * amp; + max += amp; + freq *= frequency; + amp *= amplitude; + } + + if (normalized) { + result /= max; + } + + return result; + } + + private static NoiseGenerator[] createOctaves(Random rand, int octaves) { + NoiseGenerator[] result = new NoiseGenerator[octaves]; + + for (int i = 0; i < octaves; i++) { + result[i] = new SimplexNoiseGenerator(rand); + } + + return result; + } +} diff --git a/src/main/java/org/bukkit/util/permissions/BroadcastPermissions.java b/src/main/java/org/bukkit/util/permissions/BroadcastPermissions.java new file mode 100644 index 0000000..092370e --- /dev/null +++ b/src/main/java/org/bukkit/util/permissions/BroadcastPermissions.java @@ -0,0 +1,22 @@ +package org.bukkit.util.permissions; + +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; + +public final class BroadcastPermissions { + private static final String ROOT = "bukkit.broadcast"; + private static final String PREFIX = ROOT + "."; + + private BroadcastPermissions() {} + + public static Permission registerPermissions(Permission parent) { + Permission broadcasts = DefaultPermissions.registerPermission(ROOT, "Allows the user to receive all broadcast messages", parent); + + DefaultPermissions.registerPermission(PREFIX + "admin", "Allows the user to receive administrative broadcasts", PermissionDefault.OP, broadcasts); + DefaultPermissions.registerPermission(PREFIX + "user", "Allows the user to receive user broadcasts", PermissionDefault.TRUE, broadcasts); + + broadcasts.recalculatePermissibles(); + + return broadcasts; + } +} diff --git a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java new file mode 100644 index 0000000..ab83555 --- /dev/null +++ b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java @@ -0,0 +1,111 @@ +package org.bukkit.util.permissions; + +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; + +public final class CommandPermissions { + private static final String ROOT = "bukkit.command"; + private static final String PREFIX = ROOT + "."; + + private CommandPermissions() {} + + private static Permission registerWhitelist(Permission parent) { + Permission whitelist = DefaultPermissions.registerPermission(PREFIX + "whitelist", "Allows the user to modify the server whitelist", PermissionDefault.OP, parent); + + DefaultPermissions.registerPermission(PREFIX + "whitelist.add", "Allows the user to add a player to the server whitelist", whitelist); + DefaultPermissions.registerPermission(PREFIX + "whitelist.remove", "Allows the user to remove a player from the server whitelist", whitelist); + DefaultPermissions.registerPermission(PREFIX + "whitelist.reload", "Allows the user to reload the server whitelist", whitelist); + DefaultPermissions.registerPermission(PREFIX + "whitelist.enable", "Allows the user to enable the server whitelist", whitelist); + DefaultPermissions.registerPermission(PREFIX + "whitelist.disable", "Allows the user to disable the server whitelist", whitelist); + DefaultPermissions.registerPermission(PREFIX + "whitelist.list", "Allows the user to list all the users on the server whitelist", whitelist); + + whitelist.recalculatePermissibles(); + + return whitelist; + } + + private static Permission registerBan(Permission parent) { + Permission ban = DefaultPermissions.registerPermission(PREFIX + "ban", "Allows the user to ban people", PermissionDefault.OP, parent); + + DefaultPermissions.registerPermission(PREFIX + "ban.player", "Allows the user to ban players", ban); + DefaultPermissions.registerPermission(PREFIX + "ban.ip", "Allows the user to ban IP addresses", ban); + + ban.recalculatePermissibles(); + + return ban; + } + + private static Permission registerUnban(Permission parent) { + Permission unban = DefaultPermissions.registerPermission(PREFIX + "unban", "Allows the user to unban people", PermissionDefault.OP, parent); + + DefaultPermissions.registerPermission(PREFIX + "unban.player", "Allows the user to unban players", unban); + DefaultPermissions.registerPermission(PREFIX + "unban.ip", "Allows the user to unban IP addresses", unban); + + unban.recalculatePermissibles(); + + return unban; + } + + private static Permission registerOp(Permission parent) { + Permission op = DefaultPermissions.registerPermission(PREFIX + "op", "Allows the user to change operators", PermissionDefault.OP, parent); + + DefaultPermissions.registerPermission(PREFIX + "op.give", "Allows the user to give a player operator status", op); + DefaultPermissions.registerPermission(PREFIX + "op.take", "Allows the user to take a players operator status", op); + + op.recalculatePermissibles(); + + return op; + } + + private static Permission registerSave(Permission parent) { + Permission save = DefaultPermissions.registerPermission(PREFIX + "save", "Allows the user to save the worlds", PermissionDefault.OP, parent); + + DefaultPermissions.registerPermission(PREFIX + "save.enable", "Allows the user to enable automatic saving", save); + DefaultPermissions.registerPermission(PREFIX + "save.disable", "Allows the user to disable automatic saving", save); + DefaultPermissions.registerPermission(PREFIX + "save.perform", "Allows the user to perform a manual save", save); + + save.recalculatePermissibles(); + + return save; + } + + private static Permission registerTime(Permission parent) { + Permission time = DefaultPermissions.registerPermission(PREFIX + "time", "Allows the user to alter the time", PermissionDefault.OP, parent); + + DefaultPermissions.registerPermission(PREFIX + "time.add", "Allows the user to fast-forward time", time); + DefaultPermissions.registerPermission(PREFIX + "time.set", "Allows the user to change the time", time); + + time.recalculatePermissibles(); + + return time; + } + + public static Permission registerPermissions(Permission parent) { + Permission commands = DefaultPermissions.registerPermission(ROOT, "Gives the user the ability to use all Craftbukkit commands", parent); + + registerWhitelist(commands); + registerBan(commands); + registerUnban(commands); + registerOp(commands); + registerSave(commands); + registerTime(commands); + + DefaultPermissions.registerPermission(PREFIX + "kill", "Allows the user to commit suicide", PermissionDefault.TRUE, commands); + DefaultPermissions.registerPermission(PREFIX + "me", "Allows the user to perform a chat action", PermissionDefault.TRUE, commands); + DefaultPermissions.registerPermission(PREFIX + "tell", "Allows the user to privately message another player", PermissionDefault.TRUE, commands); + DefaultPermissions.registerPermission(PREFIX + "say", "Allows the user to talk as the console", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "give", "Allows the user to give items to players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "teleport", "Allows the user to teleport players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "kick", "Allows the user to kick players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "stop", "Allows the user to stop the server", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "list", "Allows the user to list all online players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "help", "Allows the user to view the vanilla help menu", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "plugins", "Allows the user to view the list of plugins running on this server", PermissionDefault.TRUE, commands); + DefaultPermissions.registerPermission(PREFIX + "reload", "Allows the user to reload the server settings", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "version", "Allows the user to view the version of the server", PermissionDefault.TRUE, commands); + + commands.recalculatePermissibles(); + + return commands; + } +} diff --git a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java new file mode 100644 index 0000000..55affd5 --- /dev/null +++ b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java @@ -0,0 +1,84 @@ +package org.bukkit.util.permissions; + +import org.bukkit.Bukkit; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; + +import java.util.Map; + +public final class DefaultPermissions { + private static final String ROOT = "craftbukkit"; + private static final String PREFIX = ROOT + "."; + private static final String LEGACY_PREFIX = "craft"; + + private DefaultPermissions() {} + + public static Permission registerPermission(Permission perm) { + return registerPermission(perm, true); + } + + public static Permission registerPermission(Permission perm, boolean withLegacy) { + Permission result = perm; + + try { + Bukkit.getPluginManager().addPermission(perm); + } catch (IllegalArgumentException ex) { + result = Bukkit.getPluginManager().getPermission(perm.getName()); + } + + if (withLegacy) { + Permission legacy = new Permission(LEGACY_PREFIX + result.getName(), result.getDescription(), PermissionDefault.FALSE); + legacy.getChildren().put(result.getName(), true); + registerPermission(perm, false); + } + + return result; + } + + public static Permission registerPermission(Permission perm, Permission parent) { + parent.getChildren().put(perm.getName(), true); + return registerPermission(perm); + } + + public static Permission registerPermission(String name, String desc) { + Permission perm = registerPermission(new Permission(name, desc)); + return perm; + } + + public static Permission registerPermission(String name, String desc, Permission parent) { + Permission perm = registerPermission(name, desc); + parent.getChildren().put(perm.getName(), true); + return perm; + } + + public static Permission registerPermission(String name, String desc, PermissionDefault def) { + Permission perm = registerPermission(new Permission(name, desc, def)); + return perm; + } + + public static Permission registerPermission(String name, String desc, PermissionDefault def, Permission parent) { + Permission perm = registerPermission(name, desc, def); + parent.getChildren().put(perm.getName(), true); + return perm; + } + + public static Permission registerPermission(String name, String desc, PermissionDefault def, Map children) { + Permission perm = registerPermission(new Permission(name, desc, def, children)); + return perm; + } + + public static Permission registerPermission(String name, String desc, PermissionDefault def, Map children, Permission parent) { + Permission perm = registerPermission(name, desc, def, children); + parent.getChildren().put(perm.getName(), true); + return perm; + } + + public static void registerCorePermissions() { + Permission parent = registerPermission(ROOT, "Gives the user the ability to use all Craftbukkit utilities and commands"); + + CommandPermissions.registerPermissions(parent); + BroadcastPermissions.registerPermissions(parent); + + parent.recalculatePermissibles(); + } +} diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..a77e8c3 --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Created-By: 1.6.0 +Specification-Title: Bukkit +Main-Class: org.bukkit.craftbukkit.Main +Specification-Version: unknown +Specification-Vendor: Bukkit Team +Implementation-Version: git-Bukkit-0.0.0-980-g4ed23b1-b1060jnks +Implementation-Vendor: Bukkit Team +Sealed: true +Implementation-Title: CraftBukkit + +Name: net/bukkit/ +Sealed: true + +Name: com/bukkit/ +Sealed: true + +Name: org/bukkit/ +Sealed: true diff --git a/src/main/resources/achievement/map.txt b/src/main/resources/achievement/map.txt new file mode 100644 index 0000000..aaf280a --- /dev/null +++ b/src/main/resources/achievement/map.txt @@ -0,0 +1,446 @@ +1000,43ddd8b48469d9a8c011718aa846facb +1001,aaed8c669f583cf35300f7c5d5396fce +1002,d517ae73160fd8576d7687ead1c1a973 +1003,ac37df168bae3c69a24d7fd5bae913c7 +1004,6d2591e94464b8327afadbdba44978d +1100,8b1df73e012e2ae34cd2d84a72a7898b +2000,c9ee0d494e0524c86a577cf684f5816d +2001,cd7a2836ea0b77b23a6131222f5be354 +2002,381aeedb2c5c5a7a9a01333e0eebc839 +2003,229048d1bb9e928831734cb2e5000286 +2004,b2c088c3c6928bfe29684a75ae1b127c +2005,1ce3491a1021a5aed07c687e3f6133e6 +2006,6c3d114caffd8160f7d56fc8757419a +2007,bcb501cfac8f7e73b455563bddbcb417 +2008,e1aa93d7bba48898a32810c43c6ff5c3 +2010,d0818779df1b967cc2f8ffc3ada631ec +2011,ecf0dbe93240e84edf6bd263645e634f +2020,b4a67353e11c3039ad755a3e96b4a046 +2021,1bb21f7731a5b3ffc6a1e2b586dae3f5 +2022,e58162e284df8fe339f05626eb46d835 +2023,739948643f5f6f685aea81c42883a480 +2024,799b0d35362a9574d3226c2d762b53c6 +2025,5ec18fbb462516a1e1a3427e0595a7d6 +16908544,12512904b67d2091dd516dc8eeb0cfa0 +16908545,a5c35cc01a263f91419d3e8e981708f1 +16908546,f6bdebf227e42c204066cede8cb5928c +16908547,9c44e6d3ab80afa2bb52fe3499559d5e +16908548,2e1799ddfdab14417c2a8e24d8c0c731 +16908549,3f4169a181feb5d2532efc6aa91f2ee5 +16908550,895725d3432cbf374b1cce4f7db28e9 +16908551,12892864f18d30521b6f4a6c45b65ece +16908552,146f6c3458adde8e0bca04d976275f85 +16908553,7c40dbd9451129b4762f3ab04ce7ffb9 +16908554,56d763eeb6a0107c2146d7dccd686d2a +16908555,9a4fff004ae419711c2a876b57cba69f +16908556,170ff67dd90d8d3d8dae393037da5e9b +16908557,3e65d657af8611cb3578cd8713419d4c +16908558,f3cb95383f698c4e9721b5aaa5fac3a7 +16908559,65bd006dc163a186f2dbb127f8ec0b27 +16908560,8c6479d786f9117e04910153a4f47d86 +16908561,75a25bd69f36250789d914ac01da34c1 +16908562,87a28b2bf2fad838af72ce00e2fb1937 +16908563,249ff32d605c5ba0a07694ff4fbbf15a +16908564,ba3b355eb9134bcd7522a1fc203c4c58 +16908565,321e1cb3657d2aca73fb9a8083d9c3bf +16908566,adb182051fab2c2269df89b4f75e505e +16908567,3d9ae8982f01fb6a6c56cffbe2fa074e +16908568,1efffb054b2c864f5ebe180ae46891c3 +16908569,25c73629d0b6b46690d222cecf331ba2 +16908570,6a46694c996e5721b14c9da1f00fe62c +16908571,5efc1c291eef23fe33f5209388b8cc33 +16908572,f71fc7deef6835c8efc305a00f1e8b8f +16908573,15484a373254c6024d90edf3b7a82947 +16908574,8253f1aaa2205dcaf828903cfce46e4 +16908575,ab778410d1fb2c0e55fec0c7d764b17c +16908576,19ad61c04ff3ae082955f72fc8771866 +16908577,b5d3eeff40086643a03f034b5345504d +16908578,3d647bf5562e743263cbd90be36b6a1c +16908579,5a9d2fb7050009785421257d5ef24416 +16908580,909b03e2d2eeee2e868b5aaf446e81ea +16908581,e603a4cbfdfcbf4d0bfe25efb753b424 +16908582,e355f481f99220e50e4b2b2eb45dcc56 +16908583,73a25e59c2d18ae77db02928b0a70e3 +16908584,8f81a2fb647f817422a299829994de7b +16908585,128e9978380ee9ef981d2e12d008255e +16908586,fd1453f3e2a3125e7d16cfe6fd2d4722 +16908587,8e27b6f750bec22333a5d4108ce1e094 +16908588,b2169f6190bdf95236037bed2301712b +16908589,536e6340e5328075ede672428d94d921 +16908590,cb9eede8b783b4a5d7ff7529e3fb1f44 +16908591,267d51d891c3c32b3a02577d38f4e242 +16908592,3f31e8ab260f02acca218c720fafc7b8 +16908593,552869a63aa3151e79e875596f31e505 +16908594,c5b0399e7fc64f0561a82063773e1282 +16908595,cfd61cdbf22133caeca528da9b53474e +16908596,8d3802169313f270d5adcda790170ca2 +16908597,a82c4f31d6d3f5bef9aa3062945c02d6 +16908598,85eca649072752e9ffafdefa1287470f +16908599,98ffd259abbe2e4794c00716a9d2da7 +16908600,263f8fab89ae0f9d695a74512443070b +16908601,b4ae28e8babe7bd09b2a392780565dbe +16908602,dfd84b5b35231267a47891cc8c8f48ba +16908603,f6990bbd57862a238aaf68b0c2f4c998 +16908604,9dca837e109ae977a89ed64dd17fab10 +16908605,ebdb407fd6e4d5c450f73173487c3162 +16908606,fdf869946d814f4f2aeebe269db06e31 +16908607,f9ea1fa393862a86e79ffade6a2662e7 +16908608,60491b4f5956534afd5959e7c2411cda +16908609,b78fc6d8b8b8ecb1266eb9c04c5129b +16908610,add241f6dcfe6af3f096a45b96fb04e1 +16908611,38760b28c0d26204b1e0383ca318947a +16908612,d3d8076b8b7a911b7cbbf5099f8ffd48 +16908613,fc78be6fb5735b715325ac499990550e +16908614,a7504fcd85d6696a8880f32b97b34a60 +16908615,f0821b6fdc8ebbf8a6fcb37c75086b1d +16908616,88b0e1b842fc88f0cbc5f38e95d68417 +16908617,d977f8453c349a44baa7e05c3dd81cb8 +16908618,26184c3c1edfa7623d5620433c0ff36 +16908619,8edbf7f3996852add4fcb18008cb722f +16908620,39e5881696ed1141fb934593dd6bab70 +16908621,1e0d787240ea16af6edbbdb1ab372fe7 +16908622,af6ec83a0b072b4abd4194d8d43f7f02 +16908623,658b5f77ff892a455a7fce5dc93268ac +16908624,6474336f089d541c9cec4a1df0c3b6cf +16908625,72cfc6fe503df207d53119aa7d5b84b4 +16908626,3070c2283ca5fd0fe00f7880a4bcdf18 +16908627,340cef5b043dceb7073ede0be69d700d +16908628,24dda1839a72d6707ed1932f6f32bd8e +16908629,1c50c7d94cec18710417d513708094d1 +16908630,2b1f11fed636bf7892650b9adc9b8e94 +16908631,afd9ba61c39fa742a840fe6ab2cfb490 +16908632,b709157ffabe225e820218b020508173 +16908633,3e9f7b867952f7b2df48e156402d558 +16908634,ab9f22a1fbc265d19a4dd7f84f3a4585 +16908635,c89cf9510108d63d7d181b3f7c546094 +16908636,c7af3251ce44f2dafb2c192d817e9c52 +16908637,796f607d214012447b7c552673f95b4a +16908638,ea796bd83dd7689d322085c74d0957a7 +16908639,ce2f6f842d68418baad5fc2ecefcb879 +16908640,6b3016429a5f814f3cccaff484a46831 +16908641,7dea9bdb69c9c5965609eab99af9f9d9 +16908642,3add5c50b3427182fcb7dd04fe953945 +16908643,4175965cd5cee134d43038ac54858b0f +16908644,feae27a32b6cc95860ec46da6d37c4b0 +16908645,5898813ee0b2785afc9dad2524f56162 +16910544,adb04e128238341b88a18532f3448d13 +16910545,8e274d3a14b5cb87cbce019d0a3b9a23 +16974080,cfed396d9f54d3c04bc390a004916c52 +16974081,64f1b3409c0937114f77f9933a4e2b82 +16974082,5a6e9dc254405a6cb066472172fa09b1 +16974083,b23adf8b24d9a42637977c3322f02b75 +16974091,df1b76bca1e6a035d3e22e7c01f67bc6 +16974092,4bb3d702d36739ba62041c0c936cbfb6 +16974093,d02062bdb07f81100381ef87e6fc2922 +16974094,1a0d208f9f489b37b800c6eeaaa752c9 +16974095,34ee6807c2040168606740d0e3f46e30 +16974096,9b8bb8517841df03f1a894b238251068 +16974097,bb0b43349ffa6aa13b5d84ca70d25eb3 +16974098,b3b647da85fe51c6da997e28b66cb4c3 +16974099,d33c3d7d3fbc6880e0e03ce573644b1e +16974100,17d45fba9866349c133608e9d42e4ac9 +16974101,74205e9529729bd0ef51c3d544c1e372 +16974102,edf620106dc10c10a3357436a306400d +16974103,74b3a17953dca5a0cb9bb8c47b241eca +16974107,1938aff98985ef5e79c7003868c1e91 +16974108,14b782f5d9afda571ce6c8bad868e2bd +16974109,cb124718b4ecfb29a900e1e617c79544 +16974110,ae3c73a1546a058da74d4b8a588b59f2 +16974114,cbdefe9bd14088ad45141843474d2bb0 +16974115,641938697f84f6e7b59ebc08edc4648b +16974116,74ccb1de521aa54c65ffcb906ffd1d3b +16974117,fffed44e7bb844ad6c69f7eb4540cff3 +16974118,536b2d3a4009eed61300bf5f0af7419e +16974122,8a8ea889723fc0f8de50c53339819871 +16974123,768b65f8e24b1e042b75cf6f576cfcd1 +16974124,a4b5522486920acfc2ed97e105c7831 +16974125,6e9b513f3c219f4276556070b36a0339 +16974126,942450301cd8068c9a14352c1cecc2d0 +16974127,c98e2b8eb252d75a2a1f90144596ada4 +16974128,7b13a95332dac62ad73cddf33d3bba0f +16974129,1951adc5a346867490626a854788b9ad +16974130,b75636944eeba77a4ce3f254460e0d49 +16974131,bb5bc2285c0a2e24548533f59af76788 +16974132,929561410b14786db52aa89b675a9759 +16974133,6b07bd2605f311d8134a8170ba49fd73 +16974134,2f97923d891e3e8c1967d53f7734ff55 +16974135,dea0b11c8760d28eafbe76e25df7d301 +16974136,586e309c00ba6f3c2ada595b742bef23 +16974137,29e48d74dc5062eb900d376196fd4f23 +16974138,fa79e8b641b225166b17ea86a9ecb174 +16974139,7a66328b6b976337ff5bde5c7edccaa5 +16974140,95559b402657cf222a87248d1e6ce0f5 +16974141,52843420526ced65d57513afad342515 +16974170,56690bacbebf8107b83e80528f40740 +16908289,83cfae9a11032a88e08c95b7fcef84cc +16908291,39a4ea3b5ddf7f89b41faf675f7bfc0f +16908292,64ec21dc8495fb180cc94f59f873efb8 +16908293,fda16e9858404b9545649ba21a828a6a +16908294,a57157213ffc25d269ea46e45984eae0 +16908295,90f2ac6ac3005ad4cabcd248831f2205 +16908296,4adafcbbef5ace168ca03e173af10452 +16908298,bb2e0425d8b489fc856cab2c0828f2ff +16908300,76b80613789c553593097956002a392b +16908301,23bd5cc4fb97d25e432604be0958320d +16908302,7b129f5775b2d4997681338012130cad +16908303,4935425ac3ef59e71bca7c4c8bf7e2ea +16908304,564d5c2df622b99692929bedbcd7f4b1 +16908305,e06bb538b6b224ce1376b47804ee2bbb +16908306,f13b4a0fa66e65ed33dcbd7ead08ac46 +16908307,29710a54739e35ae0d34919fca091640 +16908308,8693b46ac89dd595f8e3efd4437e6e90 +16908309,3ebf10825c7d8f2e17deae70b37d1fbd +16908310,354d414b2a1f29494a80b3acedb72ae2 +16908311,de662954670ec00899809b916abe6c60 +16908312,831dd7a79cd7e5f3cad86690c6724902 +16908313,265f19645487a858e4f53b9706cdff03 +16908314,2ad06f9f7e24f920fb067e2f2cc7869c +16908315,99f3286cc36b9a4393b3e967878b01d4 +16908316,4fbc91a39f7f4814f8f79ba425e4f30a +16908318,ccb82be2278587dd637ac763a1087c7 +16908323,8e8a2f6a87c3701e76650680e7b2f6e6 +16908325,fcd992a9a44518d5de6bd09c409ea7de +16908326,e41e706456c10963824e032484992946 +16908327,662301d3344073cc69887a27a8c42f24 +16908329,313738e052612f868d55f47940080288 +16908330,79474b10f860f09be4e9183ad5f1c7b4 +16908332,60a3062d151151a2ff229a02d3221337 +16908333,833c8c420ce04aa18b9912ff05e5ced2 +16908334,6e0f4183ad7abbb63c5b6a1ead24214a +16908335,477292deea02d72acc1087b2425c570a +16908336,82cf44076f1a94ed31f3172433a80ef6 +16908337,84f64a9f8523d35a1cf8319f580dd578 +16908338,b6365376050089a025a1ed1d85a85dba +16908339,4e989db8b445f22b61bd4d30daee1a05 +16908340,50ec890e85029d44ea96bfa31d8ed16a +16908341,b4f23438454d39a742546dafd5d3cfc6 +16908342,5414035b686e0fb0a1ce0d535d0a0f82 +16908343,72d6218e86d3787422fa6b03f30ccaf3 +16908344,ddfe42c53aae03dd94c2d3163869ddc0 +16908345,b8b09ac7af1bb81e28715a3e0f0eeb17 +16908346,c53d28ac584d8053ec438f692a58cd1a +16908347,243cf7fb2bf36e60e3a25cde83b33a5e +16908349,2837ae3dabc00c4c5515bafa34a302dc +16908351,4973e12438ce4c870f6ba1c158873c43 +16908352,37678301896aa95cc358bcd73308232c +16908353,31c5e38768bda9a8a7cd1bbca7c9226d +16908354,5ff1e27f9ef25fcf0a3c51b0551f7fd2 +16908355,60a060ee3e51167f4d87cf6d923f9ca7 +16908356,b24aa4a609b3483b795c4f3bf89116b7 +16908357,7a17a96ff758cd4ff8c0ffd070230cc7 +16908358,c14586711c04239a174c192d24b8ce20 +16908359,1f0abe2925128be5191932a1cc4a3019 +16908360,a9c8343cf444aa7686d9dd2b40e90a47 +16908361,94a02b3ef18bb35970105bf276001fe0 +16908363,bfa45b4169d1944debabc84b04880837 +16908365,a3d0bb31ba7c30209129e4366e072b05 +16908366,de6d35451526c85c7c5907a0adcbeff7 +16908367,4a0d45a9aedaa06eb574f88f580c265b +16908368,56ab2510d3cb4787bdcfa9680aa7e757 +16908369,feef935305ae32e1972d3b017a4eb +16908370,41b270e7ecb39d0b81d1b60f32c3943 +16908371,b159339fc55e60000efee4c55d0e1d1c +16908372,74ca5387c7d373fc88e65e0623d5991f +16908373,8b8ae20ea681d47cd899f74f75bde08d +16908374,5cb926f4743f6ccdb4988c8b35dc97dd +16908375,947a02e037fe9d31c8eb4c4a22dba58c +16908376,2c2a7e8a269a770cc4afbe695e662601 +16908377,9a992e19651652de8b4f5ce07d1d2af0 +16908378,3e37efadc720d972ddc30ccae606ab00 +16908380,77b1802a2504a685bf8ff34a1f9de6c3 +16908381,45c0dbda39dca97dc634a6e89f037716 +16908383,ca404ded18b83fd872a5810c8a44517d +16843027,ecc0eb0ba51e2c14aaa006e168eacc8c +16842753,f6282e18f6f87e4cf68970579aac7219 +16843026,6f3d105b3e6d1624af4ce68b2a55362d +16843025,aa1c8e137823bf5245f0d27c980796e7 +16843024,ed65803a11251872c6cf659381d0aaaa +16843031,fa2f9de197813d8e32d78bd184603161 +16842757,1a13db89ae6fdbb152856edbe3688d95 +16843030,46bd8fadf2f12988d808e69dcfc138cb +16843029,bf398d8ec9fef1d04c67fbf474fda790 +16843028,69ee29bc3bd715b3203d888ca2a88cc0 +16843035,2f79ed9030fe0339dec2eb43f56fa369 +16843034,e2f097a36cdf87a1b211d27eb31dea32 +16843033,c02e9379a6624b40fef669494a7e7183 +16843032,af44f7fe9a4366c67479a44b24ae80b +16843038,501ead1cb03222808aa09b376c9d5cac +16843037,a2d01853631a9b52006ad32497ddc865 +16843036,6e381ac09bfc75ef7f71e02f3b99f279 +16843010,bcfe734d49949142a5073766188213dc +16843011,88ea7e11c57b09139afe92169c443e20 +16843008,91f14375672f1b2003202ec7682771cb +16843009,f5007e4886946d1eb603979a35726d69 +16843014,b0bde3daab8a1cc6354cd86c65db90e2 +16842772,b59c880de07e668eaba0888fc4de229a +16843015,7184233667abf34d2ee3eea20fb9f82b +16842775,bcc06ff4c56de9b4a1557d3c47ec1783 +16842774,6f2eab110a33c15cb17238708244db4d +16843013,3fe45d065187550d481cc745780c29c2 +16843018,7bddb0161d99059f0a6c1c09d0b35b34 +16842777,fdc779803765398f0c782a1fd55a9d86 +16842776,6b6c09ee89a933288c37f55d2187eddd +16843019,87545673867c5cf2f97ea6cc3e0d3595 +16843016,e2288c9f60d09d5f2882175abf161bd +16842779,9667a31366f5dcf740d64b775402c64 +16843017,e3108d8ee8530e50d7b425de217a4585 +16843022,847f1b6f38ebf442a1d34cac0fd6080e +16843023,5d01d19f8441e4d5dd5c41266f480ffc +16842780,b02509b360e6f14eac4fb03f55c11fed +16843020,90e2ab194dab9f482eca64c651ea41e9 +16843021,58d3e73bd29c14b6ec97d4187cee5500 +16843057,bf533b7d78ccc350cfd2f41a8e1f0822 +16842787,e49146643faf3308ca7246d82fc5b2bb +16843056,d8e023c15aa80df2445c782c6b2179da +16843059,c649596d99d96be696332cb08b4a33f2 +16843058,d129fce211dfb56e80195a11f39ab1e9 +16843061,441d86175b74884ef3f672066ae52c90 +16843060,cf6d7dfef99b200a4551cd65467fb9fc +16843063,f50f8b7fafde6d640ced3ec4d797f807 +16843062,d22de0ebc290280b2699b5cb77568fcb +16842794,d347d92a886b9d445d7d60b090a5bcda +16843065,a393477443f20a1a8a511c390024f963 +16843064,e6f28eea0ebbad0d18d23ea3c15f2102 +16843067,d6efe6a63f529d675417c2092546e144 +16842793,d5ac3bcc56cbc370ae3b172dd6ed5df4 +16843066,935aa84de286e8bced6a127b69347997 +16842798,377a21bcb39dcfcb4a0902a7555a984f +16843069,63cc6da6165cc068740827890b4460ed +16843068,6dda3129884399b67b935bb4e51ad34f +16842799,d4831a785c1c65ad2054bb1232babf0c +16842796,48be99a37d3a885d38657a50d6f77365 +16842797,8da03c2f611c7f0654aa71096832b5c +16842802,9b2a96570a99f6677e299d8215b1eecd +16843042,322d7c02f205806126f1529564ab3cd0 +16843043,660acf0ca76261ec49deb7a7bd072f8c +16843044,d8dd28acc9e4431ff8eb481c1d8d9832 +16842806,919bc6715eddf74c0517372ead95cdcb +16843045,72ae59db2ef5c472f671b31f1c6f07ce +16842805,9e359ce06b5603c820bd749592beb4a7 +16843046,cee09c2303e44dfbbaadbf167cdc503c +16842810,8ecd9ec7607c958cdf2e252f516fe3d8 +16843049,47171b2af8bb14c3816f52f79579b46d +16842809,fef5bbbc588422579bf3de8a49c73e18 +16843050,6b29998dbe690122afdf6da71e905009 +16843051,5f9f017aa89719c7a282aa222c65baf +16843052,216a61701714cb3f04e23a74a1336864 +16843053,e146704e3fe30e6821352ceb3b090184 +16842813,899942760d5a83d94cf58a536be6171e +16843054,5aa0a467c7451f88f9c6056e8c7427cc +16843055,6881fc74a0574433e9e0f05f7cae53f7 +16843095,50f6c2ffdc69bea12cd7b58c69824be1 +16842821,42b4814e4e61191b61a8d3f7c6041938 +16843094,356c3f0d5b88d0e2077d85168eac6306 +16842822,d69011621d777519c5ab6a68da8959 +16843092,d84a39f3d30a72b13640e3afb7ea2018 +16843091,37603e187bd7ad9dceccb8ef2b6b5335 +16842817,bad6f1072232c28353aabf42142cbd26 +16842818,bd0c4079c99e529e55abef5ac44dcdf8 +16843088,5e5d08b1780bfd69747216c24b7aee92 +16842819,ae608e1ca5ca083163d92974d7c66b06 +16843103,d4d1b946336039e515c3e4a392694223 +16842828,6a15bcf38bcf78021f9416ac395cac85 +16843102,603020acbbdc6e8765c2e2cd589f7933 +16842829,41cce73f9ce59993afa3517becd4bd3c +16842824,2368ffe803beb1d06772e96eeffd9cc9 +16843099,c373e78822d440c926edf7f1b700d4c5 +16843098,503a4fb49cbfebe1fb71ef185c8ced56 +16843097,4e72dc4d35b34147ce69d691aa2937e3 +16842837,4c903ddf3b9cd49a952a3889fc2c5573 +16842836,a304f875b846d65498366479fbf34568 +16843076,1b11a34d5c6cee280c727938ee96054b +16843077,ff170af78a0a674445f16e24394546c0 +16843074,ba8bd10757ab9a4446f024952bf3f1e3 +16843075,b34ec8f0f5f92acf230925c89eacec65 +16842832,3b10180dc99ab99568b51010d89c655c +16843072,d752bd5dd907feec915d036d76707ee5 +16843073,168e43895b105169862fa2e3c205529b +16842834,58efc828918aa006d5af09e32fe7799b +16843085,b30c099494e63d26f755d58ba109136a +16842841,2c471142bddf9a982a48e0ecb52cbb8 +16843082,5574b9699d71e02f3efb48f3712da8bf +16843080,4945e39d1260ff273c49d39dfc58c2a8 +16842843,bfc9dce4c1ccef959c57360fb9f70205 +16843108,4e225dd49c0231b617a15ded1ba6cb0a +16843109,35715377a038019c56925b2e661cfdab +16843105,3b91182484dc677a0bf27263e612d818 +16843106,affab7221afa03df4b7306b9ce50be7f +16843107,e3710bc197d17e0dc78ae3f607c46048 +16777217,9012132a1d0f770eca67e62a68247137 +16777219,58fc65723143afeb33f742c17e028c94 +16777220,1d5e2088f7137e304366873dd829ca98 +16777221,66a18fa3f554756edc12bf1a08586bc8 +16777222,4007295f7bdae0b78a6e47a9d64521 +16777228,c154160ce7b52d4bdc220fc954edf796 +16777229,2400808c6f442f2663b6869e4930c879 +16777230,7ae3b31e8e0f2f22f50fbf224e1fe4f7 +16777231,fe5698e183b10037e38f979a411489b8 +16777232,aeae00c7b4a95ff05423c1629bf3ad7e +16777233,72153ea3d60930cebf4c0d37fac89102 +16777235,f517ab768fbb35e275440b74b6631bfc +16777236,623df9298630687873579ea16bb97e7b +16777237,6984cb9e6a322728be736860b97b971a +16777238,6947378f4e2abb24b47e2b943945b16f +16777239,55a585682bf0569a60a71a66f031ca2 +16777240,f653295b0c48244dc2aa68fc5b94fa29 +16777241,c213fb7ee968403b24ff6ede98686add +16777243,afd641da6f3834b319b761ba6d72ff74 +16777244,8d822c710a221b8a407b2def97885470 +16777246,9c99187cc6fd9c958417b4736772e4d3 +16777251,6418210d69669c4a602148ed42ab2ecd +16777253,afe51ea56dc8c831f9b0b5ae02bac702 +16777254,95812c1d4021558b6a7f62521228c52a +16777255,3a1252acb6fe968751d2b61d57557e09 +16777257,fd7caeeb5d16756028f19ba016ed1970 +16777258,6339b8043c05d19c6b15135eade95f94 +16777260,aa1ed939a8b275df9dc5474bc0477a33 +16777261,b631dcf219d3add3560f243ff6cceb75 +16777262,91eca0c33ac53fb155feb15db48c43de +16777263,b681c19d7812c281b4b2feabb88697f4 +16777264,a2b07ae4f37a65fe1f5992826b578b02 +16777265,af5255a4dcb486e2ab11669fd3de8441 +16777266,8a4b2b706f219e52a261e342b47a3964 +16777269,921cb54cfb47ca9eca0edcf8e660e3cd +16777270,b79b3a522d1e2f865eb1e9aeb63dc66a +16777272,36e1c1dd8cbb267488e1669811319e7e +16777273,c84a7d710228024c2e100a79a2c30e55 +16777274,a1674e3020689bae5680f29f937e5424 +16777277,46b34dd723f7efeb38f670925ee3824f +16777281,da71e3e4f9a25c6621d2f0b40ffd1c72 +16777282,388109bb9b9b49c1f5bb604abee91671 +16777283,eb6912fd84b2d57ed3433acb3f85d3e6 +16777285,619967351702f1d570d4d0195bbbcc1e +16777286,ebff74d54387fb154d5b467e01d92b64 +16777288,f8154dd7c9c1d397dd64eeb6569d7d34 +16777289,971cc6f827398c6c4755b310c6795672 +16777291,bb952ff9523f248ddaae56317e91a509 +16777293,e5c24577cf35a31bd217d206b88a7499 +16777294,f4c170867c75982e604358da611b26e3 +16777295,922200512d058ecc0ef19a0efcdb51bf +16777296,39283c3dbafb10b2a732f9d6ef3e08b6 +16777297,3603ae881c41c957a89aaa30990c0040 +16777298,fbf9e47600457d091060b0f877458a83 +16777300,2b0d53bafa91c68bf59b5863354bd7ae +16777301,50b99fabae858e971eb02ed5146fd63a +16777302,7a32eac396b4cf3930ba9ca7b5d8dbae +16777303,115f1e956219026bb9cca0bcafb2b11b +16777304,afb2f032a96d859ca5f24d8ff129bd64 +16777305,372b3a0fd7c09f64f3cfcab89f03a9a0 +16777306,e4b6233ac91337dcc3940e309d21c3c +16777311,d290638555ce76ce3053c70fdacf7d55 +5242880,8099ff561e194072c9086dea38757a89 +5242881,90b3d9a90a8cf3e21527fc8fe3b43c49 +5242882,c9806dd45be8ebed3e4ab94f66e65212 +5242883,f382ded5f9a4299e3879dea4f7fe1c50 +5242884,27af08a994f76a2a08ec8671d14fdcc2 +5242885,9969ce4355ae7338470461f48f4e5ef5 +5242886,39208e0b0f070629cad494da5fb95f0d +5242887,678e63329d3d813f22e0f15006a93768 +5242888,694ffe9efa49193780d4b757115c9064 +5242889,9080a51ccefd23f9924bae9a854e7b49 +5242890,5f1d51ccd1b4adf141707907233f8379 +5242891,73df45f45e0b7484ef51441ad0e50604 +5242892,c9e52234c475354483dc3e9e6386af61 +5242893,3c3ee1df989ecf5de70a5673acfa33b8 +5242894,468cc8b546e1586406b78ad733976f5f +5242895,e546a7afaaa6c6729e3b062fc4ace4ae diff --git a/src/main/resources/font.txt b/src/main/resources/font.txt new file mode 100644 index 0000000..59c1d31 --- /dev/null +++ b/src/main/resources/font.txt @@ -0,0 +1,10 @@ +# This file NEEDS to be in UTF-8 format! + !"#$%&'()*+,-./ +0123456789:;<=>? +@ABCDEFGHIJKLMNO +PQRSTUVWXYZ[\]^_ +'abcdefghijklmno +pqrstuvwxyz{|}~⌂ +ÇüéâäàåçêëèïîìÄÅ +ÉæÆôöòûùÿÖÜø£Ø×ƒ +áíóúñѪº¿®¬½¼¡«» \ No newline at end of file diff --git a/src/main/resources/lang/en_US.lang b/src/main/resources/lang/en_US.lang new file mode 100644 index 0000000..704f1c4 --- /dev/null +++ b/src/main/resources/lang/en_US.lang @@ -0,0 +1,579 @@ + +gui.done=Done +gui.cancel=Cancel +gui.toMenu=Back to title screen +gui.up=Up +gui.down=Down +gui.yes=Yes +gui.no=No + +menu.singleplayer=Singleplayer +menu.multiplayer=Multiplayer +menu.mods=Mods and Texture Packs +menu.options=Options... +menu.quit=Quit Game + +selectWorld.title=Select World +selectWorld.empty=empty +selectWorld.world=World +selectWorld.select=Play Selected World +selectWorld.create=Create New World +selectWorld.createDemo=Play New Demo World +selectWorld.delete=Delete +selectWorld.rename=Rename +selectWorld.deleteQuestion=Are you sure you want to delete this world? +selectWorld.deleteWarning=will be lost forever! (A long time!) +selectWorld.deleteButton=Delete +selectWorld.renameButton=Rename +selectWorld.renameTitle=Rename World +selectWorld.conversion=Must be converted! +selectWorld.newWorld=New World +selectWorld.enterName=World Name +selectWorld.resultFolder=Will be saved in: +selectWorld.enterSeed=Seed for the World Generator +selectWorld.seedInfo=Leave blank for a random seed + +multiplayer.title=Play Multiplayer +multiplayer.connect=Connect +multiplayer.info1=Minecraft Multiplayer is currently not finished, but there +multiplayer.info2=is some buggy early testing going on. +multiplayer.ipinfo=Enter the IP of a server to connect to it: + +multiplayer.downloadingTerrain=Downloading terrain + +multiplayer.stopSleeping=Leave Bed + +demo.day.1=This demo will last five game days, do your best! +demo.day.2=Day Two +demo.day.3=Day Three +demo.day.4=Day Four +demo.day.5=This is your last day! +demo.day.warning=Your time is almost up! +demo.day.6=You have passed your fifth day, use F2 to save a screenshot of your creation +demo.reminder=The demo time has expired, buy the game to continue or start a new world! +demo.help.movement=Use %1$s, %2$s, %3$s, %4$s and the mouse to move around +demo.help.jump=Jump by pressing %1$s +demo.help.inventory=Use %1$s to open your inventory + +connect.connecting=Connecting to the server... +connect.authorizing=Logging in... +connect.failed=Failed to connect to the server + +disconnect.genericReason=%s +disconnect.disconnected=Disconnected by Server +disconnect.lost=Connection Lost +disconnect.kicked=Was kicked from the game +disconnect.timeout=Timed out +disconnect.closed=Connection closed +disconnect.loginFailed=Failed to login +disconnect.loginFailedInfo=Failed to login: %s +disconnect.quitting=Quitting +disconnect.endOfStream=End of stream +disconnect.overflow=Buffer overflow + +options.off=OFF +options.on=ON +options.title=Options +options.controls=Controls... +options.video=Video Settings... +options.videoTitle=Video Settings +options.music=Music +options.sound=Sound +options.invertMouse=Invert Mouse +options.sensitivity=Sensitivity +options.sensitivity.min=*yawn* +options.sensitivity.max=HYPERSPEED!!! +options.renderDistance=Render Distance +options.renderDistance.tiny=Tiny +options.renderDistance.short=Short +options.renderDistance.normal=Normal +options.renderDistance.far=Far +options.viewBobbing=View Bobbing +options.ao=Smooth Lighting +options.anaglyph=3D Anaglyph +options.framerateLimit=Performance +options.difficulty=Difficulty +options.difficulty.peaceful=Peaceful +options.difficulty.easy=Easy +options.difficulty.normal=Normal +options.difficulty.hard=Hard +options.graphics=Graphics +options.graphics.fancy=Fancy +options.graphics.fast=Fast +options.guiScale=GUI Scale +options.guiScale.auto=Auto +options.guiScale.small=Small +options.guiScale.normal=Normal +options.guiScale.large=Large +options.advancedOpengl=Advanced OpenGL + +performance.max=Max FPS +performance.balanced=Balanced +performance.powersaver=Power saver + +controls.title=Controls + +key.forward=Forward +key.left=Left +key.back=Back +key.right=Right +key.jump=Jump +key.inventory=Inventory +key.drop=Drop +key.chat=Chat +key.fog=Toggle Fog +key.sneak=Sneak +key.playerlist=List players + +texturePack.openFolder=Open texture pack folder +texturePack.title=Select Texture Pack +texturePack.folderInfo=(Place texture pack files here) + +tile.stone.name=Stone +tile.stone.desc= +tile.grass.name=Grass +tile.grass.desc= +tile.dirt.name=Dirt +tile.dirt.desc= +tile.stonebrick.name=Cobblestone +tile.stonebrick.desc= +tile.wood.name=Wooden Planks +tile.wood.desc= +tile.sapling.name=Sapling +tile.sapling.desc= +tile.bedrock.name=Bedrock +tile.bedrock.desc= +tile.water.name=Water +tile.water.desc= +tile.lava.name=Lava +tile.lava.desc= +tile.sand.name=Sand +tile.sand.desc= +tile.sandStone.name=Sandstone +tile.sand.desc= +tile.gravel.name=Gravel +tile.gravel.desc= +tile.oreGold.name=Gold Ore +tile.oreGold.desc= +tile.oreIron.name=Iron Ore +tile.oreIron.desc= +tile.oreCoal.name=Coal Ore +tile.oreCoal.desc= +tile.log.name=Wood +tile.log.desc= +tile.leaves.name=Leaves +tile.leaves.desc= +tile.sponge.name=Sponge +tile.sponge.desc= +tile.glass.name=Glass +tile.glass.desc= +tile.cloth.name=Wool +tile.cloth.desc= +tile.flower.name=Flower +tile.flower.desc= +tile.rose.name=Rose +tile.rose.desc= +tile.mushroom.name=Mushroom +tile.mushroom.desc= +tile.blockGold.name=Block of Gold +tile.blockGold.desc= +tile.blockIron.name=Block of Iron +tile.blockIron.desc= +tile.stoneSlab.stone.name=Stone Slab +tile.stoneSlab.stone.desc= +tile.stoneSlab.sand.name=Sandstone Slab +tile.stoneSlab.sand.desc= +tile.stoneSlab.wood.name=Wooden Slab +tile.stoneSlab.wood.desc= +tile.stoneSlab.cobble.name=Stone Slab +tile.stoneSlab.cobble.desc= +tile.brick.name=Bricks +tile.brick.desc= +tile.tnt.name=TNT +tile.tnt.desc= +tile.bookshelf.name=Bookshelf +tile.bookshelf.desc= +tile.stoneMoss.name=Moss Stone +tile.stoneMoss.desc= +tile.obsidian.name=Obsidian +tile.obsidian.desc= +tile.torch.name=Torch +tile.torch.desc= +tile.fire.name=Fire +tile.fire.desc= +tile.mobSpawner.name=Monster Spawner +tile.mobSpawner.desc= +tile.stairsWood.name=Wooden Stairs +tile.stairsWood.desc= +tile.chest.name=Chest +tile.chest.desc= +tile.redstoneDust.name=Redstone Dust +tile.redstoneDust.desc= +tile.oreDiamond.name=Diamond Ore +tile.oreDiamond.desc= +tile.blockDiamond.name=Block of Diamond +tile.blockDiamond.desc= +tile.workbench.name=Crafting Table +tile.workbench.desc= +tile.crops.name=Crops +tile.crops.desc= +tile.farmland.name=Farmland +tile.farmland.desc= +tile.furnace.name=Furnace +tile.furnace.desc= +tile.sign.name=Sign +tile.sign.desc= +tile.doorWood.name=Wooden Door +tile.doorWood.desc= +tile.ladder.name=Ladder +tile.ladder.desc= +tile.rail.name=Rail +tile.rail.desc= +tile.goldenRail.name=Powered Rail +tile.goldenRail.desc= +tile.detectorRail.name=Detector Rail +tile.detectorRail.desc= +tile.stairsStone.name=Stone Stairs +tile.stairsStone.desc= +tile.lever.name=Lever +tile.lever.desc= +tile.pressurePlate.name=Pressure Plate +tile.pressurePlate.desc= +tile.doorIron.name=Iron Door +tile.doorIron.desc= +tile.oreRedstone.name=Redstone Ore +tile.oreRedstone.desc= +tile.notGate.name=Redstone Torch +tile.notGate.desc= +tile.button.name=Button +tile.button.desc= +tile.snow.name=Snow +tile.snow.desc= +tile.ice.name=Ice +tile.ice.desc= +tile.cactus.name=Cactus +tile.cactus.desc= +tile.clay.name=Clay +tile.clay.desc= +tile.reeds.name=Sugar cane +tile.reeds.desc= +tile.jukebox.name=Jukebox +tile.jukebox.desc= +tile.fence.name=Fence +tile.fence.desc= +tile.pumpkin.name=Pumpkin +tile.pumpkin.desc= +tile.litpumpkin.name=Jack 'o' Lantern +tile.litpumpkin.desc= +tile.hellrock.name=Netherrack +tile.hellrock.desc= +tile.hellsand.name=Soul Sand +tile.hellsand.desc= +tile.lightgem.name=Glowstone +tile.lightgem.desc= +tile.portal.name=Portal +tile.portal.desc= +tile.cloth.black.name=Black Wool +tile.cloth.black.desc= +tile.cloth.red.name=Red Wool +tile.cloth.red.desc= +tile.cloth.green.name=Green Wool +tile.cloth.green.desc= +tile.cloth.brown.name=Brown Wool +tile.cloth.brown.desc= +tile.cloth.blue.name=Blue Wool +tile.cloth.blue.desc= +tile.cloth.purple.name=Purple Wool +tile.cloth.purple.desc= +tile.cloth.cyan.name=Cyan Wool +tile.cloth.cyan.desc= +tile.cloth.silver.name=Light Gray Wool +tile.cloth.silver.desc= +tile.cloth.gray.name=Gray Wool +tile.cloth.gray.desc= +tile.cloth.pink.name=Pink Wool +tile.cloth.pink.desc= +tile.cloth.lime.name=Lime Wool +tile.cloth.lime.desc= +tile.cloth.yellow.name=Yellow Wool +tile.cloth.yellow.desc= +tile.cloth.lightBlue.name=Light Blue Wool +tile.cloth.lightBlue.desc= +tile.cloth.magenta.name=Magenta Wool +tile.cloth.magenta.desc= +tile.cloth.orange.name=Orange Wool +tile.cloth.orange.desc= +tile.cloth.white.name=Wool +tile.cloth.white.desc= +tile.oreLapis.name=Lapis Lazuli Ore +tile.oreLapis.desc= +tile.blockLapis.name=Lapis Lazuli Block +tile.blockLapis.desc= +tile.dispenser.name=Dispenser +tile.dispenser.desc= +tile.musicBlock.name=Note Block +tile.musicBlock.desc= +tile.cake.name=Cake +tile.cake.desc= +tile.bed.name=Bed +tile.bed.desc= +tile.bed.occupied=This bed is occupied +tile.bed.noSleep=You can only sleep at night +tile.bed.notValid=Your home bed was missing or obstructed +tile.lockedchest.name=Locked chest +tile.lockedchest.desc= +tile.trapdoor.name=Trapdoor +tile.trapdoor.desc= +tile.web.name=Cobweb +tile.web.desc= +tile.stonebricksmooth.name=Stone Bricks +tile.stonebricksmooth.desc= +tile.pistonBase.name=Piston +tile.pistonBase.desc= +tile.pistonStickyBase.name=Sticky Piston +tile.pistonStickyBase.desc= + +item.shovelIron.name=Iron Shovel +item.shovelIron.desc= +item.pickaxeIron.name=Iron Pickaxe +item.pickaxeIron.desc= +item.hatchetIron.name=Iron Axe +item.hatchetIron.desc= +item.flintAndSteel.name=Flint and Steel +item.flintAndSteel.desc= +item.apple.name=Apple +item.apple.desc= +item.cookie.name=Cookie +item.cookie.desc= +item.bow.name=Bow +item.bow.desc= +item.arrow.name=Arrow +item.arrow.desc= +item.coal.name=Coal +item.coal.desc= +item.charcoal.name=Charcoal +item.charcoal.desc= +item.emerald.name=Diamond +item.emerald.desc= +item.ingotIron.name=Iron Ingot +item.ingotIron.desc= +item.ingotGold.name=Gold Ingot +item.ingotGold.desc= +item.swordIron.name=Iron Sword +item.swordIron.desc= +item.swordWood.name=Wooden Sword +item.swordWood.desc= +item.shovelWood.name=Wooden Shovel +item.shovelWood.desc= +item.pickaxeWood.name=Wooden Pickaxe +item.pickaxeWood.desc= +item.hatchetWood.name=Wooden Axe +item.hatchetWood.desc= +item.swordStone.name=Stone Sword +item.swordStone.desc= +item.shovelStone.name=Stone Shovel +item.shovelStone.desc= +item.pickaxeStone.name=Stone Pickaxe +item.pickaxeStone.desc= +item.hatchetStone.name=Stone Axe +item.hatchetStone.desc= +item.swordDiamond.name=Diamond Sword +item.swordDiamond.desc= +item.shovelDiamond.name=Diamond Shovel +item.shovelDiamond.desc= +item.pickaxeDiamond.name=Diamond Pickaxe +item.pickaxeDiamond.desc= +item.hatchetDiamond.name=Diamond Axe +item.hatchetDiamond.desc= +item.stick.name=Stick +item.stick.desc= +item.bowl.name=Bowl +item.bowl.desc= +item.mushroomStew.name=Mushroom Stew +item.mushroomStew.desc= +item.swordGold.name=Golden Sword +item.swordGold.desc= +item.shovelGold.name=Golden Shovel +item.shovelGold.desc= +item.pickaxeGold.name=Golden Pickaxe +item.pickaxeGold.desc= +item.hatchetGold.name=Golden Axe +item.hatchetGold.desc= +item.string.name=String +item.string.desc= +item.feather.name=Feather +item.feather.desc= +item.sulphur.name=Gunpowder +item.sulphur.desc= +item.hoeWood.name=Wooden Hoe +item.hoeWood.desc= +item.hoeStone.name=Stone Hoe +item.hoeStone.desc= +item.hoeIron.name=Iron Hoe +item.hoeIron.desc= +item.hoeDiamond.name=Diamond Hoe +item.hoeDiamond.desc= +item.hoeGold.name=Golden Hoe +item.hoeGold.desc= +item.seeds.name=Seeds +item.seeds.desc= +item.wheat.name=Wheat +item.wheat.desc= +item.bread.name=Bread +item.bread.desc= +item.helmetCloth.name=Leather Cap +item.helmetCloth.desc= +item.chestplateCloth.name=Leather Tunic +item.chestplateCloth.desc= +item.leggingsCloth.name=Leather Pants +item.leggingsCloth.desc= +item.bootsCloth.name=Leather Boots +item.bootsCloth.desc= +item.helmetChain.name=Chain Helmet +item.helmetChain.desc= +item.chestplateChain.name=Chain Chestplate +item.chestplateChain.desc= +item.leggingsChain.name=Chain Leggings +item.leggingsChain.desc= +item.bootsChain.name=Chain Boots +item.bootsChain.desc= +item.helmetIron.name=Iron Helmet +item.helmetIron.desc= +item.chestplateIron.name=Iron Chestplate +item.chestplateIron.desc= +item.leggingsIron.name=Iron Leggings +item.leggingsIron.desc= +item.bootsIron.name=Iron Boots +item.bootsIron.desc= +item.helmetDiamond.name=Diamond Helmet +item.helmetDiamond.desc= +item.chestplateDiamond.name=Diamond Chestplate +item.chestplateDiamond.desc= +item.leggingsDiamond.name=Diamond Leggings +item.leggingsDiamond.desc= +item.bootsDiamond.name=Diamond Boots +item.bootsDiamond.desc= +item.helmetGold.name=Golden Helmet +item.helmetGold.desc= +item.chestplateGold.name=Golden Chestplate +item.chestplateGold.desc= +item.leggingsGold.name=Golden Leggings +item.leggingsGold.desc= +item.bootsGold.name=Golden boots +item.bootsGold.desc= +item.flint.name=Flint +item.flint.desc= +item.porkchopRaw.name=Raw Porkchop +item.porkchopRaw.desc= +item.porkchopCooked.name=Cooked Porkchop +item.porkchopCooked.desc= +item.painting.name=Painting +item.painting.desc= +item.appleGold.name=Golden Apple +item.appleGold.desc= +item.sign.name=Sign +item.sign.desc= +item.doorWood.name=Wooden Door +item.doorWood.desc= +item.bucket.name=Bucket +item.bucket.desc= +item.bucketWater.name=Water Bucket +item.bucketWater.desc= +item.bucketLava.name=Lava bucket +item.bucketLava.desc= +item.minecart.name=Minecart +item.minecart.desc= +item.saddle.name=Saddle +item.saddle.desc= +item.doorIron.name=Iron Door +item.doorIron.desc= +item.redstone.name=Redstone +item.redstone.desc= +item.snowball.name=Snowball +item.snowball.desc= +item.boat.name=Boat +item.boat.desc= +item.leather.name=Leather +item.leather.desc= +item.milk.name=Milk +item.milk.desc= +item.brick.name=Brick +item.brick.desc= +item.clay.name=Clay +item.clay.desc= +item.reeds.name=Sugar Canes +item.reeds.desc= +item.paper.name=Paper +item.paper.desc= +item.book.name=Book +item.book.desc= +item.slimeball.name=Slimeball +item.slimeball.desc= +item.minecartChest.name=Minecart with Chest +item.minecartChest.desc= +item.minecartFurnace.name=Minecart with Furnace +item.minecartFurnace.desc= +item.egg.name=Egg +item.egg.desc= +item.compass.name=Compass +item.compass.desc= +item.fishingRod.name=Fishing Rod +item.fishingRod.desc= +item.clock.name=Clock +item.clock.desc= +item.yellowDust.name=Glowstone Dust +item.yellowDust.desc= +item.fishRaw.name=Raw Fish +item.fishRaw.desc= +item.fishCooked.name=Cooked Fish +item.fishCooked.desc= +item.record.name=Music Disc +item.record.desc= +item.bone.name=Bone +item.bone.desc= +item.dyePowder.black.name=Ink Sac +item.dyePowder.black.desc= +item.dyePowder.red.name=Rose Red +item.dyePowder.red.desc= +item.dyePowder.green.name=Cactus Green +item.dyePowder.green.desc= +item.dyePowder.brown.name=Cocoa Beans +item.dyePowder.brown.desc= +item.dyePowder.blue.name=Lapis Lazuli +item.dyePowder.blue.desc= +item.dyePowder.purple.name=Purple Dye +item.dyePowder.purple.desc= +item.dyePowder.cyan.name=Cyan Dye +item.dyePowder.cyan.desc= +item.dyePowder.silver.name=Light Gray Dye +item.dyePowder.silver.desc= +item.dyePowder.gray.name=Gray Dye +item.dyePowder.gray.desc= +item.dyePowder.pink.name=Pink Dye +item.dyePowder.pink.desc= +item.dyePowder.lime.name=Lime Dye +item.dyePowder.lime.desc= +item.dyePowder.yellow.name=Dandelion Yellow +item.dyePowder.yellow.desc= +item.dyePowder.lightBlue.name=Light Blue Dye +item.dyePowder.lightBlue.desc= +item.dyePowder.magenta.name=Magenta Dye +item.dyePowder.magenta.desc= +item.dyePowder.orange.name=Orange Dye +item.dyePowder.orange.desc= +item.dyePowder.white.name=Bone Meal +item.dyePowder.white.desc= +item.sugar.name=Sugar +item.sugar.desc= +item.cake.name=Cake +item.cake.desc= +item.bed.name=Bed +item.bed.desc= +item.diode.name=Redstone Repeater +item.diode.desc= +item.map.name=Map +item.map.desc= +item.leaves.name=Leaves +item.leaves.desc= +item.shears.name=Shears +item.shears.desc= diff --git a/src/main/resources/lang/stats_US.lang b/src/main/resources/lang/stats_US.lang new file mode 100644 index 0000000..caba23a --- /dev/null +++ b/src/main/resources/lang/stats_US.lang @@ -0,0 +1,81 @@ +gui.achievements=Achievements +gui.stats=Statistics + +stat.generalButton=General +stat.blocksButton=Blocks +stat.itemsButton=Items + +stat.used=Times Used +stat.mined=Times Mined +stat.depleted=Times Depleted +stat.crafted=Times Crafted + +stat.startGame=Times played +stat.createWorld=Worlds played +stat.loadWorld=Saves loaded +stat.joinMultiplayer=Multiplayer joins +stat.leaveGame=Games quit + +stat.playOneMinute=Minutes Played + +stat.walkOneCm=Distance Walked +stat.fallOneCm=Distance Fallen +stat.swimOneCm=Distance Swum +stat.flyOneCm=Distance Flown +stat.climbOneCm=Distance Climbed +stat.diveOneCm=Distance Dove +stat.minecartOneCm=Distance by Minecart +stat.boatOneCm=Distance by Boat +stat.pigOneCm=Distance by Pig +stat.jump=Jumps +stat.drop=Items Dropped + +stat.damageDealt=Damage Dealt +stat.damageTaken=Damage Taken +stat.deaths=Number of Deaths +stat.mobKills=Mob Kills +stat.playerKills=Player Kills +stat.fishCaught=Fish Caught + +stat.mineBlock=%1$s Mined +stat.craftItem=%1$s Crafted +stat.useItem=%1$s Used +stat.breakItem=%1$s Depleted + +achievement.get=Achievement get! + +achievement.taken=Taken! + +achievement.requires=Requires '%1$s' +achievement.openInventory=Taking Inventory +achievement.openInventory.desc=Press '%1$s' to open your inventory. +achievement.mineWood=Getting Wood +achievement.mineWood.desc=Attack a tree until a block of wood pops out +achievement.buildWorkBench=Benchmarking +achievement.buildWorkBench.desc=Craft a workbench with four blocks of planks +achievement.buildPickaxe=Time to Mine! +achievement.buildPickaxe.desc=Use planks and sticks to make a pickaxe +achievement.buildFurnace=Hot Topic +achievement.buildFurnace.desc=Construct a furnace out of eight stone blocks +achievement.acquireIron=Acquire Hardware +achievement.acquireIron.desc=Smelt an iron ingot +achievement.buildHoe=Time to Farm! +achievement.buildHoe.desc=Use planks and sticks to make a hoe +achievement.makeBread=Bake Bread +achievement.makeBread.desc=Turn wheat into bread +achievement.bakeCake=The Lie +achievement.bakeCake.desc=Wheat, sugar, milk and eggs! +achievement.buildBetterPickaxe=Getting an Upgrade +achievement.buildBetterPickaxe.desc=Construct a better pickaxe +achievement.cookFish=Delicious Fish +achievement.cookFish.desc=Catch and cook fish! +achievement.onARail=On A Rail +achievement.onARail.desc=Travel by minecart at least 1 km from where you started +achievement.buildSword=Time to Strike! +achievement.buildSword.desc=Use planks and sticks to make a sword +achievement.killEnemy=Monster Hunter +achievement.killEnemy.desc=Attack and destroy a monster +achievement.killCow=Cow Tipper +achievement.killCow.desc=Harvest some leather +achievement.flyPig=When Pigs Fly +achievement.flyPig.desc=Fly a pig off a cliff diff --git a/version.json b/version.json new file mode 100644 index 0000000..38b0de5 --- /dev/null +++ b/version.json @@ -0,0 +1,3 @@ +{ + "newestVersion": "1.1.8" +}