convert to patches

This commit is contained in:
ㄗㄠˋ ㄑㄧˊ
2020-04-01 18:17:33 +08:00
parent 3ee44ec206
commit dd949dfa38
2324 changed files with 833 additions and 317766 deletions

View File

@@ -29,15 +29,14 @@ jobs:
- run: git config --global user.email "circle@circleci.com" - run: git config --global user.email "circle@circleci.com"
- run: git config --global user.name "CircleCI" - run: git config --global user.name "CircleCI"
- run: chmod -Rv +x scripts/ - run: chmod -Rv +x scripts/
- run: ./scripts/build.sh - run: ./akarin build
- run: ./scripts/inst.sh --setup --remote
# Save dependency cache # Save dependency cache
- save_cache: - save_cache:
key: v1-dep-{{ .Branch }}-{{ epoch }} key: v1-dep-{{ .Branch }}-{{ epoch }}
paths: paths:
- ~/.m2 - ~/.m2
# Test # Test
- run: yes|cp -rf ./akarin-*.jar $CIRCLE_ARTIFACTS - run: cp akarin-paperclip.jar $CIRCLE_ARTIFACTS
# Teardown # Teardown
# Save test results # Save test results
- store_test_results: - store_test_results:

74
.gitignore vendored
View File

@@ -1,57 +1,43 @@
# Eclipse stuff # Akarin
.classpath Akarin-Server
.project Akarin-API
.settings/ mc-dev
.factorypath .idea
.externalToolBuilders/ testserver
run
/akarin-paperclip.jar
# netbeans # Compiled class file
nbproject/ *.class
nbactions.xml
# we use maven! # Log file
build.xml *.log
# maven # BlueJ files
target/ *.ctxt
dependency-reduced-pom.xml
# vim # Mobile Tools for Java (J2ME)
.*.sw[a-p] .mtj.tmp/
# various other potential build files # IntelliJ
build/
bin/
dist/
manifest.mf
work/1.*
work/Minecraft
work/BuildData
work/Bukkit
work/CraftBukkit
work/Paperclip
work/Spigot
work/Spigot-Server
work/Spigot-API
work/*.jar
work/test-server
# Mac filesystem dust
.DS_Store/
.DS_Store
# intellij
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
.idea/ .idea/
out/ out/
# Linux temp files # Maven
*~ target/
# other stuff # Package Files #
run/ *.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
akarin-*.jar

4
.gitmodules vendored
View File

@@ -1,4 +1,4 @@
[submodule "work/Paper"] [submodule "Paper"]
path = work/Paper path = Paper
url = https://github.com/PaperMC/Paper.git url = https://github.com/PaperMC/Paper.git
branch = master branch = master

View File

@@ -1,2 +0,0 @@
#Sat Mar 28 16:11:26 MST 2020
gradle.version=6.2.2

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,25 +0,0 @@
language: java
dist: trusty
jdk:
- oraclejdk8
install: true
script:
- git config --global user.email "circle@circleci.com"
- git config --global user.name "CircleCI"
- chmod -Rv +x scripts/
- ./scripts/build.sh
- ./scripts/inst.sh --setup --remote
after_success:
- rm -rf push
- mkdir push
- cp ./target/*.jar ./push/
deploy:
skip_cleanup: true
provider: releases
api_key:
secure: $Github_token
file:
- ./push/*
file_glob: true
on:
tags: true

View File

133
akarin Executable file
View File

@@ -0,0 +1,133 @@
#!/usr/bin/env bash
# exit immediately if a command exits with a non-zero status
set -e
# get base dir regardless of execution location
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
SOURCE=$([[ "$SOURCE" = /* ]] && echo "$SOURCE" || echo "$PWD/${SOURCE#./}")
basedir=$(dirname "$SOURCE")
. "$basedir"/scripts/init.sh
paperstash() {
STASHED=$(git stash)
}
paperunstash() {
if [[ "$STASHED" != "No local changes to save" ]] ; then
git stash pop
fi
}
case "$1" in
"rb" | "rbp" | "rebuild")
(
set -e
cd "$basedir"
scripts/rebuildpatches.sh "$basedir"
)
;;
"p" | "patch" | "apply")
(
set -e
cd "$basedir"
if [ "$2" != "fast" ]; then
scripts/upstream.sh
fi
scripts/apply.sh "$basedir"
)
;;
"b" | "bu" | "build")
(
basedir
mvn -N install
cd ${FORK_NAME}-API
mvn -e clean install && cd ../${FORK_NAME}-Server && mvn -e clean install
)
;;
"jar" | "paperclip")
(
basedir
cd "$basedir"
if [ "$2" != "fast" ]; then
scripts/upstream.sh
fi
./scripts/apply.sh "$basedir"
cd "$basedir"
mvn -N install
cd ${FORK_NAME}-API
mvn -e clean install && cd ../${FORK_NAME}-Server && mvn -e clean install
cd "$basedir"
./scripts/paperclip.sh
)
;;
"d" | "de" | "deploy")
(
basedir
mvn -N install
cd ${FORK_NAME}-API
mvn clean deploy && cd ../${FORK_NAME}-Server && mvn clean install
)
;;
"up" | "upstream")
(
cd "$basedir"
scripts/upstream.sh "$2"
)
;;
"r" | "root")
cd "$basedir"
;;
"a" | "api")
cd "$basedir/Akarin-API"
;;
"s" | "server")
cd "$basedir/Akarin-Server"
;;
"setup")
if [[ -f ~/.bashrc ]] ; then
NAME="ec"
if [[ ! -z "${2+x}" ]] ; then
NAME="$2"
fi
(grep "alias $NAME=" ~/.bashrc > /dev/null) && (sed -i "s|alias $NAME=.*|alias $NAME='. $SOURCE'|g" ~/.bashrc) || (echo "alias $NAME='. $SOURCE'" >> ~/.bashrc)
alias "$NAME=. $SOURCE"
echo "You can now just type '$NAME' at any time to access the paper tool."
fi
;;
*)
echo "Akarin build tool command. This provides a variety of commands to build and manage the PaperMC build"
echo "environment. For all of the functionality of this command to be available, you must first run the"
echo "'setup' command. View below for details. For essential building and patching, you do not need to do the setup."
echo ""
echo " Normal commands:"
echo " * rb, rebuild | Rebuild patches, can be called from anywhere."
echo " * p, patch | Apply all patches to top of Paper without building it. Can be run from anywhere."
echo " * up, upstream | Build Paper upstream, pass arg up to update paper. Can be run from anywhere."
echo " * b, build | Build API and Server but no deploy. Can be ran anywhere."
echo " * d, deploy | Build and Deploy API jar and build Server. Can be ran anywhere."
echo ""
echo " These commands require the setup command before use:"
echo " * r, root | Change directory to the root of the project."
echo " * a. api | Move to the Paper-API directory."
echo " * s, server | Move to the Paper-Server directory."
echo " * e, edit | Use to edit a specific patch, give it the argument \"server\" or \"api\""
echo " | respectively to edit the correct project. Use the argument \"continue\" after"
echo " | the changes have been made to finish and rebuild patches. Can be called from anywhere."
echo ""
echo " * setup | Add an alias to .bashrc to allow full functionality of this script. Run as:"
echo " | . ./akarin setup"
echo " | After you run this command you'll be able to just run 'akarin' from anywhere."
echo " | The default name for the resulting alias is 'akarin', you can give an argument to override"
echo " | this default, such as:"
echo " | . ./akarin setup example"
echo " | Which will allow you to run 'example' instead."
;;
esac
unset -f paperstash
unset -f paperunstash

View File

@@ -1,245 +0,0 @@
<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>
<artifactId>akarin-api</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>com.destroystokyo.paper</groupId>
<artifactId>paper-parent</artifactId>
<version>dev-SNAPSHOT</version>
</parent>
<name>Akarin-API</name>
<url>https://github.com/Akarin-project/Akarin</url>
<description>An enhanced plugin API for Minecraft servers.</description>
<properties>
<!-- <skipTests>true</skipTests> Paper - This [was] not going to end well -->
<!-- Paper - #Logic -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<!--
If you are a plugin developer, please use https://hub.spigotmc.org/nexus/content/repositories/snapshots/
as your repository URL. This will ensure only Bukkit / Spigot-API are pulled from our Maven repository.
Please see https://www.spigotmc.org/go/maven for more information.
-->
<repository>
<id>spigotmc-public</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spigotmc-public</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
<!-- bundled with Minecraft, shouldn't ever change -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>1.3.9</version>
<scope>compile</scope>
</dependency>
<!-- bundled with Minecraft, should be kept in sync -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
<scope>compile</scope>
</dependency>
<!-- bundled with Minecraft, should be kept in sync -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>1.13-SNAPSHOT</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
<scope>compile</scope>
</dependency>
<!-- annotations -->
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations-java5</artifactId>
<version>17.0.0</version>
<scope>provided</scope>
</dependency>
<!-- Paper - Add SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
</dependency>
<!-- testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>7.1</version>
<scope>test</scope>
</dependency>
<!-- ASM -->
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>7.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>7.1</version>
</dependency>
<!-- Akarin -->
<dependency>
<groupId>com.koloboke</groupId>
<artifactId>koloboke-api-jdk8</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.koloboke</groupId>
<artifactId>koloboke-impl-jdk8</artifactId>
<version>1.0.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>clean install</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<dependencies>
<!-- we need our custom version as it fixes some bugs on case sensitive file systems -->
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-eclipse</artifactId>
<version>2.8.5-spigotmc</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>org.bukkit</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>
<!-- when downloading via Maven we can pull depends individually -->
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>development</id>
<properties>
<skipTests>false</skipTests>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.17</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java17</artifactId>
<version>1.0</version>
</signature>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -1,84 +0,0 @@
package co.aikar.timings;
import static co.aikar.timings.TimingsManager.*;
import org.jetbrains.annotations.NotNull;
public class FullServerTickHandler extends TimingHandler {
private static final TimingIdentifier IDENTITY = new TimingIdentifier("Minecraft", "Full Server Tick", null);
final TimingData minuteData;
double avgFreeMemory = -1D;
double avgUsedMemory = -1D;
FullServerTickHandler() {
super(IDENTITY);
minuteData = new TimingData(id);
TIMING_MAP.put(IDENTITY, this);
}
@NotNull
@Override
public Timing startTiming() {
if (TimingsManager.needsFullReset) {
TimingsManager.resetTimings();
} else if (TimingsManager.needsRecheckEnabled) {
TimingsManager.recheckEnabled();
}
return super.startTiming();
}
@Override
public void stopTiming() {
super.stopTiming();
if (!isEnabled()) {
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;
TIMINGS_TICK.addDiff(diff, null);
// addDiff for TIMINGS_TICK incremented this, bring it back down to 1 per tick.
record.setCurTickCount(record.getCurTickCount()-1);
minuteData.setCurTickTotal(record.getCurTickTotal());
minuteData.setCurTickCount(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();
}
TimingsExport.reportTimings();
}
boolean isViolated() {
return record.getCurTickTotal() > 50000000;
}
}

View File

@@ -1,68 +0,0 @@
/*
* 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.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class NullTimingHandler implements Timing {
public static final Timing NULL = new NullTimingHandler();
@NotNull
@Override
public Timing startTiming() {
return this;
}
@Override
public void stopTiming() {
}
@NotNull
@Override
public Timing startTimingIfSync() {
return this;
}
@Override
public void stopTimingIfSync() {
}
@Override
public void abort() {
}
@Nullable
@Override
public TimingHandler getTimingHandler() {
return null;
}
@Override
public void close() {
}
}

View File

@@ -1,83 +0,0 @@
/*
* 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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 Executor to wrap
* @param plugin Owning plugin
* @param method EventHandler method
* @param eventClass Owning class
*/
public TimedEventExecutor(@NotNull EventExecutor executor, @NotNull Plugin plugin, @Nullable Method method, @NotNull 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);
this.timings = Timings.ofSafe(plugin.getName(), (verbose ? "## " : "") +
"Event: " + id + " (" + eventName + ")", null);
}
@Override
public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
if (event.isAsynchronous() || !Timings.timingsEnabled || !Bukkit.isPrimaryThread()) {
executor.execute(listener, event);
return;
}
try (Timing ignored = timings.startTiming()){
executor.execute(listener, event);
}
}
}

View File

@@ -1,83 +0,0 @@
/*
* 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.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* 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.
*
* @return Timing
*/
@NotNull
Timing 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
*/
void stopTiming();
/**
* Starts timing the execution until {@link #stopTiming()} is called.
*
* But only if we are on the primary thread.
*
* @return Timing
*/
@NotNull
Timing 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.
*/
void stopTimingIfSync();
/**
* @deprecated Doesn't do anything - Removed
*/
@Deprecated
void abort();
/**
* Used internally to get the actual backing Handler in the case of delegated Handlers
*
* @return TimingHandler
*/
@Nullable
TimingHandler getTimingHandler();
@Override
void close();
}

View File

@@ -1,122 +0,0 @@
/*
* 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 java.util.List;
import org.jetbrains.annotations.NotNull;
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 {
private final int id;
private int count = 0;
private int lagCount = 0;
private long totalTime = 0;
private long lagTotalTime = 0;
private int curTickCount = 0;
private long curTickTotal = 0;
TimingData(int id) {
this.id = id;
}
private 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);
}
@NotNull
List<Object> export() {
List<Object> list = toArray(
id,
count,
totalTime);
if (lagCount > 0) {
list.add(lagCount);
list.add(lagTotalTime);
}
return list;
}
boolean hasData() {
return count > 0;
}
long getTotalTime() {
return totalTime;
}
int getCurTickCount() {
return curTickCount;
}
void setCurTickCount(int curTickCount) {
this.curTickCount = curTickCount;
}
long getCurTickTotal() {
return curTickTotal;
}
void setCurTickTotal(long curTickTotal) {
this.curTickTotal = curTickTotal;
}
}

View File

@@ -1,227 +0,0 @@
/*
* 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 it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
class TimingHandler implements Timing {
private static AtomicInteger idPool = new AtomicInteger(1);
private static Deque<TimingHandler> TIMING_STACK = new ArrayDeque<>();
final int id = idPool.getAndIncrement();
final TimingIdentifier identifier;
private final boolean verbose;
private final Int2ObjectOpenHashMap<TimingData> children = new LoadingIntMap<>(TimingData::new);
final TimingData record;
private TimingHandler startParent;
private final TimingHandler groupHandler;
private long start = 0;
private int timingDepth = 0;
private boolean added;
private boolean timed;
private boolean enabled;
TimingHandler(@NotNull TimingIdentifier id) {
this.identifier = id;
this.verbose = id.name.startsWith("##");
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.getCurTickCount() == 0) {
timingDepth = 0;
start = 0;
return;
}
record.processTick(violated);
for (TimingData handler : children.values()) {
handler.processTick(violated);
}
}
@NotNull
@Override
public Timing startTimingIfSync() {
startTiming();
return this;
}
@Override
public void stopTimingIfSync() {
stopTiming();
}
@NotNull
public Timing startTiming() {
if (!enabled || !Bukkit.isPrimaryThread()) {
return this;
}
if (++timingDepth == 1) {
startParent = TIMING_STACK.peekLast();
start = System.nanoTime();
}
TIMING_STACK.addLast(this);
return this;
}
public void stopTiming() {
if (!enabled || timingDepth <= 0 || start == 0 || !Bukkit.isPrimaryThread()) {
return;
}
popTimingStack();
if (--timingDepth == 0) {
addDiff(System.nanoTime() - start, startParent);
startParent = null;
start = 0;
}
}
private void popTimingStack() {
TimingHandler last;
while ((last = TIMING_STACK.removeLast()) != this) {
last.timingDepth = 0;
String reportTo;
if ("Minecraft".equalsIgnoreCase(last.identifier.group)) {
reportTo = "Paper! This is a potential bug in Paper";
} else {
reportTo = "the plugin " + last.identifier.group + "(Look for errors above this in the logs)";
}
Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Report this to " + reportTo + " (" + last.identifier + " did not stopTiming)", new Throwable());
boolean found = TIMING_STACK.contains(this);
if (!found) {
// We aren't even in the stack... Don't pop everything
TIMING_STACK.addLast(last);
break;
}
}
}
@Override
public final void abort() {
}
void addDiff(long diff, @Nullable TimingHandler 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, parent);
groupHandler.children.get(id).add(diff);
}
}
/**
* Reset this timer, setting all values to zero.
*/
void reset(boolean full) {
record.reset();
if (full) {
timed = false;
}
start = 0;
timingDepth = 0;
added = false;
children.clear();
checkEnabled();
}
@NotNull
@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;
}
boolean isTimed() {
return timed;
}
public boolean isEnabled() {
return enabled;
}
@NotNull
TimingData[] cloneChildren() {
final TimingData[] clonedChildren = new TimingData[children.size()];
int i = 0;
for (TimingData child : children.values()) {
clonedChildren[i++] = child.clone();
}
return clonedChildren;
}
}

View File

@@ -1,354 +0,0 @@
/*
* 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.timings.TimingHistory.RegionData.RegionId;
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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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", "Convert2Lambda", "Anonymous2MethodRef"})
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;
private static int worldIdPool = 1;
static Map<String, Integer> worldMap = LoadingMap.newHashMap(new Function<String, Integer>() {
@NotNull
@Override
public Integer apply(@Nullable String input) {
return worldIdPool++;
}
});
private final long endTime;
private final long startTime;
private final long totalTicks;
private final long totalTime; // Represents all time spent running the server this history
private final MinuteReport[] minuteReports;
private final TimingHistoryEntry[] entries;
final Set<Material> tileEntityTypeSet = Sets.newHashSet();
final Set<EntityType> entityTypeSet = Sets.newHashSet();
private 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.getTotalTime();
this.entries = new TimingHistoryEntry[TimingsManager.HANDLERS.size()];
int i = 0;
for (TimingHandler handler : TimingsManager.HANDLERS) {
entries[i++] = new TimingHistoryEntry(handler);
}
// Information about all loaded chunks/entities
//noinspection unchecked
this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function<World, JSONPair>() {
@NotNull
@Override
public JSONPair apply(World world) {
Map<RegionId, RegionData> regions = LoadingMap.newHashMap(RegionData.LOADER);
for (Chunk chunk : world.getLoadedChunks()) {
RegionData data = regions.get(new RegionId(chunk.getX(), chunk.getZ()));
for (Entity entity : chunk.getEntities()) {
if (entity == null) {
Bukkit.getLogger().warning("Null entity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ());
continue;
}
data.entityCounts.get(entity.getType()).increment();
}
for (BlockState tileEntity : chunk.getTileEntities(false)) {
if (tileEntity == null) {
Bukkit.getLogger().warning("Null tileentity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ());
continue;
}
data.tileEntityCounts.get(tileEntity.getBlock().getType()).increment();
}
}
return pair(
worldMap.get(world.getName()),
toArrayMapper(regions.values(),new Function<RegionData, Object>() {
@NotNull
@Override
public Object apply(RegionData input) {
return toArray(
input.regionId.x,
input.regionId.z,
toObjectMapper(input.entityCounts.entrySet(),
new Function<Map.Entry<EntityType, Counter>, JSONPair>() {
@NotNull
@Override
public JSONPair apply(Map.Entry<EntityType, Counter> entry) {
entityTypeSet.add(entry.getKey());
return pair(
String.valueOf(entry.getKey().ordinal()),
entry.getValue().count()
);
}
}
),
toObjectMapper(input.tileEntityCounts.entrySet(),
new Function<Map.Entry<Material, Counter>, JSONPair>() {
@NotNull
@Override
public JSONPair apply(Map.Entry<Material, Counter> entry) {
tileEntityTypeSet.add(entry.getKey());
return pair(
String.valueOf(entry.getKey().ordinal()),
entry.getValue().count()
);
}
}
)
);
}
})
);
}
});
}
static class RegionData {
final RegionId regionId;
@SuppressWarnings("Guava")
static Function<RegionId, RegionData> LOADER = new Function<RegionId, RegionData>() {
@NotNull
@Override
public RegionData apply(@NotNull RegionId id) {
return new RegionData(id);
}
};
RegionData(@NotNull RegionId id) {
this.regionId = id;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RegionData that = (RegionData) o;
return regionId.equals(that.regionId);
}
@Override
public int hashCode() {
return regionId.hashCode();
}
@SuppressWarnings("unchecked")
final Map<EntityType, Counter> entityCounts = MRUMapCache.of(LoadingMap.of(
new EnumMap<EntityType, Counter>(EntityType.class), k -> new Counter()
));
@SuppressWarnings("unchecked")
final Map<Material, Counter> tileEntityCounts = MRUMapCache.of(LoadingMap.of(
new EnumMap<Material, Counter>(Material.class), k -> new Counter()
));
static class RegionId {
final int x, z;
final long regionId;
RegionId(int x, int z) {
this.x = x >> 5 << 5;
this.z = z >> 5 << 5;
this.regionId = ((long) (this.x) << 32) + (this.z >> 5 << 5) - Integer.MIN_VALUE;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RegionId regionId1 = (RegionId) o;
return regionId == regionId1.regionId;
}
@Override
public int hashCode() {
return (int) (regionId ^ (regionId >>> 32));
}
}
}
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;
}
@NotNull
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>() {
@Nullable
@Override
public Object apply(TimingHistoryEntry entry) {
TimingData record = entry.data;
if (!record.hasData()) {
return null;
}
return entry.export();
}
})),
pair("mp", toArrayMapper(minuteReports, new Function<MinuteReport, Object>() {
@NotNull
@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();
@NotNull
List<Object> 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
);
}
}
private 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;
}
}
private static class PingRecord {
final double avg;
PingRecord() {
final Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
int totalPing = 0;
for (Player player : onlinePlayers) {
totalPing += player.spigot().getPing();
}
avg = onlinePlayers.isEmpty() ? 0 : totalPing / onlinePlayers.size();
}
}
private static class Counter {
private int count = 0;
public int increment() {
return ++count;
}
public int count() {
return count;
}
}
}

View File

@@ -1,58 +0,0 @@
/*
* 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 org.jetbrains.annotations.NotNull;
import static co.aikar.util.JSONUtil.toArrayMapper;
class TimingHistoryEntry {
final TimingData data;
private final TimingData[] children;
TimingHistoryEntry(@NotNull TimingHandler handler) {
this.data = handler.record.clone();
children = handler.cloneChildren();
}
@NotNull
List<Object> export() {
List<Object> result = data.export();
if (children.length > 0) {
result.add(
toArrayMapper(children, new Function<TimingData, Object>() {
@NotNull
@Override
public Object apply(TimingData child) {
return child.export();
}
})
);
}
return result;
}
}

View File

@@ -1,116 +0,0 @@
/*
* 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.LoadingMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* <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 = LoadingMap.of(new ConcurrentHashMap<>(64, .5F), TimingGroup::new);
private static final TimingGroup DEFAULT_GROUP = getGroup("Minecraft");
final String group;
final String name;
final TimingHandler groupHandler;
private final int hashCode;
TimingIdentifier(@Nullable String group, @NotNull String name, @Nullable Timing groupHandler) {
this.group = group != null ? group: DEFAULT_GROUP.name;
this.name = name;
this.groupHandler = groupHandler != null ? groupHandler.getTimingHandler() : null;
this.hashCode = (31 * this.group.hashCode()) + this.name.hashCode();
}
@NotNull
static TimingGroup getGroup(@Nullable String groupName) {
if (groupName == null) {
//noinspection ConstantConditions
return DEFAULT_GROUP;
}
return GROUP_MAP.get(groupName);
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
TimingIdentifier that = (TimingIdentifier) o;
return Objects.equals(group, that.group) && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public String toString() {
return "TimingIdentifier{id=" + group + ":" + name +'}';
}
static class TimingGroup {
private static AtomicInteger idPool = new AtomicInteger(1);
final int id = idPool.getAndIncrement();
final String name;
final List<TimingHandler> handlers = Collections.synchronizedList(new ArrayList<>(64));
private TimingGroup(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TimingGroup that = (TimingGroup) o;
return id == that.id;
}
@Override
public int hashCode() {
return id;
}
}
}

View File

@@ -1,293 +0,0 @@
/*
* 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.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import java.util.Queue;
import java.util.logging.Level;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings({"UnusedDeclaration", "WeakerAccess", "SameParameterValue"})
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
*/
@NotNull
public static Timing of(@NotNull Plugin plugin, @NotNull 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
*/
@NotNull
public static Timing of(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) {
Preconditions.checkNotNull(plugin, "Plugin can not be null");
return TimingsManager.getHandler(plugin.getName(), name, groupHandler);
}
/**
* 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
*/
@NotNull
public static Timing ofStart(@NotNull Plugin plugin, @NotNull 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
*/
@NotNull
public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) {
Timing timing = of(plugin, name, groupHandler);
timing.startTiming();
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 verboseEnabled;
}
/**
* <p>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(@Nullable CommandSender sender) {
if (sender == null) {
sender = Bukkit.getConsoleSender();
}
TimingsExport.requestingReport.add(sender);
}
/**
* Generates a report and sends it to the specified listener.
* Use with {@link org.bukkit.command.BufferedCommandSender} to get full response when done!
* @param sender The listener to send responses too.
*/
public static void generateReport(@NotNull TimingsReportListener sender) {
Validate.notNull(sender);
TimingsExport.requestingReport.add(sender);
}
/*
=================
Protected API: These are for internal use only in Bukkit/CraftBukkit
These do not have isPrimaryThread() checks in the startTiming/stopTiming
=================
*/
@NotNull
static TimingHandler ofSafe(@NotNull String name) {
return ofSafe(null, name, null);
}
@NotNull
static Timing ofSafe(@Nullable Plugin plugin, @NotNull 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);
}
@NotNull
static TimingHandler ofSafe(@NotNull String name, @Nullable Timing groupHandler) {
return ofSafe(null, name, groupHandler);
}
@NotNull
static TimingHandler ofSafe(@Nullable String groupName, @NotNull String name, @Nullable Timing groupHandler) {
return TimingsManager.getHandler(groupName, name, groupHandler);
}
}

View File

@@ -1,122 +0,0 @@
/*
* 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class TimingsCommand extends BukkitCommand {
private static final List<String> TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste", "verbon", "verboff");
private long lastResetAttempt = 0;
public TimingsCommand(@NotNull 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(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull 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;
}
long now = System.currentTimeMillis();
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)) {
if (now - lastResetAttempt < 30000) {
TimingsManager.reset();
sender.sendMessage(ChatColor.RED + "Timings reset. Please wait 5-10 minutes before using /timings report.");
} else {
lastResetAttempt = now;
sender.sendMessage(ChatColor.RED + "WARNING: Timings v2 should not be reset. If you are encountering lag, please wait 3 minutes and then issue a report. The best timings will include 10+ minutes, with data before and after your lag period. If you really want to reset, run this command again within 30 seconds.");
}
} 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)
) {
Timings.generateReport(sender);
} else {
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
}
return true;
}
@NotNull
@Override
public List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull 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

@@ -1,355 +0,0 @@
/*
* 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.Lists;
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.configuration.ConfigurationSection;
import org.bukkit.configuration.MemorySection;
import org.bukkit.entity.EntityType;
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.ManagementFactory;
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.appendObjectData;
import static co.aikar.util.JSONUtil.createObject;
import static co.aikar.util.JSONUtil.pair;
import static co.aikar.util.JSONUtil.toArray;
import static co.aikar.util.JSONUtil.toArrayMapper;
import static co.aikar.util.JSONUtil.toObjectMapper;
@SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
class TimingsExport extends Thread {
private final TimingsReportListener listeners;
private final Map out;
private final TimingHistory[] history;
private static long lastReport = 0;
final static List<CommandSender> requestingReport = Lists.newArrayList();
private TimingsExport(TimingsReportListener listeners, Map out, TimingHistory[] history) {
super("Timings paste thread");
this.listeners = listeners;
this.out = out;
this.history = history;
}
/**
* Checks if any pending reports are being requested, and builds one if needed.
*/
static void reportTimings() {
if (requestingReport.isEmpty()) {
return;
}
TimingsReportListener listeners = new TimingsReportListener(requestingReport);
listeners.addConsoleIfNeeded();
requestingReport.clear();
long now = System.currentTimeMillis();
final long lastReportDiff = now - lastReport;
if (lastReportDiff < 60000) {
listeners.sendMessage(ChatColor.RED + "Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)");
listeners.done();
return;
}
final long lastStartDiff = now - TimingsManager.timingStart;
if (lastStartDiff < 180000) {
listeners.sendMessage(ChatColor.RED + "Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)");
listeners.done();
return;
}
listeners.sendMessage(ChatColor.GREEN + "Preparing Timings Report...");
lastReport = now;
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.getUnsafe().getTimingsServerName()),
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(), input -> 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();
Map groupData;
synchronized (TimingIdentifier.GROUP_MAP) {
for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) {
synchronized (group.handlers) {
for (TimingHandler id : group.handlers) {
if (!id.isTimed() && !id.isSpecial()) {
continue;
}
String name = id.identifier.name;
if (name.startsWith("##")) {
name = name.substring(3);
}
handlers.put(id.id, toArray(
group.id,
name
));
}
}
}
groupData = toObjectMapper(
TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name));
}
parent.put("idmap", createObject(
pair("groups", groupData),
pair("handlers", handlers),
pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))),
pair("tileentity",
toObjectMapper(tileEntityTypeSet, input -> pair(input.ordinal(), input.name()))),
pair("entity",
toObjectMapper(entityTypeSet, input -> pair(input.ordinal(), input.name())))
));
// Information about loaded plugins
parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(),
plugin -> 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("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
));
new TimingsExport(listeners, 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, input -> valAsJSON(input, parentKey));
} else {
return val.toString();
}
} else {
return mapAsJSON((ConfigurationSection) val, parentKey);
}
}
@Override
public void run() {
out.put("data", toArrayMapper(history, TimingHistory::export));
String response = null;
String timingsURL = null;
try {
HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection();
con.setDoOutput(true);
String hostName = "BrokenHost";
try {
hostName = InetAddress.getLocalHost().getHostName();
} catch (Exception ignored) {}
con.setRequestProperty("User-Agent", "Paper/" + Bukkit.getUnsafe().getTimingsServerName() + "/" + hostName);
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) {
listeners.sendMessage(
ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage());
listeners.sendMessage(ChatColor.RED + "Check your logs for more information");
if (response != null) {
Bukkit.getLogger().log(Level.SEVERE, response);
}
return;
}
timingsURL = con.getHeaderField("Location");
listeners.sendMessage(ChatColor.GREEN + "View Timings Report: " + timingsURL);
if (response != null && !response.isEmpty()) {
Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response);
}
} catch (IOException ex) {
listeners.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);
} finally {
this.listeners.done(timingsURL);
}
}
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) {
listeners.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

@@ -1,188 +0,0 @@
/*
* 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.LoadingMap;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class TimingsManager {
static final Map<TimingIdentifier, TimingHandler> TIMING_MAP = LoadingMap.of(
new ConcurrentHashMap<>(4096, .5F), TimingHandler::new
);
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 List<TimingHandler> HANDLERS = new ArrayList<>(1024);
static final List<TimingHistory.MinuteReport> MINUTE_REPORTS = new ArrayList<>(64);
static EvictingQueue<TimingHistory> HISTORY = EvictingQueue.create(12);
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();
}
@NotNull
static TimingHandler getHandler(@Nullable String group, @NotNull String name, @Nullable Timing parent) {
return TIMING_MAP.get(new TimingIdentifier(group, name, parent));
}
/**
* <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
*/
@NotNull
public static Timing getCommandTiming(@Nullable String pluginName, @NotNull Command command) {
Plugin plugin = null;
final Server server = Bukkit.getServer();
if (!( server == null || pluginName == null ||
"minecraft".equals(pluginName) || "bukkit".equals(pluginName) ||
"spigot".equalsIgnoreCase(pluginName) || "paper".equals(pluginName)
)) {
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
*/
@Nullable
public static Plugin getPluginByClassloader(@Nullable 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

@@ -1,75 +0,0 @@
package co.aikar.timings;
import com.google.common.collect.Lists;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.MessageCommandSender;
import org.bukkit.command.RemoteConsoleCommandSender;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("WeakerAccess")
public class TimingsReportListener implements MessageCommandSender {
private final List<CommandSender> senders;
private final Runnable onDone;
private String timingsURL;
public TimingsReportListener(@NotNull CommandSender senders) {
this(senders, null);
}
public TimingsReportListener(@NotNull CommandSender sender, @Nullable Runnable onDone) {
this(Lists.newArrayList(sender), onDone);
}
public TimingsReportListener(@NotNull List<CommandSender> senders) {
this(senders, null);
}
public TimingsReportListener(@NotNull List<CommandSender> senders, @Nullable Runnable onDone) {
Validate.notNull(senders);
Validate.notEmpty(senders);
this.senders = Lists.newArrayList(senders);
this.onDone = onDone;
}
@Nullable
public String getTimingsURL() {
return timingsURL;
}
public void done() {
done(null);
}
public void done(@Nullable String url) {
this.timingsURL = url;
if (onDone != null) {
onDone.run();
}
for (CommandSender sender : senders) {
if (sender instanceof TimingsReportListener) {
((TimingsReportListener) sender).done();
}
}
}
@Override
public void sendMessage(@NotNull String message) {
senders.forEach((sender) -> sender.sendMessage(message));
}
public void addConsoleIfNeeded() {
boolean hasConsole = false;
for (CommandSender sender : this.senders) {
if (sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
hasConsole = true;
}
}
if (!hasConsole) {
this.senders.add(Bukkit.getConsoleSender());
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* 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.jetbrains.annotations.NotNull;
class UnsafeTimingHandler extends TimingHandler {
UnsafeTimingHandler(@NotNull TimingIdentifier id) {
super(id);
}
private static void checkThread() {
if (!Bukkit.isPrimaryThread()) {
throw new IllegalStateException("Calling Timings from Async Operation");
}
}
@NotNull
@Override
public Timing startTiming() {
checkThread();
return super.startTiming();
}
@Override
public void stopTiming() {
checkThread();
super.stopTiming();
}
}

View File

@@ -1,38 +0,0 @@
package co.aikar.util;
import com.google.common.collect.ForwardingMap;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class Counter <T> extends ForwardingMap<T, Long> {
private final Map<T, Long> counts = new HashMap<>();
public long decrement(@Nullable T key) {
return increment(key, -1);
}
public long increment(@Nullable T key) {
return increment(key, 1);
}
public long decrement(@Nullable T key, long amount) {
return decrement(key, -amount);
}
public long increment(@Nullable T key, long amount) {
Long count = this.getCount(key);
count += amount;
this.counts.put(key, count);
return count;
}
public long getCount(@Nullable T key) {
return this.counts.getOrDefault(key, 0L);
}
@NotNull
@Override
protected Map<T, Long> delegate() {
return this.counts;
}
}

View File

@@ -1,140 +0,0 @@
package co.aikar.util;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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 Key to use
* @param obj Value to use
* @return JSONPair
*/
@NotNull
public static JSONPair pair(@NotNull String key, @Nullable Object obj) {
return new JSONPair(key, obj);
}
@NotNull
public static JSONPair pair(long key, @Nullable Object obj) {
return new JSONPair(String.valueOf(key), obj);
}
/**
* Creates a new JSON object from multiple JSONPair key/value pairs
*
* @param data JSONPairs
* @return Map
*/
@NotNull
public static Map<String, Object> createObject(@NotNull JSONPair... data) {
return appendObjectData(new LinkedHashMap(), data);
}
/**
* This appends multiple key/value Obj pairs into a JSON Object
*
* @param parent Map to be appended to
* @param data Data to append
* @return Map
*/
@NotNull
public static Map<String, Object> appendObjectData(@NotNull Map parent, @NotNull 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 Data to build JSON array from
* @return List
*/
@NotNull
public static List toArray(@NotNull Object... data) {
return Lists.newArrayList(data);
}
/**
* These help build a single JSON array using a mapper function
*
* @param collection Collection to apply to
* @param mapper Mapper to apply
* @param <E> Element Type
* @return List
*/
@NotNull
public static <E> List toArrayMapper(@NotNull E[] collection, @NotNull Function<E, Object> mapper) {
return toArrayMapper(Lists.newArrayList(collection), mapper);
}
@NotNull
public static <E> List toArrayMapper(@NotNull Iterable<E> collection, @NotNull 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 Collection to apply to
* @param mapper Mapper to apply
* @param <E> Element Type
* @return Map
*/
@NotNull
public static <E> Map toObjectMapper(@NotNull E[] collection, @NotNull Function<E, JSONPair> mapper) {
return toObjectMapper(Lists.newArrayList(collection), mapper);
}
@NotNull
public static <E> Map toObjectMapper(@NotNull Iterable<E> collection, @NotNull 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(@NotNull String key, @NotNull Object val) {
this.key = key;
this.val = val;
}
}
}

View File

@@ -1,76 +0,0 @@
/*
* 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 it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* 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 Int2ObjectOpenHashMap<V> {
private final Function<Integer, V> loader;
public LoadingIntMap(@NotNull Function<Integer, V> loader) {
super();
this.loader = loader;
}
public LoadingIntMap(int expectedSize, @NotNull Function<Integer, V> loader) {
super(expectedSize);
this.loader = loader;
}
public LoadingIntMap(int expectedSize, float loadFactor, @NotNull Function<Integer, V> loader) {
super(expectedSize, loadFactor);
this.loader = loader;
}
@Nullable
@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> Type
*/
public abstract static class Feeder <T> implements Function<T, T> {
@Nullable
@Override
public T apply(@Nullable Object input) {
return apply();
}
@Nullable
public abstract T apply();
}
}

View File

@@ -1,368 +0,0 @@
/*
* 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.Preconditions;
import java.lang.reflect.Constructor;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* 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 java.util.function.Function<K, V> loader;
/**
* Initializes an auto loading map using specified loader and backing map
* @param backingMap Map to wrap
* @param loader Loader
*/
public LoadingMap(@NotNull Map<K, V> backingMap, @NotNull java.util.function.Function<K, V> loader) {
this.backingMap = backingMap;
this.loader = loader;
}
/**
* Creates a new LoadingMap with the specified map and loader
*
* @param backingMap Actual map being used.
* @param loader Loader to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map
*/
@NotNull
public static <K, V> Map<K, V> of(@NotNull Map<K, V> backingMap, @NotNull Function<K, V> loader) {
return new LoadingMap<>(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()
*/
@NotNull
public static <K, V> Map<K, V> newAutoMap(@NotNull Map<K, V> backingMap, @Nullable final Class<? extends K> keyClass,
@NotNull final Class<? extends V> valueClass) {
return new LoadingMap<>(backingMap, new AutoInstantiatingLoader<>(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()
*/
@NotNull
public static <K, V> Map<K, V> newAutoMap(@NotNull Map<K, V> backingMap,
@NotNull final Class<? extends V> valueClass) {
return newAutoMap(backingMap, null, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
*
* @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()
*/
@NotNull
public static <K, V> Map<K, V> newHashAutoMap(@Nullable final Class<? extends K> keyClass, @NotNull final Class<? extends V> valueClass) {
return newAutoMap(new HashMap<>(), keyClass, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
*
* @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()
*/
@NotNull
public static <K, V> Map<K, V> newHashAutoMap(@NotNull final Class<? extends V> valueClass) {
return newHashAutoMap(null, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
*
* @param keyClass Class used for the K generic
* @param valueClass Class used for the V generic
* @param initialCapacity Initial capacity to use
* @param loadFactor Load factor to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map that auto instantiates on .get()
*/
@NotNull
public static <K, V> Map<K, V> newHashAutoMap(@Nullable final Class<? extends K> keyClass, @NotNull final Class<? extends V> valueClass, int initialCapacity, float loadFactor) {
return newAutoMap(new HashMap<>(initialCapacity, loadFactor), keyClass, valueClass);
}
/**
* @see #newAutoMap
*
* new Auto initializing map using a HashMap.
*
* @param valueClass Class used for the V generic
* @param initialCapacity Initial capacity to use
* @param loadFactor Load factor to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map that auto instantiates on .get()
*/
@NotNull
public static <K, V> Map<K, V> newHashAutoMap(@NotNull 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 Loader to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map
*/
@NotNull
public static <K, V> Map<K, V> newHashMap(@NotNull Function<K, V> loader) {
return new LoadingMap<>(new HashMap<>(), loader);
}
/**
* Initializes an auto loading map using a HashMap
*
* @param loader Loader to use
* @param initialCapacity Initial capacity to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map
*/
@NotNull
public static <K, V> Map<K, V> newHashMap(@NotNull Function<K, V> loader, int initialCapacity) {
return new LoadingMap<>(new HashMap<>(initialCapacity), loader);
}
/**
* Initializes an auto loading map using a HashMap
*
* @param loader Loader to use
* @param initialCapacity Initial capacity to use
* @param loadFactor Load factor to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map
*/
@NotNull
public static <K, V> Map<K, V> newHashMap(@NotNull Function<K, V> loader, int initialCapacity, float loadFactor) {
return new LoadingMap<>(new HashMap<>(initialCapacity, loadFactor), loader);
}
/**
* Initializes an auto loading map using an Identity HashMap
*
* @param loader Loader to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map
*/
@NotNull
public static <K, V> Map<K, V> newIdentityHashMap(@NotNull Function<K, V> loader) {
return new LoadingMap<>(new IdentityHashMap<>(), loader);
}
/**
* Initializes an auto loading map using an Identity HashMap
*
* @param loader Loader to use
* @param initialCapacity Initial capacity to use
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map
*/
@NotNull
public static <K, V> Map<K, V> newIdentityHashMap(@NotNull Function<K, V> loader, int initialCapacity) {
return new LoadingMap<>(new IdentityHashMap<>(initialCapacity), loader);
}
@Override
public int size() {return backingMap.size();}
@Override
public boolean isEmpty() {return backingMap.isEmpty();}
@Override
public boolean containsKey(@Nullable Object key) {return backingMap.containsKey(key);}
@Override
public boolean containsValue(@Nullable Object value) {return backingMap.containsValue(value);}
@Nullable
@Override
public V get(@Nullable Object key) {
V v = backingMap.get(key);
if (v != null) {
return v;
}
return backingMap.computeIfAbsent((K) key, loader);
}
@Nullable
public V put(@Nullable K key, @Nullable V value) {return backingMap.put(key, value);}
@Nullable
@Override
public V remove(@Nullable Object key) {return backingMap.remove(key);}
public void putAll(@NotNull Map<? extends K, ? extends V> m) {backingMap.putAll(m);}
@Override
public void clear() {backingMap.clear();}
@NotNull
@Override
public Set<K> keySet() {return backingMap.keySet();}
@NotNull
@Override
public Collection<V> values() {return backingMap.values();}
@Override
public boolean equals(@Nullable Object o) {return backingMap.equals(o);}
@Override
public int hashCode() {return backingMap.hashCode();}
@NotNull
@Override
public Set<Entry<K, V>> entrySet() {
return backingMap.entrySet();
}
@NotNull
public LoadingMap<K, V> clone() {
return new LoadingMap<>(backingMap, loader);
}
private static class AutoInstantiatingLoader<K, V> implements Function<K, V> {
final Constructor<? extends V> constructor;
private final Class<? extends V> valueClass;
AutoInstantiatingLoader(@Nullable Class<? extends K> keyClass, @NotNull 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));
}
}
@NotNull
@Override
public V apply(@Nullable 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> Type
*/
public abstract static class Feeder <T> implements Function<T, T> {
@Nullable
@Override
public T apply(@Nullable Object input) {
return apply();
}
@Nullable
public abstract T apply();
}
}

View File

@@ -1,111 +0,0 @@
/*
* 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implements a Most Recently Used cache in front of a backing map, to quickly access the last accessed result.
*
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
*/
public class MRUMapCache<K, V> extends AbstractMap<K, V> {
final Map<K, V> backingMap;
Object cacheKey;
V cacheValue;
public MRUMapCache(@NotNull final Map<K, V> backingMap) {
this.backingMap = backingMap;
}
public int size() {return backingMap.size();}
public boolean isEmpty() {return backingMap.isEmpty();}
public boolean containsKey(@Nullable Object key) {
return key != null && key.equals(cacheKey) || backingMap.containsKey(key);
}
public boolean containsValue(@Nullable Object value) {
return value != null && value == cacheValue || backingMap.containsValue(value);
}
@Nullable
public V get(@Nullable Object key) {
if (cacheKey != null && cacheKey.equals(key)) {
return cacheValue;
}
cacheKey = key;
return cacheValue = backingMap.get(key);
}
@Nullable
public V put(@Nullable K key, @Nullable V value) {
cacheKey = key;
return cacheValue = backingMap.put(key, value);
}
@Nullable
public V remove(@Nullable Object key) {
if (key != null && key.equals(cacheKey)) {
cacheKey = null;
}
return backingMap.remove(key);
}
public void putAll(@NotNull Map<? extends K, ? extends V> m) {backingMap.putAll(m);}
public void clear() {
cacheKey = null;
cacheValue = null;
backingMap.clear();
}
@NotNull
public Set<K> keySet() {return backingMap.keySet();}
@NotNull
public Collection<V> values() {return backingMap.values();}
@NotNull
public Set<Map.Entry<K, V>> entrySet() {return backingMap.entrySet();}
/**
* Wraps the specified map with a most recently used cache
*
* @param map Map to be wrapped
* @param <K> Key Type of the Map
* @param <V> Value Type of the Map
* @return Map
*/
@NotNull
public static <K, V> Map<K, V> of(@NotNull Map<K, V> map) {
return new MRUMapCache<K, V>(map);
}
}

View File

@@ -1,35 +0,0 @@
package com.destroystokyo.paper;
import org.bukkit.World;
/**
* Enumeration of different heightmap types maintained by the server. Generally using these maps is much faster
* than using an iterative search for a block in a given x, z coordinate.
*/
public enum HeightmapType {
/**
* The highest block used for lighting in the world. Also the block returned by {@link World#getHighestBlockYAt(int, int)}}
*/
LIGHT_BLOCKING,
/**
* References the highest block in the world.
*/
ANY,
/**
* References the highest solid block in a world.
*/
SOLID,
/**
* References the highest solid or liquid block in a world.
*/
SOLID_OR_LIQUID,
/**
* References the highest solid or liquid block in a world, excluding leaves.
*/
SOLID_OR_LIQUID_NO_LEAVES;
}

View File

@@ -1,190 +0,0 @@
/*
* Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
*/
package com.destroystokyo.paper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import java.util.Collection;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class MaterialSetTag implements Tag<Material> {
private final NamespacedKey key;
private final Set<Material> materials;
/**
* @deprecated Use NamespacedKey version of constructor
*/
@Deprecated
public MaterialSetTag(@NotNull Predicate<Material> filter) {
this(null, Stream.of(Material.values()).filter(filter).collect(Collectors.toList()));
}
/**
* @deprecated Use NamespacedKey version of constructor
*/
@Deprecated
public MaterialSetTag(@NotNull Collection<Material> materials) {
this(null, materials);
}
/**
* @deprecated Use NamespacedKey version of constructor
*/
@Deprecated
public MaterialSetTag(@NotNull Material... materials) {
this(null, materials);
}
public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Predicate<Material> filter) {
this(key, Stream.of(Material.values()).filter(filter).collect(Collectors.toList()));
}
public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Material... materials) {
this(key, Lists.newArrayList(materials));
}
public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection<Material> materials) {
this.key = key != null ? key : NamespacedKey.randomKey();
this.materials = Sets.newEnumSet(materials, Material.class);
}
@NotNull
@Override
public NamespacedKey getKey() {
return key;
}
@NotNull
public MaterialSetTag add(@NotNull Tag<Material>... tags) {
for (Tag<Material> tag : tags) {
add(tag.getValues());
}
return this;
}
@NotNull
public MaterialSetTag add(@NotNull MaterialSetTag... tags) {
for (Tag<Material> tag : tags) {
add(tag.getValues());
}
return this;
}
@NotNull
public MaterialSetTag add(@NotNull Material... material) {
this.materials.addAll(Lists.newArrayList(material));
return this;
}
@NotNull
public MaterialSetTag add(@NotNull Collection<Material> materials) {
this.materials.addAll(materials);
return this;
}
@NotNull
public MaterialSetTag contains(@NotNull String with) {
return add(mat -> mat.name().contains(with));
}
@NotNull
public MaterialSetTag endsWith(@NotNull String with) {
return add(mat -> mat.name().endsWith(with));
}
@NotNull
public MaterialSetTag startsWith(@NotNull String with) {
return add(mat -> mat.name().startsWith(with));
}
@NotNull
public MaterialSetTag add(@NotNull Predicate<Material> filter) {
add(Stream.of(Material.values()).filter(((Predicate<Material>) Material::isLegacy).negate()).filter(filter).collect(Collectors.toList()));
return this;
}
@NotNull
public MaterialSetTag not(@NotNull MaterialSetTag tags) {
not(tags.getValues());
return this;
}
@NotNull
public MaterialSetTag not(@NotNull Material... material) {
this.materials.removeAll(Lists.newArrayList(material));
return this;
}
@NotNull
public MaterialSetTag not(@NotNull Collection<Material> materials) {
this.materials.removeAll(materials);
return this;
}
@NotNull
public MaterialSetTag not(@NotNull Predicate<Material> filter) {
not(Stream.of(Material.values()).filter(((Predicate<Material>) Material::isLegacy).negate()).filter(filter).collect(Collectors.toList()));
return this;
}
@NotNull
public MaterialSetTag notEndsWith(@NotNull String with) {
return not(mat -> mat.name().endsWith(with));
}
@NotNull
public MaterialSetTag notStartsWith(@NotNull String with) {
return not(mat -> mat.name().startsWith(with));
}
@NotNull
public Set<Material> getValues() {
return this.materials;
}
public boolean isTagged(@NotNull BlockData block) {
return isTagged(block.getMaterial());
}
public boolean isTagged(@NotNull BlockState block) {
return isTagged(block.getType());
}
public boolean isTagged(@NotNull Block block) {
return isTagged(block.getType());
}
public boolean isTagged(@NotNull ItemStack item) {
return isTagged(item.getType());
}
public boolean isTagged(@NotNull Material material) {
return this.materials.contains(material);
}
@NotNull
public MaterialSetTag ensureSize(@NotNull String label, int size) {
long actual = this.materials.stream().filter(((Predicate<Material>) Material::isLegacy).negate()).count();
if (size != actual) {
throw new IllegalStateException(label + " - Expected " + size + " materials, got " + actual);
}
return this;
}
}

View File

@@ -1,374 +0,0 @@
/*
* Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
*
* 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 com.destroystokyo.paper;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag;
/**
* Represents a collection tags to identify materials that share common properties.
* Will map to minecraft for missing tags, as well as custom ones that may be useful.
*/
@SuppressWarnings({"NonFinalUtilityClass", "unused", "WeakerAccess"})
public class MaterialTags {
private static NamespacedKey keyFor(String key) {
//noinspection deprecation
return new NamespacedKey("paper", key + "_settag");
}
public static final MaterialSetTag ARROWS = new MaterialSetTag(keyFor("arrows"))
.endsWith("ARROW")
.ensureSize("ARROWS", 3);
/**
* Cover all 16 colors of beds.
*/
public static final MaterialSetTag BEDS = new MaterialSetTag(keyFor("beds"))
.endsWith("_BED")
.ensureSize("BEDS", 16);
/**
* Covers all bucket items.
*/
public static final MaterialSetTag BUCKETS = new MaterialSetTag(keyFor("buckets"))
.endsWith("BUCKET")
.ensureSize("BUCKETS", 8);
/**
* Covers coal and charcoal.
*/
public static final MaterialSetTag COALS = new MaterialSetTag(keyFor("coals"))
.add(Material.COAL, Material.CHARCOAL);
/**
* Covers both cobblestone wall variants.
*/
public static final MaterialSetTag COBBLESTONE_WALLS = new MaterialSetTag(keyFor("cobblestone_walls"))
.endsWith("COBBLESTONE_WALL")
.ensureSize("COBBLESTONE_WALLS", 2);
/**
* Covers both cobblestone and mossy Cobblestone.
*/
public static final MaterialSetTag COBBLESTONES = new MaterialSetTag(keyFor("cobblestones"))
.add(Material.COBBLESTONE, Material.MOSSY_COBBLESTONE);
/**
* Covers all 16 colors of concrete.
*/
public static final MaterialSetTag CONCRETES = new MaterialSetTag(keyFor("concretes"))
.endsWith("_CONCRETE")
.ensureSize("CONCRETES", 16);
/**
* Covers all 16 colors of concrete powder.
*/
public static final MaterialSetTag CONCRETE_POWDER = new MaterialSetTag(keyFor("concrete_powder"))
.endsWith("_CONCRETE_POWDER")
.ensureSize("CONCRETE_POWDER", 16);
/**
* Covers the two types of cooked fish.
*/
public static final MaterialSetTag COOKED_FISH = new MaterialSetTag(keyFor("cooked_fish"))
.add(Material.COOKED_COD, Material.COOKED_SALMON);
/**
* Covers all 16 dyes.
*/
public static final MaterialSetTag DYES = new MaterialSetTag(keyFor("dyes"))
.endsWith("_DYE")
.ensureSize("DYES", 16);
/**
* Covers all 6 wood variants of gates.
*/
public static final MaterialSetTag FENCE_GATES = new MaterialSetTag(keyFor("fence_gates"))
.endsWith("_GATE")
.ensureSize("FENCE_GATES", 6);
/**
* Covers all 6 wood variants and nether brick fence.
*/
public static final MaterialSetTag FENCES = new MaterialSetTag(keyFor("fences"))
.endsWith("_FENCE")
.ensureSize("FENCES", 7);
/**
* Covers all 4 variants of fish buckets.
*/
public static final MaterialSetTag FISH_BUCKETS = new MaterialSetTag(keyFor("fish_buckets"))
.add(Material.COD_BUCKET, Material.PUFFERFISH_BUCKET, Material.SALMON_BUCKET, Material.TROPICAL_FISH_BUCKET);
/**
* Covers the non-colored glass and 16 stained glass (not panes).
*/
public static final MaterialSetTag GLASS = new MaterialSetTag(keyFor("glass"))
.endsWith("_GLASS")
.add(Material.GLASS)
.ensureSize("GLASS", 17);
/**
* Covers the non-colored glass panes and 16 stained glass panes (panes only).
*/
public static final MaterialSetTag GLASS_PANES = new MaterialSetTag(keyFor("glass_panes"))
.endsWith("GLASS_PANE")
.ensureSize("GLASS_PANES", 17);
/**
* Covers all 16 glazed terracotta blocks.
*/
public static final MaterialSetTag GLAZED_TERRACOTTA = new MaterialSetTag(keyFor("glazed_terracotta"))
.endsWith("GLAZED_TERRACOTTA")
.ensureSize("GLAZED_TERRACOTTA", 16);
/**
* Covers the 16 colors of stained terracotta.
*/
public static final MaterialSetTag STAINED_TERRACOTTA = new MaterialSetTag(keyFor("stained_terracotta"))
.endsWith("TERRACOTTA")
.not(Material.TERRACOTTA)
.notEndsWith("GLAZED_TERRACOTTA")
.ensureSize("STAINED_TERRACOTTA", 16);
/**
* Covers terracotta along with the 16 stained variants.
*/
public static final MaterialSetTag TERRACOTTA = new MaterialSetTag(keyFor("terracotta"))
.endsWith("TERRACOTTA")
.ensureSize("TERRACOTTA", 33);
/**
* Covers both golden apples.
*/
public static final MaterialSetTag GOLDEN_APPLES = new MaterialSetTag(keyFor("golden_apples"))
.endsWith("GOLDEN_APPLE")
.ensureSize("GOLDEN_APPLES", 2);
/**
* Covers the 3 variants of horse armor.
*/
public static final MaterialSetTag HORSE_ARMORS = new MaterialSetTag(keyFor("horse_armors"))
.endsWith("_HORSE_ARMOR")
.ensureSize("HORSE_ARMORS", 4);
/**
* Covers the 6 variants of infested blocks.
*/
public static final MaterialSetTag INFESTED_BLOCKS = new MaterialSetTag(keyFor("infested_blocks"))
.startsWith("INFESTED_")
.ensureSize("INFESTED_BLOCKS", 6);
/**
* Covers the 3 variants of mushroom blocks.
*/
public static final MaterialSetTag MUSHROOM_BLOCKS = new MaterialSetTag(keyFor("mushroom_blocks"))
.endsWith("MUSHROOM_BLOCK")
.add(Material.MUSHROOM_STEM)
.ensureSize("MUSHROOM_BLOCKS", 3);
/**
* Covers both mushrooms.
*/
public static final MaterialSetTag MUSHROOMS = new MaterialSetTag(keyFor("mushrooms"))
.add(Material.BROWN_MUSHROOM, Material.RED_MUSHROOM);
/**
* Covers all 12 music disc items.
*/
public static final MaterialSetTag MUSIC_DISCS = new MaterialSetTag(keyFor("music_discs"))
.startsWith("MUSIC_DISC_")
.ensureSize("MUSIC_DISCS", 12);
/**
* Covers all 8 ores.
*/
public static final MaterialSetTag ORES = new MaterialSetTag(keyFor("ores"))
.endsWith("_ORE")
.ensureSize("ORES", 8);
/**
* Covers all piston typed items and blocks including the piston head and moving piston.
*/
public static final MaterialSetTag PISTONS = new MaterialSetTag(keyFor("pistons"))
.contains("PISTON")
.ensureSize("PISTONS", 4);
/**
* Covers all potato items.
*/
public static final MaterialSetTag POTATOES = new MaterialSetTag(keyFor("potatoes"))
.endsWith("POTATO")
.ensureSize("POTATOES", 3);
/**
* Covers all 6 wooden pressure plates and the 2 weighted pressure plates and 1 stone pressure plate.
*/
public static final MaterialSetTag PRESSURE_PLATES = new MaterialSetTag(keyFor("pressure_plates"))
.endsWith("_PRESSURE_PLATE")
.ensureSize("PRESSURE_PLATES", 9);
/**
* Covers the 3 variants of prismarine blocks.
*/
public static final MaterialSetTag PRISMARINE = new MaterialSetTag(keyFor("prismarine"))
.add(Material.PRISMARINE, Material.PRISMARINE_BRICKS, Material.DARK_PRISMARINE);
/**
* Covers the 3 variants of prismarine slabs.
*/
public static final MaterialSetTag PRISMARINE_SLABS = new MaterialSetTag(keyFor("prismarine_slabs"))
.add(Material.PRISMARINE_SLAB, Material.PRISMARINE_BRICK_SLAB, Material.DARK_PRISMARINE_SLAB);
/**
* Covers the 3 variants of prismarine stairs.
*/
public static final MaterialSetTag PRISMARINE_STAIRS = new MaterialSetTag(keyFor("prismarine_stairs"))
.add(Material.PRISMARINE_STAIRS, Material.PRISMARINE_BRICK_STAIRS, Material.DARK_PRISMARINE_STAIRS);
/**
* Covers the 3 variants of pumpkins.
*/
public static final MaterialSetTag PUMPKINS = new MaterialSetTag(keyFor("pumpkins"))
.add(Material.CARVED_PUMPKIN, Material.JACK_O_LANTERN, Material.PUMPKIN);
/**
* Covers the 4 variants of quartz blocks.
*/
public static final MaterialSetTag QUARTZ_BLOCKS = new MaterialSetTag(keyFor("quartz_blocks"))
.add(Material.QUARTZ_BLOCK, Material.QUARTZ_PILLAR, Material.CHISELED_QUARTZ_BLOCK, Material.SMOOTH_QUARTZ);
/**
* Covers all uncooked fish items.
*/
public static final MaterialSetTag RAW_FISH = new MaterialSetTag(keyFor("raw_fish"))
.add(Material.COD, Material.PUFFERFISH, Material.SALMON, Material.TROPICAL_FISH);
/**
* Covers the 4 variants of red sandstone blocks.
*/
public static final MaterialSetTag RED_SANDSTONES = new MaterialSetTag(keyFor("red_sandstones"))
.endsWith("RED_SANDSTONE")
.ensureSize("RED_SANDSTONES", 4);
/**
* Covers the 4 variants of sandstone blocks.
*/
public static final MaterialSetTag SANDSTONES = new MaterialSetTag(keyFor("sandstones"))
.add(Material.SANDSTONE, Material.CHISELED_SANDSTONE, Material.CUT_SANDSTONE, Material.SMOOTH_SANDSTONE);
/**
* Covers sponge and wet sponge.
*/
public static final MaterialSetTag SPONGES = new MaterialSetTag(keyFor("sponges"))
.endsWith("SPONGE")
.ensureSize("SPONGES", 2);
/**
* Covers the non-colored and 16 colored shulker boxes.
*/
public static final MaterialSetTag SHULKER_BOXES = new MaterialSetTag(keyFor("shulker_boxes"))
.endsWith("SHULKER_BOX")
.ensureSize("SHULKER_BOXES", 17);
/**
* Covers zombie, creeper, skeleton, dragon, and player heads.
*/
public static final MaterialSetTag SKULLS = new MaterialSetTag(keyFor("skulls"))
.endsWith("_HEAD")
.endsWith("_SKULL")
.not(Material.PISTON_HEAD)
.ensureSize("SKULLS", 12);
/**
* Covers all spawn egg items.
*/
public static final MaterialSetTag SPAWN_EGGS = new MaterialSetTag(keyFor("spawn_eggs"))
.endsWith("_SPAWN_EGG")
.ensureSize("SPAWN_EGGS", 58);
/**
* Covers all 16 colors of stained glass.
*/
public static final MaterialSetTag STAINED_GLASS = new MaterialSetTag(keyFor("stained_glass"))
.endsWith("_STAINED_GLASS")
.ensureSize("STAINED_GLASS", 16);
/**
* Covers all 16 colors of stained glass panes.
*/
public static final MaterialSetTag STAINED_GLASS_PANES = new MaterialSetTag(keyFor("stained_glass_panes"))
.endsWith("STAINED_GLASS_PANE")
.ensureSize("STAINED_GLASS_PANES", 16);
/**
* Covers all 7 variants of trapdoors.
*/
public static final MaterialSetTag TRAPDOORS = new MaterialSetTag(keyFor("trapdoors"))
.endsWith("_TRAPDOOR")
.ensureSize("TRAPDOORS", 7);
/**
* Covers all 6 wood variants of fences.
*/
public static final MaterialSetTag WOODEN_FENCES = new MaterialSetTag(keyFor("wooden_fences"))
.endsWith("_FENCE")
.not(Material.NETHER_BRICK_FENCE)
.ensureSize("WOODEN_FENCES", 6);
/**
* Covers all 6 wood variants of trapdoors.
*/
public static final MaterialSetTag WOODEN_TRAPDOORS = new MaterialSetTag(keyFor("wooden_trapdoors"))
.endsWith("_TRAPDOOR")
.not(Material.IRON_TRAPDOOR)
.ensureSize("WOODEN_TRAPDOORS", 6);
public static final MaterialSetTag WOODEN_GATES = new MaterialSetTag(keyFor("wooden_gates"))
.endsWith("_GATE")
.ensureSize("WOODEN_GATES", 6);
public static final MaterialSetTag PURPUR = new MaterialSetTag(keyFor("purpur"))
.startsWith("PURPUR_")
.ensureSize("PURPUR", 4);
public static final MaterialSetTag SIGNS = new MaterialSetTag(keyFor("signs"))
.endsWith("_SIGN")
.ensureSize("SIGNS", 12);
public static final MaterialSetTag TORCH = new MaterialSetTag(keyFor("torch"))
.add(Material.TORCH, Material.WALL_TORCH)
.ensureSize("TORCH", 2);
public static final MaterialSetTag REDSTONE_TORCH = new MaterialSetTag(keyFor("restone_torch"))
.add(Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH)
.ensureSize("REDSTONE_TORCH", 2);
@SuppressWarnings("unchecked")
public static final MaterialSetTag COLORABLE = new MaterialSetTag(keyFor("colorable"))
.add(Tag.WOOL, Tag.CARPETS).add(SHULKER_BOXES, STAINED_GLASS, STAINED_GLASS_PANES, CONCRETES, BEDS);
//.ensureSize("COLORABLE", 81); unit test don't have the vanilla item tags, so counts don't line up for real
}

View File

@@ -1,40 +0,0 @@
package com.destroystokyo.paper;
import org.jetbrains.annotations.NotNull;
/**
* Represents a namespaced resource, see {@link org.bukkit.NamespacedKey} for single elements
* or {@link com.destroystokyo.paper.NamespacedTag} for a collection of elements
*
* Namespaces may only contain lowercase alphanumeric characters, periods,
* underscores, and hyphens.
* <p>
* Keys may only contain lowercase alphanumeric characters, periods,
* underscores, hyphens, and forward slashes.
* <p>
* You should not be implementing this interface yourself, use {@link org.bukkit.NamespacedKey}
* or {@link com.destroystokyo.paper.NamespacedTag} as needed instead.
*/
public interface Namespaced {
/**
* Gets the namespace this resource is a part of
* <p>
* This is contractually obligated to only contain lowercase alphanumeric characters,
* periods, underscores, and hyphens.
*
* @return resource namespace
*/
@NotNull
String getNamespace();
/**
* Gets the key corresponding to this resource
* <p>
* This is contractually obligated to only contain lowercase alphanumeric characters,
* periods, underscores, hyphens, and forward slashes.
*
* @return resource key
*/
@NotNull
String getKey();
}

View File

@@ -1,142 +0,0 @@
package com.destroystokyo.paper;
import com.google.common.base.Preconditions;
import java.util.Locale;
import java.util.UUID;
import java.util.regex.Pattern;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
/**
* Represents a String based key pertaining to a tagged entry. Consists of two components - a namespace
* and a key.
* <p>
* Namespaces may only contain lowercase alphanumeric characters, periods,
* underscores, and hyphens.
* <p>
* Keys may only contain lowercase alphanumeric characters, periods,
* underscores, hyphens, and forward slashes.
*
*/
// Paper - entire class, based on org.bukkit.NamespacedKey
public final class NamespacedTag implements com.destroystokyo.paper.Namespaced {
/**
* The namespace representing all inbuilt keys.
*/
public static final String MINECRAFT = "minecraft";
/**
* The namespace representing all keys generated by Bukkit for backwards
* compatibility measures.
*/
public static final String BUKKIT = "bukkit";
//
private static final Pattern VALID_NAMESPACE = Pattern.compile("[a-z0-9._-]+");
private static final Pattern VALID_KEY = Pattern.compile("[a-z0-9/._-]+");
//
private final String namespace;
private final String key;
/**
* Create a key in a specific namespace.
*
* @param namespace String representing a grouping of keys
* @param key Name for this specific key
* @deprecated should never be used by plugins, for internal use only!!
*/
@Deprecated
public NamespacedTag(@NotNull String namespace, @NotNull String key) {
Preconditions.checkArgument(namespace != null && VALID_NAMESPACE.matcher(namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace);
Preconditions.checkArgument(key != null && VALID_KEY.matcher(key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", key);
this.namespace = namespace;
this.key = key;
String string = toString();
Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters", string);
}
/**
* Create a key in the plugin's namespace.
* <p>
* Namespaces may only contain lowercase alphanumeric characters, periods,
* underscores, and hyphens.
* <p>
* Keys may only contain lowercase alphanumeric characters, periods,
* underscores, hyphens, and forward slashes.
*
* @param plugin the plugin to use for the namespace
* @param key the key to create
*/
public NamespacedTag(@NotNull Plugin plugin, @NotNull String key) {
Preconditions.checkArgument(plugin != null, "Plugin cannot be null");
Preconditions.checkArgument(key != null, "Key cannot be null");
this.namespace = plugin.getName().toLowerCase(Locale.ROOT);
this.key = key.toLowerCase().toLowerCase(Locale.ROOT);
// Check validity after normalization
Preconditions.checkArgument(VALID_NAMESPACE.matcher(this.namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace);
Preconditions.checkArgument(VALID_KEY.matcher(this.key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", this.key);
String string = toString();
Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters (%s)", string);
}
@NotNull
public String getNamespace() {
return namespace;
}
@NotNull
public String getKey() {
return key;
}
@Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + this.namespace.hashCode();
hash = 47 * hash + this.key.hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final NamespacedTag other = (NamespacedTag) obj;
return this.namespace.equals(other.namespace) && this.key.equals(other.key);
}
@Override
public String toString() {
return "#" + this.namespace + ":" + this.key;
}
/**
* Return a new random key in the {@link #BUKKIT} namespace.
*
* @return new key
* @deprecated should never be used by plugins, for internal use only!!
*/
@Deprecated
public static NamespacedTag randomKey() {
return new NamespacedTag(BUKKIT, UUID.randomUUID().toString());
}
/**
* Get a key in the Minecraft namespace.
*
* @param key the key to use
* @return new key in the Minecraft namespace
*/
@NotNull
public static NamespacedTag minecraft(@NotNull String key) {
return new NamespacedTag(MINECRAFT, key);
}
}

View File

@@ -1,478 +0,0 @@
package com.destroystokyo.paper;
import com.google.common.collect.Lists;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.util.NumberConversions;
import java.util.Collection;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Helps prepare a particle to be sent to players.
*
* Usage of the builder is preferred over the super long {@link World#spawnParticle(Particle, Location, int, double, double, double, double, Object)} API
*/
public class ParticleBuilder {
private Particle particle;
private List<Player> receivers;
private Player source;
private Location location;
private int count = 1;
private double offsetX = 0, offsetY = 0, offsetZ = 0;
private double extra = 1;
private Object data;
private boolean force = true;
public ParticleBuilder(@NotNull Particle particle) {
this.particle = particle;
}
/**
* Sends the particle to all receiving players (or all). This method is safe to use
* Asynchronously
*
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder spawn() {
if (this.location == null) {
throw new IllegalStateException("Please specify location for this particle");
}
location.getWorld().spawnParticle(particle, receivers, source,
location.getX(), location.getY(), location.getZ(),
count, offsetX, offsetY, offsetZ, extra, data, force
);
return this;
}
/**
* @return The particle going to be sent
*/
@NotNull
public Particle particle() {
return particle;
}
/**
* Changes what particle will be sent
*
* @param particle The particle
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder particle(@NotNull Particle particle) {
this.particle = particle;
return this;
}
/**
* @return List of players who will receive the particle, or null for all in world
*/
@Nullable
public List<Player> receivers() {
return receivers;
}
/**
* Example use:
*
* builder.receivers(16); if (builder.hasReceivers()) { sendParticleAsync(builder); }
*
* @return If this particle is going to be sent to someone
*/
public boolean hasReceivers() {
return (receivers == null && !location.getWorld().getPlayers().isEmpty()) || (
receivers != null && !receivers.isEmpty());
}
/**
* Sends this particle to all players in the world. This is rather silly and you should likely not
* be doing this.
*
* Just be a logical person and use receivers by radius or collection.
*
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder allPlayers() {
this.receivers = null;
return this;
}
/**
* @param receivers List of players to receive this particle, or null for all players in the
* world
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(@Nullable List<Player> receivers) {
// Had to keep this as we first made API List<> and not Collection, but removing this may break plugins compiled on older jars
// TODO: deprecate?
this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
return this;
}
/**
* @param receivers List of players to receive this particle, or null for all players in the
* world
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(@Nullable Collection<Player> receivers) {
this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
return this;
}
/**
* @param receivers List of players to be receive this particle, or null for all players in the
* world
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(@Nullable Player... receivers) {
this.receivers = receivers != null ? Lists.newArrayList(receivers) : null;
return this;
}
/**
* Selects all players within a cuboid selection around the particle location, within the
* specified bounding box. If you want a more spherical check, see {@link #receivers(int,
* boolean)}
*
* @param radius amount to add on all axis
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(int radius) {
return receivers(radius, radius);
}
/**
* Selects all players within the specified radius around the particle location. If byDistance is
* false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is
* true, radius is tested by distance in a spherical shape
*
* @param radius amount to add on each axis
* @param byDistance true to use a spherical radius, false to use a cuboid
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(int radius, boolean byDistance) {
if (!byDistance) {
return receivers(radius, radius, radius);
} else {
this.receivers = Lists.newArrayList();
for (Player nearbyPlayer : location.getWorld()
.getNearbyPlayers(location, radius, radius, radius)) {
Location loc = nearbyPlayer.getLocation();
double x = NumberConversions.square(location.getX() - loc.getX());
double y = NumberConversions.square(location.getY() - loc.getY());
double z = NumberConversions.square(location.getZ() - loc.getZ());
if (Math.sqrt(x + y + z) > radius) {
continue;
}
this.receivers.add(nearbyPlayer);
}
return this;
}
}
/**
* Selects all players within a cuboid selection around the particle location, within the
* specified bounding box. Allows specifying a different Y size than X and Z If you want a more
* cylinder check, see {@link #receivers(int, int, boolean)} If you want a more spherical check,
* see {@link #receivers(int, boolean)}
*
* @param xzRadius amount to add on the x/z axis
* @param yRadius amount to add on the y axis
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(int xzRadius, int yRadius) {
return receivers(xzRadius, yRadius, xzRadius);
}
/**
* Selects all players within the specified radius around the particle location. If byDistance is
* false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is
* true, radius is tested by distance on the y plane and on the x/z plane, in a cylinder shape.
*
* @param xzRadius amount to add on the x/z axis
* @param yRadius amount to add on the y axis
* @param byDistance true to use a cylinder shape, false to use cuboid
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(int xzRadius, int yRadius, boolean byDistance) {
if (!byDistance) {
return receivers(xzRadius, yRadius, xzRadius);
} else {
this.receivers = Lists.newArrayList();
for (Player nearbyPlayer : location.getWorld()
.getNearbyPlayers(location, xzRadius, yRadius, xzRadius)) {
Location loc = nearbyPlayer.getLocation();
if (Math.abs(loc.getY() - this.location.getY()) > yRadius) {
continue;
}
double x = NumberConversions.square(location.getX() - loc.getX());
double z = NumberConversions.square(location.getZ() - loc.getZ());
if (x + z > NumberConversions.square(xzRadius)) {
continue;
}
this.receivers.add(nearbyPlayer);
}
return this;
}
}
/**
* Selects all players within a cuboid selection around the particle location, within the
* specified bounding box. If you want a more cylinder check, see {@link #receivers(int, int,
* boolean)} If you want a more spherical check, see {@link #receivers(int, boolean)}
*
* @param xRadius amount to add on the x axis
* @param yRadius amount to add on the y axis
* @param zRadius amount to add on the z axis
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder receivers(int xRadius, int yRadius, int zRadius) {
if (location == null) {
throw new IllegalStateException("Please set location first");
}
return receivers(location.getWorld().getNearbyPlayers(location, xRadius, yRadius, zRadius));
}
/**
* @return The player considered the source of this particle (for Visibility concerns), or null
*/
@Nullable
public Player source() {
return source;
}
/**
* Sets the source of this particle for visibility concerns (Vanish API)
*
* @param source The player who is considered the source
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder source(@Nullable Player source) {
this.source = source;
return this;
}
/**
* @return Location of where the particle will spawn
*/
@Nullable
public Location location() {
return location;
}
/**
* Sets the location of where to spawn the particle
*
* @param location The location of the particle
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder location(@NotNull Location location) {
this.location = location.clone();
return this;
}
/**
* Sets the location of where to spawn the particle
*
* @param world World to spawn particle in
* @param x X location
* @param y Y location
* @param z Z location
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder location(@NotNull World world, double x, double y, double z) {
this.location = new Location(world, x, y, z);
return this;
}
/**
* @return Number of particles to spawn
*/
public int count() {
return count;
}
/**
* Sets the number of particles to spawn
*
* @param count Number of particles
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder count(int count) {
this.count = count;
return this;
}
/**
* Particle offset X. Varies by particle on how this is used
*
* @return Particle offset X.
*/
public double offsetX() {
return offsetX;
}
/**
* Particle offset Y. Varies by particle on how this is used
*
* @return Particle offset Y.
*/
public double offsetY() {
return offsetY;
}
/**
* Particle offset Z. Varies by particle on how this is used
*
* @return Particle offset Z.
*/
public double offsetZ() {
return offsetZ;
}
/**
* Sets the particle offset. Varies by particle on how this is used
*
* @param offsetX Particle offset X
* @param offsetY Particle offset Y
* @param offsetZ Particle offset Z
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder offset(double offsetX, double offsetY, double offsetZ) {
this.offsetX = offsetX;
this.offsetY = offsetY;
this.offsetZ = offsetZ;
return this;
}
/**
* Gets the Particle extra data. Varies by particle on how this is used
*
* @return the extra particle data
*/
public double extra() {
return extra;
}
/**
* Sets the particle extra data. Varies by particle on how this is used
*
* @param extra the extra particle data
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder extra(double extra) {
this.extra = extra;
return this;
}
/**
* Gets the particle custom data. Varies by particle on how this is used
*
* @param <T> The Particle data type
* @return the ParticleData for this particle
*/
@Nullable
public <T> T data() {
//noinspection unchecked
return (T) data;
}
/**
* Sets the particle custom data. Varies by particle on how this is used
*
* @param data The new particle data
* @param <T> The Particle data type
* @return a reference to this object.
*/
@NotNull
public <T> ParticleBuilder data(@Nullable T data) {
this.data = data;
return this;
}
/**
* Sets whether the particle is forcefully shown to the player. If forced, the particle will show
* faraway, as far as the player's view distance allows. If false, the particle will show
* according to the client's particle settings.
*
* @param force true to force, false for normal
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder force(boolean force) {
this.force = force;
return this;
}
/**
* Sets the particle Color. Only valid for REDSTONE.
*
* @param color the new particle color
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder color(@Nullable Color color) {
return color(color, 1);
}
/**
* Sets the particle Color and size. Only valid for REDSTONE.
*
* @param color the new particle color
* @param size the size of the particle
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder color(@Nullable Color color, float size) {
if (particle != Particle.REDSTONE && color != null) {
throw new IllegalStateException("Color may only be set on REDSTONE");
}
// We don't officially support reusing these objects, but here we go
if (color == null) {
if (data instanceof Particle.DustOptions) {
return data(null);
} else {
return this;
}
}
return data(new Particle.DustOptions(color, size));
}
/**
* Sets the particle Color.
* Only valid for REDSTONE.
* @param r red color component
* @param g green color component
* @param b blue color component
* @return a reference to this object.
*/
@NotNull
public ParticleBuilder color(int r, int g, int b) {
return color(Color.fromRGB(r, g, b));
}
}

View File

@@ -1,373 +0,0 @@
package com.destroystokyo.paper;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* Represents a title to may be sent to a {@link Player}.
*
* <p>A title can be sent without subtitle text.</p>
*/
public final class Title {
/**
* The default number of ticks for the title to fade in.
*/
public static final int DEFAULT_FADE_IN = 20;
/**
* The default number of ticks for the title to stay.
*/
public static final int DEFAULT_STAY = 200;
/**
* The default number of ticks for the title to fade out.
*/
public static final int DEFAULT_FADE_OUT = 20;
private final BaseComponent[] title;
private final BaseComponent[] subtitle;
private final int fadeIn;
private final int stay;
private final int fadeOut;
/**
* Create a title with the default time values and no subtitle.
*
* <p>Times use default values.</p>
*
* @param title the main text of the title
* @throws NullPointerException if the title is null
*/
public Title(@NotNull BaseComponent title) {
this(title, null);
}
/**
* Create a title with the default time values and no subtitle.
*
* <p>Times use default values.</p>
*
* @param title the main text of the title
* @throws NullPointerException if the title is null
*/
public Title(@NotNull BaseComponent[] title) {
this(title, null);
}
/**
* Create a title with the default time values and no subtitle.
*
* <p>Times use default values.</p>
*
* @param title the main text of the title
* @throws NullPointerException if the title is null
*/
public Title(@NotNull String title) {
this(title, null);
}
/**
* Create a title with the default time values.
*
* <p>Times use default values.</p>
*
* @param title the main text of the title
* @param subtitle the secondary text of the title
*/
public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle) {
this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT);
}
/**
* Create a title with the default time values.
*
* <p>Times use default values.</p>
*
* @param title the main text of the title
* @param subtitle the secondary text of the title
*/
public Title(@NotNull BaseComponent[] title, @Nullable BaseComponent[] subtitle) {
this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT);
}
/**
* Create a title with the default time values.
*
* <p>Times use default values.</p>
*
* @param title the main text of the title
* @param subtitle the secondary text of the title
*/
public Title(@NotNull String title, @Nullable String subtitle) {
this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT);
}
/**
* Creates a new title.
*
* @param title the main text of the title
* @param subtitle the secondary text of the title
* @param fadeIn the number of ticks for the title to fade in
* @param stay the number of ticks for the title to stay on screen
* @param fadeOut the number of ticks for the title to fade out
* @throws IllegalArgumentException if any of the times are negative
*/
public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle, int fadeIn, int stay, int fadeOut) {
this(
new BaseComponent[]{checkNotNull(title, "title")},
subtitle == null ? null : new BaseComponent[]{subtitle},
fadeIn,
stay,
fadeOut
);
}
/**
* Creates a new title.
*
* @param title the main text of the title
* @param subtitle the secondary text of the title
* @param fadeIn the number of ticks for the title to fade in
* @param stay the number of ticks for the title to stay on screen
* @param fadeOut the number of ticks for the title to fade out
* @throws IllegalArgumentException if any of the times are negative
*/
public Title(@Nullable BaseComponent[] title, @NotNull BaseComponent[] subtitle, int fadeIn, int stay, int fadeOut) {
checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn);
checkArgument(stay >= 0, "Negative stay: %s", stay);
checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut);
this.title = checkNotNull(title, "title");
this.subtitle = subtitle;
this.fadeIn = fadeIn;
this.stay = stay;
this.fadeOut = fadeOut;
}
/**
* Creates a new title.
*
* <p>It is recommended to the {@link BaseComponent} constrctors.</p>
*
* @param title the main text of the title
* @param subtitle the secondary text of the title
* @param fadeIn the number of ticks for the title to fade in
* @param stay the number of ticks for the title to stay on screen
* @param fadeOut the number of ticks for the title to fade out
*/
public Title(@NotNull String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut) {
this(
TextComponent.fromLegacyText(checkNotNull(title, "title")),
subtitle == null ? null : TextComponent.fromLegacyText(subtitle),
fadeIn,
stay,
fadeOut
);
}
/**
* Gets the text of this title
*
* @return the text
*/
@NotNull
public BaseComponent[] getTitle() {
return this.title;
}
/**
* Gets the text of this title's subtitle
*
* @return the text
*/
@Nullable
public BaseComponent[] getSubtitle() {
return this.subtitle;
}
/**
* Gets the number of ticks to fade in.
*
* <p>The returned value is never negative.</p>
*
* @return the number of ticks to fade in
*/
public int getFadeIn() {
return this.fadeIn;
}
/**
* Gets the number of ticks to stay.
*
* <p>The returned value is never negative.</p>
*
* @return the number of ticks to stay
*/
public int getStay() {
return this.stay;
}
/**
* Gets the number of ticks to fade out.
*
* <p>The returned value is never negative.</p>
*
* @return the number of ticks to fade out
*/
public int getFadeOut() {
return this.fadeOut;
}
@NotNull
public static Builder builder() {
return new Builder();
}
/**
* A builder for creating titles
*/
public static final class Builder {
private BaseComponent[] title;
private BaseComponent[] subtitle;
private int fadeIn = DEFAULT_FADE_IN;
private int stay = DEFAULT_STAY;
private int fadeOut = DEFAULT_FADE_OUT;
/**
* Sets the title to the given text.
*
* @param title the title text
* @return this builder instance
* @throws NullPointerException if the title is null
*/
@NotNull
public Builder title(@NotNull BaseComponent title) {
return this.title(new BaseComponent[]{checkNotNull(title, "title")});
}
/**
* Sets the title to the given text.
*
* @param title the title text
* @return this builder instance
* @throws NullPointerException if the title is null
*/
@NotNull
public Builder title(@NotNull BaseComponent[] title) {
this.title = checkNotNull(title, "title");
return this;
}
/**
* Sets the title to the given text.
*
* <p>It is recommended to the {@link BaseComponent} methods.</p>
*
* @param title the title text
* @return this builder instance
* @throws NullPointerException if the title is null
*/
@NotNull
public Builder title(@NotNull String title) {
return this.title(TextComponent.fromLegacyText(checkNotNull(title, "title")));
}
/**
* Sets the subtitle to the given text.
*
* @param subtitle the title text
* @return this builder instance
*/
@NotNull
public Builder subtitle(@Nullable BaseComponent subtitle) {
return this.subtitle(subtitle == null ? null : new BaseComponent[]{subtitle});
}
/**
* Sets the subtitle to the given text.
*
* @param subtitle the title text
* @return this builder instance
*/
@NotNull
public Builder subtitle(@Nullable BaseComponent[] subtitle) {
this.subtitle = subtitle;
return this;
}
/**
* Sets the subtitle to the given text.
*
* <p>It is recommended to the {@link BaseComponent} methods.</p>
*
* @param subtitle the title text
* @return this builder instance
*/
@NotNull
public Builder subtitle(@Nullable String subtitle) {
return this.subtitle(subtitle == null ? null : TextComponent.fromLegacyText(subtitle));
}
/**
* Sets the number of ticks for the title to fade in
*
* @param fadeIn the number of ticks to fade in
* @return this builder instance
* @throws IllegalArgumentException if it is negative
*/
@NotNull
public Builder fadeIn(int fadeIn) {
checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn);
this.fadeIn = fadeIn;
return this;
}
/**
* Sets the number of ticks for the title to stay.
*
* @param stay the number of ticks to stay
* @return this builder instance
* @throws IllegalArgumentException if it is negative
*/
@NotNull
public Builder stay(int stay) {
checkArgument(stay >= 0, "Negative stay: %s", stay);
this.stay = stay;
return this;
}
/**
* Sets the number of ticks for the title to fade out.
*
* @param fadeOut the number of ticks to fade out
* @return this builder instance
* @throws IllegalArgumentException if it is negative
*/
@NotNull
public Builder fadeOut(int fadeOut) {
checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut);
this.fadeOut = fadeOut;
return this;
}
/**
* Create a title based on the values in the builder.
*
* @return a title from the values in this builder
* @throws IllegalStateException if title isn't specified
*/
@NotNull
public Title build() {
checkState(title != null, "Title not specified");
return new Title(this.title, this.subtitle, this.fadeIn, this.stay, this.fadeOut);
}
}
}

View File

@@ -1,52 +0,0 @@
package com.destroystokyo.paper.block;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
/**
* Represents the sounds that a {@link Block} makes in certain situations
* <p>
* The sound group includes break, step, place, hit, and fall sounds.
*/
public interface BlockSoundGroup {
/**
* Gets the sound that plays when breaking this block
*
* @return The break sound
*/
@NotNull
Sound getBreakSound();
/**
* Gets the sound that plays when stepping on this block
*
* @return The step sound
*/
@NotNull
Sound getStepSound();
/**
* Gets the sound that plays when placing this block
*
* @return The place sound
*/
@NotNull
Sound getPlaceSound();
/**
* Gets the sound that plays when hitting this block
*
* @return The hit sound
*/
@NotNull
Sound getHitSound();
/**
* Gets the sound that plays when this block falls
*
* @return The fall sound
*/
@NotNull
Sound getFallSound();
}

View File

@@ -1,54 +0,0 @@
package com.destroystokyo.paper.block;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.jetbrains.annotations.NotNull;
/**
* Represents information about a targeted block
*/
public class TargetBlockInfo {
private final Block block;
private final BlockFace blockFace;
public TargetBlockInfo(@NotNull Block block, @NotNull BlockFace blockFace) {
this.block = block;
this.blockFace = blockFace;
}
/**
* Get the block that is targeted
*
* @return Targeted block
*/
@NotNull
public Block getBlock() {
return block;
}
/**
* Get the targeted BlockFace
*
* @return Targeted blockface
*/
@NotNull
public BlockFace getBlockFace() {
return blockFace;
}
/**
* Get the relative Block to the targeted block on the side it is targeted at
*
* @return Block relative to targeted block
*/
@NotNull
public Block getRelativeBlock() {
return block.getRelative(blockFace);
}
public enum FluidMode {
NEVER,
SOURCE_ONLY,
ALWAYS
}
}

View File

@@ -1,170 +0,0 @@
package com.destroystokyo.paper.entity;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Handles pathfinding operations for an Entity
*/
public interface Pathfinder {
/**
*
* @return The entity that is controlled by this pathfinder
*/
@NotNull
Mob getEntity();
/**
* Instructs the Entity to stop trying to navigate to its current desired location
*/
void stopPathfinding();
/**
* If the entity is currently trying to navigate to a destination, this will return true
* @return true if the entity is navigating to a destination
*/
boolean hasPath();
/**
* @return The location the entity is trying to navigate to, or null if there is no destination
*/
@Nullable
PathResult getCurrentPath();
/**
* Calculates a destination for the Entity to navigate to, but does not set it
* as the current target. Useful for calculating what would happen before setting it.
* @param loc Location to navigate to
* @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated
*/
@Nullable PathResult findPath(@NotNull Location loc);
/**
* Calculates a destination for the Entity to navigate to to reach the target entity,
* but does not set it as the current target.
* Useful for calculating what would happen before setting it.
*
* The behavior of this PathResult is subject to the games pathfinding rules, and may
* result in the pathfinding automatically updating to follow the target Entity.
*
* However, this behavior is not guaranteed, and is subject to the games behavior.
*
* @param target the Entity to navigate to
* @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated
*/
@Nullable PathResult findPath(@NotNull LivingEntity target);
/**
* Calculates a destination for the Entity to navigate to, and sets it with default speed
* as the current target.
* @param loc Location to navigate to
* @return If the pathfinding was successfully started
*/
default boolean moveTo(@NotNull Location loc) {
return moveTo(loc, 1);
}
/**
* Calculates a destination for the Entity to navigate to, with desired speed
* as the current target.
* @param loc Location to navigate to
* @param speed Speed multiplier to navigate at, where 1 is 'normal'
* @return If the pathfinding was successfully started
*/
default boolean moveTo(@NotNull Location loc, double speed) {
PathResult path = findPath(loc);
return path != null && moveTo(path, speed);
}
/**
* Calculates a destination for the Entity to navigate to to reach the target entity,
* and sets it with default speed.
*
* The behavior of this PathResult is subject to the games pathfinding rules, and may
* result in the pathfinding automatically updating to follow the target Entity.
*
* However, this behavior is not guaranteed, and is subject to the games behavior.
*
* @param target the Entity to navigate to
* @return If the pathfinding was successfully started
*/
default boolean moveTo(@NotNull LivingEntity target) {
return moveTo(target, 1);
}
/**
* Calculates a destination for the Entity to navigate to to reach the target entity,
* and sets it with specified speed.
*
* The behavior of this PathResult is subject to the games pathfinding rules, and may
* result in the pathfinding automatically updating to follow the target Entity.
*
* However, this behavior is not guaranteed, and is subject to the games behavior.
*
* @param target the Entity to navigate to
* @param speed Speed multiplier to navigate at, where 1 is 'normal'
* @return If the pathfinding was successfully started
*/
default boolean moveTo(@NotNull LivingEntity target, double speed) {
PathResult path = findPath(target);
return path != null && moveTo(path, speed);
}
/**
* Takes the result of a previous pathfinding calculation and sets it
* as the active pathfinding with default speed.
*
* @param path The Path to start following
* @return If the pathfinding was successfully started
*/
default boolean moveTo(@NotNull PathResult path) {
return moveTo(path, 1);
}
/**
* Takes the result of a previous pathfinding calculation and sets it
* as the active pathfinding,
*
* @param path The Path to start following
* @param speed Speed multiplier to navigate at, where 1 is 'normal'
* @return If the pathfinding was successfully started
*/
boolean moveTo(@NotNull PathResult path, double speed);
/**
* Represents the result of a pathfinding calculation
*/
interface PathResult {
/**
* All currently calculated points to follow along the path to reach the destination location
*
* Will return points the entity has already moved past, see {@link #getNextPointIndex()}
* @return List of points
*/
@NotNull
List<Location> getPoints();
/**
* @return Returns the index of the current point along the points returned in {@link #getPoints()} the entity
* is trying to reach, or null if we are done with this pathfinding.
*/
int getNextPointIndex();
/**
* @return The next location in the path points the entity is trying to reach, or null if there is no next point
*/
@Nullable Location getNextPoint();
/**
* @return The closest point the path can get to the target location
*/
@Nullable Location getFinalPoint();
}
}

View File

@@ -1,31 +0,0 @@
package com.destroystokyo.paper.entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.jetbrains.annotations.NotNull;
public interface RangedEntity extends Mob {
/**
* Attack the specified entity using a ranged attack.
*
* @param target the entity to target
* @param charge How "charged" the attack is (how far back the bow was pulled for Bow attacks).
* This should be a value between 0 and 1, represented as targetDistance/maxDistance.
*/
void rangedAttack(@NotNull LivingEntity target, float charge);
/**
* Sets that the Entity is "charging" up an attack, by raising its hands
*
* @param raiseHands Whether the entities hands are raised to charge attack
*/
void setChargingAttack(boolean raiseHands);
/**
* Alias to {@link LivingEntity#isHandRaised()}, if the entity is charging an attack
* @return If entities hands are raised
*/
default boolean isChargingAttack() {
return isHandRaised();
}
}

View File

@@ -1,38 +0,0 @@
package com.destroystokyo.paper.entity;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
/**
* Represents information about a targeted entity
*/
public class TargetEntityInfo {
private final Entity entity;
private final Vector hitVec;
public TargetEntityInfo(@NotNull Entity entity, @NotNull Vector hitVec) {
this.entity = entity;
this.hitVec = hitVec;
}
/**
* Get the entity that is targeted
*
* @return Targeted entity
*/
@NotNull
public Entity getEntity() {
return entity;
}
/**
* Get the position the entity is targeted at
*
* @return Targeted position
*/
@NotNull
public Vector getHitVector() {
return hitVec;
}
}

View File

@@ -1,148 +0,0 @@
package com.destroystokyo.paper.event.block;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Called when an anvil is damaged from being used
*/
public class AnvilDamagedEvent extends InventoryEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel;
private DamageState damageState;
public AnvilDamagedEvent(@NotNull InventoryView inventory, @NotNull BlockData blockData) {
super(inventory);
this.damageState = DamageState.getState(blockData);
}
@NotNull
@Override
public AnvilInventory getInventory() {
return (AnvilInventory) super.getInventory();
}
/**
* Gets the new state of damage on the anvil
*
* @return Damage state
*/
@NotNull
public DamageState getDamageState() {
return damageState;
}
/**
* Sets the new state of damage on the anvil
*
* @param damageState Damage state
*/
public void setDamageState(@NotNull DamageState damageState) {
this.damageState = damageState;
}
/**
* Gets if anvil is breaking on this use
*
* @return True if breaking
*/
public boolean isBreaking() {
return damageState == DamageState.BROKEN;
}
/**
* Sets if anvil is breaking on this use
*
* @param breaking True if breaking
*/
public void setBreaking(boolean breaking) {
if (breaking) {
damageState = DamageState.BROKEN;
} else if (damageState == DamageState.BROKEN) {
damageState = DamageState.DAMAGED;
}
}
public boolean isCancelled() {
return cancel;
}
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Represents the amount of damage on an anvil block
*/
public enum DamageState {
FULL(Material.ANVIL),
CHIPPED(Material.CHIPPED_ANVIL),
DAMAGED(Material.DAMAGED_ANVIL),
BROKEN(Material.AIR);
private Material material;
DamageState(@NotNull Material material) {
this.material = material;
}
/**
* Get block material of this state
*
* @return Material
*/
@NotNull
public Material getMaterial() {
return material;
}
/**
* Get damaged state by block data
*
* @param blockData Block data
* @return DamageState
* @throws IllegalArgumentException If non anvil block data is given
*/
@NotNull
public static DamageState getState(@Nullable BlockData blockData) {
return blockData == null ? BROKEN : getState(blockData.getMaterial());
}
/**
* Get damaged state by block material
*
* @param material Block material
* @return DamageState
* @throws IllegalArgumentException If non anvil material is given
*/
@NotNull
public static DamageState getState(@Nullable Material material) {
if (material == null) {
return BROKEN;
}
for (DamageState state : values()) {
if (state.material == material) {
return state;
}
}
throw new IllegalArgumentException("Material not an anvil");
}
}
}

View File

@@ -1,86 +0,0 @@
package com.destroystokyo.paper.event.block;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.potion.PotionEffect;
import org.jetbrains.annotations.NotNull;
/**
* Called when a beacon effect is being applied to a player.
*/
public class BeaconEffectEvent extends BlockEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private PotionEffect effect;
private Player player;
private boolean primary;
public BeaconEffectEvent(@NotNull Block block, @NotNull PotionEffect effect, @NotNull Player player, boolean primary) {
super(block);
this.effect = effect;
this.player = player;
this.primary = primary;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
/**
* Gets the potion effect being applied.
*
* @return Potion effect
*/
@NotNull
public PotionEffect getEffect() {
return effect;
}
/**
* Sets the potion effect that will be applied.
*
* @param effect Potion effect
*/
public void setEffect(@NotNull PotionEffect effect) {
this.effect = effect;
}
/**
* Gets the player who the potion effect is being applied to.
*
* @return Affected player
*/
@NotNull
public Player getPlayer() {
return player;
}
/**
* Gets whether the effect is a primary beacon effect.
*
* @return true if this event represents a primary effect
*/
public boolean isPrimary() {
return primary;
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,92 +0,0 @@
package com.destroystokyo.paper.event.block;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired anytime the server intends to 'destroy' a block through some triggering reason.
* This does not fire anytime a block is set to air, but only with more direct triggers such
* as physics updates, pistons, Entities changing blocks, commands set to "Destroy".
*
* This event is associated with the game playing a sound effect at the block in question, when
* something can be described as "intend to destroy what is there",
*
* Events such as leaves decaying, pistons retracting (where the block is moving), does NOT fire this event.
*
*/
public class BlockDestroyEvent extends BlockEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
@NotNull private final BlockData newState;
private final boolean willDrop;
private boolean playEffect;
private boolean cancelled = false;
public BlockDestroyEvent(@NotNull Block block, @NotNull BlockData newState, boolean willDrop) {
super(block);
this.newState = newState;
this.willDrop = willDrop;
}
/**
* @return The new state of this block (Air, or a Fluid type)
*/
@NotNull
public BlockData getNewState() {
return newState;
}
/**
* @return If the server is going to drop the block in question with this destroy event
*/
public boolean willDrop() {
return this.willDrop;
}
/**
* @return If the server is going to play the sound effect for this destruction
*/
public boolean playEffect() {
return this.playEffect;
}
/**
* @param playEffect If the server should play the sound effect for this destruction
*/
public void setPlayEffect(boolean playEffect) {
this.playEffect = playEffect;
}
/**
* @return If the event is cancelled, meaning the block will not be destroyed
*/
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* If the event is cancelled, the block will remain in its previous state.
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,114 +0,0 @@
package com.destroystokyo.paper.event.block;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Called when TNT block is about to turn into {@link org.bukkit.entity.TNTPrimed}
* <p>
* Cancelling it won't turn TNT into {@link org.bukkit.entity.TNTPrimed} and leaves
* the TNT block as-is
*
* @author Mark Vainomaa
*/
public class TNTPrimeEvent extends BlockEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
@NotNull private PrimeReason reason;
@Nullable private Entity primerEntity;
public TNTPrimeEvent(@NotNull Block theBlock, @NotNull PrimeReason reason, @Nullable Entity primerEntity) {
super(theBlock);
this.reason = reason;
this.primerEntity = primerEntity;
}
/**
* Gets the TNT prime reason
*
* @return Prime reason
*/
@NotNull
public PrimeReason getReason() {
return this.reason;
}
/**
* Gets the TNT primer {@link Entity}.
*
* It's null if {@link #getReason()} is {@link PrimeReason#REDSTONE} or {@link PrimeReason#FIRE}.
* It's not null if {@link #getReason()} is {@link PrimeReason#ITEM} or {@link PrimeReason#PROJECTILE}
* It might be null if {@link #getReason()} is {@link PrimeReason#EXPLOSION}
*
* @return The {@link Entity} who primed the TNT
*/
@Nullable
public Entity getPrimerEntity() {
return this.primerEntity;
}
/**
* Gets whether spawning {@link org.bukkit.entity.TNTPrimed} should be cancelled or not
*
* @return Whether spawning {@link org.bukkit.entity.TNTPrimed} should be cancelled or not
*/
@Override
public boolean isCancelled() {
return this.cancelled;
}
/**
* Sets whether to cancel spawning {@link org.bukkit.entity.TNTPrimed} or not
*
* @param cancel whether spawning {@link org.bukkit.entity.TNTPrimed} should be cancelled or not
*/
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Nullable
@Override
public HandlerList getHandlers() {
return handlers;
}
@Nullable
public static HandlerList getHandlerList() {
return handlers;
}
public enum PrimeReason {
/**
* When TNT prime was caused by other explosion (chain reaction)
*/
EXPLOSION,
/**
* When TNT prime was caused by fire
*/
FIRE,
/**
* When {@link org.bukkit.entity.Player} used {@link org.bukkit.Material#FLINT_AND_STEEL} or
* {@link org.bukkit.Material#FIRE_CHARGE} on given TNT block
*/
ITEM,
/**
* When TNT prime was caused by an {@link Entity} shooting TNT
* using a bow with {@link org.bukkit.enchantments.Enchantment#ARROW_FIRE} enchantment
*/
PROJECTILE,
/**
* When redstone power triggered the TNT prime
*/
REDSTONE
}
}

View File

@@ -1,54 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Creeper;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a Creeper is ignite flag is changed (armed/disarmed to explode).
*/
public class CreeperIgniteEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean canceled;
private boolean ignited;
public CreeperIgniteEvent(@NotNull Creeper creeper, boolean ignited) {
super(creeper);
this.ignited = ignited;
}
@NotNull
@Override
public Creeper getEntity() {
return (Creeper) entity;
}
public boolean isIgnited() {
return ignited;
}
public void setIgnited(boolean ignited) {
this.ignited = ignited;
}
public boolean isCancelled() {
return canceled;
}
public void setCancelled(boolean cancel) {
canceled = cancel;
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,79 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.DragonFireball;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import java.util.Collection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Fired when a DragonFireball collides with a block/entity and spawns an AreaEffectCloud
*/
public class EnderDragonFireballHitEvent extends EntityEvent implements Cancellable {
@Nullable private final Collection<LivingEntity> targets;
@NotNull private final AreaEffectCloud areaEffectCloud;
public EnderDragonFireballHitEvent(@NotNull DragonFireball fireball, @Nullable Collection<LivingEntity> targets, @NotNull AreaEffectCloud areaEffectCloud) {
super(fireball);
this.targets = targets;
this.areaEffectCloud = areaEffectCloud;
}
/**
* The fireball involved in this event
*/
@NotNull
@Override
public DragonFireball getEntity() {
return (DragonFireball) super.getEntity();
}
/**
* The living entities hit by fireball
*
* May be null if no entities were hit
*
* @return the targets
*/
@Nullable
public Collection<LivingEntity> getTargets() {
return targets;
}
/**
* @return The area effect cloud spawned in this collision
*/
@NotNull
public AreaEffectCloud getAreaEffectCloud() {
return areaEffectCloud;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,61 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.EnderDragon;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when an EnderDragon spawns an AreaEffectCloud by shooting flames
*/
public class EnderDragonFlameEvent extends EntityEvent implements Cancellable {
@NotNull private final AreaEffectCloud areaEffectCloud;
public EnderDragonFlameEvent(@NotNull EnderDragon enderDragon, @NotNull AreaEffectCloud areaEffectCloud) {
super(enderDragon);
this.areaEffectCloud = areaEffectCloud;
}
/**
* The enderdragon involved in this event
*/
@NotNull
@Override
public EnderDragon getEntity() {
return (EnderDragon) super.getEntity();
}
/**
* @return The area effect cloud spawned in this collision
*/
@NotNull
public AreaEffectCloud getAreaEffectCloud() {
return areaEffectCloud;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,61 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.DragonFireball;
import org.bukkit.entity.EnderDragon;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when an EnderDragon shoots a fireball
*/
public class EnderDragonShootFireballEvent extends EntityEvent implements Cancellable {
@NotNull private final DragonFireball fireball;
public EnderDragonShootFireballEvent(@NotNull EnderDragon entity, @NotNull DragonFireball fireball) {
super(entity);
this.fireball = fireball;
}
/**
* The enderdragon shooting the fireball
*/
@NotNull
@Override
public EnderDragon getEntity() {
return (EnderDragon) super.getEntity();
}
/**
* @return The fireball being shot
*/
@NotNull
public DragonFireball getFireball() {
return fireball;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
*
* 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 com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when an Enderman determines if it should attack a player or not.
* Starts off cancelled if the player is wearing a pumpkin head or is not looking
* at the Enderman, according to Vanilla rules.
*
*/
public class EndermanAttackPlayerEvent extends EntityEvent implements Cancellable {
@NotNull private final Player player;
public EndermanAttackPlayerEvent(@NotNull Enderman entity, @NotNull Player player) {
super(entity);
this.player = player;
}
/**
* The enderman considering attacking
*
* @return The enderman considering attacking
*/
@NotNull
@Override
public Enderman getEntity() {
return (Enderman) super.getEntity();
}
/**
* The player the Enderman is considering attacking
*
* @return The player the Enderman is considering attacking
*/
@NotNull
public Player getPlayer() {
return player;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
/**
*
* @return If cancelled, the enderman will not attack
*/
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* Cancels if the Enderman will attack this player
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,87 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
public class EndermanEscapeEvent extends EntityEvent implements Cancellable {
@NotNull private final Reason reason;
public EndermanEscapeEvent(@NotNull Enderman entity, @NotNull Reason reason) {
super(entity);
this.reason = reason;
}
@NotNull
@Override
public Enderman getEntity() {
return (Enderman) super.getEntity();
}
/**
* @return The reason the enderman is trying to escape
*/
@NotNull
public Reason getReason() {
return reason;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* Cancels the escape.
*
* If this escape normally would of resulted in damage avoidance such as indirect,
* the enderman will now take damage.
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
public enum Reason {
/**
* The enderman has stopped attacking and ran away
*/
RUNAWAY,
/**
* The enderman has teleported away due to indirect damage (ranged)
*/
INDIRECT,
/**
* The enderman has teleported away due to a critical hit
*/
CRITICAL_HIT,
/**
* The enderman has teleported away due to the player staring at it during combat
*/
STARE,
/**
* Specific case for CRITICAL_HIT where the enderman is taking rain damage
*/
DROWN
}
}

View File

@@ -1,32 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired any time an entity is being added to the world for any reason.
*
* Not to be confused with {@link org.bukkit.event.entity.CreatureSpawnEvent}
* This will fire anytime a chunk is reloaded too.
*/
public class EntityAddToWorldEvent extends EntityEvent {
public EntityAddToWorldEvent(@NotNull Entity entity) {
super(entity);
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,82 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
/**
* Fired when an Entity is knocked back by the hit of another Entity. The acceleration
* vector can be modified. If this event is cancelled, the entity is not knocked back.
*
*/
public class EntityKnockbackByEntityEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
@NotNull private final Entity hitBy;
private final float knockbackStrength;
@NotNull private final Vector acceleration;
private boolean cancelled = false;
public EntityKnockbackByEntityEvent(@NotNull LivingEntity entity, @NotNull Entity hitBy, float knockbackStrength, @NotNull Vector acceleration) {
super(entity);
this.hitBy = hitBy;
this.knockbackStrength = knockbackStrength;
this.acceleration = acceleration;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
/**
* @return the entity which was knocked back
*/
@NotNull
@Override
public LivingEntity getEntity() {
return (LivingEntity) super.getEntity();
}
/**
* @return the original knockback strength.
*/
public float getKnockbackStrength() {
return knockbackStrength;
}
/**
* @return the Entity which hit
*/
@NotNull
public Entity getHitBy() {
return hitBy;
}
/**
* @return the acceleration that will be applied
*/
@NotNull
public Vector getAcceleration() {
return acceleration;
}
}

View File

@@ -1,82 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Fired when an Entity decides to start moving towards a location.
*
* This event does not fire for the entities actual movement. Only when it
* is choosing to start moving to a location.
*/
public class EntityPathfindEvent extends EntityEvent implements Cancellable {
@Nullable private final Entity targetEntity;
@NotNull private final Location loc;
public EntityPathfindEvent(@NotNull Entity entity, @NotNull Location loc, @Nullable Entity targetEntity) {
super(entity);
this.targetEntity = targetEntity;
this.loc = loc;
}
/**
* The Entity that is pathfinding.
* @return The Entity that is pathfinding.
*/
@NotNull
public Entity getEntity() {
return entity;
}
/**
* If the Entity is trying to pathfind to an entity, this is the entity in relation.
*
* Otherwise this will return null.
*
* @return The entity target or null
*/
@Nullable
public Entity getTargetEntity() {
return targetEntity;
}
/**
* The Location of where the entity is about to move to.
*
* Note that if the target happened to of been an entity
* @return Location of where the entity is trying to pathfind to.
*/
@NotNull
public Location getLoc() {
return loc;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,29 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired any time an entity is being removed from a world for any reason
*/
public class EntityRemoveFromWorldEvent extends EntityEvent {
public EntityRemoveFromWorldEvent(@NotNull Entity entity) {
super(entity);
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,31 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.Location;
import org.bukkit.block.EndGateway;
import org.bukkit.entity.Entity;
import org.bukkit.event.entity.EntityTeleportEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired any time an entity attempts to teleport in an end gateway
*/
public class EntityTeleportEndGatewayEvent extends EntityTeleportEvent {
@NotNull private final EndGateway gateway;
public EntityTeleportEndGatewayEvent(@NotNull Entity what, @NotNull Location from, @NotNull Location to, @NotNull EndGateway gateway) {
super(what, from, to);
this.gateway = gateway;
}
/**
* The gateway triggering the teleport
*
* @return EndGateway used
*/
@NotNull
public EndGateway getGateway() {
return gateway;
}
}

View File

@@ -1,92 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Entity;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.entity.EntityTransformEvent;
/**
* Fired when an entity transforms into another entity
* <p>
* If the event is cancelled, the entity will not transform
* @deprecated Bukkit has added {@link EntityTransformEvent}, you should start using that
*/
@Deprecated
public class EntityTransformedEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private final Entity transformed;
private final TransformedReason reason;
public EntityTransformedEvent(Entity entity, Entity transformed, TransformedReason reason) {
super(entity);
this.transformed = transformed;
this.reason = reason;
}
/**
* The entity after it has transformed
*
* @return Transformed entity
* @deprecated see {@link EntityTransformEvent#getTransformedEntity()}
*/
@Deprecated
public Entity getTransformed() {
return transformed;
}
/**
* @return The reason for the transformation
* @deprecated see {@link EntityTransformEvent#getTransformReason()}
*/
@Deprecated
public TransformedReason getReason() {
return reason;
}
@Override
public HandlerList getHandlers(){
return handlers;
}
public static HandlerList getHandlerList(){
return handlers;
}
@Override
public boolean isCancelled(){
return cancelled;
}
@Override
public void setCancelled(boolean cancel){
cancelled = cancel;
}
public enum TransformedReason {
/**
* When a zombie drowns
*/
DROWNED,
/**
* When a zombie villager is cured
*/
CURED,
/**
* When a villager turns to a zombie villager
*/
INFECTED,
/**
* When a mooshroom turns to a cow
*/
SHEARED,
/**
* When a pig turns to a zombiepigman
*/
LIGHTNING
}
}

View File

@@ -1,65 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LightningStrike;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.entity.EntityTransformEvent;
import java.util.Collections;
import org.jetbrains.annotations.NotNull;
/**
* Fired when lightning strikes an entity
*/
public class EntityZapEvent extends EntityTransformEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
@NotNull private final LightningStrike bolt;
public EntityZapEvent(@NotNull final Entity entity, @NotNull final LightningStrike bolt, @NotNull final Entity replacementEntity) {
super(entity, Collections.singletonList(replacementEntity), TransformReason.LIGHTNING);
Validate.notNull(bolt);
Validate.notNull(replacementEntity);
this.bolt = bolt;
}
public boolean isCancelled() {
return cancelled;
}
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
/**
* Gets the lightning bolt that is striking the entity.
* @return The lightning bolt responsible for this event
*/
@NotNull
public LightningStrike getBolt() {
return bolt;
}
/**
* Gets the entity that will replace the struck entity.
* @return The entity that will replace the struck entity
*/
@NotNull
public Entity getReplacementEntity() {
return getTransformedEntity();
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright (c) 2017 Daniel Ennis (Aikar) MIT License
*
* 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 com.destroystokyo.paper.event.entity;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired anytime the server is about to merge 2 experience orbs into one
*/
public class ExperienceOrbMergeEvent extends EntityEvent implements Cancellable {
@NotNull private final ExperienceOrb mergeTarget;
@NotNull private final ExperienceOrb mergeSource;
public ExperienceOrbMergeEvent(@NotNull ExperienceOrb mergeTarget, @NotNull ExperienceOrb mergeSource) {
super(mergeTarget);
this.mergeTarget = mergeTarget;
this.mergeSource = mergeSource;
}
/**
* @return The orb that will absorb the other experience orb
*/
@NotNull
public ExperienceOrb getMergeTarget() {
return mergeTarget;
}
/**
* @return The orb that is subject to being removed and merged into the target orb
*/
@NotNull
public ExperienceOrb getMergeSource() {
return mergeSource;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* @param cancel true if you wish to cancel this event, and prevent the orbs from merging
*/
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,31 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Called when a phantom is spawned for an exhausted player
*/
public class PhantomPreSpawnEvent extends PreCreatureSpawnEvent {
@NotNull private final Entity entity;
public PhantomPreSpawnEvent(@NotNull Location location, @NotNull Entity entity, @NotNull CreatureSpawnEvent.SpawnReason reason) {
super(location, EntityType.PHANTOM, reason);
this.entity = entity;
}
/**
* Get the entity this phantom is spawning for
*
* @return Entity
*/
@Nullable
public Entity getSpawningEntity() {
return entity;
}
}

View File

@@ -1,64 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when the server is calculating what chunks to try to spawn monsters in every Monster Spawn Tick event
*/
public class PlayerNaturallySpawnCreaturesEvent extends PlayerEvent implements Cancellable {
private byte radius;
public PlayerNaturallySpawnCreaturesEvent(@NotNull Player player, byte radius) {
super(player);
this.radius = radius;
}
/**
* @return The radius of chunks around this player to be included in natural spawn selection
*/
public byte getSpawnRadius() {
return radius;
}
/**
* @param radius The radius of chunks around this player to be included in natural spawn selection
*/
public void setSpawnRadius(byte radius) {
this.radius = radius;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
/**
* @return If this players chunks will be excluded from natural spawns
*/
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* @param cancel true if you wish to cancel this event, and not include this players chunks for natural spawning
*/
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,104 +0,0 @@
package com.destroystokyo.paper.event.entity;
import com.google.common.base.Preconditions;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
/**
* WARNING: This event only fires for a limited number of cases, and not for every case that CreatureSpawnEvent does.
*
* You should still listen to CreatureSpawnEvent as a backup, and only use this event as an "enhancement".
* The intent of this event is to improve server performance, so limited use cases.
*
* Currently: NATURAL and SPAWNER based reasons. Please submit a Pull Request for future additions.
* Also, Plugins that replace Entity Registrations with their own custom entities might not fire this event.
*/
public class PreCreatureSpawnEvent extends Event implements Cancellable {
@NotNull private final Location location;
@NotNull private final EntityType type;
@NotNull private final CreatureSpawnEvent.SpawnReason reason;
private boolean shouldAbortSpawn;
public PreCreatureSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason) {
this.location = Preconditions.checkNotNull(location, "Location may not be null").clone();
this.type = Preconditions.checkNotNull(type, "Type may not be null");
this.reason = Preconditions.checkNotNull(reason, "Reason may not be null");
}
/**
* @return The location this creature is being spawned at
*/
@NotNull
public Location getSpawnLocation() {
return location;
}
/**
* @return The type of creature being spawned
*/
@NotNull
public EntityType getType() {
return type;
}
/**
* @return Reason this creature is spawning (ie, NATURAL vs SPAWNER)
*/
@NotNull
public CreatureSpawnEvent.SpawnReason getReason() {
return reason;
}
/**
* @return If the spawn process should be aborted vs trying more attempts
*/
public boolean shouldAbortSpawn() {
return shouldAbortSpawn;
}
/**
* Set this if you are more blanket blocking all types of these spawns, and wish to abort the spawn process from
* trying more attempts after this cancellation.
*
* @param shouldAbortSpawn Set if the spawn process should be aborted vs trying more attempts
*/
public void setShouldAbortSpawn(boolean shouldAbortSpawn) {
this.shouldAbortSpawn = shouldAbortSpawn;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
/**
* @return If the spawn of this creature is cancelled or not
*/
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* Cancelling this event is more effecient than cancelling CreatureSpawnEvent
* @param cancel true if you wish to cancel this event, and abort the spawn of this creature
*/
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,29 +0,0 @@
package com.destroystokyo.paper.event.entity;
import com.google.common.base.Preconditions;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called before an entity is spawned into a world by a spawner.
*
* This only includes the spawner's location and not the full BlockState snapshot for performance reasons.
* If you really need it you have to get the spawner yourself.
*/
public class PreSpawnerSpawnEvent extends PreCreatureSpawnEvent {
@NotNull private final Location spawnerLocation;
public PreSpawnerSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull Location spawnerLocation) {
super(location, type, CreatureSpawnEvent.SpawnReason.SPAWNER);
this.spawnerLocation = Preconditions.checkNotNull(spawnerLocation, "Spawner location may not be null");
}
@NotNull
public Location getSpawnerLocation() {
return spawnerLocation;
}
}

View File

@@ -1,67 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when an projectile collides with an entity
* <p>
* This event is called <b>before</b> {@link org.bukkit.event.entity.EntityDamageByEntityEvent}, and cancelling it will allow the projectile to continue flying
*/
public class ProjectileCollideEvent extends EntityEvent implements Cancellable {
@NotNull private final Entity collidedWith;
/**
* Get the entity the projectile collided with
*
* @return the entity collided with
*/
@NotNull
public Entity getCollidedWith() {
return collidedWith;
}
public ProjectileCollideEvent(@NotNull Projectile what, @NotNull Entity collidedWith) {
super(what);
this.collidedWith = collidedWith;
}
/**
* Get the projectile that collided
*
* @return the projectile that collided
*/
@NotNull
public Projectile getEntity() {
return (Projectile) super.getEntity();
}
private static final HandlerList handlerList = new HandlerList();
@NotNull
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlerList;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@@ -1,47 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.SkeletonHorse;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Event called when a player gets close to a skeleton horse and triggers the lightning trap
*/
public class SkeletonHorseTrapEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
public SkeletonHorseTrapEvent(@NotNull SkeletonHorse horse) {
super(horse);
}
@NotNull
@Override
public SkeletonHorse getEntity() {
return (SkeletonHorse) super.getEntity();
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,38 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Slime;
import org.bukkit.event.Cancellable;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Slime decides to change it's facing direction.
* <p>
* This event does not fire for the entity's actual movement. Only when it
* is choosing to change direction.
*/
public class SlimeChangeDirectionEvent extends SlimePathfindEvent implements Cancellable {
private float yaw;
public SlimeChangeDirectionEvent(@NotNull Slime slime, float yaw) {
super(slime);
this.yaw = yaw;
}
/**
* Get the new chosen yaw
*
* @return Chosen yaw
*/
public float getNewYaw() {
return yaw;
}
/**
* Set the new chosen yaw
*
* @param yaw Chosen yaw
*/
public void setNewYaw(float yaw) {
this.yaw = yaw;
}
}

View File

@@ -1,53 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Slime;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Slime decides to start pathfinding.
* <p>
* This event does not fire for the entity's actual movement. Only when it
* is choosing to start moving.
*/
public class SlimePathfindEvent extends EntityEvent implements Cancellable {
public SlimePathfindEvent(@NotNull Slime slime) {
super(slime);
}
/**
* The Slime that is pathfinding.
*
* @return The Slime that is pathfinding.
*/
@NotNull
public Slime getEntity() {
return (Slime) entity;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,17 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Slime;
import org.bukkit.event.Cancellable;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Slime decides to start jumping while swimming in water/lava.
* <p>
* This event does not fire for the entity's actual movement. Only when it
* is choosing to start jumping.
*/
public class SlimeSwimEvent extends SlimeWanderEvent implements Cancellable {
public SlimeSwimEvent(@NotNull Slime slime) {
super(slime);
}
}

View File

@@ -1,31 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Slime;
import org.bukkit.event.Cancellable;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Slime decides to change direction to target a LivingEntity.
* <p>
* This event does not fire for the entity's actual movement. Only when it
* is choosing to start moving.
*/
public class SlimeTargetLivingEntityEvent extends SlimePathfindEvent implements Cancellable {
@NotNull private final LivingEntity target;
public SlimeTargetLivingEntityEvent(@NotNull Slime slime, @NotNull LivingEntity target) {
super(slime);
this.target = target;
}
/**
* Get the targeted entity
*
* @return Targeted entity
*/
@NotNull
public LivingEntity getTarget() {
return target;
}
}

View File

@@ -1,17 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Slime;
import org.bukkit.event.Cancellable;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Slime decides to start wandering.
* <p>
* This event does not fire for the entity's actual movement. Only when it
* is choosing to start moving.
*/
public class SlimeWanderEvent extends SlimePathfindEvent implements Cancellable {
public SlimeWanderEvent(@NotNull Slime slime) {
super(slime);
}
}

View File

@@ -1,49 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Turtle;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Turtle decides to go home
*/
public class TurtleGoHomeEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
public TurtleGoHomeEvent(@NotNull Turtle turtle) {
super(turtle);
}
/**
* The turtle going home
*
* @return The turtle
*/
@NotNull
public Turtle getEntity() {
return (Turtle) entity;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,87 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.Location;
import org.bukkit.entity.Turtle;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Turtle lays eggs
*/
public class TurtleLayEggEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
@NotNull
private final Location location;
private int eggCount;
public TurtleLayEggEvent(@NotNull Turtle turtle, @NotNull Location location, int eggCount) {
super(turtle);
this.location = location;
this.eggCount = eggCount;
}
/**
* The turtle laying the eggs
*
* @return The turtle
*/
@NotNull
public Turtle getEntity() {
return (Turtle) entity;
}
/**
* Get the location where the eggs are being laid
*
* @return Location of eggs
*/
@NotNull
public Location getLocation() {
return location;
}
/**
* Get the number of eggs being laid
*
* @return Number of eggs
*/
public int getEggCount() {
return eggCount;
}
/**
* Set the number of eggs being laid
*
* @param eggCount Number of eggs
*/
public void setEggCount(int eggCount) {
if (eggCount < 1) {
cancelled = true;
return;
}
eggCount = Math.min(eggCount, 4);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,62 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.Location;
import org.bukkit.entity.Turtle;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a Turtle starts digging to lay eggs
*/
public class TurtleStartDiggingEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
@NotNull private final Location location;
public TurtleStartDiggingEvent(@NotNull Turtle turtle, @NotNull Location location) {
super(turtle);
this.location = location;
}
/**
* The turtle digging
*
* @return The turtle
*/
@NotNull
public Turtle getEntity() {
return (Turtle) entity;
}
/**
* Get the location where the turtle is digging
*
* @return Location where digging
*/
@NotNull
public Location getLocation() {
return location;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,70 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.Witch;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Fired when a witch consumes the potion in their hand to buff themselves.
*/
public class WitchConsumePotionEvent extends EntityEvent implements Cancellable {
@Nullable private ItemStack potion;
public WitchConsumePotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) {
super(witch);
this.potion = potion;
}
@NotNull
@Override
public Witch getEntity() {
return (Witch) super.getEntity();
}
/**
* @return the potion the witch will consume and have the effects applied.
*/
@Nullable
public ItemStack getPotion() {
return potion;
}
/**
* Sets the potion to be consumed and applied to the witch.
* @param potion The potion
*/
public void setPotion(@Nullable ItemStack potion) {
this.potion = potion != null ? potion.clone() : null;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
/**
* @return Event was cancelled or potion was null
*/
@Override
public boolean isCancelled() {
return cancelled || potion == null;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,80 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.Material;
import org.bukkit.entity.Witch;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class WitchReadyPotionEvent extends EntityEvent implements Cancellable {
private ItemStack potion;
public WitchReadyPotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) {
super(witch);
this.potion = potion;
}
/**
* Fires thee event, returning the desired potion, or air of cancelled
* @param witch the witch whom is readying to use a potion
* @param potion the potion to be used
* @return The ItemStack to be used
*/
@Nullable
public static ItemStack process(@NotNull Witch witch, @Nullable ItemStack potion) {
WitchReadyPotionEvent event = new WitchReadyPotionEvent(witch, potion);
if (!event.callEvent() || event.getPotion() == null) {
return new ItemStack(Material.AIR);
}
return event.getPotion();
}
@NotNull
@Override
public Witch getEntity() {
return (Witch) super.getEntity();
}
/**
* @return the potion the witch is readying to use
*/
@Nullable
public ItemStack getPotion() {
return potion;
}
/**
* Sets the potion the which is going to hold and use
* @param potion The potion
*/
public void setPotion(@Nullable ItemStack potion) {
this.potion = potion != null ? potion.clone() : null;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,81 +0,0 @@
package com.destroystokyo.paper.event.entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Witch;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Fired when a witch throws a potion at a player
*/
public class WitchThrowPotionEvent extends EntityEvent implements Cancellable {
@NotNull private final LivingEntity target;
@Nullable private ItemStack potion;
public WitchThrowPotionEvent(@NotNull Witch witch, @NotNull LivingEntity target, @Nullable ItemStack potion) {
super(witch);
this.target = target;
this.potion = potion;
}
@NotNull
@Override
public Witch getEntity() {
return (Witch) super.getEntity();
}
/**
* @return The target of the potion
*/
@NotNull
public LivingEntity getTarget() {
return target;
}
/**
* @return The potion the witch will throw at a player
*/
@Nullable
public ItemStack getPotion() {
return potion;
}
/**
* Sets the potion to be thrown at a player
* @param potion The potion
*/
public void setPotion(@Nullable ItemStack potion) {
this.potion = potion != null ? potion.clone() : null;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
private boolean cancelled = false;
/**
* @return Event was cancelled or potion was null
*/
@Override
public boolean isCancelled() {
return cancelled || potion == null;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,42 +0,0 @@
package com.destroystokyo.paper.event.executor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import com.destroystokyo.paper.util.SneakyThrow;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.NotNull;
public class MethodHandleEventExecutor implements EventExecutor {
private final Class<? extends Event> eventClass;
private final MethodHandle handle;
public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull MethodHandle handle) {
this.eventClass = eventClass;
this.handle = handle;
}
public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull Method m) {
this.eventClass = eventClass;
try {
m.setAccessible(true);
this.handle = MethodHandles.lookup().unreflect(m);
} catch (IllegalAccessException e) {
throw new AssertionError("Unable to set accessible", e);
}
}
@Override
public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
if (!eventClass.isInstance(event)) return;
try {
handle.invoke(listener, event);
} catch (Throwable t) {
SneakyThrow.sneaky(t);
}
}
}

View File

@@ -1,43 +0,0 @@
package com.destroystokyo.paper.event.executor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import com.destroystokyo.paper.util.SneakyThrow;
import com.google.common.base.Preconditions;
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.jetbrains.annotations.NotNull;
public class StaticMethodHandleEventExecutor implements EventExecutor {
private final Class<? extends Event> eventClass;
private final MethodHandle handle;
public StaticMethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull Method m) {
Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m);
Preconditions.checkArgument(eventClass != null, "eventClass is null");
this.eventClass = eventClass;
try {
m.setAccessible(true);
this.handle = MethodHandles.lookup().unreflect(m);
} catch (IllegalAccessException e) {
throw new AssertionError("Unable to set accessible", e);
}
}
@Override
public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
if (!eventClass.isInstance(event)) return;
try {
handle.invoke(event);
} catch (Throwable throwable) {
SneakyThrow.sneaky(throwable);
}
}
}

View File

@@ -1,47 +0,0 @@
package com.destroystokyo.paper.event.executor.asm;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import static org.objectweb.asm.Opcodes.*;
public class ASMEventExecutorGenerator {
@NotNull
public static byte[] generateEventExecutor(@NotNull Method m, @NotNull String name) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[] {Type.getInternalName(EventExecutor.class)});
// Generate constructor
GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null), ACC_PUBLIC, "<init>", "()V");
methodGenerator.loadThis();
methodGenerator.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); // Invoke the super class (Object) constructor
methodGenerator.returnValue();
methodGenerator.endMethod();
// Generate the execute method
methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V", null, null), ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Listener;)V");;
methodGenerator.loadArg(0);
methodGenerator.checkCast(Type.getType(m.getDeclaringClass()));
methodGenerator.loadArg(1);
methodGenerator.checkCast(Type.getType(m.getParameterTypes()[0]));
methodGenerator.visitMethodInsn(m.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, Type.getInternalName(m.getDeclaringClass()), m.getName(), Type.getMethodDescriptor(m), m.getDeclaringClass().isInterface());
if (m.getReturnType() != void.class) {
methodGenerator.pop();
}
methodGenerator.returnValue();
methodGenerator.endMethod();
writer.visitEnd();
return writer.toByteArray();
}
public static AtomicInteger NEXT_ID = new AtomicInteger(1);
@NotNull
public static String generateName() {
int id = NEXT_ID.getAndIncrement();
return "com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor" + id;
}
}

View File

@@ -1,35 +0,0 @@
package com.destroystokyo.paper.event.executor.asm;
import com.destroystokyo.paper.utils.UnsafeUtils;
import org.jetbrains.annotations.NotNull;
public interface ClassDefiner {
/**
* Returns if the defined classes can bypass access checks
*
* @return if classes bypass access checks
*/
public default boolean isBypassAccessChecks() {
return false;
}
/**
* Define a class
*
* @param parentLoader the parent classloader
* @param name the name of the class
* @param data the class data to load
* @return the defined class
* @throws ClassFormatError if the class data is invalid
* @throws NullPointerException if any of the arguments are null
*/
@NotNull
public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data);
@NotNull
public static ClassDefiner getInstance() {
return SafeClassDefiner.INSTANCE;
}
}

View File

@@ -1,66 +0,0 @@
package com.destroystokyo.paper.event.executor.asm;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.google.common.base.Preconditions;
import com.google.common.collect.MapMaker;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.Type;
public class SafeClassDefiner implements ClassDefiner {
/* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner();
private SafeClassDefiner() {}
private final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new MapMaker().weakKeys().makeMap();
@NotNull
@Override
public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data) {
GeneratedClassLoader loader = loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
synchronized (loader.getClassLoadingLock(name)) {
Preconditions.checkState(!loader.hasClass(name), "%s already defined", name);
Class<?> c = loader.define(name, data);
assert c.getName().equals(name);
return c;
}
}
private static class GeneratedClassLoader extends ClassLoader {
static {
ClassLoader.registerAsParallelCapable();
}
protected GeneratedClassLoader(@NotNull ClassLoader parent) {
super(parent);
}
private Class<?> define(@NotNull String name, byte[] data) {
synchronized (getClassLoadingLock(name)) {
assert !hasClass(name);
Class<?> c = defineClass(name, data, 0, data.length);
resolveClass(c);
return c;
}
}
@Override
@NotNull
public Object getClassLoadingLock(@NotNull String name) {
return super.getClassLoadingLock(name);
}
public boolean hasClass(@NotNull String name) {
synchronized (getClassLoadingLock(name)) {
try {
Class.forName(name);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
}
}

View File

@@ -1,70 +0,0 @@
package com.destroystokyo.paper.event.player;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class IllegalPacketEvent extends PlayerEvent {
@Nullable private final String type;
@Nullable private final String ex;
@Nullable private String kickMessage;
private boolean shouldKick = true;
public IllegalPacketEvent(@NotNull Player player, @Nullable String type, @Nullable String kickMessage, @NotNull Exception e) {
super(player);
this.type = type;
this.kickMessage = kickMessage;
this.ex = e.getMessage();
}
public boolean isShouldKick() {
return shouldKick;
}
public void setShouldKick(boolean shouldKick) {
this.shouldKick = shouldKick;
}
@Nullable
public String getKickMessage() {
return kickMessage;
}
public void setKickMessage(@Nullable String kickMessage) {
this.kickMessage = kickMessage;
}
@Nullable
public String getType() {
return type;
}
@Nullable
public String getExceptionMessage() {
return ex;
}
private static final HandlerList handlers = new HandlerList();
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
public static void process(@NotNull Player player, @Nullable String type, @Nullable String kickMessage, @NotNull Exception exception) {
IllegalPacketEvent event = new IllegalPacketEvent(player, type, kickMessage, exception);
event.callEvent();
if (event.shouldKick) {
player.kickPlayer(kickMessage);
}
Bukkit.getLogger().severe(player.getName() + "/" + type + ": " + exception.getMessage());
}
}

View File

@@ -1,63 +0,0 @@
package com.destroystokyo.paper.event.player;
import org.bukkit.advancement.Advancement;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player is granted a criteria in an advancement.
*/
public class PlayerAdvancementCriterionGrantEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
@NotNull private final Advancement advancement;
@NotNull private final String criterion;
private boolean cancel = false;
public PlayerAdvancementCriterionGrantEvent(@NotNull Player who, @NotNull Advancement advancement, @NotNull String criterion) {
super(who);
this.advancement = advancement;
this.criterion = criterion;
}
/**
* Get the advancement which has been affected.
*
* @return affected advancement
*/
@NotNull
public Advancement getAdvancement() {
return advancement;
}
/**
* Get the criterion which has been granted.
*
* @return granted criterion
*/
@NotNull
public String getCriterion() {
return criterion;
}
public boolean isCancelled() {
return cancel;
}
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,137 +0,0 @@
package com.destroystokyo.paper.event.player;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.bukkit.Material.*;
/**
* Called when the player themselves change their armor items
* <p>
* Not currently called for environmental factors though it <strong>MAY BE IN THE FUTURE</strong>
*/
public class PlayerArmorChangeEvent extends PlayerEvent {
private static final HandlerList HANDLERS = new HandlerList();
@NotNull private final SlotType slotType;
@Nullable private final ItemStack oldItem;
@Nullable private final ItemStack newItem;
public PlayerArmorChangeEvent(@NotNull Player player, @NotNull SlotType slotType, @Nullable ItemStack oldItem, @Nullable ItemStack newItem) {
super(player);
this.slotType = slotType;
this.oldItem = oldItem;
this.newItem = newItem;
}
/**
* Gets the type of slot being altered.
*
* @return type of slot being altered
*/
@NotNull
public SlotType getSlotType() {
return this.slotType;
}
/**
* Gets the existing item that's being replaced
*
* @return old item
*/
@Nullable
public ItemStack getOldItem() {
return this.oldItem;
}
/**
* Gets the new item that's replacing the old
*
* @return new item
*/
@Nullable
public ItemStack getNewItem() {
return this.newItem;
}
@Override
public String toString() {
return "ArmorChangeEvent{" + "player=" + player + ", slotType=" + slotType + ", oldItem=" + oldItem + ", newItem=" + newItem + '}';
}
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLERS;
}
public enum SlotType {
HEAD(DIAMOND_HELMET, GOLDEN_HELMET, IRON_HELMET, CHAINMAIL_HELMET, LEATHER_HELMET, PUMPKIN, JACK_O_LANTERN),
CHEST(DIAMOND_CHESTPLATE, GOLDEN_CHESTPLATE, IRON_CHESTPLATE, CHAINMAIL_CHESTPLATE, LEATHER_CHESTPLATE, ELYTRA),
LEGS(DIAMOND_LEGGINGS, GOLDEN_LEGGINGS, IRON_LEGGINGS, CHAINMAIL_LEGGINGS, LEATHER_LEGGINGS),
FEET(DIAMOND_BOOTS, GOLDEN_BOOTS, IRON_BOOTS, CHAINMAIL_BOOTS, LEATHER_BOOTS);
private final Set<Material> mutableTypes = new HashSet<>();
private Set<Material> immutableTypes;
SlotType(Material... types) {
this.mutableTypes.addAll(Arrays.asList(types));
}
/**
* Gets an immutable set of all allowed material types that can be placed in an
* armor slot.
*
* @return immutable set of material types
*/
@NotNull
public Set<Material> getTypes() {
if (immutableTypes == null) {
immutableTypes = Collections.unmodifiableSet(mutableTypes);
}
return immutableTypes;
}
/**
* Gets the type of slot via the specified material
*
* @param material material to get slot by
* @return slot type the material will go in, or null if it won't
*/
@Nullable
public static SlotType getByMaterial(@NotNull Material material) {
for (SlotType slotType : values()) {
if (slotType.getTypes().contains(material)) {
return slotType;
}
}
return null;
}
/**
* Gets whether or not this material can be equipped to a slot
*
* @param material material to check
* @return whether or not this material can be equipped
*/
public static boolean isEquipable(@NotNull Material material) {
return getByMaterial(material) != null;
}
}
}

View File

@@ -1,95 +0,0 @@
package com.destroystokyo.paper.event.player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.net.InetAddress;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
/**
* <p>
* This event is invoked when a player has disconnected. It is guaranteed that,
* if the server is in online-mode, that the provided uuid and username have been
* validated.
* </p>
*
* <p>
* The event is invoked for players who have not yet logged into the world, whereas
* {@link org.bukkit.event.player.PlayerQuitEvent} is only invoked on players who have logged into the world.
* </p>
*
* <p>
* The event is invoked for players who have already logged into the world,
* although whether or not the player exists in the world at the time of
* firing is undefined. (That is, whether the plugin can retrieve a Player object
* using the event parameters is undefined). However, it is guaranteed that this
* event is invoked AFTER {@link org.bukkit.event.player.PlayerQuitEvent}, if the player has already logged into the world.
* </p>
*
* <p>
* This event is guaranteed to never fire unless {@link org.bukkit.event.player.AsyncPlayerPreLoginEvent} has
* been fired beforehand, and this event may not be called in parallel with
* {@link org.bukkit.event.player.AsyncPlayerPreLoginEvent} for the same connection.
* </p>
*
* <p>
* Cancelling the {@link org.bukkit.event.player.AsyncPlayerPreLoginEvent} guarantees the corresponding
* {@code PlayerConnectionCloseEvent} is never called.
* </p>
*
* <p>
* The event may be invoked asynchronously or synchronously. Plugins should check
* {@link Event#isAsynchronous()} and handle accordingly.
* </p>
*/
public class PlayerConnectionCloseEvent extends Event {
private static final HandlerList HANDLERS = new HandlerList();
@NotNull private final UUID playerUniqueId;
@NotNull private final String playerName;
@NotNull private final InetAddress ipAddress;
public PlayerConnectionCloseEvent(@NotNull final UUID playerUniqueId, @NotNull final String playerName, @NotNull final InetAddress ipAddress, final boolean async) {
super(async);
this.playerUniqueId = playerUniqueId;
this.playerName = playerName;
this.ipAddress = ipAddress;
}
/**
* Returns the {@code UUID} of the player disconnecting.
*/
@NotNull
public UUID getPlayerUniqueId() {
return this.playerUniqueId;
}
/**
* Returns the name of the player disconnecting.
*/
@NotNull
public String getPlayerName() {
return this.playerName;
}
/**
* Returns the player's IP address.
*/
@NotNull
public InetAddress getIpAddress() {
return this.ipAddress;
}
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLERS;
}
}

View File

@@ -1,85 +0,0 @@
package com.destroystokyo.paper.event.player;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Fired when a player boosts elytra flight with a firework
*/
public class PlayerElytraBoostEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
@NotNull private final ItemStack itemStack;
@NotNull private Firework firework;
private boolean consume = true;
public PlayerElytraBoostEvent(@NotNull Player player, @NotNull ItemStack itemStack, @NotNull Firework firework) {
super(player);
this.itemStack = itemStack;
this.firework = firework;
}
/**
* Get the firework itemstack used
*
* @return ItemStack of firework
*/
@NotNull
public ItemStack getItemStack() {
return itemStack;
}
/**
* Get the firework entity that was spawned
*
* @return Firework entity
*/
@NotNull
public Firework getFirework() {
return firework;
}
/**
* Get whether to consume the firework or not
*
* @return True to consume
*/
public boolean shouldConsume() {
return consume;
}
/**
* Set whether to consume the firework or not
*
* @param consume True to consume
*/
public void setShouldConsume(boolean consume) {
this.consume = consume;
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@@ -1,222 +0,0 @@
package com.destroystokyo.paper.event.player;
import org.apache.commons.lang.Validate;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* This event is fired during a player handshake.
*
* <p>If there are no listeners listening to this event, the logic default
* to your server platform will be ran.</p>
*
* <p>WARNING: TAMPERING WITH THIS EVENT CAN BE DANGEROUS</p>
*/
public class PlayerHandshakeEvent extends Event implements Cancellable {
private static final HandlerList HANDLERS = new HandlerList();
@NotNull private final String originalHandshake;
private boolean cancelled;
@Nullable private String serverHostname;
@Nullable private String socketAddressHostname;
@Nullable private UUID uniqueId;
@Nullable private String propertiesJson;
private boolean failed;
private String failMessage = "If you wish to use IP forwarding, please enable it in your BungeeCord config as well!";
/**
* Creates a new {@link PlayerHandshakeEvent}.
*
* @param originalHandshake the original handshake string
* @param cancelled if this event is enabled
*/
public PlayerHandshakeEvent(@NotNull String originalHandshake, boolean cancelled) {
super(true);
this.originalHandshake = originalHandshake;
this.cancelled = cancelled;
}
/**
* Determines if this event is cancelled.
*
* <p>When this event is cancelled, custom handshake logic will not
* be processed.</p>
*
* @return {@code true} if this event is cancelled, {@code false} otherwise
*/
@Override
public boolean isCancelled() {
return this.cancelled;
}
/**
* Sets if this event is cancelled.
*
* <p>When this event is cancelled, custom handshake logic will not
* be processed.</p>
*
* @param cancelled {@code true} if this event is cancelled, {@code false} otherwise
*/
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
/**
* Gets the original handshake string.
*
* @return the original handshake string
*/
@NotNull
public String getOriginalHandshake() {
return this.originalHandshake;
}
/**
* Gets the server hostname string.
*
* <p>This should not include the port.</p>
*
* @return the server hostname string
*/
@Nullable
public String getServerHostname() {
return this.serverHostname;
}
/**
* Sets the server hostname string.
*
* <p>This should not include the port.</p>
*
* @param serverHostname the server hostname string
*/
public void setServerHostname(@NotNull String serverHostname) {
this.serverHostname = serverHostname;
}
/**
* Gets the socket address hostname string.
*
* <p>This should not include the port.</p>
*
* @return the socket address hostname string
*/
@Nullable
public String getSocketAddressHostname() {
return this.socketAddressHostname;
}
/**
* Sets the socket address hostname string.
*
* <p>This should not include the port.</p>
*
* @param socketAddressHostname the socket address hostname string
*/
public void setSocketAddressHostname(@NotNull String socketAddressHostname) {
this.socketAddressHostname = socketAddressHostname;
}
/**
* Gets the unique id.
*
* @return the unique id
*/
@Nullable
public UUID getUniqueId() {
return this.uniqueId;
}
/**
* Sets the unique id.
*
* @param uniqueId the unique id
*/
public void setUniqueId(@NotNull UUID uniqueId) {
this.uniqueId = uniqueId;
}
/**
* Gets the profile properties.
*
* <p>This should be a valid JSON string.</p>
*
* @return the profile properties, as JSON
*/
@Nullable
public String getPropertiesJson() {
return this.propertiesJson;
}
/**
* Determines if authentication failed.
*
* <p>When {@code true}, the client connecting will be disconnected
* with the {@link #getFailMessage() fail message}.</p>
*
* @return {@code true} if authentication failed, {@code false} otherwise
*/
public boolean isFailed() {
return this.failed;
}
/**
* Sets if authentication failed and the client should be disconnected.
*
* <p>When {@code true}, the client connecting will be disconnected
* with the {@link #getFailMessage() fail message}.</p>
*
* @param failed {@code true} if authentication failed, {@code false} otherwise
*/
public void setFailed(boolean failed) {
this.failed = failed;
}
/**
* Sets the profile properties.
*
* <p>This should be a valid JSON string.</p>
*
* @param propertiesJson the profile properties, as JSON
*/
public void setPropertiesJson(@NotNull String propertiesJson) {
this.propertiesJson = propertiesJson;
}
/**
* Gets the message to display to the client when authentication fails.
*
* @return the message to display to the client
*/
@NotNull
public String getFailMessage() {
return this.failMessage;
}
/**
* Sets the message to display to the client when authentication fails.
*
* @param failMessage the message to display to the client
*/
public void setFailMessage(@NotNull String failMessage) {
Validate.notEmpty(failMessage, "fail message cannot be null or empty");
this.failMessage = failMessage;
}
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLERS;
}
}

View File

@@ -1,47 +0,0 @@
package com.destroystokyo.paper.event.player;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerInitialSpawnEvent extends PlayerEvent {
private static final HandlerList handlers = new HandlerList();
@NotNull private Location spawnLocation;
public PlayerInitialSpawnEvent(@NotNull final Player player, @NotNull final Location spawnLocation) {
super(player);
this.spawnLocation = spawnLocation;
}
/**
* Gets the current spawn location
*
* @return Location current spawn location
*/
@NotNull
public Location getSpawnLocation() {
return this.spawnLocation;
}
/**
* Sets the new spawn location
*
* @param spawnLocation new location for the spawn
*/
public void setSpawnLocation(@NotNull Location spawnLocation) {
this.spawnLocation = spawnLocation;
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,106 +0,0 @@
package com.destroystokyo.paper.event.player;
import com.google.common.base.Preconditions;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when the server detects the player is jumping.
* <p>
* Added to avoid the overhead and special case logic that many plugins use
* when checking for jumps via PlayerMoveEvent, this event is fired whenever
* the server detects that the player is jumping.
*/
public class PlayerJumpEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
@NotNull private Location from;
@NotNull private Location to;
public PlayerJumpEvent(@NotNull final Player player, @NotNull final Location from, @NotNull final Location to) {
super(player);
this.from = from;
this.to = to;
}
/**
* Gets the cancellation state of this event. A cancelled event will not
* be executed in the server, but will still pass to other plugins
* <p>
* If a jump event is cancelled, the player will be moved or
* teleported back to the Location as defined by getFrom(). This will not
* fire an event
*
* @return true if this event is cancelled
*/
public boolean isCancelled() {
return cancel;
}
/**
* Sets the cancellation state of this event. A cancelled event will not
* be executed in the server, but will still pass to other plugins
* <p>
* If a jump event is cancelled, the player will be moved or
* teleported back to the Location as defined by getFrom(). This will not
* fire an event
*
* @param cancel true if you wish to cancel this event
*/
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
/**
* Gets the location this player jumped from
*
* @return Location the player jumped from
*/
@NotNull
public Location getFrom() {
return from;
}
/**
* Sets the location to mark as where the player jumped from
*
* @param from New location to mark as the players previous location
*/
public void setFrom(@NotNull Location from) {
validateLocation(from);
this.from = from;
}
/**
* Gets the location this player jumped to
*
* This information is based on what the client sends, it typically
* has little relation to the arc of the jump at any given point.
*
* @return Location the player jumped to
*/
@NotNull
public Location getTo() {
return to;
}
private void validateLocation(Location loc) {
Preconditions.checkArgument(loc != null, "Cannot use null location!");
Preconditions.checkArgument(loc.getWorld() != null, "Cannot use location with null world!");
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

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