yikeesss ❤️

This commit is contained in:
disclearing 2019-08-17 20:38:37 +01:00
parent f101cc9a38
commit c48a7120e7
1531 changed files with 195346 additions and 1 deletions

View File

@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: org.json:json:20171018">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/json/json/20171018/json-20171018.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/json/json/20171018/json-20171018-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/json/json/20171018/json-20171018-sources.jar!/" />
</SOURCES>
</library>
</component>

31
PaperSpigot-API/.gitignore vendored Normal file
View File

@ -0,0 +1,31 @@
# Eclipse stuff
/.classpath
/.project
/.settings
# netbeans
/nbproject
# we use maven!
/build.xml
# maven
/target
# vim
.*.sw[a-p]
# various other potential build files
/build
/bin
/dist
/manifest.mf
# Mac filesystem dust
.DS_Store
# intellij
*.iml
*.ipr
*.iws
.idea/

View File

@ -0,0 +1,497 @@
# How to Contribute
The Bukkit project prides itself on being community built and driven. We love it when members of our community want to jump right in and get involved, so here's what you need to know.
## Quick Guide
1. Create or find an issue to address on our [JIRA issue tracker](http://leaky.bukkit.org).
- Does your proposed change [fit Bukkit's goals](#does-the-change-fit-bukkits-goals)?
- Fork the repository if you haven't done so already.
- Make your changes in a new branch (if your change affects both Bukkit and CraftBukkit, we highly suggest you use the same name for your branches in both repos).
- Test your changes.
- Push to your fork and submit a pull request.
- **Note:** The project is put under a code freeze leading up to the release of a Minecraft update in order to give the Bukkit team a static code base to work on.
![Life Cycle of a Bukkit Improvement](http://i.imgur.com/Ed6T7AE.png)
## Getting Started
- You'll need a free [JIRA account](http://leaky.bukkit.org) (on our issue tracker affectionately called Leaky).
- You'll need a free [GitHub account](https://github.com/signup/free).
- Make sure you have a JIRA ticket for your issue at hand.
* Either search the list of current issues and find an appropriate issue.
* Or create one yourself if one does not already exist.
* When creating an issue, make sure to clearly describe the issue (including steps to reproduce it if it is a bug).
- Fork the repository on GitHub.
- **Note:** The project is put under a code freeze leading up to the release of a Minecraft update in order to give the Bukkit team a static code base to work on.
## Does the Change Fit Bukkit's Goals?
As a rough guideline, ask yourself the following questions to determine if your proposed change fits the Bukkit project's goals. Please remember that this is only a rough guideline and may or may not reflect the definitive answer to this question.
* Does it expose an implementation detail of the server software, the protocol or file formats?
If your change revolves around an implementation detail then it is not proper API design. Examples of bad API design would be along the lines of a packet API, an NBT storage API, or basing an enum on implementation values.
* Does it result in unexpected behaviour as defined by the Vanilla specification?
One of the goals of the Bukkit project is to be an extended Minecraft vanilla server - meaning: if you choose to run the Bukkit server without any plugins, it should function exactly as the Minecraft server would with some rare exceptions. If your change alters the behaviour of the server in such a way that you would not have the same experience as you would in Vanilla, your change does not fit the Bukkit project's goals.
* Does it expose an issue or vulnerability when operating within the Vanilla environment?
One of the goals of the Bukkit project is to be able to operate within the limitations of the Vanilla environment. If your change results in or exposes the ability to, for example, crash the client when invalid data is set, it does not fit the Bukkit project's needs.
If you answered yes to any of these questions, chances are high your change does not fit the Bukkit project's goals and will most likely not be accepted. Regardless, there are a few other important questions you need to ask yourself before you start working on a change:
* Is this change reasonably supportable and maintainable?
* Is this change future proof?
## Making the Changes
* Create a branch on your fork where you'll be making your changes.
* Name your branch something relevant to the change you are looking to make.
* Note: if your changes affect both Bukkit and CraftBukkit, it is highly suggested you use the same branch name on both repos.
* To create a branch in Git;
* `git branch relevantBranchName`
* Then checkout the new branch with `git checkout relevantBranchName`
* Check for unnecessary whitespace with `git diff --check` before committing.
* Make sure your code meets [our requirements](#code-requirements).
* If the work you want to do involves editing Minecraft classes, be sure to read over the [Using Minecraft Internals](#using-minecraft-internals) section.
* Make sure your commit messages are in the [proper format](#commit-message-example).
* Test your changes to make sure it actually addresses the issue it should.
* Make sure your code compiles under Java 6, as that is what the project has to be built with.
### Code Requirements
* We generally follow the [Sun/Oracle coding standards](http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html).
* No tabs; use 4 spaces instead.
* No trailing whitespaces.
* No CRLF line endings, LF only, set your Gits 'core.autocrlf' to 'true'.
These whitespace requirements are easily and often overlooked. They are critical formatting requirements designed to help simplify a shared heterogeneous development environment. Learn how your IDE functions in order to show you these characters and verify them. Analyse the git diff closely to verify every character and if the PR should include the character change. It is tedious and it is critical.
Eclipse: http://stackoverflow.com/a/11596227/532590
NetBeans: http://stackoverflow.com/a/1866385/532590
* No 80 column limit or 'weird' midstatement newlines.
* Any major additions should have documentation ready and provided if applicable (this is usually the case).
* Try to follow test driven development where applicable.
Bukkit employs JUnit (http://www.vogella.com/articles/JUnit/article.html) for testing and PRs should attempt to integrate with that framework as appropriate. Bukkit is a large project and what seems simple to a PR author at the time of writing a PR may easily be overlooked later by other authors and updates. Including unit tests with your PR will help to ensure the PR can be easily maintained over time and encourage the Bukkit Team to pull the PR.
* There needs to be a new line at the end of every file.
* Imports should be organised by alphabetical order, separated and grouped by package.
**For example:**
```java
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.Callable;
// CraftBukkit start
import java.io.UnsupportedEncodingException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.logging.Level;
import java.util.HashSet;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.util.LazyPlayerSet;
import org.bukkit.craftbukkit.util.Waitable;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerAnimationEvent;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.event.player.PlayerToggleSprintEvent;
import org.bukkit.event.inventory.*;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerToggleFlightEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.InventoryView;
// CraftBukkit end
```
### Using Minecraft Internals
#### Importing a New Minecraft Class
When contributing to the Bukkit project, you will likely find that you need to edit a Minecraft class that isn't already found within the project. In this case, you need to look at [our mc-dev repository](https://github.com/Bukkit/mc-dev), find the class you need, add it to the CraftBukkit repo and include it in its own special commit separate from your other changes. The commit message of this special commit should simply be "Add x for diff visibility", where x is the name of the file you are adding from mc-dev.
If, however, you need to import multiple files from mc-dev into the Bukkit project, they should all be contained in the same special commit with the commit message "Add files for diff visibility". Note how the commit message no longer specifically mentions any class names.
#### Making Changes to Minecraft Classes
The Bukkit project employs a Minimal Diff policy to help guide when changes should be made to Minecraft classes and what those changes should be. This is to ensure that any changes made have the smallest impact possible on the update process we go through whenever a Minecraft update is released. As well as keeping the Minimal Diff policy in mind, every change made to a Minecraft class needs to be marked as such with the appropriate CraftBukkit comment.
##### Minimal Diff Policy
The Minimal Diff policy is a really important part of the project as it reminds us that every change to the Minecraft Internals has an impact on our update process. When people think of the phrase "minimal diffs", they often take it to the extreme - they go completely out of their way to abstract the changes they are trying to make away from editing Minecraft's classes as much as possible. However, this isn't what we mean by "minimal diffs". Instead, when trying to understand the minimal diffs policy, it helps to keep in mind its end goal: to reduce the impact changes we make to Minecraft's internals have on our update process.
Put simply, the Minimal Diffs Policy simply means to make the smallest change in a Minecraft class possible without duplicating logic.
Here are a few tips you should keep in mind or common areas you should focus on:
* Try to avoid duplicating logic or code when making changes.
* Try to keep your changes easily discernible - don't nest or group several unrelated changes together.
* If you only use an import once within a class, don't import it and use fully qualified names instead.
* Try to employ "short circuiting" of logic if at all possible. This means that you should force a conditional to be the value needed to side-step the code block if you would like to ignore that block of code.
**For example, to short circuit this:**
```java
if (!this.world.isStatic && !this.dead && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) {
this.die();
this.h();
}
```
**You would do this:**
```java
if (false && !this.world.isStatic && !this.dead && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) { // CraftBukkit - not needed
this.die();
this.h();
}
```
* When adding a validation check, see if the Validate package we already use has a better, more concise method you can use instead.
**For example, you should use:**
```java
Validate.notNull(sender, "Sender cannot be null");
```
**Instead of:**
```java
if (sender == null) {
throw new IllegalArgumentException("Sender cannot be null");
}
```
* When the change you are attempting to make involves removing code, instead of removing it outright, you should comment it out.
**For example:**
```java
// CraftBukkit start - special case dropping so we can get info from the tile entity
public void dropNaturally(World world, int i, int j, int k, int l, float f, int i1) {
if (world.random.nextFloat() < f) {
ItemStack itemstack = new ItemStack(Item.SKULL.id, 1, this.getDropData(world, i, j, k));
TileEntitySkull tileentityskull = (TileEntitySkull) world.getTileEntity(i, j, k);
if (tileentityskull.getSkullType() == 3 && tileentityskull.getExtraType() != null && tileentityskull.getExtraType().length() > 0) {
itemstack.setTag(new NBTTagCompound());
itemstack.getTag().setString("SkullOwner", tileentityskull.getExtraType());
}
this.b(world, i, j, k, itemstack);
}
}
// CraftBukkit end
public void a(World world, int i, int j, int k, int l, EntityHuman entityhuman) {
if (entityhuman.abilities.canInstantlyBuild) {
l |= 8;
world.setData(i, j, k, l, 4);
}
super.a(world, i, j, k, l, entityhuman);
}
public void remove(World world, int i, int j, int k, int l, int i1) {
if (!world.isStatic) {
/* CraftBukkit start - drop item in code above, not here
if ((i1 & 8) == 0) {
ItemStack itemstack = new ItemStack(Item.SKULL.id, 1, this.getDropData(world, i, j, k));
TileEntitySkull tileentityskull = (TileEntitySkull) world.getTileEntity(i, j, k);
if (tileentityskull.getSkullType() == 3 && tileentityskull.getExtraType() != null && tileentityskull.getExtraType().length() > 0) {
itemstack.setTag(new NBTTagCompound());
itemstack.getTag().setString("SkullOwner", tileentityskull.getExtraType());
}
this.b(world, i, j, k, itemstack);
}
// CraftBukkit end */
super.remove(world, i, j, k, l, i1);
}
}
```
##### General Guidelines
When editing Minecraft's classes, we have a set of rules and guidelines that need to be followed to keep us sane when it comes time for us to update Bukkit.
**CraftBukkit comments**
Changes to a Minecraft class should be clearly marked using CraftBukkit comments. Here are a few tips to help explain what kind of CraftBukkit comment to use and where to use them:
* Regardless of what kind of CraftBukkit comment you use, please take care to be explicit and exact with your usage. If the "C" in "CraftBukkit" is capitalised in the example, you should capitalise it when you use it. If the "start" begins with a lowercase "s", you should make sure yours does too.
* If the change only affects one line of code, you should use an end of line CraftBukkit comment.
**Examples:**
If the change is obvious when looking at the diff, then you just need a simple end of line CraftBukkit comment.
```java
if (true || minecraftserver.getAllowNether()) { // CraftBukkit
```
If, however, the change is something important to note or difficult to discern, you should include a reason at the end of the end of line CraftBukkit comment.
```java
public int fireTicks; // CraftBukkit - private -> public
```
If adding the CraftBukkit comment to the end of the line negatively affects the readability of the code, then you should place the CraftBukkit comment on a new line above the change you made.
```java
// CraftBukkit
if (!isEffect && !world.isStatic && world.difficulty >= 2 && world.areChunksLoaded(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2), 10)) {
```
* If the change affects more than one line, you should use a multi-line CraftBukkit comment.
**Examples:**
The majority of the time multi-line changes should be accompanied by a reason since they're usually much more complicated than a single line change. We'd like to suggest you follow the same rule as above: if the change is something important to note or difficult to discern, you should include a reason at the end of the end of line CraftBukkit comment, however it is not always clear if this is the case. Looking through the code in the project, you'll see that we sometimes include a reason when we should have left it off and vice versa.
```java
// CraftBukkit start - special case dropping so we can get info from the tile entity
public void dropNaturally(World world, int i, int j, int k, int l, float f, int i1) {
if (world.random.nextFloat() < f) {
ItemStack itemstack = new ItemStack(Item.SKULL.id, 1, this.getDropData(world, i, j, k));
TileEntitySkull tileentityskull = (TileEntitySkull) world.getTileEntity(i, j, k);
if (tileentityskull.getSkullType() == 3 && tileentityskull.getExtraType() != null && tileentityskull.getExtraType().length() > 0) {
itemstack.setTag(new NBTTagCompound());
itemstack.getTag().setString("SkullOwner", tileentityskull.getExtraType());
}
this.b(world, i, j, k, itemstack);
}
}
// CraftBukkit end
````
Otherwise, just use a multi-line CraftBukkit comment without a reason.
```java
// CraftBukkit start
BlockIgniteEvent event = new BlockIgniteEvent(this.cworld.getBlockAt(i, j, k), BlockIgniteEvent.IgniteCause.LIGHTNING, null);
world.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
world.setTypeIdUpdate(i, j, k, Block.FIRE.id);
}
// CraftBukkit end
```
* CraftBukkit comments should be on the same indentation level of the code block it is in.
**For example:**
```java
if (j == 1) {
// CraftBukkit start - store a reference
ItemStack itemstack4 = playerinventory.getCarried();
if (itemstack4.count > 0) {
entityhuman.drop(itemstack4.a(1));
}
if (itemstack4.count == 0) {
// CraftBukkit end
playerinventory.setCarried((ItemStack) null);
}
}
```
**Other guidelines**
* When adding imports to a Minecraft class, they should be organised by alphabetical order, separated and grouped by package.
**For example:**
```java
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.Callable;
// CraftBukkit start
import java.io.UnsupportedEncodingException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.logging.Level;
import java.util.HashSet;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.util.LazyPlayerSet;
import org.bukkit.craftbukkit.util.Waitable;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerAnimationEvent;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.event.player.PlayerToggleSprintEvent;
import org.bukkit.event.inventory.*;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerToggleFlightEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.InventoryView;
// CraftBukkit end
```
* Do not remove unused imports if they are not marked by CraftBukkit comments.
### Commit Message Example
> Provide an example commit for CONTRIBUTING.md. Fixes BUKKIT-1
>
> The CONTRIBUTING.md is missing an example commit message. Without this
> commit, we are unable to provide potential contributors with a helpful example,
> forcing developers to guess at what an acceptable commit message would look
> like. This commit fixes this issue by providing a clear and informative example
> for contributors to base their work off of.
### Commit Message Expectations
The first line in a commit message is an imperative statement briefly explaining what the commit is achieving with an associated ticket number from our JIRA, in the form of BUKKIT-#. See the list of acceptable keywords to reference tickets with for more information on this.
The body of the commit message needs to describe how the code behaves without this change, why this is a problem and how this commit addresses it. The body of the commit message should be restricted by a 78 character, plus newline, limit per line (meaning: once you hit about 78 characters, you should explicitly start a new line in the commit message).
Acceptable keywords to reference tickets with:
* **Fixes** BUKKIT-1 - this commit fixes the bug detailed in BUKKIT-1
* **Adds** BUKKIT-2 - this commit adds the new feature requested by BUKKIT-2
You can reference multiple tickets in a single commit message, for example: "Fixes BUKKIT-1, BUKKIT-2" or "Adds BUKKIT-1, BUKKIT-2" without closing punctuation.
## Submitting the Changes
* Push your changes to a topic branch in your fork of the repository.
* Submit a pull request to the relevant repository in the Bukkit organization.
* Make sure your pull request meets [our expectations](#pull-request-formatting-expectations) before submitting.
* No merges should be included in any pull requests.
* Update your JIRA ticket to reflect that you have submitted a pull request and are ready for it to be reviewed.
* Include a link to the pull request in the ticket.
* Follow our [Tips to Get Your Pull Request Accepted](#tips-to-get-your-pull-request-accepted).
* **Note:** The project is put under a code freeze leading up to the release of a Minecraft update in order to give the Bukkit team a static code base to work on.
### Pull Request Formatting Expectations
#### Title
> [PR Type] Brief summary. Fixes BUKKIT-####
> PR Type can be B for Bukkit, C for CraftBukkit, B+C for a PR in both sides
>
> Title Example:
> [B+C] Provide an example commit for CONTRIBUTING.md. Fixes BUKKIT-1
#### Description:
> ##### The Issue:
> Paragraphs explaining what the issue the PR is meant to be addressing.
>
> ##### Justification for this PR:
> Paragraphs providing justification for the PR
>
> ##### PR Breakdown:
> Paragraphs breaking down what the PR is doing, in detail.
>
> ##### Testing Results and Materials:
> Paragraphs describing what you did to test the code in this PR and links to pre-compiled test binaries and source.
>
> ##### Relevant PR(s):
> This should be links to accompanying PRs, or alternate PRs that attempted to perform the task. Each reference should have a reason attached as to why it is being referenced (for example: "Similar to PR ### but won't empty your Bukkits"). Accompanying PRs need no explanation, but still need to be linked.
>
> B-#### - https://github.com/Bukkit/Bukkit/pull/#### - Reason
> CB-#### - https://github.com/Bukkit/CraftBukkit/pull/#### - Reason
>
> ##### JIRA Ticket:
> BUKKIT-#### - https://bukkit.atlassian.net/browse/BUKKIT-####
>
> ##### Pull Request Check List (For Your Use):
>
>**General:**
>
>- [ ] Fits Bukkit's Goals
>- [ ] Leaky Ticket Ready
>- [ ] Code Meets Requirements
>- [ ] Code is Documented
>- [ ] Code Addresses Leaky Ticket
>- [ ] Followed Pull Request Format
>- [ ] Tested Code
>- [ ] Included Test Material and Source
>
>**If Applicable:**
>
>- [ ] Importing New Minecraft Classes In Special Commit
>- [ ] Follows Minimal Diff Policy
>- [ ] Uses Proper CraftBukkit Comments
>- [ ] Imports Are Ordered, Separated and Organised Properly
### Tips to Get Your Pull Request Accepted
Making sure you follow the above conventions is important, but just the beginning. Follow these tips to better the chances of your pull request being accepted and pulled.
* Your change should [fit with Bukkit's goals](#does-the-change-fit-bukkits-goals).
* Make sure you follow all of our conventions to the letter.
* Make sure your code compiles under Java 6.
* Check for misplaced whitespaces. It may be invisible, but [we notice](https://github.com/Bukkit/CraftBukkit/pull/1070).
* Provide proper JavaDocs where appropriate.
* JavaDocs should detail every limitation, caveat and gotcha the code has.
* Provide proper accompanying documentation where appropriate.
* Test your code and provide testing material.
* For example: adding an event? Test it with a test plugin and provide us with that plugin and its source.
* Make sure to follow coding best practises.
* Your pull request should adhere to our [Pull Request Formatting Expectations](#pull-request-formatting-expectations).
* **Note:** The project is put under a code freeze leading up to the release of a Minecraft update in order to give the Bukkit team a static code base to work on.
## Useful Resources
* [An example pull request demonstrating the things we look out for](https://github.com/Bukkit/CraftBukkit/pull/1070)
* [Handy gist version of our Pull Request Format Template](https://gist.github.com/EvilSeph/35bb477eaa1dffc5f1d7)
* [More information on contributing](http://wiki.bukkit.org/Getting_Involved)
* [Leaky, Our Issue Tracker (JIRA)](http://leaky.bukkit.org)
* [General GitHub documentation](http://help.github.com/)
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
* [Join us on IRC - #bukkitdev @ irc.esper.net](http://wiki.bukkit.org/IRC)

674
PaperSpigot-API/LICENCE.txt Normal file
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>.

16
PaperSpigot-API/README.md Normal file
View File

@ -0,0 +1,16 @@
Spigot-API
======
A Minecraft Server API.
Website: [http://spigotmc.org](http://spigotmc.org)
Bugs/Suggestions: [http://www.spigotmc.org/forums/bugs-feature-requests.8/](http://www.spigotmc.org/forums/bugs-feature-requests.8/)
Contributing Guidelines: [CONTRIBUTING.md](https://github.com/SpigotMC/Spigot-API/blob/master/CONTRIBUTING.md)
Compilation
-----------
We use maven to handle our dependencies.
* Install [Maven 3](http://maven.apache.org/download.html)
* Check out this repo and: `mvn clean install`

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<parent>
<artifactId>paperspigot-parent</artifactId>
<groupId>org.github.paperspigot</groupId>
<version>dev-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>gg.manny</groupId>
<artifactId>genericspigot-api</artifactId>
<name>PaperSpigot-API</name>
<version>1.7.10-R0.1-SNAPSHOT</version>
<url>https://github.com/PaperSpigot/Spigot</url>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<optimize>true</optimize>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.0-beta-3</version>
<configuration>
<reportPlugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
<version>2.0-beta-1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<configuration>
<linksource>true</linksource>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>javadoc</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</reportPlugins>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<additionalparam>-Xdoclint:none</additionalparam>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>

163
PaperSpigot-API/pom.xml Normal file
View File

@ -0,0 +1,163 @@
<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>gg.manny</groupId>
<artifactId>genericspigot-api</artifactId>
<version>1.7.10-R0.1-SNAPSHOT</version>
<name>PaperSpigot-API</name>
<url>https://github.com/PaperSpigot/Spigot</url>
<properties>
<additionalparam>-Xdoclint:none</additionalparam>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.github.paperspigot</groupId>
<artifactId>paperspigot-parent</artifactId>
<version>dev-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<repositories>
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/public</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<optimize>true</optimize>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.0-beta-3</version>
<configuration>
<reportPlugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
<version>2.0-beta-1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<configuration>
<linksource>true</linksource>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>javadoc</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</reportPlugins>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>1.8-SNAPSHOT</version>
<type>jar</type>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.trove4j</groupId>
<artifactId>trove4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.12</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>ebean</artifactId>
<version>2.8.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>net.sf.trove4j</groupId>
<artifactId>trove4j</artifactId>
<version>3.0.3</version>
</dependency>
<!-- testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,79 @@
package co.aikar.timings;
import static co.aikar.timings.TimingsManager.*;
public class FullServerTickHandler extends TimingHandler {
static final TimingIdentifier IDENTITY = new TimingIdentifier("Minecraft", "Full Server Tick", null, false);
final TimingData minuteData;
double avgFreeMemory = -1D;
double avgUsedMemory = -1D;
FullServerTickHandler() {
super(IDENTITY);
minuteData = new TimingData(id);
TIMING_MAP.put(IDENTITY, this);
}
@Override
public void startTiming() {
if (TimingsManager.needsFullReset) {
TimingsManager.resetTimings();
} else if (TimingsManager.needsRecheckEnabled) {
TimingsManager.recheckEnabled();
}
super.startTiming();
}
@Override
public void stopTiming() {
super.stopTiming();
if (!enabled) {
return;
}
if (TimingHistory.timedTicks % 20 == 0) {
final Runtime runtime = Runtime.getRuntime();
double usedMemory = runtime.totalMemory() - runtime.freeMemory();
double freeMemory = runtime.maxMemory() - usedMemory;
if (this.avgFreeMemory == -1) {
this.avgFreeMemory = freeMemory;
} else {
this.avgFreeMemory = (this.avgFreeMemory * (59 / 60D)) + (freeMemory * (1 / 60D));
}
if (this.avgUsedMemory == -1) {
this.avgUsedMemory = usedMemory;
} else {
this.avgUsedMemory = (this.avgUsedMemory * (59 / 60D)) + (usedMemory * (1 / 60D));
}
}
long start = System.nanoTime();
TimingsManager.tick();
long diff = System.nanoTime() - start;
CURRENT = TIMINGS_TICK;
TIMINGS_TICK.addDiff(diff);
// addDiff for TIMINGS_TICK incremented this, bring it back down to 1 per tick.
record.curTickCount--;
minuteData.curTickTotal = record.curTickTotal;
minuteData.curTickCount = 1;
boolean violated = isViolated();
minuteData.processTick(violated);
TIMINGS_TICK.processTick(violated);
processTick(violated);
if (TimingHistory.timedTicks % 1200 == 0) {
MINUTE_REPORTS.add(new TimingHistory.MinuteReport());
TimingHistory.resetTicks(false);
minuteData.reset();
}
if (TimingHistory.timedTicks % Timings.getHistoryInterval() == 0) {
TimingsManager.HISTORY.add(new TimingHistory());
TimingsManager.resetTimings();
}
}
boolean isViolated() {
return record.curTickTotal > 50000000;
}
}

View File

@ -0,0 +1,61 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
public final class NullTimingHandler implements Timing {
@Override
public void startTiming() {
}
@Override
public void stopTiming() {
}
@Override
public void startTimingIfSync() {
}
@Override
public void stopTimingIfSync() {
}
@Override
public void abort() {
}
@Override
public TimingHandler getTimingHandler() {
return null;
}
@Override
public void close() {
}
}

View File

@ -0,0 +1,81 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Method;
public class TimedEventExecutor implements EventExecutor {
private final EventExecutor executor;
private final Timing timings;
/**
* Wraps an event executor and associates a timing handler to it.
*
* @param executor
* @param plugin
* @param method
* @param eventClass
*/
public TimedEventExecutor(EventExecutor executor, Plugin plugin, Method method, Class<? extends Event> eventClass) {
this.executor = executor;
String id;
if (method == null) {
if (executor.getClass().getEnclosingClass() != null) { // Oh Skript, how we love you
method = executor.getClass().getEnclosingMethod();
}
}
if (method != null) {
id = method.getDeclaringClass().getName();
} else {
id = executor.getClass().getName();
}
final String eventName = eventClass.getSimpleName();
boolean verbose = "BlockPhysicsEvent".equals(eventName) || "Drain".equals(eventName) || "Fill".equals(eventName);
this.timings = Timings.ofSafe(plugin.getName(), (verbose ? "## " : "") +
"Event: " + id + " (" + eventName + ")", null);
}
@Override
public void execute(Listener listener, Event event) throws EventException {
if (event.isAsynchronous() || !Timings.timingsEnabled || !Bukkit.isPrimaryThread()) {
executor.execute(listener, event);
return;
}
timings.startTiming();
executor.execute(listener, event);
timings.stopTiming();
}
}

View File

@ -0,0 +1,72 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
/**
* Provides an ability to time sections of code within the Minecraft Server
*/
public interface Timing extends AutoCloseable {
/**
* Starts timing the execution until {@link #stopTiming()} is called.
*/
public void startTiming();
/**
* <p>Stops timing and records the data. Propagates the data up to group handlers.</p>
*
* Will automatically be called when this Timing is used with try-with-resources
*/
public void stopTiming();
/**
* Starts timing the execution until {@link #stopTiming()} is called.
*
* But only if we are on the primary thread.
*/
public void startTimingIfSync();
/**
* <p>Stops timing and records the data. Propagates the data up to group handlers.</p>
*
* <p>Will automatically be called when this Timing is used with try-with-resources</p>
*
* But only if we are on the primary thread.
*/
public void stopTimingIfSync();
/**
* Stops timing and disregards current timing data.
*/
public void abort();
/**
* Used internally to get the actual backing Handler in the case of delegated Handlers
*
* @return TimingHandler
*/
TimingHandler getTimingHandler();
@Override
void close();
}

View File

@ -0,0 +1,105 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.base.Function;
import java.util.List;
import static co.aikar.util.JSONUtil.toArray;
/**
* <p>Lightweight object for tracking timing data</p>
*
* This is broken out to reduce memory usage
*/
class TimingData {
static Function<Integer, TimingData> LOADER = new Function<Integer, TimingData>() {
@Override
public TimingData apply(Integer input) {
return new TimingData(input);
}
};
int id;
int count = 0;
int lagCount = 0;
long totalTime = 0;
long lagTotalTime = 0;
int curTickCount = 0;
int curTickTotal = 0;
TimingData(int id) {
this.id = id;
}
TimingData(TimingData data) {
this.id = data.id;
this.totalTime = data.totalTime;
this.lagTotalTime = data.lagTotalTime;
this.count = data.count;
this.lagCount = data.lagCount;
}
void add(long diff) {
++curTickCount;
curTickTotal += diff;
}
void processTick(boolean violated) {
totalTime += curTickTotal;
count += curTickCount;
if (violated) {
lagTotalTime += curTickTotal;
lagCount += curTickCount;
}
curTickTotal = 0;
curTickCount = 0;
}
void reset() {
count = 0;
lagCount = 0;
curTickTotal = 0;
curTickCount = 0;
totalTime = 0;
lagTotalTime = 0;
}
protected TimingData clone() {
return new TimingData(this);
}
public List export() {
List list = toArray(
id,
count,
totalTime);
if (lagCount > 0) {
list.add(lagCount);
list.add(lagTotalTime);
}
return list;
}
}

View File

@ -0,0 +1,190 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import co.aikar.util.LoadingIntMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import org.bukkit.Bukkit;
import java.util.logging.Level;
class TimingHandler implements Timing {
private static int idPool = 1;
final int id = idPool++;
final String name;
final boolean verbose;
final TIntObjectHashMap<TimingData> children = new LoadingIntMap<TimingData>(TimingData.LOADER);
final TimingData record;
final TimingHandler groupHandler;
long start = 0;
int timingDepth = 0;
boolean added;
boolean timed;
boolean enabled;
TimingHandler parent;
TimingHandler(TimingIdentifier id) {
if (id.name.startsWith("##")) {
verbose = true;
this.name = id.name.substring(3);
} else {
this.name = id.name;
verbose = false;
}
this.record = new TimingData(this.id);
this.groupHandler = id.groupHandler;
TimingIdentifier.getGroup(id.group).handlers.add(this);
checkEnabled();
}
final void checkEnabled() {
enabled = Timings.timingsEnabled && (!verbose || Timings.verboseEnabled);
}
void processTick(boolean violated) {
if (timingDepth != 0 || record.curTickCount == 0) {
timingDepth = 0;
start = 0;
return;
}
record.processTick(violated);
for (TimingData handler : children.valueCollection()) {
handler.processTick(violated);
}
}
@Override
public void startTimingIfSync() {
if (Bukkit.isPrimaryThread()) {
startTiming();
}
}
@Override
public void stopTimingIfSync() {
if (Bukkit.isPrimaryThread()) {
stopTiming();
}
}
public void startTiming() {
if (enabled && ++timingDepth == 1) {
start = System.nanoTime();
parent = TimingsManager.CURRENT;
TimingsManager.CURRENT = this;
}
}
public void stopTiming() {
if (enabled && --timingDepth == 0 && start != 0) {
if (!Bukkit.isPrimaryThread()) {
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
new Throwable().printStackTrace();
start = 0;
return;
}
addDiff(System.nanoTime() - start);
start = 0;
}
}
@Override
public void abort() {
if (enabled && timingDepth > 0) {
start = 0;
}
}
void addDiff(long diff) {
if (TimingsManager.CURRENT == this) {
TimingsManager.CURRENT = parent;
if (parent != null) {
parent.children.get(id).add(diff);
}
}
record.add(diff);
if (!added) {
added = true;
timed = true;
TimingsManager.HANDLERS.add(this);
}
if (groupHandler != null) {
groupHandler.addDiff(diff);
groupHandler.children.get(id).add(diff);
}
}
/**
* Reset this timer, setting all values to zero.
*
* @param full
*/
void reset(boolean full) {
record.reset();
if (full) {
timed = false;
}
start = 0;
timingDepth = 0;
added = false;
children.clear();
checkEnabled();
}
@Override
public TimingHandler getTimingHandler() {
return this;
}
@Override
public boolean equals(Object o) {
return (this == o);
}
@Override
public int hashCode() {
return id;
}
/**
* This is simply for the Closeable interface so it can be used with
* try-with-resources ()
*/
@Override
public void close() {
stopTimingIfSync();
}
public boolean isSpecial() {
return this == TimingsManager.FULL_SERVER_TICK || this == TimingsManager.TIMINGS_TICK;
}
}

View File

@ -0,0 +1,276 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.base.Function;
import com.google.common.collect.Sets;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import co.aikar.util.LoadingMap;
import co.aikar.util.MRUMapCache;
import java.lang.management.ManagementFactory;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static co.aikar.timings.TimingsManager.FULL_SERVER_TICK;
import static co.aikar.timings.TimingsManager.MINUTE_REPORTS;
import static co.aikar.util.JSONUtil.*;
@SuppressWarnings({"deprecation", "SuppressionAnnotation"})
public class TimingHistory {
public static long lastMinuteTime;
public static long timedTicks;
public static long playerTicks;
public static long entityTicks;
public static long tileEntityTicks;
public static long activatedEntityTicks;
static int worldIdPool = 1;
static Map<String, Integer> worldMap = LoadingMap.newHashMap(new Function<String, Integer>() {
@Override
public Integer apply(String input) {
return worldIdPool++;
}
});
final long endTime;
final long startTime;
final long totalTicks;
final long totalTime; // Represents all time spent running the server this history
final MinuteReport[] minuteReports;
final TimingHistoryEntry[] entries;
final Set<Material> tileEntityTypeSet = Sets.newHashSet();
final Set<EntityType> entityTypeSet = Sets.newHashSet();
final Map<Object, Object> worlds;
TimingHistory() {
this.endTime = System.currentTimeMillis() / 1000;
this.startTime = TimingsManager.historyStart / 1000;
if (timedTicks % 1200 != 0 || MINUTE_REPORTS.isEmpty()) {
this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size() + 1]);
this.minuteReports[this.minuteReports.length - 1] = new MinuteReport();
} else {
this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size()]);
}
long ticks = 0;
for (MinuteReport mp : this.minuteReports) {
ticks += mp.ticksRecord.timed;
}
this.totalTicks = ticks;
this.totalTime = FULL_SERVER_TICK.record.totalTime;
this.entries = new TimingHistoryEntry[TimingsManager.HANDLERS.size()];
int i = 0;
for (TimingHandler handler : TimingsManager.HANDLERS) {
entries[i++] = new TimingHistoryEntry(handler);
}
final Map<EntityType, Counter> entityCounts = MRUMapCache.of(LoadingMap.of(
new EnumMap<EntityType, Counter>(EntityType.class), Counter.LOADER
));
final Map<Material, Counter> tileEntityCounts = MRUMapCache.of(LoadingMap.of(
new EnumMap<Material, Counter>(Material.class), Counter.LOADER
));
// Information about all loaded chunks/entities
this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function<World, JSONPair>() {
@Override
public JSONPair apply(World world) {
return pair(
worldMap.get(world.getName()),
toArrayMapper(world.getLoadedChunks(), new Function<Chunk, Object>() {
@Override
public Object apply(Chunk chunk) {
entityCounts.clear();
tileEntityCounts.clear();
for (Entity entity : chunk.getEntities()) {
entityCounts.get(entity.getType()).increment();
}
for (BlockState tileEntity : chunk.getTileEntities()) {
tileEntityCounts.get(tileEntity.getBlock().getType()).increment();
}
if (tileEntityCounts.isEmpty() && entityCounts.isEmpty()) {
return null;
}
return toArray(
chunk.getX(),
chunk.getZ(),
toObjectMapper(entityCounts.entrySet(),
new Function<Map.Entry<EntityType, Counter>, JSONPair>() {
@Override
public JSONPair apply(Map.Entry<EntityType, Counter> entry) {
entityTypeSet.add(entry.getKey());
return pair(
String.valueOf(entry.getKey().getTypeId()),
entry.getValue().count()
);
}
}
),
toObjectMapper(tileEntityCounts.entrySet(),
new Function<Map.Entry<Material, Counter>, JSONPair>() {
@Override
public JSONPair apply(Map.Entry<Material, Counter> entry) {
tileEntityTypeSet.add(entry.getKey());
return pair(
String.valueOf(entry.getKey().getId()),
entry.getValue().count()
);
}
}
)
);
}
})
);
}
});
}
public static void resetTicks(boolean fullReset) {
if (fullReset) {
// Non full is simply for 1 minute reports
timedTicks = 0;
}
lastMinuteTime = System.nanoTime();
playerTicks = 0;
tileEntityTicks = 0;
entityTicks = 0;
activatedEntityTicks = 0;
}
Object export() {
return createObject(
pair("s", startTime),
pair("e", endTime),
pair("tk", totalTicks),
pair("tm", totalTime),
pair("w", worlds),
pair("h", toArrayMapper(entries, new Function<TimingHistoryEntry, Object>() {
@Override
public Object apply(TimingHistoryEntry entry) {
TimingData record = entry.data;
if (record.count == 0) {
return null;
}
return entry.export();
}
})),
pair("mp", toArrayMapper(minuteReports, new Function<MinuteReport, Object>() {
@Override
public Object apply(MinuteReport input) {
return input.export();
}
}))
);
}
static class MinuteReport {
final long time = System.currentTimeMillis() / 1000;
final TicksRecord ticksRecord = new TicksRecord();
final PingRecord pingRecord = new PingRecord();
final TimingData fst = TimingsManager.FULL_SERVER_TICK.minuteData.clone();
final double tps = 1E9 / ( System.nanoTime() - lastMinuteTime ) * ticksRecord.timed;
final double usedMemory = TimingsManager.FULL_SERVER_TICK.avgUsedMemory;
final double freeMemory = TimingsManager.FULL_SERVER_TICK.avgFreeMemory;
final double loadAvg = ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
public List export() {
return toArray(
time,
Math.round(tps * 100D) / 100D,
Math.round(pingRecord.avg * 100D) / 100D,
fst.export(),
toArray(ticksRecord.timed,
ticksRecord.player,
ticksRecord.entity,
ticksRecord.activatedEntity,
ticksRecord.tileEntity
),
usedMemory,
freeMemory,
loadAvg
);
}
}
static class TicksRecord {
final long timed;
final long player;
final long entity;
final long tileEntity;
final long activatedEntity;
TicksRecord() {
timed = timedTicks - (TimingsManager.MINUTE_REPORTS.size() * 1200);
player = playerTicks;
entity = entityTicks;
tileEntity = tileEntityTicks;
activatedEntity = activatedEntityTicks;
}
}
static class PingRecord {
final double avg;
PingRecord() {
final Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
int totalPing = 0;
for (Player player : onlinePlayers) {
totalPing += player.getPing();
}
avg = onlinePlayers.isEmpty() ? 0 : totalPing / onlinePlayers.size();
}
}
static class Counter {
int count = 0;
@SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
static Function LOADER = new LoadingMap.Feeder<Counter>() {
@Override
public Counter apply() {
return new Counter();
}
};
public int increment() {
return ++count;
}
public int count() {
return count;
}
}
}

View File

@ -0,0 +1,59 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.base.Function;
import java.util.List;
import static co.aikar.util.JSONUtil.toArrayMapper;
class TimingHistoryEntry {
final TimingData data;
final TimingData[] children;
TimingHistoryEntry(TimingHandler handler) {
this.data = handler.record.clone();
children = new TimingData[handler.children.size()];
int i = 0;
for (TimingData child : handler.children.valueCollection()) {
children[i++] = child.clone();
}
}
List export() {
List result = data.export();
if (children.length > 0) {
result.add(
toArrayMapper(children, new Function<TimingData, Object>() {
@Override
public Object apply(TimingData child) {
return child.export();
}
})
);
}
return result;
}
}

View File

@ -0,0 +1,102 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.base.Function;
import co.aikar.util.LoadingMap;
import co.aikar.util.MRUMapCache;
import java.util.ArrayDeque;
import java.util.Map;
/**
* <p>Used as a basis for fast HashMap key comparisons for the Timing Map.</p>
*
* This class uses interned strings giving us the ability to do an identity check instead of equals() on the strings
*/
final class TimingIdentifier {
/**
* Holds all groups. Autoloads on request for a group by name.
*/
static final Map<String, TimingGroup> GROUP_MAP = MRUMapCache.of(
LoadingMap.newIdentityHashMap(new Function<String, TimingGroup>() {
@Override
public TimingGroup apply(String group) {
return new TimingGroup(group);
}
}, 64)
);
static final TimingGroup DEFAULT_GROUP = getGroup("Minecraft");
final String group;
final String name;
final TimingHandler groupHandler;
final boolean protect;
private final int hashCode;
TimingIdentifier(String group, String name, Timing groupHandler, boolean protect) {
this.group = group != null ? group.intern() : DEFAULT_GROUP.name;
this.name = name.intern();
this.groupHandler = groupHandler != null ? groupHandler.getTimingHandler() : null;
this.protect = protect;
this.hashCode = (31 * this.group.hashCode()) + this.name.hashCode();
}
static TimingGroup getGroup(String groupName) {
if (groupName == null) {
return DEFAULT_GROUP;
}
return GROUP_MAP.get(groupName.intern());
}
// We are using .intern() on the strings so it is guaranteed to be an identity comparison.
@SuppressWarnings("StringEquality")
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
TimingIdentifier that = (TimingIdentifier) o;
return group == that.group && name == that.name;
}
@Override
public int hashCode() {
return hashCode;
}
static class TimingGroup {
private static int idPool = 1;
final int id = idPool++;
final String name;
ArrayDeque<TimingHandler> handlers = new ArrayDeque<TimingHandler>(64);
private TimingGroup(String name) {
this.name = name;
}
}
}

View File

@ -0,0 +1,273 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.base.Preconditions;
import com.google.common.collect.EvictingQueue;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import java.util.Queue;
import java.util.logging.Level;
@SuppressWarnings("UnusedDeclaration")
public final class Timings {
private static final int MAX_HISTORY_FRAMES = 12;
public static final Timing NULL_HANDLER = new NullTimingHandler();
static boolean timingsEnabled = false;
static boolean verboseEnabled = false;
private static int historyInterval = -1;
private static int historyLength = -1;
private Timings() {}
/**
* Returns a Timing for a plugin corresponding to a name.
*
* @param plugin Plugin to own the Timing
* @param name Name of Timing
* @return Handler
*/
public static Timing of(Plugin plugin, String name) {
Timing pluginHandler = null;
if (plugin != null) {
pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER);
}
return of(plugin, name, pluginHandler);
}
/**
* <p>Returns a handler that has a groupHandler timer handler. Parent timers should not have their
* start/stop methods called directly, as the children will call it for you.</p>
*
* Parent Timers are used to group multiple subsections together and get a summary of them combined
* Parent Handler can not be changed after first call
*
* @param plugin Plugin to own the Timing
* @param name Name of Timing
* @param groupHandler Parent handler to mirror .start/stop calls to
* @return Timing Handler
*/
public static Timing of(Plugin plugin, String name, Timing groupHandler) {
Preconditions.checkNotNull(plugin, "Plugin can not be null");
return TimingsManager.getHandler(plugin.getName(), name, groupHandler, true);
}
/**
* Returns a Timing object after starting it, useful for Java7 try-with-resources.
*
* try (Timing ignored = Timings.ofStart(plugin, someName)) {
* // timed section
* }
*
* @param plugin Plugin to own the Timing
* @param name Name of Timing
* @return Timing Handler
*/
public static Timing ofStart(Plugin plugin, String name) {
return ofStart(plugin, name, null);
}
/**
* Returns a Timing object after starting it, useful for Java7 try-with-resources.
*
* try (Timing ignored = Timings.ofStart(plugin, someName, groupHandler)) {
* // timed section
* }
*
* @param plugin Plugin to own the Timing
* @param name Name of Timing
* @param groupHandler Parent handler to mirror .start/stop calls to
* @return Timing Handler
*/
public static Timing ofStart(Plugin plugin, String name, Timing groupHandler) {
Timing timing = of(plugin, name, groupHandler);
timing.startTimingIfSync();
return timing;
}
/**
* Gets whether or not the Spigot Timings system is enabled
*
* @return Enabled or not
*/
public static boolean isTimingsEnabled() {
return timingsEnabled;
}
/**
* <p>Sets whether or not the Spigot Timings system should be enabled</p>
*
* Calling this will reset timing data.
*
* @param enabled Should timings be reported
*/
public static void setTimingsEnabled(boolean enabled) {
timingsEnabled = enabled;
reset();
}
/**
* <p>Sets whether or not the Timings should monitor at Verbose level.</p>
*
* <p>When Verbose is disabled, high-frequency timings will not be available.</p>
*
* @return Enabled or not
*/
public static boolean isVerboseTimingsEnabled() {
return timingsEnabled;
}
/**
* Sets whether or not the Timings should monitor at Verbose level.
* <p/>
* When Verbose is disabled, high-frequency timings will not be available.
* Calling this will reset timing data.
*
* @param enabled Should high-frequency timings be reported
*/
public static void setVerboseTimingsEnabled(boolean enabled) {
verboseEnabled = enabled;
TimingsManager.needsRecheckEnabled = true;
}
/**
* <p>Gets the interval between Timing History report generation.</p>
*
* Defaults to 5 minutes (6000 ticks)
*
* @return Interval in ticks
*/
public static int getHistoryInterval() {
return historyInterval;
}
/**
* <p>Sets the interval between Timing History report generations.</p>
*
* <p>Defaults to 5 minutes (6000 ticks)</p>
*
* This will recheck your history length, so lowering this value will lower your
* history length if you need more than 60 history windows.
*
* @param interval Interval in ticks
*/
public static void setHistoryInterval(int interval) {
historyInterval = Math.max(20*60, interval);
// Recheck the history length with the new Interval
if (historyLength != -1) {
setHistoryLength(historyLength);
}
}
/**
* Gets how long in ticks Timings history is kept for the server.
*
* Defaults to 1 hour (72000 ticks)
*
* @return Duration in Ticks
*/
public static int getHistoryLength() {
return historyLength;
}
/**
* Sets how long Timing History reports are kept for the server.
*
* Defaults to 1 hours(72000 ticks)
*
* This value is capped at a maximum of getHistoryInterval() * MAX_HISTORY_FRAMES (12)
*
* Will not reset Timing Data but may truncate old history if the new length is less than old length.
*
* @param length Duration in ticks
*/
public static void setHistoryLength(int length) {
// Cap at 12 History Frames, 1 hour at 5 minute frames.
int maxLength = historyInterval * MAX_HISTORY_FRAMES;
// For special cases of servers with special permission to bypass the max.
// This max helps keep data file sizes reasonable for processing on Aikar's Timing parser side.
// Setting this will not help you bypass the max unless Aikar has added an exception on the API side.
if (System.getProperty("timings.bypassMax") != null) {
maxLength = Integer.MAX_VALUE;
}
historyLength = Math.max(Math.min(maxLength, length), historyInterval);
Queue<TimingHistory> oldQueue = TimingsManager.HISTORY;
int frames = (getHistoryLength() / getHistoryInterval());
if (length > maxLength) {
Bukkit.getLogger().log(Level.WARNING, "Timings Length too high. Requested " + length + ", max is " + maxLength + ". To get longer history, you must increase your interval. Set Interval to " + Math.ceil(length / MAX_HISTORY_FRAMES) + " to achieve this length.");
}
TimingsManager.HISTORY = EvictingQueue.create(frames);
TimingsManager.HISTORY.addAll(oldQueue);
}
/**
* Resets all Timing Data
*/
public static void reset() {
TimingsManager.reset();
}
/**
* Generates a report and sends it to the specified command sender.
*
* If sender is null, ConsoleCommandSender will be used.
* @param sender The sender to send to, or null to use the ConsoleCommandSender
*/
public static void generateReport(CommandSender sender) {
if (sender == null) {
sender = Bukkit.getConsoleSender();
}
TimingsExport.reportTimings(sender);
}
/*
=================
Protected API: These are for internal use only in Bukkit/CraftBukkit
These do not have isPrimaryThread() checks in the startTiming/stopTiming
=================
*/
static TimingHandler ofSafe(String name) {
return ofSafe(null, name, null);
}
static Timing ofSafe(Plugin plugin, String name) {
Timing pluginHandler = null;
if (plugin != null) {
pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER);
}
return ofSafe(plugin != null ? plugin.getName() : "Minecraft - Invalid Plugin", name, pluginHandler);
}
static TimingHandler ofSafe(String name, Timing groupHandler) {
return ofSafe(null, name, groupHandler);
}
static TimingHandler ofSafe(String groupName, String name, Timing groupHandler) {
return TimingsManager.getHandler(groupName, name, groupHandler, false);
}
}

View File

@ -0,0 +1,110 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.defaults.BukkitCommand;
import org.bukkit.util.StringUtil;
import java.util.ArrayList;
import java.util.List;
public class TimingsCommand extends BukkitCommand {
public static final List<String> TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste", "verbon", "verboff");
public TimingsCommand(String name) {
super(name);
this.description = "Manages Spigot Timings data to see performance of the server.";
this.usageMessage = "/timings <reset|report|on|off|verbon|verboff>";
this.setPermission("bukkit.command.timings");
}
@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (!testPermission(sender)) {
return true;
}
if (args.length < 1) {
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
return true;
}
final String arg = args[0];
if ("on".equalsIgnoreCase(arg)) {
Timings.setTimingsEnabled(true);
sender.sendMessage("Enabled Timings & Reset");
return true;
} else if ("off".equalsIgnoreCase(arg)) {
Timings.setTimingsEnabled(false);
sender.sendMessage("Disabled Timings");
return true;
}
if (!Timings.isTimingsEnabled()) {
sender.sendMessage("Please enable timings by typing /timings on");
return true;
}
if ("verbon".equalsIgnoreCase(arg)) {
Timings.setVerboseTimingsEnabled(true);
sender.sendMessage("Enabled Verbose Timings");
return true;
} else if ("verboff".equalsIgnoreCase(arg)) {
Timings.setVerboseTimingsEnabled(false);
sender.sendMessage("Disabled Verbose Timings");
return true;
} else if ("reset".equalsIgnoreCase(arg)) {
TimingsManager.reset();
sender.sendMessage("Timings reset");
} else if ("cost".equals(arg)) {
sender.sendMessage("Timings cost: " + TimingsExport.getCost());
} else if (
"paste".equalsIgnoreCase(arg) ||
"report".equalsIgnoreCase(arg) ||
"get".equalsIgnoreCase(arg) ||
"merged".equalsIgnoreCase(arg) ||
"separate".equalsIgnoreCase(arg)
) {
TimingsExport.reportTimings(sender);
} else {
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
}
return true;
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
Validate.notNull(sender, "Sender cannot be null");
Validate.notNull(args, "Arguments cannot be null");
Validate.notNull(alias, "Alias cannot be null");
if (args.length == 1) {
return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS,
new ArrayList<String>(TIMINGS_SUBCOMMANDS.size()));
}
return ImmutableList.of();
}
}

View File

@ -0,0 +1,373 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.base.Function;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.RemoteConsoleCommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemorySection;
import org.bukkit.entity.EntityType;
import org.bukkit.plugin.Plugin;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
import static co.aikar.timings.TimingsManager.HISTORY;
import static co.aikar.util.JSONUtil.*;
@SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
class TimingsExport extends Thread {
private final CommandSender sender;
private final Map out;
private final TimingHistory[] history;
TimingsExport(CommandSender sender, Map out, TimingHistory[] history) {
super("Timings paste thread");
this.sender = sender;
this.out = out;
this.history = history;
}
/**
* Builds an XML report of the timings to be uploaded for parsing.
*
* @param sender Who to report to
*/
static void reportTimings(CommandSender sender) {
Map parent = createObject(
// Get some basic system details about the server
pair("version", Bukkit.getVersion()),
pair("maxplayers", Bukkit.getMaxPlayers()),
pair("start", TimingsManager.timingStart / 1000),
pair("end", System.currentTimeMillis() / 1000),
pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000)
);
if (!TimingsManager.privacy) {
appendObjectData(parent,
pair("server", Bukkit.getServerName()),
pair("motd", Bukkit.getServer().getMotd()),
pair("online-mode", Bukkit.getServer().getOnlineMode()),
pair("icon", Bukkit.getServer().getServerIcon().getData())
);
}
final Runtime runtime = Runtime.getRuntime();
RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
parent.put("system", createObject(
pair("timingcost", getCost()),
pair("name", System.getProperty("os.name")),
pair("version", System.getProperty("os.version")),
pair("jvmversion", System.getProperty("java.version")),
pair("arch", System.getProperty("os.arch")),
pair("maxmem", runtime.maxMemory()),
pair("cpu", runtime.availableProcessors()),
pair("runtime", ManagementFactory.getRuntimeMXBean().getUptime()),
pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")),
pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), new Function<GarbageCollectorMXBean, JSONPair>() {
@Override
public JSONPair apply(GarbageCollectorMXBean input) {
return pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime()));
}
}))
)
);
Set<Material> tileEntityTypeSet = Sets.newHashSet();
Set<EntityType> entityTypeSet = Sets.newHashSet();
int size = HISTORY.size();
TimingHistory[] history = new TimingHistory[size + 1];
int i = 0;
for (TimingHistory timingHistory : HISTORY) {
tileEntityTypeSet.addAll(timingHistory.tileEntityTypeSet);
entityTypeSet.addAll(timingHistory.entityTypeSet);
history[i++] = timingHistory;
}
history[i] = new TimingHistory(); // Current snapshot
tileEntityTypeSet.addAll(history[i].tileEntityTypeSet);
entityTypeSet.addAll(history[i].entityTypeSet);
Map handlers = createObject();
for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) {
for (TimingHandler id : group.handlers) {
if (!id.timed && !id.isSpecial()) {
continue;
}
handlers.put(id.id, toArray(
group.id,
id.name
));
}
}
parent.put("idmap", createObject(
pair("groups", toObjectMapper(
TimingIdentifier.GROUP_MAP.values(), new Function<TimingIdentifier.TimingGroup, JSONPair>() {
@Override
public JSONPair apply(TimingIdentifier.TimingGroup group) {
return pair(group.id, group.name);
}
})),
pair("handlers", handlers),
pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), new Function<Map.Entry<String, Integer>, JSONPair>() {
@Override
public JSONPair apply(Map.Entry<String, Integer> input) {
return pair(input.getValue(), input.getKey());
}
})),
pair("tileentity",
toObjectMapper(tileEntityTypeSet, new Function<Material, JSONPair>() {
@Override
public JSONPair apply(Material input) {
return pair(input.getId(), input.name());
}
})),
pair("entity",
toObjectMapper(entityTypeSet, new Function<EntityType, JSONPair>() {
@Override
public JSONPair apply(EntityType input) {
return pair(input.getTypeId(), input.name());
}
}))
));
// Information about loaded plugins
parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(),
new Function<Plugin, JSONPair>() {
@Override
public JSONPair apply(Plugin plugin) {
return pair(plugin.getName(), createObject(
pair("version", plugin.getDescription().getVersion()),
pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()),
pair("website", plugin.getDescription().getWebsite()),
pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", "))
));
}
}));
// Information on the users Config
parent.put("config", createObject(
pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
pair("paperspigot", mapAsJSON(Bukkit.spigot().getPaperSpigotConfig(), null))
));
new TimingsExport(sender, parent, history).start();
}
static long getCost() {
// Benchmark the users System.nanotime() for cost basis
int passes = 100;
TimingHandler SAMPLER1 = Timings.ofSafe("Timings Sampler 1");
TimingHandler SAMPLER2 = Timings.ofSafe("Timings Sampler 2");
TimingHandler SAMPLER3 = Timings.ofSafe("Timings Sampler 3");
TimingHandler SAMPLER4 = Timings.ofSafe("Timings Sampler 4");
TimingHandler SAMPLER5 = Timings.ofSafe("Timings Sampler 5");
TimingHandler SAMPLER6 = Timings.ofSafe("Timings Sampler 6");
long start = System.nanoTime();
for (int i = 0; i < passes; i++) {
SAMPLER1.startTiming();
SAMPLER2.startTiming();
SAMPLER3.startTiming();
SAMPLER3.stopTiming();
SAMPLER4.startTiming();
SAMPLER5.startTiming();
SAMPLER6.startTiming();
SAMPLER6.stopTiming();
SAMPLER5.stopTiming();
SAMPLER4.stopTiming();
SAMPLER2.stopTiming();
SAMPLER1.stopTiming();
}
long timingsCost = (System.nanoTime() - start) / passes / 6;
SAMPLER1.reset(true);
SAMPLER2.reset(true);
SAMPLER3.reset(true);
SAMPLER4.reset(true);
SAMPLER5.reset(true);
SAMPLER6.reset(true);
return timingsCost;
}
private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) {
JSONObject object = new JSONObject();
for (String key : config.getKeys(false)) {
String fullKey = (parentKey != null ? parentKey + "." + key : key);
if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey)) {
continue;
}
final Object val = config.get(key);
object.put(key, valAsJSON(val, fullKey));
}
return object;
}
private static Object valAsJSON(Object val, final String parentKey) {
if (!(val instanceof MemorySection)) {
if (val instanceof List) {
Iterable<Object> v = (Iterable<Object>) val;
return toArrayMapper(v, new Function<Object, Object>() {
@Override
public Object apply(Object input) {
return valAsJSON(input, parentKey);
}
});
} else {
return val.toString();
}
} else {
return mapAsJSON((ConfigurationSection) val, parentKey);
}
}
@SuppressWarnings("CallToThreadRun")
@Override
public synchronized void start() {
if (sender instanceof RemoteConsoleCommandSender) {
sender.sendMessage(ChatColor.RED + "Warning: Timings report done over RCON will cause lag spikes.");
sender.sendMessage(ChatColor.RED + "You should use " + ChatColor.YELLOW +
"/timings report" + ChatColor.RED + " in game or console.");
run();
} else {
super.start();
}
}
@Override
public void run() {
sender.sendMessage(ChatColor.GREEN + "Preparing Timings Report...");
out.put("data", toArrayMapper(history, new Function<TimingHistory, Object>() {
@Override
public Object apply(TimingHistory input) {
return input.export();
}
}));
String response = null;
try {
HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection();
con.setDoOutput(true);
con.setRequestProperty("User-Agent", "Spigot/" + Bukkit.getServerName() + "/" + InetAddress.getLocalHost().getHostName());
con.setRequestMethod("POST");
con.setInstanceFollowRedirects(false);
OutputStream request = new GZIPOutputStream(con.getOutputStream()) {{
this.def.setLevel(7);
}};
request.write(JSONValue.toJSONString(out).getBytes("UTF-8"));
request.close();
response = getResponse(con);
if (con.getResponseCode() != 302) {
sender.sendMessage(
ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage());
sender.sendMessage(ChatColor.RED + "Check your logs for more information");
if (response != null) {
Bukkit.getLogger().log(Level.SEVERE, response);
}
return;
}
String location = con.getHeaderField("Location");
sender.sendMessage(ChatColor.GREEN + "View Timings Report: " + location);
if (!(sender instanceof ConsoleCommandSender)) {
Bukkit.getLogger().log(Level.INFO, "View Timings Report: " + location);
}
if (response != null && !response.isEmpty()) {
Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response);
}
} catch (IOException ex) {
sender.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
if (response != null) {
Bukkit.getLogger().log(Level.SEVERE, response);
}
Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex);
}
}
private String getResponse(HttpURLConnection con) throws IOException {
InputStream is = null;
try {
is = con.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(b)) != -1) {
bos.write(b, 0, bytesRead);
}
return bos.toString();
} catch (IOException ex) {
sender.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex);
return null;
} finally {
if (is != null) {
is.close();
}
}
}
}

View File

@ -0,0 +1,194 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import com.google.common.base.Function;
import com.google.common.collect.EvictingQueue;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.PluginClassLoader;
import co.aikar.util.LoadingMap;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
public final class TimingsManager {
static final Map<TimingIdentifier, TimingHandler> TIMING_MAP =
Collections.synchronizedMap(LoadingMap.newHashMap(
new Function<TimingIdentifier, TimingHandler>() {
@Override
public TimingHandler apply(TimingIdentifier id) {
return (id.protect ?
new UnsafeTimingHandler(id) :
new TimingHandler(id)
);
}
},
256, .5F
));
public static final FullServerTickHandler FULL_SERVER_TICK = new FullServerTickHandler();
public static final TimingHandler TIMINGS_TICK = Timings.ofSafe("Timings Tick", FULL_SERVER_TICK);
public static final Timing PLUGIN_GROUP_HANDLER = Timings.ofSafe("Plugins");
public static List<String> hiddenConfigs = new ArrayList<String>();
public static boolean privacy = false;
static final Collection<TimingHandler> HANDLERS = new ArrayDeque<TimingHandler>();
static final ArrayDeque<TimingHistory.MinuteReport> MINUTE_REPORTS = new ArrayDeque<TimingHistory.MinuteReport>();
static EvictingQueue<TimingHistory> HISTORY = EvictingQueue.create(12);
static TimingHandler CURRENT;
static long timingStart = 0;
static long historyStart = 0;
static boolean needsFullReset = false;
static boolean needsRecheckEnabled = false;
private TimingsManager() {}
/**
* Resets all timing data on the next tick
*/
static void reset() {
needsFullReset = true;
}
/**
* Ticked every tick by CraftBukkit to count the number of times a timer
* caused TPS loss.
*/
static void tick() {
if (Timings.timingsEnabled) {
boolean violated = FULL_SERVER_TICK.isViolated();
for (TimingHandler handler : HANDLERS) {
if (handler.isSpecial()) {
// We manually call this
continue;
}
handler.processTick(violated);
}
TimingHistory.playerTicks += Bukkit.getOnlinePlayers().size();
TimingHistory.timedTicks++;
// Generate TPS/Ping/Tick reports every minute
}
}
static void stopServer() {
Timings.timingsEnabled = false;
recheckEnabled();
}
static void recheckEnabled() {
synchronized (TIMING_MAP) {
for (TimingHandler timings : TIMING_MAP.values()) {
timings.checkEnabled();
}
}
needsRecheckEnabled = false;
}
static void resetTimings() {
if (needsFullReset) {
// Full resets need to re-check every handlers enabled state
// Timing map can be modified from async so we must sync on it.
synchronized (TIMING_MAP) {
for (TimingHandler timings : TIMING_MAP.values()) {
timings.reset(true);
}
}
Bukkit.getLogger().log(Level.INFO, "Timings Reset");
HISTORY.clear();
needsFullReset = false;
needsRecheckEnabled = false;
timingStart = System.currentTimeMillis();
} else {
// Soft resets only need to act on timings that have done something
// Handlers can only be modified on main thread.
for (TimingHandler timings : HANDLERS) {
timings.reset(false);
}
}
HANDLERS.clear();
MINUTE_REPORTS.clear();
TimingHistory.resetTicks(true);
historyStart = System.currentTimeMillis();
}
static TimingHandler getHandler(String group, String name, Timing parent, boolean protect) {
return TIMING_MAP.get(new TimingIdentifier(group, name, parent, protect));
}
/**
* <p>Due to access restrictions, we need a helper method to get a Command TimingHandler with String group</p>
*
* Plugins should never call this
*
* @param pluginName Plugin this command is associated with
* @param command Command to get timings for
* @return TimingHandler
*/
public static Timing getCommandTiming(String pluginName, Command command) {
Plugin plugin = null;
final Server server = Bukkit.getServer();
if (!("minecraft".equals(pluginName) || "bukkit".equals(pluginName) || "Spigot".equals(pluginName) ||
server == null)) {
plugin = server.getPluginManager().getPlugin(pluginName);
if (plugin == null) {
// Plugin is passing custom fallback prefix, try to look up by class loader
plugin = getPluginByClassloader(command.getClass());
}
}
if (plugin == null) {
return Timings.ofSafe("Command: " + pluginName + ":" + command.getTimingName());
}
return Timings.ofSafe(plugin, "Command: " + pluginName + ":" + command.getTimingName());
}
/**
* Looks up the class loader for the specified class, and if it is a PluginClassLoader, return the
* Plugin that created this class.
*
* @param clazz Class to check
* @return Plugin if created by a plugin
*/
public static Plugin getPluginByClassloader(Class<?> clazz) {
if (clazz == null) {
return null;
}
final ClassLoader classLoader = clazz.getClassLoader();
if (classLoader instanceof PluginClassLoader) {
PluginClassLoader pluginClassLoader = (PluginClassLoader) classLoader;
return pluginClassLoader.getPlugin();
}
return null;
}
}

View File

@ -0,0 +1,51 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.timings;
import org.bukkit.Bukkit;
class UnsafeTimingHandler extends TimingHandler {
UnsafeTimingHandler(TimingIdentifier id) {
super(id);
}
private static void checkThread() {
if (!Bukkit.isPrimaryThread()) {
throw new IllegalStateException("Calling Timings from Async Operation");
}
}
@Override
public void startTiming() {
checkThread();
super.startTiming();
}
@Override
public void stopTiming() {
checkThread();
super.stopTiming();
}
}

View File

@ -0,0 +1,123 @@
package co.aikar.util;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Provides Utility methods that assist with generating JSON Objects
*/
@SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
public final class JSONUtil {
private JSONUtil() {}
/**
* Creates a key/value "JSONPair" object
* @param key
* @param obj
* @return
*/
public static JSONPair pair(String key, Object obj) {
return new JSONPair(key, obj);
}
public static JSONPair pair(long key, Object obj) {
return new JSONPair(String.valueOf(key), obj);
}
/**
* Creates a new JSON object from multiple JsonPair key/value pairs
* @param data
* @return
*/
public static Map createObject(JSONPair... data) {
return appendObjectData(new LinkedHashMap(), data);
}
/**
* This appends multiple key/value Obj pairs into a JSON Object
* @param parent
* @param data
* @return
*/
public static Map appendObjectData(Map parent, JSONPair... data) {
for (JSONPair JSONPair : data) {
parent.put(JSONPair.key, JSONPair.val);
}
return parent;
}
/**
* This builds a JSON array from a set of data
* @param data
* @return
*/
public static List toArray(Object... data) {
return Lists.newArrayList(data);
}
/**
* These help build a single JSON array using a mapper function
* @param collection
* @param mapper
* @param <E>
* @return
*/
public static <E> List toArrayMapper(E[] collection, Function<E, Object> mapper) {
return toArrayMapper(Lists.newArrayList(collection), mapper);
}
public static <E> List toArrayMapper(Iterable<E> collection, Function<E, Object> mapper) {
List array = Lists.newArrayList();
for (E e : collection) {
Object object = mapper.apply(e);
if (object != null) {
array.add(object);
}
}
return array;
}
/**
* These help build a single JSON Object from a collection, using a mapper function
* @param collection
* @param mapper
* @param <E>
* @return
*/
public static <E> Map toObjectMapper(E[] collection, Function<E, JSONPair> mapper) {
return toObjectMapper(Lists.newArrayList(collection), mapper);
}
public static <E> Map toObjectMapper(Iterable<E> collection, Function<E, JSONPair> mapper) {
Map object = Maps.newLinkedHashMap();
for (E e : collection) {
JSONPair JSONPair = mapper.apply(e);
if (JSONPair != null) {
object.put(JSONPair.key, JSONPair.val);
}
}
return object;
}
/**
* Simply stores a key and a value, used internally by many methods below.
*/
@SuppressWarnings("PublicInnerClass")
public static class JSONPair {
final String key;
final Object val;
JSONPair(String key, Object val) {
this.key = key;
this.val = val;
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2015. Starlis LLC / dba Empire Minecraft
*
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval
*
*/
package co.aikar.util;
import com.google.common.base.Function;
import gnu.trove.map.hash.TIntObjectHashMap;
/**
* Allows you to pass a Loader function that when a key is accessed that doesn't exist,
* automatically loads the entry into the map by calling the loader Function.
*
* .get() Will only return null if the Loader can return null.
*
* You may pass any backing Map to use.
*
* This class is not thread safe and should be wrapped with Collections.synchronizedMap on the OUTSIDE of the LoadingMap if needed.
*
* Do not wrap the backing map with Collections.synchronizedMap.
*
* @param <V> Value
*/
public class LoadingIntMap<V> extends TIntObjectHashMap<V> {
private final Function<Integer, V> loader;
/**
* Initializes an auto loading map using specified loader and backing map
* @param loader The loader
*/
public LoadingIntMap(Function<Integer, V> loader) {
this.loader = loader;
}
@Override
public V get(int key) {
V res = super.get(key);
if (res == null) {
res = loader.apply(key);
if (res != null) {
put(key, res);
}
}
return res;
}
/**
* Due to java stuff, you will need to cast it to (Function) for some cases
* @param <T>
*/
public abstract static class Feeder <T> implements Function<T, T> {
@Override
public T apply(Object input) {
return apply();
}
public abstract T apply();
}
}

View File

@ -0,0 +1,323 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.util;
import com.google.common.base.Function;
import java.lang.reflect.Constructor;
import java.util.*;
/**
* Allows you to pass a Loader function that when a key is accessed that doesn't exists,
* automatically loads the entry into the map by calling the loader Function.
*
* .get() Will only return null if the Loader can return null.
*
* You may pass any backing Map to use.
*
* This class is not thread safe and should be wrapped with Collections.synchronizedMap on the OUTSIDE of the LoadingMap if needed.
*
* Do not wrap the backing map with Collections.synchronizedMap.
*
* @param <K> Key
* @param <V> Value
*/
public class LoadingMap <K,V> extends AbstractMap<K, V> {
private final Map<K, V> backingMap;
private final Function<K, V> loader;
/**
* Initializes an auto loading map using specified loader and backing map
* @param backingMap
* @param loader
*/
public LoadingMap(Map<K, V> backingMap, Function<K, V> loader) {
this.backingMap = backingMap;
this.loader = loader;
}
/**
* Creates a new LoadingMap with the specified map and loader
* @param backingMap
* @param loader
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> of(Map<K, V> backingMap, Function<K, V> loader) {
return new LoadingMap<K, V>(backingMap, loader);
}
/**
* Creates a LoadingMap with an auto instantiating loader.
*
* Will auto construct class of of Value when not found
*
* Since this uses Reflection, It is more effecient to define your own static loader
* than using this helper, but if performance is not critical, this is easier.
*
* @param backingMap Actual map being used.
* @param keyClass Class used for the K generic
* @param valueClass Class used for the V generic
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map that auto instantiates on .get()
*/
public static <K, V> Map<K, V> newAutoMap(Map<K, V> backingMap, final Class<? extends K> keyClass,
final Class<? extends V> valueClass) {
return new LoadingMap<K, V>(backingMap, new AutoInstantiatingLoader<K, V>(keyClass, valueClass));
}
/**
* Creates a LoadingMap with an auto instantiating loader.
*
* Will auto construct class of of Value when not found
*
* Since this uses Reflection, It is more effecient to define your own static loader
* than using this helper, but if performance is not critical, this is easier.
*
* @param backingMap Actual map being used.
* @param valueClass Class used for the V generic
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map that auto instantiates on .get()
*/
public static <K, V> Map<K, V> newAutoMap(Map<K, V> backingMap,
final Class<? extends V> valueClass) {
return newAutoMap(backingMap, null, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
* @param keyClass
* @param valueClass
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newHashAutoMap(final Class<? extends K> keyClass, final Class<? extends V> valueClass) {
return newAutoMap(new HashMap<K, V>(), keyClass, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
* @param valueClass
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newHashAutoMap(final Class<? extends V> valueClass) {
return newHashAutoMap(null, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
*
* @param keyClass
* @param valueClass
* @param initialCapacity
* @param loadFactor
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newHashAutoMap(final Class<? extends K> keyClass, final Class<? extends V> valueClass, int initialCapacity, float loadFactor) {
return newAutoMap(new HashMap<K, V>(initialCapacity, loadFactor), keyClass, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
*
* @param valueClass
* @param initialCapacity
* @param loadFactor
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newHashAutoMap(final Class<? extends V> valueClass, int initialCapacity, float loadFactor) {
return newHashAutoMap(null, valueClass, initialCapacity, loadFactor);
}
/**
* Initializes an auto loading map using a HashMap
* @param loader
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newHashMap(Function<K, V> loader) {
return new LoadingMap<K, V>(new HashMap<K, V>(), loader);
}
/**
* Initializes an auto loading map using a HashMap
* @param loader
* @param initialCapacity
* @param loadFactor
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newHashMap(Function<K, V> loader, int initialCapacity, float loadFactor) {
return new LoadingMap<K, V>(new HashMap<K, V>(initialCapacity, loadFactor), loader);
}
/**
* Initializes an auto loading map using an Identity HashMap
* @param loader
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newIdentityHashMap(Function<K, V> loader) {
return new LoadingMap<K, V>(new IdentityHashMap<K, V>(), loader);
}
/**
* Initializes an auto loading map using an Identity HashMap
* @param loader
* @param initialCapacity
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> newIdentityHashMap(Function<K, V> loader, int initialCapacity) {
return new LoadingMap<K, V>(new IdentityHashMap<K, V>(initialCapacity), loader);
}
@Override
public int size() {return backingMap.size();}
@Override
public boolean isEmpty() {return backingMap.isEmpty();}
@Override
public boolean containsKey(Object key) {return backingMap.containsKey(key);}
@Override
public boolean containsValue(Object value) {return backingMap.containsValue(value);}
@Override
public V get(Object key) {
V res = backingMap.get(key);
if (res == null && key != null) {
res = loader.apply((K) key);
if (res != null) {
backingMap.put((K) key, res);
}
}
return res;
}
public V put(K key, V value) {return backingMap.put(key, value);}
@Override
public V remove(Object key) {return backingMap.remove(key);}
public void putAll(Map<? extends K, ? extends V> m) {backingMap.putAll(m);}
@Override
public void clear() {backingMap.clear();}
@Override
public Set<K> keySet() {return backingMap.keySet();}
@Override
public Collection<V> values() {return backingMap.values();}
@Override
public boolean equals(Object o) {return backingMap.equals(o);}
@Override
public int hashCode() {return backingMap.hashCode();}
@Override
public Set<Entry<K, V>> entrySet() {
return backingMap.entrySet();
}
public LoadingMap<K, V> clone() {
return new LoadingMap<K, V>(backingMap, loader);
}
private static class AutoInstantiatingLoader<K, V> implements Function<K, V> {
final Constructor<? extends V> constructor;
private final Class<? extends V> valueClass;
AutoInstantiatingLoader(Class<? extends K> keyClass, Class<? extends V> valueClass) {
try {
this.valueClass = valueClass;
if (keyClass != null) {
constructor = valueClass.getConstructor(keyClass);
} else {
constructor = null;
}
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
valueClass.getName() + " does not have a constructor for " + (keyClass != null ? keyClass.getName() : null));
}
}
@Override
public V apply(K input) {
try {
return (constructor != null ? constructor.newInstance(input) : valueClass.newInstance());
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object object) {
return false;
}
}
/**
* Due to java stuff, you will need to cast it to (Function) for some cases
* @param <T>
*/
public abstract static class Feeder <T> implements Function<T, T> {
@Override
public T apply(Object input) {
return apply();
}
public abstract T apply();
}
}

View File

@ -0,0 +1,100 @@
/*
* This file is licensed under the MIT License (MIT).
*
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package co.aikar.util;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Implements a Most Recently Used cache in front of a backing map, to quickly access the last accessed result.
* @param <K>
* @param <V>
*/
public class MRUMapCache<K, V> extends AbstractMap<K, V> {
final Map<K, V> backingMap;
Object cacheKey;
V cacheValue;
public MRUMapCache(final Map<K, V> backingMap) {
this.backingMap = backingMap;
}
public int size() {return backingMap.size();}
public boolean isEmpty() {return backingMap.isEmpty();}
public boolean containsKey(Object key) {
return key != null && key.equals(cacheKey) || backingMap.containsKey(key);
}
public boolean containsValue(Object value) {
return value != null && value == cacheValue || backingMap.containsValue(value);
}
public V get(Object key) {
if (cacheKey != null && cacheKey.equals(key)) {
return cacheValue;
}
cacheKey = key;
return cacheValue = backingMap.get(key);
}
public V put(K key, V value) {
cacheKey = key;
return cacheValue = backingMap.put(key, value);
}
public V remove(Object key) {
if (key != null && key.equals(cacheKey)) {
cacheKey = null;
}
return backingMap.remove(key);
}
public void putAll(Map<? extends K, ? extends V> m) {backingMap.putAll(m);}
public void clear() {
cacheKey = null;
cacheValue = null;
backingMap.clear();
}
public Set<K> keySet() {return backingMap.keySet();}
public Collection<V> values() {return backingMap.values();}
public Set<Entry<K, V>> entrySet() {return backingMap.entrySet();}
/**
* Wraps the specified map with a most recently used cache
* @param map
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> of(Map<K, V> map) {
return new MRUMapCache<K, V>(map);
}
}

View File

@ -0,0 +1,69 @@
package org.bukkit;
/**
* Represents an achievement, which may be given to players.
*/
public enum Achievement {
OPEN_INVENTORY,
MINE_WOOD (OPEN_INVENTORY),
BUILD_WORKBENCH (MINE_WOOD),
BUILD_PICKAXE (BUILD_WORKBENCH),
BUILD_FURNACE (BUILD_PICKAXE),
ACQUIRE_IRON (BUILD_FURNACE),
BUILD_HOE (BUILD_WORKBENCH),
MAKE_BREAD (BUILD_HOE),
BAKE_CAKE (BUILD_HOE),
BUILD_BETTER_PICKAXE (BUILD_PICKAXE),
COOK_FISH (BUILD_FURNACE),
ON_A_RAIL (ACQUIRE_IRON),
BUILD_SWORD (BUILD_WORKBENCH),
KILL_ENEMY (BUILD_SWORD),
KILL_COW (BUILD_SWORD),
FLY_PIG (KILL_COW),
SNIPE_SKELETON (KILL_ENEMY),
GET_DIAMONDS (ACQUIRE_IRON),
NETHER_PORTAL (GET_DIAMONDS),
GHAST_RETURN (NETHER_PORTAL),
GET_BLAZE_ROD (NETHER_PORTAL),
BREW_POTION (GET_BLAZE_ROD),
END_PORTAL (GET_BLAZE_ROD),
THE_END (END_PORTAL),
ENCHANTMENTS (GET_DIAMONDS),
OVERKILL (ENCHANTMENTS),
BOOKCASE (ENCHANTMENTS),
EXPLORE_ALL_BIOMES (END_PORTAL),
SPAWN_WITHER (THE_END),
KILL_WITHER (SPAWN_WITHER),
FULL_BEACON (KILL_WITHER),
BREED_COW (KILL_COW),
DIAMONDS_TO_YOU (GET_DIAMONDS),
;
private final Achievement parent;
private Achievement() {
parent = null;
}
private Achievement(Achievement parent) {
this.parent = parent;
}
/**
* Returns whether or not this achievement has a parent achievement.
*
* @return whether the achievement has a parent achievement
*/
public boolean hasParent() {
return parent != null;
}
/**
* Returns the parent achievement of this achievement, or null if none.
*
* @return the parent achievement or null
*/
public Achievement getParent() {
return parent;
}
}

View File

@ -0,0 +1,111 @@
package org.bukkit;
import java.util.HashMap;
import org.apache.commons.lang.Validate;
import com.google.common.collect.Maps;
/**
* Represents the art on a painting
*/
public enum Art {
KEBAB(0, 1, 1),
AZTEC(1, 1, 1),
ALBAN(2, 1, 1),
AZTEC2(3, 1, 1),
BOMB(4, 1, 1),
PLANT(5, 1, 1),
WASTELAND(6, 1, 1),
POOL(7, 2, 1),
COURBET(8, 2, 1),
SEA(9, 2, 1),
SUNSET(10, 2, 1),
CREEBET(11, 2, 1),
WANDERER(12, 1, 2),
GRAHAM(13, 1, 2),
MATCH(14, 2, 2),
BUST(15, 2, 2),
STAGE(16, 2, 2),
VOID(17, 2, 2),
SKULL_AND_ROSES(18, 2, 2),
WITHER(19, 2, 2),
FIGHTERS(20, 4, 2),
POINTER(21, 4, 4),
PIGSCENE(22, 4, 4),
BURNINGSKULL(23, 4, 4),
SKELETON(24, 4, 3),
DONKEYKONG(25, 4, 3);
private int id, width, height;
private static final HashMap<String, Art> BY_NAME = Maps.newHashMap();
private static final HashMap<Integer, Art> BY_ID = Maps.newHashMap();
private Art(int id, int width, int height) {
this.id = id;
this.width = width;
this.height = height;
}
/**
* Gets the width of the painting, in blocks
*
* @return The width of the painting, in blocks
*/
public int getBlockWidth() {
return width;
}
/**
* Gets the height of the painting, in blocks
*
* @return The height of the painting, in blocks
*/
public int getBlockHeight() {
return height;
}
/**
* Get the ID of this painting.
*
* @return The ID of this painting
* @deprecated Magic value
*/
@Deprecated
public int getId() {
return id;
}
/**
* Get a painting by its numeric ID
*
* @param id The ID
* @return The painting
* @deprecated Magic value
*/
@Deprecated
public static Art getById(int id) {
return BY_ID.get(id);
}
/**
* Get a painting by its unique name
* <p>
* This ignores underscores and capitalization
*
* @param name The name
* @return The painting
*/
public static Art getByName(String name) {
Validate.notNull(name, "Name cannot be null");
return BY_NAME.get(name.toLowerCase().replaceAll("_", ""));
}
static {
for (Art art : values()) {
BY_ID.put(art.id, art);
BY_NAME.put(art.toString().toLowerCase().replaceAll("_", ""), art);
}
}
}

View File

@ -0,0 +1,111 @@
package org.bukkit;
/**
* A static representation of the bounding box of some Entity or Block
*/
public class AxisAlignedBB {
private final double minX;
private final double minY;
private final double minZ;
private final double maxX;
private final double maxY;
private final double maxZ;
public AxisAlignedBB(double minX, double minY, double minZ,
double maxX, double maxY, double maxZ) {
this.minX = minX;
this.minY = minY;
this.minZ = minZ;
this.maxX = maxX;
this.maxY = maxY;
this.maxZ = maxZ;
}
/**
* Gets the minimum x-coordinate of this bounding box.
*
* @return minimum x-coordinate
*/
public double getMinX() {
return minX;
}
/**
* Gets the minimum y-coordinate of this bounding box.
*
* @return minimum y-coordinate
*/
public double getMinY() {
return minY;
}
/**
* Gets the minimum z-coordinate of this bounding box.
*
* @return minimum z-coordinate
*/
public double getMinZ() {
return minZ;
}
/**
* Gets the maximum x-coordinate of this bounding box.
*
* @return maximum x-coordinate
*/
public double getMaxX() {
return maxX;
}
/**
* Gets the maximum y-coordinate of this bounding box.
*
* @return maximum y-coordinate
*/
public double getMaxY() {
return maxY;
}
/**
* Gets the minimum z-coordinate of this bounding box.
*
* @return maximum z-coordinate
*/
public double getMaxZ() {
return maxZ;
}
@Override
public int hashCode() {
int hash = 3;
hash = 19 * hash + (int) (Double.doubleToLongBits(this.minX) ^ (Double.doubleToLongBits(this.minX) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.minY) ^ (Double.doubleToLongBits(this.minY) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.minZ) ^ (Double.doubleToLongBits(this.minZ) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.maxX) ^ (Double.doubleToLongBits(this.maxX) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.maxY) ^ (Double.doubleToLongBits(this.maxY) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.maxZ) ^ (Double.doubleToLongBits(this.maxZ) >>> 32));
return hash;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (!(other instanceof AxisAlignedBB)) {
return false;
}
AxisAlignedBB aabb = (AxisAlignedBB) other;
return Double.compare(aabb.minX, minX) == 0
&& Double.compare(aabb.minY, minY) == 0
&& Double.compare(aabb.minZ, minZ) == 0
&& Double.compare(aabb.maxX, maxX) == 0
&& Double.compare(aabb.maxY, maxY) == 0
&& Double.compare(aabb.maxZ, maxZ) == 0;
}
@Override
public String toString() {
return "AxisAlignedBB[" + minX + ", " + minY + ", " + minZ + " -> " + maxX + ", " + maxY + ", " + maxZ + "]";
}
}

View File

@ -0,0 +1,127 @@
package org.bukkit;
import java.util.Date;
/**
* A single entry from a ban list. This may represent either a player ban or
* an IP ban.
* <p>
* Ban entries include the following properties:
* <table border=1>
* <tr>
* <th>Property</th>
* <th>Description</th>
* </tr><tr>
* <td>Target Name / IP Address</td>
* <td>The target name or IP address</td>
* </tr><tr>
* <td>Creation Date</td>
* <td>The creation date of the ban</td>
* </tr><tr>
* <td>Source</td>
* <td>The source of the ban, such as a player, console, plugin, etc</td>
* </tr><tr>
* <td>Expiration Date</td>
* <td>The expiration date of the ban</td>
* </tr><tr>
* <td>Reason</td>
* <td>The reason for the ban</td>
* </tr>
* </table>
* <p>
* Unsaved information is not automatically written to the implementation's
* ban list, instead, the {@link #save()} method must be called to write the
* changes to the ban list. If this ban entry has expired (such as from an
* unban) and is no longer found in the list, the {@link #save()} call will
* re-add it to the list, therefore banning the victim specified.
* <p>
* Likewise, changes to the associated {@link BanList} or other entries may or
* may not be reflected in this entry.
*/
public interface BanEntry {
/**
* Gets the target involved. This may be in the form of an IP or a player
* name.
*
* @return the target name or IP address
*/
public String getTarget();
/**
* Gets the date this ban entry was created.
*
* @return the creation date
*/
public Date getCreated();
/**
* Sets the date this ban entry was created.
*
* @param created the new created date, cannot be null
* @see #save() saving changes
*/
public void setCreated(Date created);
/**
* Gets the source of this ban.
* <p>
* Note: A source is considered any String, although this is generally a
* player name.
*
* @return the source of the ban
*/
public String getSource();
/**
* Sets the source of this ban.
* <p>
* Note: A source is considered any String, although this is generally a
* player name.
*
* @param source the new source where null values become empty strings
* @see #save() saving changes
*/
public void setSource(String source);
/**
* Gets the date this ban expires on, or null for no defined end date.
*
* @return the expiration date
*/
public Date getExpiration();
/**
* Sets the date this ban expires on. Null values are considered
* "infinite" bans.
*
* @param expiration the new expiration date, or null to indicate an
* eternity
* @see #save() saving changes
*/
public void setExpiration(Date expiration);
/**
* Gets the reason for this ban.
*
* @return the ban reason, or null if not set
*/
public String getReason();
/**
* Sets the reason for this ban. Reasons must not be null.
*
* @param reason the new reason, null values assume the implementation
* default
* @see #save() saving changes
*/
public void setReason(String reason);
/**
* Saves the ban entry, overwriting any previous data in the ban list.
* <p>
* Saving the ban entry of an unbanned player will cause the player to be
* banned once again.
*/
public void save();
}

View File

@ -0,0 +1,72 @@
package org.bukkit;
import java.util.Date;
import java.util.Set;
/**
* A ban list, containing bans of some {@link Type}.
*/
public interface BanList {
/**
* Represents a ban-type that a {@link BanList} may track.
*/
public enum Type {
/**
* Banned player names
*/
NAME,
/**
* Banned player IP addresses
*/
IP,
;
}
/**
* Gets a {@link BanEntry} by target.
*
* @param target entry parameter to search for
* @return the corresponding entry, or null if none found
*/
public BanEntry getBanEntry(String target);
/**
* Adds a ban to the this list. If a previous ban exists, this will
* update the previous entry.
*
* @param target the target of the ban
* @param reason reason for the ban, null indicates implementation default
* @param expires date for the ban's expiration (unban), or null to imply
* forever
* @param source source of the ban, null indicates implementation default
* @return the entry for the newly created ban, or the entry for the
* (updated) previous ban
*/
public BanEntry addBan(String target, String reason, Date expires, String source);
/**
* Gets a set containing every {@link BanEntry} in this list.
*
* @return an immutable set containing every entry tracked by this list
*/
public Set<BanEntry> getBanEntries();
/**
* Gets if a {@link BanEntry} exists for the target, indicating an active
* ban status.
*
* @param target the target to find
* @return true if a {@link BanEntry} exists for the name, indicating an
* active ban status, false otherwise
*/
public boolean isBanned(String target);
/**
* Removes the specified target from this list, therefore indicating a
* "not banned" status.
*
* @param target the target to remove from this list
*/
public void pardon(String target);
}

View File

@ -0,0 +1,104 @@
package org.bukkit;
/**
* A delegate for handling block changes. This serves as a direct interface
* between generation algorithms in the server implementation and utilizing
* code.
*/
public interface BlockChangeDelegate {
/**
* Set a block type at the specified coordinates without doing all world
* updates and notifications.
* <p>
* It is safe to have this call World.setTypeId, but it may be slower than
* World.setRawTypeId.
*
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @param typeId New block ID
* @return true if the block was set successfully
* @deprecated Magic value
*/
@Deprecated
public boolean setRawTypeId(int x, int y, int z, int typeId);
/**
* Set a block type and data at the specified coordinates without doing
* all world updates and notifications.
* <p>
* It is safe to have this call World.setTypeId, but it may be slower than
* World.setRawTypeId.
*
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @param typeId New block ID
* @param data Block data
* @return true if the block was set successfully
* @deprecated Magic value
*/
@Deprecated
public boolean setRawTypeIdAndData(int x, int y, int z, int typeId, int data);
/**
* Set a block type at the specified coordinates.
* <p>
* This method cannot call World.setRawTypeId, a full update is needed.
*
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @param typeId New block ID
* @return true if the block was set successfully
* @deprecated Magic value
*/
@Deprecated
public boolean setTypeId(int x, int y, int z, int typeId);
/**
* Set a block type and data at the specified coordinates.
* <p>
* This method cannot call World.setRawTypeId, a full update is needed.
*
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @param typeId New block ID
* @param data Block data
* @return true if the block was set successfully
* @deprecated Magic value
*/
@Deprecated
public boolean setTypeIdAndData(int x, int y, int z, int typeId, int data);
/**
* Get the block type at the location.
*
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @return The block ID
* @deprecated Magic value
*/
@Deprecated
public int getTypeId(int x, int y, int z);
/**
* Gets the height of the world.
*
* @return Height of the world
*/
public int getHeight();
/**
* Checks if the specified block is empty (air) or not.
*
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @return True if the block is considered empty.
*/
public boolean isEmpty(int x, int y, int z);
}

View File

@ -0,0 +1,776 @@
package org.bukkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger;
import co.aikar.timings.Timings;
import org.bukkit.Warning.WarningState;
import org.bukkit.command.CommandException;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.help.HelpMap;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.Recipe;
import org.bukkit.map.MapView;
import org.bukkit.metadata.MetadataStore;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicesManager;
import org.bukkit.plugin.messaging.Messenger;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scoreboard.ScoreboardManager;
import org.bukkit.util.CachedServerIcon;
import com.avaje.ebean.config.ServerConfig;
/**
* Represents the Bukkit core, for version and Server singleton handling
*/
public final class Bukkit {
private static Server server;
/**
* Static class cannot be initialized.
*/
private Bukkit() {}
/**
* Gets the current {@link Server} singleton
*
* @return Server instance being ran
*/
public static Server getServer() {
return server;
}
/**
* Attempts to set the {@link Server} singleton.
* <p>
* This cannot be done if the Server is already set.
*
* @param server Server instance
*/
public static void setServer(Server server) {
if (Bukkit.server != null) {
throw new UnsupportedOperationException("Cannot redefine singleton Server");
}
Bukkit.server = server;
server.getLogger().info("This server is running " + getName() + " version " + getVersion() + " (Implementing API version " + getBukkitVersion() + ")");
}
/**
* @see Server#getName()
*/
public static String getName() {
return server.getName();
}
/**
* @see Server#getVersion()
*/
public static String getVersion() {
return server.getVersion();
}
/**
* @see Server#getBukkitVersion()
*/
public static String getBukkitVersion() {
return server.getBukkitVersion();
}
/**
* This method exists for legacy reasons to provide backwards
* compatibility. It will not exist at runtime and should not be used
* under any circumstances.
*
* @Deprecated
* @see Server#_INVALID_getOnlinePlayers()
*/
@Deprecated
public static Player[] _INVALID_getOnlinePlayers() {
return server._INVALID_getOnlinePlayers();
}
/**
* @see Server#getOnlinePlayers()
*/
public static Collection<? extends Player> getOnlinePlayers() {
return server.getOnlinePlayers();
}
/**
* @see Server#getMaxPlayers()
*/
public static int getMaxPlayers() {
return server.getMaxPlayers();
}
/**
* @see Server#getPort()
*/
public static int getPort() {
return server.getPort();
}
/**
* @see Server#getViewDistance()
*/
public static int getViewDistance() {
return server.getViewDistance();
}
/**
* @see Server#getIp()
*/
public static String getIp() {
return server.getIp();
}
/**
* @see Server#getServerName()
*/
public static String getServerName() {
return server.getServerName();
}
/**
* @see Server#getServerId()
*/
public static String getServerId() {
return server.getServerId();
}
/**
* @see Server#getWorldType()
*/
public static String getWorldType() {
return server.getWorldType();
}
/**
* @see Server#getGenerateStructures()
*/
public static boolean getGenerateStructures() {
return server.getGenerateStructures();
}
/**
* @see Server#getAllowNether()
*/
public static boolean getAllowNether() {
return server.getAllowNether();
}
/**
* @see Server#hasWhitelist()
*/
public static boolean hasWhitelist() {
return server.hasWhitelist();
}
/**
* @see Server#broadcastMessage(String message)
*/
public static int broadcastMessage(String message) {
return server.broadcastMessage(message);
}
/**
* @see Server#getUpdateFolder()
*/
public static String getUpdateFolder() {
return server.getUpdateFolder();
}
/**
* @see Server#getPlayer(String name)
*/
public static Player getPlayer(String name) {
return server.getPlayer(name);
}
/**
* @see Server#matchPlayer(String name)
*/
public static List<Player> matchPlayer(String name) {
return server.matchPlayer(name);
}
/**
* @see Server#getPlayer(java.util.UUID)
*/
public static Player getPlayer(UUID id) {
return server.getPlayer(id);
}
/**
* @see Server#getPluginManager()
*/
public static PluginManager getPluginManager() {
return server.getPluginManager();
}
/**
* @see Server#getScheduler()
*/
public static BukkitScheduler getScheduler() {
return server.getScheduler();
}
/**
* @see Server#getServicesManager()
*/
public static ServicesManager getServicesManager() {
return server.getServicesManager();
}
/**
* @see Server#getWorlds()
*/
public static List<World> getWorlds() {
return server.getWorlds();
}
/**
* @see Server#createWorld(WorldCreator options)
*/
public static World createWorld(WorldCreator options) {
return server.createWorld(options);
}
/**
* @see Server#unloadWorld(String name, boolean save)
*/
public static boolean unloadWorld(String name, boolean save) {
return server.unloadWorld(name, save);
}
/**
* @see Server#unloadWorld(World world, boolean save)
*/
public static boolean unloadWorld(World world, boolean save) {
return server.unloadWorld(world, save);
}
/**
* @see Server#getWorld(String name)
*/
public static World getWorld(String name) {
return server.getWorld(name);
}
/**
* @see Server#getWorld(UUID uid)
*/
public static World getWorld(UUID uid) {
return server.getWorld(uid);
}
/**
* @see Server#getMap(short id)
* @deprecated Magic value
*/
@Deprecated
public static MapView getMap(short id) {
return server.getMap(id);
}
/**
* @see Server#createMap(World world)
*/
public static MapView createMap(World world) {
return server.createMap(world);
}
/**
* @see Server#reload()
*/
public static void reload() {
server.reload();
}
/**
* @see Server#getLogger()
*/
public static Logger getLogger() {
return server.getLogger();
}
/**
* @see Server#getPluginCommand(String name)
*/
public static PluginCommand getPluginCommand(String name) {
return server.getPluginCommand(name);
}
/**
* @see Server#savePlayers()
*/
public static void savePlayers() {
server.savePlayers();
}
/**
* @see Server#dispatchCommand(CommandSender sender, String commandLine)
*/
public static boolean dispatchCommand(CommandSender sender, String commandLine) throws CommandException {
return server.dispatchCommand(sender, commandLine);
}
/**
* @see Server#configureDbConfig(ServerConfig config)
*/
public static void configureDbConfig(ServerConfig config) {
server.configureDbConfig(config);
}
/**
* @see Server#addRecipe(Recipe recipe)
*/
public static boolean addRecipe(Recipe recipe) {
return server.addRecipe(recipe);
}
/**
* @see Server#getRecipesFor(ItemStack result)
*/
public static List<Recipe> getRecipesFor(ItemStack result) {
return server.getRecipesFor(result);
}
/**
* @see Server#recipeIterator()
*/
public static Iterator<Recipe> recipeIterator() {
return server.recipeIterator();
}
/**
* @see Server#clearRecipes()
*/
public static void clearRecipes() {
server.clearRecipes();
}
/**
* @see Server#resetRecipes()
*/
public static void resetRecipes() {
server.resetRecipes();
}
/**
* @see Server#getCommandAliases()
*/
public static Map<String, String[]> getCommandAliases() {
return server.getCommandAliases();
}
/**
* @see Server#getSpawnRadius()
*/
public static int getSpawnRadius() {
return server.getSpawnRadius();
}
/**
* @see Server#setSpawnRadius(int value)
*/
public static void setSpawnRadius(int value) {
server.setSpawnRadius(value);
}
/**
* @see Server#getOnlineMode()
*/
public static boolean getOnlineMode() {
return server.getOnlineMode();
}
/**
* @see Server#getAllowFlight()
*/
public static boolean getAllowFlight() {
return server.getAllowFlight();
}
/**
* @see Server#isHardcore()
*/
public static boolean isHardcore() {
return server.isHardcore();
}
/**
* @see Server#shutdown()
*/
public static void shutdown() {
server.shutdown();
}
/**
* @see Server#broadcast(String message, String permission)
*/
public static int broadcast(String message, String permission) {
return server.broadcast(message, permission);
}
/**
* @see Server#getOfflinePlayer(String name)
*/
@Deprecated
public static OfflinePlayer getOfflinePlayer(String name) {
return server.getOfflinePlayer(name);
}
/**
* @see Server#getOfflinePlayer(java.util.UUID)
*/
public static OfflinePlayer getOfflinePlayer(UUID id) {
return server.getOfflinePlayer(id);
}
/**
* @see Server#getPlayerExact(String name)
*/
public static Player getPlayerExact(String name) {
return server.getPlayerExact(name);
}
/**
* @see Server#getIPBans()
*/
public static Set<String> getIPBans() {
return server.getIPBans();
}
/**
* @see Server#banIP(String address)
*/
public static void banIP(String address) {
server.banIP(address);
}
/**
* @see Server#unbanIP(String address)
*/
public static void unbanIP(String address) {
server.unbanIP(address);
}
/**
* @see Server#getBannedPlayers()
*/
public static Set<OfflinePlayer> getBannedPlayers() {
return server.getBannedPlayers();
}
/**
* @see Server#getBanList(BanList.Type)
*/
public static BanList getBanList(BanList.Type type){
return server.getBanList(type);
}
/**
* @see Server#setWhitelist(boolean value)
*/
public static void setWhitelist(boolean value) {
server.setWhitelist(value);
}
/**
* @see Server#getWhitelistedPlayers()
*/
public static Set<OfflinePlayer> getWhitelistedPlayers() {
return server.getWhitelistedPlayers();
}
/**
* @see Server#reloadWhitelist()
*/
public static void reloadWhitelist() {
server.reloadWhitelist();
}
/**
* @see Server#getConsoleSender()
*/
public static ConsoleCommandSender getConsoleSender() {
return server.getConsoleSender();
}
/**
* @see Server#getOperators()
*/
public static Set<OfflinePlayer> getOperators() {
return server.getOperators();
}
/**
* @see Server#getEntityMetadata()
*/
public static MetadataStore<Entity> getEntityMetadata() {
return server.getEntityMetadata();
}
/**
* @see Server#getPlayerMetadata()
*/
public static MetadataStore<OfflinePlayer> getPlayerMetadata() {
return server.getPlayerMetadata();
}
/**
* @see Server#getWorldMetadata()
*/
public static MetadataStore<World> getWorldMetadata() {
return server.getWorldMetadata();
}
/**
* @see Server#getWorldContainer()
*/
public static File getWorldContainer() {
return server.getWorldContainer();
}
/**
* @see Server#getMessenger()
*/
public static Messenger getMessenger() {
return server.getMessenger();
}
/**
* @see Server#getAllowEnd()
*/
public static boolean getAllowEnd() {
return server.getAllowEnd();
}
/**
* @see Server#getUpdateFolderFile()
*/
public static File getUpdateFolderFile() {
return server.getUpdateFolderFile();
}
/**
* @see Server#getConnectionThrottle()
*/
public static long getConnectionThrottle() {
return server.getConnectionThrottle();
}
/**
* @see Server#getTicksPerAnimalSpawns()
*/
public static int getTicksPerAnimalSpawns() {
return server.getTicksPerAnimalSpawns();
}
/**
* @see Server#getTicksPerMonsterSpawns()
*/
public static int getTicksPerMonsterSpawns() {
return server.getTicksPerMonsterSpawns();
}
/**
* @see Server#useExactLoginLocation()
*/
public static boolean useExactLoginLocation() {
return server.useExactLoginLocation();
}
/**
* @see Server#getDefaultGameMode()
*/
public static GameMode getDefaultGameMode() {
return server.getDefaultGameMode();
}
/**
* @see Server#setDefaultGameMode(GameMode mode)
*/
public static void setDefaultGameMode(GameMode mode) {
server.setDefaultGameMode(mode);
}
/**
* @see Server#getOfflinePlayers()
*/
public static OfflinePlayer[] getOfflinePlayers() {
return server.getOfflinePlayers();
}
/**
* @see Server#createInventory(InventoryHolder owner, InventoryType type)
*/
public static Inventory createInventory(InventoryHolder owner, InventoryType type) {
return server.createInventory(owner, type);
}
/**
* @see Server#createInventory(InventoryHolder owner, InventoryType type, String title)
*/
public static Inventory createInventory(InventoryHolder owner, InventoryType type, String title) {
return server.createInventory(owner, type, title);
}
/**
* @see Server#createInventory(InventoryHolder owner, int size)
*/
public static Inventory createInventory(InventoryHolder owner, int size) throws IllegalArgumentException {
return server.createInventory(owner, size);
}
/**
* @see Server#createInventory(InventoryHolder owner, int size, String
* title)
*/
public static Inventory createInventory(InventoryHolder owner, int size, String title) throws IllegalArgumentException {
return server.createInventory(owner, size, title);
}
/**
* @see Server#getHelpMap()
*/
public static HelpMap getHelpMap() {
return server.getHelpMap();
}
/**
* @see Server#getMonsterSpawnLimit()
*/
public static int getMonsterSpawnLimit() {
return server.getMonsterSpawnLimit();
}
/**
* @see Server#getAnimalSpawnLimit()
*/
public static int getAnimalSpawnLimit() {
return server.getAnimalSpawnLimit();
}
/**
* @see Server#getWaterAnimalSpawnLimit()
*/
public static int getWaterAnimalSpawnLimit() {
return server.getWaterAnimalSpawnLimit();
}
/**
* @see Server#getAmbientSpawnLimit()
*/
public static int getAmbientSpawnLimit() {
return server.getAmbientSpawnLimit();
}
/**
* @see Server#isPrimaryThread()
*/
public static boolean isPrimaryThread() {
return server.isPrimaryThread();
}
/**
* @see Server#getMotd()
*/
public static String getMotd() {
return server.getMotd();
}
/**
* @see Server#getShutdownMessage()
*/
public static String getShutdownMessage() {
return server.getShutdownMessage();
}
/**
* @see Server#getWarningState()
*/
public static WarningState getWarningState() {
return server.getWarningState();
}
/**
* @see Server#getItemFactory()
*/
public static ItemFactory getItemFactory() {
return server.getItemFactory();
}
/**
* @see Server#getScoreboardManager()
*/
public static ScoreboardManager getScoreboardManager() {
return server.getScoreboardManager();
}
/**
* @see Server#getServerIcon()
*/
public static CachedServerIcon getServerIcon() {
return server.getServerIcon();
}
/**
* @see Server#loadServerIcon(File)
*/
public static CachedServerIcon loadServerIcon(File file) throws IllegalArgumentException, Exception {
return server.loadServerIcon(file);
}
/**
* @see Server#loadServerIcon(BufferedImage)
*/
public static CachedServerIcon loadServerIcon(BufferedImage image) throws IllegalArgumentException, Exception {
return server.loadServerIcon(image);
}
/**
* @see Server#setIdleTimeout(int)
*/
public static void setIdleTimeout(int threshold) {
server.setIdleTimeout(threshold);
}
/**
* @see Server#getIdleTimeout()
*/
public static int getIdleTimeout() {
return server.getIdleTimeout();
}
/**
* @see Server#getUnsafe()
*/
@Deprecated
public static UnsafeValues getUnsafe() {
return server.getUnsafe();
}
public static Server.Spigot spigot()
{
return server.spigot();
}
}

View File

@ -0,0 +1,253 @@
package org.bukkit;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.lang.Validate;
import com.google.common.collect.Maps;
/**
* All supported color values for chat
*/
public enum ChatColor {
/**
* Represents black
*/
BLACK('0', 0x00),
/**
* Represents dark blue
*/
DARK_BLUE('1', 0x1),
/**
* Represents dark green
*/
DARK_GREEN('2', 0x2),
/**
* Represents dark blue (aqua)
*/
DARK_AQUA('3', 0x3),
/**
* Represents dark red
*/
DARK_RED('4', 0x4),
/**
* Represents dark purple
*/
DARK_PURPLE('5', 0x5),
/**
* Represents gold
*/
GOLD('6', 0x6),
/**
* Represents gray
*/
GRAY('7', 0x7),
/**
* Represents dark gray
*/
DARK_GRAY('8', 0x8),
/**
* Represents blue
*/
BLUE('9', 0x9),
/**
* Represents green
*/
GREEN('a', 0xA),
/**
* Represents aqua
*/
AQUA('b', 0xB),
/**
* Represents red
*/
RED('c', 0xC),
/**
* Represents light purple
*/
LIGHT_PURPLE('d', 0xD),
/**
* Represents yellow
*/
YELLOW('e', 0xE),
/**
* Represents white
*/
WHITE('f', 0xF),
/**
* Represents magical characters that change around randomly
*/
MAGIC('k', 0x10, true),
/**
* Makes the text bold.
*/
BOLD('l', 0x11, true),
/**
* Makes a line appear through the text.
*/
STRIKETHROUGH('m', 0x12, true),
/**
* Makes the text appear underlined.
*/
UNDERLINE('n', 0x13, true),
/**
* Makes the text italic.
*/
ITALIC('o', 0x14, true),
/**
* Resets all previous chat colors or formats.
*/
RESET('r', 0x15);
/**
* The special character which prefixes all chat colour codes. Use this if
* you need to dynamically convert colour codes from your custom format.
*/
public static final char COLOR_CHAR = '\u00A7';
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
private final int intCode;
private final char code;
private final boolean isFormat;
private final String toString;
private final static Map<Integer, ChatColor> BY_ID = Maps.newHashMap();
private final static Map<Character, ChatColor> BY_CHAR = Maps.newHashMap();
private ChatColor(char code, int intCode) {
this(code, intCode, false);
}
private ChatColor(char code, int intCode, boolean isFormat) {
this.code = code;
this.intCode = intCode;
this.isFormat = isFormat;
this.toString = new String(new char[] {COLOR_CHAR, code});
}
/**
* Gets the char value associated with this color
*
* @return A char value of this color code
*/
public char getChar() {
return code;
}
@Override
public String toString() {
return toString;
}
/**
* Checks if this code is a format code as opposed to a color code.
*/
public boolean isFormat() {
return isFormat;
}
/**
* Checks if this code is a color code as opposed to a format code.
*/
public boolean isColor() {
return !isFormat && this != RESET;
}
/**
* Gets the color represented by the specified color code
*
* @param code Code to check
* @return Associative {@link org.bukkit.ChatColor} with the given code,
* or null if it doesn't exist
*/
public static ChatColor getByChar(char code) {
return BY_CHAR.get(code);
}
/**
* Gets the color represented by the specified color code
*
* @param code Code to check
* @return Associative {@link org.bukkit.ChatColor} with the given code,
* or null if it doesn't exist
*/
public static ChatColor getByChar(String code) {
Validate.notNull(code, "Code cannot be null");
Validate.isTrue(code.length() > 0, "Code must have at least one char");
return BY_CHAR.get(code.charAt(0));
}
/**
* Strips the given message of all color codes
*
* @param input String to strip of color
* @return A copy of the input string, without any coloring
*/
public static String stripColor(final String input) {
if (input == null) {
return null;
}
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
}
/**
* Translates a string using an alternate color code character into a
* string that uses the internal ChatColor.COLOR_CODE color code
* character. The alternate color code character will only be replaced if
* it is immediately followed by 0-9, A-F, a-f, K-O, k-o, R or r.
*
* @param altColorChar The alternate color code character to replace. Ex: &
* @param textToTranslate Text containing the alternate color code character.
* @return Text containing the ChatColor.COLOR_CODE color code character.
*/
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
char[] b = textToTranslate.toCharArray();
for (int i = 0; i < b.length - 1; i++) {
if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) {
b[i] = ChatColor.COLOR_CHAR;
b[i+1] = Character.toLowerCase(b[i+1]);
}
}
return new String(b);
}
/**
* Gets the ChatColors used at the end of the given input string.
*
* @param input Input string to retrieve the colors from.
* @return Any remaining ChatColors to pass onto the next line.
*/
public static String getLastColors(String input) {
String result = "";
int length = input.length();
// Search backwards from the end as it is faster
for (int index = length - 1; index > -1; index--) {
char section = input.charAt(index);
if (section == COLOR_CHAR && index < length - 1) {
char c = input.charAt(index + 1);
ChatColor color = getByChar(c);
if (color != null) {
result = color.toString() + result;
// Once we find a color or reset we can stop searching
if (color.isColor() || color.equals(RESET)) {
break;
}
}
}
}
return result;
}
static {
for (ChatColor color : values()) {
BY_ID.put(color.intCode, color);
BY_CHAR.put(color.code, color);
}
}
}

View File

@ -0,0 +1,124 @@
package org.bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
/**
* Represents a chunk of blocks
*/
public interface Chunk {
/**
* Gets the X-coordinate of this chunk
*
* @return X-coordinate
*/
int getX();
/**
* Gets the Z-coordinate of this chunk
*
* @return Z-coordinate
*/
int getZ();
/**
* Gets the world containing this chunk
*
* @return Parent World
*/
World getWorld();
/**
* Gets a block from this chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return the Block
*/
Block getBlock(int x, int y, int z);
/**
* Capture thread-safe read-only snapshot of chunk data
*
* @return ChunkSnapshot
*/
ChunkSnapshot getChunkSnapshot();
/**
* Capture thread-safe read-only snapshot of chunk data
*
* @param includeMaxblocky - if true, snapshot includes per-coordinate
* maximum Y values
* @param includeBiome - if true, snapshot includes per-coordinate biome
* type
* @param includeBiomeTempRain - if true, snapshot includes per-coordinate
* raw biome temperature and rainfall
* @return ChunkSnapshot
*/
ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain);
/**
* Get a list of all entities in the chunk.
*
* @return The entities.
*/
Entity[] getEntities();
/**
* Get a list of all tile entities in the chunk.
*
* @return The tile entities.
*/
BlockState[] getTileEntities();
/**
* Checks if the chunk is loaded.
*
* @return True if it is loaded.
*/
boolean isLoaded();
/**
* Loads the chunk.
*
* @param generate Whether or not to generate a chunk if it doesn't
* already exist
* @return true if the chunk has loaded successfully, otherwise false
*/
boolean load(boolean generate);
/**
* Loads the chunk.
*
* @return true if the chunk has loaded successfully, otherwise false
*/
boolean load();
/**
* Unloads and optionally saves the Chunk
*
* @param save Controls whether the chunk is saved
* @param safe Controls whether to unload the chunk when players are
* nearby
* @return true if the chunk has unloaded successfully, otherwise false
*/
boolean unload(boolean save, boolean safe);
/**
* Unloads and optionally saves the Chunk
*
* @param save Controls whether the chunk is saved
* @return true if the chunk has unloaded successfully, otherwise false
*/
boolean unload(boolean save);
/**
* Unloads and optionally saves the Chunk
*
* @return true if the chunk has unloaded successfully, otherwise false
*/
boolean unload();
}

View File

@ -0,0 +1,129 @@
package org.bukkit;
import org.bukkit.block.Biome;
/**
* Represents a static, thread-safe snapshot of chunk of blocks.
* <p>
* Purpose is to allow clean, efficient copy of a chunk data to be made, and
* then handed off for processing in another thread (e.g. map rendering)
*/
public interface ChunkSnapshot {
/**
* Gets the X-coordinate of this chunk
*
* @return X-coordinate
*/
int getX();
/**
* Gets the Z-coordinate of this chunk
*
* @return Z-coordinate
*/
int getZ();
/**
* Gets name of the world containing this chunk
*
* @return Parent World Name
*/
String getWorldName();
/**
* Get block type for block at corresponding coordinate in the chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-255
* @deprecated Magic value
*/
@Deprecated
int getBlockTypeId(int x, int y, int z);
/**
* Get block data for block at corresponding coordinate in the chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-15
* @deprecated Magic value
*/
@Deprecated
int getBlockData(int x, int y, int z);
/**
* Get sky light level for block at corresponding coordinate in the chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-15
*/
int getBlockSkyLight(int x, int y, int z);
/**
* Get light level emitted by block at corresponding coordinate in the
* chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-15
*/
int getBlockEmittedLight(int x, int y, int z);
/**
* Gets the highest non-air coordinate at the given coordinates
*
* @param x X-coordinate of the blocks
* @param z Z-coordinate of the blocks
* @return Y-coordinate of the highest non-air block
*/
int getHighestBlockYAt(int x, int z);
/**
* Get biome at given coordinates
*
* @param x X-coordinate
* @param z Z-coordinate
* @return Biome at given coordinate
*/
Biome getBiome(int x, int z);
/**
* Get raw biome temperature (0.0-1.0) at given coordinate
*
* @param x X-coordinate
* @param z Z-coordinate
* @return temperature at given coordinate
*/
double getRawBiomeTemperature(int x, int z);
/**
* Get raw biome rainfall (0.0-1.0) at given coordinate
*
* @param x X-coordinate
* @param z Z-coordinate
* @return rainfall at given coordinate
*/
double getRawBiomeRainfall(int x, int z);
/**
* Get world full time when chunk snapshot was captured
*
* @return time in ticks
*/
long getCaptureFullTime();
/**
* Test if section is empty
*
* @param sy - section Y coordinate (block Y / 16)
* @return true if empty, false if not
*/
boolean isSectionEmpty(int sy);
}

View File

@ -0,0 +1,50 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* Represents the two types of coal
*/
public enum CoalType {
COAL(0x0),
CHARCOAL(0x1);
private final byte data;
private final static Map<Byte, CoalType> BY_DATA = Maps.newHashMap();
private CoalType(final int data) {
this.data = (byte) data;
}
/**
* Gets the associated data value representing this type of coal
*
* @return A byte containing the data value of this coal type
* @deprecated Magic value
*/
@Deprecated
public byte getData() {
return data;
}
/**
* Gets the type of coal with the given data value
*
* @param data Data value to fetch
* @return The {@link CoalType} representing the given value, or null if
* it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static CoalType getByData(final byte data) {
return BY_DATA.get(data);
}
static {
for (CoalType type : values()) {
BY_DATA.put(type.data, type);
}
}
}

View File

@ -0,0 +1,344 @@
package org.bukkit;
import java.util.Map;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;
import com.google.common.collect.ImmutableMap;
/**
* A container for a color palette. This class is immutable; the set methods
* return a new color. The color names listed as fields are HTML4 standards,
* but subject to change.
*/
@SerializableAs("Color")
public final class Color implements ConfigurationSerializable {
private static final int BIT_MASK = 0xff;
/**
* White, or (0xFF,0xFF,0xFF) in (R,G,B)
*/
public static final Color WHITE = fromRGB(0xFFFFFF);
/**
* Silver, or (0xC0,0xC0,0xC0) in (R,G,B)
*/
public static final Color SILVER = fromRGB(0xC0C0C0);
/**
* Gray, or (0x80,0x80,0x80) in (R,G,B)
*/
public static final Color GRAY = fromRGB(0x808080);
/**
* Black, or (0x00,0x00,0x00) in (R,G,B)
*/
public static final Color BLACK = fromRGB(0x000000);
/**
* Red, or (0xFF,0x00,0x00) in (R,G,B)
*/
public static final Color RED = fromRGB(0xFF0000);
/**
* Maroon, or (0x80,0x00,0x00) in (R,G,B)
*/
public static final Color MAROON = fromRGB(0x800000);
/**
* Yellow, or (0xFF,0xFF,0x00) in (R,G,B)
*/
public static final Color YELLOW = fromRGB(0xFFFF00);
/**
* Olive, or (0x80,0x80,0x00) in (R,G,B)
*/
public static final Color OLIVE = fromRGB(0x808000);
/**
* Lime, or (0x00,0xFF,0x00) in (R,G,B)
*/
public static final Color LIME = fromRGB(0x00FF00);
/**
* Green, or (0x00,0x80,0x00) in (R,G,B)
*/
public static final Color GREEN = fromRGB(0x008000);
/**
* Aqua, or (0x00,0xFF,0xFF) in (R,G,B)
*/
public static final Color AQUA = fromRGB(0x00FFFF);
/**
* Teal, or (0x00,0x80,0x80) in (R,G,B)
*/
public static final Color TEAL = fromRGB(0x008080);
/**
* Blue, or (0x00,0x00,0xFF) in (R,G,B)
*/
public static final Color BLUE = fromRGB(0x0000FF);
/**
* Navy, or (0x00,0x00,0x80) in (R,G,B)
*/
public static final Color NAVY = fromRGB(0x000080);
/**
* Fuchsia, or (0xFF,0x00,0xFF) in (R,G,B)
*/
public static final Color FUCHSIA = fromRGB(0xFF00FF);
/**
* Purple, or (0x80,0x00,0x80) in (R,G,B)
*/
public static final Color PURPLE = fromRGB(0x800080);
/**
* Orange, or (0xFF,0xA5,0x00) in (R,G,B)
*/
public static final Color ORANGE = fromRGB(0xFFA500);
private final byte red;
private final byte green;
private final byte blue;
/**
* Creates a new Color object from a red, green, and blue
*
* @param red integer from 0-255
* @param green integer from 0-255
* @param blue integer from 0-255
* @return a new Color object for the red, green, blue
* @throws IllegalArgumentException if any value is strictly >255 or <0
*/
public static Color fromRGB(int red, int green, int blue) throws IllegalArgumentException {
return new Color(red, green, blue);
}
/**
* Creates a new Color object from a blue, green, and red
*
* @param blue integer from 0-255
* @param green integer from 0-255
* @param red integer from 0-255
* @return a new Color object for the red, green, blue
* @throws IllegalArgumentException if any value is strictly >255 or <0
*/
public static Color fromBGR(int blue, int green, int red) throws IllegalArgumentException {
return new Color(red, green, blue);
}
/**
* Creates a new color object from an integer that contains the red,
* green, and blue bytes in the lowest order 24 bits.
*
* @param rgb the integer storing the red, green, and blue values
* @return a new color object for specified values
* @throws IllegalArgumentException if any data is in the highest order 8
* bits
*/
public static Color fromRGB(int rgb) throws IllegalArgumentException {
Validate.isTrue((rgb >> 24) == 0, "Extrenuous data in: ", rgb);
return fromRGB(rgb >> 16 & BIT_MASK, rgb >> 8 & BIT_MASK, rgb >> 0 & BIT_MASK);
}
/**
* Creates a new color object from an integer that contains the blue,
* green, and red bytes in the lowest order 24 bits.
*
* @param bgr the integer storing the blue, green, and red values
* @return a new color object for specified values
* @throws IllegalArgumentException if any data is in the highest order 8
* bits
*/
public static Color fromBGR(int bgr) throws IllegalArgumentException {
Validate.isTrue((bgr >> 24) == 0, "Extrenuous data in: ", bgr);
return fromBGR(bgr >> 16 & BIT_MASK, bgr >> 8 & BIT_MASK, bgr >> 0 & BIT_MASK);
}
private Color(int red, int green, int blue) {
Validate.isTrue(red >= 0 && red <= BIT_MASK, "Red is not between 0-255: ", red);
Validate.isTrue(green >= 0 && green <= BIT_MASK, "Green is not between 0-255: ", green);
Validate.isTrue(blue >= 0 && blue <= BIT_MASK, "Blue is not between 0-255: ", blue);
this.red = (byte) red;
this.green = (byte) green;
this.blue = (byte) blue;
}
/**
* Gets the red component
*
* @return red component, from 0 to 255
*/
public int getRed() {
return BIT_MASK & red;
}
/**
* Creates a new Color object with specified component
*
* @param red the red component, from 0 to 255
* @return a new color object with the red component
*/
public Color setRed(int red) {
return fromRGB(red, getGreen(), getBlue());
}
/**
* Gets the green component
*
* @return green component, from 0 to 255
*/
public int getGreen() {
return BIT_MASK & green;
}
/**
* Creates a new Color object with specified component
*
* @param green the red component, from 0 to 255
* @return a new color object with the red component
*/
public Color setGreen(int green) {
return fromRGB(getRed(), green, getBlue());
}
/**
* Gets the blue component
*
* @return blue component, from 0 to 255
*/
public int getBlue() {
return BIT_MASK & blue;
}
/**
* Creates a new Color object with specified component
*
* @param blue the red component, from 0 to 255
* @return a new color object with the red component
*/
public Color setBlue(int blue) {
return fromRGB(getRed(), getGreen(), blue);
}
/**
*
* @return An integer representation of this color, as 0xRRGGBB
*/
public int asRGB() {
return getRed() << 16 | getGreen() << 8 | getBlue() << 0;
}
/**
*
* @return An integer representation of this color, as 0xBBGGRR
*/
public int asBGR() {
return getBlue() << 16 | getGreen() << 8 | getRed() << 0;
}
/**
* Creates a new color with its RGB components changed as if it was dyed
* with the colors passed in, replicating vanilla workbench dyeing
*
* @param colors The DyeColors to dye with
* @return A new color with the changed rgb components
*/
// TODO: Javadoc what this method does, not what it mimics. API != Implementation
public Color mixDyes(DyeColor... colors) {
Validate.noNullElements(colors, "Colors cannot be null");
Color[] toPass = new Color[colors.length];
for (int i = 0; i < colors.length; i++) {
toPass[i] = colors[i].getColor();
}
return mixColors(toPass);
}
/**
* Creates a new color with its RGB components changed as if it was dyed
* with the colors passed in, replicating vanilla workbench dyeing
*
* @param colors The colors to dye with
* @return A new color with the changed rgb components
*/
// TODO: Javadoc what this method does, not what it mimics. API != Implementation
public Color mixColors(Color... colors) {
Validate.noNullElements(colors, "Colors cannot be null");
int totalRed = this.getRed();
int totalGreen = this.getGreen();
int totalBlue = this.getBlue();
int totalMax = Math.max(Math.max(totalRed, totalGreen), totalBlue);
for (Color color : colors) {
totalRed += color.getRed();
totalGreen += color.getGreen();
totalBlue += color.getBlue();
totalMax += Math.max(Math.max(color.getRed(), color.getGreen()), color.getBlue());
}
float averageRed = totalRed / (colors.length + 1);
float averageGreen = totalGreen / (colors.length + 1);
float averageBlue = totalBlue / (colors.length + 1);
float averageMax = totalMax / (colors.length + 1);
float maximumOfAverages = Math.max(Math.max(averageRed, averageGreen), averageBlue);
float gainFactor = averageMax / maximumOfAverages;
return Color.fromRGB((int) (averageRed * gainFactor), (int) (averageGreen * gainFactor), (int) (averageBlue * gainFactor));
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Color)) {
return false;
}
final Color that = (Color) o;
return this.blue == that.blue && this.green == that.green && this.red == that.red;
}
@Override
public int hashCode() {
return asRGB() ^ Color.class.hashCode();
}
public Map<String, Object> serialize() {
return ImmutableMap.<String, Object>of(
"RED", getRed(),
"BLUE", getBlue(),
"GREEN", getGreen()
);
}
@SuppressWarnings("javadoc")
public static Color deserialize(Map<String, Object> map) {
return fromRGB(
asInt("RED", map),
asInt("GREEN", map),
asInt("BLUE", map)
);
}
private static int asInt(String string, Map<String, Object> map) {
Object value = map.get(string);
if (value == null) {
throw new IllegalArgumentException(string + " not in map " + map);
}
if (!(value instanceof Number)) {
throw new IllegalArgumentException(string + '(' + value + ") is not a number");
}
return ((Number) value).intValue();
}
@Override
public String toString() {
return "Color:[rgb0x" + Integer.toHexString(getRed()).toUpperCase() + Integer.toHexString(getGreen()).toUpperCase() + Integer.toHexString(getBlue()).toUpperCase() + "]";
}
}

View File

@ -0,0 +1,81 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* Represents the different growth states of crops
*/
public enum CropState {
/**
* State when first seeded
*/
SEEDED(0x0),
/**
* First growth stage
*/
GERMINATED(0x1),
/**
* Second growth stage
*/
VERY_SMALL(0x2),
/**
* Third growth stage
*/
SMALL(0x3),
/**
* Fourth growth stage
*/
MEDIUM(0x4),
/**
* Fifth growth stage
*/
TALL(0x5),
/**
* Almost ripe stage
*/
VERY_TALL(0x6),
/**
* Ripe stage
*/
RIPE(0x7);
private final byte data;
private final static Map<Byte, CropState> BY_DATA = Maps.newHashMap();
private CropState(final int data) {
this.data = (byte) data;
}
/**
* Gets the associated data value representing this growth state
*
* @return A byte containing the data value of this growth state
* @deprecated Magic value
*/
@Deprecated
public byte getData() {
return data;
}
/**
* Gets the CropState with the given data value
*
* @param data Data value to fetch
* @return The {@link CropState} representing the given value, or null if
* it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static CropState getByData(final byte data) {
return BY_DATA.get(data);
}
static {
for (CropState cropState : values()) {
BY_DATA.put(cropState.getData(), cropState);
}
}
}

View File

@ -0,0 +1,72 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* Represents the various difficulty levels that are available.
*/
public enum Difficulty {
/**
* Players regain health over time, hostile mobs don't spawn, the hunger
* bar does not deplete.
*/
PEACEFUL(0),
/**
* Hostile mobs spawn, enemies deal less damage than on normal difficulty,
* the hunger bar does deplete and starving deals up to 5 hearts of
* damage. (Default value)
*/
EASY(1),
/**
* Hostile mobs spawn, enemies deal normal amounts of damage, the hunger
* bar does deplete and starving deals up to 9.5 hearts of damage.
*/
NORMAL(2),
/**
* Hostile mobs spawn, enemies deal greater damage than on normal
* difficulty, the hunger bar does deplete and starving can kill players.
*/
HARD(3);
private final int value;
private final static Map<Integer, Difficulty> BY_ID = Maps.newHashMap();
private Difficulty(final int value) {
this.value = value;
}
/**
* Gets the difficulty value associated with this Difficulty.
*
* @return An integer value of this difficulty
* @deprecated Magic value
*/
@Deprecated
public int getValue() {
return value;
}
/**
* Gets the Difficulty represented by the specified value
*
* @param value Value to check
* @return Associative {@link Difficulty} with the given value, or null if
* it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static Difficulty getByValue(final int value) {
return BY_ID.get(value);
}
static {
for (Difficulty diff : values()) {
BY_ID.put(diff.value, diff);
}
}
}

View File

@ -0,0 +1,239 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
/**
* All supported color values for dyes and cloth
*/
public enum DyeColor {
/**
* Represents white dye.
*/
WHITE(0x0, 0xF, Color.WHITE, Color.fromRGB(0xF0F0F0)),
/**
* Represents orange dye.
*/
ORANGE(0x1, 0xE, Color.fromRGB(0xD87F33), Color.fromRGB(0xEB8844)),
/**
* Represents magenta dye.
*/
MAGENTA(0x2, 0xD, Color.fromRGB(0xB24CD8), Color.fromRGB(0xC354CD)),
/**
* Represents light blue dye.
*/
LIGHT_BLUE(0x3, 0xC, Color.fromRGB(0x6699D8), Color.fromRGB(0x6689D3)),
/**
* Represents yellow dye.
*/
YELLOW(0x4, 0xB, Color.fromRGB(0xE5E533), Color.fromRGB(0xDECF2A)),
/**
* Represents lime dye.
*/
LIME(0x5, 0xA, Color.fromRGB(0x7FCC19), Color.fromRGB(0x41CD34)),
/**
* Represents pink dye.
*/
PINK(0x6, 0x9, Color.fromRGB(0xF27FA5), Color.fromRGB(0xD88198)),
/**
* Represents gray dye.
*/
GRAY(0x7, 0x8, Color.fromRGB(0x4C4C4C), Color.fromRGB(0x434343)),
/**
* Represents silver dye.
*/
SILVER(0x8, 0x7, Color.fromRGB(0x999999), Color.fromRGB(0xABABAB)),
/**
* Represents cyan dye.
*/
CYAN(0x9, 0x6, Color.fromRGB(0x4C7F99), Color.fromRGB(0x287697)),
/**
* Represents purple dye.
*/
PURPLE(0xA, 0x5, Color.fromRGB(0x7F3FB2), Color.fromRGB(0x7B2FBE)),
/**
* Represents blue dye.
*/
BLUE(0xB, 0x4, Color.fromRGB(0x334CB2), Color.fromRGB(0x253192)),
/**
* Represents brown dye.
*/
BROWN(0xC, 0x3, Color.fromRGB(0x664C33), Color.fromRGB(0x51301A)),
/**
* Represents green dye.
*/
GREEN(0xD, 0x2, Color.fromRGB(0x667F33), Color.fromRGB(0x3B511A)),
/**
* Represents red dye.
*/
RED(0xE, 0x1, Color.fromRGB(0x993333), Color.fromRGB(0xB3312C)),
/**
* Represents black dye.
*/
BLACK(0xF, 0x0, Color.fromRGB(0x191919), Color.fromRGB(0x1E1B1B));
private final byte woolData;
private final byte dyeData;
private final Color color;
private final Color firework;
private final static DyeColor[] BY_WOOL_DATA;
private final static DyeColor[] BY_DYE_DATA;
private final static Map<Color, DyeColor> BY_COLOR;
private final static Map<Color, DyeColor> BY_FIREWORK;
private DyeColor(final int woolData, final int dyeData, Color color, Color firework) {
this.woolData = (byte) woolData;
this.dyeData = (byte) dyeData;
this.color = color;
this.firework = firework;
}
/**
* Gets the associated (wool) data value representing this color.
*
* @return A byte containing the (wool) data value of this color
* @deprecated The name is misleading. It would imply {@link
* Material#INK_SACK} but uses {@link Material#WOOL}
* @see #getWoolData()
* @see #getDyeData()
*/
@Deprecated
public byte getData() {
return getWoolData();
}
/**
* Gets the associated wool data value representing this color.
*
* @return A byte containing the wool data value of this color
* @see #getDyeData()
* @deprecated Magic value
*/
@Deprecated
public byte getWoolData() {
return woolData;
}
/**
* Gets the associated dye data value representing this color.
*
* @return A byte containing the dye data value of this color
* @see #getWoolData()
* @deprecated Magic value
*/
@Deprecated
public byte getDyeData() {
return dyeData;
}
/**
* Gets the color that this dye represents.
*
* @return The {@link Color} that this dye represents
*/
public Color getColor() {
return color;
}
/**
* Gets the firework color that this dye represents.
*
* @return The {@link Color} that this dye represents
*/
public Color getFireworkColor() {
return firework;
}
/**
* Gets the DyeColor with the given (wool) data value.
*
* @param data (wool) data value to fetch
* @return The {@link DyeColor} representing the given value, or null if
* it doesn't exist
* @deprecated The name is misleading. It would imply {@link
* Material#INK_SACK} but uses {@link Material#WOOL}
* @see #getByDyeData(byte)
* @see #getByWoolData(byte)
*/
@Deprecated
public static DyeColor getByData(final byte data) {
return getByWoolData(data);
}
/**
* Gets the DyeColor with the given wool data value.
*
* @param data Wool data value to fetch
* @return The {@link DyeColor} representing the given value, or null if
* it doesn't exist
* @see #getByDyeData(byte)
* @deprecated Magic value
*/
@Deprecated
public static DyeColor getByWoolData(final byte data) {
int i = 0xff & data;
if (i >= BY_WOOL_DATA.length) {
return null;
}
return BY_WOOL_DATA[i];
}
/**
* Gets the DyeColor with the given dye data value.
*
* @param data Dye data value to fetch
* @return The {@link DyeColor} representing the given value, or null if
* it doesn't exist
* @see #getByWoolData(byte)
* @deprecated Magic value
*/
@Deprecated
public static DyeColor getByDyeData(final byte data) {
int i = 0xff & data;
if (i >= BY_DYE_DATA.length) {
return null;
}
return BY_DYE_DATA[i];
}
/**
* Gets the DyeColor with the given color value.
*
* @param color Color value to get the dye by
* @return The {@link DyeColor} representing the given value, or null if
* it doesn't exist
*/
public static DyeColor getByColor(final Color color) {
return BY_COLOR.get(color);
}
/**
* Gets the DyeColor with the given firework color value.
*
* @param color Color value to get dye by
* @return The {@link DyeColor} representing the given value, or null if
* it doesn't exist
*/
public static DyeColor getByFireworkColor(final Color color) {
return BY_FIREWORK.get(color);
}
static {
BY_WOOL_DATA = values();
BY_DYE_DATA = values();
ImmutableMap.Builder<Color, DyeColor> byColor = ImmutableMap.builder();
ImmutableMap.Builder<Color, DyeColor> byFirework = ImmutableMap.builder();
for (DyeColor color : values()) {
BY_WOOL_DATA[color.woolData & 0xff] = color;
BY_DYE_DATA[color.dyeData & 0xff] = color;
byColor.put(color.getColor(), color);
byFirework.put(color.getFireworkColor(), color);
}
BY_COLOR = byColor.build();
BY_FIREWORK = byFirework.build();
}
}

View File

@ -0,0 +1,337 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
import org.bukkit.block.BlockFace;
import org.bukkit.material.MaterialData;
import org.bukkit.potion.Potion;
/**
* A list of effects that the server is able to send to players.
*/
public enum Effect {
/**
* An alternate click sound.
*/
CLICK2(1000, Type.SOUND),
/**
* A click sound.
*/
CLICK1(1001, Type.SOUND),
/**
* Sound of a bow firing.
*/
BOW_FIRE(1002, Type.SOUND),
/**
* Sound of a door opening/closing.
*/
DOOR_TOGGLE(1003, Type.SOUND),
/**
* Sound of fire being extinguished.
*/
EXTINGUISH(1004, Type.SOUND),
/**
* A song from a record. Needs the record item ID as additional info
*/
RECORD_PLAY(1005, Type.SOUND, Material.class),
/**
* Sound of ghast shrieking.
*/
GHAST_SHRIEK(1007, Type.SOUND),
/**
* Sound of ghast firing.
*/
GHAST_SHOOT(1008, Type.SOUND),
/**
* Sound of blaze firing.
*/
BLAZE_SHOOT(1009, Type.SOUND),
/**
* Sound of zombies chewing on wooden doors.
*/
ZOMBIE_CHEW_WOODEN_DOOR(1010, Type.SOUND),
/**
* Sound of zombies chewing on iron doors.
*/
ZOMBIE_CHEW_IRON_DOOR(1011, Type.SOUND),
/**
* Sound of zombies destroying a door.
*/
ZOMBIE_DESTROY_DOOR(1012, Type.SOUND),
/**
* A visual smoke effect. Needs direction as additional info.
*/
SMOKE(2000, Type.VISUAL, BlockFace.class),
/**
* Sound of a block breaking. Needs block ID as additional info.
*/
STEP_SOUND(2001, Type.SOUND, Material.class),
/**
* Visual effect of a splash potion breaking. Needs potion data value as
* additional info.
*/
POTION_BREAK(2002, Type.VISUAL, Potion.class),
/**
* An ender eye signal; a visual effect.
*/
ENDER_SIGNAL(2003, Type.VISUAL),
/**
* The flames seen on a mobspawner; a visual effect.
*/
MOBSPAWNER_FLAMES(2004, Type.VISUAL),
/**
* The spark that comes off a fireworks
*/
FIREWORKS_SPARK("fireworksSpark", Type.PARTICLE),
/**
* Critical hit particles
*/
CRIT("crit", Type.PARTICLE),
/**
* Blue critical hit particles
*/
MAGIC_CRIT("magicCrit", Type.PARTICLE),
/**
* Multicolored potion effect particles
*/
POTION_SWIRL("mobSpell", Type.PARTICLE),
/**
* Multicolored potion effect particles that are slightly transparent
*/
POTION_SWIRL_TRANSPARENT("mobSpellAmbient", Type.PARTICLE),
/**
* A puff of white potion swirls
*/
SPELL("spell", Type.PARTICLE),
/**
* A puff of white stars
*/
INSTANT_SPELL("instantSpell", Type.PARTICLE),
/**
* A puff of purple particles
*/
WITCH_MAGIC("witchMagic", Type.PARTICLE),
/**
* The note that appears above note blocks
*/
NOTE("note", Type.PARTICLE),
/**
* The particles shown at nether portals
*/
PORTAL("portal", Type.PARTICLE),
/**
* The symbols that fly towards the enchantment table
*/
FLYING_GLYPH("enchantmenttable", Type.PARTICLE),
/**
* Fire particles
*/
FLAME("flame", Type.PARTICLE),
/**
* The particles that pop out of lava
*/
LAVA_POP("lava", Type.PARTICLE),
/**
* A small gray square
*/
FOOTSTEP("footstep", Type.PARTICLE),
/**
* Water particles
*/
SPLASH("splash", Type.PARTICLE),
/**
* Smoke particles
*/
PARTICLE_SMOKE("smoke", Type.PARTICLE),
/**
* The biggest explosion particle effect
*/
EXPLOSION_HUGE("hugeexplosion", Type.PARTICLE),
/**
* A larger version of the explode particle
*/
EXPLOSION_LARGE("largeexplode", Type.PARTICLE),
/**
* Explosion particles
*/
EXPLOSION("explode", Type.PARTICLE),
/**
* Small gray particles
*/
VOID_FOG("depthsuspend", Type.PARTICLE),
/**
* Small gray particles
*/
SMALL_SMOKE("townaura", Type.PARTICLE),
/**
* A puff of white smoke
*/
CLOUD("cloud", Type.PARTICLE),
/**
* Multicolored dust particles
*/
COLOURED_DUST("reddust", Type.PARTICLE),
/**
* Snowball breaking
*/
SNOWBALL_BREAK("snowballpoof", Type.PARTICLE),
/**
* The water drip particle that appears on blocks under water
*/
WATERDRIP("dripWater", Type.PARTICLE),
/**
* The lava drip particle that appears on blocks under lava
*/
LAVADRIP("dripLava", Type.PARTICLE),
/**
* White particles
*/
SNOW_SHOVEL("snowshovel", Type.PARTICLE),
/**
* The particle shown when a slime jumps
*/
SLIME("slime", Type.PARTICLE),
/**
* The particle that appears when breading animals
*/
HEART("heart", Type.PARTICLE),
/**
* The particle that appears when hitting a villager
*/
VILLAGER_THUNDERCLOUD("angryVillager", Type.PARTICLE),
/**
* The particle that appears when trading with a villager
*/
HAPPY_VILLAGER("happyVillager", Type.PARTICLE),
/**
* The smoke particles that appears on blazes, minecarts
* with furnaces and fire
*/
LARGE_SMOKE("largesmoke", Type.PARTICLE),
/**
* The particles generated when a tool breaks.
* This particle requires a Material so that the client can select the correct texture.
*/
ITEM_BREAK("iconcrack", Type.PARTICLE, Material.class),
/**
* The particles generated while breaking a block.
* This particle requires a Material and data value so that the client can select the correct texture.
*/
TILE_BREAK("blockcrack", Type.PARTICLE, MaterialData.class),
/**
* The particles generated while sprinting a block
* This particle requires a Material and data value so that the client can select the correct texture.
*/
TILE_DUST("blockdust", Type.PARTICLE, MaterialData.class);
private final int id;
private final Type type;
private final Class<?> data;
private static final Map<Integer, Effect> BY_ID = Maps.newHashMap();
private static final Map<String, Effect> BY_NAME = Maps.newHashMap();
private final String particleName;
private Effect(int id, Type type) {
this(id,type,null);
}
private Effect(int id, Type type, Class<?> data) {
this.id = id;
this.type = type;
this.data = data;
particleName = null;
}
private Effect(String particleName, Type type, Class<?> data) {
this.particleName = particleName;
this.type = type;
id = 0;
this.data = data;
}
private Effect(String particleName, Type type) {
this.particleName = particleName;
this.type = type;
id = 0;
this.data = null;
}
/**
* Gets the ID for this effect.
*
* @return if this Effect isn't of type PARTICLE it returns ID of this effect
* @deprecated Magic value
*/
@Deprecated
public int getId() {
return this.id;
}
/**
* Returns the effect's name. This returns null if the effect is not a particle
*
* @return The effect's name
*/
public String getName() {
return particleName;
}
/**
* @return The type of the effect.
*/
public Type getType() {
return this.type;
}
/**
* @return if this Effect isn't of type PARTICLE it returns the class which represents data for this effect, or null if none
*/
public Class<?> getData() {
return this.data;
}
/**
* Gets the Effect associated with the given ID.
*
* @param id ID of the Effect to return
* @return Effect with the given ID
* @deprecated Magic value
*/
@Deprecated
public static Effect getById(int id) {
return BY_ID.get(id);
}
static {
for (Effect effect : values()) {
if (effect.type != Type.PARTICLE) {
BY_ID.put(effect.id, effect);
}
}
}
/**
* Gets the Effect associated with the given name.
*
* @param name name of the Effect to return
* @return Effect with the given name
*/
public static Effect getByName(String name) {
return BY_NAME.get(name);
}
static {
for (Effect effect : values()) {
if (effect.type == Type.PARTICLE) {
BY_NAME.put(effect.particleName, effect);
}
}
}
/**
* Represents the type of an effect.
*/
public enum Type {SOUND, VISUAL, PARTICLE}
}

View File

@ -0,0 +1,136 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* A list of all Effects that can happen to entities.
*/
public enum EntityEffect {
/**
* When mobs get hurt.
*/
HURT(2),
/**
* When a mob dies.
* <p>
* <b>This will cause client-glitches!
*/
DEATH(3),
/**
* The smoke when taming a wolf fails.
* <p>
* Without client-mods this will be ignored if the entity is not a wolf.
*/
WOLF_SMOKE(6),
/**
* The hearts when taming a wolf succeeds.
* <p>
* Without client-mods this will be ignored if the entity is not a wolf.
*/
WOLF_HEARTS(7),
/**
* When a wolf shakes (after being wet).
* <p>
* Without client-mods this will be ignored if the entity is not a wolf.
*/
WOLF_SHAKE(8),
/**
* When a sheep eats a LONG_GRASS block.
*/
SHEEP_EAT(10),
/**
* When an Iron Golem gives a rose.
* <p>
* This will not play an effect if the entity is not an iron golem.
*/
IRON_GOLEM_ROSE(11),
/**
* Hearts from a villager.
* <p>
* This will not play an effect if the entity is not a villager.
*/
VILLAGER_HEART(12),
/**
* When a villager is angry.
* <p>
* This will not play an effect if the entity is not a villager.
*/
VILLAGER_ANGRY(13),
/**
* Happy particles from a villager.
* <p>
* This will not play an effect if the entity is not a villager.
*/
VILLAGER_HAPPY(14),
/**
* Magic particles from a witch.
* <p>
* This will not play an effect if the entity is not a witch.
*/
WITCH_MAGIC(15),
/**
* When a zombie transforms into a villager by shaking violently.
* <p>
* This will not play an effect if the entity is not a zombie.
*/
ZOMBIE_TRANSFORM(16),
/**
* When a firework explodes.
* <p>
* This will not play an effect if the entity is not a firework.
*/
FIREWORK_EXPLODE(17);
private final byte data;
private final static Map<Byte, EntityEffect> BY_DATA = Maps.newHashMap();
EntityEffect(final int data) {
this.data = (byte) data;
}
/**
* Gets the data value of this EntityEffect
*
* @return The data value
* @deprecated Magic value
*/
@Deprecated
public byte getData() {
return data;
}
/**
* Gets the EntityEffect with the given data value
*
* @param data Data value to fetch
* @return The {@link EntityEffect} representing the given value, or null
* if it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static EntityEffect getByData(final byte data) {
return BY_DATA.get(data);
}
static {
for (EntityEffect entityEffect : values()) {
BY_DATA.put(entityEffect.data, entityEffect);
}
}
}

View File

@ -0,0 +1,421 @@
package org.bukkit;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Represents a single firework effect.
*/
@SerializableAs("Firework")
public final class FireworkEffect implements ConfigurationSerializable {
/**
* The type or shape of the effect.
*/
public enum Type {
/**
* A small ball effect.
*/
BALL,
/**
* A large ball effect.
*/
BALL_LARGE,
/**
* A star-shaped effect.
*/
STAR,
/**
* A burst effect.
*/
BURST,
/**
* A creeper-face effect.
*/
CREEPER,
;
}
/**
* Construct a firework effect.
*
* @return A utility object for building a firework effect
*/
public static Builder builder() {
return new Builder();
}
/**
* This is a builder for FireworkEffects.
*
* @see FireworkEffect#builder()
*/
public static final class Builder {
boolean flicker = false;
boolean trail = false;
final ImmutableList.Builder<Color> colors = ImmutableList.builder();
ImmutableList.Builder<Color> fadeColors = null;
Type type = Type.BALL;
Builder() {}
/**
* Specify the type of the firework effect.
*
* @param type The effect type
* @return This object, for chaining
* @throws IllegalArgumentException If type is null
*/
public Builder with(Type type) throws IllegalArgumentException {
Validate.notNull(type, "Cannot have null type");
this.type = type;
return this;
}
/**
* Add a flicker to the firework effect.
*
* @return This object, for chaining
*/
public Builder withFlicker() {
flicker = true;
return this;
}
/**
* Set whether the firework effect should flicker.
*
* @param flicker true if it should flicker, false if not
* @return This object, for chaining
*/
public Builder flicker(boolean flicker) {
this.flicker = flicker;
return this;
}
/**
* Add a trail to the firework effect.
*
* @return This object, for chaining
*/
public Builder withTrail() {
trail = true;
return this;
}
/**
* Set whether the firework effect should have a trail.
*
* @param trail true if it should have a trail, false for no trail
* @return This object, for chaining
*/
public Builder trail(boolean trail) {
this.trail = trail;
return this;
}
/**
* Add a primary color to the firework effect.
*
* @param color The color to add
* @return This object, for chaining
* @throws IllegalArgumentException If color is null
*/
public Builder withColor(Color color) throws IllegalArgumentException {
Validate.notNull(color, "Cannot have null color");
colors.add(color);
return this;
}
/**
* Add several primary colors to the firework effect.
*
* @param colors The colors to add
* @return This object, for chaining
* @throws IllegalArgumentException If colors is null
* @throws IllegalArgumentException If any color is null (may be
* thrown after changes have occurred)
*/
public Builder withColor(Color...colors) throws IllegalArgumentException {
Validate.notNull(colors, "Cannot have null colors");
if (colors.length == 0) {
return this;
}
ImmutableList.Builder<Color> list = this.colors;
for (Color color : colors) {
Validate.notNull(color, "Color cannot be null");
list.add(color);
}
return this;
}
/**
* Add several primary colors to the firework effect.
*
* @param colors An iterable object whose iterator yields the desired
* colors
* @return This object, for chaining
* @throws IllegalArgumentException If colors is null
* @throws IllegalArgumentException If any color is null (may be
* thrown after changes have occurred)
*/
public Builder withColor(Iterable<?> colors) throws IllegalArgumentException {
Validate.notNull(colors, "Cannot have null colors");
ImmutableList.Builder<Color> list = this.colors;
for (Object color : colors) {
if (!(color instanceof Color)) {
throw new IllegalArgumentException(color + " is not a Color in " + colors);
}
list.add((Color) color);
}
return this;
}
/**
* Add a fade color to the firework effect.
*
* @param color The color to add
* @return This object, for chaining
* @throws IllegalArgumentException If colors is null
* @throws IllegalArgumentException If any color is null (may be
* thrown after changes have occurred)
*/
public Builder withFade(Color color) throws IllegalArgumentException {
Validate.notNull(color, "Cannot have null color");
if (fadeColors == null) {
fadeColors = ImmutableList.builder();
}
fadeColors.add(color);
return this;
}
/**
* Add several fade colors to the firework effect.
*
* @param colors The colors to add
* @return This object, for chaining
* @throws IllegalArgumentException If colors is null
* @throws IllegalArgumentException If any color is null (may be
* thrown after changes have occurred)
*/
public Builder withFade(Color...colors) throws IllegalArgumentException {
Validate.notNull(colors, "Cannot have null colors");
if (colors.length == 0) {
return this;
}
ImmutableList.Builder<Color> list = this.fadeColors;
if (list == null) {
list = this.fadeColors = ImmutableList.builder();
}
for (Color color : colors) {
Validate.notNull(color, "Color cannot be null");
list.add(color);
}
return this;
}
/**
* Add several fade colors to the firework effect.
*
* @param colors An iterable object whose iterator yields the desired
* colors
* @return This object, for chaining
* @throws IllegalArgumentException If colors is null
* @throws IllegalArgumentException If any color is null (may be
* thrown after changes have occurred)
*/
public Builder withFade(Iterable<?> colors) throws IllegalArgumentException {
Validate.notNull(colors, "Cannot have null colors");
ImmutableList.Builder<Color> list = this.fadeColors;
if (list == null) {
list = this.fadeColors = ImmutableList.builder();
}
for (Object color : colors) {
if (!(color instanceof Color)) {
throw new IllegalArgumentException(color + " is not a Color in " + colors);
}
list.add((Color) color);
}
return this;
}
/**
* Create a {@link FireworkEffect} from the current contents of this
* builder.
* <p>
* To successfully build, you must have specified at least one color.
*
* @return The representative firework effect
*/
public FireworkEffect build() {
return new FireworkEffect(
flicker,
trail,
colors.build(),
fadeColors == null ? ImmutableList.<Color>of() : fadeColors.build(),
type
);
}
}
private static final String FLICKER = "flicker";
private static final String TRAIL = "trail";
private static final String COLORS = "colors";
private static final String FADE_COLORS = "fade-colors";
private static final String TYPE = "type";
private final boolean flicker;
private final boolean trail;
private final ImmutableList<Color> colors;
private final ImmutableList<Color> fadeColors;
private final Type type;
private String string = null;
FireworkEffect(boolean flicker, boolean trail, ImmutableList<Color> colors, ImmutableList<Color> fadeColors, Type type) {
if (colors.isEmpty()) {
throw new IllegalStateException("Cannot make FireworkEffect without any color");
}
this.flicker = flicker;
this.trail = trail;
this.colors = colors;
this.fadeColors = fadeColors;
this.type = type;
}
/**
* Get whether the firework effect flickers.
*
* @return true if it flickers, false if not
*/
public boolean hasFlicker() {
return flicker;
}
/**
* Get whether the firework effect has a trail.
*
* @return true if it has a trail, false if not
*/
public boolean hasTrail() {
return trail;
}
/**
* Get the primary colors of the firework effect.
*
* @return An immutable list of the primary colors
*/
public List<Color> getColors() {
return colors;
}
/**
* Get the fade colors of the firework effect.
*
* @return An immutable list of the fade colors
*/
public List<Color> getFadeColors() {
return fadeColors;
}
/**
* Get the type of the firework effect.
*
* @return The effect type
*/
public Type getType() {
return type;
}
/**
* @see ConfigurationSerializable
*/
public static ConfigurationSerializable deserialize(Map<String, Object> map) {
Type type = Type.valueOf((String) map.get(TYPE));
if (type == null) {
throw new IllegalArgumentException(map.get(TYPE) + " is not a valid Type");
}
return builder()
.flicker((Boolean) map.get(FLICKER))
.trail((Boolean) map.get(TRAIL))
.withColor((Iterable<?>) map.get(COLORS))
.withFade((Iterable<?>) map.get(FADE_COLORS))
.with(type)
.build();
}
public Map<String, Object> serialize() {
return ImmutableMap.<String, Object>of(
FLICKER, flicker,
TRAIL, trail,
COLORS, colors,
FADE_COLORS, fadeColors,
TYPE, type.name()
);
}
@Override
public String toString() {
final String string = this.string;
if (string == null) {
return this.string = "FireworkEffect:" + serialize();
}
return string;
}
@Override
public int hashCode() {
/**
* TRUE and FALSE as per boolean.hashCode()
*/
final int PRIME = 31, TRUE = 1231, FALSE = 1237;
int hash = 1;
hash = hash * PRIME + (flicker ? TRUE : FALSE);
hash = hash * PRIME + (trail ? TRUE : FALSE);
hash = hash * PRIME + type.hashCode();
hash = hash * PRIME + colors.hashCode();
hash = hash * PRIME + fadeColors.hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof FireworkEffect)) {
return false;
}
FireworkEffect that = (FireworkEffect) obj;
return this.flicker == that.flicker
&& this.trail == that.trail
&& this.type == that.type
&& this.colors.equals(that.colors)
&& this.fadeColors.equals(that.fadeColors);
}
}

View File

@ -0,0 +1,66 @@
package org.bukkit;
import java.util.Map;
import org.bukkit.entity.HumanEntity;
import com.google.common.collect.Maps;
/**
* Represents the various type of game modes that {@link HumanEntity}s may
* have
*/
public enum GameMode {
/**
* Creative mode may fly, build instantly, become invulnerable and create
* free items.
*/
CREATIVE(1),
/**
* Survival mode is the "normal" gameplay type, with no special features.
*/
SURVIVAL(0),
/**
* Adventure mode cannot break blocks without the correct tools.
*/
ADVENTURE(2);
private final int value;
private final static Map<Integer, GameMode> BY_ID = Maps.newHashMap();
private GameMode(final int value) {
this.value = value;
}
/**
* Gets the mode value associated with this GameMode
*
* @return An integer value of this gamemode
* @deprecated Magic value
*/
@Deprecated
public int getValue() {
return value;
}
/**
* Gets the GameMode represented by the specified value
*
* @param value Value to check
* @return Associative {@link GameMode} with the given value, or null if
* it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static GameMode getByValue(final int value) {
return BY_ID.get(value);
}
static {
for (GameMode mode : values()) {
BY_ID.put(mode.getValue(), mode);
}
}
}

View File

@ -0,0 +1,61 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* Represents the different types of grass.
*/
public enum GrassSpecies {
/**
* Represents the dead looking grass.
*/
DEAD(0x0),
/**
* Represents the normal grass species.
*/
NORMAL(0x1),
/**
* Represents the fern-looking grass species.
*/
FERN_LIKE(0x2);
private final byte data;
private final static Map<Byte, GrassSpecies> BY_DATA = Maps.newHashMap();
private GrassSpecies(final int data) {
this.data = (byte) data;
}
/**
* Gets the associated data value representing this species
*
* @return A byte containing the data value of this grass species
* @deprecated Magic value
*/
@Deprecated
public byte getData() {
return data;
}
/**
* Gets the GrassSpecies with the given data value
*
* @param data Data value to fetch
* @return The {@link GrassSpecies} representing the given value, or null
* if it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static GrassSpecies getByData(final byte data) {
return BY_DATA.get(data);
}
static {
for (GrassSpecies grassSpecies : values()) {
BY_DATA.put(grassSpecies.getData(), grassSpecies);
}
}
}

View File

@ -0,0 +1,67 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
public enum Instrument {
/**
* Piano is the standard instrument for a note block.
*/
PIANO(0x0),
/**
* Bass drum is normally played when a note block is on top of a
* stone-like block
*/
BASS_DRUM(0x1),
/**
* Snare drum is normally played when a note block is on top of a sandy
* block.
*/
SNARE_DRUM(0x2),
/**
* Sticks are normally played when a note block is on top of a glass
* block.
*/
STICKS(0x3),
/**
* Bass guitar is normally played when a note block is on top of a wooden
* block.
*/
BASS_GUITAR(0x4);
private final byte type;
private final static Map<Byte, Instrument> BY_DATA = Maps.newHashMap();
private Instrument(final int type) {
this.type = (byte) type;
}
/**
* @return The type ID of this instrument.
* @deprecated Magic value
*/
@Deprecated
public byte getType() {
return this.type;
}
/**
* Get an instrument by its type ID.
*
* @param type The type ID
* @return The instrument
* @deprecated Magic value
*/
@Deprecated
public static Instrument getByType(final byte type) {
return BY_DATA.get(type);
}
static {
for (Instrument instrument : Instrument.values()) {
BY_DATA.put(instrument.getType(), instrument);
}
}
}

View File

@ -0,0 +1,560 @@
package org.bukkit;
import org.bukkit.block.Block;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.Vector;
/**
* Represents a 3-dimensional position in a world
*/
public class Location implements Cloneable {
private World world;
private double x;
private double y;
private double z;
private float pitch;
private float yaw;
/**
* Constructs a new Location with the given coordinates
*
* @param world The world in which this location resides
* @param x The x-coordinate of this new location
* @param y The y-coordinate of this new location
* @param z The z-coordinate of this new location
*/
public Location(final World world, final double x, final double y, final double z) {
this(world, x, y, z, 0, 0);
}
/**
* Constructs a new Location with the given coordinates and direction
*
* @param world The world in which this location resides
* @param x The x-coordinate of this new location
* @param y The y-coordinate of this new location
* @param z The z-coordinate of this new location
* @param yaw The absolute rotation on the x-plane, in degrees
* @param pitch The absolute rotation on the y-plane, in degrees
*/
public Location(final World world, final double x, final double y, final double z, final float yaw, final float pitch) {
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.pitch = pitch;
this.yaw = yaw;
}
/**
* Sets the world that this location resides in
*
* @param world New world that this location resides in
*/
public void setWorld(World world) {
this.world = world;
}
/**
* Gets the world that this location resides in
*
* @return World that contains this location
*/
public World getWorld() {
return world;
}
/**
* Gets the chunk at the represented location
*
* @return Chunk at the represented location
*/
public Chunk getChunk() {
return world.getChunkAt(this);
}
/**
* Gets the block at the represented location
*
* @return Block at the represented location
*/
public Block getBlock() {
return world.getBlockAt(this);
}
/**
* Sets the x-coordinate of this location
*
* @param x X-coordinate
*/
public void setX(double x) {
this.x = x;
}
/**
* Gets the x-coordinate of this location
*
* @return x-coordinate
*/
public double getX() {
return x;
}
/**
* Gets the floored value of the X component, indicating the block that
* this location is contained with.
*
* @return block X
*/
public int getBlockX() {
return locToBlock(x);
}
/**
* Sets the y-coordinate of this location
*
* @param y y-coordinate
*/
public void setY(double y) {
this.y = y;
}
/**
* Gets the y-coordinate of this location
*
* @return y-coordinate
*/
public double getY() {
return y;
}
/**
* Gets the floored value of the Y component, indicating the block that
* this location is contained with.
*
* @return block y
*/
public int getBlockY() {
return locToBlock(y);
}
/**
* Sets the z-coordinate of this location
*
* @param z z-coordinate
*/
public void setZ(double z) {
this.z = z;
}
/**
* Gets the z-coordinate of this location
*
* @return z-coordinate
*/
public double getZ() {
return z;
}
/**
* Gets the floored value of the Z component, indicating the block that
* this location is contained with.
*
* @return block z
*/
public int getBlockZ() {
return locToBlock(z);
}
/**
* Sets the yaw of this location, measured in degrees.
* <ul>
* <li>A yaw of 0 or 360 represents the positive z direction.
* <li>A yaw of 180 represents the negative z direction.
* <li>A yaw of 90 represents the negative x direction.
* <li>A yaw of 270 represents the positive x direction.
* </ul>
* Increasing yaw values are the equivalent of turning to your
* right-facing, increasing the scale of the next respective axis, and
* decreasing the scale of the previous axis.
*
* @param yaw new rotation's yaw
*/
public void setYaw(float yaw) {
this.yaw = yaw;
}
/**
* Gets the yaw of this location, measured in degrees.
* <ul>
* <li>A yaw of 0 or 360 represents the positive z direction.
* <li>A yaw of 180 represents the negative z direction.
* <li>A yaw of 90 represents the negative x direction.
* <li>A yaw of 270 represents the positive x direction.
* </ul>
* Increasing yaw values are the equivalent of turning to your
* right-facing, increasing the scale of the next respective axis, and
* decreasing the scale of the previous axis.
*
* @return the rotation's yaw
*/
public float getYaw() {
return yaw;
}
/**
* Sets the pitch of this location, measured in degrees.
* <ul>
* <li>A pitch of 0 represents level forward facing.
* <li>A pitch of 90 represents downward facing, or negative y
* direction.
* <li>A pitch of -90 represents upward facing, or positive y direction.
* <ul>
* Increasing pitch values the equivalent of looking down.
*
* @param pitch new incline's pitch
*/
public void setPitch(float pitch) {
this.pitch = pitch;
}
/**
* Gets the pitch of this location, measured in degrees.
* <ul>
* <li>A pitch of 0 represents level forward facing.
* <li>A pitch of 90 represents downward facing, or negative y
* direction.
* <li>A pitch of -90 represents upward facing, or positive y direction.
* <ul>
* Increasing pitch values the equivalent of looking down.
*
* @return the incline's pitch
*/
public float getPitch() {
return pitch;
}
/**
* Gets a unit-vector pointing in the direction that this Location is
* facing.
*
* @return a vector pointing the direction of this location's {@link
* #getPitch() pitch} and {@link #getYaw() yaw}
*/
public Vector getDirection() {
Vector vector = new Vector();
double rotX = this.getYaw();
double rotY = this.getPitch();
vector.setY(-Math.sin(Math.toRadians(rotY)));
double xz = Math.cos(Math.toRadians(rotY));
vector.setX(-xz * Math.sin(Math.toRadians(rotX)));
vector.setZ(xz * Math.cos(Math.toRadians(rotX)));
return vector;
}
/**
* Sets the {@link #getYaw() yaw} and {@link #getPitch() pitch} to point
* in the direction of the vector.
*/
public Location setDirection(Vector vector) {
/*
* Sin = Opp / Hyp
* Cos = Adj / Hyp
* Tan = Opp / Adj
*
* x = -Opp
* z = Adj
*/
final double _2PI = 2 * Math.PI;
final double x = vector.getX();
final double z = vector.getZ();
if (x == 0 && z == 0) {
pitch = vector.getY() > 0 ? -90 : 90;
return this;
}
double theta = Math.atan2(-x, z);
yaw = (float) Math.toDegrees((theta + _2PI) % _2PI);
double x2 = NumberConversions.square(x);
double z2 = NumberConversions.square(z);
double xz = Math.sqrt(x2 + z2);
pitch = (float) Math.toDegrees(Math.atan(-vector.getY() / xz));
return this;
}
/**
* Adds the location by another.
*
* @see Vector
* @param vec The other location
* @return the same location
* @throws IllegalArgumentException for differing worlds
*/
public Location add(Location vec) {
if (vec == null || vec.getWorld() != getWorld()) {
throw new IllegalArgumentException("Cannot add Locations of differing worlds");
}
x += vec.x;
y += vec.y;
z += vec.z;
return this;
}
/**
* Adds the location by a vector.
*
* @see Vector
* @param vec Vector to use
* @return the same location
*/
public Location add(Vector vec) {
this.x += vec.getX();
this.y += vec.getY();
this.z += vec.getZ();
return this;
}
/**
* Adds the location by another. Not world-aware.
*
* @see Vector
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @return the same location
*/
public Location add(double x, double y, double z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
/**
* Subtracts the location by another.
*
* @see Vector
* @param vec The other location
* @return the same location
* @throws IllegalArgumentException for differing worlds
*/
public Location subtract(Location vec) {
if (vec == null || vec.getWorld() != getWorld()) {
throw new IllegalArgumentException("Cannot add Locations of differing worlds");
}
x -= vec.x;
y -= vec.y;
z -= vec.z;
return this;
}
/**
* Subtracts the location by a vector.
*
* @see Vector
* @param vec The vector to use
* @return the same location
*/
public Location subtract(Vector vec) {
this.x -= vec.getX();
this.y -= vec.getY();
this.z -= vec.getZ();
return this;
}
/**
* Subtracts the location by another. Not world-aware and
* orientation independent.
*
* @see Vector
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @return the same location
*/
public Location subtract(double x, double y, double z) {
this.x -= x;
this.y -= y;
this.z -= z;
return this;
}
/**
* Gets the magnitude of the location, defined as sqrt(x^2+y^2+z^2). The
* value of this method is not cached and uses a costly square-root
* function, so do not repeatedly call this method to get the location's
* magnitude. NaN will be returned if the inner result of the sqrt()
* function overflows, which will be caused if the length is too long. Not
* world-aware and orientation independent.
*
* @see Vector
* @return the magnitude
*/
public double length() {
return Math.sqrt(NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z));
}
/**
* Gets the magnitude of the location squared. Not world-aware and
* orientation independent.
*
* @see Vector
* @return the magnitude
*/
public double lengthSquared() {
return NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z);
}
/**
* Get the distance between this location and another. The value of this
* method is not cached and uses a costly square-root function, so do not
* repeatedly call this method to get the location's magnitude. NaN will
* be returned if the inner result of the sqrt() function overflows, which
* will be caused if the distance is too long.
*
* @see Vector
* @param o The other location
* @return the distance
* @throws IllegalArgumentException for differing worlds
*/
public double distance(Location o) {
return Math.sqrt(distanceSquared(o));
}
/**
* Get the squared distance between this location and another.
*
* @see Vector
* @param o The other location
* @return the distance
* @throws IllegalArgumentException for differing worlds
*/
public double distanceSquared(Location o) {
if (o == null) {
throw new IllegalArgumentException("Cannot measure distance to a null location");
} else if (o.getWorld() == null || getWorld() == null) {
throw new IllegalArgumentException("Cannot measure distance to a null world");
} else if (o.getWorld() != getWorld()) {
throw new IllegalArgumentException("Cannot measure distance between " + getWorld().getName() + " and " + o.getWorld().getName());
}
return NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z);
}
/**
* Performs scalar multiplication, multiplying all components with a
* scalar. Not world-aware.
*
* @param m The factor
* @see Vector
* @return the same location
*/
public Location multiply(double m) {
x *= m;
y *= m;
z *= m;
return this;
}
/**
* Zero this location's components. Not world-aware.
*
* @see Vector
* @return the same location
*/
public Location zero() {
x = 0;
y = 0;
z = 0;
return this;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Location other = (Location) obj;
if (this.world != other.world && (this.world == null || !this.world.equals(other.world))) {
return false;
}
if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) {
return false;
}
if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) {
return false;
}
if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z)) {
return false;
}
if (Float.floatToIntBits(this.pitch) != Float.floatToIntBits(other.pitch)) {
return false;
}
if (Float.floatToIntBits(this.yaw) != Float.floatToIntBits(other.yaw)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 19 * hash + (this.world != null ? this.world.hashCode() : 0);
hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
hash = 19 * hash + Float.floatToIntBits(this.pitch);
hash = 19 * hash + Float.floatToIntBits(this.yaw);
return hash;
}
@Override
public String toString() {
return "Location{" + "world=" + world + ",x=" + x + ",y=" + y + ",z=" + z + ",pitch=" + pitch + ",yaw=" + yaw + '}';
}
/**
* Constructs a new {@link Vector} based on this Location
*
* @return New Vector containing the coordinates represented by this
* Location
*/
public Vector toVector() {
return new Vector(x, y, z);
}
@Override
public Location clone() {
try {
return (Location) super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
/**
* Safely converts a double (location coordinate) to an int (block
* coordinate)
*
* @param loc Precise coordinate
* @return Block coordinate
*/
public static int locToBlock(double loc) {
return NumberConversions.floor(loc);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
package org.bukkit;
public enum NetherWartsState {
/**
* State when first seeded
*/
SEEDED,
/**
* First growth stage
*/
STAGE_ONE,
/**
* Second growth stage
*/
STAGE_TWO,
/**
* Ready to harvest
*/
RIPE;
}

View File

@ -0,0 +1,276 @@
package org.bukkit;
import java.util.Map;
import org.apache.commons.lang.Validate;
import com.google.common.collect.Maps;
/**
* A note class to store a specific note.
*/
public class Note {
/**
* An enum holding tones.
*/
public enum Tone {
G(0x1, true),
A(0x3, true),
B(0x5, false),
C(0x6, true),
D(0x8, true),
E(0xA, false),
F(0xB, true);
private final boolean sharpable;
private final byte id;
private static final Map<Byte, Note.Tone> BY_DATA = Maps.newHashMap();
/** The number of tones including sharped tones. */
public static final byte TONES_COUNT = 12;
private Tone(int id, boolean sharpable) {
this.id = (byte) (id % TONES_COUNT);
this.sharpable = sharpable;
}
/**
* Returns the not sharped id of this tone.
*
* @return the not sharped id of this tone.
* @deprecated Magic value
*/
@Deprecated
public byte getId() {
return getId(false);
}
/**
* Returns the id of this tone. These method allows to return the
* sharped id of the tone. If the tone couldn't be sharped it always
* return the not sharped id of this tone.
*
* @param sharped Set to true to return the sharped id.
* @return the id of this tone.
* @deprecated Magic value
*/
@Deprecated
public byte getId(boolean sharped) {
byte id = (byte) (sharped && sharpable ? this.id + 1 : this.id);
return (byte) (id % TONES_COUNT);
}
/**
* Returns if this tone could be sharped.
*
* @return if this tone could be sharped.
*/
public boolean isSharpable() {
return sharpable;
}
/**
* Returns if this tone id is the sharped id of the tone.
*
* @param id the id of the tone.
* @return if the tone id is the sharped id of the tone.
* @throws IllegalArgumentException if neither the tone nor the
* semitone have the id.
* @deprecated Magic value
*/
@Deprecated
public boolean isSharped(byte id) {
if (id == getId(false)) {
return false;
} else if (id == getId(true)) {
return true;
} else {
// The id isn't matching to the tone!
throw new IllegalArgumentException("The id isn't matching to the tone.");
}
}
/**
* Returns the tone to id. Also returning the semitones.
*
* @param id the id of the tone.
* @return the tone to id.
* @deprecated Magic value
*/
@Deprecated
public static Tone getById(byte id) {
return BY_DATA.get(id);
}
static {
for (Tone tone : values()) {
int id = tone.id % TONES_COUNT;
BY_DATA.put((byte) id, tone);
if (tone.isSharpable()) {
id = (id + 1) % TONES_COUNT;
BY_DATA.put((byte) id, tone);
}
}
}
}
private final byte note;
/**
* Creates a new note.
*
* @param note Internal note id. {@link #getId()} always return this
* value. The value has to be in the interval [0;&nbsp;24].
*/
public Note(int note) {
Validate.isTrue(note >= 0 && note <= 24, "The note value has to be between 0 and 24.");
this.note = (byte) note;
}
/**
* Creates a new note.
*
* @param octave The octave where the note is in. Has to be 0 - 2.
* @param tone The tone within the octave. If the octave is 2 the note has
* to be F#.
* @param sharped Set if the tone is sharped (e.g. for F#).
*/
public Note(int octave, Tone tone, boolean sharped) {
if (sharped && !tone.isSharpable()) {
tone = Tone.values()[tone.ordinal() + 1];
sharped = false;
}
if (octave < 0 || octave > 2 || (octave == 2 && !(tone == Tone.F && sharped))) {
throw new IllegalArgumentException("Tone and octave have to be between F#0 and F#2");
}
this.note = (byte) (octave * Tone.TONES_COUNT + tone.getId(sharped));
}
/**
* Creates a new note for a flat tone, such as A-flat.
*
* @param octave The octave where the note is in. Has to be 0 - 1.
* @param tone The tone within the octave.
* @return The new note.
*/
public static Note flat(int octave, Tone tone) {
Validate.isTrue(octave != 2, "Octave cannot be 2 for flats");
tone = tone == Tone.G ? Tone.F : Tone.values()[tone.ordinal() - 1];
return new Note(octave, tone, tone.isSharpable());
}
/**
* Creates a new note for a sharp tone, such as A-sharp.
*
* @param octave The octave where the note is in. Has to be 0 - 2.
* @param tone The tone within the octave. If the octave is 2 the note has
* to be F#.
* @return The new note.
*/
public static Note sharp(int octave, Tone tone) {
return new Note(octave, tone, true);
}
/**
* Creates a new note for a natural tone, such as A-natural.
*
* @param octave The octave where the note is in. Has to be 0 - 1.
* @param tone The tone within the octave.
* @return The new note.
*/
public static Note natural(int octave, Tone tone) {
Validate.isTrue(octave != 2, "Octave cannot be 2 for naturals");
return new Note(octave, tone, false);
}
/**
* @return The note a semitone above this one.
*/
public Note sharped() {
Validate.isTrue(note < 24, "This note cannot be sharped because it is the highest known note!");
return new Note(note + 1);
}
/**
* @return The note a semitone below this one.
*/
public Note flattened() {
Validate.isTrue(note > 0, "This note cannot be flattened because it is the lowest known note!");
return new Note(note - 1);
}
/**
* Returns the internal id of this note.
*
* @return the internal id of this note.
* @deprecated Magic value
*/
@Deprecated
public byte getId() {
return note;
}
/**
* Returns the octave of this note.
*
* @return the octave of this note.
*/
public int getOctave() {
return note / Tone.TONES_COUNT;
}
private byte getToneByte() {
return (byte) (note % Tone.TONES_COUNT);
}
/**
* Returns the tone of this note.
*
* @return the tone of this note.
*/
public Tone getTone() {
return Tone.getById(getToneByte());
}
/**
* Returns if this note is sharped.
*
* @return if this note is sharped.
*/
public boolean isSharped() {
byte note = getToneByte();
return Tone.getById(note).isSharped(note);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + note;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Note other = (Note) obj;
if (note != other.note)
return false;
return true;
}
@Override
public String toString() {
return "Note{" + getTone().toString() + (isSharped() ? "#" : "") + "}";
}
}

View File

@ -0,0 +1,136 @@
package org.bukkit;
import java.util.Date;
import java.util.UUID;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.AnimalTamer;
import org.bukkit.entity.Player;
import org.bukkit.permissions.ServerOperator;
public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable {
/**
* Checks if this player is currently online
*
* @return true if they are online
*/
public boolean isOnline();
/**
* Returns the name of this player
* <p>
* Names are no longer unique past a single game session. For persistent storage
* it is recommended that you use {@link #getUniqueId()} instead.
*
* @return Player name or null if we have not seen a name for this player yet
*/
public String getName();
/**
* Returns the UUID of this player
*
* @return Player UUID
*/
public UUID getUniqueId();
/**
* Checks if this player is banned or not
*
* @return true if banned, otherwise false
*/
public boolean isBanned();
/**
* Bans or unbans this player
*
* @param banned true if banned
* @deprecated Use {@link org.bukkit.BanList#addBan(String, String, Date,
* String)} or {@link org.bukkit.BanList#pardon(String)} to enhance
* functionality
*/
@Deprecated
public void setBanned(boolean banned);
/**
* Checks if this player is whitelisted or not
*
* @return true if whitelisted
*/
public boolean isWhitelisted();
/**
* Sets if this player is whitelisted or not
*
* @param value true if whitelisted
*/
public void setWhitelisted(boolean value);
/**
* Gets a {@link Player} object that this represents, if there is one
* <p>
* If the player is online, this will return that player. Otherwise,
* it will return null.
*
* @return Online player
*/
public Player getPlayer();
/**
* Gets the first date and time that this player was witnessed on this
* server.
* <p>
* If the player has never played before, this will return 0. Otherwise,
* it will be the amount of milliseconds since midnight, January 1, 1970
* UTC.
*
* @return Date of first log-in for this player, or 0
*/
public long getFirstPlayed();
/**
* @deprecated Use {@link #getLastLogin()} or {@link #getLastLogout()}
*/
@Deprecated
public long getLastPlayed();
/**
* Gets the last date and time that this player was witnessed on this
* server.
* <p>
* If the player has never played before, this will return 0. Otherwise,
* it will be the amount of milliseconds since midnight, January 1, 1970
* UTC.
*
* @return Date of last log-in for this player, or 0
*/
public long getLastLogin();
/**
* Gets the last date and time that this player logged out of the server.
* <p>
* If the player has never played before, this will return 0. Otherwise,
* it will be the amount of milliseconds since midnight, January 1, 1970
* UTC.
*
* @see #getLastLogin
* @return Date of last log-in for this player, or 0
*/
public long getLastLogout();
/**
* Checks if this player has played on this server before.
*
* @return True if the player has played before, otherwise false
*/
public boolean hasPlayedBefore();
/**
* Gets the Location where the player will spawn at their bed, null if
* they have not slept in one or their current bed spawn is invalid.
*
* @return Bed Spawn Location if bed exists, otherwise null.
*/
public Location getBedSpawnLocation();
}

View File

@ -0,0 +1,22 @@
package org.bukkit;
/**
* Represents various types of portals that can be made in a world.
*/
public enum PortalType {
/**
* This is a Nether portal, made of obsidian.
*/
NETHER,
/**
* This is an Ender portal.
*/
ENDER,
/**
* This is a custom Plugin portal.
*/
CUSTOM;
}

View File

@ -0,0 +1,47 @@
package org.bukkit;
/**
* An enum to specify a rotation based orientation, like that on a clock.
* <p>
* It represents how something is viewed, as opposed to cardinal directions.
*/
public enum Rotation {
/**
* No rotation
*/
NONE,
/**
* Rotated clockwise by 90 degrees
*/
CLOCKWISE,
/**
* Flipped upside-down, a 180 degree rotation
*/
FLIPPED,
/**
* Rotated counter-clockwise by 90 degrees
*/
COUNTER_CLOCKWISE,
;
private static final Rotation [] rotations = values();
/**
* Rotate clockwise by 90 degrees.
*
* @return the relative rotation
*/
public Rotation rotateClockwise() {
return rotations[(this.ordinal() + 1) & 0x3];
}
/**
* Rotate counter-clockwise by 90 degrees.
*
* @return the relative rotation
*/
public Rotation rotateCounterClockwise() {
return rotations[(this.ordinal() - 1) & 0x3];
}
}

View File

@ -0,0 +1,51 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* Represents the three different types of Sandstone
*/
public enum SandstoneType {
CRACKED(0x0),
GLYPHED(0x1),
SMOOTH(0x2);
private final byte data;
private final static Map<Byte, SandstoneType> BY_DATA = Maps.newHashMap();
private SandstoneType(final int data) {
this.data = (byte) data;
}
/**
* Gets the associated data value representing this type of sandstone
*
* @return A byte containing the data value of this sandstone type
* @deprecated Magic value
*/
@Deprecated
public byte getData() {
return data;
}
/**
* Gets the type of sandstone with the given data value
*
* @param data Data value to fetch
* @return The {@link SandstoneType} representing the given value, or null
* if it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static SandstoneType getByData(final byte data) {
return BY_DATA.get(data);
}
static {
for (SandstoneType type : values()) {
BY_DATA.put(type.data, type);
}
}
}

View File

@ -0,0 +1,976 @@
package org.bukkit;
import com.avaje.ebean.config.ServerConfig;
import com.google.common.collect.ImmutableList;
import org.bukkit.Warning.WarningState;
import org.bukkit.command.CommandException;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.server.ServerListPingEvent;
import org.bukkit.help.HelpMap;
import org.bukkit.inventory.*;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.map.MapView;
import org.bukkit.metadata.MetadataStore;
import org.bukkit.permissions.Permissible;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicesManager;
import org.bukkit.plugin.messaging.Messenger;
import org.bukkit.plugin.messaging.PluginMessageRecipient;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scoreboard.ScoreboardManager;
import org.bukkit.util.CachedServerIcon;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.Serializable;
import java.util.*;
import java.util.logging.Logger;
/**
* Represents a server implementation.
*/
public interface Server extends PluginMessageRecipient {
/**
* Used for all administrative messages, such as an operator using a
* command.
* <p>
* For use in {@link #broadcast(java.lang.String, java.lang.String)}.
*/
public static final String BROADCAST_CHANNEL_ADMINISTRATIVE = "bukkit.broadcast.admin";
/**
* Used for all announcement messages, such as informing users that a
* player has joined.
* <p>
* For use in {@link #broadcast(java.lang.String, java.lang.String)}.
*/
public static final String BROADCAST_CHANNEL_USERS = "bukkit.broadcast.user";
/**
* Gets the name of this server implementation.
*
* @return name of this server implementation
*/
public String getName();
/**
* Gets the version string of this server implementation.
*
* @return version of this server implementation
*/
public String getVersion();
/**
* Gets the Bukkit version that this server is running.
*
* @return version of Bukkit
*/
public String getBukkitVersion();
/**
* Gets an array copy of all currently logged in players.
* <p>
* This method exists for legacy reasons to provide backwards
* compatibility. It will not exist at runtime and should not be used
* under any circumstances.
*
* @Deprecated superseded by {@link #getOnlinePlayers()}
* @return an array of Players that are currently online
*/
@Deprecated
public Player[] _INVALID_getOnlinePlayers();
/**
* Gets a view of all currently logged in players. This {@linkplain
* Collections#unmodifiableCollection(Collection) view} is a reused
* object, making some operations like {@link Collection#size()}
* zero-allocation.
* <p>
* The collection is a view backed by the internal representation, such
* that, changes to the internal state of the server will be reflected
* immediately. However, the reuse of the returned collection (identity)
* is not strictly guaranteed for future or all implementations. Casting
* the collection, or relying on interface implementations (like {@link
* Serializable} or {@link List}), is deprecated.
* <p>
* Iteration behavior is undefined outside of self-contained main-thread
* uses. Normal and immediate iterator use without consequences that
* affect the collection are fully supported. The effects following
* (non-exhaustive) {@link Entity#teleport(Location) teleportation},
* {@link Player#setHealth(double) death}, and {@link Player#kickPlayer(
* String) kicking} are undefined. Any use of this collection from
* asynchronous threads is unsafe.
* <p>
* For safe consequential iteration or mimicking the old array behavior,
* using {@link Collection#toArray(Object[])} is recommended. For making
* snapshots, {@link ImmutableList#copyOf(Collection)} is recommended.
*
* @return a view of currently online players.
*/
public Collection<? extends Player> getOnlinePlayers();
/**
* Get the maximum amount of players which can login to this server.
*
* @return the amount of players this server allows
*/
public int getMaxPlayers();
/**
* Get the game port that the server runs on.
*
* @return the port number of this server
*/
public int getPort();
/**
* Get the view distance from this server.
*
* @return the view distance from this server.
*/
public int getViewDistance();
/**
* Get the IP that this server is bound to, or empty string if not
* specified.
*
* @return the IP string that this server is bound to, otherwise empty
* string
*/
public String getIp();
/**
* Get the name of this server.
*
* @return the name of this server
*/
public String getServerName();
/**
* Get an ID of this server. The ID is a simple generally alphanumeric ID
* that can be used for uniquely identifying this server.
*
* @return the ID of this server
*/
public String getServerId();
/**
* Get world type (level-type setting) for default world.
*
* @return the value of level-type (e.g. DEFAULT, FLAT, DEFAULT_1_1)
*/
public String getWorldType();
/**
* Get generate-structures setting.
*
* @return true if structure generation is enabled, false otherwise
*/
public boolean getGenerateStructures();
/**
* Gets whether this server allows the End or not.
*
* @return whether this server allows the End or not
*/
public boolean getAllowEnd();
/**
* Gets whether this server allows the Nether or not.
*
* @return whether this server allows the Nether or not
*/
public boolean getAllowNether();
/**
* Gets whether this server has a whitelist or not.
*
* @return whether this server has a whitelist or not
*/
public boolean hasWhitelist();
/**
* Sets if the server is whitelisted.
*
* @param value true for whitelist on, false for off
*/
public void setWhitelist(boolean value);
/**
* Gets a list of whitelisted players.
*
* @return a set containing all whitelisted players
*/
public Set<OfflinePlayer> getWhitelistedPlayers();
/**
* Reloads the whitelist from disk.
*/
public void reloadWhitelist();
/**
* Broadcast a message to all players.
* <p>
* This is the same as calling {@link #broadcast(java.lang.String,
* java.lang.String)} to {@link #BROADCAST_CHANNEL_USERS}
*
* @param message the message
* @return the number of players
*/
public int broadcastMessage(String message);
/**
* Gets the name of the update folder. The update folder is used to safely
* update plugins at the right moment on a plugin load.
* <p>
* The update folder name is relative to the plugins folder.
*
* @return the name of the update folder
*/
public String getUpdateFolder();
/**
* Gets the update folder. The update folder is used to safely update
* plugins at the right moment on a plugin load.
*
* @return the update folder
*/
public File getUpdateFolderFile();
/**
* Gets the value of the connection throttle setting.
*
* @return the value of the connection throttle setting
*/
public long getConnectionThrottle();
/**
* Gets default ticks per animal spawns value.
* <p>
* <b>Example Usage:</b>
* <ul>
* <li>A value of 1 will mean the server will attempt to spawn monsters
* every tick.
* <li>A value of 400 will mean the server will attempt to spawn monsters
* every 400th tick.
* <li>A value below 0 will be reset back to Minecraft's default.
* </ul>
* <p>
* <b>Note:</b> If set to 0, animal spawning will be disabled. We
* recommend using spawn-animals to control this instead.
* <p>
* Minecraft default: 400.
*
* @return the default ticks per animal spawns value
*/
public int getTicksPerAnimalSpawns();
/**
* Gets the default ticks per monster spawns value.
* <p>
* <b>Example Usage:</b>
* <ul>
* <li>A value of 1 will mean the server will attempt to spawn monsters
* every tick.
* <li>A value of 400 will mean the server will attempt to spawn monsters
* every 400th tick.
* <li>A value below 0 will be reset back to Minecraft's default.
* </ul>
* <p>
* <b>Note:</b> If set to 0, monsters spawning will be disabled. We
* recommend using spawn-monsters to control this instead.
* <p>
* Minecraft default: 1.
*
* @return the default ticks per monsters spawn value
*/
public int getTicksPerMonsterSpawns();
/**
* Gets a player object by the given username.
* <p>
* This method may not return objects for offline players.
*
* @param name the name to look up
* @return a player if one was found, null otherwise
*/
public Player getPlayer(String name);
/**
* Gets the player with the exact given name, case insensitive.
*
* @param name Exact name of the player to retrieve
* @return a player object if one was found, null otherwise
*/
public Player getPlayerExact(String name);
/**
* Attempts to match any players with the given name, and returns a list
* of all possibly matches.
* <p>
* This list is not sorted in any particular order. If an exact match is
* found, the returned list will only contain a single result.
*
* @param name the (partial) name to match
* @return list of all possible players
*/
public List<Player> matchPlayer(String name);
/**
* Gets the player with the given UUID.
*
* @param id UUID of the player to retrieve
* @return a player object if one was found, null otherwise
*/
public Player getPlayer(UUID id);
/**
* Gets the plugin manager for interfacing with plugins.
*
* @return a plugin manager for this Server instance
*/
public PluginManager getPluginManager();
/**
* Gets the scheduler for managing scheduled events.
*
* @return a scheduling service for this server
*/
public BukkitScheduler getScheduler();
/**
* Gets a services manager.
*
* @return s services manager
*/
public ServicesManager getServicesManager();
/**
* Gets a list of all worlds on this server.
*
* @return a list of worlds
*/
public List<World> getWorlds();
/**
* Creates or loads a world with the given name using the specified
* options.
* <p>
* If the world is already loaded, it will just return the equivalent of
* getWorld(creator.name()).
*
* @param creator the options to use when creating the world
* @return newly created or loaded world
*/
public World createWorld(WorldCreator creator);
/**
* Unloads a world with the given name.
*
* @param name Name of the world to unload
* @param save whether to save the chunks before unloading
* @return true if successful, false otherwise
*/
public boolean unloadWorld(String name, boolean save);
/**
* Unloads the given world.
*
* @param world the world to unload
* @param save whether to save the chunks before unloading
* @return true if successful, false otherwise
*/
public boolean unloadWorld(World world, boolean save);
/**
* Gets the world with the given name.
*
* @param name the name of the world to retrieve
* @return a world with the given name, or null if none exists
*/
public World getWorld(String name);
/**
* Gets the world from the given Unique ID.
*
* @param uid a unique-id of the world to retrieve
* @return a world with the given Unique ID, or null if none exists
*/
public World getWorld(UUID uid);
/**
* Gets the map from the given item ID.
*
* @param id the id of the map to get
* @return a map view if it exists, or null otherwise
* @deprecated Magic value
*/
@Deprecated
public MapView getMap(short id);
/**
* Create a new map with an automatically assigned ID.
*
* @param world the world the map will belong to
* @return a newly created map view
*/
public MapView createMap(World world);
/**
* Reloads the server, refreshing settings and plugin information.
*/
public void reload();
/**
* Returns the primary logger associated with this server instance.
*
* @return Logger associated with this server
*/
public Logger getLogger();
/**
* Gets a {@link PluginCommand} with the given name or alias.
*
* @param name the name of the command to retrieve
* @return a plugin command if found, null otherwise
*/
public PluginCommand getPluginCommand(String name);
/**
* Writes loaded players to disk.
*/
public void savePlayers();
/**
* Dispatches a command on this server, and executes it if found.
*
* @param sender the apparent sender of the command
* @param commandLine the command + arguments. Example: <code>test abc
* 123</code>
* @return returns false if no target is found
* @throws CommandException thrown when the executor for the given command
* fails with an unhandled exception
*/
public boolean dispatchCommand(CommandSender sender, String commandLine) throws CommandException;
/**
* Populates a given {@link ServerConfig} with values attributes to this
* server.
*
* @param config the server config to populate
*/
public void configureDbConfig(ServerConfig config);
/**
* Adds a recipe to the crafting manager.
*
* @param recipe the recipe to add
* @return true if the recipe was added, false if it wasn't for some
* reason
*/
public boolean addRecipe(Recipe recipe);
/**
* Get a list of all recipes for a given item. The stack size is ignored
* in comparisons. If the durability is -1, it will match any data value.
*
* @param result the item to match against recipe results
* @return a list of recipes with the given result
*/
public List<Recipe> getRecipesFor(ItemStack result);
/**
* Get an iterator through the list of crafting recipes.
*
* @return an iterator
*/
public Iterator<Recipe> recipeIterator();
/**
* Clears the list of crafting recipes.
*/
public void clearRecipes();
/**
* Resets the list of crafting recipes to the default.
*/
public void resetRecipes();
/**
* Gets a list of command aliases defined in the server properties.
*
* @return a map of aliases to command names
*/
public Map<String, String[]> getCommandAliases();
/**
* Gets the radius, in blocks, around each worlds spawn point to protect.
*
* @return spawn radius, or 0 if none
*/
public int getSpawnRadius();
/**
* Sets the radius, in blocks, around each worlds spawn point to protect.
*
* @param value new spawn radius, or 0 if none
*/
public void setSpawnRadius(int value);
/**
* Gets whether the Server is in online mode or not.
*
* @return true if the server authenticates clients, false otherwise
*/
public boolean getOnlineMode();
/**
* Gets whether this server allows flying or not.
*
* @return true if the server allows flight, false otherwise
*/
public boolean getAllowFlight();
/**
* Gets whether the server is in hardcore mode or not.
*
* @return true if the server mode is hardcore, false otherwise
*/
public boolean isHardcore();
/**
* Gets whether to use vanilla (false) or exact behaviour (true).
*
* <ul>
* <li>Vanilla behaviour: check for collisions and move the player if
* needed.
* <li>Exact behaviour: spawn players exactly where they should be.
* </ul>
*
* @return true if exact location locations are used for spawning, false
* for vanilla collision detection or otherwise
*/
public boolean useExactLoginLocation();
/**
* Shutdowns the server, stopping everything.
*/
public void shutdown();
/**
* Broadcasts the specified message to every user with the given
* permission name.
*
* @param message message to broadcast
* @param permission the required permission {@link Permissible
* permissibles} must have to receive the broadcast
* @return number of message recipients
*/
public int broadcast(String message, String permission);
/**
* Gets the player by the given name, regardless if they are offline or
* online.
* <p>
* This method may involve a blocking web request to get the UUID for the
* given name.
* <p>
* This will return an object even if the player does not exist. To this
* method, all players will exist.
*
* @deprecated Persistent storage of users should be by UUID as names are no longer
* unique past a single session.
* @param name the name the player to retrieve
* @return an offline player
* @see #getOfflinePlayer(java.util.UUID)
*/
@Deprecated
public OfflinePlayer getOfflinePlayer(String name);
/**
* Gets the player by the given UUID, regardless if they are offline or
* online.
* <p>
* This will return an object even if the player does not exist. To this
* method, all players will exist.
*
* @param id the UUID of the player to retrieve
* @return an offline player
*/
public OfflinePlayer getOfflinePlayer(UUID id);
/**
* Gets a set containing all current IPs that are banned.
*
* @return a set containing banned IP addresses
*/
public Set<String> getIPBans();
/**
* Bans the specified address from the server.
*
* @param address the IP address to ban
*/
public void banIP(String address);
/**
* Unbans the specified address from the server.
*
* @param address the IP address to unban
*/
public void unbanIP(String address);
/**
* Gets a set containing all banned players.
*
* @return a set containing banned players
*/
public Set<OfflinePlayer> getBannedPlayers();
/**
* Gets a ban list for the supplied type.
* <p>
* Bans by name are no longer supported and this method will return
* null when trying to request them. The replacement is bans by UUID.
*
* @param type the type of list to fetch, cannot be null
* @return a ban list of the specified type
*/
public BanList getBanList(BanList.Type type);
/**
* Gets a set containing all player operators.
*
* @return a set containing player operators
*/
public Set<OfflinePlayer> getOperators();
/**
* Gets the default {@link GameMode} for new players.
*
* @return the default game mode
*/
public GameMode getDefaultGameMode();
/**
* Sets the default {@link GameMode} for new players.
*
* @param mode the new game mode
*/
public void setDefaultGameMode(GameMode mode);
/**
* Gets a {@link ConsoleCommandSender} that may be used as an input source
* for this server.
*
* @return a console command sender
*/
public ConsoleCommandSender getConsoleSender();
/**
* Gets the metadata store for all entities.
*
* @return entity metadata store
*/
public MetadataStore<Entity> getEntityMetadata();
/**
* Gets the metadata store for all players.
*
* @return player metadata store
*/
public MetadataStore<OfflinePlayer> getPlayerMetadata();
/**
* Gets the metadata store for all worlds.
*
* @return world metadata store
*/
public MetadataStore<World> getWorldMetadata();
/**
* Gets the folder that contains all of the various {@link World}s.
*
* @return folder that contains all worlds
*/
public File getWorldContainer();
/**
* Gets every player that has ever played on this server.
*
* @return an array containing all previous players
*/
public OfflinePlayer[] getOfflinePlayers();
/**
* Gets the {@link Messenger} responsible for this server.
*
* @return messenger responsible for this server
*/
public Messenger getMessenger();
/**
* Gets the {@link HelpMap} providing help topics for this server.
*
* @return a help map for this server
*/
public HelpMap getHelpMap();
/**
* Creates an empty inventory of the specified type. If the type is {@link
* InventoryType#CHEST}, the new inventory has a size of 27; otherwise the
* new inventory has the normal size for its type.
*
* @param owner the holder of the inventory, or null to indicate no holder
* @param type the type of inventory to create
* @return a new inventory
*/
Inventory createInventory(InventoryHolder owner, InventoryType type);
/**
* Creates an empty inventory with the specified type and title. If the type
* is {@link InventoryType#CHEST}, the new inventory has a size of 27;
* otherwise the new inventory has the normal size for its type.<br />
* It should be noted that some inventory types do not support titles and
* may not render with said titles on the Minecraft client.
*
* @param owner The holder of the inventory; can be null if there's no holder.
* @param type The type of inventory to create.
* @param title The title of the inventory, to be displayed when it is viewed.
* @return The new inventory.
*/
Inventory createInventory(InventoryHolder owner, InventoryType type, String title);
/**
* Creates an empty inventory of type {@link InventoryType#CHEST} with the
* specified size.
*
* @param owner the holder of the inventory, or null to indicate no holder
* @param size a multiple of 9 as the size of inventory to create
* @return a new inventory
* @throws IllegalArgumentException if the size is not a multiple of 9
*/
Inventory createInventory(InventoryHolder owner, int size) throws IllegalArgumentException;
/**
* Creates an empty inventory of type {@link InventoryType#CHEST} with the
* specified size and title.
*
* @param owner the holder of the inventory, or null to indicate no holder
* @param size a multiple of 9 as the size of inventory to create
* @param title the title of the inventory, displayed when inventory is
* viewed
* @return a new inventory
* @throws IllegalArgumentException if the size is not a multiple of 9
*/
Inventory createInventory(InventoryHolder owner, int size, String title) throws IllegalArgumentException;
/**
* Gets user-specified limit for number of monsters that can spawn in a
* chunk.
*
* @return the monster spawn limit
*/
int getMonsterSpawnLimit();
/**
* Gets user-specified limit for number of animals that can spawn in a
* chunk.
*
* @return the animal spawn limit
*/
int getAnimalSpawnLimit();
/**
* Gets user-specified limit for number of water animals that can spawn in
* a chunk.
*
* @return the water animal spawn limit
*/
int getWaterAnimalSpawnLimit();
/**
* Gets user-specified limit for number of ambient mobs that can spawn in
* a chunk.
*
* @return the ambient spawn limit
*/
int getAmbientSpawnLimit();
/**
* Checks the current thread against the expected primary thread for the
* server.
* <p>
* <b>Note:</b> this method should not be used to indicate the current
* synchronized state of the runtime. A current thread matching the main
* thread indicates that it is synchronized, but a mismatch <b>does not
* preclude</b> the same assumption.
*
* @return true if the current thread matches the expected primary thread,
* false otherwise
*/
boolean isPrimaryThread();
/**
* Gets the message that is displayed on the server list.
*
* @return the servers MOTD
*/
String getMotd();
/**
* Gets the default message that is displayed when the server is stopped.
*
* @return the shutdown message
*/
String getShutdownMessage();
/**
* Gets the current warning state for the server.
*
* @return the configured warning state
*/
public WarningState getWarningState();
/**
* Gets the instance of the item factory (for {@link ItemMeta}).
*
* @return the item factory
* @see ItemFactory
*/
ItemFactory getItemFactory();
/**
* Gets the instance of the scoreboard manager.
* <p>
* This will only exist after the first world has loaded.
*
* @return the scoreboard manager or null if no worlds are loaded.
*/
ScoreboardManager getScoreboardManager();
/**
* Gets an instance of the server's default server-icon.
*
* @return the default server-icon; null values may be used by the
* implementation to indicate no defined icon, but this behavior is
* not guaranteed
*/
CachedServerIcon getServerIcon();
/**
* Loads an image from a file, and returns a cached image for the specific
* server-icon.
* <p>
* Size and type are implementation defined. An incompatible file is
* guaranteed to throw an implementation-defined {@link Exception}.
*
* @param file the file to load the from
* @throws IllegalArgumentException if image is null
* @throws Exception if the image does not meet current server server-icon
* specifications
* @return a cached server-icon that can be used for a {@link
* ServerListPingEvent#setServerIcon(CachedServerIcon)}
*/
CachedServerIcon loadServerIcon(File file) throws IllegalArgumentException, Exception;
/**
* Creates a cached server-icon for the specific image.
* <p>
* Size and type are implementation defined. An incompatible file is
* guaranteed to throw an implementation-defined {@link Exception}.
*
* @param image the image to use
* @throws IllegalArgumentException if image is null
* @throws Exception if the image does not meet current server
* server-icon specifications
* @return a cached server-icon that can be used for a {@link
* ServerListPingEvent#setServerIcon(CachedServerIcon)}
*/
CachedServerIcon loadServerIcon(BufferedImage image) throws IllegalArgumentException, Exception;
/**
* Set the idle kick timeout. Any players idle for the specified amount of
* time will be automatically kicked.
* <p>
* A value of 0 will disable the idle kick timeout.
*
* @param threshold the idle timeout in minutes
*/
public void setIdleTimeout(int threshold);
/**
* Gets the idle kick timeout.
*
* @return the idle timeout in minutes
*/
public int getIdleTimeout();
/**
* @see UnsafeValues
*/
@Deprecated
UnsafeValues getUnsafe();
public class Spigot
{
public org.bukkit.configuration.file.YamlConfiguration getConfig()
{
throw new UnsupportedOperationException( "Not supported yet." );
}
public org.bukkit.configuration.file.YamlConfiguration getBukkitConfig()
{
throw new UnsupportedOperationException( "Not supported yet." );
}
public org.bukkit.configuration.file.YamlConfiguration getSpigotConfig()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public org.bukkit.configuration.file.YamlConfiguration getPaperSpigotConfig()
{
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Sends the component to the player
*
* @param component the components to send
*/
public void broadcast(net.md_5.bungee.api.chat.BaseComponent component)
{
throw new UnsupportedOperationException( "Not supported yet." );
}
/**
* Sends an array of components as a single message to the
* player
*
* @param components the components to send
*/
public void broadcast(net.md_5.bungee.api.chat.BaseComponent ...components)
{
throw new UnsupportedOperationException( "Not supported yet." );
}
// PaperSpigot start - Add getTPS method
public double[] getTPS()
{
throw new UnsupportedOperationException( "Not supported yet." );
}
// PaperSpigot end
}
Spigot spigot();
}

View File

@ -0,0 +1,12 @@
package org.bukkit;
/**
* Represents the different types of skulls.
*/
public enum SkullType {
SKELETON,
WITHER,
ZOMBIE,
PLAYER,
CREEPER;
}

View File

@ -0,0 +1,211 @@
package org.bukkit;
/**
* An Enum of Sounds the server is able to send to players.
* <p>
* WARNING: At any time, sounds may be added/removed from this Enum or even
* MineCraft itself! There is no guarantee the sounds will play. There is no
* guarantee values will not be removed from this Enum. As such, you should
* not depend on the ordinal values of this class.
*/
public enum Sound {
AMBIENCE_CAVE,
AMBIENCE_RAIN,
AMBIENCE_THUNDER,
ANVIL_BREAK,
ANVIL_LAND,
ANVIL_USE,
ARROW_HIT,
BURP,
CHEST_CLOSE,
CHEST_OPEN,
CLICK,
DOOR_CLOSE,
DOOR_OPEN,
DRINK,
EAT,
EXPLODE,
FALL_BIG,
FALL_SMALL,
FIRE,
FIRE_IGNITE,
FIZZ,
FUSE,
GLASS,
HURT_FLESH,
ITEM_BREAK,
ITEM_PICKUP,
LAVA,
LAVA_POP,
LEVEL_UP,
MINECART_BASE,
MINECART_INSIDE,
NOTE_BASS,
NOTE_PIANO,
NOTE_BASS_DRUM,
NOTE_STICKS,
NOTE_BASS_GUITAR,
NOTE_SNARE_DRUM,
NOTE_PLING,
ORB_PICKUP,
PISTON_EXTEND,
PISTON_RETRACT,
PORTAL,
PORTAL_TRAVEL,
PORTAL_TRIGGER,
SHOOT_ARROW,
SPLASH,
SPLASH2,
STEP_GRASS,
STEP_GRAVEL,
STEP_LADDER,
STEP_SAND,
STEP_SNOW,
STEP_STONE,
STEP_WOOD,
STEP_WOOL,
SWIM,
WATER,
WOOD_CLICK,
// Mob sounds
BAT_DEATH,
BAT_HURT,
BAT_IDLE,
BAT_LOOP,
BAT_TAKEOFF,
BLAZE_BREATH,
BLAZE_DEATH,
BLAZE_HIT,
CAT_HISS,
CAT_HIT,
CAT_MEOW,
CAT_PURR,
CAT_PURREOW,
CHICKEN_IDLE,
CHICKEN_HURT,
CHICKEN_EGG_POP,
CHICKEN_WALK,
COW_IDLE,
COW_HURT,
COW_WALK,
CREEPER_HISS,
CREEPER_DEATH,
ENDERDRAGON_DEATH,
ENDERDRAGON_GROWL,
ENDERDRAGON_HIT,
ENDERDRAGON_WINGS,
ENDERMAN_DEATH,
ENDERMAN_HIT,
ENDERMAN_IDLE,
ENDERMAN_TELEPORT,
ENDERMAN_SCREAM,
ENDERMAN_STARE,
GHAST_SCREAM,
GHAST_SCREAM2,
GHAST_CHARGE,
GHAST_DEATH,
GHAST_FIREBALL,
GHAST_MOAN,
IRONGOLEM_DEATH,
IRONGOLEM_HIT,
IRONGOLEM_THROW,
IRONGOLEM_WALK,
MAGMACUBE_WALK,
MAGMACUBE_WALK2,
MAGMACUBE_JUMP,
PIG_IDLE,
PIG_DEATH,
PIG_WALK,
SHEEP_IDLE,
SHEEP_SHEAR,
SHEEP_WALK,
SILVERFISH_HIT,
SILVERFISH_KILL,
SILVERFISH_IDLE,
SILVERFISH_WALK,
SKELETON_IDLE,
SKELETON_DEATH,
SKELETON_HURT,
SKELETON_WALK,
SLIME_ATTACK,
SLIME_WALK,
SLIME_WALK2,
SPIDER_IDLE,
SPIDER_DEATH,
SPIDER_WALK,
WITHER_DEATH,
WITHER_HURT,
WITHER_IDLE,
WITHER_SHOOT,
WITHER_SPAWN,
WOLF_BARK,
WOLF_DEATH,
WOLF_GROWL,
WOLF_HOWL,
WOLF_HURT,
WOLF_PANT,
WOLF_SHAKE,
WOLF_WALK,
WOLF_WHINE,
ZOMBIE_METAL,
ZOMBIE_WOOD,
ZOMBIE_WOODBREAK,
ZOMBIE_IDLE,
ZOMBIE_DEATH,
ZOMBIE_HURT,
ZOMBIE_INFECT,
ZOMBIE_UNFECT,
ZOMBIE_REMEDY,
ZOMBIE_WALK,
ZOMBIE_PIG_IDLE,
ZOMBIE_PIG_ANGRY,
ZOMBIE_PIG_DEATH,
ZOMBIE_PIG_HURT,
// Dig Sounds
DIG_WOOL,
DIG_GRASS,
DIG_GRAVEL,
DIG_SAND,
DIG_SNOW,
DIG_STONE,
DIG_WOOD,
// Fireworks
FIREWORK_BLAST,
FIREWORK_BLAST2,
FIREWORK_LARGE_BLAST,
FIREWORK_LARGE_BLAST2,
FIREWORK_TWINKLE,
FIREWORK_TWINKLE2,
FIREWORK_LAUNCH,
SUCCESSFUL_HIT,
// Horses
HORSE_ANGRY,
HORSE_ARMOR,
HORSE_BREATHE,
HORSE_DEATH,
HORSE_GALLOP,
HORSE_HIT,
HORSE_IDLE,
HORSE_JUMP,
HORSE_LAND,
HORSE_SADDLE,
HORSE_SOFT,
HORSE_WOOD,
DONKEY_ANGRY,
DONKEY_DEATH,
DONKEY_HIT,
DONKEY_IDLE,
HORSE_SKELETON_DEATH,
HORSE_SKELETON_HIT,
HORSE_SKELETON_IDLE,
HORSE_ZOMBIE_DEATH,
HORSE_ZOMBIE_HIT,
HORSE_ZOMBIE_IDLE,
// Villager
VILLAGER_DEATH,
VILLAGER_HAGGLE,
VILLAGER_HIT,
VILLAGER_IDLE,
VILLAGER_NO,
VILLAGER_YES,
}

View File

@ -0,0 +1,108 @@
package org.bukkit;
/**
* Represents a countable statistic, which is tracked by the server.
*/
public enum Statistic {
DAMAGE_DEALT,
DAMAGE_TAKEN,
DEATHS,
MOB_KILLS,
PLAYER_KILLS,
FISH_CAUGHT,
ANIMALS_BRED,
TREASURE_FISHED,
JUNK_FISHED,
LEAVE_GAME,
JUMP,
DROP,
PLAY_ONE_TICK,
WALK_ONE_CM,
SWIM_ONE_CM,
FALL_ONE_CM,
CLIMB_ONE_CM,
FLY_ONE_CM,
DIVE_ONE_CM,
MINECART_ONE_CM,
BOAT_ONE_CM,
PIG_ONE_CM,
HORSE_ONE_CM,
MINE_BLOCK(Type.BLOCK),
USE_ITEM(Type.ITEM),
BREAK_ITEM(Type.ITEM),
CRAFT_ITEM(Type.ITEM),
KILL_ENTITY(Type.ENTITY),
ENTITY_KILLED_BY(Type.ENTITY);
private final Type type;
private Statistic() {
this(Type.UNTYPED);
}
private Statistic(Type type) {
this.type = type;
}
/**
* Gets the type of this statistic.
*
* @return the type of this statistic
*/
public Type getType() {
return type;
}
/**
* Checks if this is a substatistic.
* <p>
* A substatistic exists en masse for each block, item, or entitytype, depending on
* {@link #getType()}.
* <p>
* This is a redundant method and equivalent to checking
* <code>getType() != Type.UNTYPED</code>
*
* @return true if this is a substatistic
*/
public boolean isSubstatistic() {
return type != Type.UNTYPED;
}
/**
* Checks if this is a substatistic dealing with blocks.
* <p>
* This is a redundant method and equivalent to checking
* <code>getType() == Type.BLOCK</code>
*
* @return true if this deals with blocks
*/
public boolean isBlock() {
return type == Type.BLOCK;
}
/**
* The type of statistic.
*
*/
public enum Type {
/**
* Statistics of this type do not require a qualifier.
*/
UNTYPED,
/**
* Statistics of this type require an Item Material qualifier.
*/
ITEM,
/**
* Statistics of this type require a Block Material qualifier.
*/
BLOCK,
/**
* Statistics of this type require an EntityType qualifier.
*/
ENTITY;
}
}

View File

@ -0,0 +1,94 @@
package org.bukkit;
/**
* The Travel Agent handles the creation and the research of Nether and End
* portals when Entities try to use one.
* <p>
* It is used in {@link org.bukkit.event.entity.EntityPortalEvent} and in
* {@link org.bukkit.event.player.PlayerPortalEvent} to help developers
* reproduce and/or modify Vanilla behaviour.
*/
public interface TravelAgent {
/**
* Set the Block radius to search in for available portals.
*
* @param radius the radius in which to search for a portal from the
* location
* @return this travel agent
*/
public TravelAgent setSearchRadius(int radius);
/**
* Gets the search radius value for finding an available portal.
*
* @return the currently set search radius
*/
public int getSearchRadius();
/**
* Sets the maximum radius from the given location to create a portal.
*
* @param radius the radius in which to create a portal from the location
* @return this travel agent
*/
public TravelAgent setCreationRadius(int radius);
/**
* Gets the maximum radius from the given location to create a portal.
*
* @return the currently set creation radius
*/
public int getCreationRadius();
/**
* Returns whether the TravelAgent will attempt to create a destination
* portal or not.
*
* @return whether the TravelAgent should create a destination portal or
* not
*/
public boolean getCanCreatePortal();
/**
* Sets whether the TravelAgent should attempt to create a destination
* portal or not.
*
* @param create Sets whether the TravelAgent should create a destination
* portal or not
*/
public void setCanCreatePortal(boolean create);
/**
* Attempt to find a portal near the given location, if a portal is not
* found it will attempt to create one.
*
* @param location the location where the search for a portal should begin
* @return the location of a portal which has been found or returns the
* location passed to the method if unsuccessful
* @see #createPortal(Location)
*/
public Location findOrCreate(Location location);
/**
* Attempt to find a portal near the given location.
*
* @param location the desired location of the portal
* @return the location of the nearest portal to the location
*/
public Location findPortal(Location location);
/**
* Attempt to create a portal near the given location.
* <p>
* In the case of a Nether portal teleportation, this will attempt to
* create a Nether portal.
* <p>
* In the case of an Ender portal teleportation, this will (re-)create the
* obsidian platform and clean blocks above it.
*
* @param location the desired location of the portal
* @return true if a portal was successfully created
*/
public boolean createPortal(Location location);
}

View File

@ -0,0 +1,74 @@
package org.bukkit;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* Represents the different species of trees regardless of size.
*/
public enum TreeSpecies {
/**
* Represents the common tree species.
*/
GENERIC(0x0),
/**
* Represents the darker barked/leaved tree species.
*/
REDWOOD(0x1),
/**
* Represents birches.
*/
BIRCH(0x2),
/**
* Represents jungle trees.
*/
JUNGLE(0x3),
/**
* Represents acacia trees.
*/
ACACIA(0x4),
/**
* Represents dark oak trees.
*/
DARK_OAK(0x5),
;
private final byte data;
private final static Map<Byte, TreeSpecies> BY_DATA = Maps.newHashMap();
private TreeSpecies(final int data) {
this.data = (byte) data;
}
/**
* Gets the associated data value representing this species
*
* @return A byte containing the data value of this tree species
* @deprecated Magic value
*/
@Deprecated
public byte getData() {
return data;
}
/**
* Gets the TreeSpecies with the given data value
*
* @param data Data value to fetch
* @return The {@link TreeSpecies} representing the given value, or null
* if it doesn't exist
* @deprecated Magic value
*/
@Deprecated
public static TreeSpecies getByData(final byte data) {
return BY_DATA.get(data);
}
static {
for (TreeSpecies species : values()) {
BY_DATA.put(species.data, species);
}
}
}

View File

@ -0,0 +1,72 @@
package org.bukkit;
/**
* Tree and organic structure types.
*/
public enum TreeType {
/**
* Regular tree, no branches
*/
TREE,
/**
* Regular tree, extra tall with branches
*/
BIG_TREE,
/**
* Redwood tree, shaped like a pine tree
*/
REDWOOD,
/**
* Tall redwood tree with just a few leaves at the top
*/
TALL_REDWOOD,
/**
* Birch tree
*/
BIRCH,
/**
* Standard jungle tree; 4 blocks wide and tall
*/
JUNGLE,
/**
* Smaller jungle tree; 1 block wide
*/
SMALL_JUNGLE,
/**
* Jungle tree with cocoa plants; 1 block wide
*/
COCOA_TREE,
/**
* Small bush that grows in the jungle
*/
JUNGLE_BUSH,
/**
* Big red mushroom; short and fat
*/
RED_MUSHROOM,
/**
* Big brown mushroom; tall and umbrella-like
*/
BROWN_MUSHROOM,
/**
* Swamp tree (regular with vines on the side)
*/
SWAMP,
/**
* Acacia tree.
*/
ACACIA,
/**
* Dark Oak tree.
*/
DARK_OAK,
/**
* Mega redwood tree; 4 blocks wide and tall
*/
MEGA_REDWOOD,
/**
* Tall birch tree
*/
TALL_BIRCH,
}

View File

@ -0,0 +1,33 @@
package org.bukkit;
import java.util.List;
import org.bukkit.inventory.ItemStack;
/**
* This interface provides value conversions that may be specific to a
* runtime, or have arbitrary meaning (read: magic values).
* <p>
* Their existence and behavior is not guaranteed across future versions. They
* may be poorly named, throw exceptions, have misleading parameters, or any
* other bad programming practice.
* <p>
* This interface is unsupported and only for internal use.
*
* @deprecated Unsupported & internal use only
*/
@Deprecated
public interface UnsafeValues {
Material getMaterialFromInternalName(String name);
List<String> tabCompleteInternalMaterialName(String token, List<String> completions);
ItemStack modifyItemStack(ItemStack stack, String arguments);
Statistic getStatisticFromInternalName(String name);
Achievement getAchievementFromInternalName(String name);
List<String> tabCompleteInternalStatisticOrAchievementName(String token, List<String> completions);
}

View File

@ -0,0 +1,18 @@
package org.bukkit;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation indicates a method (and sometimes constructor) will chain
* its internal operations.
* <p>
* This is solely meant for identifying methods that don't need to be
* overridden / handled manually.
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Utility {
}

View File

@ -0,0 +1,109 @@
package org.bukkit;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
/**
* This designates the warning state for a specific item.
* <p>
* When the server settings dictate 'default' warnings, warnings are printed
* if the {@link #value()} is true.
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Warning {
/**
* This represents the states that server verbose for warnings may be.
*/
public enum WarningState {
/**
* Indicates all warnings should be printed for deprecated items.
*/
ON,
/**
* Indicates no warnings should be printed for deprecated items.
*/
OFF,
/**
* Indicates each warning would default to the configured {@link
* Warning} annotation, or always if annotation not found.
*/
DEFAULT;
private static final Map<String, WarningState> values = ImmutableMap.<String,WarningState>builder()
.put("off", OFF)
.put("false", OFF)
.put("f", OFF)
.put("no", OFF)
.put("n", OFF)
.put("on", ON)
.put("true", ON)
.put("t", ON)
.put("yes", ON)
.put("y", ON)
.put("", DEFAULT)
.put("d", DEFAULT)
.put("default", DEFAULT)
.build();
/**
* This method checks the provided warning should be printed for this
* state
*
* @param warning The warning annotation added to a deprecated item
* @return <ul>
* <li>ON is always True
* <li>OFF is always false
* <li>DEFAULT is false if and only if annotation is not null and
* specifies false for {@link Warning#value()}, true otherwise.
* </ul>
*/
public boolean printFor(Warning warning) {
if (this == DEFAULT) {
return warning == null || warning.value();
}
return this == ON;
}
/**
* This method returns the corresponding warning state for the given
* string value.
*
* @param value The string value to check
* @return {@link #DEFAULT} if not found, or the respective
* WarningState
*/
public static WarningState value(final String value) {
if (value == null) {
return DEFAULT;
}
WarningState state = values.get(value.toLowerCase());
if (state == null) {
return DEFAULT;
}
return state;
}
}
/**
* This sets if the deprecation warnings when registering events gets
* printed when the setting is in the default state.
*
* @return false normally, or true to encourage warning printout
*/
boolean value() default false;
/**
* This can provide detailed information on why the event is deprecated.
*
* @return The reason an event is deprecated
*/
String reason() default "";
}

View File

@ -0,0 +1,17 @@
package org.bukkit;
/**
* An enum of all current weather types
*/
public enum WeatherType {
/**
* Raining or snowing depending on biome.
*/
DOWNFALL,
/**
* Clear weather, clouds but no rain.
*/
CLEAR,
;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,295 @@
package org.bukkit;
import java.util.Random;
import org.bukkit.command.CommandSender;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
/**
* Represents various types of options that may be used to create a world.
*/
public class WorldCreator {
private final String name;
private long seed;
private World.Environment environment = World.Environment.NORMAL;
private ChunkGenerator generator = null;
private WorldType type = WorldType.NORMAL;
private boolean generateStructures = true;
/**
* Creates an empty WorldCreationOptions for the given world name
*
* @param name Name of the world that will be created
*/
public WorldCreator(String name) {
if (name == null) {
throw new IllegalArgumentException("World name cannot be null");
}
this.name = name;
this.seed = (new Random()).nextLong();
}
/**
* Copies the options from the specified world
*
* @param world World to copy options from
* @return This object, for chaining
*/
public WorldCreator copy(World world) {
if (world == null) {
throw new IllegalArgumentException("World cannot be null");
}
seed = world.getSeed();
environment = world.getEnvironment();
generator = world.getGenerator();
return this;
}
/**
* Copies the options from the specified {@link WorldCreator}
*
* @param creator World creator to copy options from
* @return This object, for chaining
*/
public WorldCreator copy(WorldCreator creator) {
if (creator == null) {
throw new IllegalArgumentException("Creator cannot be null");
}
seed = creator.seed();
environment = creator.environment();
generator = creator.generator();
return this;
}
/**
* Gets the name of the world that is to be loaded or created.
*
* @return World name
*/
public String name() {
return name;
}
/**
* Gets the seed that will be used to create this world
*
* @return World seed
*/
public long seed() {
return seed;
}
/**
* Sets the seed that will be used to create this world
*
* @param seed World seed
* @return This object, for chaining
*/
public WorldCreator seed(long seed) {
this.seed = seed;
return this;
}
/**
* Gets the environment that will be used to create or load the world
*
* @return World environment
*/
public World.Environment environment() {
return environment;
}
/**
* Sets the environment that will be used to create or load the world
*
* @param env World environment
* @return This object, for chaining
*/
public WorldCreator environment(World.Environment env) {
this.environment = env;
return this;
}
/**
* Gets the type of the world that will be created or loaded
*
* @return World type
*/
public WorldType type() {
return type;
}
/**
* Sets the type of the world that will be created or loaded
*
* @param type World type
* @return This object, for chaining
*/
public WorldCreator type(WorldType type) {
this.type = type;
return this;
}
/**
* Gets the generator that will be used to create or load the world.
* <p>
* This may be null, in which case the "natural" generator for this
* environment will be used.
*
* @return Chunk generator
*/
public ChunkGenerator generator() {
return generator;
}
/**
* Sets the generator that will be used to create or load the world.
* <p>
* This may be null, in which case the "natural" generator for this
* environment will be used.
*
* @param generator Chunk generator
* @return This object, for chaining
*/
public WorldCreator generator(ChunkGenerator generator) {
this.generator = generator;
return this;
}
/**
* Sets the generator that will be used to create or load the world.
* <p>
* This may be null, in which case the "natural" generator for this
* environment will be used.
* <p>
* If the generator cannot be found for the given name, the natural
* environment generator will be used instead and a warning will be
* printed to the console.
*
* @param generator Name of the generator to use, in "plugin:id" notation
* @return This object, for chaining
*/
public WorldCreator generator(String generator) {
this.generator = getGeneratorForName(name, generator, Bukkit.getConsoleSender());
return this;
}
/**
* Sets the generator that will be used to create or load the world.
* <p>
* This may be null, in which case the "natural" generator for this
* environment will be used.
* <p>
* If the generator cannot be found for the given name, the natural
* environment generator will be used instead and a warning will be
* printed to the specified output
*
* @param generator Name of the generator to use, in "plugin:id" notation
* @param output {@link CommandSender} that will receive any error
* messages
* @return This object, for chaining
*/
public WorldCreator generator(String generator, CommandSender output) {
this.generator = getGeneratorForName(name, generator, output);
return this;
}
/**
* Sets whether or not worlds created or loaded with this creator will
* have structures.
*
* @param generate Whether to generate structures
* @return This object, for chaining
*/
public WorldCreator generateStructures(boolean generate) {
this.generateStructures = generate;
return this;
}
/**
* Gets whether or not structures will be generated in the world.
*
* @return True if structures will be generated
*/
public boolean generateStructures() {
return generateStructures;
}
/**
* Creates a world with the specified options.
* <p>
* If the world already exists, it will be loaded from disk and some
* options may be ignored.
*
* @return Newly created or loaded world
*/
public World createWorld() {
return Bukkit.createWorld(this);
}
/**
* Creates a new {@link WorldCreator} for the given world name
*
* @param name Name of the world to load or create
* @return Resulting WorldCreator
*/
public static WorldCreator name(String name) {
return new WorldCreator(name);
}
/**
* Attempts to get the {@link ChunkGenerator} with the given name.
* <p>
* If the generator is not found, null will be returned and a message will
* be printed to the specified {@link CommandSender} explaining why.
* <p>
* The name must be in the "plugin:id" notation, or optionally just
* "plugin", where "plugin" is the safe-name of a plugin and "id" is an
* optional unique identifier for the generator you wish to request from
* the plugin.
*
* @param world Name of the world this will be used for
* @param name Name of the generator to retrieve
* @param output Where to output if errors are present
* @return Resulting generator, or null
*/
public static ChunkGenerator getGeneratorForName(String world, String name, CommandSender output) {
ChunkGenerator result = null;
if (world == null) {
throw new IllegalArgumentException("World name must be specified");
}
if (output == null) {
output = Bukkit.getConsoleSender();
}
if (name != null) {
String[] split = name.split(":", 2);
String id = (split.length > 1) ? split[1] : null;
Plugin plugin = Bukkit.getPluginManager().getPlugin(split[0]);
if (plugin == null) {
output.sendMessage("Could not set generator for world '" + world + "': Plugin '" + split[0] + "' does not exist");
} else if (!plugin.isEnabled()) {
output.sendMessage("Could not set generator for world '" + world + "': Plugin '" + plugin.getDescription().getFullName() + "' is not enabled");
} else {
result = plugin.getDefaultWorldGenerator(world, id);
}
}
return result;
}
}

View File

@ -0,0 +1,47 @@
package org.bukkit;
import com.google.common.collect.Maps;
import java.util.Map;
/**
* Represents various types of worlds that may exist
*/
public enum WorldType {
NORMAL("DEFAULT"),
FLAT("FLAT"),
VERSION_1_1("DEFAULT_1_1"),
LARGE_BIOMES("LARGEBIOMES"),
AMPLIFIED("AMPLIFIED");
private final static Map<String, WorldType> BY_NAME = Maps.newHashMap();
private final String name;
private WorldType(String name) {
this.name = name;
}
/**
* Gets the name of this WorldType
*
* @return Name of this type
*/
public String getName() {
return name;
}
/**
* Gets a Worldtype by its name
*
* @param name Name of the WorldType to get
* @return Requested WorldType, or null if not found
*/
public static WorldType getByName(String name) {
return BY_NAME.get(name.toUpperCase());
}
static {
for (WorldType type : values()) {
BY_NAME.put(type.name, type);
}
}
}

View File

@ -0,0 +1,9 @@
package org.bukkit.block;
import org.bukkit.inventory.InventoryHolder;
/**
* Represents a beacon.
*/
public interface Beacon extends BlockState, InventoryHolder {
}

View File

@ -0,0 +1,68 @@
package org.bukkit.block;
/**
* Holds all accepted Biomes in the default server
*/
public enum Biome {
SWAMPLAND,
FOREST,
TAIGA,
DESERT,
PLAINS,
HELL,
SKY,
OCEAN,
RIVER,
EXTREME_HILLS,
FROZEN_OCEAN,
FROZEN_RIVER,
ICE_PLAINS,
ICE_MOUNTAINS,
MUSHROOM_ISLAND,
MUSHROOM_SHORE,
BEACH,
DESERT_HILLS,
FOREST_HILLS,
TAIGA_HILLS,
SMALL_MOUNTAINS,
JUNGLE,
JUNGLE_HILLS,
JUNGLE_EDGE,
DEEP_OCEAN,
STONE_BEACH,
COLD_BEACH,
BIRCH_FOREST,
BIRCH_FOREST_HILLS,
ROOFED_FOREST,
COLD_TAIGA,
COLD_TAIGA_HILLS,
MEGA_TAIGA,
MEGA_TAIGA_HILLS,
EXTREME_HILLS_PLUS,
SAVANNA,
SAVANNA_PLATEAU,
MESA,
MESA_PLATEAU_FOREST,
MESA_PLATEAU,
SUNFLOWER_PLAINS,
DESERT_MOUNTAINS,
FLOWER_FOREST,
TAIGA_MOUNTAINS,
SWAMPLAND_MOUNTAINS,
ICE_PLAINS_SPIKES,
JUNGLE_MOUNTAINS,
JUNGLE_EDGE_MOUNTAINS,
COLD_TAIGA_MOUNTAINS,
SAVANNA_MOUNTAINS,
SAVANNA_PLATEAU_MOUNTAINS,
MESA_BRYCE,
MESA_PLATEAU_FOREST_MOUNTAINS,
MESA_PLATEAU_MOUNTAINS,
BIRCH_FOREST_MOUNTAINS,
BIRCH_FOREST_HILLS_MOUNTAINS,
ROOFED_FOREST_MOUNTAINS,
MEGA_SPRUCE_TAIGA,
EXTREME_HILLS_MOUNTAINS,
EXTREME_HILLS_PLUS_MOUNTAINS,
MEGA_SPRUCE_TAIGA_HILLS,
}

View File

@ -0,0 +1,393 @@
package org.bukkit.block;
import java.util.Collection;
import org.bukkit.AxisAlignedBB;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.Metadatable;
/**
* Represents a block. This is a live object, and only one Block may exist for
* any given location in a world. The state of the block may change
* concurrently to your own handling of it; use block.getState() to get a
* snapshot state of a block which will not be modified.
*/
public interface Block extends Metadatable {
/**
* Gets the metadata for this block
*
* @return block specific metadata
* @deprecated Magic value
*/
@Deprecated
byte getData();
/**
* Gets the block at the given offsets
*
* @param modX X-coordinate offset
* @param modY Y-coordinate offset
* @param modZ Z-coordinate offset
* @return Block at the given offsets
*/
Block getRelative(int modX, int modY, int modZ);
/**
* Gets the block at the given face
* <p>
* This method is equal to getRelative(face, 1)
*
* @param face Face of this block to return
* @return Block at the given face
* @see #getRelative(BlockFace, int)
*/
Block getRelative(BlockFace face);
/**
* Gets the block at the given distance of the given face
* <p>
* For example, the following method places water at 100,102,100; two
* blocks above 100,100,100.
*
* <pre>
* Block block = world.getBlockAt(100, 100, 100);
* Block shower = block.getRelative(BlockFace.UP, 2);
* shower.setType(Material.WATER);
* </pre>
*
* @param face Face of this block to return
* @param distance Distance to get the block at
* @return Block at the given face
*/
Block getRelative(BlockFace face, int distance);
/**
* Gets the type of this block
*
* @return block type
*/
Material getType();
/**
* Gets the type-id of this block
*
* @return block type-id
* @deprecated Magic value
*/
@Deprecated
int getTypeId();
/**
* Gets the light level between 0-15
*
* @return light level
*/
byte getLightLevel();
/**
* Get the amount of light at this block from the sky.
* <p>
* Any light given from other sources (such as blocks like torches) will
* be ignored.
*
* @return Sky light level
*/
byte getLightFromSky();
/**
* Get the amount of light at this block from nearby blocks.
* <p>
* Any light given from other sources (such as the sun) will be ignored.
*
* @return Block light level
*/
byte getLightFromBlocks();
/**
* Gets the world which contains this Block
*
* @return World containing this block
*/
World getWorld();
/**
* Gets the x-coordinate of this block
*
* @return x-coordinate
*/
int getX();
/**
* Gets the y-coordinate of this block
*
* @return y-coordinate
*/
int getY();
/**
* Gets the z-coordinate of this block
*
* @return z-coordinate
*/
int getZ();
/**
* Returns the bounding box of the block
*
* @return Bounding box of block
*/
AxisAlignedBB getBoundingBox();
/**
* Gets the Location of the block
*
* @return Location of block
*/
Location getLocation();
/**
* Stores the location of the block in the provided Location object.
* <p>
* If the provided Location is null this method does nothing and returns
* null.
*
* @return The Location object provided or null
*/
Location getLocation(Location loc);
/**
* Gets the chunk which contains this block
*
* @return Containing Chunk
*/
Chunk getChunk();
/**
* Sets the metadata for this block
*
* @param data New block specific metadata
* @deprecated Magic value
*/
@Deprecated
void setData(byte data);
/**
* Sets the metadata for this block
*
* @param data New block specific metadata
* @param applyPhysics False to cancel physics from the changed block.
* @deprecated Magic value
*/
@Deprecated
void setData(byte data, boolean applyPhysics);
/**
* Sets the type of this block
*
* @param type Material to change this block to
*/
void setType(Material type);
/**
* Sets the type-id of this block
*
* @param type Type-Id to change this block to
* @return whether the block was changed
* @deprecated Magic value
*/
@Deprecated
boolean setTypeId(int type);
/**
* Sets the type-id of this block
*
* @param type Type-Id to change this block to
* @param applyPhysics False to cancel physics on the changed block.
* @return whether the block was changed
* @deprecated Magic value
*/
@Deprecated
boolean setTypeId(int type, boolean applyPhysics);
/**
* Sets the type-id of this block
*
* @param type Type-Id to change this block to
* @param data The data value to change this block to
* @param applyPhysics False to cancel physics on the changed block
* @return whether the block was changed
* @deprecated Magic value
*/
@Deprecated
boolean setTypeIdAndData(int type, byte data, boolean applyPhysics);
/**
* Gets the face relation of this block compared to the given block
* <p>
* For example:
* <pre>
* Block current = world.getBlockAt(100, 100, 100);
* Block target = world.getBlockAt(100, 101, 100);
*
* current.getFace(target) == BlockFace.Up;
* </pre>
* <br />
* If the given block is not connected to this block, null may be returned
*
* @param block Block to compare against this block
* @return BlockFace of this block which has the requested block, or null
*/
BlockFace getFace(Block block);
/**
* Captures the current state of this block. You may then cast that state
* into any accepted type, such as Furnace or Sign.
* <p>
* The returned object will never be updated, and you are not guaranteed
* that (for example) a sign is still a sign after you capture its state.
*
* @return BlockState with the current state of this block.
*/
BlockState getState();
/**
* Returns the biome that this block resides in
*
* @return Biome type containing this block
*/
Biome getBiome();
/**
* Sets the biome that this block resides in
*
* @param bio new Biome type for this block
*/
void setBiome(Biome bio);
/**
* Returns true if the block is being powered by Redstone.
*
* @return True if the block is powered.
*/
boolean isBlockPowered();
/**
* Returns true if the block is being indirectly powered by Redstone.
*
* @return True if the block is indirectly powered.
*/
boolean isBlockIndirectlyPowered();
/**
* Returns true if the block face is being powered by Redstone.
*
* @param face The block face
* @return True if the block face is powered.
*/
boolean isBlockFacePowered(BlockFace face);
/**
* Returns true if the block face is being indirectly powered by Redstone.
*
* @param face The block face
* @return True if the block face is indirectly powered.
*/
boolean isBlockFaceIndirectlyPowered(BlockFace face);
/**
* Returns the redstone power being provided to this block face
*
* @param face the face of the block to query or BlockFace.SELF for the
* block itself
* @return The power level.
*/
int getBlockPower(BlockFace face);
/**
* Returns the redstone power being provided to this block
*
* @return The power level.
*/
int getBlockPower();
/**
* Checks if this block is empty.
* <p>
* A block is considered empty when {@link #getType()} returns {@link
* Material#AIR}.
*
* @return true if this block is empty
*/
boolean isEmpty();
/**
* Checks if this block is liquid.
* <p>
* A block is considered liquid when {@link #getType()} returns {@link
* Material#WATER}, {@link Material#STATIONARY_WATER}, {@link
* Material#LAVA} or {@link Material#STATIONARY_LAVA}.
*
* @return true if this block is liquid
*/
boolean isLiquid();
/**
* Gets the temperature of the biome of this block
*
* @return Temperature of this block
*/
double getTemperature();
/**
* Gets the humidity of the biome of this block
*
* @return Humidity of this block
*/
double getHumidity();
/**
* Returns the reaction of the block when moved by a piston
*
* @return reaction
*/
PistonMoveReaction getPistonMoveReaction();
/**
* Breaks the block and spawns items as if a player had digged it
*
* @return true if the block was destroyed
*/
boolean breakNaturally();
/**
* Breaks the block and spawns items as if a player had digged it with a
* specific tool
*
* @param tool The tool or item in hand used for digging
* @return true if the block was destroyed
*/
boolean breakNaturally(ItemStack tool);
/**
* Returns a list of items which would drop by destroying this block
*
* @return a list of dropped items for this type of block
*/
Collection<ItemStack> getDrops();
/**
* Returns a list of items which would drop by destroying this block with
* a specific tool
*
* @param tool The tool or item in hand used for digging
* @return a list of dropped items for this type of block
*/
Collection<ItemStack> getDrops(ItemStack tool);
// String getName();
}

View File

@ -0,0 +1,132 @@
package org.bukkit.block;
/**
* Represents the face of a block
*/
public enum BlockFace {
NORTH(0, 0, -1),
EAST(1, 0, 0),
SOUTH(0, 0, 1),
WEST(-1, 0, 0),
UP(0, 1, 0),
DOWN(0, -1, 0),
NORTH_EAST(NORTH, EAST),
NORTH_WEST(NORTH, WEST),
SOUTH_EAST(SOUTH, EAST),
SOUTH_WEST(SOUTH, WEST),
WEST_NORTH_WEST(WEST, NORTH_WEST),
NORTH_NORTH_WEST(NORTH, NORTH_WEST),
NORTH_NORTH_EAST(NORTH, NORTH_EAST),
EAST_NORTH_EAST(EAST, NORTH_EAST),
EAST_SOUTH_EAST(EAST, SOUTH_EAST),
SOUTH_SOUTH_EAST(SOUTH, SOUTH_EAST),
SOUTH_SOUTH_WEST(SOUTH, SOUTH_WEST),
WEST_SOUTH_WEST(WEST, SOUTH_WEST),
SELF(0, 0, 0);
private final int modX;
private final int modY;
private final int modZ;
private BlockFace(final int modX, final int modY, final int modZ) {
this.modX = modX;
this.modY = modY;
this.modZ = modZ;
}
private BlockFace(final BlockFace face1, final BlockFace face2) {
this.modX = face1.getModX() + face2.getModX();
this.modY = face1.getModY() + face2.getModY();
this.modZ = face1.getModZ() + face2.getModZ();
}
/**
* Get the amount of X-coordinates to modify to get the represented block
*
* @return Amount of X-coordinates to modify
*/
public int getModX() {
return modX;
}
/**
* Get the amount of Y-coordinates to modify to get the represented block
*
* @return Amount of Y-coordinates to modify
*/
public int getModY() {
return modY;
}
/**
* Get the amount of Z-coordinates to modify to get the represented block
*
* @return Amount of Z-coordinates to modify
*/
public int getModZ() {
return modZ;
}
public BlockFace getOppositeFace() {
switch (this) {
case NORTH:
return BlockFace.SOUTH;
case SOUTH:
return BlockFace.NORTH;
case EAST:
return BlockFace.WEST;
case WEST:
return BlockFace.EAST;
case UP:
return BlockFace.DOWN;
case DOWN:
return BlockFace.UP;
case NORTH_EAST:
return BlockFace.SOUTH_WEST;
case NORTH_WEST:
return BlockFace.SOUTH_EAST;
case SOUTH_EAST:
return BlockFace.NORTH_WEST;
case SOUTH_WEST:
return BlockFace.NORTH_EAST;
case WEST_NORTH_WEST:
return BlockFace.EAST_SOUTH_EAST;
case NORTH_NORTH_WEST:
return BlockFace.SOUTH_SOUTH_EAST;
case NORTH_NORTH_EAST:
return BlockFace.SOUTH_SOUTH_WEST;
case EAST_NORTH_EAST:
return BlockFace.WEST_SOUTH_WEST;
case EAST_SOUTH_EAST:
return BlockFace.WEST_NORTH_WEST;
case SOUTH_SOUTH_EAST:
return BlockFace.NORTH_NORTH_WEST;
case SOUTH_SOUTH_WEST:
return BlockFace.NORTH_NORTH_EAST;
case WEST_SOUTH_WEST:
return BlockFace.EAST_NORTH_EAST;
case SELF:
return BlockFace.SELF;
}
return BlockFace.SELF;
}
}

View File

@ -0,0 +1,194 @@
package org.bukkit.block;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.material.MaterialData;
import org.bukkit.metadata.Metadatable;
/**
* Represents a captured state of a block, which will not change
* automatically.
* <p>
* Unlike Block, which only one object can exist per coordinate, BlockState
* can exist multiple times for any given Block. Note that another plugin may
* change the state of the block and you will not know, or they may change the
* block to another type entirely, causing your BlockState to become invalid.
*/
public interface BlockState extends Metadatable {
/**
* Gets the block represented by this BlockState
*
* @return Block that this BlockState represents
*/
Block getBlock();
/**
* Gets the metadata for this block
*
* @return block specific metadata
*/
MaterialData getData();
/**
* Gets the type of this block
*
* @return block type
*/
Material getType();
/**
* Gets the type-id of this block
*
* @return block type-id
* @deprecated Magic value
*/
@Deprecated
int getTypeId();
/**
* Gets the light level between 0-15
*
* @return light level
*/
byte getLightLevel();
/**
* Gets the world which contains this Block
*
* @return World containing this block
*/
World getWorld();
/**
* Gets the x-coordinate of this block
*
* @return x-coordinate
*/
int getX();
/**
* Gets the y-coordinate of this block
*
* @return y-coordinate
*/
int getY();
/**
* Gets the z-coordinate of this block
*
* @return z-coordinate
*/
int getZ();
/**
* Gets the location of this block
*
* @return location
*/
Location getLocation();
/**
* Stores the location of this block in the provided Location object.
* <p>
* If the provided Location is null this method does nothing and returns
* null.
*
* @return The Location object provided or null
*/
Location getLocation(Location loc);
/**
* Gets the chunk which contains this block
*
* @return Containing Chunk
*/
Chunk getChunk();
/**
* Sets the metadata for this block
*
* @param data New block specific metadata
*/
void setData(MaterialData data);
/**
* Sets the type of this block
*
* @param type Material to change this block to
*/
void setType(Material type);
/**
* Sets the type-id of this block
*
* @param type Type-Id to change this block to
* @return Whether it worked?
* @deprecated Magic value
*/
@Deprecated
boolean setTypeId(int type);
/**
* Attempts to update the block represented by this state, setting it to
* the new values as defined by this state.
* <p>
* This has the same effect as calling update(false). That is to say,
* this will not modify the state of a block if it is no longer the same
* type as it was when this state was taken. It will return false in this
* eventuality.
*
* @return true if the update was successful, otherwise false
* @see #update(boolean)
*/
boolean update();
/**
* Attempts to update the block represented by this state, setting it to
* the new values as defined by this state.
* <p>
* This has the same effect as calling update(force, true). That is to
* say, this will trigger a physics update to surrounding blocks.
*
* @param force true to forcefully set the state
* @return true if the update was successful, otherwise false
*/
boolean update(boolean force);
/**
* Attempts to update the block represented by this state, setting it to
* the new values as defined by this state.
* <p>
* Unless force is true, this will not modify the state of a block if it
* is no longer the same type as it was when this state was taken. It will
* return false in this eventuality.
* <p>
* If force is true, it will set the type of the block to match the new
* state, set the state data and then return true.
* <p>
* If applyPhysics is true, it will trigger a physics update on
* surrounding blocks which could cause them to update or disappear.
*
* @param force true to forcefully set the state
* @param applyPhysics false to cancel updating physics on surrounding
* blocks
* @return true if the update was successful, otherwise false
*/
boolean update(boolean force, boolean applyPhysics);
/**
* @return The data as a raw byte.
* @deprecated Magic value
*/
@Deprecated
public byte getRawData();
/**
* @param data The new data value for the block.
* @deprecated Magic value
*/
@Deprecated
public void setRawData(byte data);
}

View File

@ -0,0 +1,25 @@
package org.bukkit.block;
import org.bukkit.inventory.BrewerInventory;
/**
* Represents a brewing stand.
*/
public interface BrewingStand extends BlockState, ContainerBlock {
/**
* How much time is left in the brewing cycle
*
* @return Brew Time
*/
int getBrewingTime();
/**
* Set the time left before brewing completes.
*
* @param brewTime Brewing time
*/
void setBrewingTime(int brewTime);
public BrewerInventory getInventory();
}

View File

@ -0,0 +1,17 @@
package org.bukkit.block;
import org.bukkit.inventory.Inventory;
/**
* Represents a chest.
*/
public interface Chest extends BlockState, ContainerBlock {
/**
* Returns the chest's inventory. If this is a double chest, it returns
* just the portion of the inventory linked to this half of the chest.
*
* @return The inventory.
*/
Inventory getBlockInventory();
}

View File

@ -0,0 +1,40 @@
package org.bukkit.block;
public interface CommandBlock extends BlockState {
/**
* Gets the command that this CommandBlock will run when powered.
* This will never return null. If the CommandBlock does not have a
* command, an empty String will be returned instead.
*
* @return Command that this CommandBlock will run when powered.
*/
public String getCommand();
/**
* Sets the command that this CommandBlock will run when powered.
* Setting the command to null is the same as setting it to an empty
* String.
*
* @param command Command that this CommandBlock will run when powered.
*/
public void setCommand(String command);
/**
* Gets the name of this CommandBlock. The name is used with commands
* that this CommandBlock executes. This name will never be null, and
* by default is "@".
*
* @return Name of this CommandBlock.
*/
public String getName();
/**
* Sets the name of this CommandBlock. The name is used with commands
* that this CommandBlock executes. Setting the name to null is the
* same as setting it to "@".
*
* @param name New name for this CommandBlock.
*/
public void setName(String name);
}

View File

@ -0,0 +1,11 @@
package org.bukkit.block;
import org.bukkit.inventory.InventoryHolder;
/**
* Indicates a block type that has inventory.
*
* @deprecated in favour of {@link InventoryHolder}
*/
@Deprecated
public interface ContainerBlock extends InventoryHolder {}

View File

@ -0,0 +1,88 @@
package org.bukkit.block;
import org.bukkit.entity.CreatureType;
import org.bukkit.entity.EntityType;
/**
* Represents a creature spawner.
*/
public interface CreatureSpawner extends BlockState {
/**
* Get the spawner's creature type.
*
* @return The creature type.
* @deprecated In favour of {@link #getSpawnedType()}.
*/
@Deprecated
public CreatureType getCreatureType();
/**
* Get the spawner's creature type.
*
* @return The creature type.
*/
public EntityType getSpawnedType();
/**
* Set the spawner's creature type.
*
* @param creatureType The creature type.
*/
public void setSpawnedType(EntityType creatureType);
/**
* Set the spawner creature type.
*
* @param creatureType The creature type.
* @deprecated In favour of {@link #setSpawnedType(EntityType)}.
*/
@Deprecated
public void setCreatureType(CreatureType creatureType);
/**
* Get the spawner's creature type.
*
* @return The creature type's name.
* @deprecated Use {@link #getCreatureTypeName()}.
*/
@Deprecated
public String getCreatureTypeId();
/**
* Set the spawner mob type.
*
* @param creatureType The creature type's name.
*/
public void setCreatureTypeByName(String creatureType);
/**
* Get the spawner's creature type.
*
* @return The creature type's name.
*/
public String getCreatureTypeName();
/**
* Set the spawner mob type.
*
* @param creatureType The creature type's name.
* @deprecated Use {@link #setCreatureTypeByName(String)}.
*/
@Deprecated
public void setCreatureTypeId(String creatureType);
/**
* Get the spawner's delay.
*
* @return The delay.
*/
public int getDelay();
/**
* Set the spawner's delay.
*
* @param delay The delay.
*/
public void setDelay(int delay);
}

View File

@ -0,0 +1,27 @@
package org.bukkit.block;
import org.bukkit.projectiles.BlockProjectileSource;
/**
* Represents a dispenser.
*/
public interface Dispenser extends BlockState, ContainerBlock {
/**
* Gets the BlockProjectileSource object for this dispenser.
* <p>
* If the block is no longer a dispenser, this will return null.
*
* @return a BlockProjectileSource if valid, otherwise null
*/
public BlockProjectileSource getBlockProjectileSource();
/**
* Attempts to dispense the contents of this block.
* <p>
* If the block is no longer a dispenser, this will return false.
*
* @return true if successful, otherwise false
*/
public boolean dispense();
}

View File

@ -0,0 +1,50 @@
package org.bukkit.block;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.inventory.DoubleChestInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
/**
* Represents a double chest.
*/
public class DoubleChest implements InventoryHolder {
private DoubleChestInventory inventory;
public DoubleChest(DoubleChestInventory chest) {
inventory = chest;
}
public Inventory getInventory() {
return inventory;
}
public InventoryHolder getLeftSide() {
return inventory.getLeftSide().getHolder();
}
public InventoryHolder getRightSide() {
return inventory.getRightSide().getHolder();
}
public Location getLocation() {
return new Location(getWorld(), getX(), getY(), getZ());
}
public World getWorld() {
return ((Chest)getLeftSide()).getWorld();
}
public double getX() {
return 0.5 * (((Chest)getLeftSide()).getX() + ((Chest)getRightSide()).getX());
}
public double getY() {
return 0.5 * (((Chest)getLeftSide()).getY() + ((Chest)getRightSide()).getY());
}
public double getZ() {
return 0.5 * (((Chest)getLeftSide()).getZ() + ((Chest)getRightSide()).getZ());
}
}

View File

@ -0,0 +1,25 @@
package org.bukkit.block;
import org.bukkit.inventory.InventoryHolder;
/**
* Represents a dropper.
*/
public interface Dropper extends BlockState, InventoryHolder {
/**
* Tries to drop a randomly selected item from the Dropper's inventory,
* following the normal behavior of a Dropper.
* <p>
* Normal behavior of a Dropper is as follows:
* <p>
* If the block that the Dropper is facing is an InventoryHolder or
* ContainerBlock the randomly selected ItemStack is placed within that
* Inventory in the first slot that's available, starting with 0 and
* counting up. If the inventory is full, nothing happens.
* <p>
* If the block that the Dropper is facing is not an InventoryHolder or
* ContainerBlock, the randomly selected ItemStack is dropped on
* the ground in the form of an {@link org.bukkit.entity.Item Item}.
*/
public void drop();
}

View File

@ -0,0 +1,57 @@
package org.bukkit.block;
import org.bukkit.inventory.FurnaceInventory;
/**
* Represents a furnace.
*/
public interface Furnace extends BlockState, ContainerBlock {
/**
* Gets the speed multiplier that this {@link Furnace} will cook
* compared to vanilla.
*
* @return the multiplier, a value between 0 and 200
*/
double getCookSpeedMultiplier() throws IllegalArgumentException;
/**
* Sets the speed multiplier that this {@link Furnace} will cook
* compared to vanilla.
*
* @param multiplier the multiplier to set, a value between 0 and 200
* @throws IllegalArgumentException if value is less than 0
* @throws IllegalArgumentException if value is more than 200
*/
void setCookSpeedMultiplier(double multiplier);
/**
* Get burn time.
*
* @return Burn time
*/
public short getBurnTime();
/**
* Set burn time.
*
* @param burnTime Burn time
*/
public void setBurnTime(short burnTime);
/**
* Get cook time.
*
* @return Cook time
*/
public short getCookTime();
/**
* Set cook time.
*
* @param cookTime Cook time
*/
public void setCookTime(short cookTime);
public FurnaceInventory getInventory();
}

View File

@ -0,0 +1,10 @@
package org.bukkit.block;
import org.bukkit.inventory.InventoryHolder;
/**
* Represents a hopper.
*/
public interface Hopper extends BlockState, InventoryHolder {
}

View File

@ -0,0 +1,36 @@
package org.bukkit.block;
import org.bukkit.Material;
/**
* Represents a Jukebox
*/
public interface Jukebox extends BlockState {
/**
* Get the record currently playing
*
* @return The record Material, or AIR if none is playing
*/
public Material getPlaying();
/**
* Set the record currently playing
*
* @param record The record Material, or null/AIR to stop playing
*/
public void setPlaying(Material record);
/**
* Check if the jukebox is currently playing a record
*
* @return True if there is a record playing
*/
public boolean isPlaying();
/**
* Stop the jukebox playing and eject the current record
*
* @return True if a record was ejected; false if there was none playing
*/
public boolean eject();
}

View File

@ -0,0 +1,72 @@
package org.bukkit.block;
import org.bukkit.Instrument;
import org.bukkit.Note;
/**
* Represents a note.
*/
public interface NoteBlock extends BlockState {
/**
* Gets the note.
*
* @return The note.
*/
public Note getNote();
/**
* Gets the note.
*
* @return The note ID.
* @deprecated Magic value
*/
@Deprecated
public byte getRawNote();
/**
* Set the note.
*
* @param note The note.
*/
public void setNote(Note note);
/**
* Set the note.
*
* @param note The note ID.
* @deprecated Magic value
*/
@Deprecated
public void setRawNote(byte note);
/**
* Attempts to play the note at block
* <p>
* If the block is no longer a note block, this will return false
*
* @return true if successful, otherwise false
*/
public boolean play();
/**
* Plays an arbitrary note with an arbitrary instrument
*
* @param instrument Instrument ID
* @param note Note ID
* @return true if successful, otherwise false
* @deprecated Magic value
*/
@Deprecated
public boolean play(byte instrument, byte note);
/**
* Plays an arbitrary note with an arbitrary instrument
*
* @param instrument The instrument
* @param note The note
* @return true if successful, otherwise false
* @see Instrument Note
*/
public boolean play(Instrument instrument, Note note);
}

View File

@ -0,0 +1,51 @@
package org.bukkit.block;
import java.util.HashMap;
import java.util.Map;
public enum PistonMoveReaction {
/**
* Indicates that the block can be pushed or pulled.
*/
MOVE(0),
/**
* Indicates the block is fragile and will break if pushed on.
*/
BREAK(1),
/**
* Indicates that the block will resist being pushed or pulled.
*/
BLOCK(2);
private int id;
private static Map<Integer, PistonMoveReaction> byId = new HashMap<Integer, PistonMoveReaction>();
static {
for (PistonMoveReaction reaction : PistonMoveReaction.values()) {
byId.put(reaction.id, reaction);
}
}
private PistonMoveReaction(int id) {
this.id = id;
}
/**
* @return The ID of the move reaction
* @deprecated Magic value
*/
@Deprecated
public int getId() {
return this.id;
}
/**
* @param id An ID
* @return The move reaction with that ID
* @deprecated Magic value
*/
@Deprecated
public static PistonMoveReaction getById(int id) {
return byId.get(id);
}
}

View File

@ -0,0 +1,51 @@
package org.bukkit.block;
/**
* Represents either a SignPost or a WallSign
*/
public interface Sign extends BlockState {
/**
* Gets all the lines of text currently on this sign.
*
* @return Array of Strings containing each line of text
*/
public String[] getLines();
/**
* Gets the line of text at the specified index.
* <p>
* For example, getLine(0) will return the first line of text.
*
* @param index Line number to get the text from, starting at 0
* @throws IndexOutOfBoundsException Thrown when the line does not exist
* @return Text on the given line
*/
public String getLine(int index) throws IndexOutOfBoundsException;
/**
* Sets the line of text at the specified index.
* <p>
* For example, setLine(0, "Line One") will set the first line of text to
* "Line One".
*
* @param index Line number to set the text at, starting from 0
* @param line New text to set at the specified index
* @throws IndexOutOfBoundsException If the index is out of the range 0..3
*/
public void setLine(int index, String line) throws IndexOutOfBoundsException;
/**
* Sets the editable status of this sign.
*
* @param editable the new status
*/
public void setEditable(boolean editable);
/**
* Returns whether or not this sign is editable.
*
* @return editable status
*/
public boolean isEditable();
}

View File

@ -0,0 +1,62 @@
package org.bukkit.block;
import org.bukkit.SkullType;
/**
* Represents a Skull
*/
public interface Skull extends BlockState {
/**
* Checks to see if the skull has an owner
*
* @return true if the skull has an owner
*/
public boolean hasOwner();
/**
* Gets the owner of the skull, if one exists
*
* @return the owner of the skull or null if the skull does not have an owner
*/
public String getOwner();
/**
* Sets the owner of the skull
* <p>
* Involves a potentially blocking web request to acquire the profile data for
* the provided name.
*
* @param name the new owner of the skull
* @return true if the owner was successfully set
*/
public boolean setOwner(String name);
/**
* Gets the rotation of the skull in the world
*
* @return the rotation of the skull
*/
public BlockFace getRotation();
/**
* Sets the rotation of the skull in the world
*
* @param rotation the rotation of the skull
*/
public void setRotation(BlockFace rotation);
/**
* Gets the type of skull
*
* @return the type of skull
*/
public SkullType getSkullType();
/**
* Sets the type of skull
*
* @param skullType the type of skull
*/
public void setSkullType(SkullType skullType);
}

View File

@ -0,0 +1,13 @@
package org.bukkit.command;
import org.bukkit.block.Block;
public interface BlockCommandSender extends CommandSender {
/**
* Returns the block this command sender belongs to
*
* @return Block for the command sender
*/
public Block getBlock();
}

View File

@ -0,0 +1,397 @@
package org.bukkit.command;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.entity.minecart.CommandMinecart;
import org.bukkit.permissions.Permissible;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.util.StringUtil;
import com.google.common.collect.ImmutableList;
/**
* Represents a Command, which executes various tasks upon user input
*/
public abstract class Command {
private final String name;
private String nextLabel;
private String label;
private List<String> aliases;
private List<String> activeAliases;
private CommandMap commandMap = null;
protected String description = "";
protected String usageMessage;
private String permission;
private String permissionMessage;
public co.aikar.timings.Timing timings; // Spigot
public String getTimingName() {return getName();} // Spigot
protected Command(String name) {
this(name, "", "/" + name, new ArrayList<String>());
}
protected Command(String name, String description, String usageMessage, List<String> aliases) {
this.name = name;
this.nextLabel = name;
this.label = name;
this.description = description;
this.usageMessage = usageMessage;
this.aliases = aliases;
this.activeAliases = new ArrayList<String>(aliases);
}
/**
* Executes the command, returning its success
*
* @param sender Source object which is executing this command
* @param commandLabel The alias of the command used
* @param args All arguments passed to the command, split via ' '
* @return true if the command was successful, otherwise false
*/
public abstract boolean execute(CommandSender sender, String commandLabel, String[] args);
/**
* @deprecated This method is not supported and returns null
*/
@Deprecated
public List<String> tabComplete(CommandSender sender, String[] args) {
return null;
}
/**
* Executed on tab completion for this command, returning a list of
* options the player can tab through.
*
* @param sender Source object which is executing this command
* @param alias the alias being used
* @param args All arguments passed to the command, split via ' '
* @return a list of tab-completions for the specified arguments. This
* will never be null. List may be immutable.
* @throws IllegalArgumentException if sender, alias, or args is null
*/
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
Validate.notNull(sender, "Sender cannot be null");
Validate.notNull(args, "Arguments cannot be null");
Validate.notNull(alias, "Alias cannot be null");
if (args.length == 0) {
return ImmutableList.of();
}
String lastWord = args[args.length - 1];
Player senderPlayer = sender instanceof Player ? (Player) sender : null;
ArrayList<String> matchedPlayers = new ArrayList<String>();
for (Player player : sender.getServer().getOnlinePlayers()) {
String name = player.getName();
if ((senderPlayer == null || senderPlayer.canSee(player)) && StringUtil.startsWithIgnoreCase(name, lastWord)) {
matchedPlayers.add(name);
}
}
Collections.sort(matchedPlayers, String.CASE_INSENSITIVE_ORDER);
return matchedPlayers;
}
/**
* Returns the name of this command
*
* @return Name of this command
*/
public String getName() {
return name;
}
/**
* Gets the permission required by users to be able to perform this
* command
*
* @return Permission name, or null if none
*/
public String getPermission() {
return permission;
}
/**
* Sets the permission required by users to be able to perform this
* command
*
* @param permission Permission name or null
*/
public void setPermission(String permission) {
this.permission = permission;
}
/**
* Tests the given {@link CommandSender} to see if they can perform this
* command.
* <p>
* If they do not have permission, they will be informed that they cannot
* do this.
*
* @param target User to test
* @return true if they can use it, otherwise false
*/
public boolean testPermission(CommandSender target) {
if (testPermissionSilent(target)) {
return true;
}
if (permissionMessage == null) {
target.sendMessage(ChatColor.RED + "You don't have permission to use this command.");
} else if (permissionMessage.length() != 0) {
for (String line : permissionMessage.replace("<permission>", permission).split("\n")) {
target.sendMessage(line);
}
}
return false;
}
/**
* Tests the given {@link CommandSender} to see if they can perform this
* command.
* <p>
* No error is sent to the sender.
*
* @param target User to test
* @return true if they can use it, otherwise false
*/
public boolean testPermissionSilent(CommandSender target) {
if ((permission == null) || (permission.length() == 0)) {
return true;
}
for (String p : permission.split(";")) {
if (target.hasPermission(p)) {
return true;
}
}
return false;
}
/**
* Returns the current label for this command
*
* @return Label of this command or null if not registered
*/
public String getLabel() {
return label;
}
/**
* Sets the label of this command.
* <p>
* If the command is currently registered the label change will only take
* effect after its been re-registered e.g. after a /reload
*
* @param name The command's name
* @return returns true if the name change happened instantly or false if
* it was scheduled for re-registration
*/
public boolean setLabel(String name) {
this.nextLabel = name;
if (!isRegistered()) {
this.label = name;
return true;
}
return false;
}
/**
* Registers this command to a CommandMap.
* Once called it only allows changes the registered CommandMap
*
* @param commandMap the CommandMap to register this command to
* @return true if the registration was successful (the current registered
* CommandMap was the passed CommandMap or null) false otherwise
*/
public boolean register(CommandMap commandMap) {
if (allowChangesFrom(commandMap)) {
this.commandMap = commandMap;
return true;
}
return false;
}
/**
* Unregisters this command from the passed CommandMap applying any
* outstanding changes
*
* @param commandMap the CommandMap to unregister
* @return true if the unregistration was successfull (the current
* registered CommandMap was the passed CommandMap or null) false
* otherwise
*/
public boolean unregister(CommandMap commandMap) {
if (allowChangesFrom(commandMap)) {
this.commandMap = null;
this.activeAliases = new ArrayList<String>(this.aliases);
this.label = this.nextLabel;
return true;
}
return false;
}
private boolean allowChangesFrom(CommandMap commandMap) {
return (null == this.commandMap || this.commandMap == commandMap);
}
/**
* Returns the current registered state of this command
*
* @return true if this command is currently registered false otherwise
*/
public boolean isRegistered() {
return (null != this.commandMap);
}
/**
* Returns a list of active aliases of this command
*
* @return List of aliases
*/
public List<String> getAliases() {
return activeAliases;
}
/**
* Returns a message to be displayed on a failed permission check for this
* command
*
* @return Permission check failed message
*/
public String getPermissionMessage() {
return permissionMessage;
}
/**
* Gets a brief description of this command
*
* @return Description of this command
*/
public String getDescription() {
return description;
}
/**
* Gets an example usage of this command
*
* @return One or more example usages
*/
public String getUsage() {
return usageMessage;
}
/**
* Sets the list of aliases to request on registration for this command.
* This is not effective outside of defining aliases in the {@link
* PluginDescriptionFile#getCommands()} (under the
* `<code>aliases</code>' node) is equivalent to this method.
*
* @param aliases aliases to register to this command
* @return this command object, for chaining
*/
public Command setAliases(List<String> aliases) {
this.aliases = aliases;
if (!isRegistered()) {
this.activeAliases = new ArrayList<String>(aliases);
}
return this;
}
/**
* Sets a brief description of this command. Defining a description in the
* {@link PluginDescriptionFile#getCommands()} (under the
* `<code>description</code>' node) is equivalent to this method.
*
* @param description new command description
* @return this command object, for chaining
*/
public Command setDescription(String description) {
this.description = description;
return this;
}
/**
* Sets the message sent when a permission check fails
*
* @param permissionMessage new permission message, null to indicate
* default message, or an empty string to indicate no message
* @return this command object, for chaining
*/
public Command setPermissionMessage(String permissionMessage) {
this.permissionMessage = permissionMessage;
return this;
}
/**
* Sets the example usage of this command
*
* @param usage new example usage
* @return this command object, for chaining
*/
public Command setUsage(String usage) {
this.usageMessage = usage;
return this;
}
public static void broadcastCommandMessage(CommandSender source, String message) {
broadcastCommandMessage(source, message, true);
}
public static void broadcastCommandMessage(CommandSender source, String message, boolean sendToSource) {
String result = source.getName() + ": " + message;
if (source instanceof BlockCommandSender) {
BlockCommandSender blockCommandSender = (BlockCommandSender) source;
if (blockCommandSender.getBlock().getWorld().getGameRuleValue("commandBlockOutput").equalsIgnoreCase("false")) {
Bukkit.getConsoleSender().sendMessage(result);
return;
}
} else if (source instanceof CommandMinecart) {
CommandMinecart commandMinecart = (CommandMinecart) source;
if (commandMinecart.getWorld().getGameRuleValue("commandBlockOutput").equalsIgnoreCase("false")) {
Bukkit.getConsoleSender().sendMessage(result);
return;
}
}
Set<Permissible> users = Bukkit.getPluginManager().getPermissionSubscriptions(Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
String colored = ChatColor.GRAY + "" + ChatColor.ITALIC + "[" + result + ChatColor.GRAY + ChatColor.ITALIC + "]";
if (sendToSource && !(source instanceof ConsoleCommandSender)) {
source.sendMessage(message);
}
for (Permissible user : users) {
if (user instanceof CommandSender && user.hasPermission(Server.BROADCAST_CHANNEL_ADMINISTRATIVE)) {
CommandSender target = (CommandSender) user;
if (target instanceof ConsoleCommandSender) {
target.sendMessage(result);
} else if (target != source) {
target.sendMessage(colored);
}
}
}
}
@Override
public String toString() {
return getClass().getName() + '(' + name + ')';
}
}

View File

@ -0,0 +1,28 @@
package org.bukkit.command;
/**
* Thrown when an unhandled exception occurs during the execution of a Command
*/
@SuppressWarnings("serial")
public class CommandException extends RuntimeException {
/**
* Creates a new instance of <code>CommandException</code> without detail
* message.
*/
public CommandException() {}
/**
* Constructs an instance of <code>CommandException</code> with the
* specified detail message.
*
* @param msg the detail message.
*/
public CommandException(String msg) {
super(msg);
}
public CommandException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,18 @@
package org.bukkit.command;
/**
* Represents a class which contains a single method for executing commands
*/
public interface CommandExecutor {
/**
* Executes the given command, returning its success
*
* @param sender Source of the command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return true if a valid command, otherwise false
*/
public boolean onCommand(CommandSender sender, Command command, String label, String[] args);
}

View File

@ -0,0 +1,109 @@
package org.bukkit.command;
import java.util.List;
public interface CommandMap {
/**
* Registers all the commands belonging to a certain plugin.
* <p>
* Caller can use:-
* <ul>
* <li>command.getName() to determine the label registered for this
* command
* <li>command.getAliases() to determine the aliases which where
* registered
* </ul>
*
* @param fallbackPrefix a prefix which is prepended to each command with
* a ':' one or more times to make the command unique
* @param commands a list of commands to register
*/
public void registerAll(String fallbackPrefix, List<Command> commands);
/**
* Registers a command. Returns true on success; false if name is already
* taken and fallback had to be used.
* <p>
* Caller can use:-
* <ul>
* <li>command.getName() to determine the label registered for this
* command
* <li>command.getAliases() to determine the aliases which where
* registered
* </ul>
*
* @param label the label of the command, without the '/'-prefix.
* @param fallbackPrefix a prefix which is prepended to the command with a
* ':' one or more times to make the command unique
* @param command the command to register
* @return true if command was registered with the passed in label, false
* otherwise, which indicates the fallbackPrefix was used one or more
* times
*/
public boolean register(String label, String fallbackPrefix, Command command);
/**
* Registers a command. Returns true on success; false if name is already
* taken and fallback had to be used.
* <p>
* Caller can use:-
* <ul>
* <li>command.getName() to determine the label registered for this
* command
* <li>command.getAliases() to determine the aliases which where
* registered
* </ul>
*
* @param fallbackPrefix a prefix which is prepended to the command with a
* ':' one or more times to make the command unique
* @param command the command to register, from which label is determined
* from the command name
* @return true if command was registered with the passed in label, false
* otherwise, which indicates the fallbackPrefix was used one or more
* times
*/
public boolean register(String fallbackPrefix, Command command);
/**
* Looks for the requested command and executes it if found.
*
* @param sender The command's sender
* @param cmdLine command + arguments. Example: "/test abc 123"
* @return returns false if no target is found, true otherwise.
* @throws CommandException Thrown when the executor for the given command
* fails with an unhandled exception
*/
public boolean dispatch(CommandSender sender, String cmdLine) throws CommandException;
/**
* Clears all registered commands.
*/
public void clearCommands();
/**
* Gets the command registered to the specified name
*
* @param name Name of the command to retrieve
* @return Command with the specified name or null if a command with that
* label doesn't exist
*/
public Command getCommand(String name);
/**
* Looks for the requested command and executes an appropriate
* tab-completer if found. This method will also tab-complete partial
* commands.
*
* @param sender The command's sender.
* @param cmdLine The entire command string to tab-complete, excluding
* initial slash.
* @return a list of possible tab-completions. This list may be immutable.
* Will be null if no matching command of which sender has permission.
* @throws CommandException Thrown when the tab-completer for the given
* command fails with an unhandled exception
* @throws IllegalArgumentException if either sender or cmdLine are null
*/
public List<String> tabComplete(CommandSender sender, String cmdLine) throws IllegalArgumentException;
}

View File

@ -0,0 +1,35 @@
package org.bukkit.command;
import org.bukkit.Server;
import org.bukkit.permissions.Permissible;
public interface CommandSender extends Permissible {
/**
* Sends this sender a message
*
* @param message Message to be displayed
*/
public void sendMessage(String message);
/**
* Sends this sender multiple messages
*
* @param messages An array of messages to be displayed
*/
public void sendMessage(String[] messages);
/**
* Returns the server instance that this command is running on
*
* @return Server instance
*/
public Server getServer();
/**
* Gets the name of this command sender
*
* @return Name of the sender
*/
public String getName();
}

View File

@ -0,0 +1,6 @@
package org.bukkit.command;
import org.bukkit.conversations.Conversable;
public interface ConsoleCommandSender extends CommandSender, Conversable {
}

View File

@ -0,0 +1,120 @@
package org.bukkit.command;
import java.util.ArrayList;
import org.bukkit.Bukkit;
public class FormattedCommandAlias extends Command {
private final String[] formatStrings;
public FormattedCommandAlias(String alias, String[] formatStrings) {
super(alias);
timings = co.aikar.timings.TimingsManager.getCommandTiming("minecraft", this); // Spigot
this.formatStrings = formatStrings;
}
@Override
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
boolean result = false;
ArrayList<String> commands = new ArrayList<String>();
for (String formatString : formatStrings) {
try {
commands.add(buildCommand(formatString, args));
} catch (Throwable throwable) {
if (throwable instanceof IllegalArgumentException) {
sender.sendMessage(throwable.getMessage());
} else {
sender.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command");
}
return false;
}
}
for (String command : commands) {
result |= Bukkit.dispatchCommand(sender, command);
}
return result;
}
private String buildCommand(String formatString, String[] args) {
int index = formatString.indexOf("$");
while (index != -1) {
int start = index;
if (index > 0 && formatString.charAt(start - 1) == '\\') {
formatString = formatString.substring(0, start - 1) + formatString.substring(start);
index = formatString.indexOf("$", index);
continue;
}
boolean required = false;
if (formatString.charAt(index + 1) == '$') {
required = true;
// Move index past the second $
index++;
}
// Move index past the $
index++;
int argStart = index;
while (index < formatString.length() && inRange(((int) formatString.charAt(index)) - 48, 0, 9)) {
// Move index past current digit
index++;
}
// No numbers found
if (argStart == index) {
throw new IllegalArgumentException("Invalid replacement token");
}
int position = Integer.valueOf(formatString.substring(argStart, index));
// Arguments are not 0 indexed
if (position == 0) {
throw new IllegalArgumentException("Invalid replacement token");
}
// Convert position to 0 index
position--;
boolean rest = false;
if (index < formatString.length() && formatString.charAt(index) == '-') {
rest = true;
// Move index past the -
index++;
}
int end = index;
if (required && position >= args.length) {
throw new IllegalArgumentException("Missing required argument " + (position + 1));
}
StringBuilder replacement = new StringBuilder();
if (rest && position < args.length) {
for (int i = position; i < args.length; i++) {
if (i != position) {
replacement.append(' ');
}
replacement.append(args[i]);
}
} else if (position < args.length) {
replacement.append(args[position]);
}
formatString = formatString.substring(0, start) + replacement.toString() + formatString.substring(end);
// Move index past the replaced data so we don't process it again
index = start + replacement.length();
// Move to the next replacement token
index = formatString.indexOf("$", index);
}
return formatString;
}
private static boolean inRange(int i, int j, int k) {
return i >= j && i <= k;
}
}

View File

@ -0,0 +1,33 @@
package org.bukkit.command;
/**
* Represents a command that delegates to one or more other commands
*/
public class MultipleCommandAlias extends Command {
private Command[] commands;
public MultipleCommandAlias(String name, Command[] commands) {
super(name);
this.commands = commands;
}
/**
* Gets the commands associated with the multi-command alias.
*
* @return commands associated with alias
*/
public Command[] getCommands() {
return commands;
}
@Override
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
boolean result = false;
for (Command command : commands) {
result |= command.execute(sender, commandLabel, args);
}
return result;
}
}

View File

@ -0,0 +1,160 @@
package org.bukkit.command;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.bukkit.plugin.Plugin;
/**
* Represents a {@link Command} belonging to a plugin
*/
public final class PluginCommand extends Command implements PluginIdentifiableCommand {
private final Plugin owningPlugin;
private CommandExecutor executor;
private TabCompleter completer;
protected PluginCommand(String name, Plugin owner) {
super(name);
this.executor = owner;
this.owningPlugin = owner;
this.usageMessage = "";
}
/**
* Executes the command, returning its success
*
* @param sender Source object which is executing this command
* @param commandLabel The alias of the command used
* @param args All arguments passed to the command, split via ' '
* @return true if the command was successful, otherwise false
*/
@Override
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
boolean success = false;
if (!owningPlugin.isEnabled()) {
return false;
}
if (!testPermission(sender)) {
return true;
}
try {
success = executor.onCommand(sender, this, commandLabel, args);
} catch (Throwable ex) {
throw new CommandException("Unhandled exception executing command '" + commandLabel + "' in plugin " + owningPlugin.getDescription().getFullName(), ex);
}
if (!success && usageMessage.length() > 0) {
for (String line : usageMessage.replace("<command>", commandLabel).split("\n")) {
sender.sendMessage(line);
}
}
return success;
}
/**
* Sets the {@link CommandExecutor} to run when parsing this command
*
* @param executor New executor to run
*/
public void setExecutor(CommandExecutor executor) {
this.executor = executor == null ? owningPlugin : executor;
}
/**
* Gets the {@link CommandExecutor} associated with this command
*
* @return CommandExecutor object linked to this command
*/
public CommandExecutor getExecutor() {
return executor;
}
/**
* Sets the {@link TabCompleter} to run when tab-completing this command.
* <p>
* If no TabCompleter is specified, and the command's executor implements
* TabCompleter, then the executor will be used for tab completion.
*
* @param completer New tab completer
*/
public void setTabCompleter(TabCompleter completer) {
this.completer = completer;
}
/**
* Gets the {@link TabCompleter} associated with this command.
*
* @return TabCompleter object linked to this command
*/
public TabCompleter getTabCompleter() {
return completer;
}
/**
* Gets the owner of this PluginCommand
*
* @return Plugin that owns this command
*/
public Plugin getPlugin() {
return owningPlugin;
}
/**
* {@inheritDoc}
* <p>
* Delegates to the tab completer if present.
* <p>
* If it is not present or returns null, will delegate to the current
* command executor if it implements {@link TabCompleter}. If a non-null
* list has not been found, will default to standard player name
* completion in {@link
* Command#tabComplete(CommandSender, String, String[])}.
* <p>
* This method does not consider permissions.
*
* @throws CommandException if the completer or executor throw an
* exception during the process of tab-completing.
* @throws IllegalArgumentException if sender, alias, or args is null
*/
@Override
public java.util.List<String> tabComplete(CommandSender sender, String alias, String[] args) throws CommandException, IllegalArgumentException {
Validate.notNull(sender, "Sender cannot be null");
Validate.notNull(args, "Arguments cannot be null");
Validate.notNull(alias, "Alias cannot be null");
List<String> completions = null;
try {
if (completer != null) {
completions = completer.onTabComplete(sender, this, alias, args);
}
if (completions == null && executor instanceof TabCompleter) {
completions = ((TabCompleter) executor).onTabComplete(sender, this, alias, args);
}
} catch (Throwable ex) {
StringBuilder message = new StringBuilder();
message.append("Unhandled exception during tab completion for command '/").append(alias).append(' ');
for (String arg : args) {
message.append(arg).append(' ');
}
message.deleteCharAt(message.length() - 1).append("' in plugin ").append(owningPlugin.getDescription().getFullName());
throw new CommandException(message.toString(), ex);
}
if (completions == null) {
return super.tabComplete(sender, alias, args);
}
return completions;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder(super.toString());
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
stringBuilder.append(", ").append(owningPlugin.getDescription().getFullName()).append(')');
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,76 @@
package org.bukkit.command;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
public class PluginCommandYamlParser {
public static List<Command> parse(Plugin plugin) {
List<Command> pluginCmds = new ArrayList<Command>();
Map<String, Map<String, Object>> map = plugin.getDescription().getCommands();
if (map == null) {
return pluginCmds;
}
for (Entry<String, Map<String, Object>> entry : map.entrySet()) {
if (entry.getKey().contains(":")) {
Bukkit.getServer().getLogger().severe("Could not load command " + entry.getKey() + " for plugin " + plugin.getName() + ": Illegal Characters");
continue;
}
Command newCmd = new PluginCommand(entry.getKey(), plugin);
Object description = entry.getValue().get("description");
Object usage = entry.getValue().get("usage");
Object aliases = entry.getValue().get("aliases");
Object permission = entry.getValue().get("permission");
Object permissionMessage = entry.getValue().get("permission-message");
if (description != null) {
newCmd.setDescription(description.toString());
}
if (usage != null) {
newCmd.setUsage(usage.toString());
}
if (aliases != null) {
List<String> aliasList = new ArrayList<String>();
if (aliases instanceof List) {
for (Object o : (List<?>) aliases) {
if (o.toString().contains(":")) {
Bukkit.getServer().getLogger().severe("Could not load alias " + o.toString() + " for plugin " + plugin.getName() + ": Illegal Characters");
continue;
}
aliasList.add(o.toString());
}
} else {
if (aliases.toString().contains(":")) {
Bukkit.getServer().getLogger().severe("Could not load alias " + aliases.toString() + " for plugin " + plugin.getName() + ": Illegal Characters");
} else {
aliasList.add(aliases.toString());
}
}
newCmd.setAliases(aliasList);
}
if (permission != null) {
newCmd.setPermission(permission.toString());
}
if (permissionMessage != null) {
newCmd.setPermissionMessage(permissionMessage.toString());
}
pluginCmds.add(newCmd);
}
return pluginCmds;
}
}

View File

@ -0,0 +1,19 @@
package org.bukkit.command;
import org.bukkit.plugin.Plugin;
/**
* This interface is used by the help system to group commands into
* sub-indexes based on the {@link Plugin} they are a part of. Custom command
* implementations will need to implement this interface to have a sub-index
* automatically generated on the plugin's behalf.
*/
public interface PluginIdentifiableCommand {
/**
* Gets the owner of this PluginIdentifiableCommand.
*
* @return Plugin that owns this PluginIdentifiableCommand.
*/
public Plugin getPlugin();
}

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