Initial commit
build-and-test / build (push) Waiting to run
Java-Compatibility / build (17) (push) Waiting to run
Java-Compatibility / build (21) (push) Waiting to run
Release Workflow / build-and-release (push) Waiting to run

This commit is contained in:
2026-09-20 01:56:07 +01:00
commit 82192a4802
943 changed files with 92762 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
# 📌 Pull Request
## Description
<!--
Provide a clear and concise summary of what this PR does.
Explain *why* the change is needed and what problem it solves.
-->
## Related Issues / Discussions
<!--
Link any related issues, PRs, or discussions.
Use "Fixes #123" to automatically close issues when merged.
-->
- Fixes #
- Related to #
## Motivation & Context
<!--
Why is this change important for Project Poseidon?
Does it fix a bug, improve stability, add a feature, or improve compatibility?
-->
## 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
<!--
Describe how this change was tested.
Include environments, steps, and results.
-->
- [ ] 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)
<!-- Paste relevant log output, stack traces, or attach screenshots to help reviewers understand the change. -->
```(Optional)```
## Compatibility Considerations
<!-- Does this change affect: Plugins? Network behavior? UUID / inventory handling? Other? -->
- [ ] No known compatibility impact
- [ ] Potential plugin impact (described below)
- [ ] Network / protocol (Netcode) behavior changed
- [ ] Configuration change required
## Compatibility Notes
<!-- Describe any known compatibility risks or required changes if applicable. -->
## 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
<!-- Anything else reviewers should know? Design decisions, limitations, future follow-ups, etc. -->
## Thanks for contributing to Project Poseidon!
+101
View File
@@ -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
+39
View File
@@ -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
+112
View File
@@ -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'
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>johnymuffin-nexus</id>
<username>${env.NEXUS_USERNAME}</username>
<password>${env.NEXUS_PASSWORD}</password>
</server>
</servers>
</settings>
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 }}
+237
View File
@@ -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
+674
View File
@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 <http://www.gnu.org/licenses/>.
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:
<program> Copyright (C) <year> <name of author>
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
<http://www.gnu.org/licenses/>.
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
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+111
View File
@@ -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.<br>**
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.<br>
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<br>
Any future commits to this repository will remain under the same GNU General Public License v3.0<br>
Libraries in the compiled .jar files distrusted may contain their own licenses.<br>
This project contains decompiled code that is copyrighted by Mojang AB typically under the `net.minecraft.server` package.<br>
## 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
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

+253
View File
@@ -0,0 +1,253 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.legacyminecraft.poseidon</groupId>
<artifactId>poseidon-craftbukkit</artifactId>
<version>1.1.12</version>
<packaging>jar</packaging>
<name>Project Poseidon</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<api.version>unknown</api.version>
</properties>
<scm>
<connection>scm:git:git://github.com/Bukkit/CraftBukkit.git</connection>
<developerConnection>scm:git:ssh://git@github.com/Bukkit/CraftBukkit.git</developerConnection>
<url>https://github.com/Bukkit/CraftBukkit</url>
</scm>
<repositories>
<repository>
<id>bukkit-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
<!-- <repository>-->
<!-- <id>chew-jenkins</id>-->
<!-- <url>https://jenkins.chew.pw/plugin/repository/everything</url>-->
<!-- </repository>-->
<repository>
<id>jline</id>
<name>JLine Project Repository</name>
<url>http://jline.sourceforge.net/m2repo</url>
</repository>
<!-- Repository for resolving release dependencies -->
<repository>
<id>johnymuffin-nexus-releases</id>
<url>https://repository.johnymuffin.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<!-- Repository for resolving snapshot dependencies -->
<repository>
<id>johnymuffin-nexus-snapshots</id>
<url>https://repository.johnymuffin.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>johnymuffin-nexus</id>
<url>https://repository.johnymuffin.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>johnymuffin-nexus</id>
<url>https://repository.johnymuffin.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>org.bukkit</groupId>-->
<!-- <artifactId>bukkit</artifactId>-->
<!-- <version>0.0.1-SNAPSHOT</version>-->
<!-- <type>jar</type>-->
<!-- <scope>compile</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>0.0.1-POSEIDON</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>jopt-simple</artifactId>
<version>6.0-alpha-3</version>
</dependency>
<dependency>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
<version>0.9.93</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.7.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.14</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>modloader</groupId>
<artifactId>ModLoaderMP-B1.7.3</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/ModLoaderMP.jar</systemPath>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>ebean</artifactId>
<version>2.7.3</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-collections</artifactId>
<version>r03</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>20.0.0</version>
</dependency>
<!-- Bukkit Mods -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.0.0-jre</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<!-- This builds a completely 'ready to start' jar with all dependencies inside -->
<build>
<defaultGoal>clean install</defaultGoal>
<!-- <sourceDirectory>src</sourceDirectory>-->
<!-- <resources>-->
<!-- <resource>-->
<!-- <directory>src</directory>-->
<!-- <excludes>-->
<!-- <exclude>**/*.java</exclude>-->
<!-- </excludes>-->
<!-- </resource>-->
<!-- </resources>-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifestEntries>
<Main-Class>org.bukkit.craftbukkit.Main</Main-Class>
<Implementation-Title>Project-Posiden</Implementation-Title>
<Implementation-Vendor>RhysB</Implementation-Vendor>
<Specification-Title>Bukkit</Specification-Title>
<Specification-Version>${api.version}</Specification-Version>
<Specification-Vendor>Bukkit Team</Specification-Vendor>
<Sealed>true</Sealed>
</manifestEntries>
<manifestSections>
<manifestSection>
<name>net/bukkit/</name>
<manifestEntries>
<Sealed>true</Sealed>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>com/bukkit/</name>
<manifestEntries>
<Sealed>true</Sealed>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>org/bukkit/</name>
<manifestEntries>
<Sealed>true</Sealed>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>junit:junit</exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
+19
View File
@@ -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
+446
View File
@@ -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
+10
View File
@@ -0,0 +1,10 @@
# This file NEEDS to be in UTF-8 format!
!"#$%&'()*+,-./
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\]^_
'abcdefghijklmno
pqrstuvwxyz{|}~⌂
ÇüéâäàåçêëèïîìÄÅ
ÉæÆôöòûùÿÖÜø£Ø×ƒ
áíóúñѪº¿®¬½¼¡«»
+579
View File
@@ -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=
+81
View File
@@ -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
View File
@@ -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<Pattern> fileFilters;
private final File updateDirectory;
public PluginLoadPlanner(Server server, Set<Pattern> 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<PlannedPlugin> 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<String, PluginCandidate> 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<PlannedPlugin> plan = new ArrayList<>();
// Create a deterministic load order
Set<String> loadedNames = new LinkedHashSet<>();
LinkedHashSet<PluginCandidate> 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<PluginCandidate> 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<String, PluginCandidate> candidates) {
return !candidate.getMissingHardDependencies(candidates).isEmpty();
}
private boolean dependenciesLoaded(Collection<String> dependencies, Set<String> 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<String> hardDependencies;
private final List<String> 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<String> getHardDependencies() {
return hardDependencies;
}
private List<String> getMissingHardDependencies(Map<String, PluginCandidate> candidates) {
List<String> missing = new ArrayList<>();
for (String dependency : hardDependencies) {
if (!candidates.containsKey(dependency)) {
missing.add(dependency);
}
}
return missing;
}
private List<String> getPresentSoftDependencies(Map<String, PluginCandidate> candidates) {
List<String> present = new ArrayList<>();
for (String dependency : softDependencies) {
if (candidates.containsKey(dependency)) {
present.add(dependency);
}
}
return present;
}
private boolean hasMissingSoftDependencies(Map<String, PluginCandidate> 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<String> copyDependencies(Object dependencies) {
if (dependencies == null) {
return Collections.emptyList();
}
return new ArrayList<>((Collection<String>) dependencies);
}
}
}
@@ -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<Double> of TPS records.
*/
public static LinkedList<Double> 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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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<String> hiddenCommands = new ArrayList<>();
private final Properties versionProperties = new Properties();
private boolean serverInitialized = false;
private PoseidonVersionChecker poseidonVersionChecker;
private WatchDogThread watchDogThread;
private Map<String, PerformanceStatistic> listenerPerformance = new HashMap<String, PerformanceStatistic>();
private Map<String, PerformanceStatistic> taskPerformance = new HashMap<String, PerformanceStatistic>();
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<String> commands) {
for (String cmd : commands) {
addHiddenCommand(cmd);
}
}
public Map<String, PerformanceStatistic> getListenerPerformance() {
return listenerPerformance;
}
public Map<String, PerformanceStatistic> getTaskPerformance() {
return taskPerformance;
}
// Generic method to sort any performance map
public Map<String, PerformanceStatistic> getSortedPerformance(Map<String, PerformanceStatistic> unsortedMap) {
return unsortedMap.entrySet()
.stream()
.sorted(Map.Entry.<String, PerformanceStatistic>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<String, PerformanceStatistic> getSortedListenerPerformance() {
return getSortedPerformance(getListenerPerformance());
}
// Specific method to get sorted task performance
public Map<String, PerformanceStatistic> getSortedTaskPerformance() {
return getSortedPerformance(getTaskPerformance());
}
public PoseidonConfig getConfig() {
return config;
}
}
@@ -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;
}
}
}
}
}
}
@@ -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;
}
}
@@ -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 <command>";
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 <command>");
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<String, Command> knownCommands = (Map<String, Command>) knownCommandsField.get(commandMap);
for (Map.Entry<String, Command> 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;
}
}
@@ -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<String, Integer> 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<Double> tpsRecords = Poseidon.getTpsRecords();
StringBuilder message = new StringBuilder("§bServer TPS: ");
// Calculate and format TPS for each interval dynamically
for (Map.Entry<String, Integer> 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<Double> 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);
}
}
@@ -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<ItemStack> 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;
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -0,0 +1,6 @@
package com.legacyminecraft.poseidon.event;
import org.bukkit.event.Listener;
public interface PoseidonCustomListener extends Listener {
}
@@ -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;
}
}
@@ -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();
}
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
}
@@ -0,0 +1,6 @@
package com.legacyminecraft.poseidon.util;
public interface SessionRequestRunnable
{
public void callback(int responseCode, String username, String uuid, String ip);
}
@@ -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<Map<String, UUID>> {
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<String> names;
private final boolean rateLimiting;
public UUIDFetcher(List<String> names, boolean rateLimiting) {
this.names = ImmutableList.copyOf(names);
this.rateLimiting = rateLimiting;
}
public UUIDFetcher(List<String> names) {
this(names, true);
}
public Map<String, UUID> call() throws Exception {
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
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);
}
}
@@ -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
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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");
}
}
}
@@ -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();
}
}
@@ -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,
}
+2
View File
@@ -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
@@ -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);
}
}
@@ -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
}
@@ -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;
}
}
@@ -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<ConnectionPause> connectionPauses = new HashSet<ConnectionPause>();
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<ConnectionPause> 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;
}
}
@@ -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<String, List<UUIDEntry>> usernameCache = new ConcurrentHashMap<>();
private final Map<UUID, List<UUIDEntry>> uuidCache = new ConcurrentHashMap<>();
private List<UUIDEntry> 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<List<UUIDEntry>>() {}.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<UUIDEntry> userEntries = usernameCache.get(entry.name.toLowerCase());
if (userEntries != null) userEntries.remove(entry);
List<UUIDEntry> 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<UUIDEntry> 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<UUIDEntry> 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<UUIDEntry> 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<UUIDEntry> 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<UUIDEntry> 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<UUIDEntry> 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<UUIDEntry> 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;
}
}
}
@@ -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;
}
}
@@ -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");
}
}
@@ -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));
}
}
@@ -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 + "]";
}
}
@@ -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() {}
}
@@ -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();
}
}
@@ -0,0 +1,6 @@
package net.minecraft.server;
public class BiomeDesert extends BiomeBase {
public BiomeDesert() {}
}
@@ -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()));
}
}
@@ -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));
}
}
@@ -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;
}
}
@@ -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());
}
}
@@ -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));
}
}
@@ -0,0 +1,6 @@
package net.minecraft.server;
public class BiomeSwamp extends BiomeBase {
public BiomeSwamp() {}
}
@@ -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());
}
}
@@ -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<Integer> 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();
}
}
@@ -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;
}
}
@@ -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
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
}
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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_();
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -0,0 +1,8 @@
package net.minecraft.server;
public class BlockDirt extends Block {
protected BlockDirt(int i, int j) {
super(i, j, Material.EARTH);
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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());
}
}
}
}
@@ -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;
}
}
@@ -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());
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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;
}
}

Some files were not shown because too many files have changed in this diff Show More