Compare commits
339 Commits
1.12.2-R0.
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a0951bd4c | ||
|
|
7dcfc130d2 | ||
|
|
0e9940771e | ||
|
|
ee8e09fe58 | ||
|
|
b74ec9aa2e | ||
|
|
ea8292aaf9 | ||
|
|
7b47710c42 | ||
|
|
d34531aa84 | ||
|
|
30bb7a43fb | ||
|
|
9a54ba116e | ||
|
|
a3cc630375 | ||
|
|
e5081d4575 | ||
|
|
852acc0d65 | ||
|
|
7e756e786d | ||
|
|
62848df6de | ||
|
|
f5a531a15c | ||
|
|
ba3d1c9672 | ||
|
|
fa08306751 | ||
|
|
9a8d4c35a9 | ||
|
|
adf961666a | ||
|
|
947b22892c | ||
|
|
0d9f04a748 | ||
|
|
26652d43fc | ||
|
|
ac24d10a57 | ||
|
|
f220a6a153 | ||
|
|
233aab099e | ||
|
|
5268e9a55a | ||
|
|
83c30311d0 | ||
|
|
6a7f2b8699 | ||
|
|
cb55572504 | ||
|
|
9d5c535d18 | ||
|
|
b46cddd84d | ||
|
|
936cf720f4 | ||
|
|
9b6412766f | ||
|
|
d847e87c65 | ||
|
|
ff8c0cd3be | ||
|
|
19991463bf | ||
|
|
c2931e362e | ||
|
|
e912498dac | ||
|
|
98a7b4d757 | ||
|
|
62aa216b48 | ||
|
|
1a56f7ac75 | ||
|
|
0080380486 | ||
|
|
e7419af0de | ||
|
|
371817ab85 | ||
|
|
9ad318d4bb | ||
|
|
e066c5e12c | ||
|
|
cfa99ef96e | ||
|
|
03bcac33d7 | ||
|
|
fcbda069fc | ||
|
|
27561af9d8 | ||
|
|
ecb47cc23f | ||
|
|
2fd9d75ba7 | ||
|
|
69c5da47a0 | ||
|
|
c46b459f08 | ||
|
|
a540b150aa | ||
|
|
16eb219b60 | ||
|
|
3dac5cebbf | ||
|
|
78a3fb3aad | ||
|
|
df97aca45f | ||
|
|
a0daa4f40e | ||
|
|
ebf0968fd3 | ||
|
|
a0d41a8dea | ||
|
|
8101d7b1a7 | ||
|
|
9a0558d218 | ||
|
|
6d023d0ff5 | ||
|
|
26d65b8875 | ||
|
|
b65309abd3 | ||
|
|
e07860fb92 | ||
|
|
9491da6b8f | ||
|
|
4d57eb6172 | ||
|
|
2920fa4993 | ||
|
|
48574c2eb4 | ||
|
|
233199054e | ||
|
|
fe6068d6de | ||
|
|
a9a9b933f5 | ||
|
|
d082c42898 | ||
|
|
d784d03289 | ||
|
|
3702d83f80 | ||
|
|
ebd4a75b88 | ||
|
|
d45dde48f1 | ||
|
|
55878409ac | ||
|
|
5f0eca806a | ||
|
|
5e656d02eb | ||
|
|
e407443ca9 | ||
|
|
345faccac7 | ||
|
|
0dcd33f41b | ||
|
|
10a0c82475 | ||
|
|
2871e0dc81 | ||
|
|
15ab29a426 | ||
|
|
93cac1aeea | ||
|
|
55bbbdfbf2 | ||
|
|
01555f49a0 | ||
|
|
4c40903958 | ||
|
|
74d0113b46 | ||
|
|
1db625034e | ||
|
|
6fbd890884 | ||
|
|
3411916593 | ||
|
|
9e2b072bc6 | ||
|
|
cf03617415 | ||
|
|
d2c3477e59 | ||
|
|
6c9c9bef6e | ||
|
|
4a48e19dcc | ||
|
|
0e44c002df | ||
|
|
cbe1830f1c | ||
|
|
c7e7d1a40b | ||
|
|
daf6af0269 | ||
|
|
b510185638 | ||
|
|
0eaeb3b28c | ||
|
|
a2fad07eb6 | ||
|
|
f07072102b | ||
|
|
94264a57a3 | ||
|
|
83f71f673b | ||
|
|
3794ab48c1 | ||
|
|
643f313789 | ||
|
|
573d187e38 | ||
|
|
2e9075e2d7 | ||
|
|
db9cf4e5a2 | ||
|
|
08c6269f3e | ||
|
|
d25176aff1 | ||
|
|
f5fc1e6b64 | ||
|
|
000ea6409b | ||
|
|
925e91c99e | ||
|
|
b1b3efae8d | ||
|
|
a00d3645e1 | ||
|
|
95d3bc3529 | ||
|
|
677914bd39 | ||
|
|
e82e06c760 | ||
|
|
e40656e7f2 | ||
|
|
676173300f | ||
|
|
2d45820922 | ||
|
|
bdbec60f02 | ||
|
|
433e18e7d2 | ||
|
|
21d24bdfa5 | ||
|
|
4eec855840 | ||
|
|
dbe68a55d4 | ||
|
|
08d22009b7 | ||
|
|
0f32cb2ee9 | ||
|
|
fc47e66e4c | ||
|
|
8778323b0c | ||
|
|
8751adbf1b | ||
|
|
742fe4e0a3 | ||
|
|
3d75fe1118 | ||
|
|
a1c3051508 | ||
|
|
da57bfbf57 | ||
|
|
54e05c84f6 | ||
|
|
9fd22502b2 | ||
|
|
5551f505a1 | ||
|
|
8f421ffb2a | ||
|
|
7fe2637206 | ||
|
|
362c9561dd | ||
|
|
fa1cf770f4 | ||
|
|
4758e8aeef | ||
|
|
998b18d2d8 | ||
|
|
b5b7684c58 | ||
|
|
48604bc9a6 | ||
|
|
2f4b0a7a88 | ||
|
|
16a91e1e31 | ||
|
|
d64d8eb5f8 | ||
|
|
e10f2ae716 | ||
|
|
e62e662196 | ||
|
|
6c425fa820 | ||
|
|
29385180ab | ||
|
|
295d11b87a | ||
|
|
fda0839d62 | ||
|
|
6002e2e6d2 | ||
|
|
b23baff1d8 | ||
|
|
05ea8eda44 | ||
|
|
84de7a43fc | ||
|
|
3a53619460 | ||
|
|
fd6f9ef9f3 | ||
|
|
bcea435a88 | ||
|
|
8d669910f6 | ||
|
|
5f3843eb14 | ||
|
|
c407e63047 | ||
|
|
c60d1f672e | ||
|
|
ff6b2d60ab | ||
|
|
1cde35cfc1 | ||
|
|
49cfe2d8e6 | ||
|
|
19f2be2d7d | ||
|
|
8ce60a6575 | ||
|
|
1fffe53720 | ||
|
|
c33f5cea3b | ||
|
|
bc27b6b11d | ||
|
|
ea9589df5c | ||
|
|
53e8b9cf2a | ||
|
|
1d0b02d8d3 | ||
|
|
7436817e08 | ||
|
|
7b6f58c979 | ||
|
|
7f12dd9c28 | ||
|
|
973d4d56c2 | ||
|
|
db31b8edde | ||
|
|
2aabcc3bb1 | ||
|
|
9e83056973 | ||
|
|
7d268c178c | ||
|
|
4ed193b1dd | ||
|
|
1445ea5401 | ||
|
|
950662e652 | ||
|
|
9686940a08 | ||
|
|
46c2fd8790 | ||
|
|
53b7a9095c | ||
|
|
1803ed497f | ||
|
|
9931749781 | ||
|
|
5721388795 | ||
|
|
7e195b8bd9 | ||
|
|
3929f61633 | ||
|
|
d9b608826a | ||
|
|
30f216b3c5 | ||
|
|
663953230d | ||
|
|
18868c715c | ||
|
|
26e0546b50 | ||
|
|
1708888915 | ||
|
|
a4c72a2762 | ||
|
|
a096eeadb1 | ||
|
|
47fc205ba4 | ||
|
|
8a9d3acc05 | ||
|
|
c4db74f13a | ||
|
|
044759f197 | ||
|
|
c120dafe85 | ||
|
|
3cf50c844d | ||
|
|
fbeb9840ea | ||
|
|
82106ee8b6 | ||
|
|
a74aa135ae | ||
|
|
0201722e69 | ||
|
|
cbf71003ff | ||
|
|
90f6d0e9ba | ||
|
|
4290216041 | ||
|
|
33b5d7fb22 | ||
|
|
ac1d99be3b | ||
|
|
d282f46a5b | ||
|
|
a1dee4e1b6 | ||
|
|
e8e6eb230d | ||
|
|
5fd8d633cb | ||
|
|
473190dc17 | ||
|
|
ce64d00b3a | ||
|
|
810c8a5d00 | ||
|
|
768ac2f14c | ||
|
|
183c5fc53d | ||
|
|
5e51b97d27 | ||
|
|
dbd6e66ab9 | ||
|
|
8cb2bc2356 | ||
|
|
48ff1679fe | ||
|
|
8f77cd21b5 | ||
|
|
a825d60641 | ||
|
|
64f74e19a0 | ||
|
|
a741a4336c | ||
|
|
6946210cf9 | ||
|
|
e412d13ccc | ||
|
|
a74603ce85 | ||
|
|
b9a14c436f | ||
|
|
3ff1a9d072 | ||
|
|
0174722008 | ||
|
|
7475c7fb8f | ||
|
|
41da0735ba | ||
|
|
843e612652 | ||
|
|
739614b286 | ||
|
|
04502d021b | ||
|
|
2bc7a3b190 | ||
|
|
1cbd868bdf | ||
|
|
c54d83cedc | ||
|
|
d9040bf6f3 | ||
|
|
a877b1903f | ||
|
|
a768ef41c6 | ||
|
|
22d100f9f4 | ||
|
|
1e57476b41 | ||
|
|
d5e59449fd | ||
|
|
3b20dbd3f8 | ||
|
|
ec977b85e9 | ||
|
|
c22d51f944 | ||
|
|
c05abe18b1 | ||
|
|
da6685793d | ||
|
|
55b7a1bfed | ||
|
|
0f9e51fd0b | ||
|
|
bfca47a782 | ||
|
|
f2563e1f76 | ||
|
|
a5d9181450 | ||
|
|
f1b3273cba | ||
|
|
1028ea8ff8 | ||
|
|
3d562bec84 | ||
|
|
610ec6d52e | ||
|
|
27a7b2a823 | ||
|
|
cb3fe4a4c2 | ||
|
|
b894a5256a | ||
|
|
b99ec14a99 | ||
|
|
4f2510bb51 | ||
|
|
24360a8085 | ||
|
|
367f5e2e87 | ||
|
|
91e0140620 | ||
|
|
24b26ab846 | ||
|
|
c0df425445 | ||
|
|
389c787eb9 | ||
|
|
685b07f51d | ||
|
|
43adb03349 | ||
|
|
d742c096c6 | ||
|
|
8071a603ba | ||
|
|
889b6ea5ba | ||
|
|
2df37be2e2 | ||
|
|
36543cabf5 | ||
|
|
2173b1e2bc | ||
|
|
6e9351caaf | ||
|
|
eb28c5ae38 | ||
|
|
ae6de9567f | ||
|
|
a6c252130f | ||
|
|
5b2147cef5 | ||
|
|
a4836cf014 | ||
|
|
a924263f2f | ||
|
|
eb4ac897c7 | ||
|
|
090ab24a6b | ||
|
|
445f6f185d | ||
|
|
3c198efd87 | ||
|
|
8fa3e82671 | ||
|
|
7381ae8793 | ||
|
|
ac5291d8e4 | ||
|
|
57b84f327b | ||
|
|
4529c0237a | ||
|
|
0dfabac80f | ||
|
|
7c4a81bcb6 | ||
|
|
263cf75f49 | ||
|
|
005b2d2097 | ||
|
|
13b5b7cc13 | ||
|
|
1bc90004ca | ||
|
|
8a41fa0401 | ||
|
|
043b87f4ef | ||
|
|
6da2ca1f67 | ||
|
|
f0044d7d07 | ||
|
|
ea18e73509 | ||
|
|
f24d488601 | ||
|
|
a3501fb8dd | ||
|
|
70b75489f2 | ||
|
|
abe730886a | ||
|
|
645293ed0e | ||
|
|
00859a2e18 | ||
|
|
d643cae29f | ||
|
|
9aa63c56ab | ||
|
|
b06e5f3e13 | ||
|
|
f2a81f8a1e | ||
|
|
7487ac4edf | ||
|
|
07a8521999 | ||
|
|
1879eebd8f |
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "work/Paper"]
|
||||
path = work/Paper
|
||||
url = https://github.com/Akarin-project/Paper.git
|
||||
url = https://github.com/Akarin-project/Paper.git
|
||||
|
||||
24
Jenkinsfile
vendored
Normal file
24
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Init Submodules') {
|
||||
steps {
|
||||
sh 'git submodule update --init --recursive'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'chmod +x scripts/inst.sh'
|
||||
sh './scripts/inst.sh --setup --fast --remote'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Archive') {
|
||||
steps {
|
||||
archiveArtifacts(artifacts: '*.jar', fingerprint: true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
14
README.md
14
README.md
@@ -1,31 +1,29 @@
|
||||
# <img src="https://i.loli.net/2018/05/17/5afd869c443ef.png" alt="Akarin Face" align="right">Akarin
|
||||
[](https://akarin.io)
|
||||
[](https://discord.gg/fw2pJAj)
|
||||
[](https://bstats.org/plugin/bukkit/Torch)
|
||||
[](https://circleci.com/gh/Akarin-project/Akarin/tree/ver/1.12.2)
|
||||
[](https://bstats.org/plugin/bukkit/Torch)
|
||||
|
||||
Akarin is currently **under heavy development** and contributions are welcome!
|
||||
|
||||
Introduction
|
||||
---
|
||||
> Akarin is a powerful server software from the 'new dimension', formerly known as Torch.
|
||||
> Akarin is a powerful server software from the 'new dimension', formerly known as Torch.
|
||||
|
||||
As a [Paper](https://github.com/PaperMC/Paper) fork, it should support almost all plugins that work on [Spigot](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse).
|
||||
|
||||
Our project has a few key goals:
|
||||
|
||||
* **Open Access** - Make more game mechanics configurable.
|
||||
* **Open Access** - Make more game mechanics configurable.
|
||||
* **Bedrock** - Make the server more safe and stable.
|
||||
* **Fast** - Simplify the logic and implement multi-threaded computing.
|
||||
|
||||
*Issues and Pull Requests will be labeled accordingly*
|
||||
|
||||
Get Akarin
|
||||
---
|
||||
---
|
||||
### Download
|
||||
#### Recommended
|
||||
+ ~~[**Jenkins**](http://ci.ilummc.com/job/Akarin/)~~ - Kudos to [Izzel_Aliz](https://github.com/IzzelAliz)
|
||||
+ [**Circle CI**](https://circleci.com/gh/Akarin-project/Akarin/tree/ver/1.12.2) - Checkout the 'Artifacts' tab of the latest build
|
||||
+ [**Jenkins**](http://ci.josephworks.net/job/Akarin/job/ver%252F1.12.2/) - Kudos to [JosephWorks](https://github.com/josephworks)
|
||||
|
||||
*Open an [Issue](https://github.com/Akarin-project/Akarin/issues) or a [Pull Request](https://github.com/Akarin-project/Akarin/pulls) if you want to add your website here*
|
||||
|
||||
@@ -40,7 +38,7 @@ Get Akarin
|
||||
```
|
||||
|
||||
**Notes**
|
||||
* You must use `--setup` at least once to deploy necessary dependencies otherwise some imports cannot be organized.
|
||||
* You must use `--setup` at least once to deploy necessary dependencies otherwise some imports cannot be organized.
|
||||
* For non-modified projects, it is recommended to add the `--fast` option to skip any tests.
|
||||
* If your machine has insufficient memory, you may want to add the `--remote` option to avoid decompiling locally.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ if [ "$2" == "--setup" ] || [ "$3" == "--setup" ] || [ "$4" == "--setup" ]; then
|
||||
if [ -d "Minecraft" ]; then
|
||||
rm Minecraft/ -r
|
||||
fi
|
||||
git clone https://github.com/Akarin-project/Minecraft.git
|
||||
git clone https://github.com/LegacyGamerHD/Minecraft.git
|
||||
fi
|
||||
|
||||
cd "$paperbasedir"
|
||||
@@ -51,4 +51,4 @@ echo "[Akarin] Ready to build"
|
||||
echo "[Akarin] Migrated final jar to $basedir/akarin-$minecraftversion.jar"
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
set -e
|
||||
basedir="$pwd"
|
||||
|
||||
(git submodule update --init --remote && chmod +x scripts/build.sh && ./scripts/build.sh "$basedir" "$1" "$2" "$3") || (
|
||||
(chmod +x scripts/build.sh && ./scripts/build.sh "$basedir" "$1" "$2" "$3") || (
|
||||
echo "Failed to build Akarin"
|
||||
exit 1
|
||||
) || exit 1
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
106
sources/pom.xml
106
sources/pom.xml
@@ -30,7 +30,7 @@
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.24.Final</version>
|
||||
<version>4.1.78.Final</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -45,6 +45,12 @@
|
||||
<version>${minecraft.version}-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>minecraft-server</artifactId>
|
||||
<version>${minecraft.version}-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.jopt-simple</groupId>
|
||||
<artifactId>jopt-simple</artifactId>
|
||||
@@ -60,7 +66,7 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.45</version>
|
||||
<version>8.0.28</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -69,7 +75,6 @@
|
||||
<version>3.0.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.minecrell</groupId>
|
||||
<artifactId>terminalconsoleappender</artifactId>
|
||||
@@ -91,7 +96,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<version>2.17.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -99,20 +104,20 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<version>2.17.2</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-iostreams</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<version>2.17.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Paper - Async loggers -->
|
||||
<dependency>
|
||||
<groupId>com.lmax</groupId>
|
||||
<artifactId>disruptor</artifactId>
|
||||
<version>3.4.2</version>
|
||||
<version>3.4.4</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -129,7 +134,7 @@
|
||||
<version>1.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Akarin -->
|
||||
<dependency>
|
||||
<groupId>io.akarin</groupId>
|
||||
@@ -149,18 +154,14 @@
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.6.3-SNAPSHOT</version>
|
||||
<version>2.9.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>akarin-repo</id>
|
||||
<url>https://raw.githubusercontent.com/Akarin-project/akarin-repo/master/repository</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigotmc-public</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
<id>elmakers-repo</id>
|
||||
<url>http://maven.elmakers.com/repository/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spongepowered-repo</id>
|
||||
@@ -170,12 +171,36 @@
|
||||
<id>nallar-repo</id>
|
||||
<url>http://repo.nallar.me/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>josephworks</id>
|
||||
<url>http://repo.josephworks.net/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sonatype-nexusg</id>
|
||||
<url>https://oss.sonatype.org/content/repositories</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spigotmc-public</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
<id>paper</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
@@ -216,6 +241,7 @@
|
||||
<Specification-Title>Bukkit</Specification-Title>
|
||||
<Specification-Version>${api.version}</Specification-Version>
|
||||
<Specification-Vendor>Bukkit Team</Specification-Vendor>
|
||||
<Multi-Release>true</Multi-Release> <!-- Paper start - update log4j -->
|
||||
</manifestEntries>
|
||||
<manifestSections>
|
||||
<manifestSection>
|
||||
@@ -243,7 +269,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
@@ -252,6 +278,25 @@
|
||||
</goals>
|
||||
<configuration>
|
||||
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation> <!-- Paper -->
|
||||
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>org.spigotmc:minecraft-server:**</artifact>
|
||||
<excludes>
|
||||
<exclude>io/netty/**</exclude>
|
||||
<exclude>org/apache/logging/log4j/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
|
||||
<relocations>
|
||||
<!-- Paper - Workaround for hardcoded path lookup in dependency, easier than forking it - GH-189 -->
|
||||
<!--<relocation>-->
|
||||
@@ -283,27 +328,16 @@
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/services/java.sql.Driver</resource>
|
||||
</transformer>
|
||||
<transformer implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer" />
|
||||
<transformer implementation="io.github.edwgiz.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformer" />
|
||||
</transformers>
|
||||
<!-- Akarin - Avoid signature failure -->
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.edwgiz</groupId>
|
||||
<artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<groupId>io.github.edwgiz</groupId>
|
||||
<artifactId>log4j-maven-shade-plugin-extensions</artifactId>
|
||||
<version>2.17.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
@@ -311,6 +345,12 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>org/spigotmc/CaseInsensitiveHashingStrategy.java</exclude>
|
||||
<exclude>org/spigotmc/CaseInsensitiveMap.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
128
sources/src/main/java/co/aikar/timings/MinecraftTimings.java
Normal file
128
sources/src/main/java/co/aikar/timings/MinecraftTimings.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package co.aikar.timings;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import net.minecraft.server.*;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import org.bukkit.craftbukkit.scheduler.CraftTask;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public final class MinecraftTimings {
|
||||
|
||||
public static final Timing playerListTimer = Timings.ofSafe("Player List");
|
||||
public static final Timing commandFunctionsTimer = Timings.ofSafe("Command Functions");
|
||||
public static final Timing connectionTimer = Timings.ofSafe("Connection Handler");
|
||||
public static final Timing tickablesTimer = Timings.ofSafe("Tickables");
|
||||
public static final Timing minecraftSchedulerTimer = Timings.ofSafe("Minecraft Scheduler");
|
||||
public static final Timing bukkitSchedulerTimer = Timings.ofSafe("Bukkit Scheduler");
|
||||
public static final Timing bukkitSchedulerPendingTimer = Timings.ofSafe("Bukkit Scheduler - Pending");
|
||||
public static final Timing bukkitSchedulerFinishTimer = Timings.ofSafe("Bukkit Scheduler - Finishing");
|
||||
public static final Timing chunkIOTickTimer = Timings.ofSafe("ChunkIOTick");
|
||||
public static final Timing timeUpdateTimer = Timings.ofSafe("Time Update");
|
||||
public static final Timing serverCommandTimer = Timings.ofSafe("Server Command");
|
||||
public static final Timing savePlayers = Timings.ofSafe("Save Players");
|
||||
|
||||
public static final Timing tickEntityTimer = Timings.ofSafe("## tickEntity");
|
||||
public static final Timing tickTileEntityTimer = Timings.ofSafe("## tickTileEntity");
|
||||
public static final Timing packetProcessTimer = Timings.ofSafe("## Packet Processing");
|
||||
public static final Timing scheduledBlocksTimer = Timings.ofSafe("## Scheduled Blocks");
|
||||
public static final Timing structureGenerationTimer = Timings.ofSafe("Structure Generation");
|
||||
|
||||
public static final Timing processQueueTimer = Timings.ofSafe("processQueue");
|
||||
|
||||
public static final Timing playerCommandTimer = Timings.ofSafe("playerCommand");
|
||||
|
||||
public static final Timing entityActivationCheckTimer = Timings.ofSafe("entityActivationCheck");
|
||||
|
||||
public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update");
|
||||
public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate");
|
||||
|
||||
private static final Map<Class<? extends Runnable>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
|
||||
|
||||
private MinecraftTimings() {}
|
||||
|
||||
/**
|
||||
* Gets a timer associated with a plugins tasks.
|
||||
* @param bukkitTask
|
||||
* @param period
|
||||
* @return
|
||||
*/
|
||||
public static Timing getPluginTaskTimings(BukkitTask bukkitTask, long period) {
|
||||
if (!bukkitTask.isSync()) {
|
||||
return NullTimingHandler.NULL;
|
||||
}
|
||||
Plugin plugin;
|
||||
|
||||
Runnable task = ((CraftTask) bukkitTask).task;
|
||||
|
||||
final Class<? extends Runnable> taskClass = task.getClass();
|
||||
if (bukkitTask.getOwner() != null) {
|
||||
plugin = bukkitTask.getOwner();
|
||||
} else {
|
||||
plugin = TimingsManager.getPluginByClassloader(taskClass);
|
||||
}
|
||||
|
||||
final String taskname = taskNameCache.computeIfAbsent(taskClass, clazz ->
|
||||
clazz.isAnonymousClass() || clazz.isLocalClass()
|
||||
? clazz.getName()
|
||||
: clazz.getCanonicalName());
|
||||
|
||||
StringBuilder name = new StringBuilder(64);
|
||||
name.append("Task: ").append(taskname);
|
||||
if (period > 0) {
|
||||
name.append(" (interval:").append(period).append(")");
|
||||
} else {
|
||||
name.append(" (Single)");
|
||||
}
|
||||
|
||||
if (plugin == null) {
|
||||
return Timings.ofSafe(null, name.toString());
|
||||
}
|
||||
|
||||
return Timings.ofSafe(plugin, name.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a named timer for the specified entity type to track type specific timings.
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public static Timing getEntityTimings(Entity entity) {
|
||||
String entityType = entity.getClass().getName();
|
||||
return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType, tickEntityTimer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a named timer for the specified tile entity type to track type specific timings.
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public static Timing getTileEntityTimings(TileEntity entity) {
|
||||
String entityType = entity.getClass().getName();
|
||||
return Timings.ofSafe("Minecraft", "## tickTileEntity - " + entityType, tickTileEntityTimer);
|
||||
}
|
||||
public static Timing getCancelTasksTimer() {
|
||||
return Timings.ofSafe("Cancel Tasks");
|
||||
}
|
||||
public static Timing getCancelTasksTimer(Plugin plugin) {
|
||||
return Timings.ofSafe(plugin, "Cancel Tasks");
|
||||
}
|
||||
|
||||
public static void stopServer() {
|
||||
TimingsManager.stopServer();
|
||||
}
|
||||
|
||||
public static Timing getBlockTiming(Block block) {
|
||||
return Timings.ofSafe("## Scheduled Block: " + block.getName(), scheduledBlocksTimer);
|
||||
}
|
||||
|
||||
public static Timing getStructureTiming(StructureGenerator structureGenerator) {
|
||||
return Timings.ofSafe("Structure Generator - " + structureGenerator.getName(), structureGenerationTimer);
|
||||
}
|
||||
|
||||
public static Timing getPacketTiming(Packet packet) {
|
||||
return Timings.ofSafe("## Packet - " + packet.getClass().getSimpleName(), packetProcessTimer);
|
||||
}
|
||||
}
|
||||
131
sources/src/main/java/co/aikar/timings/TimedChunkGenerator.java
Normal file
131
sources/src/main/java/co/aikar/timings/TimedChunkGenerator.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This file is licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2014-2016 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 net.minecraft.server.BiomeBase.BiomeMeta;
|
||||
import net.minecraft.server.BlockPosition;
|
||||
import net.minecraft.server.Chunk;
|
||||
import net.minecraft.server.EnumCreatureType;
|
||||
import net.minecraft.server.World;
|
||||
import net.minecraft.server.WorldServer;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.generator.InternalChunkGenerator;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class TimedChunkGenerator extends InternalChunkGenerator {
|
||||
private final WorldServer world;
|
||||
private final InternalChunkGenerator timedGenerator;
|
||||
|
||||
public TimedChunkGenerator(WorldServer worldServer, InternalChunkGenerator gen) {
|
||||
world = worldServer;
|
||||
timedGenerator = gen;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public byte[] generate(org.bukkit.World world, Random random, int x, int z) {
|
||||
return timedGenerator.generate(world, random, x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public short[][] generateExtBlockSections(org.bukkit.World world, Random random, int x, int z,
|
||||
BiomeGrid biomes) {
|
||||
return timedGenerator.generateExtBlockSections(world, random, x, z, biomes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public byte[][] generateBlockSections(org.bukkit.World world, Random random, int x, int z,
|
||||
BiomeGrid biomes) {
|
||||
return timedGenerator.generateBlockSections(world, random, x, z, biomes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkData generateChunkData(org.bukkit.World world, Random random, int x, int z, BiomeGrid biome) {
|
||||
return timedGenerator.generateChunkData(world, random, x, z, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSpawn(org.bukkit.World world, int x, int z) {
|
||||
return timedGenerator.canSpawn(world, x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPopulator> getDefaultPopulators(org.bukkit.World world) {
|
||||
return timedGenerator.getDefaultPopulators(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getFixedSpawnLocation(org.bukkit.World world, Random random) {
|
||||
return timedGenerator.getFixedSpawnLocation(world, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getOrCreateChunk(int i, int j) {
|
||||
try (Timing ignored = world.timings.chunkGeneration.startTiming()) {
|
||||
return timedGenerator.getOrCreateChunk(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recreateStructures(int i, int j) {
|
||||
try (Timing ignored = world.timings.syncChunkLoadStructuresTimer.startTiming()) {
|
||||
timedGenerator.recreateStructures(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean a(Chunk chunk, int i, int j) {
|
||||
return timedGenerator.a(chunk, i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BiomeMeta> getMobsFor(EnumCreatureType enumcreaturetype, BlockPosition blockposition) {
|
||||
return timedGenerator.getMobsFor(enumcreaturetype, blockposition);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockPosition findNearestMapFeature(World world, String s, BlockPosition blockposition, boolean flag) {
|
||||
return timedGenerator.findNearestMapFeature(world, s, blockposition, flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recreateStructures(Chunk chunk, int i, int j) {
|
||||
try (Timing ignored = world.timings.syncChunkLoadStructuresTimer.startTiming()) {
|
||||
timedGenerator.recreateStructures(chunk, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean a(World world, String s, BlockPosition blockPosition) {
|
||||
return timedGenerator.a(world, s, blockPosition);
|
||||
}
|
||||
}
|
||||
228
sources/src/main/java/co/aikar/timings/TimingHandler.java
Normal file
228
sources/src/main/java/co/aikar/timings/TimingHandler.java
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* 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 io.akarin.api.internal.Akari;
|
||||
import io.akarin.api.internal.Akari.AssignableThread;
|
||||
import io.akarin.server.core.AkarinGlobalConfig;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
class TimingHandler implements Timing {
|
||||
String name;
|
||||
private static AtomicInteger idPool = new AtomicInteger(1);
|
||||
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 final TimingHandler groupHandler;
|
||||
|
||||
private long start = 0;
|
||||
private int timingDepth = 0;
|
||||
private boolean added;
|
||||
private boolean timed;
|
||||
private boolean enabled;
|
||||
|
||||
TimingHandler(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);
|
||||
}
|
||||
}
|
||||
|
||||
public Timing startTimingIfSync() {
|
||||
startTiming();
|
||||
return (Timing) this;
|
||||
}
|
||||
|
||||
public void stopTimingIfSync() {
|
||||
if (Akari.isPrimaryThread(false)) {
|
||||
stopTiming(true); // Avoid twice thread check
|
||||
}
|
||||
}
|
||||
|
||||
public Timing startTiming() {
|
||||
if (enabled && Bukkit.isPrimaryThread() && ++timingDepth == 1) {
|
||||
start = System.nanoTime();
|
||||
TIMING_STACK.addLast(this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void stopTiming() {
|
||||
stopTiming(false);
|
||||
}
|
||||
|
||||
public void stopTiming(long start) {
|
||||
if (enabled) addDiff(System.nanoTime() - start);
|
||||
}
|
||||
|
||||
public void stopTiming(boolean alreadySync) {
|
||||
if (!enabled) return;
|
||||
if (!alreadySync) {
|
||||
Thread curThread = Thread.currentThread();
|
||||
if (curThread.getClass() == AssignableThread.class) return;
|
||||
if (curThread != MinecraftServer.getServer().primaryThread) {
|
||||
if (AkarinGlobalConfig.silentAsyncTimings) return;
|
||||
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
|
||||
Thread.dumpStack();
|
||||
}
|
||||
}
|
||||
|
||||
// Main thread ensured
|
||||
if (--timingDepth == 0 && start != 0) {
|
||||
addDiff(System.nanoTime() - start);
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void abort() {
|
||||
|
||||
}
|
||||
void addDiff(long diff) {
|
||||
if (this != null) {
|
||||
this.children.get(id).add(diff);
|
||||
}
|
||||
|
||||
record.add(diff);
|
||||
if (!added) {
|
||||
added = true;
|
||||
timed = true;
|
||||
TimingsManager.HANDLERS.add(this);
|
||||
}
|
||||
if (groupHandler != null) {
|
||||
groupHandler.addDiff(diff, this);
|
||||
groupHandler.children.get(id).add(diff);
|
||||
}
|
||||
}
|
||||
void addDiff(long diff, 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();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
TimingData[] cloneChildren() {
|
||||
final TimingData[] clonedChildren = new TimingData[children.size()];
|
||||
int i = 0;
|
||||
for (TimingData child : children.values()) {
|
||||
clonedChildren[i++] = child.clone();
|
||||
}
|
||||
return clonedChildren;
|
||||
}
|
||||
}
|
||||
103
sources/src/main/java/co/aikar/timings/WorldTimingsHandler.java
Normal file
103
sources/src/main/java/co/aikar/timings/WorldTimingsHandler.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package co.aikar.timings;
|
||||
|
||||
import net.minecraft.server.World;
|
||||
|
||||
/**
|
||||
* Set of timers per world, to track world specific timings.
|
||||
*/
|
||||
public class WorldTimingsHandler {
|
||||
public final Timing mobSpawn;
|
||||
public final Timing doChunkUnload;
|
||||
public final Timing doPortalForcer;
|
||||
public final Timing scheduledBlocks;
|
||||
public final Timing scheduledBlocksCleanup;
|
||||
public final Timing scheduledBlocksTicking;
|
||||
public final Timing chunkTicks;
|
||||
public final Timing lightChunk;
|
||||
public final Timing chunkTicksBlocks;
|
||||
public final Timing doVillages;
|
||||
public final Timing doChunkMap;
|
||||
public final Timing doChunkMapUpdate;
|
||||
public final Timing doChunkMapToUpdate;
|
||||
public final Timing doChunkMapSortMissing;
|
||||
public final Timing doChunkMapSortSendToPlayers;
|
||||
public final Timing doChunkMapPlayersNeedingChunks;
|
||||
public final Timing doChunkMapPendingSendToPlayers;
|
||||
public final Timing doChunkMapUnloadChunks;
|
||||
public final Timing doChunkGC;
|
||||
public final Timing doSounds;
|
||||
public final Timing entityRemoval;
|
||||
public final Timing entityTick;
|
||||
public final Timing tileEntityTick;
|
||||
public final Timing tileEntityPending;
|
||||
public final Timing tracker1;
|
||||
public final Timing tracker2;
|
||||
public final Timing doTick;
|
||||
public final Timing tickEntities;
|
||||
|
||||
public final Timing syncChunkLoadTimer;
|
||||
public final Timing syncChunkLoadDataTimer;
|
||||
public final Timing syncChunkLoadStructuresTimer;
|
||||
public final Timing syncChunkLoadPostTimer;
|
||||
public final Timing syncChunkLoadNBTTimer;
|
||||
public final Timing syncChunkLoadPopulateNeighbors;
|
||||
public final Timing chunkGeneration;
|
||||
public final Timing chunkIOStage1;
|
||||
public final Timing chunkIOStage2;
|
||||
public final Timing worldSave;
|
||||
public final Timing worldSaveChunks;
|
||||
public final Timing worldSaveLevel;
|
||||
public final Timing chunkSaveData;
|
||||
|
||||
public final Timing lightingQueueTimer;
|
||||
|
||||
public WorldTimingsHandler(World server) {
|
||||
String name = server.worldData.getName() +" - ";
|
||||
|
||||
mobSpawn = Timings.ofSafe(name + "mobSpawn");
|
||||
doChunkUnload = Timings.ofSafe(name + "doChunkUnload");
|
||||
scheduledBlocks = Timings.ofSafe(name + "Scheduled Blocks");
|
||||
scheduledBlocksCleanup = Timings.ofSafe(name + "Scheduled Blocks - Cleanup");
|
||||
scheduledBlocksTicking = Timings.ofSafe(name + "Scheduled Blocks - Ticking");
|
||||
chunkTicks = Timings.ofSafe(name + "Chunk Ticks");
|
||||
lightChunk = Timings.ofSafe(name + "Light Chunk");
|
||||
chunkTicksBlocks = Timings.ofSafe(name + "Chunk Ticks - Blocks");
|
||||
doVillages = Timings.ofSafe(name + "doVillages");
|
||||
doChunkMap = Timings.ofSafe(name + "doChunkMap");
|
||||
doChunkMapUpdate = Timings.ofSafe(name + "doChunkMap - Update");
|
||||
doChunkMapToUpdate = Timings.ofSafe(name + "doChunkMap - To Update");
|
||||
doChunkMapSortMissing = Timings.ofSafe(name + "doChunkMap - Sort Missing");
|
||||
doChunkMapSortSendToPlayers = Timings.ofSafe(name + "doChunkMap - Sort Send To Players");
|
||||
doChunkMapPlayersNeedingChunks = Timings.ofSafe(name + "doChunkMap - Players Needing Chunks");
|
||||
doChunkMapPendingSendToPlayers = Timings.ofSafe(name + "doChunkMap - Pending Send To Players");
|
||||
doChunkMapUnloadChunks = Timings.ofSafe(name + "doChunkMap - Unload Chunks");
|
||||
doSounds = Timings.ofSafe(name + "doSounds");
|
||||
doChunkGC = Timings.ofSafe(name + "doChunkGC");
|
||||
doPortalForcer = Timings.ofSafe(name + "doPortalForcer");
|
||||
entityTick = Timings.ofSafe(name + "entityTick");
|
||||
entityRemoval = Timings.ofSafe(name + "entityRemoval");
|
||||
tileEntityTick = Timings.ofSafe(name + "tileEntityTick");
|
||||
tileEntityPending = Timings.ofSafe(name + "tileEntityPending");
|
||||
|
||||
syncChunkLoadTimer = Timings.ofSafe(name + "syncChunkLoad");
|
||||
syncChunkLoadDataTimer = Timings.ofSafe(name + "syncChunkLoad - Data");
|
||||
syncChunkLoadStructuresTimer = Timings.ofSafe(name + "chunkLoad - recreateStructures");
|
||||
syncChunkLoadPostTimer = Timings.ofSafe(name + "chunkLoad - Post");
|
||||
syncChunkLoadNBTTimer = Timings.ofSafe(name + "chunkLoad - NBT");
|
||||
syncChunkLoadPopulateNeighbors = Timings.ofSafe(name + "chunkLoad - Populate Neighbors");
|
||||
chunkGeneration = Timings.ofSafe(name + "chunkGeneration");
|
||||
chunkIOStage1 = Timings.ofSafe(name + "ChunkIO Stage 1 - DiskIO");
|
||||
chunkIOStage2 = Timings.ofSafe(name + "ChunkIO Stage 2 - Post Load");
|
||||
worldSave = Timings.ofSafe(name + "World Save");
|
||||
worldSaveLevel = Timings.ofSafe(name + "World Save - Level");
|
||||
worldSaveChunks = Timings.ofSafe(name + "World Save - Chunks");
|
||||
chunkSaveData = Timings.ofSafe(name + "Chunk Save - Data");
|
||||
|
||||
tracker1 = Timings.ofSafe(name + "tracker stage 1");
|
||||
tracker2 = Timings.ofSafe(name + "tracker stage 2");
|
||||
doTick = Timings.ofSafe(name + "doTick");
|
||||
tickEntities = Timings.ofSafe(name + "tickEntities");
|
||||
|
||||
lightingQueueTimer = Timings.ofSafe(name + "Lighting Queue");
|
||||
}
|
||||
}
|
||||
@@ -98,9 +98,10 @@ public class AkarinSlackScheduler extends Thread {
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100 - (System.currentTimeMillis() - startProcessTiming));
|
||||
long sleepFixed = 100 - (System.currentTimeMillis() - startProcessTiming);
|
||||
if (sleepFixed > 0) Thread.sleep(sleepFixed);
|
||||
} catch (InterruptedException interrupted) {
|
||||
;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public abstract class MixinMinecraftServer {
|
||||
|
||||
for (int i = 0; i < worlds.size(); ++i) {
|
||||
WorldServer world = worlds.get(i);
|
||||
TileEntityHopper.skipHopperEvents = world.paperConfig.disableHopperMoveEvents || InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0;
|
||||
//TileEntityHopper.skipHopperEvents = world.paperConfig.disableHopperMoveEvents || InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0;
|
||||
}
|
||||
AkarinSlackScheduler.get().boot();
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package io.akarin.server.mixin.core;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import co.aikar.timings.Timing;
|
||||
import io.akarin.api.internal.Akari;
|
||||
import io.akarin.api.internal.Akari.AssignableThread;
|
||||
import io.akarin.server.core.AkarinGlobalConfig;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
@Mixin(targets = "co.aikar.timings.TimingHandler", remap = false)
|
||||
public abstract class MixinTimingHandler {
|
||||
@Shadow @Final String name;
|
||||
@Shadow private boolean enabled;
|
||||
@Shadow private long start;
|
||||
@Shadow private int timingDepth;
|
||||
|
||||
@Shadow abstract void addDiff(long diff);
|
||||
@Shadow public abstract Timing startTiming();
|
||||
|
||||
@Overwrite // Overwrite to avoid twice thread check
|
||||
public Timing startTimingIfSync() {
|
||||
startTiming();
|
||||
return (Timing) this;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Inject(method = "startTiming", at = @At("HEAD"), cancellable = true)
|
||||
public void onStartTiming(CallbackInfoReturnable ci) {
|
||||
if (!Akari.isPrimaryThread(false)) ci.setReturnValue(this); // Avoid modify any field
|
||||
}
|
||||
|
||||
@Overwrite
|
||||
public void stopTimingIfSync() {
|
||||
if (Akari.isPrimaryThread(false)) {
|
||||
stopTiming(true); // Avoid twice thread check
|
||||
}
|
||||
}
|
||||
|
||||
@Overwrite
|
||||
public void stopTiming() {
|
||||
stopTiming(false);
|
||||
}
|
||||
|
||||
public void stopTiming(long start) {
|
||||
if (enabled) addDiff(System.nanoTime() - start);
|
||||
}
|
||||
|
||||
public void stopTiming(boolean alreadySync) {
|
||||
if (!enabled) return;
|
||||
if (!alreadySync) {
|
||||
Thread curThread = Thread.currentThread();
|
||||
if (curThread.getClass() == AssignableThread.class) return;
|
||||
if (curThread != MinecraftServer.getServer().primaryThread) {
|
||||
if (AkarinGlobalConfig.silentAsyncTimings) return;
|
||||
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
|
||||
Thread.dumpStack();
|
||||
}
|
||||
}
|
||||
|
||||
// Main thread ensured
|
||||
if (--timingDepth == 0 && start != 0) {
|
||||
addDiff(System.nanoTime() - start);
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
479
sources/src/main/java/net/minecraft/server/BlockChest.java
Normal file
479
sources/src/main/java/net/minecraft/server/BlockChest.java
Normal file
@@ -0,0 +1,479 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BlockChest extends BlockTileEntity {
|
||||
|
||||
public static final BlockStateDirection FACING = BlockFacingHorizontal.FACING;
|
||||
protected static final AxisAlignedBB b = new AxisAlignedBB(0.0625D, 0.0D, 0.0D, 0.9375D, 0.875D, 0.9375D);
|
||||
protected static final AxisAlignedBB c = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 0.9375D, 0.875D, 1.0D);
|
||||
protected static final AxisAlignedBB d = new AxisAlignedBB(0.0D, 0.0D, 0.0625D, 0.9375D, 0.875D, 0.9375D);
|
||||
protected static final AxisAlignedBB e = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 1.0D, 0.875D, 0.9375D);
|
||||
protected static final AxisAlignedBB f = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 0.9375D, 0.875D, 0.9375D);
|
||||
public final BlockChest.Type g;
|
||||
|
||||
protected BlockChest(BlockChest.Type blockchest_type) {
|
||||
super(Material.WOOD);
|
||||
this.w(this.blockStateList.getBlockData().set(BlockChest.FACING, EnumDirection.NORTH));
|
||||
this.g = blockchest_type;
|
||||
this.a(blockchest_type == BlockChest.Type.TRAP ? CreativeModeTab.d : CreativeModeTab.c);
|
||||
}
|
||||
|
||||
public boolean b(IBlockData iblockdata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean c(IBlockData iblockdata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public EnumRenderType a(IBlockData iblockdata) {
|
||||
return EnumRenderType.ENTITYBLOCK_ANIMATED;
|
||||
}
|
||||
|
||||
public AxisAlignedBB b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) {
|
||||
return iblockaccess.getType(blockposition.north()).getBlock() == this ? BlockChest.b : (iblockaccess.getType(blockposition.south()).getBlock() == this ? BlockChest.c : (iblockaccess.getType(blockposition.west()).getBlock() == this ? BlockChest.d : (iblockaccess.getType(blockposition.east()).getBlock() == this ? BlockChest.e : BlockChest.f)));
|
||||
}
|
||||
|
||||
public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
|
||||
this.e(world, blockposition, iblockdata);
|
||||
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EnumDirection enumdirection = (EnumDirection) iterator.next();
|
||||
BlockPosition blockposition1 = blockposition.shift(enumdirection);
|
||||
// NeonPaper start - Dont load chunks for chests
|
||||
final IBlockData iblockdata1 = world.isLoaded(blockposition1) ? world.getType(blockposition1) : null;
|
||||
if (iblockdata1 == null) {
|
||||
continue;
|
||||
}
|
||||
// NeonPaper end
|
||||
|
||||
if (iblockdata1.getBlock() == this) {
|
||||
this.e(world, blockposition1, iblockdata1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IBlockData getPlacedState(World world, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2, int i, EntityLiving entityliving) {
|
||||
return this.getBlockData().set(BlockChest.FACING, entityliving.getDirection());
|
||||
}
|
||||
|
||||
public void postPlace(World world, BlockPosition blockposition, IBlockData iblockdata, EntityLiving entityliving, ItemStack itemstack) {
|
||||
EnumDirection enumdirection = EnumDirection.fromType2(MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3).opposite();
|
||||
|
||||
iblockdata = iblockdata.set(BlockChest.FACING, enumdirection);
|
||||
BlockPosition blockposition1 = blockposition.north();
|
||||
BlockPosition blockposition2 = blockposition.south();
|
||||
BlockPosition blockposition3 = blockposition.west();
|
||||
BlockPosition blockposition4 = blockposition.east();
|
||||
boolean flag = this == world.getType(blockposition1).getBlock();
|
||||
boolean flag1 = this == world.getType(blockposition2).getBlock();
|
||||
boolean flag2 = this == world.getType(blockposition3).getBlock();
|
||||
boolean flag3 = this == world.getType(blockposition4).getBlock();
|
||||
|
||||
if (!flag && !flag1 && !flag2 && !flag3) {
|
||||
world.setTypeAndData(blockposition, iblockdata, 3);
|
||||
} else if (enumdirection.k() == EnumDirection.EnumAxis.X && (flag || flag1)) {
|
||||
if (flag) {
|
||||
world.setTypeAndData(blockposition1, iblockdata, 3);
|
||||
} else {
|
||||
world.setTypeAndData(blockposition2, iblockdata, 3);
|
||||
}
|
||||
|
||||
world.setTypeAndData(blockposition, iblockdata, 3);
|
||||
} else if (enumdirection.k() == EnumDirection.EnumAxis.Z && (flag2 || flag3)) {
|
||||
if (flag2) {
|
||||
world.setTypeAndData(blockposition3, iblockdata, 3);
|
||||
} else {
|
||||
world.setTypeAndData(blockposition4, iblockdata, 3);
|
||||
}
|
||||
|
||||
world.setTypeAndData(blockposition, iblockdata, 3);
|
||||
}
|
||||
|
||||
if (itemstack.hasName()) {
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
|
||||
if (tileentity instanceof TileEntityChest) {
|
||||
((TileEntityChest) tileentity).setCustomName(itemstack.getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IBlockData e(World world, BlockPosition blockposition, IBlockData iblockdata) {
|
||||
if (world.isClientSide) {
|
||||
return iblockdata;
|
||||
} else {
|
||||
IBlockData iblockdata1 = world.getType(blockposition.north());
|
||||
IBlockData iblockdata2 = world.getType(blockposition.south());
|
||||
IBlockData iblockdata3 = world.getType(blockposition.west());
|
||||
IBlockData iblockdata4 = world.getType(blockposition.east());
|
||||
EnumDirection enumdirection = (EnumDirection) iblockdata.get(BlockChest.FACING);
|
||||
|
||||
if (iblockdata1.getBlock() != this && iblockdata2.getBlock() != this) {
|
||||
boolean flag = iblockdata1.b();
|
||||
boolean flag1 = iblockdata2.b();
|
||||
|
||||
if (iblockdata3.getBlock() == this || iblockdata4.getBlock() == this) {
|
||||
BlockPosition blockposition1 = iblockdata3.getBlock() == this ? blockposition.west() : blockposition.east();
|
||||
IBlockData iblockdata5 = world.getType(blockposition1.north());
|
||||
IBlockData iblockdata6 = world.getType(blockposition1.south());
|
||||
|
||||
enumdirection = EnumDirection.SOUTH;
|
||||
EnumDirection enumdirection1;
|
||||
|
||||
if (iblockdata3.getBlock() == this) {
|
||||
enumdirection1 = (EnumDirection) iblockdata3.get(BlockChest.FACING);
|
||||
} else {
|
||||
enumdirection1 = (EnumDirection) iblockdata4.get(BlockChest.FACING);
|
||||
}
|
||||
|
||||
if (enumdirection1 == EnumDirection.NORTH) {
|
||||
enumdirection = EnumDirection.NORTH;
|
||||
}
|
||||
|
||||
if ((flag || iblockdata5.b()) && !flag1 && !iblockdata6.b()) {
|
||||
enumdirection = EnumDirection.SOUTH;
|
||||
}
|
||||
|
||||
if ((flag1 || iblockdata6.b()) && !flag && !iblockdata5.b()) {
|
||||
enumdirection = EnumDirection.NORTH;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BlockPosition blockposition2 = iblockdata1.getBlock() == this ? blockposition.north() : blockposition.south();
|
||||
IBlockData iblockdata7 = world.getType(blockposition2.west());
|
||||
IBlockData iblockdata8 = world.getType(blockposition2.east());
|
||||
|
||||
enumdirection = EnumDirection.EAST;
|
||||
EnumDirection enumdirection2;
|
||||
|
||||
if (iblockdata1.getBlock() == this) {
|
||||
enumdirection2 = (EnumDirection) iblockdata1.get(BlockChest.FACING);
|
||||
} else {
|
||||
enumdirection2 = (EnumDirection) iblockdata2.get(BlockChest.FACING);
|
||||
}
|
||||
|
||||
if (enumdirection2 == EnumDirection.WEST) {
|
||||
enumdirection = EnumDirection.WEST;
|
||||
}
|
||||
|
||||
if ((iblockdata3.b() || iblockdata7.b()) && !iblockdata4.b() && !iblockdata8.b()) {
|
||||
enumdirection = EnumDirection.EAST;
|
||||
}
|
||||
|
||||
if ((iblockdata4.b() || iblockdata8.b()) && !iblockdata3.b() && !iblockdata7.b()) {
|
||||
enumdirection = EnumDirection.WEST;
|
||||
}
|
||||
}
|
||||
|
||||
iblockdata = iblockdata.set(BlockChest.FACING, enumdirection);
|
||||
world.setTypeAndData(blockposition, iblockdata, 3);
|
||||
return iblockdata;
|
||||
}
|
||||
}
|
||||
|
||||
public IBlockData f(World world, BlockPosition blockposition, IBlockData iblockdata) {
|
||||
EnumDirection enumdirection = null;
|
||||
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EnumDirection enumdirection1 = (EnumDirection) iterator.next();
|
||||
IBlockData iblockdata1 = world.getType(blockposition.shift(enumdirection1));
|
||||
|
||||
if (iblockdata1.getBlock() == this) {
|
||||
return iblockdata;
|
||||
}
|
||||
|
||||
if (iblockdata1.b()) {
|
||||
if (enumdirection != null) {
|
||||
enumdirection = null;
|
||||
break;
|
||||
}
|
||||
|
||||
enumdirection = enumdirection1;
|
||||
}
|
||||
}
|
||||
|
||||
if (enumdirection != null) {
|
||||
return iblockdata.set(BlockChest.FACING, enumdirection.opposite());
|
||||
} else {
|
||||
EnumDirection enumdirection2 = (EnumDirection) iblockdata.get(BlockChest.FACING);
|
||||
|
||||
if (world.getType(blockposition.shift(enumdirection2)).b()) {
|
||||
enumdirection2 = enumdirection2.opposite();
|
||||
}
|
||||
|
||||
if (world.getType(blockposition.shift(enumdirection2)).b()) {
|
||||
enumdirection2 = enumdirection2.e();
|
||||
}
|
||||
|
||||
if (world.getType(blockposition.shift(enumdirection2)).b()) {
|
||||
enumdirection2 = enumdirection2.opposite();
|
||||
}
|
||||
|
||||
return iblockdata.set(BlockChest.FACING, enumdirection2);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canPlace(World world, BlockPosition blockposition) {
|
||||
int i = 0;
|
||||
BlockPosition blockposition1 = blockposition.west();
|
||||
BlockPosition blockposition2 = blockposition.east();
|
||||
BlockPosition blockposition3 = blockposition.north();
|
||||
BlockPosition blockposition4 = blockposition.south();
|
||||
|
||||
if (world.getType(blockposition1).getBlock() == this) {
|
||||
if (this.d(world, blockposition1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (world.getType(blockposition2).getBlock() == this) {
|
||||
if (this.d(world, blockposition2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (world.getType(blockposition3).getBlock() == this) {
|
||||
if (this.d(world, blockposition3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (world.getType(blockposition4).getBlock() == this) {
|
||||
if (this.d(world, blockposition4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return i <= 1;
|
||||
}
|
||||
|
||||
private boolean d(World world, BlockPosition blockposition) {
|
||||
if (world.getType(blockposition).getBlock() != this) {
|
||||
return false;
|
||||
} else {
|
||||
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
|
||||
|
||||
EnumDirection enumdirection;
|
||||
|
||||
do {
|
||||
if (!iterator.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enumdirection = (EnumDirection) iterator.next();
|
||||
} while (world.getType(blockposition.shift(enumdirection)).getBlock() != this);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) {
|
||||
super.a(iblockdata, world, blockposition, block, blockposition1);
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
|
||||
if (tileentity instanceof TileEntityChest) {
|
||||
tileentity.invalidateBlockCache();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void remove(World world, BlockPosition blockposition, IBlockData iblockdata) {
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
|
||||
if (tileentity instanceof IInventory) {
|
||||
InventoryUtils.dropInventory(world, blockposition, (IInventory) tileentity);
|
||||
world.updateAdjacentComparators(blockposition, this);
|
||||
}
|
||||
|
||||
super.remove(world, blockposition, iblockdata);
|
||||
}
|
||||
|
||||
public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, EnumDirection enumdirection, float f, float f1, float f2) {
|
||||
if (world.isClientSide) {
|
||||
return true;
|
||||
} else {
|
||||
ITileInventory itileinventory = this.getInventory(world, blockposition);
|
||||
|
||||
if (itileinventory != null) {
|
||||
entityhuman.openContainer(itileinventory);
|
||||
if (this.g == BlockChest.Type.BASIC) {
|
||||
entityhuman.b(StatisticList.aa);
|
||||
} else if (this.g == BlockChest.Type.TRAP) {
|
||||
entityhuman.b(StatisticList.U);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ITileInventory getInventory(World world, BlockPosition blockposition) {
|
||||
return this.a(world, blockposition, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ITileInventory a(World world, BlockPosition blockposition, boolean flag) {
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
|
||||
if (!(tileentity instanceof TileEntityChest)) {
|
||||
return null;
|
||||
} else {
|
||||
Object object = (TileEntityChest) tileentity;
|
||||
|
||||
if (!flag && this.e(world, blockposition)) {
|
||||
return null;
|
||||
} else {
|
||||
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EnumDirection enumdirection = (EnumDirection) iterator.next();
|
||||
BlockPosition blockposition1 = blockposition.shift(enumdirection);
|
||||
// Paper start - don't load chunks if the other side of the chest is in unloaded chunk
|
||||
final IBlockData type = world.getTypeIfLoaded(blockposition1); // Paper
|
||||
if (type == null) {
|
||||
continue;
|
||||
}
|
||||
Block block = type.getBlock();
|
||||
// Paper end
|
||||
|
||||
if (block == this) {
|
||||
if (!flag && this.e(world, blockposition1)) { // Paper - check for allowBlocked flag - MC-99321
|
||||
return null;
|
||||
}
|
||||
|
||||
TileEntity tileentity1 = world.getTileEntity(blockposition1);
|
||||
|
||||
if (tileentity1 instanceof TileEntityChest) {
|
||||
if (enumdirection != EnumDirection.WEST && enumdirection != EnumDirection.NORTH) {
|
||||
object = new InventoryLargeChest("container.chestDouble", (ITileInventory) object, (TileEntityChest) tileentity1);
|
||||
} else {
|
||||
object = new InventoryLargeChest("container.chestDouble", (TileEntityChest) tileentity1, (ITileInventory) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ITileInventory) object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TileEntity a(World world, int i) {
|
||||
return new TileEntityChest();
|
||||
}
|
||||
|
||||
public boolean isPowerSource(IBlockData iblockdata) {
|
||||
return this.g == BlockChest.Type.TRAP;
|
||||
}
|
||||
|
||||
public int b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
|
||||
if (!iblockdata.m()) {
|
||||
return 0;
|
||||
} else {
|
||||
int i = 0;
|
||||
TileEntity tileentity = iblockaccess.getTileEntity(blockposition);
|
||||
|
||||
if (tileentity instanceof TileEntityChest) {
|
||||
i = ((TileEntityChest) tileentity).l;
|
||||
}
|
||||
|
||||
return MathHelper.clamp(i, 0, 15);
|
||||
}
|
||||
}
|
||||
|
||||
public int c(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
|
||||
return enumdirection == EnumDirection.UP ? iblockdata.a(iblockaccess, blockposition, enumdirection) : 0;
|
||||
}
|
||||
|
||||
private boolean e(World world, BlockPosition blockposition) {
|
||||
return this.i(world, blockposition) || this.j(world, blockposition);
|
||||
}
|
||||
|
||||
private boolean i(World world, BlockPosition blockposition) {
|
||||
return world.getType(blockposition.up()).l();
|
||||
}
|
||||
|
||||
private boolean j(World world, BlockPosition blockposition) {
|
||||
// Paper start - Option ti dsiable chest cat detection
|
||||
if (world.paperConfig.disableChestCatDetection) {
|
||||
return false;
|
||||
}
|
||||
// Paper end
|
||||
Iterator iterator = world.a(EntityOcelot.class, new AxisAlignedBB((double) blockposition.getX(), (double) (blockposition.getY() + 1), (double) blockposition.getZ(), (double) (blockposition.getX() + 1), (double) (blockposition.getY() + 2), (double) (blockposition.getZ() + 1))).iterator();
|
||||
|
||||
EntityOcelot entityocelot;
|
||||
|
||||
do {
|
||||
if (!iterator.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Entity entity = (Entity) iterator.next();
|
||||
|
||||
entityocelot = (EntityOcelot) entity;
|
||||
} while (!entityocelot.isSitting());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isComplexRedstone(IBlockData iblockdata) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int c(IBlockData iblockdata, World world, BlockPosition blockposition) {
|
||||
return Container.b((IInventory) this.getInventory(world, blockposition));
|
||||
}
|
||||
|
||||
public IBlockData fromLegacyData(int i) {
|
||||
EnumDirection enumdirection = EnumDirection.fromType1(i);
|
||||
|
||||
if (enumdirection.k() == EnumDirection.EnumAxis.Y) {
|
||||
enumdirection = EnumDirection.NORTH;
|
||||
}
|
||||
|
||||
return this.getBlockData().set(BlockChest.FACING, enumdirection);
|
||||
}
|
||||
|
||||
public int toLegacyData(IBlockData iblockdata) {
|
||||
return ((EnumDirection) iblockdata.get(BlockChest.FACING)).a();
|
||||
}
|
||||
|
||||
public IBlockData a(IBlockData iblockdata, EnumBlockRotation enumblockrotation) {
|
||||
return iblockdata.set(BlockChest.FACING, enumblockrotation.a((EnumDirection) iblockdata.get(BlockChest.FACING)));
|
||||
}
|
||||
|
||||
public IBlockData a(IBlockData iblockdata, EnumBlockMirror enumblockmirror) {
|
||||
return iblockdata.a(enumblockmirror.a((EnumDirection) iblockdata.get(BlockChest.FACING)));
|
||||
}
|
||||
|
||||
protected BlockStateList getStateList() {
|
||||
return new BlockStateList(this, new IBlockState[] { BlockChest.FACING});
|
||||
}
|
||||
|
||||
public EnumBlockFaceShape a(IBlockAccess iblockaccess, IBlockData iblockdata, BlockPosition blockposition, EnumDirection enumdirection) {
|
||||
return EnumBlockFaceShape.UNDEFINED;
|
||||
}
|
||||
|
||||
public static enum Type {
|
||||
|
||||
BASIC, TRAP;
|
||||
|
||||
private Type() {}
|
||||
}
|
||||
}
|
||||
118
sources/src/main/java/net/minecraft/server/BlockStationary.java
Normal file
118
sources/src/main/java/net/minecraft/server/BlockStationary.java
Normal file
@@ -0,0 +1,118 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit
|
||||
|
||||
public class BlockStationary extends BlockFluids {
|
||||
|
||||
protected BlockStationary(Material material) {
|
||||
super(material);
|
||||
this.a(false);
|
||||
if (material == Material.LAVA) {
|
||||
this.a(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) {
|
||||
if (!this.e(world, blockposition, iblockdata)) {
|
||||
this.f(world, blockposition, iblockdata);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void f(World world, BlockPosition blockposition, IBlockData iblockdata) {
|
||||
BlockFlowing blockflowing = a(this.material);
|
||||
|
||||
world.setTypeAndData(blockposition, blockflowing.getBlockData().set(BlockStationary.LEVEL, iblockdata.get(BlockStationary.LEVEL)), 2);
|
||||
world.a(blockposition, (Block) blockflowing, this.a(world));
|
||||
}
|
||||
|
||||
public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) {
|
||||
if (this.material == Material.LAVA) {
|
||||
if (world.getGameRules().getBoolean("doFireTick")) {
|
||||
int i = random.nextInt(3);
|
||||
|
||||
if (i > 0) {
|
||||
BlockPosition blockposition1 = blockposition;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
blockposition1 = blockposition1.a(random.nextInt(3) - 1, 1, random.nextInt(3) - 1);
|
||||
if (blockposition1.getY() >= 0 && blockposition1.getY() < 256 && !world.isLoaded(blockposition1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block block = world.getType(blockposition1).getBlock();
|
||||
|
||||
if (block.material == Material.AIR) {
|
||||
if (this.c(world, blockposition1)) {
|
||||
// CraftBukkit start - Prevent lava putting something on fire
|
||||
if (world.getType(blockposition1) != Blocks.FIRE) {
|
||||
if (CraftEventFactory.callBlockIgniteEvent(world, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), blockposition.getX(), blockposition.getY(), blockposition.getZ()).isCancelled()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
world.setTypeUpdate(blockposition1, Blocks.FIRE.getBlockData());
|
||||
return;
|
||||
}
|
||||
} else if (block.material.isSolid()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
BlockPosition blockposition2 = blockposition.a(random.nextInt(3) - 1, 0, random.nextInt(3) - 1);
|
||||
|
||||
if (blockposition2.getY() >= 0 && blockposition2.getY() < 256 && !world.isLoaded(blockposition2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (world.isEmpty(blockposition2.up()) && this.d(world, blockposition2)) {
|
||||
// CraftBukkit start - Prevent lava putting something on fire
|
||||
BlockPosition up = blockposition2.up();
|
||||
if (world.getType(up) != Blocks.FIRE) {
|
||||
if (CraftEventFactory.callBlockIgniteEvent(world, up.getX(), up.getY(), up.getZ(), blockposition.getX(), blockposition.getY(), blockposition.getZ()).isCancelled()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
world.setTypeUpdate(blockposition2.up(), Blocks.FIRE.getBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean c(World world, BlockPosition blockposition) {
|
||||
EnumDirection[] aenumdirection = EnumDirection.values();
|
||||
int i = aenumdirection.length;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
EnumDirection enumdirection = aenumdirection[j];
|
||||
|
||||
if (this.d(world, blockposition.shift(enumdirection))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean d(World world, BlockPosition blockposition) {
|
||||
// Dionysus start - improve fire spread checks
|
||||
if (blockposition.getY() >= 0 && blockposition.getY() < 256) {
|
||||
IBlockData blockData = world.getTypeIfLoaded(blockposition);
|
||||
|
||||
if (blockData != null) {
|
||||
return blockData.getMaterial().isBurnable();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// Dionysus end
|
||||
}
|
||||
}
|
||||
1561
sources/src/main/java/net/minecraft/server/Chunk.java
Normal file
1561
sources/src/main/java/net/minecraft/server/Chunk.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,458 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.destroystokyo.paper.PaperConfig;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import com.destroystokyo.paper.exception.ServerInternalException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
// CraftBukkit start
|
||||
import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class ChunkProviderServer implements IChunkProvider {
|
||||
|
||||
private static final Logger a = LogManager.getLogger();
|
||||
public final LongArraySet unloadQueue = new LongArraySet(512); // Dionysus
|
||||
public final ChunkGenerator chunkGenerator;
|
||||
private final IChunkLoader chunkLoader;
|
||||
// Paper start - chunk save stats
|
||||
private long lastQueuedSaves = 0L; // Paper
|
||||
private long lastProcessedSaves = 0L; // Paper
|
||||
private long lastSaveStatPrinted = System.currentTimeMillis();
|
||||
// Paper end
|
||||
// Paper start
|
||||
protected Chunk lastChunkByPos = null;
|
||||
public Long2ObjectOpenHashMap<Chunk> chunks = new Long2ObjectOpenHashMap<Chunk>(8192) {
|
||||
|
||||
@Override
|
||||
public Chunk get(long key) {
|
||||
if (lastChunkByPos != null && key == lastChunkByPos.chunkKey) {
|
||||
return lastChunkByPos;
|
||||
}
|
||||
return lastChunkByPos = super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk remove(long key) {
|
||||
if (lastChunkByPos != null && key == lastChunkByPos.chunkKey) {
|
||||
lastChunkByPos = null;
|
||||
}
|
||||
return super.remove(key);
|
||||
}
|
||||
}; // CraftBukkit
|
||||
// Paper end
|
||||
public final WorldServer world;
|
||||
|
||||
public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, ChunkGenerator chunkgenerator) {
|
||||
this.world = worldserver;
|
||||
this.chunkLoader = ichunkloader;
|
||||
this.chunkGenerator = chunkgenerator;
|
||||
}
|
||||
|
||||
public Collection<Chunk> a() {
|
||||
return this.chunks.values();
|
||||
}
|
||||
|
||||
public void unload(Chunk chunk) {
|
||||
if (this.world.worldProvider.c(chunk.locX, chunk.locZ)) {
|
||||
this.unloadQueue.add(Long.valueOf(ChunkCoordIntPair.a(chunk.locX, chunk.locZ)));
|
||||
chunk.d = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void b() {
|
||||
ObjectIterator objectiterator = this.chunks.values().iterator();
|
||||
|
||||
while (objectiterator.hasNext()) {
|
||||
Chunk chunk = (Chunk) objectiterator.next();
|
||||
|
||||
this.unload(chunk);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Paper start
|
||||
public boolean isChunkGenerated(int x, int z) {
|
||||
return this.chunks.containsKey(ChunkCoordIntPair.asLong(x, z)) || this.chunkLoader.chunkExists(x, z);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@Nullable
|
||||
public Chunk getLoadedChunkAt(int i, int j) {
|
||||
long k = ChunkCoordIntPair.a(i, j);
|
||||
Chunk chunk = (Chunk) this.chunks.get(k);
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.d = false;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Chunk getOrLoadChunkAt(int i, int j) {
|
||||
Chunk chunk = this.getLoadedChunkAt(i, j);
|
||||
|
||||
if (chunk == null) {
|
||||
// CraftBukkit start
|
||||
ChunkRegionLoader loader = null;
|
||||
|
||||
if (this.chunkLoader instanceof ChunkRegionLoader) {
|
||||
loader = (ChunkRegionLoader) this.chunkLoader;
|
||||
}
|
||||
if (loader != null && loader.chunkExists(i, j)) {
|
||||
chunk = ChunkIOExecutor.syncChunkLoad(world, loader, this, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Chunk originalGetOrLoadChunkAt(int i, int j) {
|
||||
// CraftBukkit end
|
||||
Chunk chunk = this.getLoadedChunkAt(i, j);
|
||||
|
||||
if (chunk == null) {
|
||||
chunk = this.loadChunk(i, j);
|
||||
if (chunk != null) {
|
||||
this.chunks.put(ChunkCoordIntPair.a(i, j), chunk);
|
||||
chunk.addEntities();
|
||||
chunk.loadNearby(this, this.chunkGenerator, false); // CraftBukkit
|
||||
}
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
public Chunk getChunkIfLoaded(int x, int z) {
|
||||
return chunks.get(ChunkCoordIntPair.a(x, z));
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
public Chunk getChunkAt(int i, int j) {
|
||||
return getChunkAt(i, j, null);
|
||||
}
|
||||
|
||||
public Chunk getChunkAt(int i, int j, Runnable runnable) {
|
||||
return getChunkAt(i, j, runnable, true);
|
||||
}
|
||||
|
||||
public Chunk getChunkAt(int i, int j, Runnable runnable, boolean generate) {
|
||||
Chunk chunk = world.paperConfig.allowPermaChunkLoaders ? getLoadedChunkAt(i, j) : getChunkIfLoaded(i, j); // Paper - Configurable perma chunk loaders
|
||||
ChunkRegionLoader loader = null;
|
||||
|
||||
if (this.chunkLoader instanceof ChunkRegionLoader) {
|
||||
loader = (ChunkRegionLoader) this.chunkLoader;
|
||||
|
||||
}
|
||||
// We can only use the queue for already generated chunks
|
||||
if (chunk == null && loader != null && loader.chunkExists(i, j)) {
|
||||
if (runnable != null) {
|
||||
ChunkIOExecutor.queueChunkLoad(world, loader, this, i, j, runnable);
|
||||
return null;
|
||||
} else {
|
||||
chunk = ChunkIOExecutor.syncChunkLoad(world, loader, this, i, j);
|
||||
|
||||
// Paper start - If there was an issue loading the chunk from region, stage1 will fail and stage2 will load it sync
|
||||
// all we need to do is fetch an instance
|
||||
if (chunk == null) {
|
||||
chunk = getChunkIfLoaded(i, j);
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
} else if (chunk == null && generate) {
|
||||
chunk = originalGetChunkAt(i, j);
|
||||
}
|
||||
|
||||
// If we didn't load the chunk async and have a callback run it now
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public Chunk originalGetChunkAt(int i, int j) {
|
||||
Chunk chunk = this.originalGetOrLoadChunkAt(i, j);
|
||||
// CraftBukkit end
|
||||
|
||||
if (chunk == null) {
|
||||
world.timings.syncChunkLoadTimer.startTiming(); // Spigot
|
||||
long k = ChunkCoordIntPair.a(i, j);
|
||||
|
||||
try {
|
||||
chunk = this.chunkGenerator.getOrCreateChunk(i, j);
|
||||
} catch (Throwable throwable) {
|
||||
CrashReport crashreport = CrashReport.a(throwable, "Exception generating new chunk");
|
||||
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Chunk to be generated");
|
||||
|
||||
crashreportsystemdetails.a("Location", (Object) String.format("%d,%d", new Object[] { Integer.valueOf(i), Integer.valueOf(j)}));
|
||||
crashreportsystemdetails.a("Position hash", (Object) Long.valueOf(k));
|
||||
crashreportsystemdetails.a("Generator", (Object) this.chunkGenerator);
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
|
||||
this.chunks.put(k, chunk);
|
||||
chunk.addEntities();
|
||||
chunk.loadNearby(this, this.chunkGenerator, true); // CraftBukkit
|
||||
world.timings.syncChunkLoadTimer.stopTiming(); // Spigot
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Chunk loadChunk(int i, int j) {
|
||||
try {
|
||||
Chunk chunk = this.chunkLoader.a(this.world, i, j);
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.setLastSaved(this.world.getTime());
|
||||
this.chunkGenerator.recreateStructures(chunk, i, j);
|
||||
}
|
||||
|
||||
return chunk;
|
||||
} catch (Exception exception) {
|
||||
// Paper start
|
||||
String msg = "Couldn\'t load chunk";
|
||||
ChunkProviderServer.a.error(msg, exception);
|
||||
ServerInternalException.reportInternalException(exception);
|
||||
// Paper end
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChunkNOP(Chunk chunk) {
|
||||
try {
|
||||
// this.chunkLoader.b(this.world, chunk); // Spigot
|
||||
} catch (Exception exception) {
|
||||
// Paper start
|
||||
String msg = "Couldn\'t save entities";
|
||||
ChunkProviderServer.a.error(msg, exception);
|
||||
ServerInternalException.reportInternalException(exception);
|
||||
// Paper end
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void saveChunk(Chunk chunk, boolean unloaded) { // Spigot
|
||||
try (co.aikar.timings.Timing timed = world.timings.chunkSaveData.startTiming()) {
|
||||
chunk.setLastSaved(this.world.getTime());
|
||||
this.chunkLoader.saveChunk(this.world, chunk, unloaded); // Spigot
|
||||
} catch (IOException ioexception) {
|
||||
// Paper start
|
||||
String msg = "Couldn\'t save chunk";
|
||||
ChunkProviderServer.a.error(msg, ioexception);
|
||||
ServerInternalException.reportInternalException(ioexception);
|
||||
} catch (ExceptionWorldConflict exceptionworldconflict) {
|
||||
String msg = "Couldn\'t save chunk; already in use by another instance of Minecraft?";
|
||||
ChunkProviderServer.a.error(msg, exceptionworldconflict);
|
||||
ServerInternalException.reportInternalException(exceptionworldconflict);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean a(boolean flag) {
|
||||
int i = 0;
|
||||
|
||||
// CraftBukkit start
|
||||
// Paper start
|
||||
final ChunkRegionLoader chunkLoader = (ChunkRegionLoader) world.getChunkProviderServer().chunkLoader;
|
||||
final int queueSize = chunkLoader.getQueueSize();
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
final long timeSince = (now - lastSaveStatPrinted) / 1000;
|
||||
final Integer printRateSecs = Integer.getInteger("printSaveStats");
|
||||
if (printRateSecs != null && timeSince >= printRateSecs) {
|
||||
final String timeStr = "/" + timeSince +"s";
|
||||
final long queuedSaves = chunkLoader.getQueuedSaves();
|
||||
long queuedDiff = queuedSaves - lastQueuedSaves;
|
||||
lastQueuedSaves = queuedSaves;
|
||||
|
||||
final long processedSaves = chunkLoader.getProcessedSaves();
|
||||
long processedDiff = processedSaves - lastProcessedSaves;
|
||||
lastProcessedSaves = processedSaves;
|
||||
|
||||
lastSaveStatPrinted = now;
|
||||
if (processedDiff > 0 || queueSize > 0 || queuedDiff > 0) {
|
||||
System.out.println("[Chunk Save Stats] " + world.worldData.getName() +
|
||||
" - Current: " + queueSize +
|
||||
" - Queued: " + queuedDiff + timeStr +
|
||||
" - Processed: " +processedDiff + timeStr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (queueSize > world.paperConfig.queueSizeAutoSaveThreshold){
|
||||
return false;
|
||||
}
|
||||
final int autoSaveLimit = world.paperConfig.maxAutoSaveChunksPerTick;
|
||||
// Paper end
|
||||
Iterator iterator = this.chunks.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Chunk chunk = (Chunk) iterator.next();
|
||||
// CraftBukkit end
|
||||
|
||||
if (flag) {
|
||||
this.saveChunkNOP(chunk);
|
||||
}
|
||||
|
||||
if (chunk.a(flag)) {
|
||||
this.saveChunk(chunk, false); // Spigot
|
||||
chunk.f(false);
|
||||
++i;
|
||||
if (!flag && i >= autoSaveLimit) { // Spigot - // Paper - Incremental Auto Save - cap max per tick
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void c() {
|
||||
this.chunkLoader.c();
|
||||
}
|
||||
|
||||
private static final double UNLOAD_QUEUE_RESIZE_FACTOR = 0.96;
|
||||
|
||||
public boolean unloadChunks() {
|
||||
if (!this.world.savingDisabled) {
|
||||
if (!this.unloadQueue.isEmpty()) {
|
||||
// Spigot start
|
||||
org.spigotmc.SlackActivityAccountant activityAccountant = this.world.getMinecraftServer().slackActivityAccountant;
|
||||
activityAccountant.startActivity(0.5);
|
||||
int targetSize = Math.min(this.unloadQueue.size() - 100, (int) (this.unloadQueue.size() * UNLOAD_QUEUE_RESIZE_FACTOR)); // Paper - Make more aggressive
|
||||
// Spigot end
|
||||
|
||||
LongIterator iterator = this.unloadQueue.iterator();
|
||||
|
||||
while (iterator.hasNext()) { // Spigot
|
||||
Long chunkKey = iterator.nextLong();
|
||||
iterator.remove(); // Spigot
|
||||
Chunk chunk = (Chunk) this.chunks.get(chunkKey);
|
||||
|
||||
if (chunk != null && chunk.d) {
|
||||
// CraftBukkit start - move unload logic to own method
|
||||
chunk.setShouldUnload(false); // Paper
|
||||
if (!unloadChunk(chunk, true)) {
|
||||
continue;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
// Spigot start
|
||||
if (this.unloadQueue.size() <= targetSize && activityAccountant.activityTimeIsExhausted()) {
|
||||
break;
|
||||
}
|
||||
// Spigot end
|
||||
}
|
||||
}
|
||||
|
||||
activityAccountant.endActivity(); // Spigot
|
||||
}
|
||||
// Paper start - delayed chunk unloads
|
||||
long now = System.currentTimeMillis();
|
||||
long unloadAfter = world.paperConfig.delayChunkUnloadsBy;
|
||||
if (unloadAfter > 0) {
|
||||
//noinspection Convert2streamapi
|
||||
for (Chunk chunk : chunks.values()) {
|
||||
if (chunk.scheduledForUnload != null && now - chunk.scheduledForUnload > unloadAfter) {
|
||||
chunk.scheduledForUnload = null;
|
||||
unload(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
this.chunkLoader.b();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
public boolean unloadChunk(Chunk chunk, boolean save) {
|
||||
ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk, save);
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
save = event.isSaveChunk();
|
||||
chunk.lightingQueue.processUnload(); // Paper
|
||||
|
||||
// Update neighbor counts
|
||||
for (int x = -2; x < 3; x++) {
|
||||
for (int z = -2; z < 3; z++) {
|
||||
if (x == 0 && z == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z);
|
||||
if (neighbor != null) {
|
||||
neighbor.setNeighborUnloaded(-x, -z);
|
||||
chunk.setNeighborUnloaded(x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Moved from unloadChunks above
|
||||
chunk.removeEntities();
|
||||
if (save) {
|
||||
this.saveChunk(chunk, true); // Spigot
|
||||
this.saveChunkNOP(chunk);
|
||||
}
|
||||
this.chunks.remove(chunk.chunkKey);
|
||||
return true;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
public boolean e() {
|
||||
return !this.world.savingDisabled;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "ServerChunkCache: " + this.chunks.size() + " Drop: " + this.unloadQueue.size();
|
||||
}
|
||||
|
||||
public List<BiomeBase.BiomeMeta> a(EnumCreatureType enumcreaturetype, BlockPosition blockposition) {
|
||||
return this.chunkGenerator.getMobsFor(enumcreaturetype, blockposition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BlockPosition a(World world, String s, BlockPosition blockposition, boolean flag) {
|
||||
return this.chunkGenerator.findNearestMapFeature(world, s, blockposition, flag);
|
||||
}
|
||||
|
||||
public boolean a(World world, String s, BlockPosition blockposition) {
|
||||
return this.chunkGenerator.a(world, s, blockposition);
|
||||
}
|
||||
|
||||
public int g() {
|
||||
return this.chunks.size();
|
||||
}
|
||||
|
||||
public boolean isLoaded(int i, int j) {
|
||||
return this.chunks.containsKey(ChunkCoordIntPair.a(i, j));
|
||||
}
|
||||
|
||||
public boolean e(int i, int j) {
|
||||
return this.chunks.containsKey(ChunkCoordIntPair.a(i, j)) || this.chunkLoader.chunkExists(i, j);
|
||||
}
|
||||
}
|
||||
115
sources/src/main/java/net/minecraft/server/ContainerHorse.java
Normal file
115
sources/src/main/java/net/minecraft/server/ContainerHorse.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
// CraftBukkit start
|
||||
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
// CraftBukkit end
|
||||
|
||||
public class ContainerHorse extends Container {
|
||||
|
||||
private final IInventory a;
|
||||
private final EntityHorseAbstract f;
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity;
|
||||
PlayerInventory player;
|
||||
|
||||
@Override
|
||||
public InventoryView getBukkitView() {
|
||||
if (bukkitEntity != null) {
|
||||
return bukkitEntity;
|
||||
}
|
||||
|
||||
return bukkitEntity = new CraftInventoryView(player.player.getBukkitEntity(), a.getOwner().getInventory(), this);
|
||||
}
|
||||
|
||||
public ContainerHorse(IInventory iinventory, final IInventory iinventory1, final EntityHorseAbstract entityhorseabstract, EntityHuman entityhuman) {
|
||||
player = (PlayerInventory) iinventory;
|
||||
// CraftBukkit end
|
||||
this.a = iinventory1;
|
||||
this.f = entityhorseabstract;
|
||||
boolean flag = true;
|
||||
|
||||
iinventory1.startOpen(entityhuman);
|
||||
boolean flag1 = true;
|
||||
|
||||
this.a(new Slot(iinventory1, 0, 8, 18) {
|
||||
public boolean isAllowed(ItemStack itemstack) {
|
||||
return itemstack.getItem() == Items.SADDLE && !this.hasItem() && entityhorseabstract.dF();
|
||||
}
|
||||
});
|
||||
this.a(new Slot(iinventory1, 1, 8, 36) {
|
||||
public boolean isAllowed(ItemStack itemstack) {
|
||||
return entityhorseabstract.f(itemstack);
|
||||
}
|
||||
|
||||
public int getMaxStackSize() {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (entityhorseabstract instanceof EntityHorseChestedAbstract && ((EntityHorseChestedAbstract) entityhorseabstract).isCarryingChest()) {
|
||||
for (i = 0; i < 3; ++i) {
|
||||
for (j = 0; j < ((EntityHorseChestedAbstract) entityhorseabstract).dt(); ++j) {
|
||||
this.a(new Slot(iinventory1, 2 + j + i * ((EntityHorseChestedAbstract) entityhorseabstract).dt(), 80 + j * 18, 18 + i * 18));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
for (j = 0; j < 9; ++j) {
|
||||
this.a(new Slot(iinventory, j + i * 9 + 9, 8 + j * 18, 102 + i * 18 + -18));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; ++i) {
|
||||
this.a(new Slot(iinventory, i, 8 + i * 18, 142));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean canUse(EntityHuman entityhuman) {
|
||||
return this.a.a(entityhuman) && this.f.isAlive() && this.f.valid && this.f.g((Entity) entityhuman) < 8.0F; // NeonPaper! - Fix MC-161754
|
||||
}
|
||||
|
||||
public ItemStack shiftClick(EntityHuman entityhuman, int i) {
|
||||
ItemStack itemstack = ItemStack.a;
|
||||
Slot slot = (Slot) this.slots.get(i);
|
||||
|
||||
if (slot != null && slot.hasItem()) {
|
||||
ItemStack itemstack1 = slot.getItem();
|
||||
|
||||
itemstack = itemstack1.cloneItemStack();
|
||||
if (i < this.a.getSize()) {
|
||||
if (!this.a(itemstack1, this.a.getSize(), this.slots.size(), true)) {
|
||||
return ItemStack.a;
|
||||
}
|
||||
} else if (this.getSlot(1).isAllowed(itemstack1) && !this.getSlot(1).hasItem()) {
|
||||
if (!this.a(itemstack1, 1, 2, false)) {
|
||||
return ItemStack.a;
|
||||
}
|
||||
} else if (this.getSlot(0).isAllowed(itemstack1)) {
|
||||
if (!this.a(itemstack1, 0, 1, false)) {
|
||||
return ItemStack.a;
|
||||
}
|
||||
} else if (this.a.getSize() <= 2 || !this.a(itemstack1, 2, this.a.getSize(), false)) {
|
||||
return ItemStack.a;
|
||||
}
|
||||
|
||||
if (itemstack1.isEmpty()) {
|
||||
slot.set(ItemStack.a);
|
||||
} else {
|
||||
slot.f();
|
||||
}
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
public void b(EntityHuman entityhuman) {
|
||||
super.b(entityhuman);
|
||||
this.a.closeContainer(entityhuman);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,868 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
// CraftBukkit start
|
||||
import java.util.List;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.TreeType;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.event.block.BlockDispenseEvent;
|
||||
import org.bukkit.event.world.StructureGrowEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class DispenserRegistry {
|
||||
|
||||
public static final PrintStream a = System.out;
|
||||
private static boolean c;
|
||||
public static boolean b;
|
||||
private static final Logger d = LogManager.getLogger();
|
||||
|
||||
public static boolean a() {
|
||||
return DispenserRegistry.c;
|
||||
}
|
||||
|
||||
static void b() {
|
||||
BlockDispenser.REGISTRY.a(Items.ARROW, new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack) {
|
||||
EntityTippedArrow entitytippedarrow = new EntityTippedArrow(world, iposition.getX(), iposition.getY(), iposition.getZ());
|
||||
|
||||
entitytippedarrow.fromPlayer = EntityArrow.PickupStatus.ALLOWED;
|
||||
return entitytippedarrow;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.TIPPED_ARROW, new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack) {
|
||||
EntityTippedArrow entitytippedarrow = new EntityTippedArrow(world, iposition.getX(), iposition.getY(), iposition.getZ());
|
||||
|
||||
entitytippedarrow.a(itemstack);
|
||||
entitytippedarrow.fromPlayer = EntityArrow.PickupStatus.ALLOWED;
|
||||
return entitytippedarrow;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.SPECTRAL_ARROW, new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack) {
|
||||
EntitySpectralArrow entityspectralarrow = new EntitySpectralArrow(world, iposition.getX(), iposition.getY(), iposition.getZ());
|
||||
|
||||
entityspectralarrow.fromPlayer = EntityArrow.PickupStatus.ALLOWED;
|
||||
return entityspectralarrow;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.EGG, new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack) {
|
||||
return new EntityEgg(world, iposition.getX(), iposition.getY(), iposition.getZ());
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.SNOWBALL, new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack) {
|
||||
return new EntitySnowball(world, iposition.getX(), iposition.getY(), iposition.getZ());
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.EXPERIENCE_BOTTLE, new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack) {
|
||||
return new EntityThrownExpBottle(world, iposition.getX(), iposition.getY(), iposition.getZ());
|
||||
}
|
||||
|
||||
protected float a() {
|
||||
return super.a() * 0.5F;
|
||||
}
|
||||
|
||||
protected float getPower() {
|
||||
return super.getPower() * 1.25F;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.SPLASH_POTION, new IDispenseBehavior() {
|
||||
public ItemStack a(ISourceBlock isourceblock, final ItemStack itemstack) {
|
||||
return (new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack1) { // CraftBukkit - decompile issue
|
||||
return new EntityPotion(world, iposition.getX(), iposition.getY(), iposition.getZ(), itemstack1.cloneItemStack());
|
||||
}
|
||||
|
||||
protected float a() {
|
||||
return super.a() * 0.5F;
|
||||
}
|
||||
|
||||
protected float getPower() {
|
||||
return super.getPower() * 1.25F;
|
||||
}
|
||||
}).a(isourceblock, itemstack);
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.LINGERING_POTION, new IDispenseBehavior() {
|
||||
public ItemStack a(ISourceBlock isourceblock, final ItemStack itemstack) {
|
||||
return (new DispenseBehaviorProjectile() {
|
||||
protected IProjectile a(World world, IPosition iposition, ItemStack itemstack1) { // CraftBukkit - decompile issue
|
||||
return new EntityPotion(world, iposition.getX(), iposition.getY(), iposition.getZ(), itemstack1.cloneItemStack());
|
||||
}
|
||||
|
||||
protected float a() {
|
||||
return super.a() * 0.5F;
|
||||
}
|
||||
|
||||
protected float getPower() {
|
||||
return super.getPower() * 1.25F;
|
||||
}
|
||||
}).a(isourceblock, itemstack);
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.SPAWN_EGG, new DispenseBehaviorItem() {
|
||||
public ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
EnumDirection enumdirection = (EnumDirection) isourceblock.e().get(BlockDispenser.FACING);
|
||||
double d0 = isourceblock.getX() + (double) enumdirection.getAdjacentX();
|
||||
double d1 = (double) ((float) (isourceblock.getBlockPosition().getY() + enumdirection.getAdjacentY()) + 0.2F);
|
||||
double d2 = isourceblock.getZ() + (double) enumdirection.getAdjacentZ();
|
||||
// Entity entity = ItemMonsterEgg.a(isourceblock.getWorld(), ItemMonsterEgg.h(itemstack), d0, d1, d2);
|
||||
|
||||
// CraftBukkit start
|
||||
World world = isourceblock.getWorld();
|
||||
ItemStack itemstack1 = itemstack.cloneAndSubtract(1);
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1, d2));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
itemstack.add(1);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
itemstack.add(1);
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
itemstack1 = CraftItemStack.asNMSCopy(event.getItem());
|
||||
|
||||
Entity entity = ItemMonsterEgg.spawnCreature(isourceblock.getWorld(), ItemMonsterEgg.h(itemstack), event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DISPENSE_EGG);
|
||||
|
||||
if (entity instanceof EntityLiving && itemstack.hasName()) {
|
||||
entity.setCustomName(itemstack.getName());
|
||||
}
|
||||
|
||||
ItemMonsterEgg.a(isourceblock.getWorld(), (EntityHuman) null, itemstack, entity);
|
||||
// itemstack.subtract(1);// Handled during event processing
|
||||
// CraftBukkit end
|
||||
return itemstack;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.FIREWORKS, new DispenseBehaviorItem() {
|
||||
public ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
EnumDirection enumdirection = (EnumDirection) isourceblock.e().get(BlockDispenser.FACING);
|
||||
double d0 = isourceblock.getX() + (double) enumdirection.getAdjacentX();
|
||||
double d1 = (double) ((float) isourceblock.getBlockPosition().getY() + 0.2F);
|
||||
double d2 = isourceblock.getZ() + (double) enumdirection.getAdjacentZ();
|
||||
// CraftBukkit start
|
||||
World world = isourceblock.getWorld();
|
||||
ItemStack itemstack1 = itemstack.cloneAndSubtract(1);
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1, d2));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
itemstack.add(1);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
itemstack.add(1);
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
itemstack1 = CraftItemStack.asNMSCopy(event.getItem());
|
||||
EntityFireworks entityfireworks = new EntityFireworks(isourceblock.getWorld(), event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), itemstack1);
|
||||
|
||||
isourceblock.getWorld().addEntity(entityfireworks);
|
||||
// itemstack.subtract(1); // Handled during event processing
|
||||
// CraftBukkit end
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
protected void a(ISourceBlock isourceblock) {
|
||||
isourceblock.getWorld().triggerEffect(1004, isourceblock.getBlockPosition(), 0);
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.FIRE_CHARGE, new DispenseBehaviorItem() {
|
||||
public ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
EnumDirection enumdirection = (EnumDirection) isourceblock.e().get(BlockDispenser.FACING);
|
||||
IPosition iposition = BlockDispenser.a(isourceblock);
|
||||
double d0 = iposition.getX() + (double) ((float) enumdirection.getAdjacentX() * 0.3F);
|
||||
double d1 = iposition.getY() + (double) ((float) enumdirection.getAdjacentY() * 0.3F);
|
||||
double d2 = iposition.getZ() + (double) ((float) enumdirection.getAdjacentZ() * 0.3F);
|
||||
World world = isourceblock.getWorld();
|
||||
Random random = world.random;
|
||||
double d3 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentX();
|
||||
double d4 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentY();
|
||||
double d5 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentZ();
|
||||
|
||||
// CraftBukkit start
|
||||
ItemStack itemstack1 = itemstack.cloneAndSubtract(1);
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d3, d4, d5));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
itemstack.add(1);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
itemstack.add(1);
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
EntitySmallFireball fireball = new EntitySmallFireball(world, d0, d1, d2, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ());
|
||||
fireball.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource((TileEntityDispenser) isourceblock.getTileEntity());
|
||||
|
||||
world.addEntity(fireball);
|
||||
// itemstack.subtract(1); // Handled during event processing
|
||||
// CraftBukkit end
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
protected void a(ISourceBlock isourceblock) {
|
||||
isourceblock.getWorld().triggerEffect(1018, isourceblock.getBlockPosition(), 0);
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.aH, new DispenserRegistry.a(EntityBoat.EnumBoatType.OAK));
|
||||
BlockDispenser.REGISTRY.a(Items.aI, new DispenserRegistry.a(EntityBoat.EnumBoatType.SPRUCE));
|
||||
BlockDispenser.REGISTRY.a(Items.aJ, new DispenserRegistry.a(EntityBoat.EnumBoatType.BIRCH));
|
||||
BlockDispenser.REGISTRY.a(Items.aK, new DispenserRegistry.a(EntityBoat.EnumBoatType.JUNGLE));
|
||||
BlockDispenser.REGISTRY.a(Items.aM, new DispenserRegistry.a(EntityBoat.EnumBoatType.DARK_OAK));
|
||||
BlockDispenser.REGISTRY.a(Items.aL, new DispenserRegistry.a(EntityBoat.EnumBoatType.ACACIA));
|
||||
DispenseBehaviorItem dispensebehavioritem = new DispenseBehaviorItem() {
|
||||
private final DispenseBehaviorItem b = new DispenseBehaviorItem();
|
||||
|
||||
public ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
ItemBucket itembucket = (ItemBucket) itemstack.getItem();
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift((EnumDirection) isourceblock.e().get(BlockDispenser.FACING));
|
||||
|
||||
// CraftBukkit start
|
||||
World world = isourceblock.getWorld();
|
||||
int x = blockposition.getX();
|
||||
int y = blockposition.getY();
|
||||
int z = blockposition.getZ();
|
||||
if (world.isEmpty(blockposition) || !world.getType(blockposition).getMaterial().isBuildable()) {
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
itembucket = (ItemBucket) CraftItemStack.asNMSCopy(event.getItem()).getItem();
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (itembucket.a((EntityHuman) null, isourceblock.getWorld(), blockposition)) {
|
||||
// CraftBukkit start - Handle stacked buckets
|
||||
Item item = Items.BUCKET;
|
||||
itemstack.subtract(1);
|
||||
if (itemstack.isEmpty()) {
|
||||
itemstack.setItem(Items.BUCKET);
|
||||
itemstack.setCount(1);
|
||||
} else if (((TileEntityDispenser) isourceblock.getTileEntity()).addItem(new ItemStack(item)) < 0) {
|
||||
this.b.a(isourceblock, new ItemStack(item));
|
||||
}
|
||||
// CraftBukkit end
|
||||
return itemstack;
|
||||
} else {
|
||||
return this.b.a(isourceblock, itemstack);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BlockDispenser.REGISTRY.a(Items.LAVA_BUCKET, dispensebehavioritem);
|
||||
BlockDispenser.REGISTRY.a(Items.WATER_BUCKET, dispensebehavioritem);
|
||||
BlockDispenser.REGISTRY.a(Items.BUCKET, new DispenseBehaviorItem() {
|
||||
private final DispenseBehaviorItem b = new DispenseBehaviorItem();
|
||||
|
||||
public ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
World world = isourceblock.getWorld();
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift((EnumDirection) isourceblock.e().get(BlockDispenser.FACING));
|
||||
IBlockData iblockdata = world.getType(blockposition);
|
||||
Block block = iblockdata.getBlock();
|
||||
Material material = iblockdata.getMaterial();
|
||||
Item item;
|
||||
|
||||
if (Material.WATER.equals(material) && block instanceof BlockFluids && ((Integer) iblockdata.get(BlockFluids.LEVEL)).intValue() == 0) {
|
||||
item = Items.WATER_BUCKET;
|
||||
} else {
|
||||
if (!Material.LAVA.equals(material) || !(block instanceof BlockFluids) || ((Integer) iblockdata.get(BlockFluids.LEVEL)).intValue() != 0) {
|
||||
return super.b(isourceblock, itemstack);
|
||||
}
|
||||
|
||||
item = Items.LAVA_BUCKET;
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
world.setAir(blockposition);
|
||||
itemstack.subtract(1);
|
||||
if (itemstack.isEmpty()) {
|
||||
return new ItemStack(item);
|
||||
} else {
|
||||
if (((TileEntityDispenser) isourceblock.getTileEntity()).addItem(new ItemStack(item)) < 0) {
|
||||
this.b.a(isourceblock, new ItemStack(item));
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.FLINT_AND_STEEL, new DispenserRegistry.b() {
|
||||
protected ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
World world = isourceblock.getWorld();
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
this.b = true;
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift((EnumDirection) isourceblock.e().get(BlockDispenser.FACING));
|
||||
|
||||
if (world.isEmpty(blockposition)) {
|
||||
// CraftBukkit start - Ignition by dispensing flint and steel
|
||||
if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()).isCancelled()) {
|
||||
world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData());
|
||||
if (itemstack.isDamaged(1, world.random, (EntityPlayer) null)) {
|
||||
itemstack.setCount(0);
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
} else if (world.getType(blockposition).getBlock() == Blocks.TNT) {
|
||||
Blocks.TNT.postBreak(world, blockposition, Blocks.TNT.getBlockData().set(BlockTNT.EXPLODE, Boolean.valueOf(true)));
|
||||
world.setAir(blockposition);
|
||||
} else {
|
||||
this.b = false;
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.DYE, new DispenserRegistry.b() {
|
||||
protected ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
this.b = true;
|
||||
if (EnumColor.WHITE == EnumColor.fromInvColorIndex(itemstack.getData())) {
|
||||
World world = isourceblock.getWorld();
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift((EnumDirection) isourceblock.e().get(BlockDispenser.FACING));
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
world.captureTreeGeneration = true;
|
||||
// CraftBukkit end
|
||||
|
||||
if (ItemDye.a(itemstack, world, blockposition)) {
|
||||
if (!world.isClientSide) {
|
||||
world.triggerEffect(2005, blockposition, 0);
|
||||
}
|
||||
} else {
|
||||
this.b = false;
|
||||
}
|
||||
// CraftBukkit start
|
||||
world.captureTreeGeneration = false;
|
||||
if (world.capturedBlockStates.size() > 0) {
|
||||
TreeType treeType = BlockSapling.treeType;
|
||||
BlockSapling.treeType = null;
|
||||
Location location = new Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
List<org.bukkit.block.BlockState> blocks = (List<org.bukkit.block.BlockState>) world.capturedBlockStates.clone();
|
||||
world.capturedBlockStates.clear();
|
||||
StructureGrowEvent structureEvent = null;
|
||||
if (treeType != null) {
|
||||
structureEvent = new StructureGrowEvent(location, treeType, false, null, blocks);
|
||||
org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent);
|
||||
}
|
||||
if (structureEvent == null || !structureEvent.isCancelled()) {
|
||||
for (org.bukkit.block.BlockState blockstate : blocks) {
|
||||
blockstate.update(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
return itemstack;
|
||||
} else {
|
||||
return super.b(isourceblock, itemstack);
|
||||
}
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Item.getItemOf(Blocks.TNT), new DispenseBehaviorItem() {
|
||||
protected ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
World world = isourceblock.getWorld();
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift((EnumDirection) isourceblock.e().get(BlockDispenser.FACING));
|
||||
// EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, (EntityLiving) null);
|
||||
|
||||
// CraftBukkit start
|
||||
ItemStack itemstack1 = itemstack.cloneAndSubtract(1);
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
itemstack.add(1);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
itemstack.add(1);
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), (EntityLiving) null);
|
||||
// CraftBukkit end
|
||||
|
||||
world.addEntity(entitytntprimed);
|
||||
world.a((EntityHuman) null, entitytntprimed.locX, entitytntprimed.locY, entitytntprimed.locZ, SoundEffects.hW, SoundCategory.BLOCKS, 1.0F, 1.0F);
|
||||
// itemstack.subtract(1); // CraftBukkit - handled above
|
||||
return itemstack;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Items.SKULL, new DispenserRegistry.b() {
|
||||
protected ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
World world = isourceblock.getWorld();
|
||||
EnumDirection enumdirection = (EnumDirection) isourceblock.e().get(BlockDispenser.FACING);
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift(enumdirection);
|
||||
BlockSkull blockskull = Blocks.SKULL;
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
this.b = true;
|
||||
if (world.isEmpty(blockposition) && blockskull.b(world, blockposition, itemstack)) {
|
||||
if (!world.isClientSide) {
|
||||
world.setTypeAndData(blockposition, blockskull.getBlockData().set(BlockSkull.FACING, EnumDirection.UP), 3);
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
|
||||
if (tileentity instanceof TileEntitySkull) {
|
||||
if (itemstack.getData() == 3) {
|
||||
GameProfile gameprofile = null;
|
||||
|
||||
if (itemstack.hasTag()) {
|
||||
NBTTagCompound nbttagcompound = itemstack.getTag();
|
||||
|
||||
if (nbttagcompound.hasKeyOfType("SkullOwner", 10)) {
|
||||
gameprofile = GameProfileSerializer.deserialize(nbttagcompound.getCompound("SkullOwner"));
|
||||
} else if (nbttagcompound.hasKeyOfType("SkullOwner", 8)) {
|
||||
String s = nbttagcompound.getString("SkullOwner");
|
||||
|
||||
if (!UtilColor.b(s)) {
|
||||
gameprofile = new GameProfile((UUID) null, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
((TileEntitySkull) tileentity).setGameProfile(gameprofile);
|
||||
} else {
|
||||
((TileEntitySkull) tileentity).setSkullType(itemstack.getData());
|
||||
}
|
||||
|
||||
((TileEntitySkull) tileentity).setRotation(enumdirection.opposite().get2DRotationValue() * 4);
|
||||
Blocks.SKULL.a(world, blockposition, (TileEntitySkull) tileentity);
|
||||
}
|
||||
|
||||
itemstack.subtract(1);
|
||||
}
|
||||
} else if (ItemArmor.a(isourceblock, itemstack).isEmpty()) {
|
||||
this.b = false;
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
});
|
||||
BlockDispenser.REGISTRY.a(Item.getItemOf(Blocks.PUMPKIN), new DispenserRegistry.b() {
|
||||
protected ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
World world = isourceblock.getWorld();
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift((EnumDirection) isourceblock.e().get(BlockDispenser.FACING));
|
||||
BlockPumpkin blockpumpkin = (BlockPumpkin) Blocks.PUMPKIN;
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
this.b = true;
|
||||
if (world.isEmpty(blockposition) && blockpumpkin.b(world, blockposition)) {
|
||||
if (!world.isClientSide) {
|
||||
world.setTypeAndData(blockposition, blockpumpkin.getBlockData(), 3);
|
||||
}
|
||||
|
||||
itemstack.subtract(1);
|
||||
} else {
|
||||
ItemStack itemstack1 = ItemArmor.a(isourceblock, itemstack);
|
||||
|
||||
if (itemstack1.isEmpty()) {
|
||||
this.b = false;
|
||||
}
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
});
|
||||
EnumColor[] aenumcolor = EnumColor.values();
|
||||
int i = aenumcolor.length;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
EnumColor enumcolor = aenumcolor[j];
|
||||
|
||||
BlockDispenser.REGISTRY.a(Item.getItemOf(BlockShulkerBox.a(enumcolor)), new DispenserRegistry.c(null));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void c() {
|
||||
if (!DispenserRegistry.c) {
|
||||
DispenserRegistry.c = true;
|
||||
d();
|
||||
SoundEffect.b();
|
||||
Block.w();
|
||||
BlockFire.e();
|
||||
MobEffectList.k();
|
||||
Enchantment.g();
|
||||
Item.t();
|
||||
PotionRegistry.b();
|
||||
PotionBrewer.a();
|
||||
EntityTypes.c();
|
||||
BiomeBase.q();
|
||||
b();
|
||||
if (!CraftingManager.init()) {
|
||||
DispenserRegistry.b = true;
|
||||
DispenserRegistry.d.error("Errors with built-in recipes!");
|
||||
}
|
||||
|
||||
StatisticList.a();
|
||||
if (DispenserRegistry.d.isDebugEnabled()) {
|
||||
if ((new AdvancementDataWorld((File) null)).b()) {
|
||||
DispenserRegistry.b = true;
|
||||
DispenserRegistry.d.error("Errors with built-in advancements!");
|
||||
}
|
||||
|
||||
if (!LootTables.b()) {
|
||||
DispenserRegistry.b = true;
|
||||
DispenserRegistry.d.error("Errors with built-in loot tables");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void d() {
|
||||
if (DispenserRegistry.d.isDebugEnabled()) {
|
||||
System.setErr(new DebugOutputStream("STDERR", System.err));
|
||||
System.setOut(new DebugOutputStream("STDOUT", DispenserRegistry.a));
|
||||
} else {
|
||||
System.setErr(new RedirectStream("STDERR", System.err));
|
||||
System.setOut(new RedirectStream("STDOUT", DispenserRegistry.a));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class c extends DispenserRegistry.b {
|
||||
|
||||
private c() {}
|
||||
|
||||
protected ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
Block block = Block.asBlock(itemstack.getItem());
|
||||
World world = isourceblock.getWorld();
|
||||
EnumDirection enumdirection = (EnumDirection) isourceblock.e().get(BlockDispenser.FACING);
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift(enumdirection);
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
this.b = world.a(block, blockposition, false, EnumDirection.DOWN, (Entity) null);
|
||||
if (this.b) {
|
||||
EnumDirection enumdirection1 = world.isEmpty(blockposition.down()) ? enumdirection : EnumDirection.UP;
|
||||
IBlockData iblockdata = block.getBlockData().set(BlockShulkerBox.a, enumdirection1);
|
||||
// Dionysus start - fix Dispenser crashes
|
||||
boolean wasPlaced = world.setTypeUpdate(blockposition, iblockdata);
|
||||
if (!wasPlaced) {
|
||||
return itemstack;
|
||||
}
|
||||
// Dionysus end
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
ItemStack itemstack1 = itemstack.cloneAndSubtract(1);
|
||||
|
||||
if (itemstack1.hasTag()) {
|
||||
((TileEntityShulkerBox) tileentity).e(itemstack1.getTag().getCompound("BlockEntityTag"));
|
||||
}
|
||||
|
||||
if (itemstack1.hasName()) {
|
||||
((TileEntityShulkerBox) tileentity).setCustomName(itemstack1.getName());
|
||||
}
|
||||
|
||||
world.updateAdjacentComparators(blockposition, iblockdata.getBlock());
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
c(Object object) {
|
||||
this();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class b extends DispenseBehaviorItem {
|
||||
|
||||
protected boolean b = true;
|
||||
|
||||
public b() {}
|
||||
|
||||
protected void a(ISourceBlock isourceblock) {
|
||||
isourceblock.getWorld().triggerEffect(this.b ? 1000 : 1001, isourceblock.getBlockPosition(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static class a extends DispenseBehaviorItem {
|
||||
|
||||
private final DispenseBehaviorItem b = new DispenseBehaviorItem();
|
||||
private final EntityBoat.EnumBoatType c;
|
||||
|
||||
public a(EntityBoat.EnumBoatType entityboat_enumboattype) {
|
||||
this.c = entityboat_enumboattype;
|
||||
}
|
||||
|
||||
public ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) {
|
||||
EnumDirection enumdirection = (EnumDirection) isourceblock.e().get(BlockDispenser.FACING);
|
||||
World world = isourceblock.getWorld();
|
||||
double d0 = isourceblock.getX() + (double) ((float) enumdirection.getAdjacentX() * 1.125F);
|
||||
double d1 = isourceblock.getY() + (double) ((float) enumdirection.getAdjacentY() * 1.125F);
|
||||
double d2 = isourceblock.getZ() + (double) ((float) enumdirection.getAdjacentZ() * 1.125F);
|
||||
BlockPosition blockposition = isourceblock.getBlockPosition().shift(enumdirection);
|
||||
Material material = world.getType(blockposition).getMaterial();
|
||||
double d3;
|
||||
|
||||
if (Material.WATER.equals(material)) {
|
||||
d3 = 1.0D;
|
||||
} else {
|
||||
if (!Material.AIR.equals(material) || !Material.WATER.equals(world.getType(blockposition.down()).getMaterial())) {
|
||||
return this.b.a(isourceblock, itemstack);
|
||||
}
|
||||
|
||||
d3 = 0.0D;
|
||||
}
|
||||
|
||||
// EntityBoat entityboat = new EntityBoat(world, d0, d1 + d3, d2);
|
||||
// CraftBukkit start
|
||||
ItemStack itemstack1 = itemstack.cloneAndSubtract(1);
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
|
||||
|
||||
BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2));
|
||||
if (!BlockDispenser.eventFired) {
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
itemstack.add(1);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
if (!event.getItem().equals(craftItem)) {
|
||||
itemstack.add(1);
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.REGISTRY.get(eventStack.getItem());
|
||||
if (idispensebehavior != IDispenseBehavior.NONE && idispensebehavior != this) {
|
||||
idispensebehavior.a(isourceblock, eventStack);
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
EntityBoat entityboat = new EntityBoat(world, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ());
|
||||
// CraftBukkit end
|
||||
|
||||
entityboat.setType(this.c);
|
||||
entityboat.yaw = enumdirection.l();
|
||||
if (!world.addEntity(entityboat)) itemstack.add(1); // CraftBukkit
|
||||
// itemstack.subtract(1); // CraftBukkit - handled during event processing
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
protected void a(ISourceBlock isourceblock) {
|
||||
isourceblock.getWorld().triggerEffect(1000, isourceblock.getBlockPosition(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,6 +118,7 @@ public class EnchantmentManager {
|
||||
EnchantmentManager.a.a = 0;
|
||||
EnchantmentManager.a.b = damagesource;
|
||||
a(EnchantmentManager.a, iterable);
|
||||
EnchantmentManager.a.b = null; // Reaper - Fix MC-128547
|
||||
return EnchantmentManager.a.a;
|
||||
}
|
||||
|
||||
@@ -144,6 +145,11 @@ public class EnchantmentManager {
|
||||
if (entity instanceof EntityHuman) {
|
||||
a(EnchantmentManager.c, entityliving.getItemInMainHand());
|
||||
}
|
||||
|
||||
// Reaper start - Fix MC-128547
|
||||
EnchantmentManager.c.b = null;
|
||||
EnchantmentManager.c.a = null;
|
||||
// Reaper end
|
||||
|
||||
}
|
||||
|
||||
@@ -157,7 +163,10 @@ public class EnchantmentManager {
|
||||
if (entityliving instanceof EntityHuman) {
|
||||
a(EnchantmentManager.d, entityliving.getItemInMainHand());
|
||||
}
|
||||
|
||||
// Reaper start - Fix MC-128547
|
||||
EnchantmentManager.d.b = null;
|
||||
EnchantmentManager.d.a = null;
|
||||
// Reaper end
|
||||
}
|
||||
|
||||
public static int a(Enchantment enchantment, EntityLiving entityliving) {
|
||||
|
||||
@@ -45,6 +45,10 @@ import org.bukkit.event.entity.EntityPortalEvent;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
// CraftBukkit end
|
||||
|
||||
// Dionysus start
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
// Dionysus end
|
||||
|
||||
/**
|
||||
* Akarin Changes Note
|
||||
* 1) Random -> LightRandom (performance)
|
||||
@@ -91,7 +95,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
private static int entityCount = 1; // Paper - MC-111480 - ID 0 is treated as special for DataWatchers, start 1
|
||||
private int id;
|
||||
public boolean i; public boolean blocksEntitySpawning() { return i; } // Paper - OBFHELPER
|
||||
public final List<Entity> passengers;
|
||||
public final ObjectArrayList<Entity> passengers; // Dionysus
|
||||
protected int j;
|
||||
private Entity au;public void setVehicle(Entity entity) { this.au = entity; } // Paper // OBFHELPER
|
||||
public boolean attachedToPlayer;
|
||||
@@ -205,7 +209,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
|
||||
public Entity(World world) {
|
||||
this.id = Entity.entityCount++;
|
||||
this.passengers = Lists.newArrayList();
|
||||
this.passengers = new ObjectArrayList<>(); // Dionysus
|
||||
this.boundingBox = Entity.c;
|
||||
this.width = 0.6F;
|
||||
this.length = 1.8F;
|
||||
@@ -1383,37 +1387,33 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
public void d(EntityHuman entityhuman) {}
|
||||
|
||||
public void collide(Entity entity) {
|
||||
if (!this.x(entity)) {
|
||||
if (!entity.noclip && !this.noclip) {
|
||||
double d0 = entity.locX - this.locX;
|
||||
double d1 = entity.locZ - this.locZ;
|
||||
double d2 = MathHelper.a(d0, d1);
|
||||
if (entity.noclip || this.noclip || this.x(entity)) return; // NeonPaper - Test this earlier
|
||||
double d0 = entity.locX - this.locX;
|
||||
double d1 = entity.locZ - this.locZ;
|
||||
double d2 = MathHelper.a(d0, d1);
|
||||
|
||||
if (d2 >= 0.009999999776482582D) {
|
||||
d2 = (double) MathHelper.sqrt(d2);
|
||||
d0 /= d2;
|
||||
d1 /= d2;
|
||||
double d3 = 1.0D / d2;
|
||||
if (d2 >= 0.009999999776482582D) {
|
||||
d2 = (double) MathHelper.sqrt(d2);
|
||||
d0 /= d2;
|
||||
d1 /= d2;
|
||||
double d3 = 1.0D / d2;
|
||||
|
||||
if (d3 > 1.0D) {
|
||||
d3 = 1.0D;
|
||||
}
|
||||
if (d3 > 1.0D) {
|
||||
d3 = 1.0D;
|
||||
}
|
||||
|
||||
d0 *= d3;
|
||||
d1 *= d3;
|
||||
d0 *= 0.05000000074505806D;
|
||||
d1 *= 0.05000000074505806D;
|
||||
d0 *= (double) (1.0F - this.R);
|
||||
d1 *= (double) (1.0F - this.R);
|
||||
if (!this.isVehicle()) {
|
||||
this.f(-d0, 0.0D, -d1);
|
||||
}
|
||||
|
||||
if (!entity.isVehicle()) {
|
||||
entity.f(d0, 0.0D, d1);
|
||||
}
|
||||
}
|
||||
d0 *= d3;
|
||||
d1 *= d3;
|
||||
d0 *= 0.05000000074505806D;
|
||||
d1 *= 0.05000000074505806D;
|
||||
d0 *= (double) (1.0F - this.R);
|
||||
d1 *= (double) (1.0F - this.R);
|
||||
if (!this.isVehicle()) {
|
||||
this.f(-d0, 0.0D, -d1);
|
||||
}
|
||||
|
||||
if (!entity.isVehicle()) {
|
||||
entity.f(d0, 0.0D, d1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2881,7 +2881,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
}
|
||||
|
||||
public List<Entity> bF() {
|
||||
return (List) (this.passengers.isEmpty() ? Collections.emptyList() : Lists.newArrayList(this.passengers));
|
||||
return (List) (this.passengers.isEmpty() ? Collections.emptyList() : new ObjectArrayList<>(this.passengers)); // Dionysus
|
||||
}
|
||||
|
||||
public boolean w(Entity entity) {
|
||||
|
||||
476
sources/src/main/java/net/minecraft/server/EntityEnderman.java
Normal file
476
sources/src/main/java/net/minecraft/server/EntityEnderman.java
Normal file
@@ -0,0 +1,476 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.destroystokyo.paper.event.entity.EndermanEscapeEvent;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.bukkit.event.entity.EntityTargetEvent;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class EntityEnderman extends EntityMonster {
|
||||
|
||||
private static final UUID a = UUID.fromString("020E0DFB-87AE-4653-9556-831010E291A0");
|
||||
private static final AttributeModifier b = (new AttributeModifier(EntityEnderman.a, "Attacking speed boost", 0.15000000596046448D, 0)).a(false);
|
||||
private static final Set<Block> c = Sets.newIdentityHashSet();
|
||||
private static final DataWatcherObject<Optional<IBlockData>> bx = DataWatcher.a(EntityEnderman.class, DataWatcherRegistry.g);
|
||||
private static final DataWatcherObject<Boolean> by = DataWatcher.a(EntityEnderman.class, DataWatcherRegistry.h);
|
||||
private int bz;
|
||||
private int bA;
|
||||
|
||||
public EntityEnderman(World world) {
|
||||
super(world);
|
||||
this.setSize(0.6F, 2.9F);
|
||||
this.P = 1.0F;
|
||||
this.a(PathType.WATER, -1.0F);
|
||||
}
|
||||
|
||||
protected void r() {
|
||||
this.goalSelector.a(0, new PathfinderGoalFloat(this));
|
||||
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
|
||||
this.goalSelector.a(7, new PathfinderGoalRandomStrollLand(this, 1.0D, 0.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this));
|
||||
this.goalSelector.a(10, new EntityEnderman.PathfinderGoalEndermanPlaceBlock(this));
|
||||
this.goalSelector.a(11, new EntityEnderman.PathfinderGoalEndermanPickupBlock(this));
|
||||
this.targetSelector.a(1, new EntityEnderman.PathfinderGoalPlayerWhoLookedAtTarget(this));
|
||||
this.targetSelector.a(2, new PathfinderGoalHurtByTarget(this, false, new Class[0]));
|
||||
this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget(this, EntityEndermite.class, 10, true, false, new Predicate() {
|
||||
public boolean a(@Nullable EntityEndermite entityendermite) {
|
||||
return entityendermite.p();
|
||||
}
|
||||
|
||||
public boolean apply(@Nullable Object object) {
|
||||
return this.a((EntityEndermite) object);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected void initAttributes() {
|
||||
super.initAttributes();
|
||||
this.getAttributeInstance(GenericAttributes.maxHealth).setValue(40.0D);
|
||||
this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.30000001192092896D);
|
||||
this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(7.0D);
|
||||
this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(64.0D);
|
||||
}
|
||||
|
||||
public void setGoalTarget(@Nullable EntityLiving entityliving) {
|
||||
// CraftBukkit start - fire event
|
||||
setGoalTarget(entityliving, EntityTargetEvent.TargetReason.UNKNOWN, true);
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private boolean tryEscape(EndermanEscapeEvent.Reason reason) {
|
||||
return new EndermanEscapeEvent((org.bukkit.craftbukkit.entity.CraftEnderman) this.getBukkitEntity(), reason).callEvent();
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
public boolean setGoalTarget(EntityLiving entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent) {
|
||||
if (!super.setGoalTarget(entityliving, reason, fireEvent)) {
|
||||
return false;
|
||||
}
|
||||
entityliving = getGoalTarget();
|
||||
// CraftBukkit end
|
||||
AttributeInstance attributeinstance = this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED);
|
||||
|
||||
if (entityliving == null) {
|
||||
this.bA = 0;
|
||||
this.datawatcher.set(EntityEnderman.by, Boolean.valueOf(false));
|
||||
attributeinstance.c(EntityEnderman.b);
|
||||
} else {
|
||||
this.bA = this.ticksLived;
|
||||
this.datawatcher.set(EntityEnderman.by, Boolean.valueOf(true));
|
||||
if (!attributeinstance.a(EntityEnderman.b)) {
|
||||
attributeinstance.b(EntityEnderman.b);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
protected void i() {
|
||||
super.i();
|
||||
this.datawatcher.register(EntityEnderman.bx, Optional.absent());
|
||||
this.datawatcher.register(EntityEnderman.by, Boolean.valueOf(false));
|
||||
}
|
||||
|
||||
public void p() {
|
||||
if (this.ticksLived >= this.bz + 400) {
|
||||
this.bz = this.ticksLived;
|
||||
if (!this.isSilent()) {
|
||||
this.world.a(this.locX, this.locY + (double) this.getHeadHeight(), this.locZ, SoundEffects.bh, this.bK(), 2.5F, 1.0F, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a(DataWatcherObject<?> datawatcherobject) {
|
||||
if (EntityEnderman.by.equals(datawatcherobject) && this.do_() && this.world.isClientSide) {
|
||||
this.p();
|
||||
}
|
||||
|
||||
super.a(datawatcherobject);
|
||||
}
|
||||
|
||||
public static void a(DataConverterManager dataconvertermanager) {
|
||||
EntityInsentient.a(dataconvertermanager, EntityEnderman.class);
|
||||
}
|
||||
|
||||
public void b(NBTTagCompound nbttagcompound) {
|
||||
super.b(nbttagcompound);
|
||||
IBlockData iblockdata = this.getCarried();
|
||||
|
||||
if (iblockdata != null) {
|
||||
nbttagcompound.setShort("carried", (short) Block.getId(iblockdata.getBlock()));
|
||||
nbttagcompound.setShort("carriedData", (short) iblockdata.getBlock().toLegacyData(iblockdata));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a(NBTTagCompound nbttagcompound) {
|
||||
super.a(nbttagcompound);
|
||||
IBlockData iblockdata;
|
||||
|
||||
if (nbttagcompound.hasKeyOfType("carried", 8)) {
|
||||
iblockdata = Block.getByName(nbttagcompound.getString("carried")).fromLegacyData(nbttagcompound.getShort("carriedData") & '\uffff');
|
||||
} else {
|
||||
iblockdata = Block.getById(nbttagcompound.getShort("carried")).fromLegacyData(nbttagcompound.getShort("carriedData") & '\uffff');
|
||||
}
|
||||
|
||||
if (iblockdata == null || iblockdata.getBlock() == null || iblockdata.getMaterial() == Material.AIR) {
|
||||
iblockdata = null;
|
||||
}
|
||||
|
||||
this.setCarried(iblockdata);
|
||||
}
|
||||
|
||||
// Paper start - OBFHELPER - ok not really, but verify this on updates
|
||||
private boolean f(EntityHuman entityhuman) {
|
||||
boolean shouldAttack = f_real(entityhuman);
|
||||
com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) entityhuman.getBukkitEntity());
|
||||
event.setCancelled(!shouldAttack);
|
||||
return event.callEvent();
|
||||
}
|
||||
private boolean f_real(EntityHuman entityhuman) {
|
||||
// Paper end
|
||||
ItemStack itemstack = (ItemStack) entityhuman.inventory.armor.get(3);
|
||||
|
||||
if (itemstack.getItem() == Item.getItemOf(Blocks.PUMPKIN)) {
|
||||
return false;
|
||||
} else {
|
||||
Vec3D vec3d = entityhuman.e(1.0F).a();
|
||||
Vec3D vec3d1 = new Vec3D(this.locX - entityhuman.locX, this.getBoundingBox().b + (double) this.getHeadHeight() - (entityhuman.locY + (double) entityhuman.getHeadHeight()), this.locZ - entityhuman.locZ);
|
||||
double d0 = vec3d1.b();
|
||||
|
||||
vec3d1 = vec3d1.a();
|
||||
double d1 = vec3d.b(vec3d1);
|
||||
|
||||
return d1 > 1.0D - 0.025D / d0 ? entityhuman.hasLineOfSight(this) : false;
|
||||
}
|
||||
}
|
||||
|
||||
public float getHeadHeight() {
|
||||
return 2.55F;
|
||||
}
|
||||
|
||||
public void n() {
|
||||
if (this.world.isClientSide) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
this.world.addParticle(EnumParticle.PORTAL, this.locX + (this.random.nextDouble() - 0.5D) * (double) this.width, this.locY + this.random.nextDouble() * (double) this.length - 0.25D, this.locZ + (this.random.nextDouble() - 0.5D) * (double) this.width, (this.random.nextDouble() - 0.5D) * 2.0D, -this.random.nextDouble(), (this.random.nextDouble() - 0.5D) * 2.0D, new int[0]);
|
||||
}
|
||||
}
|
||||
|
||||
this.bd = false;
|
||||
super.n();
|
||||
}
|
||||
|
||||
protected void M() {
|
||||
if (this.an()) {
|
||||
this.damageEntity(DamageSource.DROWN, 1.0F);
|
||||
}
|
||||
|
||||
if (this.world.D() && this.ticksLived >= this.bA + 600) {
|
||||
float f = this.aw();
|
||||
|
||||
if (f > 0.5F && this.world.h(new BlockPosition(this)) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && tryEscape(EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper
|
||||
this.setGoalTarget((EntityLiving) null);
|
||||
this.dm();
|
||||
}
|
||||
}
|
||||
|
||||
super.M();
|
||||
}
|
||||
|
||||
public boolean teleportRandomly() { return dm(); } // Paper - OBFHELPER
|
||||
protected boolean dm() {
|
||||
double d0 = this.locX + (this.random.nextDouble() - 0.5D) * 64.0D;
|
||||
double d1 = this.locY + (double) (this.random.nextInt(64) - 32);
|
||||
double d2 = this.locZ + (this.random.nextDouble() - 0.5D) * 64.0D;
|
||||
|
||||
return this.k(d0, d1, d2);
|
||||
}
|
||||
|
||||
protected boolean a(Entity entity) {
|
||||
Vec3D vec3d = new Vec3D(this.locX - entity.locX, this.getBoundingBox().b + (double) (this.length / 2.0F) - entity.locY + (double) entity.getHeadHeight(), this.locZ - entity.locZ);
|
||||
|
||||
vec3d = vec3d.a();
|
||||
double d0 = 16.0D;
|
||||
double d1 = this.locX + (this.random.nextDouble() - 0.5D) * 8.0D - vec3d.x * 16.0D;
|
||||
double d2 = this.locY + (double) (this.random.nextInt(16) - 8) - vec3d.y * 16.0D;
|
||||
double d3 = this.locZ + (this.random.nextDouble() - 0.5D) * 8.0D - vec3d.z * 16.0D;
|
||||
|
||||
return this.k(d1, d2, d3);
|
||||
}
|
||||
|
||||
private boolean k(double d0, double d1, double d2) {
|
||||
boolean flag = this.j(d0, d1, d2);
|
||||
|
||||
if (flag) {
|
||||
this.world.a((EntityHuman) null, this.lastX, this.lastY, this.lastZ, SoundEffects.bi, this.bK(), 1.0F, 1.0F);
|
||||
this.a(SoundEffects.bi, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
protected SoundEffect F() {
|
||||
return this.do_() ? SoundEffects.bg : SoundEffects.bd;
|
||||
}
|
||||
|
||||
protected SoundEffect d(DamageSource damagesource) {
|
||||
return SoundEffects.bf;
|
||||
}
|
||||
|
||||
protected SoundEffect cf() {
|
||||
return SoundEffects.be;
|
||||
}
|
||||
|
||||
protected void dropEquipment(boolean flag, int i) {
|
||||
super.dropEquipment(flag, i);
|
||||
IBlockData iblockdata = this.getCarried();
|
||||
|
||||
if (iblockdata != null) {
|
||||
Item item = Item.getItemOf(iblockdata.getBlock());
|
||||
int j = item.k() ? iblockdata.getBlock().toLegacyData(iblockdata) : 0;
|
||||
|
||||
this.a(new ItemStack(item, 1, j), 0.0F);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected MinecraftKey J() {
|
||||
return LootTables.w;
|
||||
}
|
||||
|
||||
public void setCarried(@Nullable IBlockData iblockdata) {
|
||||
this.datawatcher.set(EntityEnderman.bx, Optional.fromNullable(iblockdata));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IBlockData getCarried() {
|
||||
return (IBlockData) ((Optional) this.datawatcher.get(EntityEnderman.bx)).orNull();
|
||||
}
|
||||
|
||||
public boolean damageEntity(DamageSource damagesource, float f) {
|
||||
if (this.isInvulnerable(damagesource)) {
|
||||
return false;
|
||||
} else if (damagesource instanceof EntityDamageSourceIndirect && tryEscape(EndermanEscapeEvent.Reason.INDIRECT)) { // Paper
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
if (this.dm()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
boolean flag = super.damageEntity(damagesource, f);
|
||||
|
||||
if (damagesource.ignoresArmor() && this.random.nextInt(10) != 0 && tryEscape(damagesource == DamageSource.DROWN ? EndermanEscapeEvent.Reason.DROWN : EndermanEscapeEvent.Reason.CRITICAL_HIT)) { // Paper
|
||||
this.dm();
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean do_() {
|
||||
return ((Boolean) this.datawatcher.get(EntityEnderman.by)).booleanValue();
|
||||
}
|
||||
|
||||
static {
|
||||
EntityEnderman.c.add(Blocks.GRASS);
|
||||
EntityEnderman.c.add(Blocks.DIRT);
|
||||
EntityEnderman.c.add(Blocks.SAND);
|
||||
EntityEnderman.c.add(Blocks.GRAVEL);
|
||||
EntityEnderman.c.add(Blocks.YELLOW_FLOWER);
|
||||
EntityEnderman.c.add(Blocks.RED_FLOWER);
|
||||
EntityEnderman.c.add(Blocks.BROWN_MUSHROOM);
|
||||
EntityEnderman.c.add(Blocks.RED_MUSHROOM);
|
||||
EntityEnderman.c.add(Blocks.TNT);
|
||||
EntityEnderman.c.add(Blocks.CACTUS);
|
||||
EntityEnderman.c.add(Blocks.CLAY);
|
||||
EntityEnderman.c.add(Blocks.PUMPKIN);
|
||||
EntityEnderman.c.add(Blocks.MELON_BLOCK);
|
||||
EntityEnderman.c.add(Blocks.MYCELIUM);
|
||||
EntityEnderman.c.add(Blocks.NETHERRACK);
|
||||
}
|
||||
|
||||
static class PathfinderGoalEndermanPickupBlock extends PathfinderGoal {
|
||||
|
||||
private final EntityEnderman enderman;
|
||||
|
||||
public PathfinderGoalEndermanPickupBlock(EntityEnderman entityenderman) {
|
||||
this.enderman = entityenderman;
|
||||
}
|
||||
|
||||
public boolean a() {
|
||||
return this.enderman.getCarried() != null ? false : (!this.enderman.world.getGameRules().getBoolean("mobGriefing") ? false : this.enderman.getRandom().nextInt(20) == 0);
|
||||
}
|
||||
|
||||
public void e() {
|
||||
Random random = this.enderman.getRandom();
|
||||
World world = this.enderman.world;
|
||||
int i = MathHelper.floor(this.enderman.locX - 2.0D + random.nextDouble() * 4.0D);
|
||||
int j = MathHelper.floor(this.enderman.locY + random.nextDouble() * 3.0D);
|
||||
int k = MathHelper.floor(this.enderman.locZ - 2.0D + random.nextDouble() * 4.0D);
|
||||
BlockPosition blockposition = new BlockPosition(i, j, k);
|
||||
IBlockData iblockdata = world.getTypeIfLoaded(blockposition); // NeonPaper
|
||||
if (iblockdata == null) return; // NeonPaper
|
||||
Block block = iblockdata.getBlock();
|
||||
MovingObjectPosition movingobjectposition = world.rayTrace(new Vec3D((double) ((float) MathHelper.floor(this.enderman.locX) + 0.5F), (double) ((float) j + 0.5F), (double) ((float) MathHelper.floor(this.enderman.locZ) + 0.5F)), new Vec3D((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F)), false, true, false);
|
||||
boolean flag = movingobjectposition != null && movingobjectposition.a().equals(blockposition);
|
||||
|
||||
if (EntityEnderman.c.contains(block) && flag) {
|
||||
// CraftBukkit start - Pickup event
|
||||
if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, this.enderman.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), org.bukkit.Material.AIR).isCancelled()) {
|
||||
this.enderman.setCarried(iblockdata);
|
||||
world.setAir(blockposition);
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class PathfinderGoalEndermanPlaceBlock extends PathfinderGoal {
|
||||
|
||||
private final EntityEnderman a;
|
||||
|
||||
public PathfinderGoalEndermanPlaceBlock(EntityEnderman entityenderman) {
|
||||
this.a = entityenderman;
|
||||
}
|
||||
|
||||
public boolean a() {
|
||||
return this.a.getCarried() == null ? false : (!this.a.world.getGameRules().getBoolean("mobGriefing") ? false : this.a.getRandom().nextInt(2000) == 0);
|
||||
}
|
||||
|
||||
public void e() {
|
||||
Random random = this.a.getRandom();
|
||||
World world = this.a.world;
|
||||
int i = MathHelper.floor(this.a.locX - 1.0D + random.nextDouble() * 2.0D);
|
||||
int j = MathHelper.floor(this.a.locY + random.nextDouble() * 2.0D);
|
||||
int k = MathHelper.floor(this.a.locZ - 1.0D + random.nextDouble() * 2.0D);
|
||||
BlockPosition blockposition = new BlockPosition(i, j, k);
|
||||
IBlockData iblockdata = world.getTypeIfLoaded(blockposition); // NeonPaper
|
||||
if (iblockdata == null) return; // NeonPaper
|
||||
IBlockData iblockdata1 = world.getType(blockposition.down());
|
||||
IBlockData iblockdata2 = this.a.getCarried();
|
||||
|
||||
if (iblockdata2 != null && this.a(world, blockposition, iblockdata2.getBlock(), iblockdata, iblockdata1)) {
|
||||
// CraftBukkit start - Place event
|
||||
if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.a, blockposition, this.a.getCarried().getBlock(), this.a.getCarried().getBlock().toLegacyData(this.a.getCarried())).isCancelled()) {
|
||||
world.setTypeAndData(blockposition, iblockdata2, 3);
|
||||
this.a.setCarried((IBlockData) null);
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean a(World world, BlockPosition blockposition, Block block, IBlockData iblockdata, IBlockData iblockdata1) {
|
||||
return !block.canPlace(world, blockposition) ? false : (iblockdata.getMaterial() != Material.AIR ? false : (iblockdata1.getMaterial() == Material.AIR ? false : iblockdata1.g()));
|
||||
}
|
||||
}
|
||||
|
||||
static class PathfinderGoalPlayerWhoLookedAtTarget extends PathfinderGoalNearestAttackableTarget<EntityHuman> {
|
||||
|
||||
private final EntityEnderman i; public EntityEnderman getEnderman() { return i; } // Paper - OBFHELPER
|
||||
private EntityHuman j;
|
||||
private int k;
|
||||
private int l;
|
||||
|
||||
public PathfinderGoalPlayerWhoLookedAtTarget(EntityEnderman entityenderman) {
|
||||
super(entityenderman, EntityHuman.class, false);
|
||||
this.i = entityenderman;
|
||||
}
|
||||
|
||||
public boolean a() {
|
||||
double d0 = this.i();
|
||||
|
||||
this.j = this.i.world.a(this.i.locX, this.i.locY, this.i.locZ, d0, d0, (Function) null, new Predicate() {
|
||||
public boolean a(@Nullable EntityHuman entityhuman) {
|
||||
return entityhuman != null && PathfinderGoalPlayerWhoLookedAtTarget.this.i.f(entityhuman);
|
||||
}
|
||||
|
||||
public boolean apply(@Nullable Object object) {
|
||||
return this.a((EntityHuman) object);
|
||||
}
|
||||
});
|
||||
return this.j != null;
|
||||
}
|
||||
|
||||
public void c() {
|
||||
this.k = 5;
|
||||
this.l = 0;
|
||||
}
|
||||
|
||||
public void d() {
|
||||
this.j = null;
|
||||
super.d();
|
||||
}
|
||||
|
||||
public boolean b() {
|
||||
if (this.j != null) {
|
||||
if (!this.i.f(this.j)) {
|
||||
return false;
|
||||
} else {
|
||||
this.i.a((Entity) this.j, 10.0F, 10.0F);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return this.d != null && ((EntityHuman) this.d).isAlive() ? true : super.b();
|
||||
}
|
||||
}
|
||||
|
||||
public void e() {
|
||||
if (this.j != null) {
|
||||
if (--this.k <= 0) {
|
||||
this.d = this.j;
|
||||
this.j = null;
|
||||
super.c();
|
||||
}
|
||||
} else {
|
||||
if (this.d != null) {
|
||||
if (this.i.f((EntityHuman) this.d)) {
|
||||
if (((EntityHuman) this.d).h(this.i) < 16.0D && this.getEnderman().tryEscape(EndermanEscapeEvent.Reason.STARE)) { // Paper
|
||||
this.i.dm();
|
||||
}
|
||||
|
||||
this.l = 0;
|
||||
} else if (((EntityHuman) this.d).h(this.i) > 256.0D && this.l++ >= 30 && this.i.a((Entity) this.d)) {
|
||||
this.l = 0;
|
||||
}
|
||||
}
|
||||
|
||||
super.e();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,538 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
// CraftBukkit start
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Fish;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class EntityFishingHook extends Entity {
|
||||
|
||||
private static final DataWatcherObject<Integer> b = DataWatcher.a(EntityFishingHook.class, DataWatcherRegistry.b);
|
||||
private boolean isInGround;
|
||||
private int d;
|
||||
public EntityHuman owner;
|
||||
private int f;
|
||||
private int g;
|
||||
private int h;
|
||||
private int at;
|
||||
private float au;
|
||||
public Entity hooked;
|
||||
private EntityFishingHook.HookState av;
|
||||
private int aw;
|
||||
private int ax;
|
||||
|
||||
public EntityFishingHook(World world, EntityHuman entityhuman) {
|
||||
super(world);
|
||||
this.av = EntityFishingHook.HookState.FLYING;
|
||||
this.a(entityhuman);
|
||||
this.n();
|
||||
}
|
||||
|
||||
private void a(EntityHuman entityhuman) {
|
||||
this.setSize(0.25F, 0.25F);
|
||||
this.ah = true;
|
||||
this.owner = entityhuman;
|
||||
this.owner.hookedFish = this;
|
||||
}
|
||||
|
||||
public void a(int i) {
|
||||
this.ax = i;
|
||||
}
|
||||
|
||||
public void c(int i) {
|
||||
this.aw = i;
|
||||
}
|
||||
|
||||
private void n() {
|
||||
float f = this.owner.lastPitch + (this.owner.pitch - this.owner.lastPitch);
|
||||
float f1 = this.owner.lastYaw + (this.owner.yaw - this.owner.lastYaw);
|
||||
float f2 = MathHelper.cos(-f1 * 0.017453292F - 3.1415927F);
|
||||
float f3 = MathHelper.sin(-f1 * 0.017453292F - 3.1415927F);
|
||||
float f4 = -MathHelper.cos(-f * 0.017453292F);
|
||||
float f5 = MathHelper.sin(-f * 0.017453292F);
|
||||
double d0 = this.owner.lastX + (this.owner.locX - this.owner.lastX) - (double) f3 * 0.3D;
|
||||
double d1 = this.owner.lastY + (this.owner.locY - this.owner.lastY) + (double) this.owner.getHeadHeight();
|
||||
double d2 = this.owner.lastZ + (this.owner.locZ - this.owner.lastZ) - (double) f2 * 0.3D;
|
||||
|
||||
this.setPositionRotation(d0, d1, d2, f1, f);
|
||||
this.motX = (double) (-f3);
|
||||
this.motY = (double) MathHelper.a(-(f5 / f4), -5.0F, 5.0F);
|
||||
this.motZ = (double) (-f2);
|
||||
float f6 = MathHelper.sqrt(this.motX * this.motX + this.motY * this.motY + this.motZ * this.motZ);
|
||||
|
||||
this.motX *= 0.6D / (double) f6 + 0.5D + this.random.nextGaussian() * 0.0045D;
|
||||
this.motY *= 0.6D / (double) f6 + 0.5D + this.random.nextGaussian() * 0.0045D;
|
||||
this.motZ *= 0.6D / (double) f6 + 0.5D + this.random.nextGaussian() * 0.0045D;
|
||||
float f7 = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ);
|
||||
|
||||
this.yaw = (float) (MathHelper.c(this.motX, this.motZ) * 57.2957763671875D);
|
||||
this.pitch = (float) (MathHelper.c(this.motY, (double) f7) * 57.2957763671875D);
|
||||
this.lastYaw = this.yaw;
|
||||
this.lastPitch = this.pitch;
|
||||
}
|
||||
|
||||
protected void i() {
|
||||
this.getDataWatcher().register(EntityFishingHook.b, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
public void a(DataWatcherObject<?> datawatcherobject) {
|
||||
if (EntityFishingHook.b.equals(datawatcherobject)) {
|
||||
int i = ((Integer) this.getDataWatcher().get(EntityFishingHook.b)).intValue();
|
||||
|
||||
this.hooked = i > 0 ? this.world.getEntity(i - 1) : null;
|
||||
}
|
||||
|
||||
super.a(datawatcherobject);
|
||||
}
|
||||
|
||||
public void B_() {
|
||||
super.B_();
|
||||
if (this.owner == null) {
|
||||
this.die();
|
||||
} else if (this.world.isClientSide || !this.p()) {
|
||||
if (this.isInGround) {
|
||||
++this.d;
|
||||
if (this.d >= 1200) {
|
||||
this.die();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float f = 0.0F;
|
||||
BlockPosition blockposition = new BlockPosition(this);
|
||||
IBlockData iblockdata = this.world.getType(blockposition);
|
||||
|
||||
if (iblockdata.getMaterial() == Material.WATER) {
|
||||
f = BlockFluids.g(iblockdata, this.world, blockposition);
|
||||
}
|
||||
|
||||
double d0;
|
||||
|
||||
if (this.av == EntityFishingHook.HookState.FLYING) {
|
||||
if (this.hooked != null) {
|
||||
this.motX = 0.0D;
|
||||
this.motY = 0.0D;
|
||||
this.motZ = 0.0D;
|
||||
this.av = EntityFishingHook.HookState.HOOKED_IN_ENTITY;
|
||||
return;
|
||||
}
|
||||
|
||||
if (f > 0.0F) {
|
||||
this.motX *= 0.3D;
|
||||
this.motY *= 0.2D;
|
||||
this.motZ *= 0.3D;
|
||||
this.av = EntityFishingHook.HookState.BOBBING;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.world.isClientSide) {
|
||||
this.r();
|
||||
}
|
||||
|
||||
if (!this.isInGround && !this.onGround && !this.positionChanged) {
|
||||
++this.f;
|
||||
} else {
|
||||
this.f = 0;
|
||||
this.motX = 0.0D;
|
||||
this.motY = 0.0D;
|
||||
this.motZ = 0.0D;
|
||||
}
|
||||
} else {
|
||||
if (this.av == EntityFishingHook.HookState.HOOKED_IN_ENTITY) {
|
||||
if (this.hooked != null) {
|
||||
if (this.hooked.dead) {
|
||||
this.hooked = null;
|
||||
this.av = EntityFishingHook.HookState.FLYING;
|
||||
} else {
|
||||
this.locX = this.hooked.locX;
|
||||
double d1 = (double) this.hooked.length;
|
||||
|
||||
this.locY = this.hooked.getBoundingBox().b + d1 * 0.8D;
|
||||
this.locZ = this.hooked.locZ;
|
||||
this.setPosition(this.locX, this.locY, this.locZ);
|
||||
if (this.ak) this.die(); // NeonPaper - Prevent going through portals
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.av == EntityFishingHook.HookState.BOBBING) {
|
||||
this.motX *= 0.9D;
|
||||
this.motZ *= 0.9D;
|
||||
d0 = this.locY + this.motY - (double) blockposition.getY() - (double) f;
|
||||
if (Math.abs(d0) < 0.01D) {
|
||||
d0 += Math.signum(d0) * 0.1D;
|
||||
}
|
||||
|
||||
this.motY -= d0 * (double) this.random.nextFloat() * 0.2D;
|
||||
if (!this.world.isClientSide && f > 0.0F) {
|
||||
this.a(blockposition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iblockdata.getMaterial() != Material.WATER) {
|
||||
this.motY -= 0.03D;
|
||||
}
|
||||
|
||||
this.move(EnumMoveType.SELF, this.motX, this.motY, this.motZ);
|
||||
this.q();
|
||||
d0 = 0.92D;
|
||||
this.motX *= 0.92D;
|
||||
this.motY *= 0.92D;
|
||||
this.motZ *= 0.92D;
|
||||
this.setPosition(this.locX, this.locY, this.locZ);
|
||||
|
||||
// Paper start - These shouldn't be going through portals
|
||||
if (this.inPortal()) {
|
||||
this.die();
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
}
|
||||
|
||||
private boolean p() {
|
||||
ItemStack itemstack = this.owner.getItemInMainHand();
|
||||
ItemStack itemstack1 = this.owner.getItemInOffHand();
|
||||
boolean flag = itemstack.getItem() == Items.FISHING_ROD;
|
||||
boolean flag1 = itemstack1.getItem() == Items.FISHING_ROD;
|
||||
|
||||
if (!this.owner.dead && this.owner.isAlive() && (flag || flag1) && this.h(this.owner) <= 1024.0D) {
|
||||
return false;
|
||||
} else {
|
||||
this.die();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void q() {
|
||||
float f = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ);
|
||||
|
||||
this.yaw = (float) (MathHelper.c(this.motX, this.motZ) * 57.2957763671875D);
|
||||
|
||||
for (this.pitch = (float) (MathHelper.c(this.motY, (double) f) * 57.2957763671875D); this.pitch - this.lastPitch < -180.0F; this.lastPitch -= 360.0F) {
|
||||
;
|
||||
}
|
||||
|
||||
while (this.pitch - this.lastPitch >= 180.0F) {
|
||||
this.lastPitch += 360.0F;
|
||||
}
|
||||
|
||||
while (this.yaw - this.lastYaw < -180.0F) {
|
||||
this.lastYaw -= 360.0F;
|
||||
}
|
||||
|
||||
while (this.yaw - this.lastYaw >= 180.0F) {
|
||||
this.lastYaw += 360.0F;
|
||||
}
|
||||
|
||||
this.pitch = this.lastPitch + (this.pitch - this.lastPitch) * 0.2F;
|
||||
this.yaw = this.lastYaw + (this.yaw - this.lastYaw) * 0.2F;
|
||||
}
|
||||
|
||||
private void r() {
|
||||
Vec3D vec3d = new Vec3D(this.locX, this.locY, this.locZ);
|
||||
Vec3D vec3d1 = new Vec3D(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ);
|
||||
MovingObjectPosition movingobjectposition = this.world.rayTrace(vec3d, vec3d1, false, true, false);
|
||||
|
||||
vec3d = new Vec3D(this.locX, this.locY, this.locZ);
|
||||
vec3d1 = new Vec3D(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ);
|
||||
|
||||
// Paper start - Call ProjectileCollideEvent
|
||||
if (movingobjectposition != null && movingobjectposition.entity != null) {
|
||||
com.destroystokyo.paper.event.entity.ProjectileCollideEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition);
|
||||
if (event.isCancelled()) {
|
||||
movingobjectposition = null;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
if (movingobjectposition != null) {
|
||||
vec3d1 = new Vec3D(movingobjectposition.pos.x, movingobjectposition.pos.y, movingobjectposition.pos.z);
|
||||
}
|
||||
|
||||
Entity entity = null;
|
||||
List list = this.world.getEntities(this, this.getBoundingBox().b(this.motX, this.motY, this.motZ).g(1.0D));
|
||||
double d0 = 0.0D;
|
||||
Iterator iterator = list.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity1 = (Entity) iterator.next();
|
||||
|
||||
if (this.a(entity1) && (entity1 != this.owner || this.f >= 5)) {
|
||||
AxisAlignedBB axisalignedbb = entity1.getBoundingBox().g(0.30000001192092896D);
|
||||
MovingObjectPosition movingobjectposition1 = axisalignedbb.b(vec3d, vec3d1);
|
||||
|
||||
if (movingobjectposition1 != null) {
|
||||
double d1 = vec3d.distanceSquared(movingobjectposition1.pos);
|
||||
|
||||
if (d1 < d0 || d0 == 0.0D) {
|
||||
entity = entity1;
|
||||
d0 = d1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
movingobjectposition = new MovingObjectPosition(entity);
|
||||
}
|
||||
|
||||
if (movingobjectposition != null && movingobjectposition.type != MovingObjectPosition.EnumMovingObjectType.MISS) {
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this, movingobjectposition); // Craftbukkit - Call event
|
||||
if (movingobjectposition.type == MovingObjectPosition.EnumMovingObjectType.ENTITY) {
|
||||
this.hooked = movingobjectposition.entity;
|
||||
this.s();
|
||||
} else {
|
||||
this.isInGround = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void s() {
|
||||
this.getDataWatcher().set(EntityFishingHook.b, Integer.valueOf(this.hooked.getId() + 1));
|
||||
}
|
||||
|
||||
private void a(BlockPosition blockposition) {
|
||||
WorldServer worldserver = (WorldServer) this.world;
|
||||
int i = 1;
|
||||
BlockPosition blockposition1 = blockposition.up();
|
||||
|
||||
if (this.random.nextFloat() < 0.25F && this.world.isRainingAt(blockposition1)) {
|
||||
++i;
|
||||
}
|
||||
|
||||
if (this.random.nextFloat() < 0.5F && !this.world.h(blockposition1)) {
|
||||
--i;
|
||||
}
|
||||
|
||||
if (this.g > 0) {
|
||||
--this.g;
|
||||
if (this.g <= 0) {
|
||||
this.h = 0;
|
||||
this.at = 0;
|
||||
// CraftBukkit start
|
||||
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.FAILED_ATTEMPT);
|
||||
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
|
||||
// CraftBukkit end
|
||||
} else {
|
||||
this.motY -= 0.2D * (double) this.random.nextFloat() * (double) this.random.nextFloat();
|
||||
}
|
||||
} else {
|
||||
float f;
|
||||
float f1;
|
||||
float f2;
|
||||
double d0;
|
||||
double d1;
|
||||
double d2;
|
||||
Block block;
|
||||
|
||||
if (this.at > 0) {
|
||||
this.at -= i;
|
||||
if (this.at > 0) {
|
||||
this.au = (float) ((double) this.au + this.random.nextGaussian() * 4.0D);
|
||||
f = this.au * 0.017453292F;
|
||||
f1 = MathHelper.sin(f);
|
||||
f2 = MathHelper.cos(f);
|
||||
d0 = this.locX + (double) (f1 * (float) this.at * 0.1F);
|
||||
d1 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F);
|
||||
d2 = this.locZ + (double) (f2 * (float) this.at * 0.1F);
|
||||
block = worldserver.getType(new BlockPosition(d0, d1 - 1.0D, d2)).getBlock();
|
||||
if (block == Blocks.WATER || block == Blocks.FLOWING_WATER) {
|
||||
if (this.random.nextFloat() < 0.15F) {
|
||||
worldserver.a(EnumParticle.WATER_BUBBLE, d0, d1 - 0.10000000149011612D, d2, 1, (double) f1, 0.1D, (double) f2, 0.0D, new int[0]);
|
||||
}
|
||||
|
||||
float f3 = f1 * 0.04F;
|
||||
float f4 = f2 * 0.04F;
|
||||
|
||||
worldserver.a(EnumParticle.WATER_WAKE, d0, d1, d2, 0, (double) f4, 0.01D, (double) (-f3), 1.0D, new int[0]);
|
||||
worldserver.a(EnumParticle.WATER_WAKE, d0, d1, d2, 0, (double) (-f4), 0.01D, (double) f3, 1.0D, new int[0]);
|
||||
}
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.BITE);
|
||||
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
|
||||
if (playerFishEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.motY = (double) (-0.4F * MathHelper.a(this.random, 0.6F, 1.0F));
|
||||
this.a(SoundEffects.K, 0.25F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F);
|
||||
double d3 = this.getBoundingBox().b + 0.5D;
|
||||
|
||||
worldserver.a(EnumParticle.WATER_BUBBLE, this.locX, d3, this.locZ, (int) (1.0F + this.width * 20.0F), (double) this.width, 0.0D, (double) this.width, 0.20000000298023224D, new int[0]);
|
||||
worldserver.a(EnumParticle.WATER_WAKE, this.locX, d3, this.locZ, (int) (1.0F + this.width * 20.0F), (double) this.width, 0.0D, (double) this.width, 0.20000000298023224D, new int[0]);
|
||||
this.g = MathHelper.nextInt(this.random, 20, 40);
|
||||
}
|
||||
} else if (this.h > 0) {
|
||||
this.h -= i;
|
||||
f = 0.15F;
|
||||
if (this.h < 20) {
|
||||
f = (float) ((double) f + (double) (20 - this.h) * 0.05D);
|
||||
} else if (this.h < 40) {
|
||||
f = (float) ((double) f + (double) (40 - this.h) * 0.02D);
|
||||
} else if (this.h < 60) {
|
||||
f = (float) ((double) f + (double) (60 - this.h) * 0.01D);
|
||||
}
|
||||
|
||||
if (this.random.nextFloat() < f) {
|
||||
f1 = MathHelper.a(this.random, 0.0F, 360.0F) * 0.017453292F;
|
||||
f2 = MathHelper.a(this.random, 25.0F, 60.0F);
|
||||
d0 = this.locX + (double) (MathHelper.sin(f1) * f2 * 0.1F);
|
||||
d1 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F);
|
||||
d2 = this.locZ + (double) (MathHelper.cos(f1) * f2 * 0.1F);
|
||||
block = worldserver.getType(new BlockPosition((int) d0, (int) d1 - 1, (int) d2)).getBlock();
|
||||
if (block == Blocks.WATER || block == Blocks.FLOWING_WATER) {
|
||||
worldserver.a(EnumParticle.WATER_SPLASH, d0, d1, d2, 2 + this.random.nextInt(2), 0.10000000149011612D, 0.0D, 0.10000000149011612D, 0.0D, new int[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.h <= 0) {
|
||||
this.au = MathHelper.a(this.random, 0.0F, 360.0F);
|
||||
this.at = MathHelper.nextInt(this.random, 20, 80);
|
||||
}
|
||||
} else {
|
||||
this.h = MathHelper.nextInt(this.random, world.paperConfig.fishingMinTicks, world.paperConfig.fishingMaxTicks); // Paper
|
||||
this.h -= this.ax * 20 * 5;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean a(Entity entity) {
|
||||
return entity.isInteractable() || entity instanceof EntityItem;
|
||||
}
|
||||
|
||||
public void b(NBTTagCompound nbttagcompound) {}
|
||||
|
||||
public void a(NBTTagCompound nbttagcompound) {}
|
||||
|
||||
public int j() {
|
||||
if (!this.world.isClientSide && this.owner != null) {
|
||||
int i = 0;
|
||||
|
||||
if (this.hooked != null) {
|
||||
// CraftBukkit start
|
||||
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), this.hooked.getBukkitEntity(), (Fish) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_ENTITY);
|
||||
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
|
||||
|
||||
if (playerFishEvent.isCancelled()) {
|
||||
return 0;
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.k();
|
||||
this.world.broadcastEntityEffect(this, (byte) 31);
|
||||
i = this.hooked instanceof EntityItem ? 3 : 5;
|
||||
} else if (this.g > 0) {
|
||||
LootTableInfo.a loottableinfo_a = new LootTableInfo.a((WorldServer) this.world);
|
||||
|
||||
loottableinfo_a.a((float) this.aw + this.owner.du());
|
||||
Iterator iterator = this.world.getLootTableRegistry().a(LootTables.aA).a(this.random, loottableinfo_a.a()).iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ItemStack itemstack = (ItemStack) iterator.next();
|
||||
EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY, this.locZ, itemstack);
|
||||
// CraftBukkit start
|
||||
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), entityitem.getBukkitEntity(), (Fish) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH);
|
||||
playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1);
|
||||
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
|
||||
|
||||
if (playerFishEvent.isCancelled()) {
|
||||
return 0;
|
||||
}
|
||||
// CraftBukkit end
|
||||
double d0 = this.owner.locX - this.locX;
|
||||
double d1 = this.owner.locY - this.locY;
|
||||
double d2 = this.owner.locZ - this.locZ;
|
||||
double d3 = (double) MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
|
||||
double d4 = 0.1D;
|
||||
|
||||
entityitem.motX = d0 * 0.1D;
|
||||
entityitem.motY = d1 * 0.1D + (double) MathHelper.sqrt(d3) * 0.08D;
|
||||
entityitem.motZ = d2 * 0.1D;
|
||||
this.world.addEntity(entityitem);
|
||||
// CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop()
|
||||
if (playerFishEvent.getExpToDrop() > 0) {
|
||||
this.owner.world.addEntity(new EntityExperienceOrb(this.owner.world, this.owner.locX, this.owner.locY + 0.5D, this.owner.locZ + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.owner, this)); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
Item item = itemstack.getItem();
|
||||
|
||||
if (item == Items.FISH || item == Items.COOKED_FISH) {
|
||||
this.owner.a(StatisticList.E, 1);
|
||||
}
|
||||
}
|
||||
|
||||
i = 1;
|
||||
}
|
||||
|
||||
if (this.isInGround) {
|
||||
// CraftBukkit start
|
||||
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.IN_GROUND);
|
||||
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
|
||||
|
||||
if (playerFishEvent.isCancelled()) {
|
||||
return 0;
|
||||
}
|
||||
// CraftBukkit end
|
||||
i = 2;
|
||||
}
|
||||
// CraftBukkit start
|
||||
if (i == 0) {
|
||||
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.FAILED_ATTEMPT);
|
||||
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
|
||||
if (playerFishEvent.isCancelled()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
this.die();
|
||||
return i;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void k() {
|
||||
if (this.owner != null) {
|
||||
double d0 = this.owner.locX - this.locX;
|
||||
double d1 = this.owner.locY - this.locY;
|
||||
double d2 = this.owner.locZ - this.locZ;
|
||||
double d3 = 0.1D;
|
||||
|
||||
this.hooked.motX += d0 * 0.1D;
|
||||
this.hooked.motY += d1 * 0.1D;
|
||||
this.hooked.motZ += d2 * 0.1D;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean playStepSound() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void die() {
|
||||
super.die();
|
||||
if (this.owner != null) {
|
||||
this.owner.hookedFish = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public EntityHuman l() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
static enum HookState {
|
||||
|
||||
FLYING, HOOKED_IN_ENTITY, BOBBING;
|
||||
|
||||
private HookState() {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.bukkit.event.player.PlayerShearEntityEvent; // CraftBukkit
|
||||
|
||||
public class EntityMushroomCow extends EntityCow {
|
||||
|
||||
public EntityMushroomCow(World world) {
|
||||
super(world);
|
||||
this.setSize(0.9F, 1.4F);
|
||||
this.bA = Blocks.MYCELIUM;
|
||||
}
|
||||
|
||||
public static void c(DataConverterManager dataconvertermanager) {
|
||||
EntityInsentient.a(dataconvertermanager, EntityMushroomCow.class);
|
||||
}
|
||||
|
||||
public boolean a(EntityHuman entityhuman, EnumHand enumhand) {
|
||||
ItemStack itemstack = entityhuman.b(enumhand);
|
||||
|
||||
if (itemstack.getItem() == Items.BOWL && this.getAge() >= 0 && !entityhuman.abilities.canInstantlyBuild) {
|
||||
itemstack.subtract(1);
|
||||
if (itemstack.isEmpty()) {
|
||||
entityhuman.a(enumhand, new ItemStack(Items.MUSHROOM_STEW));
|
||||
} else if (!entityhuman.inventory.pickup(new ItemStack(Items.MUSHROOM_STEW))) {
|
||||
entityhuman.drop(new ItemStack(Items.MUSHROOM_STEW), false);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (itemstack.getItem() == Items.SHEARS && this.getAge() >= 0) {
|
||||
if (this.dead) return false; // Reaper - Fix cow dupe
|
||||
// CraftBukkit start
|
||||
PlayerShearEntityEvent event = new PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity());
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.die();
|
||||
this.world.addParticle(EnumParticle.EXPLOSION_LARGE, this.locX, this.locY + (double) (this.length / 2.0F), this.locZ, 0.0D, 0.0D, 0.0D, new int[0]);
|
||||
if (!this.world.isClientSide) {
|
||||
EntityCow entitycow = new EntityCow(this.world);
|
||||
|
||||
entitycow.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, this.pitch);
|
||||
entitycow.setHealth(this.getHealth());
|
||||
entitycow.aN = this.aN;
|
||||
if (this.hasCustomName()) {
|
||||
entitycow.setCustomName(this.getCustomName());
|
||||
}
|
||||
|
||||
this.world.addEntity(entitycow);
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
this.world.addEntity(new EntityItem(this.world, this.locX, this.locY + (double) this.length, this.locZ, new ItemStack(Blocks.RED_MUSHROOM)));
|
||||
}
|
||||
|
||||
itemstack.damage(1, entityhuman);
|
||||
this.a(SoundEffects.ei, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return super.a(entityhuman, enumhand);
|
||||
}
|
||||
}
|
||||
|
||||
public EntityMushroomCow c(EntityAgeable entityageable) {
|
||||
return new EntityMushroomCow(this.world);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected MinecraftKey J() {
|
||||
return LootTables.M;
|
||||
}
|
||||
|
||||
public EntityCow b(EntityAgeable entityageable) {
|
||||
return this.c(entityageable);
|
||||
}
|
||||
|
||||
public EntityAgeable createChild(EntityAgeable entityageable) {
|
||||
return this.c(entityageable);
|
||||
}
|
||||
}
|
||||
@@ -784,7 +784,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
protected void a(double d0, boolean flag, IBlockData iblockdata, BlockPosition blockposition) {}
|
||||
|
||||
protected void b(BlockPosition blockposition) {
|
||||
if (!this.isSpectator()) {
|
||||
if (valid && (!this.isSpectator() || this.world.isLoaded(new BlockPosition(this)))) { // Dionysus - don't tick dead players that are not in the world currently (pending respawn)
|
||||
super.b(blockposition);
|
||||
}
|
||||
|
||||
@@ -1156,6 +1156,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
this.getDataWatcher().set(EntityPlayer.br, entityplayer.getDataWatcher().get(EntityPlayer.br));
|
||||
this.lastSentExp = -1;
|
||||
this.lastHealthSent = -1.0F;
|
||||
setSneaking(false); // NeonPaper - fix MC-10657
|
||||
this.ch = -1;
|
||||
// this.cr.a((RecipeBook) entityplayer.cr); // CraftBukkit
|
||||
// Paper start - Optimize remove queue
|
||||
|
||||
@@ -0,0 +1,654 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
// CraftBukkit start
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerVelocityEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class EntityTrackerEntry {
|
||||
|
||||
private static final Logger c = LogManager.getLogger();
|
||||
private final Entity tracker;
|
||||
private final int e;
|
||||
private int f;
|
||||
private final int g;
|
||||
private long xLoc;
|
||||
private long yLoc;
|
||||
private long zLoc;
|
||||
private int yRot;
|
||||
private int xRot;
|
||||
private int headYaw;
|
||||
private double n;
|
||||
private double o;
|
||||
private double p;
|
||||
public int a;
|
||||
private double q;
|
||||
private double r;
|
||||
private double s;
|
||||
private boolean isMoving;
|
||||
private final boolean u;
|
||||
private int v;
|
||||
private List<Entity> w = Collections.emptyList();
|
||||
private boolean x;
|
||||
private boolean y;
|
||||
public boolean b;
|
||||
// Paper start
|
||||
// Replace trackedPlayers Set with a Map. The value is true until the player receives
|
||||
// their first update (which is forced to have absolute coordinates), false afterward.
|
||||
public java.util.Map<EntityPlayer, Boolean> trackedPlayerMap = new java.util.HashMap<EntityPlayer, Boolean>();
|
||||
public Set<EntityPlayer> trackedPlayers = trackedPlayerMap.keySet();
|
||||
// Paper end
|
||||
|
||||
public EntityTrackerEntry(Entity entity, int i, int j, int k, boolean flag) {
|
||||
entity.tracker = this; // Paper
|
||||
this.tracker = entity;
|
||||
this.e = i;
|
||||
this.f = j;
|
||||
this.g = k;
|
||||
this.u = flag;
|
||||
this.xLoc = EntityTracker.a(entity.locX);
|
||||
this.yLoc = EntityTracker.a(entity.locY);
|
||||
this.zLoc = EntityTracker.a(entity.locZ);
|
||||
this.yRot = MathHelper.d(entity.yaw * 256.0F / 360.0F);
|
||||
this.xRot = MathHelper.d(entity.pitch * 256.0F / 360.0F);
|
||||
this.headYaw = MathHelper.d(entity.getHeadRotation() * 256.0F / 360.0F);
|
||||
this.y = entity.onGround;
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof EntityTrackerEntry ? ((EntityTrackerEntry) object).tracker.getId() == this.tracker.getId() : false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.tracker.getId();
|
||||
}
|
||||
|
||||
public void track(List<EntityHuman> list) {
|
||||
this.b = false;
|
||||
if (!this.isMoving || this.tracker.d(this.q, this.r, this.s) > 16.0D) {
|
||||
this.q = this.tracker.locX;
|
||||
this.r = this.tracker.locY;
|
||||
this.s = this.tracker.locZ;
|
||||
this.isMoving = true;
|
||||
this.b = true;
|
||||
this.scanPlayers(list);
|
||||
}
|
||||
|
||||
List list1 = this.tracker.bF();
|
||||
|
||||
if (!list1.equals(this.w)) {
|
||||
this.w = list1;
|
||||
this.broadcastIncludingSelf(new PacketPlayOutMount(this.tracker)); // CraftBukkit
|
||||
}
|
||||
|
||||
// PAIL : rename
|
||||
if (this.tracker instanceof EntityItemFrame && this.a % 20 == 0) { // Paper
|
||||
EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker;
|
||||
ItemStack itemstack = entityitemframe.getItem();
|
||||
|
||||
if (itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // Paper - moved back up
|
||||
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.tracker.world);
|
||||
Iterator iterator = this.trackedPlayers.iterator(); // CraftBukkit
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EntityHuman entityhuman = (EntityHuman) iterator.next();
|
||||
EntityPlayer entityplayer = (EntityPlayer) entityhuman;
|
||||
|
||||
worldmap.a(entityplayer, itemstack);
|
||||
Packet packet = Items.FILLED_MAP.a(itemstack, this.tracker.world, (EntityHuman) entityplayer);
|
||||
|
||||
if (packet != null) {
|
||||
entityplayer.playerConnection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.d();
|
||||
}
|
||||
|
||||
if (this.a % this.g == 0 || this.tracker.impulse || this.tracker.getDataWatcher().a()) {
|
||||
int i;
|
||||
|
||||
if (this.tracker.isPassenger()) {
|
||||
i = MathHelper.d(this.tracker.yaw * 256.0F / 360.0F);
|
||||
int j = MathHelper.d(this.tracker.pitch * 256.0F / 360.0F);
|
||||
boolean flag = Math.abs(i - this.yRot) >= 1 || Math.abs(j - this.xRot) >= 1;
|
||||
|
||||
if (flag) {
|
||||
this.broadcast(new PacketPlayOutEntity.PacketPlayOutEntityLook(this.tracker.getId(), (byte) i, (byte) j, this.tracker.onGround));
|
||||
this.yRot = i;
|
||||
this.xRot = j;
|
||||
}
|
||||
|
||||
this.xLoc = EntityTracker.a(this.tracker.locX);
|
||||
this.yLoc = EntityTracker.a(this.tracker.locY);
|
||||
this.zLoc = EntityTracker.a(this.tracker.locZ);
|
||||
this.d();
|
||||
this.x = true;
|
||||
} else {
|
||||
++this.v;
|
||||
long k = EntityTracker.a(this.tracker.locX);
|
||||
long l = EntityTracker.a(this.tracker.locY);
|
||||
long i1 = EntityTracker.a(this.tracker.locZ);
|
||||
int j1 = MathHelper.d(this.tracker.yaw * 256.0F / 360.0F);
|
||||
int k1 = MathHelper.d(this.tracker.pitch * 256.0F / 360.0F);
|
||||
long l1 = k - this.xLoc;
|
||||
long i2 = l - this.yLoc;
|
||||
long j2 = i1 - this.zLoc;
|
||||
Object object = null;
|
||||
boolean flag1 = l1 * l1 + i2 * i2 + j2 * j2 >= 128L || this.a % 60 == 0;
|
||||
boolean flag2 = Math.abs(j1 - this.yRot) >= 1 || Math.abs(k1 - this.xRot) >= 1;
|
||||
|
||||
if (this.a > 0 || this.tracker instanceof EntityArrow) { // Paper - Moved up
|
||||
// CraftBukkit start - Code moved from below
|
||||
if (flag1) {
|
||||
this.xLoc = k;
|
||||
this.yLoc = l;
|
||||
this.zLoc = i1;
|
||||
}
|
||||
|
||||
if (flag2) {
|
||||
this.yRot = j1;
|
||||
this.xRot = k1;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (l1 >= -32768L && l1 < 32768L && i2 >= -32768L && i2 < 32768L && j2 >= -32768L && j2 < 32768L && this.v <= 400 && !this.x && this.y == this.tracker.onGround) {
|
||||
if ((!flag1 || !flag2) && !(this.tracker instanceof EntityArrow)) {
|
||||
if (flag1) {
|
||||
object = new PacketPlayOutEntity.PacketPlayOutRelEntityMove(this.tracker.getId(), l1, i2, j2, this.tracker.onGround);
|
||||
} else if (flag2) {
|
||||
object = new PacketPlayOutEntity.PacketPlayOutEntityLook(this.tracker.getId(), (byte) j1, (byte) k1, this.tracker.onGround);
|
||||
}
|
||||
} else {
|
||||
object = new PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook(this.tracker.getId(), l1, i2, j2, (byte) j1, (byte) k1, this.tracker.onGround);
|
||||
}
|
||||
} else {
|
||||
this.y = this.tracker.onGround;
|
||||
this.v = 0;
|
||||
// CraftBukkit start - Refresh list of who can see a player before sending teleport packet
|
||||
if (this.tracker instanceof EntityPlayer) {
|
||||
this.scanPlayers(new java.util.ArrayList(this.trackedPlayers));
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.c();
|
||||
object = new PacketPlayOutEntityTeleport(this.tracker);
|
||||
}
|
||||
}
|
||||
|
||||
boolean flag3 = this.u;
|
||||
|
||||
if (this.tracker instanceof EntityLiving && ((EntityLiving) this.tracker).cP()) {
|
||||
flag3 = true;
|
||||
}
|
||||
|
||||
if (flag3 && this.a > 0) {
|
||||
double d0 = this.tracker.motX - this.n;
|
||||
double d1 = this.tracker.motY - this.o;
|
||||
double d2 = this.tracker.motZ - this.p;
|
||||
double d3 = 0.02D;
|
||||
double d4 = d0 * d0 + d1 * d1 + d2 * d2;
|
||||
|
||||
if (d4 > 4.0E-4D || d4 > 0.0D && this.tracker.motX == 0.0D && this.tracker.motY == 0.0D && this.tracker.motZ == 0.0D) {
|
||||
this.n = this.tracker.motX;
|
||||
this.o = this.tracker.motY;
|
||||
this.p = this.tracker.motZ;
|
||||
this.broadcast(new PacketPlayOutEntityVelocity(this.tracker.getId(), this.n, this.o, this.p));
|
||||
}
|
||||
}
|
||||
|
||||
if (object != null) {
|
||||
// Paper start - ensure fresh viewers get an absolute position on their first update,
|
||||
// since we can't be certain what position they received in the spawn packet.
|
||||
if (object instanceof PacketPlayOutEntityTeleport) {
|
||||
this.broadcast((Packet) object);
|
||||
} else {
|
||||
PacketPlayOutEntityTeleport teleportPacket = null;
|
||||
|
||||
for (java.util.Map.Entry<EntityPlayer, Boolean> viewer : trackedPlayerMap.entrySet()) {
|
||||
if (viewer.getValue()) {
|
||||
viewer.setValue(false);
|
||||
if (teleportPacket == null) {
|
||||
teleportPacket = new PacketPlayOutEntityTeleport(this.tracker);
|
||||
}
|
||||
viewer.getKey().playerConnection.sendPacket(teleportPacket);
|
||||
} else {
|
||||
viewer.getKey().playerConnection.sendPacket((Packet) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
|
||||
this.d();
|
||||
/* CraftBukkit start - Code moved up
|
||||
if (flag1) {
|
||||
this.xLoc = k;
|
||||
this.yLoc = l;
|
||||
this.zLoc = i1;
|
||||
}
|
||||
|
||||
if (flag2) {
|
||||
this.yRot = j1;
|
||||
this.xRot = k1;
|
||||
}
|
||||
// CraftBukkit end */
|
||||
|
||||
this.x = false;
|
||||
}
|
||||
|
||||
i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
|
||||
if (Math.abs(i - this.headYaw) >= 1) {
|
||||
this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i));
|
||||
this.headYaw = i;
|
||||
}
|
||||
|
||||
this.tracker.impulse = false;
|
||||
}
|
||||
|
||||
++this.a;
|
||||
if (this.tracker.velocityChanged) {
|
||||
// CraftBukkit start - Create PlayerVelocity event
|
||||
boolean cancelled = false;
|
||||
|
||||
if (this.tracker instanceof EntityPlayer) {
|
||||
Player player = (Player) this.tracker.getBukkitEntity();
|
||||
org.bukkit.util.Vector velocity = player.getVelocity();
|
||||
|
||||
PlayerVelocityEvent event = new PlayerVelocityEvent(player, velocity.clone());
|
||||
this.tracker.world.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
cancelled = true;
|
||||
} else if (!velocity.equals(event.getVelocity())) {
|
||||
player.setVelocity(event.getVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
this.broadcastIncludingSelf(new PacketPlayOutEntityVelocity(this.tracker));
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.tracker.velocityChanged = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void d() {
|
||||
DataWatcher datawatcher = this.tracker.getDataWatcher();
|
||||
|
||||
if (datawatcher.a()) {
|
||||
this.broadcastIncludingSelf(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false));
|
||||
}
|
||||
|
||||
if (this.tracker instanceof EntityLiving) {
|
||||
AttributeMapServer attributemapserver = (AttributeMapServer) ((EntityLiving) this.tracker).getAttributeMap();
|
||||
Set set = attributemapserver.getAttributes();
|
||||
|
||||
if (!set.isEmpty()) {
|
||||
// CraftBukkit start - Send scaled max health
|
||||
if (this.tracker instanceof EntityPlayer) {
|
||||
((EntityPlayer) this.tracker).getBukkitEntity().injectScaledMaxHealth(set, false);
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.broadcastIncludingSelf(new PacketPlayOutUpdateAttributes(this.tracker.getId(), set));
|
||||
}
|
||||
|
||||
set.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void broadcast(Packet<?> packet) {
|
||||
Iterator iterator = this.trackedPlayers.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
|
||||
|
||||
entityplayer.playerConnection.sendPacket(packet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void broadcastIncludingSelf(Packet<?> packet) {
|
||||
this.broadcast(packet);
|
||||
if (this.tracker instanceof EntityPlayer) {
|
||||
((EntityPlayer) this.tracker).playerConnection.sendPacket(packet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a() {
|
||||
Iterator iterator = this.trackedPlayers.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
|
||||
|
||||
this.tracker.c(entityplayer);
|
||||
entityplayer.c(this.tracker);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a(EntityPlayer entityplayer) {
|
||||
if (this.trackedPlayers.contains(entityplayer)) {
|
||||
this.tracker.c(entityplayer);
|
||||
entityplayer.c(this.tracker);
|
||||
this.trackedPlayers.remove(entityplayer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void updatePlayer(EntityPlayer entityplayer) {
|
||||
org.spigotmc.AsyncCatcher.catchOp( "player tracker update"); // Spigot
|
||||
if (entityplayer != this.tracker) {
|
||||
if (this.c(entityplayer)) {
|
||||
if (!this.trackedPlayers.contains(entityplayer) && (this.e(entityplayer) || this.tracker.attachedToPlayer)) {
|
||||
// CraftBukkit start - respect vanish API
|
||||
if (this.tracker instanceof EntityPlayer) {
|
||||
Player player = ((EntityPlayer) this.tracker).getBukkitEntity();
|
||||
if (!entityplayer.getBukkitEntity().canSee(player)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
entityplayer.removeQueue.remove(Integer.valueOf(this.tracker.getId()));
|
||||
// CraftBukkit end
|
||||
this.trackedPlayerMap.put(entityplayer, true); // Paper
|
||||
Packet packet = this.e();
|
||||
|
||||
entityplayer.playerConnection.sendPacket(packet);
|
||||
if (!this.tracker.getDataWatcher().d()) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityMetadata(this.tracker.getId(), this.tracker.getDataWatcher(), true));
|
||||
}
|
||||
|
||||
boolean flag = this.u;
|
||||
|
||||
if (this.tracker instanceof EntityLiving) {
|
||||
AttributeMapServer attributemapserver = (AttributeMapServer) ((EntityLiving) this.tracker).getAttributeMap();
|
||||
Collection collection = attributemapserver.c();
|
||||
|
||||
// CraftBukkit start - If sending own attributes send scaled health instead of current maximum health
|
||||
if (this.tracker.getId() == entityplayer.getId()) {
|
||||
((EntityPlayer) this.tracker).getBukkitEntity().injectScaledMaxHealth(collection, false);
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (!collection.isEmpty()) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(this.tracker.getId(), collection));
|
||||
}
|
||||
|
||||
if (((EntityLiving) this.tracker).cP()) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.n = this.tracker.motX;
|
||||
this.o = this.tracker.motY;
|
||||
this.p = this.tracker.motZ;
|
||||
if (flag && !(packet instanceof PacketPlayOutSpawnEntityLiving)) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityVelocity(this.tracker.getId(), this.tracker.motX, this.tracker.motY, this.tracker.motZ));
|
||||
}
|
||||
|
||||
if (this.tracker instanceof EntityLiving) {
|
||||
EnumItemSlot[] aenumitemslot = EnumItemSlot.values();
|
||||
int i = aenumitemslot.length;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
EnumItemSlot enumitemslot = aenumitemslot[j];
|
||||
ItemStack itemstack = ((EntityLiving) this.tracker).getEquipment(enumitemslot);
|
||||
|
||||
if (!itemstack.isEmpty()) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEquipment(this.tracker.getId(), enumitemslot, itemstack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.tracker instanceof EntityHuman) {
|
||||
EntityHuman entityhuman = (EntityHuman) this.tracker;
|
||||
|
||||
if (entityhuman.isSleeping()) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutBed(entityhuman, new BlockPosition(this.tracker)));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.tracker instanceof EntityLiving) {
|
||||
// CraftBukkit start - Fix for nonsensical head yaw
|
||||
this.headYaw = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
|
||||
this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) headYaw));
|
||||
// CraftBukkit end
|
||||
EntityLiving entityliving = (EntityLiving) this.tracker;
|
||||
Iterator iterator = entityliving.getEffects().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
MobEffect mobeffect = (MobEffect) iterator.next();
|
||||
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(this.tracker.getId(), mobeffect));
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.tracker.bF().isEmpty()) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker));
|
||||
}
|
||||
|
||||
if (this.tracker.isPassenger()) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker.bJ()));
|
||||
}
|
||||
|
||||
this.tracker.b(entityplayer);
|
||||
entityplayer.d(this.tracker);
|
||||
updatePassengers(entityplayer); // Paper
|
||||
}
|
||||
} else if (this.trackedPlayers.contains(entityplayer)) {
|
||||
this.trackedPlayers.remove(entityplayer);
|
||||
this.tracker.c(entityplayer);
|
||||
entityplayer.c(this.tracker);
|
||||
updatePassengers(entityplayer); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public boolean c(EntityPlayer entityplayer) {
|
||||
// Paper start
|
||||
if (tracker.isPassenger()) {
|
||||
return isTrackedBy(tracker.getVehicle(), entityplayer);
|
||||
} else if (hasPassengerInRange(tracker, entityplayer)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isInRangeOfPlayer(entityplayer);
|
||||
}
|
||||
private static boolean hasPassengerInRange(Entity entity, EntityPlayer entityplayer) {
|
||||
if (!entity.isVehicle()) {
|
||||
return false;
|
||||
}
|
||||
for (Entity passenger : entity.passengers) {
|
||||
if (passenger.tracker != null && passenger.tracker.isInRangeOfPlayer(entityplayer)) {
|
||||
return true;
|
||||
}
|
||||
if (passenger.isVehicle()) {
|
||||
if (hasPassengerInRange(passenger, entityplayer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static boolean isTrackedBy(Entity entity, EntityPlayer entityplayer) {
|
||||
return entity == entityplayer || entity.tracker != null && entity.tracker.trackedPlayers.contains(entityplayer);
|
||||
}
|
||||
private void updatePassengers(EntityPlayer player) {
|
||||
if (tracker.isVehicle()) {
|
||||
tracker.passengers.forEach((e) -> {
|
||||
if (e.tracker != null) {
|
||||
e.tracker.updatePlayer(player);
|
||||
}
|
||||
});
|
||||
player.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker));
|
||||
}
|
||||
}
|
||||
private boolean isInRangeOfPlayer(EntityPlayer entityplayer) {
|
||||
// Paper end
|
||||
double d0 = entityplayer.locX - (double) this.xLoc / 4096.0D;
|
||||
double d1 = entityplayer.locZ - (double) this.zLoc / 4096.0D;
|
||||
int i = Math.min(this.e, this.f);
|
||||
|
||||
return d0 >= (double) (-i) && d0 <= (double) i && d1 >= (double) (-i) && d1 <= (double) i && this.tracker.a(entityplayer);
|
||||
}
|
||||
|
||||
private boolean e(EntityPlayer entityplayer) {
|
||||
return entityplayer.x().getPlayerChunkMap().a(entityplayer, this.tracker.ab, this.tracker.ad);
|
||||
}
|
||||
|
||||
public void scanPlayers(List<EntityHuman> list) {
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
this.updatePlayer((EntityPlayer) list.get(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Packet<?> e() {
|
||||
if (this.tracker.dead) {
|
||||
// CraftBukkit start - Remove useless error spam, just return
|
||||
// EntityTrackerEntry.d.warn("Fetching addPacket for removed entity");
|
||||
return null;
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
if (this.tracker instanceof EntityPlayer) {
|
||||
return new PacketPlayOutNamedEntitySpawn((EntityHuman) this.tracker);
|
||||
} else if (this.tracker instanceof IAnimal) {
|
||||
this.headYaw = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
|
||||
return new PacketPlayOutSpawnEntityLiving((EntityLiving) this.tracker);
|
||||
} else if (this.tracker instanceof EntityPainting) {
|
||||
return new PacketPlayOutSpawnEntityPainting((EntityPainting) this.tracker);
|
||||
} else if (this.tracker instanceof EntityItem) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 2, 1);
|
||||
} else if (this.tracker instanceof EntityMinecartAbstract) {
|
||||
EntityMinecartAbstract entityminecartabstract = (EntityMinecartAbstract) this.tracker;
|
||||
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 10, entityminecartabstract.v().a());
|
||||
} else if (this.tracker instanceof EntityBoat) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 1);
|
||||
} else if (this.tracker instanceof EntityExperienceOrb) {
|
||||
return new PacketPlayOutSpawnEntityExperienceOrb((EntityExperienceOrb) this.tracker);
|
||||
} else if (this.tracker instanceof EntityFishingHook) {
|
||||
EntityHuman entityhuman = ((EntityFishingHook) this.tracker).l();
|
||||
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 90, entityhuman == null ? this.tracker.getId() : entityhuman.getId());
|
||||
} else {
|
||||
Entity entity;
|
||||
|
||||
if (this.tracker instanceof EntitySpectralArrow) {
|
||||
entity = ((EntitySpectralArrow) this.tracker).shooter;
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 91, 1 + (entity == null ? this.tracker.getId() : entity.getId()));
|
||||
} else if (this.tracker instanceof EntityTippedArrow) {
|
||||
entity = ((EntityArrow) this.tracker).shooter;
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 60, 1 + (entity == null ? this.tracker.getId() : entity.getId()));
|
||||
} else if (this.tracker instanceof EntitySnowball) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 61);
|
||||
} else if (this.tracker instanceof EntityLlamaSpit) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 68);
|
||||
} else if (this.tracker instanceof EntityPotion) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 73);
|
||||
} else if (this.tracker instanceof EntityThrownExpBottle) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 75);
|
||||
} else if (this.tracker instanceof EntityEnderPearl) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 65);
|
||||
} else if (this.tracker instanceof EntityEnderSignal) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 72);
|
||||
} else if (this.tracker instanceof EntityFireworks) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 76);
|
||||
} else if (this.tracker instanceof EntityFireball) {
|
||||
EntityFireball entityfireball = (EntityFireball) this.tracker;
|
||||
PacketPlayOutSpawnEntity packetplayoutspawnentity = null;
|
||||
byte b0 = 63;
|
||||
|
||||
if (this.tracker instanceof EntitySmallFireball) {
|
||||
b0 = 64;
|
||||
} else if (this.tracker instanceof EntityDragonFireball) {
|
||||
b0 = 93;
|
||||
} else if (this.tracker instanceof EntityWitherSkull) {
|
||||
b0 = 66;
|
||||
}
|
||||
|
||||
if (entityfireball.shooter != null) {
|
||||
packetplayoutspawnentity = new PacketPlayOutSpawnEntity(this.tracker, b0, ((EntityFireball) this.tracker).shooter.getId());
|
||||
} else {
|
||||
packetplayoutspawnentity = new PacketPlayOutSpawnEntity(this.tracker, b0, 0);
|
||||
}
|
||||
|
||||
packetplayoutspawnentity.a((int) (entityfireball.dirX * 8000.0D));
|
||||
packetplayoutspawnentity.b((int) (entityfireball.dirY * 8000.0D));
|
||||
packetplayoutspawnentity.c((int) (entityfireball.dirZ * 8000.0D));
|
||||
return packetplayoutspawnentity;
|
||||
} else if (this.tracker instanceof EntityShulkerBullet) {
|
||||
PacketPlayOutSpawnEntity packetplayoutspawnentity1 = new PacketPlayOutSpawnEntity(this.tracker, 67, 0);
|
||||
|
||||
packetplayoutspawnentity1.a((int) (this.tracker.motX * 8000.0D));
|
||||
packetplayoutspawnentity1.b((int) (this.tracker.motY * 8000.0D));
|
||||
packetplayoutspawnentity1.c((int) (this.tracker.motZ * 8000.0D));
|
||||
return packetplayoutspawnentity1;
|
||||
} else if (this.tracker instanceof EntityEgg) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 62);
|
||||
} else if (this.tracker instanceof EntityEvokerFangs) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 79);
|
||||
} else if (this.tracker instanceof EntityTNTPrimed) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 50);
|
||||
} else if (this.tracker instanceof EntityEnderCrystal) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 51);
|
||||
} else if (this.tracker instanceof EntityFallingBlock) {
|
||||
EntityFallingBlock entityfallingblock = (EntityFallingBlock) this.tracker;
|
||||
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 70, Block.getCombinedId(entityfallingblock.getBlock()));
|
||||
} else if (this.tracker instanceof EntityArmorStand) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 78);
|
||||
} else if (this.tracker instanceof EntityItemFrame) {
|
||||
EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker;
|
||||
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 71, entityitemframe.direction.get2DRotationValue(), entityitemframe.getBlockPosition());
|
||||
} else if (this.tracker instanceof EntityLeash) {
|
||||
EntityLeash entityleash = (EntityLeash) this.tracker;
|
||||
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 77, 0, entityleash.getBlockPosition());
|
||||
} else if (this.tracker instanceof EntityAreaEffectCloud) {
|
||||
return new PacketPlayOutSpawnEntity(this.tracker, 3);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don\'t know how to add " + this.tracker.getClass() + "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(EntityPlayer entityplayer) {
|
||||
org.spigotmc.AsyncCatcher.catchOp( "player tracker clear"); // Spigot
|
||||
if (this.trackedPlayers.contains(entityplayer)) {
|
||||
this.trackedPlayers.remove(entityplayer);
|
||||
this.tracker.c(entityplayer);
|
||||
entityplayer.c(this.tracker);
|
||||
updatePassengers(entityplayer); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Entity b() {
|
||||
return this.tracker;
|
||||
}
|
||||
|
||||
public void a(int i) {
|
||||
this.f = i;
|
||||
}
|
||||
|
||||
public void c() {
|
||||
this.isMoving = false;
|
||||
}
|
||||
}
|
||||
504
sources/src/main/java/net/minecraft/server/Explosion.java
Normal file
504
sources/src/main/java/net/minecraft/server/Explosion.java
Normal file
@@ -0,0 +1,504 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
// CraftBukkit start
|
||||
import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.block.BlockExplodeEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class Explosion {
|
||||
|
||||
private final boolean a;
|
||||
private final boolean b;
|
||||
private final Random c = new Random();
|
||||
private final World world;
|
||||
private final double posX;
|
||||
private final double posY;
|
||||
private final double posZ;
|
||||
public final Entity source;
|
||||
private final float size;
|
||||
private final ArrayList<BlockPosition> blocks = Lists.newArrayList();
|
||||
private final Map<EntityHuman, Vec3D> k = Maps.newHashMap();
|
||||
public boolean wasCanceled = false; // CraftBukkit - add field
|
||||
|
||||
// Dionysus start
|
||||
private final BlockPosition.MutableBlockPosition cachedPos = new BlockPosition.MutableBlockPosition();
|
||||
// The chunk coordinate of the most recently stepped through block.
|
||||
private int prevChunkX = Integer.MIN_VALUE;
|
||||
private int prevChunkZ = Integer.MIN_VALUE;
|
||||
|
||||
// The chunk belonging to prevChunkPos.
|
||||
private Chunk prevChunk;
|
||||
|
||||
private static final com.google.common.base.Predicate<Entity> hitPredicate = entity -> IEntitySelector.d.apply(entity) && !entity.dead; // Dionysus - Paper - don't hit dead entities
|
||||
// Dionysus end
|
||||
|
||||
public Explosion(World world, Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) {
|
||||
this.world = world;
|
||||
this.source = entity;
|
||||
this.size = (float) Math.max(f, 0.0); // CraftBukkit - clamp bad values
|
||||
this.posX = d0;
|
||||
this.posY = d1;
|
||||
this.posZ = d2;
|
||||
this.a = flag;
|
||||
this.b = flag1;
|
||||
}
|
||||
|
||||
public void a() {
|
||||
// CraftBukkit start
|
||||
if (this.size < 0.1F) {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
// Dionysus start - optimize memory usage from explosions
|
||||
// CaffeineMC optimized raytracing loop
|
||||
// @author JellySquid
|
||||
// @author nopjmp
|
||||
// https://github.com/CaffeineMC/lithium-fabric
|
||||
// Using integer encoding for the block positions provides a massive speedup and prevents us from needing to
|
||||
// allocate a block position for every step we make along each ray, eliminating essentially all the memory
|
||||
// allocations of this function. The overhead of packing block positions into integer format is negligible
|
||||
// compared to a memory allocation and associated overhead of hashing real objects in a set.
|
||||
final LongOpenHashSet touched = new LongOpenHashSet(0);
|
||||
final Random random = this.world.random;
|
||||
for (int rayX = 0; rayX < 16; ++rayX) {
|
||||
boolean xPlane = rayX == 0 || rayX == 15;
|
||||
double vecX = (((float) rayX / 15.0F) * 2.0F) - 1.0F;
|
||||
|
||||
for (int rayY = 0; rayY < 16; ++rayY) {
|
||||
boolean yPlane = rayY == 0 || rayY == 15;
|
||||
double vecY = (((float) rayY / 15.0F) * 2.0F) - 1.0F;
|
||||
|
||||
for (int rayZ = 0; rayZ < 16; ++rayZ) {
|
||||
boolean zPlane = rayZ == 0 || rayZ == 15;
|
||||
|
||||
// We only fire rays from the surface of our origin volume
|
||||
if (xPlane || yPlane || zPlane) {
|
||||
double vecZ = (((float) rayZ / 15.0F) * 2.0F) - 1.0F;
|
||||
|
||||
this.performRayCast(random, vecX, vecY, vecZ, touched);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can now iterate back over the set of positions we modified and re-build BlockPos objects from them
|
||||
// This will only allocate as many objects as there are in the set, where otherwise we would allocate them
|
||||
// each step of a every ray.
|
||||
blocks.ensureCapacity(touched.size());
|
||||
for (Long longPos : touched) {
|
||||
blocks.add(BlockPosition.fromLong(longPos));
|
||||
}
|
||||
float f3 = this.size * 2.0F;
|
||||
|
||||
int i = MathHelper.floor(this.posX - (double) f3 - 1.0D);
|
||||
int j = MathHelper.floor(this.posX + (double) f3 + 1.0D);
|
||||
int l = MathHelper.floor(this.posY - (double) f3 - 1.0D);
|
||||
int i1 = MathHelper.floor(this.posY + (double) f3 + 1.0D);
|
||||
int j1 = MathHelper.floor(this.posZ - (double) f3 - 1.0D);
|
||||
int k1 = MathHelper.floor(this.posZ + (double) f3 + 1.0D);
|
||||
// Paper start - Fix lag from explosions processing dead entities
|
||||
List<Entity> list = this.world.getEntities(this.source, new AxisAlignedBB(i, l, j1, j, i1, k1), hitPredicate);
|
||||
// Paper end
|
||||
Vec3D vec3d = new Vec3D(this.posX, this.posY, this.posZ);
|
||||
|
||||
for (Entity entity : list) {
|
||||
|
||||
if (!entity.bB()) {
|
||||
double d7 = entity.e(this.posX, this.posY, this.posZ) / (double) f3;
|
||||
|
||||
if (d7 <= 1.0D) {
|
||||
double d8 = entity.locX - this.posX;
|
||||
double d9 = entity.locY + (double) entity.getHeadHeight() - this.posY;
|
||||
double d10 = entity.locZ - this.posZ;
|
||||
double d11 = MathHelper.sqrt(d8 * d8 + d9 * d9 + d10 * d10);
|
||||
|
||||
if (d11 != 0.0D) {
|
||||
d8 /= d11;
|
||||
d9 /= d11;
|
||||
d10 /= d11;
|
||||
double d12 = this.getBlockDensity(vec3d, entity.getBoundingBox()); // Paper - Optimize explosions
|
||||
double d13 = (1.0D - d7) * d12;
|
||||
|
||||
// CraftBukkit start
|
||||
// entity.damageEntity(DamageSource.explosion(this), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f3 + 1.0D)));
|
||||
CraftEventFactory.entityDamage = source;
|
||||
entity.forceExplosionKnockback = false;
|
||||
boolean wasDamaged = entity.damageEntity(DamageSource.explosion(this), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f3 + 1.0D)));
|
||||
CraftEventFactory.entityDamage = null;
|
||||
if (!wasDamaged && !(entity instanceof EntityTNTPrimed || entity instanceof EntityFallingBlock) && !entity.forceExplosionKnockback) {
|
||||
continue;
|
||||
}
|
||||
// CraftBukkit end
|
||||
double d14 = d13;
|
||||
|
||||
if (entity instanceof EntityLiving) {
|
||||
d14 = entity instanceof EntityHuman && world.paperConfig.disableExplosionKnockback ? 0 : EnchantmentProtection.a((EntityLiving) entity, d13); // Paper - Disable explosion knockback
|
||||
}
|
||||
|
||||
entity.motX += d8 * d14;
|
||||
entity.motY += d9 * d14;
|
||||
entity.motZ += d10 * d14;
|
||||
if (entity instanceof EntityHuman) {
|
||||
EntityHuman entityhuman = (EntityHuman) entity;
|
||||
|
||||
if (!entityhuman.isSpectator() && (!entityhuman.z() && !world.paperConfig.disableExplosionKnockback || !entityhuman.abilities.isFlying)) { // Paper - Disable explosion knockback
|
||||
this.k.put(entityhuman, new Vec3D(d8 * d13, d9 * d13, d10 * d13));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void performRayCast(Random random, double vecX, double vecY, double vecZ, LongOpenHashSet touched) {
|
||||
double dist = Math.sqrt((vecX * vecX) + (vecY * vecY) + (vecZ * vecZ));
|
||||
|
||||
double normX = (vecX / dist) * 0.3D;
|
||||
double normY = (vecY / dist) * 0.3D;
|
||||
double normZ = (vecZ / dist) * 0.3D;
|
||||
|
||||
float strength = this.size * (0.7F + (random.nextFloat() * 0.6F));
|
||||
|
||||
double stepX = this.posX;
|
||||
double stepY = this.posY;
|
||||
double stepZ = this.posZ;
|
||||
|
||||
int prevX = Integer.MIN_VALUE;
|
||||
int prevY = Integer.MIN_VALUE;
|
||||
int prevZ = Integer.MIN_VALUE;
|
||||
|
||||
float prevResistance = 0.0F;
|
||||
|
||||
// Step through the ray until it is finally stopped
|
||||
while (strength > 0.0F) {
|
||||
int blockX = MathHelper.floor(stepX);
|
||||
int blockY = MathHelper.floor(stepY);
|
||||
int blockZ = MathHelper.floor(stepZ);
|
||||
|
||||
float resistance;
|
||||
|
||||
// Check whether or not we have actually moved into a new block this step. Due to how rays are stepped through,
|
||||
// over-sampling of the same block positions will occur. Changing this behaviour would introduce differences in
|
||||
// aliasing and sampling, which is unacceptable for our purposes. As a band-aid, we can simply re-use the
|
||||
// previous result and get a decent boost.
|
||||
if (prevX != blockX || prevY != blockY || prevZ != blockZ) {
|
||||
resistance = this.traverseBlock(strength, blockX, blockY, blockZ, touched);
|
||||
|
||||
prevX = blockX;
|
||||
prevY = blockY;
|
||||
prevZ = blockZ;
|
||||
|
||||
prevResistance = resistance;
|
||||
} else {
|
||||
resistance = prevResistance;
|
||||
}
|
||||
|
||||
strength -= resistance;
|
||||
// Apply a constant fall-off
|
||||
strength -= 0.22500001F;
|
||||
|
||||
stepX += normX;
|
||||
stepY += normY;
|
||||
stepZ += normZ;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called for every step made by a ray being cast by an explosion.
|
||||
*
|
||||
* @param strength The strength of the ray during this step
|
||||
* @param blockX The x-coordinate of the block the ray is inside of
|
||||
* @param blockY The y-coordinate of the block the ray is inside of
|
||||
* @param blockZ The z-coordinate of the block the ray is inside of
|
||||
* @return The resistance of the current block space to the ray
|
||||
*/
|
||||
private float traverseBlock(float strength, int blockX, int blockY, int blockZ, LongOpenHashSet touched) {
|
||||
cachedPos.c(blockX, blockY, blockZ);
|
||||
IBlockData iblockdata = this.world.getType(cachedPos);
|
||||
|
||||
// Early-exit if the y-coordinate is out of bounds.
|
||||
if (cachedPos.isInvalidYLocation()) {
|
||||
if (iblockdata.getMaterial() != Material.AIR) {
|
||||
float blastResistance = this.source != null ? this.source.a(this, this.world, cachedPos, iblockdata) : iblockdata.getBlock().a((Entity) null);
|
||||
return (blastResistance + 0.3F) * 0.3F;
|
||||
}
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
|
||||
int chunkX = blockX >> 4;
|
||||
int chunkZ = blockZ >> 4;
|
||||
|
||||
// Avoid calling into the chunk manager as much as possible through managing chunks locally
|
||||
if (this.prevChunkX != chunkX || this.prevChunkZ != chunkZ) {
|
||||
this.prevChunk = this.world.getChunkAt(chunkX, chunkZ);
|
||||
|
||||
this.prevChunkX = chunkX;
|
||||
this.prevChunkZ = chunkZ;
|
||||
}
|
||||
|
||||
final Chunk chunk = this.prevChunk;
|
||||
|
||||
float totalResistance = 0.0F;
|
||||
Optional<Float> blastResistance = Optional.empty();
|
||||
|
||||
// If the chunk is missing or out of bounds, assume that it is air
|
||||
if (chunk != null) {
|
||||
// We operate directly on chunk sections to avoid interacting with BlockPos and to squeeze out as much
|
||||
// performance as possible here
|
||||
ChunkSection section = chunk.getSections()[blockY >> 4];
|
||||
|
||||
// If the section doesn't exist or it's empty, assume that the block is air
|
||||
if (section != null && !section.a()) {
|
||||
// Retrieve the block state from the chunk section directly to avoid associated overhead
|
||||
IBlockData blockState = section.getType(blockX & 15, blockY & 15, blockZ & 15);
|
||||
|
||||
// If the block state is air, it cannot have fluid or any kind of resistance, so just leave
|
||||
if (blockState.getBlock() != Blocks.AIR) {
|
||||
// Get the explosion resistance like vanilla
|
||||
blastResistance = Optional.of(this.source != null ? this.source.a(this, this.world, cachedPos, iblockdata) : iblockdata.getBlock().a((Entity) null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate how much this block will resist an explosion's ray
|
||||
if (blastResistance.isPresent()) {
|
||||
totalResistance = (blastResistance.get() + 0.3F) * 0.3F;
|
||||
}
|
||||
|
||||
// Check if this ray is still strong enough to break blocks, and if so, add this position to the set
|
||||
// of positions to destroy
|
||||
float reducedStrength = strength - totalResistance;
|
||||
if (reducedStrength > 0.0F && (this.a || iblockdata.getMaterial() != Material.AIR)) {
|
||||
if ((this.source == null || this.source.a(this, this.world, cachedPos, iblockdata, reducedStrength)) && cachedPos.getY() < 256 && cachedPos.getY() >= 0) {
|
||||
touched.add(cachedPos.asLong());
|
||||
}
|
||||
}
|
||||
|
||||
return totalResistance;
|
||||
}
|
||||
// Dionysus end
|
||||
|
||||
|
||||
public void a(boolean flag) {
|
||||
this.world.a((EntityHuman) null, this.posX, this.posY, this.posZ, SoundEffects.bV, SoundCategory.BLOCKS, 4.0F, (1.0F + (this.world.random.nextFloat() - this.world.random.nextFloat()) * 0.2F) * 0.7F);
|
||||
if (this.size >= 2.0F && this.b) {
|
||||
this.world.addParticle(EnumParticle.EXPLOSION_HUGE, this.posX, this.posY, this.posZ, 1.0D, 0.0D, 0.0D);
|
||||
} else {
|
||||
this.world.addParticle(EnumParticle.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 1.0D, 0.0D, 0.0D);
|
||||
}
|
||||
|
||||
Iterator iterator;
|
||||
BlockPosition blockposition;
|
||||
|
||||
if (this.b) {
|
||||
// CraftBukkit start
|
||||
org.bukkit.World bworld = this.world.getWorld();
|
||||
org.bukkit.entity.Entity explode = this.source == null ? null : this.source.getBukkitEntity();
|
||||
Location location = new Location(bworld, this.posX, this.posY, this.posZ);
|
||||
|
||||
List<org.bukkit.block.Block> blockList = Lists.newArrayList();
|
||||
for (int i1 = this.blocks.size() - 1; i1 >= 0; i1--) {
|
||||
BlockPosition cpos = (BlockPosition) this.blocks.get(i1);
|
||||
org.bukkit.block.Block bblock = bworld.getBlockAt(cpos.getX(), cpos.getY(), cpos.getZ());
|
||||
if (bblock.getType() != org.bukkit.Material.AIR) {
|
||||
blockList.add(bblock);
|
||||
}
|
||||
}
|
||||
|
||||
boolean cancelled;
|
||||
List<org.bukkit.block.Block> bukkitBlocks;
|
||||
float yield;
|
||||
|
||||
if (explode != null) {
|
||||
EntityExplodeEvent event = new EntityExplodeEvent(explode, location, blockList, 1.0F / this.size);
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
cancelled = event.isCancelled();
|
||||
bukkitBlocks = event.blockList();
|
||||
yield = event.getYield();
|
||||
} else {
|
||||
BlockExplodeEvent event = new BlockExplodeEvent(location.getBlock(), blockList, 1.0F / this.size);
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
cancelled = event.isCancelled();
|
||||
bukkitBlocks = event.blockList();
|
||||
yield = event.getYield();
|
||||
}
|
||||
|
||||
this.blocks.clear();
|
||||
|
||||
this.blocks.ensureCapacity(bukkitBlocks.size());
|
||||
for (org.bukkit.block.Block bblock : bukkitBlocks) {
|
||||
BlockPosition coords = new BlockPosition(bblock.getX(), bblock.getY(), bblock.getZ());
|
||||
blocks.add(coords);
|
||||
}
|
||||
|
||||
if (cancelled) {
|
||||
this.wasCanceled = true;
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
iterator = this.blocks.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
blockposition = (BlockPosition) iterator.next();
|
||||
IBlockData iblockdata = this.world.getType(blockposition);
|
||||
Block block = iblockdata.getBlock();
|
||||
this.world.chunkPacketBlockController.updateNearbyBlocks(this.world, blockposition); // Paper - Anti-Xray
|
||||
|
||||
if (flag) {
|
||||
double d0 = (double) ((float) blockposition.getX() + this.world.random.nextFloat());
|
||||
double d1 = (double) ((float) blockposition.getY() + this.world.random.nextFloat());
|
||||
double d2 = (double) ((float) blockposition.getZ() + this.world.random.nextFloat());
|
||||
double d3 = d0 - this.posX;
|
||||
double d4 = d1 - this.posY;
|
||||
double d5 = d2 - this.posZ;
|
||||
double d6 = (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
|
||||
|
||||
d3 /= d6;
|
||||
d4 /= d6;
|
||||
d5 /= d6;
|
||||
double d7 = 0.5D / (d6 / (double) this.size + 0.1D);
|
||||
|
||||
d7 *= (double) (this.world.random.nextFloat() * this.world.random.nextFloat() + 0.3F);
|
||||
d3 *= d7;
|
||||
d4 *= d7;
|
||||
d5 *= d7;
|
||||
this.world.addParticle(EnumParticle.EXPLOSION_NORMAL, (d0 + this.posX) / 2.0D, (d1 + this.posY) / 2.0D, (d2 + this.posZ) / 2.0D, d3, d4, d5);
|
||||
this.world.addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, d3, d4, d5);
|
||||
}
|
||||
|
||||
if (iblockdata.getMaterial() != Material.AIR) {
|
||||
if (block.a(this)) {
|
||||
// CraftBukkit - add yield
|
||||
block.dropNaturally(this.world, blockposition, this.world.getType(blockposition), yield, 0);
|
||||
}
|
||||
|
||||
this.world.setTypeAndData(blockposition, Blocks.AIR.getBlockData(), 3);
|
||||
block.wasExploded(this.world, blockposition, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.a) {
|
||||
iterator = this.blocks.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
blockposition = (BlockPosition) iterator.next();
|
||||
if (this.world.getType(blockposition).getMaterial() == Material.AIR && this.world.getType(blockposition.down()).b() && this.c.nextInt(3) == 0) {
|
||||
// CraftBukkit start - Ignition by explosion
|
||||
if (!CraftEventFactory.callBlockIgniteEvent(this.world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this).isCancelled()) {
|
||||
this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData());
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Map<EntityHuman, Vec3D> b() {
|
||||
return this.k;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityLiving getSource() {
|
||||
// CraftBukkit start - obtain Fireball shooter for explosion tracking
|
||||
return this.source == null ? null : (this.source instanceof EntityTNTPrimed ? ((EntityTNTPrimed) this.source).getSource() : (this.source instanceof EntityLiving ? (EntityLiving) this.source : (this.source instanceof EntityFireball ? ((EntityFireball) this.source).shooter : null)));
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
public void clearBlocks() {
|
||||
this.blocks.clear();
|
||||
}
|
||||
|
||||
public List<BlockPosition> getBlocks() {
|
||||
return this.blocks;
|
||||
}
|
||||
|
||||
// Paper start - Optimize explosions
|
||||
private float getBlockDensity(Vec3D vec3d, AxisAlignedBB aabb) {
|
||||
if (!this.world.paperConfig.optimizeExplosions) {
|
||||
return this.world.a(vec3d, aabb);
|
||||
}
|
||||
CacheKey key = new CacheKey(this, aabb);
|
||||
return this.world.explosionDensityCache.computeIfAbsent(key, k1 -> this.world.a(vec3d, aabb));
|
||||
}
|
||||
|
||||
static class CacheKey {
|
||||
private final World world;
|
||||
private final double posX, posY, posZ;
|
||||
private final double minX, minY, minZ;
|
||||
private final double maxX, maxY, maxZ;
|
||||
|
||||
public CacheKey(Explosion explosion, AxisAlignedBB aabb) {
|
||||
this.world = explosion.world;
|
||||
this.posX = explosion.posX;
|
||||
this.posY = explosion.posY;
|
||||
this.posZ = explosion.posZ;
|
||||
this.minX = aabb.a;
|
||||
this.minY = aabb.b;
|
||||
this.minZ = aabb.c;
|
||||
this.maxX = aabb.d;
|
||||
this.maxY = aabb.e;
|
||||
this.maxZ = aabb.f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CacheKey cacheKey = (CacheKey) o;
|
||||
|
||||
if (Double.compare(cacheKey.posX, posX) != 0) return false;
|
||||
if (Double.compare(cacheKey.posY, posY) != 0) return false;
|
||||
if (Double.compare(cacheKey.posZ, posZ) != 0) return false;
|
||||
if (Double.compare(cacheKey.minX, minX) != 0) return false;
|
||||
if (Double.compare(cacheKey.minY, minY) != 0) return false;
|
||||
if (Double.compare(cacheKey.minZ, minZ) != 0) return false;
|
||||
if (Double.compare(cacheKey.maxX, maxX) != 0) return false;
|
||||
if (Double.compare(cacheKey.maxY, maxY) != 0) return false;
|
||||
if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false;
|
||||
return world.equals(cacheKey.world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
result = world.hashCode();
|
||||
temp = Double.doubleToLongBits(posX);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(posY);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(posZ);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(minX);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(minY);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(minZ);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(maxX);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(maxY);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(maxZ);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
// CraftBukkit start
|
||||
import java.net.InetAddress;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
// CraftBukkit end
|
||||
|
||||
public class HandshakeListener implements PacketHandshakingInListener {
|
||||
|
||||
private static final com.google.gson.Gson gson = new com.google.gson.Gson(); // Spigot
|
||||
// CraftBukkit start - add fields
|
||||
private static final Object2LongOpenHashMap<InetAddress> throttleTracker = new Object2LongOpenHashMap<>();
|
||||
private static int throttleCounter = 0;
|
||||
// CraftBukkit end
|
||||
|
||||
private final MinecraftServer a;
|
||||
private final NetworkManager b;
|
||||
private NetworkManager getNetworkManager() { return b; } // Paper - OBFHELPER
|
||||
|
||||
public HandshakeListener(MinecraftServer minecraftserver, NetworkManager networkmanager) {
|
||||
this.a = minecraftserver;
|
||||
this.b = networkmanager;
|
||||
}
|
||||
|
||||
public void a(PacketHandshakingInSetProtocol packethandshakinginsetprotocol) {
|
||||
switch (packethandshakinginsetprotocol.a()) {
|
||||
case LOGIN:
|
||||
this.b.setProtocol(EnumProtocol.LOGIN);
|
||||
ChatMessage chatmessage;
|
||||
|
||||
// CraftBukkit start - Connection throttle
|
||||
try {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long connectionThrottle = MinecraftServer.getServer().server.getConnectionThrottle();
|
||||
InetAddress address = ((java.net.InetSocketAddress) this.b.getSocketAddress()).getAddress();
|
||||
|
||||
synchronized (throttleTracker) {
|
||||
if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.getLong(address) < connectionThrottle) {
|
||||
throttleTracker.put(address, currentTime);
|
||||
chatmessage = new ChatMessage("Connection throttled! Please wait before reconnecting.");
|
||||
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
|
||||
this.b.close(chatmessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throttleTracker.put(address, currentTime);
|
||||
throttleCounter++;
|
||||
if (throttleCounter > 200) {
|
||||
throttleCounter = 0;
|
||||
|
||||
// Cleanup stale entries
|
||||
throttleTracker.object2LongEntrySet().removeIf(entry -> entry.getLongValue() > connectionThrottle); // Dionysus
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (packethandshakinginsetprotocol.b() > 340) {
|
||||
chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), "1.12.2" ) ); // Spigot
|
||||
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
|
||||
this.b.close(chatmessage);
|
||||
} else if (packethandshakinginsetprotocol.b() < 340) {
|
||||
chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), "1.12.2" ) ); // Spigot
|
||||
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
|
||||
this.b.close(chatmessage);
|
||||
} else {
|
||||
this.b.setPacketListener(new LoginListener(this.a, this.b));
|
||||
// Paper start - handshake event
|
||||
boolean proxyLogicEnabled = org.spigotmc.SpigotConfig.bungee;
|
||||
boolean handledByEvent = false;
|
||||
// Try and handle the handshake through the event
|
||||
if (com.destroystokyo.paper.event.player.PlayerHandshakeEvent.getHandlerList().getRegisteredListeners().length != 0) { // Hello? Can you hear me?
|
||||
com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packethandshakinginsetprotocol.hostname, !proxyLogicEnabled);
|
||||
if (event.callEvent()) {
|
||||
// If we've failed somehow, let the client know so and go no further.
|
||||
if (event.isFailed()) {
|
||||
chatmessage = new ChatMessage(event.getFailMessage());
|
||||
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
|
||||
this.b.close(chatmessage);
|
||||
return;
|
||||
}
|
||||
|
||||
packethandshakinginsetprotocol.hostname = event.getServerHostname();
|
||||
this.b.l = new java.net.InetSocketAddress(event.getSocketAddressHostname(), ((java.net.InetSocketAddress) this.b.getSocketAddress()).getPort());
|
||||
this.b.spoofedUUID = event.getUniqueId();
|
||||
this.b.spoofedProfile = gson.fromJson(event.getPropertiesJson(), com.mojang.authlib.properties.Property[].class);
|
||||
handledByEvent = true; // Hooray, we did it!
|
||||
}
|
||||
}
|
||||
// Don't try and handle default logic if it's been handled by the event.
|
||||
if (!handledByEvent && proxyLogicEnabled) {
|
||||
// Paper end
|
||||
// Spigot Start
|
||||
//if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above!
|
||||
String[] split = packethandshakinginsetprotocol.hostname.split("\00");
|
||||
if ( split.length == 3 || split.length == 4 ) {
|
||||
packethandshakinginsetprotocol.hostname = split[0];
|
||||
b.l = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) b.getSocketAddress()).getPort());
|
||||
b.spoofedUUID = com.mojang.util.UUIDTypeAdapter.fromString( split[2] );
|
||||
} else
|
||||
{
|
||||
chatmessage = new ChatMessage("If you wish to use IP forwarding, please enable it in your BungeeCord config as well!");
|
||||
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
|
||||
this.b.close(chatmessage);
|
||||
return;
|
||||
}
|
||||
if ( split.length == 4 )
|
||||
{
|
||||
b.spoofedProfile = gson.fromJson(split[3], com.mojang.authlib.properties.Property[].class);
|
||||
}
|
||||
}
|
||||
// Spigot End
|
||||
((LoginListener) this.b.i()).hostname = packethandshakinginsetprotocol.hostname + ":" + packethandshakinginsetprotocol.port; // CraftBukkit - set hostname
|
||||
}
|
||||
break;
|
||||
|
||||
case STATUS:
|
||||
this.b.setProtocol(EnumProtocol.STATUS);
|
||||
this.b.setPacketListener(new PacketStatusListener(this.a, this.b));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException("Invalid intention " + packethandshakinginsetprotocol.a());
|
||||
}
|
||||
|
||||
// Paper start - NetworkClient implementation
|
||||
this.getNetworkManager().protocolVersion = packethandshakinginsetprotocol.getProtocolVersion();
|
||||
this.getNetworkManager().virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(packethandshakinginsetprotocol.hostname, packethandshakinginsetprotocol.port);
|
||||
// Paper end
|
||||
}
|
||||
|
||||
public void a(IChatBaseComponent ichatbasecomponent) {}
|
||||
}
|
||||
113
sources/src/main/java/net/minecraft/server/IntCache.java
Normal file
113
sources/src/main/java/net/minecraft/server/IntCache.java
Normal file
@@ -0,0 +1,113 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
// NeonPaper start
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
// NeonPaper end
|
||||
|
||||
public class IntCache {
|
||||
// NeonPaper start - Refactored IntCache to be thread local instead of static
|
||||
private static final ThreadLocal<IntCache> caches = new ThreadLocal<IntCache>() {
|
||||
@Override
|
||||
protected IntCache initialValue() {
|
||||
IntCache cache = new IntCache();
|
||||
synchronized (ALL_CACHES) {
|
||||
ALL_CACHES.add(new WeakReference<>(cache));
|
||||
}
|
||||
return new IntCache();
|
||||
}
|
||||
};
|
||||
|
||||
private static final List<WeakReference<IntCache>> ALL_CACHES = new ObjectArrayList<>();
|
||||
|
||||
private int a = 256;
|
||||
private final List<int[]> b = new ObjectArrayList<>();
|
||||
private final List<int[]> c = new ObjectArrayList<>();
|
||||
private final List<int[]> d = new ObjectArrayList<>();
|
||||
private final List<int[]> e = new ObjectArrayList<>();
|
||||
|
||||
private final int cacheLimit = org.spigotmc.SpigotConfig.intCacheLimit;
|
||||
|
||||
public static int[] a(int i) {
|
||||
return caches.get().aNonStatic(i);
|
||||
}
|
||||
|
||||
public int[] aNonStatic(int i) {
|
||||
int[] aint;
|
||||
|
||||
if (i <= 256) {
|
||||
if (this.b.isEmpty()) {
|
||||
aint = new int[256];
|
||||
if (c.size() < cacheLimit) this.c.add(aint);
|
||||
return aint;
|
||||
} else {
|
||||
aint = this.b.remove(this.b.size() - 1);
|
||||
if (c.size() < cacheLimit) this.c.add(aint);
|
||||
return aint;
|
||||
}
|
||||
} else if (i > this.a) {
|
||||
this.a = i;
|
||||
this.d.clear();
|
||||
this.e.clear();
|
||||
aint = new int[this.a];
|
||||
if (e.size() < cacheLimit) this.e.add(aint);
|
||||
return aint;
|
||||
} else if (this.d.isEmpty()) {
|
||||
aint = new int[this.a];
|
||||
if (e.size() < cacheLimit) this.e.add(aint);
|
||||
return aint;
|
||||
} else {
|
||||
aint = this.d.remove(this.d.size() - 1);
|
||||
if (e.size() < cacheLimit) this.e.add(aint);
|
||||
return aint;
|
||||
}
|
||||
}
|
||||
|
||||
public static void a() {
|
||||
caches.get().aNonStatic();
|
||||
}
|
||||
|
||||
public void aNonStatic() {
|
||||
if (!this.d.isEmpty()) {
|
||||
this.d.remove(this.d.size() - 1);
|
||||
}
|
||||
|
||||
if (!this.b.isEmpty()) {
|
||||
this.b.remove(this.b.size() - 1);
|
||||
}
|
||||
|
||||
this.d.addAll(this.e);
|
||||
this.b.addAll(this.c);
|
||||
this.e.clear();
|
||||
this.c.clear();
|
||||
}
|
||||
|
||||
public static String b() {
|
||||
int cache = 0;
|
||||
int tcache = 0;
|
||||
int allocated = 0;
|
||||
int tallocated = 0;
|
||||
int numberOfCaches;
|
||||
|
||||
synchronized (ALL_CACHES) {
|
||||
numberOfCaches = ALL_CACHES.size();
|
||||
Iterator<WeakReference<IntCache>> iter = ALL_CACHES.iterator();
|
||||
while (iter.hasNext()) {
|
||||
WeakReference<IntCache> reference = iter.next();
|
||||
IntCache intcache = reference.get();
|
||||
if (intcache != null) {
|
||||
cache += intcache.d.size();
|
||||
tcache += intcache.b.size();
|
||||
allocated += intcache.e.size();
|
||||
tallocated += intcache.c.size();
|
||||
} else {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return numberOfCaches + " IntCaches. In Total => cache: " + cache + ", tcache: " + tcache + ", allocated: " + allocated + ", tallocated: " + tallocated;
|
||||
}
|
||||
// NeonPaper end
|
||||
}
|
||||
367
sources/src/main/java/net/minecraft/server/ItemWorldMap.java
Normal file
367
sources/src/main/java/net/minecraft/server/ItemWorldMap.java
Normal file
@@ -0,0 +1,367 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multisets;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
// CraftBukkit start
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.server.MapInitializeEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class ItemWorldMap extends ItemWorldMapBase {
|
||||
|
||||
protected ItemWorldMap() {
|
||||
this.a(true);
|
||||
}
|
||||
|
||||
public static ItemStack a(World world, double d0, double d1, byte b0, boolean flag, boolean flag1) {
|
||||
World worldMain = world.getServer().getServer().worlds.get(0); // CraftBukkit - store reference to primary world
|
||||
ItemStack itemstack = new ItemStack(Items.FILLED_MAP, 1, worldMain.b("map")); // CraftBukkit - use primary world for maps
|
||||
String s = "map_" + itemstack.getData();
|
||||
WorldMap worldmap = new WorldMap(s);
|
||||
|
||||
worldMain.a(s, (PersistentBase) worldmap); // CraftBukkit
|
||||
worldmap.scale = b0;
|
||||
worldmap.a(d0, d1, worldmap.scale);
|
||||
worldmap.map = (byte) ((WorldServer) world).dimension; // CraftBukkit - use bukkit dimension
|
||||
worldmap.track = flag;
|
||||
worldmap.unlimitedTracking = flag1;
|
||||
worldmap.c();
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.callEvent(new org.bukkit.event.server.MapInitializeEvent(worldmap.mapView)); // CraftBukkit
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WorldMap getSavedMap(ItemStack itemstack, World world) {
|
||||
World worldMain = world.getServer().getServer().worlds.get(0); // CraftBukkit - store reference to primary world
|
||||
String s = "map_" + itemstack.getData();
|
||||
WorldMap worldmap = (WorldMap) worldMain.a(WorldMap.class, s); // CraftBukkit - use primary world for maps
|
||||
|
||||
if (worldmap == null && !world.isClientSide) {
|
||||
itemstack.setData(worldMain.b("map")); // CraftBukkit - use primary world for maps
|
||||
s = "map_" + itemstack.getData();
|
||||
worldmap = new WorldMap(s);
|
||||
worldmap.scale = 3;
|
||||
worldmap.a((double) world.getWorldData().b(), (double) world.getWorldData().d(), worldmap.scale);
|
||||
worldmap.map = (byte) ((WorldServer) world).dimension; // CraftBukkit - fixes Bukkit multiworld maps
|
||||
worldmap.c();
|
||||
worldMain.a(s, (PersistentBase) worldmap); // CraftBukkit - use primary world for maps
|
||||
|
||||
// CraftBukkit start
|
||||
MapInitializeEvent event = new MapInitializeEvent(worldmap.mapView);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
return worldmap;
|
||||
}
|
||||
|
||||
public void a(World world, Entity entity, WorldMap worldmap) {
|
||||
// CraftBukkit - world.worldProvider -> ((WorldServer) world)
|
||||
if (((WorldServer) world).dimension == worldmap.map && entity instanceof EntityHuman) {
|
||||
int i = 1 << worldmap.scale;
|
||||
int j = worldmap.centerX;
|
||||
int k = worldmap.centerZ;
|
||||
int l = MathHelper.floor(entity.locX - (double) j) / i + 64;
|
||||
int i1 = MathHelper.floor(entity.locZ - (double) k) / i + 64;
|
||||
int j1 = 128 / i;
|
||||
|
||||
if (world.worldProvider.n()) {
|
||||
j1 /= 2;
|
||||
}
|
||||
|
||||
WorldMap.WorldMapHumanTracker worldmap_worldmaphumantracker = worldmap.a((EntityHuman) entity);
|
||||
|
||||
++worldmap_worldmaphumantracker.b;
|
||||
boolean flag = false;
|
||||
|
||||
for (int k1 = l - j1 + 1; k1 < l + j1; ++k1) {
|
||||
if ((k1 & 15) == (worldmap_worldmaphumantracker.b & 15) || flag) {
|
||||
flag = false;
|
||||
double d0 = 0.0D;
|
||||
|
||||
for (int l1 = i1 - j1 - 1; l1 < i1 + j1; ++l1) {
|
||||
if (k1 >= 0 && l1 >= -1 && k1 < 128 && l1 < 128) {
|
||||
int i2 = k1 - l;
|
||||
int j2 = l1 - i1;
|
||||
boolean flag1 = i2 * i2 + j2 * j2 > (j1 - 2) * (j1 - 2);
|
||||
int k2 = (j / i + k1 - 64) * i;
|
||||
int l2 = (k / i + l1 - 64) * i;
|
||||
HashMultiset hashmultiset = HashMultiset.create();
|
||||
Chunk chunk = world.getChunkIfLoaded(new BlockPosition(k2, 0, l2)); // NeonPaper - Maps shouldn't load chunks
|
||||
|
||||
if (chunk != null && !chunk.isEmpty()) { // NeonPaper - Maps shouldn't load chunks
|
||||
int i3 = k2 & 15;
|
||||
int j3 = l2 & 15;
|
||||
int k3 = 0;
|
||||
double d1 = 0.0D;
|
||||
|
||||
if (world.worldProvider.n()) {
|
||||
int l3 = k2 + l2 * 231871;
|
||||
|
||||
l3 = l3 * l3 * 31287121 + l3 * 11;
|
||||
if ((l3 >> 20 & 1) == 0) {
|
||||
hashmultiset.add(Blocks.DIRT.getBlockData().set(BlockDirt.VARIANT, BlockDirt.EnumDirtVariant.DIRT).a((IBlockAccess) world, BlockPosition.ZERO), 10);
|
||||
} else {
|
||||
hashmultiset.add(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.STONE).a((IBlockAccess) world, BlockPosition.ZERO), 100);
|
||||
}
|
||||
|
||||
d1 = 100.0D;
|
||||
} else {
|
||||
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
|
||||
|
||||
for (int i4 = 0; i4 < i; ++i4) {
|
||||
for (int j4 = 0; j4 < i; ++j4) {
|
||||
int k4 = chunk.b(i4 + i3, j4 + j3) + 1;
|
||||
IBlockData iblockdata = Blocks.AIR.getBlockData();
|
||||
|
||||
if (k4 > 1) {
|
||||
do {
|
||||
--k4;
|
||||
iblockdata = chunk.a(i4 + i3, k4, j4 + j3);
|
||||
blockposition_mutableblockposition.c((chunk.locX << 4) + i4 + i3, k4, (chunk.locZ << 4) + j4 + j3);
|
||||
} while (iblockdata.a((IBlockAccess) world, blockposition_mutableblockposition) == MaterialMapColor.c && k4 > 0);
|
||||
|
||||
if (k4 > 0 && iblockdata.getMaterial().isLiquid()) {
|
||||
int l4 = k4 - 1;
|
||||
|
||||
IBlockData iblockdata1;
|
||||
|
||||
do {
|
||||
iblockdata1 = chunk.a(i4 + i3, l4--, j4 + j3);
|
||||
++k3;
|
||||
} while (l4 > 0 && iblockdata1.getMaterial().isLiquid());
|
||||
}
|
||||
} else {
|
||||
iblockdata = Blocks.BEDROCK.getBlockData();
|
||||
}
|
||||
|
||||
d1 += (double) k4 / (double) (i * i);
|
||||
hashmultiset.add(iblockdata.a((IBlockAccess) world, blockposition_mutableblockposition));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k3 /= i * i;
|
||||
double d2 = (d1 - d0) * 4.0D / (double) (i + 4) + ((double) (k1 + l1 & 1) - 0.5D) * 0.4D;
|
||||
byte b0 = 1;
|
||||
|
||||
if (d2 > 0.6D) {
|
||||
b0 = 2;
|
||||
}
|
||||
|
||||
if (d2 < -0.6D) {
|
||||
b0 = 0;
|
||||
}
|
||||
|
||||
MaterialMapColor materialmapcolor = (MaterialMapColor) Iterables.getFirst(Multisets.copyHighestCountFirst(hashmultiset), MaterialMapColor.c);
|
||||
|
||||
if (materialmapcolor == MaterialMapColor.o) {
|
||||
d2 = (double) k3 * 0.1D + (double) (k1 + l1 & 1) * 0.2D;
|
||||
b0 = 1;
|
||||
if (d2 < 0.5D) {
|
||||
b0 = 2;
|
||||
}
|
||||
|
||||
if (d2 > 0.9D) {
|
||||
b0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
d0 = d1;
|
||||
if (l1 >= 0 && i2 * i2 + j2 * j2 < j1 * j1 && (!flag1 || (k1 + l1 & 1) != 0)) {
|
||||
byte b1 = worldmap.colors[k1 + l1 * 128];
|
||||
byte b2 = (byte) (materialmapcolor.ad * 4 + b0);
|
||||
|
||||
if (b1 != b2) {
|
||||
worldmap.colors[k1 + l1 * 128] = b2;
|
||||
worldmap.flagDirty(k1, l1);
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void a(World world, ItemStack itemstack) {
|
||||
if (itemstack.getItem() == Items.FILLED_MAP) {
|
||||
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, world);
|
||||
|
||||
if (worldmap != null) {
|
||||
if (world.worldProvider.getDimensionManager().getDimensionID() == worldmap.map) {
|
||||
int i = 1 << worldmap.scale;
|
||||
int j = worldmap.centerX;
|
||||
int k = worldmap.centerZ;
|
||||
BiomeBase[] abiomebase = world.getWorldChunkManager().a((BiomeBase[]) null, (j / i - 64) * i, (k / i - 64) * i, 128 * i, 128 * i, false);
|
||||
|
||||
for (int l = 0; l < 128; ++l) {
|
||||
for (int i1 = 0; i1 < 128; ++i1) {
|
||||
int j1 = l * i;
|
||||
int k1 = i1 * i;
|
||||
BiomeBase biomebase = abiomebase[j1 + k1 * 128 * i];
|
||||
MaterialMapColor materialmapcolor = MaterialMapColor.c;
|
||||
int l1 = 3;
|
||||
int i2 = 8;
|
||||
|
||||
if (l > 0 && i1 > 0 && l < 127 && i1 < 127) {
|
||||
if (abiomebase[(l - 1) * i + (i1 - 1) * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (abiomebase[(l - 1) * i + (i1 + 1) * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (abiomebase[(l - 1) * i + i1 * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (abiomebase[(l + 1) * i + (i1 - 1) * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (abiomebase[(l + 1) * i + (i1 + 1) * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (abiomebase[(l + 1) * i + i1 * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (abiomebase[l * i + (i1 - 1) * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (abiomebase[l * i + (i1 + 1) * i * 128 * i].j() >= 0.0F) {
|
||||
--i2;
|
||||
}
|
||||
|
||||
if (biomebase.j() < 0.0F) {
|
||||
materialmapcolor = MaterialMapColor.r;
|
||||
if (i2 > 7 && i1 % 2 == 0) {
|
||||
l1 = (l + (int) (MathHelper.sin((float) i1 + 0.0F) * 7.0F)) / 8 % 5;
|
||||
if (l1 == 3) {
|
||||
l1 = 1;
|
||||
} else if (l1 == 4) {
|
||||
l1 = 0;
|
||||
}
|
||||
} else if (i2 > 7) {
|
||||
materialmapcolor = MaterialMapColor.c;
|
||||
} else if (i2 > 5) {
|
||||
l1 = 1;
|
||||
} else if (i2 > 3) {
|
||||
l1 = 0;
|
||||
} else if (i2 > 1) {
|
||||
l1 = 0;
|
||||
}
|
||||
} else if (i2 > 0) {
|
||||
materialmapcolor = MaterialMapColor.C;
|
||||
if (i2 > 3) {
|
||||
l1 = 1;
|
||||
} else {
|
||||
l1 = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (materialmapcolor != MaterialMapColor.c) {
|
||||
worldmap.colors[l + i1 * 128] = (byte) (materialmapcolor.ad * 4 + l1);
|
||||
worldmap.flagDirty(l, i1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void a(ItemStack itemstack, World world, Entity entity, int i, boolean flag) {
|
||||
if (!world.isClientSide) {
|
||||
WorldMap worldmap = this.getSavedMap(itemstack, world);
|
||||
|
||||
if (entity instanceof EntityHuman) {
|
||||
EntityHuman entityhuman = (EntityHuman) entity;
|
||||
|
||||
worldmap.a(entityhuman, itemstack);
|
||||
}
|
||||
|
||||
if (flag || entity instanceof EntityHuman && ((EntityHuman) entity).getItemInOffHand() == itemstack) {
|
||||
this.a(world, entity, worldmap);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Packet<?> a(ItemStack itemstack, World world, EntityHuman entityhuman) {
|
||||
return this.getSavedMap(itemstack, world).a(itemstack, world, entityhuman);
|
||||
}
|
||||
|
||||
public void b(ItemStack itemstack, World world, EntityHuman entityhuman) {
|
||||
NBTTagCompound nbttagcompound = itemstack.getTag();
|
||||
|
||||
if (nbttagcompound != null) {
|
||||
if (nbttagcompound.hasKeyOfType("map_scale_direction", 99)) {
|
||||
a(itemstack, world, nbttagcompound.getInt("map_scale_direction"));
|
||||
nbttagcompound.remove("map_scale_direction");
|
||||
} else if (nbttagcompound.getBoolean("map_tracking_position")) {
|
||||
b(itemstack, world);
|
||||
nbttagcompound.remove("map_tracking_position");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static void a(ItemStack itemstack, World world, int i) {
|
||||
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, world);
|
||||
|
||||
world = world.getServer().getServer().worlds.get(0); // CraftBukkit - use primary world for maps
|
||||
itemstack.setData(world.b("map"));
|
||||
WorldMap worldmap1 = new WorldMap("map_" + itemstack.getData());
|
||||
|
||||
if (worldmap != null) {
|
||||
worldmap1.scale = (byte) MathHelper.clamp(worldmap.scale + i, 0, 4);
|
||||
worldmap1.track = worldmap.track;
|
||||
worldmap1.a((double) worldmap.centerX, (double) worldmap.centerZ, worldmap1.scale);
|
||||
worldmap1.map = worldmap.map;
|
||||
worldmap1.c();
|
||||
world.a("map_" + itemstack.getData(), (PersistentBase) worldmap1);
|
||||
// CraftBukkit start
|
||||
MapInitializeEvent event = new MapInitializeEvent(worldmap1.mapView);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static void b(ItemStack itemstack, World world) {
|
||||
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, world);
|
||||
|
||||
world = world.getServer().getServer().worlds.get(0); // CraftBukkit - use primary world for maps
|
||||
itemstack.setData(world.b("map"));
|
||||
WorldMap worldmap1 = new WorldMap("map_" + itemstack.getData());
|
||||
|
||||
worldmap1.track = true;
|
||||
if (worldmap != null) {
|
||||
worldmap1.centerX = worldmap.centerX;
|
||||
worldmap1.centerZ = worldmap.centerZ;
|
||||
worldmap1.scale = worldmap.scale;
|
||||
worldmap1.map = worldmap.map;
|
||||
worldmap1.c();
|
||||
world.a("map_" + itemstack.getData(), (PersistentBase) worldmap1);
|
||||
// CraftBukkit start
|
||||
MapInitializeEvent event = new MapInitializeEvent(worldmap1.mapView);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
370
sources/src/main/java/net/minecraft/server/MathHelper.java
Normal file
370
sources/src/main/java/net/minecraft/server/MathHelper.java
Normal file
@@ -0,0 +1,370 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MathHelper {
|
||||
|
||||
public static final float a = c(2.0F);
|
||||
private static final int[] SINE_TABLE_INT = new int[16384 + 1];
|
||||
private static final float SINE_TABLE_MIDPOINT;
|
||||
private static final Random c = new Random();
|
||||
private static final int[] d;
|
||||
private static final double e;
|
||||
private static final double[] f;
|
||||
private static final double[] g;
|
||||
|
||||
public static float sin(float f) {
|
||||
return lookup((int) (f * 10430.38) & 0xFFFF);
|
||||
}
|
||||
|
||||
public static float cos(float f) {
|
||||
return lookup((int) (f * 10430.38 + 16384.0) & 0xFFFF);
|
||||
}
|
||||
|
||||
private static float lookup(int index) {
|
||||
if (index == 32768) {
|
||||
return SINE_TABLE_MIDPOINT;
|
||||
}
|
||||
int neg = (index & 0x8000) << 16;
|
||||
int mask = (index << 17) >> 31;
|
||||
int pos = (0x8001 & mask) + (index ^ mask);
|
||||
pos &= 0x7fff;
|
||||
return Float.intBitsToFloat(SINE_TABLE_INT[pos] ^ neg);
|
||||
}
|
||||
|
||||
public static float c(float f) {
|
||||
return (float) Math.sqrt((double) f);
|
||||
}
|
||||
|
||||
public static float sqrt(double d0) {
|
||||
return (float) Math.sqrt(d0);
|
||||
}
|
||||
|
||||
public static int d(float f) {
|
||||
int i = (int) f;
|
||||
|
||||
return f < (float) i ? i - 1 : i;
|
||||
}
|
||||
|
||||
public static int floor(double d0) {
|
||||
int i = (int) d0;
|
||||
|
||||
return d0 < (double) i ? i - 1 : i;
|
||||
}
|
||||
|
||||
public static long d(double d0) {
|
||||
long i = (long) d0;
|
||||
|
||||
return d0 < (double) i ? i - 1L : i;
|
||||
}
|
||||
|
||||
public static float e(float f) {
|
||||
return f >= 0.0F ? f : -f;
|
||||
}
|
||||
|
||||
public static int a(int i) {
|
||||
return i >= 0 ? i : -i;
|
||||
}
|
||||
|
||||
public static int f(float f) {
|
||||
int i = (int) f;
|
||||
|
||||
return f > (float) i ? i + 1 : i;
|
||||
}
|
||||
|
||||
public static int f(double d0) {
|
||||
int i = (int) d0;
|
||||
|
||||
return d0 > (double) i ? i + 1 : i;
|
||||
}
|
||||
|
||||
public static int clamp(int i, int j, int k) {
|
||||
return i < j ? j : (i > k ? k : i);
|
||||
}
|
||||
|
||||
public static float a(float f, float f1, float f2) {
|
||||
return f < f1 ? f1 : (f > f2 ? f2 : f);
|
||||
}
|
||||
|
||||
public static double a(double d0, double d1, double d2) {
|
||||
return d0 < d1 ? d1 : (d0 > d2 ? d2 : d0);
|
||||
}
|
||||
|
||||
public static double b(double d0, double d1, double d2) {
|
||||
return d2 < 0.0D ? d0 : (d2 > 1.0D ? d1 : d0 + (d1 - d0) * d2);
|
||||
}
|
||||
|
||||
public static double a(double d0, double d1) {
|
||||
if (d0 < 0.0D) {
|
||||
d0 = -d0;
|
||||
}
|
||||
|
||||
if (d1 < 0.0D) {
|
||||
d1 = -d1;
|
||||
}
|
||||
|
||||
return d0 > d1 ? d0 : d1;
|
||||
}
|
||||
|
||||
public static int nextInt(Random random, int i, int j) {
|
||||
return i >= j ? i : random.nextInt(j - i + 1) + i;
|
||||
}
|
||||
|
||||
public static float a(Random random, float f, float f1) {
|
||||
return f >= f1 ? f : random.nextFloat() * (f1 - f) + f;
|
||||
}
|
||||
|
||||
public static double a(Random random, double d0, double d1) {
|
||||
return d0 >= d1 ? d0 : random.nextDouble() * (d1 - d0) + d0;
|
||||
}
|
||||
|
||||
public static double a(long[] along) {
|
||||
long i = 0L;
|
||||
long[] along1 = along;
|
||||
int j = along.length;
|
||||
|
||||
for (int k = 0; k < j; ++k) {
|
||||
long l = along1[k];
|
||||
|
||||
i += l;
|
||||
}
|
||||
|
||||
return (double) i / (double) along.length;
|
||||
}
|
||||
|
||||
public static float g(float f) {
|
||||
f %= 360.0F;
|
||||
if (f >= 180.0F) {
|
||||
f -= 360.0F;
|
||||
}
|
||||
|
||||
if (f < -180.0F) {
|
||||
f += 360.0F;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public static double g(double d0) {
|
||||
d0 %= 360.0D;
|
||||
if (d0 >= 180.0D) {
|
||||
d0 -= 360.0D;
|
||||
}
|
||||
|
||||
if (d0 < -180.0D) {
|
||||
d0 += 360.0D;
|
||||
}
|
||||
|
||||
return d0;
|
||||
}
|
||||
|
||||
public static int b(int i) {
|
||||
i %= 360;
|
||||
if (i >= 180) {
|
||||
i -= 360;
|
||||
}
|
||||
|
||||
if (i < -180) {
|
||||
i += 360;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public static int a(String s, int i) {
|
||||
try {
|
||||
return Integer.parseInt(s);
|
||||
} catch (Throwable throwable) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public static int a(String s, int i, int j) {
|
||||
return Math.max(j, a(s, i));
|
||||
}
|
||||
|
||||
public static double a(String s, double d0) {
|
||||
try {
|
||||
return Double.parseDouble(s);
|
||||
} catch (Throwable throwable) {
|
||||
return d0;
|
||||
}
|
||||
}
|
||||
|
||||
public static double a(String s, double d0, double d1) {
|
||||
return Math.max(d1, a(s, d0));
|
||||
}
|
||||
|
||||
public static int c(int i) {
|
||||
int j = i - 1;
|
||||
|
||||
j |= j >> 1;
|
||||
j |= j >> 2;
|
||||
j |= j >> 4;
|
||||
j |= j >> 8;
|
||||
j |= j >> 16;
|
||||
return j + 1;
|
||||
}
|
||||
|
||||
private static boolean g(int i) {
|
||||
return i != 0 && (i & i - 1) == 0;
|
||||
}
|
||||
|
||||
public static int d(int i) {
|
||||
i = g(i) ? i : c(i);
|
||||
return MathHelper.d[(int) ((long) i * 125613361L >> 27) & 31];
|
||||
}
|
||||
|
||||
public static int e(int i) {
|
||||
return d(i) - (g(i) ? 0 : 1);
|
||||
}
|
||||
|
||||
public static int c(int i, int j) {
|
||||
if (j == 0) {
|
||||
return 0;
|
||||
} else if (i == 0) {
|
||||
return j;
|
||||
} else {
|
||||
if (i < 0) {
|
||||
j *= -1;
|
||||
}
|
||||
|
||||
int k = i % j;
|
||||
|
||||
return k == 0 ? i : i + j - k;
|
||||
}
|
||||
}
|
||||
|
||||
public static long c(int i, int j, int k) {
|
||||
long l = (long) (i * 3129871) ^ (long) k * 116129781L ^ (long) j;
|
||||
|
||||
l = l * l * 42317861L + l * 11L;
|
||||
return l;
|
||||
}
|
||||
|
||||
public static UUID a(Random random) {
|
||||
long i = random.nextLong() & -61441L | 16384L;
|
||||
long j = random.nextLong() & 4611686018427387903L | Long.MIN_VALUE;
|
||||
|
||||
return new UUID(i, j);
|
||||
}
|
||||
|
||||
public static UUID a() {
|
||||
return a(MathHelper.c);
|
||||
}
|
||||
|
||||
public static double c(double d0, double d1, double d2) {
|
||||
return (d0 - d1) / (d2 - d1);
|
||||
}
|
||||
|
||||
public static double c(double d0, double d1) {
|
||||
double d2 = d1 * d1 + d0 * d0;
|
||||
|
||||
if (Double.isNaN(d2)) {
|
||||
return Double.NaN;
|
||||
} else {
|
||||
boolean flag = d0 < 0.0D;
|
||||
|
||||
if (flag) {
|
||||
d0 = -d0;
|
||||
}
|
||||
|
||||
boolean flag1 = d1 < 0.0D;
|
||||
|
||||
if (flag1) {
|
||||
d1 = -d1;
|
||||
}
|
||||
|
||||
boolean flag2 = d0 > d1;
|
||||
double d3;
|
||||
|
||||
if (flag2) {
|
||||
d3 = d1;
|
||||
d1 = d0;
|
||||
d0 = d3;
|
||||
}
|
||||
|
||||
d3 = i(d2);
|
||||
d1 *= d3;
|
||||
d0 *= d3;
|
||||
double d4 = MathHelper.e + d0;
|
||||
int i = (int) Double.doubleToRawLongBits(d4);
|
||||
double d5 = MathHelper.f[i];
|
||||
double d6 = MathHelper.g[i];
|
||||
double d7 = d4 - MathHelper.e;
|
||||
double d8 = d0 * d6 - d1 * d7;
|
||||
double d9 = (6.0D + d8 * d8) * d8 * 0.16666666666666666D;
|
||||
double d10 = d5 + d9;
|
||||
|
||||
if (flag2) {
|
||||
d10 = 1.5707963267948966D - d10;
|
||||
}
|
||||
|
||||
if (flag1) {
|
||||
d10 = 3.141592653589793D - d10;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
d10 = -d10;
|
||||
}
|
||||
|
||||
return d10;
|
||||
}
|
||||
}
|
||||
|
||||
public static double i(double d0) {
|
||||
double d1 = 0.5D * d0;
|
||||
long i = Double.doubleToRawLongBits(d0);
|
||||
|
||||
i = 6910469410427058090L - (i >> 1);
|
||||
d0 = Double.longBitsToDouble(i);
|
||||
d0 *= 1.5D - d1 * d0 * d0;
|
||||
return d0;
|
||||
}
|
||||
|
||||
public static int f(int i) {
|
||||
i ^= i >>> 16;
|
||||
i *= -2048144789;
|
||||
i ^= i >>> 13;
|
||||
i *= -1028477387;
|
||||
i ^= i >>> 16;
|
||||
return i;
|
||||
}
|
||||
|
||||
static {
|
||||
int i;
|
||||
|
||||
final float[] SINE_TABLE = new float[65536];
|
||||
for (i = 0; i < 65536; ++i) {
|
||||
SINE_TABLE[i] = (float) Math.sin((double) i * 3.141592653589793D * 2.0D / 65536.0D);
|
||||
}
|
||||
for (i = 0; i < SINE_TABLE_INT.length; i++) {
|
||||
SINE_TABLE_INT[i] = Float.floatToRawIntBits(SINE_TABLE[i]);
|
||||
}
|
||||
|
||||
SINE_TABLE_MIDPOINT = SINE_TABLE[SINE_TABLE.length / 2];
|
||||
for (i = 0; i < SINE_TABLE.length; i++) {
|
||||
float expected = SINE_TABLE[i];
|
||||
float value = lookup(i);
|
||||
|
||||
if (expected != value) {
|
||||
throw new IllegalArgumentException(String.format("LUT error at index %d (expected: %s, found: %s)", i, expected, value));
|
||||
}
|
||||
}
|
||||
|
||||
d = new int[] { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
|
||||
e = Double.longBitsToDouble(4805340802404319232L);
|
||||
f = new double[257];
|
||||
g = new double[257];
|
||||
|
||||
for (i = 0; i < 257; ++i) {
|
||||
double d0 = (double) i / 256.0D;
|
||||
double d1 = Math.asin(d0);
|
||||
|
||||
MathHelper.g[i] = Math.cos(d1);
|
||||
MathHelper.f[i] = d1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
164
sources/src/main/java/net/minecraft/server/MethodProfiler.java
Normal file
164
sources/src/main/java/net/minecraft/server/MethodProfiler.java
Normal file
@@ -0,0 +1,164 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class MethodProfiler {
|
||||
|
||||
public static final boolean ENABLED = Boolean.getBoolean("enableDebugMethodProfiler"); // CraftBukkit - disable unless specified in JVM arguments
|
||||
private static final Logger b = LogManager.getLogger();
|
||||
private final ObjectArrayList<String> c = new ObjectArrayList<>(); // Dionysus
|
||||
private final LongArrayList d = new LongArrayList(); // Dionysus
|
||||
public boolean a;
|
||||
private String e = "";
|
||||
private final Object2LongOpenHashMap<String> f = new Object2LongOpenHashMap<>();
|
||||
|
||||
public MethodProfiler() {}
|
||||
|
||||
public void a() {
|
||||
if (!ENABLED) return; // CraftBukkit
|
||||
this.f.clear();
|
||||
this.e = "";
|
||||
this.c.clear();
|
||||
}
|
||||
|
||||
public void a(String s) {
|
||||
if (!ENABLED) return; // CraftBukkit
|
||||
if (this.a) {
|
||||
if (!this.e.isEmpty()) {
|
||||
this.e = this.e + ".";
|
||||
}
|
||||
|
||||
this.e = this.e + s;
|
||||
this.c.add(this.e);
|
||||
this.d.add(Long.valueOf(System.nanoTime()));
|
||||
}
|
||||
}
|
||||
|
||||
public void a(Supplier<String> supplier) {
|
||||
if (!ENABLED) return; // CraftBukkit
|
||||
if (this.a) {
|
||||
this.a((String) supplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
public void b() {
|
||||
if (!ENABLED) return; // CraftBukkit
|
||||
if (this.a) {
|
||||
long i = System.nanoTime();
|
||||
long j = this.d.removeLong(this.d.size() - 1);
|
||||
|
||||
this.c.remove(this.c.size() - 1);
|
||||
long k = i - j;
|
||||
|
||||
if (this.f.containsKey(this.e)) {
|
||||
this.f.put(this.e, this.f.get(this.e) + k);
|
||||
} else {
|
||||
this.f.put(this.e, k);
|
||||
}
|
||||
|
||||
if (k > 100000000L) {
|
||||
MethodProfiler.b.warn("Something\'s taking too long! \'{}\' took aprox {} ms", this.e, Double.valueOf((double) k / 1000000.0D));
|
||||
}
|
||||
|
||||
this.e = this.c.isEmpty() ? "" : (String) this.c.get(this.c.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public List<MethodProfiler.ProfilerInfo> b(String s) {
|
||||
if (!ENABLED || !this.a) { // CraftBukkit
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
long i = this.f.getOrDefault("root", 0L);
|
||||
long j = this.f.getOrDefault(s, -1L);
|
||||
ArrayList<MethodProfiler.ProfilerInfo> arraylist = Lists.newArrayList();
|
||||
|
||||
if (!s.isEmpty()) {
|
||||
s = s + ".";
|
||||
}
|
||||
|
||||
long k = 0L;
|
||||
for (String s1 : this.f.keySet()) {
|
||||
if (s1.length() > s.length() && s1.startsWith(s) && s1.indexOf(".", s.length() + 1) < 0) {
|
||||
k += this.f.getLong(s1);
|
||||
}
|
||||
}
|
||||
|
||||
float f = (float) k;
|
||||
|
||||
if (k < j) {
|
||||
k = j;
|
||||
}
|
||||
|
||||
if (i < k) {
|
||||
i = k;
|
||||
}
|
||||
|
||||
for (Object2LongMap.Entry<String> entry : this.f.object2LongEntrySet()) {
|
||||
String s2 = entry.getKey();
|
||||
if (s2.length() > s.length() && s2.startsWith(s) && s2.indexOf(".", s.length() + 1) < 0) {
|
||||
long l = this.f.getLong(s2);
|
||||
double d0 = (double) l * 100.0D / (double) k;
|
||||
double d1 = (double) l * 100.0D / (double) i;
|
||||
String s3 = s2.substring(s.length());
|
||||
|
||||
arraylist.add(new MethodProfiler.ProfilerInfo(s3, d0, d1));
|
||||
}
|
||||
entry.setValue(entry.getLongValue() * 999L / 1000L);
|
||||
}
|
||||
|
||||
if ((float) k > f) {
|
||||
arraylist.add(new MethodProfiler.ProfilerInfo("unspecified", (double) ((float) k - f) * 100.0D / (double) k, (double) ((float) k - f) * 100.0D / (double) i));
|
||||
}
|
||||
|
||||
Collections.sort(arraylist);
|
||||
arraylist.add(0, new MethodProfiler.ProfilerInfo(s, 100.0D, (double) k * 100.0D / (double) i));
|
||||
return arraylist;
|
||||
}
|
||||
}
|
||||
|
||||
public void c(String s) {
|
||||
if (!ENABLED) return; // CraftBukkit
|
||||
this.b();
|
||||
this.a(s);
|
||||
}
|
||||
|
||||
public String c() {
|
||||
if (!ENABLED) return "[DISABLED]"; // CraftBukkit
|
||||
return this.c.isEmpty() ? "[UNKNOWN]" : (String) this.c.get(this.c.size() - 1);
|
||||
}
|
||||
|
||||
public static final class ProfilerInfo implements Comparable<MethodProfiler.ProfilerInfo> {
|
||||
|
||||
public double a;
|
||||
public double b;
|
||||
public String c;
|
||||
|
||||
public ProfilerInfo(String s, double d0, double d1) {
|
||||
this.c = s;
|
||||
this.a = d0;
|
||||
this.b = d1;
|
||||
}
|
||||
|
||||
public int a(MethodProfiler.ProfilerInfo methodprofiler_profilerinfo) {
|
||||
return methodprofiler_profilerinfo.a < this.a ? -1 : (methodprofiler_profilerinfo.a > this.a ? 1 : methodprofiler_profilerinfo.c.compareTo(this.c));
|
||||
}
|
||||
|
||||
public int compareTo(MethodProfiler.ProfilerInfo object) { // CraftBukkit: decompile error
|
||||
return this.a((MethodProfiler.ProfilerInfo) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,10 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet object) throws Exception { // CraftBukkit - fix decompile error
|
||||
this.a(channelhandlercontext, object);
|
||||
// FlamePaper - Check if channel is opened before reading packet
|
||||
if (isConnected()) {
|
||||
this.a(channelhandlercontext, object);
|
||||
}
|
||||
}
|
||||
|
||||
public static class QueuedPacket { // Akarin - default -> public
|
||||
|
||||
@@ -916,6 +916,11 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
case START_DESTROY_BLOCK:
|
||||
case ABORT_DESTROY_BLOCK:
|
||||
case STOP_DESTROY_BLOCK:
|
||||
// NeonPaper start - Don't allow digging in unloaded chunks
|
||||
if (!worldserver.isChunkLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4, true)) {
|
||||
return;
|
||||
}
|
||||
// NeonPaper end - Don't allow digging in unloaded chunks
|
||||
double d0 = this.player.locX - ((double) blockposition.getX() + 0.5D);
|
||||
double d1 = this.player.locY - ((double) blockposition.getY() + 0.5D) + 1.5D;
|
||||
double d2 = this.player.locZ - ((double) blockposition.getZ() + 0.5D);
|
||||
|
||||
@@ -0,0 +1,568 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
// CraftBukkit start
|
||||
import java.util.ArrayList;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class PlayerInteractManager {
|
||||
|
||||
public World world;
|
||||
public EntityPlayer player;
|
||||
private EnumGamemode gamemode;
|
||||
private boolean d;
|
||||
private int lastDigTick;
|
||||
private BlockPosition f;
|
||||
private int currentTick;
|
||||
private boolean h;
|
||||
private BlockPosition i;
|
||||
private int j;
|
||||
private int k;
|
||||
|
||||
public PlayerInteractManager(World world) {
|
||||
this.gamemode = EnumGamemode.NOT_SET;
|
||||
this.f = BlockPosition.ZERO;
|
||||
this.i = BlockPosition.ZERO;
|
||||
this.k = -1;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void setGameMode(EnumGamemode enumgamemode) {
|
||||
this.gamemode = enumgamemode;
|
||||
enumgamemode.a(this.player.abilities);
|
||||
this.player.updateAbilities();
|
||||
this.player.server.getPlayerList().sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE, new EntityPlayer[] { this.player}), this.player); // CraftBukkit
|
||||
this.world.everyoneSleeping();
|
||||
}
|
||||
|
||||
public EnumGamemode getGameMode() {
|
||||
return this.gamemode;
|
||||
}
|
||||
|
||||
public boolean c() {
|
||||
return this.gamemode.e();
|
||||
}
|
||||
|
||||
public boolean isCreative() {
|
||||
return this.gamemode.isCreative();
|
||||
}
|
||||
|
||||
public void b(EnumGamemode enumgamemode) {
|
||||
if (this.gamemode == EnumGamemode.NOT_SET) {
|
||||
this.gamemode = enumgamemode;
|
||||
}
|
||||
|
||||
this.setGameMode(this.gamemode);
|
||||
}
|
||||
|
||||
public void a() {
|
||||
this.currentTick = MinecraftServer.currentTick; // CraftBukkit;
|
||||
float f;
|
||||
int i;
|
||||
|
||||
if (this.h) {
|
||||
int j = this.currentTick - this.j;
|
||||
IBlockData iblockdata = this.world.getType(this.i);
|
||||
|
||||
if (iblockdata.getMaterial() == Material.AIR) {
|
||||
this.h = false;
|
||||
} else {
|
||||
f = iblockdata.a((EntityHuman) this.player, this.player.world, this.i) * (float) (j + 1);
|
||||
i = (int) (f * 10.0F);
|
||||
if (i != this.k) {
|
||||
this.world.c(this.player.getId(), this.i, i);
|
||||
this.k = i;
|
||||
}
|
||||
|
||||
if (f >= 1.0F) {
|
||||
this.h = false;
|
||||
this.breakBlock(this.i);
|
||||
}
|
||||
}
|
||||
} else if (this.d) {
|
||||
IBlockData iblockdata1 = this.world.getType(this.f);
|
||||
|
||||
if (iblockdata1.getMaterial() == Material.AIR) {
|
||||
this.world.c(this.player.getId(), this.f, -1);
|
||||
this.k = -1;
|
||||
this.d = false;
|
||||
} else {
|
||||
int k = this.currentTick - this.lastDigTick;
|
||||
|
||||
f = iblockdata1.a((EntityHuman) this.player, this.player.world, this.i) * (float) (k + 1);
|
||||
i = (int) (f * 10.0F);
|
||||
if (i != this.k) {
|
||||
this.world.c(this.player.getId(), this.f, i);
|
||||
this.k = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a(BlockPosition blockposition, EnumDirection enumdirection) {
|
||||
// CraftBukkit start
|
||||
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, blockposition, enumdirection, this.player.inventory.getItemInHand(), EnumHand.MAIN_HAND);
|
||||
if (event.isCancelled()) {
|
||||
// Let the client know the block still exists
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
cancelBreakBlock(blockposition, this.world.getType(blockposition)); // Paper - Avoid visual issues on the client
|
||||
// Update any tile entity data for this block
|
||||
TileEntity tileentity = this.world.getTileEntity(blockposition);
|
||||
if (tileentity != null) {
|
||||
this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
|
||||
}
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
if (this.isCreative()) {
|
||||
if (!this.world.douseFire((EntityHuman) null, blockposition, enumdirection)) {
|
||||
this.breakBlock(blockposition);
|
||||
}
|
||||
|
||||
} else {
|
||||
IBlockData iblockdata = this.world.getType(blockposition);
|
||||
Block block = iblockdata.getBlock();
|
||||
|
||||
if (this.gamemode.c()) {
|
||||
if (this.gamemode == EnumGamemode.SPECTATOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.player.dk()) {
|
||||
ItemStack itemstack = this.player.getItemInMainHand();
|
||||
|
||||
if (itemstack.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!itemstack.a(block)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this.world.douseFire((EntityHuman) null, blockposition, enumdirection); // CraftBukkit - Moved down
|
||||
this.lastDigTick = this.currentTick;
|
||||
float f = 1.0F;
|
||||
|
||||
// CraftBukkit start - Swings at air do *NOT* exist.
|
||||
if (event.useInteractedBlock() == Event.Result.DENY) {
|
||||
// If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door.
|
||||
IBlockData data = this.world.getType(blockposition);
|
||||
if (block == Blocks.WOODEN_DOOR) {
|
||||
// For some reason *BOTH* the bottom/top part have to be marked updated.
|
||||
boolean bottom = data.get(BlockDoor.HALF) == BlockDoor.EnumDoorHalf.LOWER;
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, bottom ? blockposition.up() : blockposition.down()));
|
||||
} else if (block == Blocks.TRAPDOOR) {
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
}
|
||||
} else if (iblockdata.getMaterial() != Material.AIR) {
|
||||
block.attack(this.world, blockposition, this.player);
|
||||
f = iblockdata.a((EntityHuman) this.player, this.player.world, blockposition);
|
||||
// Allow fire punching to be blocked
|
||||
this.world.douseFire((EntityHuman) null, blockposition, enumdirection);
|
||||
}
|
||||
|
||||
if (event.useItemInHand() == Event.Result.DENY) {
|
||||
// If we 'insta destroyed' then the client needs to be informed.
|
||||
if (f > 1.0f) {
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
}
|
||||
return;
|
||||
}
|
||||
org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.player.inventory.getItemInHand(), f >= 1.0f);
|
||||
|
||||
if (blockEvent.isCancelled()) {
|
||||
// Let the client know the block still exists
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
return;
|
||||
}
|
||||
|
||||
if (blockEvent.getInstaBreak()) {
|
||||
f = 2.0f;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (iblockdata.getMaterial() != Material.AIR && f >= 1.0F) {
|
||||
this.breakBlock(blockposition);
|
||||
} else {
|
||||
this.d = true;
|
||||
this.f = blockposition;
|
||||
int i = (int) (f * 10.0F);
|
||||
|
||||
this.world.c(this.player.getId(), blockposition, i);
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, blockposition)); // Paper - MC-54026 - backport from 1.13
|
||||
this.k = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.world.chunkPacketBlockController.updateNearbyBlocks(this.world, blockposition); // Paper - Anti-Xray
|
||||
}
|
||||
|
||||
public void a(BlockPosition blockposition) {
|
||||
if (blockposition.equals(this.f)) {
|
||||
this.currentTick = MinecraftServer.currentTick; // CraftBukkit
|
||||
int i = this.currentTick - this.lastDigTick;
|
||||
IBlockData iblockdata = this.world.getType(blockposition);
|
||||
|
||||
if (iblockdata.getMaterial() != Material.AIR) {
|
||||
float f = iblockdata.a((EntityHuman) this.player, this.player.world, blockposition) * (float) (i + 1);
|
||||
|
||||
if (f >= 0.7F) {
|
||||
this.d = false;
|
||||
this.world.c(this.player.getId(), blockposition, -1);
|
||||
this.breakBlock(blockposition);
|
||||
} else if (!this.h) {
|
||||
this.d = false;
|
||||
this.h = true;
|
||||
this.i = blockposition;
|
||||
this.j = this.lastDigTick;
|
||||
}
|
||||
}
|
||||
// CraftBukkit start - Force block reset to client
|
||||
} else {
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void e() {
|
||||
this.d = false;
|
||||
this.world.c(this.player.getId(), this.f, -1);
|
||||
}
|
||||
|
||||
private boolean c(BlockPosition blockposition) {
|
||||
IBlockData iblockdata = this.world.getType(blockposition);
|
||||
|
||||
iblockdata.getBlock().a(this.world, blockposition, iblockdata, (EntityHuman) this.player);
|
||||
boolean flag = this.world.setAir(blockposition);
|
||||
|
||||
if (flag) {
|
||||
iblockdata.getBlock().postBreak(this.world, blockposition, iblockdata);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
// Paper start - Extra method to avoid visual issues on the client when cancelling block breaks
|
||||
private void cancelBreakBlock(BlockPosition position, IBlockData data) {
|
||||
Block block = data.getBlock();
|
||||
// Send other half of the door
|
||||
if (block instanceof BlockDoor) {
|
||||
boolean bottom = data.get(BlockDoor.HALF) == BlockDoor.EnumDoorHalf.LOWER;
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, bottom ? position.up() : position.down()));
|
||||
} else if (block instanceof BlockTallPlant) {
|
||||
boolean bottom = data.get(BlockTallPlant.HALF) == BlockTallPlant.EnumTallPlantHalf.LOWER;
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, bottom ? position.up() : position.down()));
|
||||
} else if (block instanceof BlockPistonExtension) {
|
||||
BlockPosition piston = position.shift(data.get(BlockPistonExtension.FACING).opposite());
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, piston));
|
||||
} else if (block instanceof BlockBed) {
|
||||
if (data.get(BlockBed.PART) == BlockBed.EnumBedPart.FOOT) {
|
||||
// Restore head of bed
|
||||
BlockPosition head = position.shift(data.get(BlockBed.FACING));
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, head));
|
||||
|
||||
TileEntity tileentity = this.world.getTileEntity(head);
|
||||
if (tileentity != null) {
|
||||
this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public boolean breakBlock(BlockPosition blockposition) {
|
||||
// CraftBukkit start - fire BlockBreakEvent
|
||||
BlockBreakEvent event = null;
|
||||
|
||||
if (this.player instanceof EntityPlayer) {
|
||||
org.bukkit.block.Block block = this.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
|
||||
// Sword + Creative mode pre-cancel
|
||||
boolean isSwordNoBreak = this.gamemode.isCreative() && !this.player.getItemInMainHand().isEmpty() && this.player.getItemInMainHand().getItem() instanceof ItemSword;
|
||||
|
||||
// Tell client the block is gone immediately then process events
|
||||
// Don't tell the client if its a creative sword break because its not broken!
|
||||
if (world.getTileEntity(blockposition) == null && !isSwordNoBreak) {
|
||||
PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(this.world, blockposition);
|
||||
packet.block = Blocks.AIR.getBlockData();
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(packet);
|
||||
}
|
||||
|
||||
event = new BlockBreakEvent(block, this.player.getBukkitEntity());
|
||||
|
||||
// Sword + Creative mode pre-cancel
|
||||
event.setCancelled(isSwordNoBreak);
|
||||
|
||||
// Calculate default block experience
|
||||
IBlockData nmsData = this.world.getType(blockposition);
|
||||
Block nmsBlock = nmsData.getBlock();
|
||||
|
||||
ItemStack itemstack = this.player.getEquipment(EnumItemSlot.MAINHAND);
|
||||
|
||||
if (nmsBlock != null && !event.isCancelled() && !this.isCreative() && this.player.hasBlock(nmsBlock.getBlockData())) {
|
||||
// Copied from block.a(World world, EntityHuman entityhuman, BlockPosition blockposition, IBlockData iblockdata, @Nullable TileEntity tileentity, ItemStack itemstack)
|
||||
// PAIL: checkme each update
|
||||
if (!(nmsBlock.o() && EnchantmentManager.getEnchantmentLevel(Enchantments.SILK_TOUCH, itemstack) > 0)) {
|
||||
int bonusLevel = EnchantmentManager.getEnchantmentLevel(Enchantments.LOOT_BONUS_BLOCKS, itemstack);
|
||||
|
||||
event.setExpToDrop(nmsBlock.getExpDrop(this.world, nmsData, bonusLevel));
|
||||
}
|
||||
}
|
||||
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
if (isSwordNoBreak) {
|
||||
return false;
|
||||
}
|
||||
// Let the client know the block still exists
|
||||
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
cancelBreakBlock(blockposition, nmsData); // Paper - Move cancellation code to extra "cancelBreakBlock" method
|
||||
// Update any tile entity data for this block
|
||||
TileEntity tileentity = this.world.getTileEntity(blockposition);
|
||||
if (tileentity != null) {
|
||||
this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (false && this.gamemode.isCreative() && !this.player.getItemInMainHand().isEmpty() && this.player.getItemInMainHand().getItem() instanceof ItemSword) { // CraftBukkit - false
|
||||
return false;
|
||||
} else {
|
||||
IBlockData iblockdata = this.world.getType(blockposition);
|
||||
if (iblockdata.getBlock() == Blocks.AIR) return false; // CraftBukkit - A plugin set block to air without cancelling
|
||||
TileEntity tileentity = this.world.getTileEntity(blockposition);
|
||||
Block block = iblockdata.getBlock();
|
||||
|
||||
// CraftBukkit start - Special case skulls, their item data comes from a tile entity (Also check if block should drop items)
|
||||
if (iblockdata.getBlock() == Blocks.SKULL && !this.isCreative() && event.isDropItems()) {
|
||||
iblockdata.getBlock().dropNaturally(world, blockposition, iblockdata, 1.0F, 0);
|
||||
return this.c(blockposition);
|
||||
}
|
||||
|
||||
// And shulker boxes too for duplication on cancel reasons (Also check if block should drop items)
|
||||
if (iblockdata.getBlock() instanceof BlockShulkerBox && event.isDropItems()) {
|
||||
iblockdata.getBlock().dropNaturally(world, blockposition, iblockdata, 1.0F, 0);
|
||||
return this.c(blockposition);
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if ((block instanceof BlockCommand || block instanceof BlockStructure) && !this.player.isCreativeAndOp()) {
|
||||
this.world.notify(blockposition, iblockdata, iblockdata, 3);
|
||||
return false;
|
||||
} else {
|
||||
if (this.gamemode.c()) {
|
||||
if (this.gamemode == EnumGamemode.SPECTATOR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.player.dk()) {
|
||||
ItemStack itemstack = this.player.getItemInMainHand();
|
||||
|
||||
if (itemstack.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!itemstack.a(block)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.world.a(this.player, 2001, blockposition, Block.getCombinedId(iblockdata));
|
||||
// CraftBukkit start
|
||||
world.captureDrops = new ArrayList<>();
|
||||
boolean flag = this.c(blockposition);
|
||||
if (event.isDropItems()) {
|
||||
for (EntityItem item : world.captureDrops) {
|
||||
world.addEntity(item);
|
||||
}
|
||||
}
|
||||
world.captureDrops = null;
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.isCreative()) {
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
} else {
|
||||
ItemStack itemstack1 = this.player.getItemInMainHand();
|
||||
//ItemStack itemstack2 = itemstack1.isEmpty() ? ItemStack.a : itemstack1.cloneItemStack(); //NeonPaper move up
|
||||
boolean flag1 = this.player.hasBlock(iblockdata);
|
||||
ItemStack itemstack2 = flag && flag1 && event.isDropItems() && !itemstack1.isEmpty() ? itemstack1.cloneItemStack() : ItemStack.a; // NeonPaper - clone before use
|
||||
|
||||
if (!itemstack1.isEmpty()) {
|
||||
itemstack1.a(this.world, iblockdata, blockposition, this.player);
|
||||
}
|
||||
|
||||
// CraftBukkit start - Check if block should drop items
|
||||
if (flag && flag1 && event.isDropItems()) {
|
||||
iblockdata.getBlock().a(this.world, this.player, blockposition, iblockdata, tileentity, itemstack2);
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
// CraftBukkit start - Drop event experience
|
||||
if (flag && event != null) {
|
||||
iblockdata.getBlock().dropExperience(this.world, blockposition, event.getExpToDrop(), this.player); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EnumInteractionResult a(EntityHuman entityhuman, World world, ItemStack itemstack, EnumHand enumhand) {
|
||||
if (this.gamemode == EnumGamemode.SPECTATOR) {
|
||||
return EnumInteractionResult.PASS;
|
||||
} else if (entityhuman.getCooldownTracker().a(itemstack.getItem())) {
|
||||
return EnumInteractionResult.PASS;
|
||||
} else {
|
||||
int i = itemstack.getCount();
|
||||
int j = itemstack.getData();
|
||||
InteractionResultWrapper interactionresultwrapper = itemstack.a(world, entityhuman, enumhand);
|
||||
ItemStack itemstack1 = (ItemStack) interactionresultwrapper.b();
|
||||
|
||||
if (itemstack1 == itemstack && itemstack1.getCount() == i && itemstack1.m() <= 0 && itemstack1.getData() == j) {
|
||||
return interactionresultwrapper.a();
|
||||
} else if (interactionresultwrapper.a() == EnumInteractionResult.FAIL && itemstack1.m() > 0 && !entityhuman.isHandRaised()) {
|
||||
return interactionresultwrapper.a();
|
||||
} else {
|
||||
entityhuman.a(enumhand, itemstack1);
|
||||
if (this.isCreative()) {
|
||||
itemstack1.setCount(i);
|
||||
if (itemstack1.f()) {
|
||||
itemstack1.setData(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemstack1.isEmpty()) {
|
||||
entityhuman.a(enumhand, ItemStack.a);
|
||||
}
|
||||
|
||||
if (!entityhuman.isHandRaised()) {
|
||||
((EntityPlayer) entityhuman).updateInventory(entityhuman.defaultContainer);
|
||||
}
|
||||
|
||||
return interactionresultwrapper.a();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CraftBukkit start - whole method
|
||||
public boolean interactResult = false;
|
||||
public boolean firedInteract = false;
|
||||
public EnumInteractionResult a(EntityHuman entityhuman, World world, ItemStack itemstack, EnumHand enumhand, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2) {
|
||||
IBlockData blockdata = world.getType(blockposition);
|
||||
EnumInteractionResult enuminteractionresult = EnumInteractionResult.FAIL;
|
||||
if (blockdata.getBlock() != Blocks.AIR) {
|
||||
boolean cancelledBlock = false;
|
||||
|
||||
if (this.gamemode == EnumGamemode.SPECTATOR) {
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
cancelledBlock = !(tileentity instanceof ITileInventory || tileentity instanceof IInventory);
|
||||
}
|
||||
|
||||
if (entityhuman.getCooldownTracker().a(itemstack.getItem())) {
|
||||
cancelledBlock = true;
|
||||
}
|
||||
|
||||
if (itemstack.getItem() instanceof ItemBlock && !entityhuman.isCreativeAndOp()) {
|
||||
Block block1 = ((ItemBlock) itemstack.getItem()).getBlock();
|
||||
|
||||
if (block1 instanceof BlockCommand || block1 instanceof BlockStructure) {
|
||||
cancelledBlock = true;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(entityhuman, Action.RIGHT_CLICK_BLOCK, blockposition, enumdirection, itemstack, cancelledBlock, enumhand);
|
||||
firedInteract = true;
|
||||
interactResult = event.useItemInHand() == Event.Result.DENY;
|
||||
|
||||
if (event.useInteractedBlock() == Event.Result.DENY) {
|
||||
// If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door.
|
||||
if (blockdata.getBlock() instanceof BlockDoor) {
|
||||
boolean bottom = blockdata.get(BlockDoor.HALF) == BlockDoor.EnumDoorHalf.LOWER;
|
||||
((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutBlockChange(world, bottom ? blockposition.up() : blockposition.down()));
|
||||
} else if (blockdata.getBlock() instanceof BlockCake) {
|
||||
((EntityPlayer) entityhuman).getBukkitEntity().sendHealthUpdate(); // SPIGOT-1341 - reset health for cake
|
||||
// Paper start - extend Player Interact cancellation
|
||||
} else if (blockdata.getBlock() instanceof BlockStructure) {
|
||||
((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutCloseWindow());
|
||||
} else if (blockdata.getBlock() instanceof BlockCommand) {
|
||||
((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutCloseWindow());
|
||||
} else if (blockdata.getBlock() instanceof BlockFlowerPot) {
|
||||
// Send a block change to air and then send back the correct block, just to make the client happy
|
||||
PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(this.world, blockposition);
|
||||
packet.block = Blocks.AIR.getBlockData();
|
||||
this.player.playerConnection.sendPacket(packet);
|
||||
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
|
||||
|
||||
TileEntity tileentity = this.world.getTileEntity(blockposition);
|
||||
if (tileentity != null) {
|
||||
player.playerConnection.sendPacket(tileentity.getUpdatePacket());
|
||||
}
|
||||
// Paper end - extend Player Interact cancellation
|
||||
}
|
||||
((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-2867
|
||||
enuminteractionresult = (event.useItemInHand() != Event.Result.ALLOW) ? EnumInteractionResult.SUCCESS : EnumInteractionResult.PASS;
|
||||
} else if (this.gamemode == EnumGamemode.SPECTATOR) {
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
|
||||
if (tileentity instanceof ITileInventory) {
|
||||
Block block = world.getType(blockposition).getBlock();
|
||||
ITileInventory itileinventory = (ITileInventory) tileentity;
|
||||
|
||||
if (itileinventory instanceof TileEntityChest && block instanceof BlockChest) {
|
||||
itileinventory = ((BlockChest) block).getInventory(world, blockposition);
|
||||
}
|
||||
|
||||
if (itileinventory != null) {
|
||||
entityhuman.openContainer(itileinventory);
|
||||
return EnumInteractionResult.SUCCESS;
|
||||
}
|
||||
} else if (tileentity instanceof IInventory) {
|
||||
entityhuman.openContainer((IInventory) tileentity);
|
||||
return EnumInteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return EnumInteractionResult.PASS;
|
||||
} else {
|
||||
if (!entityhuman.isSneaking() || entityhuman.getItemInMainHand().isEmpty() && entityhuman.getItemInOffHand().isEmpty()) {
|
||||
IBlockData iblockdata = world.getType(blockposition);
|
||||
|
||||
enuminteractionresult = iblockdata.getBlock().interact(world, blockposition, iblockdata, entityhuman, enumhand, enumdirection, f, f1, f2) ? EnumInteractionResult.SUCCESS : EnumInteractionResult.PASS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemstack.isEmpty() && enuminteractionresult != EnumInteractionResult.SUCCESS && !interactResult) { // add !interactResult SPIGOT-764
|
||||
int i = itemstack.getData();
|
||||
int j = itemstack.getCount();
|
||||
|
||||
enuminteractionresult = itemstack.placeItem(entityhuman, world, blockposition, enumhand, enumdirection, f, f1, f2);
|
||||
|
||||
// The item count should not decrement in Creative mode.
|
||||
if (this.isCreative()) {
|
||||
itemstack.setData(i);
|
||||
itemstack.setCount(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return enuminteractionresult;
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
public void a(WorldServer worldserver) {
|
||||
this.world = worldserver;
|
||||
}
|
||||
}
|
||||
@@ -79,8 +79,20 @@ public abstract class PlayerList {
|
||||
private int v;
|
||||
|
||||
// CraftBukkit start
|
||||
private CraftServer cserver;
|
||||
private final Map<String,EntityPlayer> playersByName = new org.spigotmc.CaseInsensitiveMap<EntityPlayer>();
|
||||
private final CraftServer cserver;
|
||||
private final Map<String,EntityPlayer> playersByName = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap<String, EntityPlayer>(
|
||||
new it.unimi.dsi.fastutil.Hash.Strategy<String>() {
|
||||
@Override
|
||||
public int hashCode(String o) {
|
||||
return o.toLowerCase().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(String a, String b) {
|
||||
return a.equalsIgnoreCase(b);
|
||||
}
|
||||
}
|
||||
);
|
||||
@Nullable String collideRuleTeamName; // Paper - Team name used for collideRule
|
||||
|
||||
public PlayerList(MinecraftServer minecraftserver) {
|
||||
@@ -546,9 +558,10 @@ public abstract class PlayerList {
|
||||
Player player = entity.getBukkitEntity();
|
||||
PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.networkManager.getRawAddress()).getAddress());
|
||||
String s;
|
||||
|
||||
if (getProfileBans().isBanned(gameprofile) && !getProfileBans().get(gameprofile).hasExpired()) {
|
||||
GameProfileBanEntry gameprofilebanentry = this.k.get(gameprofile);
|
||||
// NeonPaper start - Fix MC-158900
|
||||
GameProfileBanEntry gameprofilebanentry;
|
||||
if (getProfileBans().isBanned(gameprofile) && (gameprofilebanentry = getProfileBans().get(gameprofile)) != null) {
|
||||
// NeonPaper end
|
||||
|
||||
s = LocaleI18n.a(AkarinGlobalConfig.messageBan,
|
||||
gameprofilebanentry.getReason().equals(Akari.EMPTY_STRING) ? Akari.EMPTY_STRING : AkarinGlobalConfig.messageBanReason + gameprofilebanentry.getReason(),
|
||||
|
||||
506
sources/src/main/java/net/minecraft/server/RegionFile.java
Normal file
506
sources/src/main/java/net/minecraft/server/RegionFile.java
Normal file
@@ -0,0 +1,506 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.destroystokyo.paper.exception.ServerInternalException;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.List;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class RegionFile {
|
||||
|
||||
// Spigot start
|
||||
// Minecraft is limited to 256 sections per chunk. So 1MB. This can easily be overriden.
|
||||
// So we extend this to use the REAL size when the count is maxed by seeking to that section and reading the length.
|
||||
private static final boolean ENABLE_EXTENDED_SAVE = Boolean.parseBoolean(System.getProperty("net.minecraft.server.RegionFile.enableExtendedSave", "true"));
|
||||
// Spigot end
|
||||
private static final byte[] a = new byte[4096];
|
||||
private final File b;private File getFile() { return b; } // Paper - OBFHELPER
|
||||
private RandomAccessFile c;private RandomAccessFile getDataFile() { return c; } // Paper - OBFHELPER
|
||||
private final int[] d = new int[1024];private int[] offsets = d; // Paper - OBFHELPER
|
||||
private final int[] e = new int[1024];private int[] timestamps = e; // Paper - OBFHELPER
|
||||
private List<Boolean> f;
|
||||
private int g;
|
||||
private long h;
|
||||
|
||||
public RegionFile(File file) {
|
||||
this.b = file;
|
||||
this.g = 0;
|
||||
|
||||
try {
|
||||
if (file.exists()) {
|
||||
this.h = file.lastModified();
|
||||
}
|
||||
|
||||
|
||||
this.c = new RandomAccessFile(file, "rw");
|
||||
if (this.c.length() < 8192L) { // Paper - headers should be 8192
|
||||
this.c.write(a);
|
||||
this.c.write(a);
|
||||
this.g += 8192;
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
if ((this.c.length() & 4095L) != 0L) {
|
||||
for (i = 0; (long) i < (this.c.length() & 4095L); ++i) {
|
||||
this.c.write(0);
|
||||
}
|
||||
}
|
||||
|
||||
i = (int) this.c.length() / 4096;
|
||||
this.f = Lists.newArrayListWithCapacity(i);
|
||||
|
||||
int j;
|
||||
|
||||
for (j = 0; j < i; ++j) {
|
||||
this.f.add(Boolean.valueOf(true));
|
||||
}
|
||||
|
||||
this.f.set(0, Boolean.valueOf(false));
|
||||
this.f.set(1, Boolean.valueOf(false));
|
||||
this.c.seek(0L);
|
||||
|
||||
int k;
|
||||
|
||||
// Paper Start
|
||||
ByteBuffer header = ByteBuffer.allocate(8192);
|
||||
while (header.hasRemaining()) {
|
||||
if (this.c.getChannel().read(header) == -1) throw new EOFException();
|
||||
}
|
||||
((Buffer) header).clear();
|
||||
IntBuffer headerAsInts = header.asIntBuffer();
|
||||
initOversizedState();
|
||||
// Paper End
|
||||
for (j = 0; j < 1024; ++j) {
|
||||
k = headerAsInts.get(); // Paper
|
||||
this.d[j] = k;
|
||||
// Spigot start
|
||||
int length = k & 255;
|
||||
if (length == 255) {
|
||||
if ((k >> 8) <= this.f.size()) {
|
||||
// We're maxed out, so we need to read the proper length from the section
|
||||
this.c.seek((k >> 8) * 4096);
|
||||
length = (this.c.readInt() + 4) / 4096 + 1;
|
||||
this.c.seek(j * 4 + 4); // Go back to where we were
|
||||
}
|
||||
}
|
||||
if (k > 0 && (k >> 8) > 1 && (k >> 8) + (length) <= this.f.size()) { // Paper >= 1 as 0/1 are the headers, and negative isnt valid
|
||||
for (int l = 0; l < (length); ++l) {
|
||||
// Spigot end
|
||||
this.f.set((k >> 8) + l, Boolean.valueOf(false));
|
||||
}
|
||||
}
|
||||
// Spigot start
|
||||
else if (k != 0) { // Paper
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Invalid chunk: ({0}, {1}) Offset: {2} Length: {3} runs off end file. {4}", new Object[]{j % 32, (int) (j / 32), k >> 8, length, file});
|
||||
deleteChunk(j); // Paper
|
||||
}
|
||||
// Spigot end
|
||||
}
|
||||
|
||||
for (j = 0; j < 1024; ++j) {
|
||||
k = headerAsInts.get(); // Paper
|
||||
if (offsets[j] != 0) this.timestamps[j] = k; // Paper - don't set timestamp if it got 0'd above due to corruption
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
ioexception.printStackTrace();
|
||||
ServerInternalException.reportInternalException(ioexception); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public synchronized DataInputStream getReadStream(int i, int j) { return a(i, j); } @Nullable public synchronized DataInputStream a(int i, int j) { // Paper - OBFHELPER
|
||||
if (this.d(i, j)) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
int k = this.getOffset(i, j);
|
||||
|
||||
if (k == 0) {
|
||||
return null;
|
||||
} else {
|
||||
int l = k >> 8;
|
||||
int i1 = k & 255;
|
||||
// Spigot start
|
||||
if (i1 == 255) {
|
||||
this.c.seek(l * 4096);
|
||||
i1 = (this.c.readInt() + 4) / 4096 + 1;
|
||||
}
|
||||
// Spigot end
|
||||
|
||||
if (l + i1 > this.f.size()) {
|
||||
return null;
|
||||
} else {
|
||||
this.c.seek((long) (l * 4096));
|
||||
int j1 = this.c.readInt();
|
||||
|
||||
if (j1 > 4096 * i1) {
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Invalid chunk: ({0}, {1}) Offset: {2} Invalid Size: {3}>{4} {5}", new Object[]{i, j, l, j1, i1 * 4096, this.b}); // Spigot
|
||||
return null;
|
||||
} else if (j1 <= 0) {
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Invalid chunk: ({0}, {1}) Offset: {2} Invalid Size: {3} {4}", new Object[]{i, j, l, j1, this.b}); // Spigot
|
||||
return null;
|
||||
} else {
|
||||
byte b0 = this.c.readByte();
|
||||
byte[] abyte;
|
||||
|
||||
if (b0 == 1) {
|
||||
abyte = new byte[j1 - 1];
|
||||
this.c.read(abyte);
|
||||
return new DataInputStream(new BufferedInputStream(new GZIPInputStream(new ByteArrayInputStream(abyte))));
|
||||
} else if (b0 == 2) {
|
||||
abyte = new byte[j1 - 1];
|
||||
this.c.read(abyte);
|
||||
return new DataInputStream(new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(abyte))));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DataOutputStream getWriteStream(int i, int j) { return b(i, j); } @Nullable public DataOutputStream b(int i, int j) { // Paper - OBFHELPER
|
||||
return this.d(i, j) ? null : new DataOutputStream(new RegionFile.ChunkBuffer(i, j)); // Paper - remove middleware, move deflate to .close() for dynamic levels
|
||||
}
|
||||
|
||||
protected synchronized void a(int i, int j, byte[] abyte, int k) {
|
||||
try {
|
||||
int l = this.getOffset(i, j);
|
||||
int i1 = l >> 8;
|
||||
int j1 = l & 255;
|
||||
// Spigot start
|
||||
if (j1 == 255) {
|
||||
this.c.seek(i1 * 4096);
|
||||
j1 = (this.c.readInt() + 4) / 4096 + 1;
|
||||
}
|
||||
// Spigot end
|
||||
int k1 = (k + 5) / 4096 + 1;
|
||||
|
||||
if (k1 >= 256) {
|
||||
// Spigot start
|
||||
if (!USE_SPIGOT_OVERSIZED_METHOD && !RegionFileCache.isOverzealous()) throw new ChunkTooLargeException(i, j, k1); // Paper - throw error instead
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING,"Large Chunk Detected: ({0}, {1}) Size: {2} {3}", new Object[]{i, j, k1, this.b});
|
||||
if (!ENABLE_EXTENDED_SAVE) return;
|
||||
// Spigot end
|
||||
}
|
||||
|
||||
if (i1 != 0 && j1 == k1) {
|
||||
this.a(i1, abyte, k);
|
||||
} else {
|
||||
int l1;
|
||||
|
||||
for (l1 = 0; l1 < j1; ++l1) {
|
||||
this.f.set(i1 + l1, Boolean.valueOf(true));
|
||||
}
|
||||
|
||||
l1 = this.f.indexOf(Boolean.valueOf(true));
|
||||
int i2 = 0;
|
||||
int j2;
|
||||
|
||||
if (l1 != -1) {
|
||||
for (j2 = l1; j2 < this.f.size(); ++j2) {
|
||||
if (i2 != 0) {
|
||||
if (((Boolean) this.f.get(j2)).booleanValue()) {
|
||||
++i2;
|
||||
} else {
|
||||
i2 = 0;
|
||||
}
|
||||
} else if (((Boolean) this.f.get(j2)).booleanValue()) {
|
||||
l1 = j2;
|
||||
i2 = 1;
|
||||
}
|
||||
|
||||
if (i2 >= k1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i2 >= k1) {
|
||||
i1 = l1;
|
||||
this.a(i, j, l1 << 8 | (k1 > 255 ? 255 : k1)); // Spigot
|
||||
|
||||
for (j2 = 0; j2 < k1; ++j2) {
|
||||
this.f.set(i1 + j2, Boolean.valueOf(false));
|
||||
}
|
||||
|
||||
this.a(i1, abyte, k);
|
||||
} else {
|
||||
this.c.seek(this.c.length());
|
||||
i1 = this.f.size();
|
||||
|
||||
for (j2 = 0; j2 < k1; ++j2) {
|
||||
this.c.write(RegionFile.a);
|
||||
this.f.add(Boolean.valueOf(false));
|
||||
}
|
||||
|
||||
this.g += 4096 * k1;
|
||||
this.a(i1, abyte, k);
|
||||
this.a(i, j, i1 << 8 | (k1 > 255 ? 255 : k1)); // Spigot
|
||||
}
|
||||
}
|
||||
|
||||
this.b(i, j, (int) (MinecraftServer.aw() / 1000L));
|
||||
} catch (IOException ioexception) {
|
||||
org.spigotmc.SneakyThrow.sneaky(ioexception); // Paper - we want the upper try/catch to retry this
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void a(int i, byte[] abyte, int j) throws IOException {
|
||||
this.c.seek((long) (i * 4096));
|
||||
this.c.writeInt(j + 1);
|
||||
this.c.writeByte(2);
|
||||
this.c.write(abyte, 0, j);
|
||||
}
|
||||
|
||||
private boolean d(int i, int j) {
|
||||
return i < 0 || i >= 32 || j < 0 || j >= 32;
|
||||
}
|
||||
|
||||
private synchronized int getOffset(int i, int j) {
|
||||
return this.d[i + j * 32];
|
||||
}
|
||||
|
||||
public boolean c(int i, int j) {
|
||||
return this.getOffset(i, j) != 0;
|
||||
}
|
||||
|
||||
private void a(int i, int j, int k) throws IOException {
|
||||
this.d[i + j * 32] = k;
|
||||
this.c.seek((long) ((i + j * 32) * 4));
|
||||
this.c.writeInt(k);
|
||||
}
|
||||
|
||||
private void b(int i, int j, int k) throws IOException {
|
||||
this.e[i + j * 32] = k;
|
||||
this.c.seek((long) (4096 + (i + j * 32) * 4));
|
||||
this.c.writeInt(k);
|
||||
}
|
||||
|
||||
public void c() throws IOException {
|
||||
if (this.c != null) {
|
||||
this.c.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Paper start
|
||||
public synchronized void deleteChunk(int j1) {
|
||||
backup();
|
||||
int k = offsets[j1];
|
||||
int x = j1 & 1024;
|
||||
int z = j1 >> 2;
|
||||
int offset = (k >> 8);
|
||||
int len = (k & 255);
|
||||
org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger();
|
||||
String debug = "idx:" + + j1 + " - " + x + "," + z + " - offset: " + offset + " - len: " + len;
|
||||
try {
|
||||
RandomAccessFile file = getDataFile();
|
||||
file.seek(j1 * 4);
|
||||
file.writeInt(0);
|
||||
// clear the timestamp
|
||||
file.seek(4096 + j1 * 4);
|
||||
file.writeInt(0);
|
||||
timestamps[j1] = 0;
|
||||
offsets[j1] = 0;
|
||||
logger.error("Deleted corrupt chunk (" + debug + ") " + getFile().getAbsolutePath(), e);
|
||||
} catch (IOException e) {
|
||||
|
||||
logger.error("Error deleting corrupt chunk (" + debug + ") " + getFile().getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
private boolean backedUp = false;
|
||||
private synchronized void backup() {
|
||||
if (backedUp) {
|
||||
return;
|
||||
}
|
||||
backedUp = true;
|
||||
File file = this.getFile();
|
||||
java.text.DateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd");
|
||||
java.util.Date today = new java.util.Date();
|
||||
File corrupt = new File(file.getParentFile(), file.getName() + "." + formatter.format(today) + ".corrupt");
|
||||
if (corrupt.exists()) {
|
||||
return;
|
||||
}
|
||||
org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger();
|
||||
logger.error("Region file " + file.getAbsolutePath() + " was corrupt. Backing up to " + corrupt.getAbsolutePath() + " and repairing");
|
||||
try {
|
||||
java.nio.file.Files.copy(file.toPath(), corrupt.toPath());
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error("Error backing up corrupt file" + file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private final byte[] oversized = new byte[1024];
|
||||
private int oversizedCount = 0;
|
||||
|
||||
private synchronized void initOversizedState() throws IOException {
|
||||
File metaFile = getOversizedMetaFile();
|
||||
if (metaFile.exists()) {
|
||||
final byte[] read = java.nio.file.Files.readAllBytes(metaFile.toPath());
|
||||
System.arraycopy(read, 0, oversized, 0, oversized.length);
|
||||
for (byte temp : oversized) {
|
||||
oversizedCount += temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getChunkIndex(int x, int z) {
|
||||
return (x & 31) + (z & 31) * 32;
|
||||
}
|
||||
synchronized boolean isOversized(int x, int z) {
|
||||
return this.oversized[getChunkIndex(x, z)] == 1;
|
||||
}
|
||||
synchronized void setOversized(int x, int z, boolean oversized) throws IOException {
|
||||
final int offset = getChunkIndex(x, z);
|
||||
boolean previous = this.oversized[offset] == 1;
|
||||
this.oversized[offset] = (byte) (oversized ? 1 : 0);
|
||||
if (!previous && oversized) {
|
||||
oversizedCount++;
|
||||
} else if (!oversized && previous) {
|
||||
oversizedCount--;
|
||||
}
|
||||
if (previous && !oversized) {
|
||||
File oversizedFile = getOversizedFile(x, z);
|
||||
if (oversizedFile.exists()) {
|
||||
oversizedFile.delete();
|
||||
}
|
||||
}
|
||||
if (oversizedCount > 0) {
|
||||
if (previous != oversized) {
|
||||
writeOversizedMeta();
|
||||
}
|
||||
} else if (previous) {
|
||||
File oversizedMetaFile = getOversizedMetaFile();
|
||||
if (oversizedMetaFile.exists()) {
|
||||
oversizedMetaFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOversizedMeta() throws IOException {
|
||||
java.nio.file.Files.write(getOversizedMetaFile().toPath(), oversized);
|
||||
}
|
||||
|
||||
private File getOversizedMetaFile() {
|
||||
return new File(getFile().getParentFile(), getFile().getName().replaceAll("\\.mca$", "") + ".oversized.nbt");
|
||||
}
|
||||
|
||||
private File getOversizedFile(int x, int z) {
|
||||
return new File(this.getFile().getParentFile(), this.getFile().getName().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt");
|
||||
}
|
||||
|
||||
void writeOversizedData(int x, int z, NBTTagCompound oversizedData) throws IOException {
|
||||
File file = getOversizedFile(x, z);
|
||||
try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new DeflaterOutputStream(new java.io.FileOutputStream(file), new java.util.zip.Deflater(java.util.zip.Deflater.BEST_COMPRESSION), 32 * 1024), 32 * 1024))) {
|
||||
NBTCompressedStreamTools.writeNBT(oversizedData, out);
|
||||
}
|
||||
this.setOversized(x, z, true);
|
||||
|
||||
}
|
||||
|
||||
synchronized NBTTagCompound getOversizedData(int x, int z) throws IOException {
|
||||
File file = getOversizedFile(x, z);
|
||||
try (DataInputStream out = new DataInputStream(new BufferedInputStream(new InflaterInputStream(new java.io.FileInputStream(file))))) {
|
||||
return NBTCompressedStreamTools.readNBT(out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final boolean USE_SPIGOT_OVERSIZED_METHOD = Boolean.getBoolean("Paper.useSpigotExtendedSaveMethod"); // Paper
|
||||
static {
|
||||
if (USE_SPIGOT_OVERSIZED_METHOD) {
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "====================================");
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Using Spigot Oversized Chunk save method. Warning this will result in extremely fragmented chunks, as well as making the entire region file unable to be to used in any other software but Forge or Spigot (not usable in Vanilla or CraftBukkit). Paper's method is highly recommended.");
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "====================================");
|
||||
}
|
||||
}
|
||||
|
||||
public class ChunkTooLargeException extends RuntimeException {
|
||||
public ChunkTooLargeException(int x, int z, int sectors) {
|
||||
super("Chunk " + x + "," + z + " of " + getFile().toString() + " is too large (" + sectors + "/256)");
|
||||
}
|
||||
}
|
||||
private static class DirectByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
public DirectByteArrayOutputStream() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DirectByteArrayOutputStream(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
public byte[] getBuffer() {
|
||||
return this.buf;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
class ChunkBuffer extends ByteArrayOutputStream {
|
||||
|
||||
private final int b;
|
||||
private final int c;
|
||||
|
||||
public ChunkBuffer(int i, int j) {
|
||||
super(8096);
|
||||
this.b = i;
|
||||
this.c = j;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
// Paper start - apply dynamic compression
|
||||
int origLength = this.count;
|
||||
byte[] buf = this.buf;
|
||||
DirectByteArrayOutputStream out = compressData(buf, origLength);
|
||||
byte[] bytes = out.getBuffer();
|
||||
int length = out.size();
|
||||
|
||||
RegionFile.this.a(this.b, this.c, bytes, length); // Paper - change to bytes/length
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] compressionBuffer = new byte[1024 * 64]; // 64k fits most standard chunks input size even, ideally 1 pass through zlib
|
||||
private static final java.util.zip.Deflater deflater = new java.util.zip.Deflater();
|
||||
// since file IO is single threaded, no benefit to using per-region file buffers/synchronization, we can change that later if it becomes viable.
|
||||
private static DirectByteArrayOutputStream compressData(byte[] buf, int length) throws IOException {
|
||||
synchronized (deflater) {
|
||||
deflater.setInput(buf, 0, length);
|
||||
deflater.finish();
|
||||
|
||||
|
||||
DirectByteArrayOutputStream out = new DirectByteArrayOutputStream(length);
|
||||
while (!deflater.finished()) {
|
||||
out.write(compressionBuffer, 0, deflater.deflate(compressionBuffer));
|
||||
}
|
||||
out.close();
|
||||
deflater.reset();
|
||||
return out;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
}
|
||||
356
sources/src/main/java/net/minecraft/server/SpawnerCreature.java
Normal file
356
sources/src/main/java/net/minecraft/server/SpawnerCreature.java
Normal file
@@ -0,0 +1,356 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
// CraftBukkit start
|
||||
import com.destroystokyo.paper.exception.ServerInternalException;
|
||||
import org.bukkit.craftbukkit.util.LongHash;
|
||||
import org.bukkit.craftbukkit.util.LongHashSet;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
// CraftBukkit end
|
||||
|
||||
public final class SpawnerCreature {
|
||||
|
||||
private static final int a = (int) Math.pow(17.0D, 2.0D);
|
||||
private final LongHashSet b = new LongHashSet(); // CraftBukkit
|
||||
|
||||
public SpawnerCreature() {}
|
||||
|
||||
// Spigot start - get entity count only from chunks being processed in b
|
||||
private int getEntityCount(WorldServer server, Class oClass)
|
||||
{
|
||||
// Paper start - use entire world, not just active chunks. Spigot broke vanilla expectations.
|
||||
if (true) {
|
||||
int sum = 0;
|
||||
for (Chunk c : server.getChunkProviderServer().chunks.values()) {
|
||||
sum += c.entityCount.get(oClass);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
// Paper end
|
||||
int i = 0;
|
||||
Iterator<Long> it = this.b.iterator();
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
Long coord = it.next();
|
||||
int x = LongHash.msw( coord );
|
||||
int z = LongHash.lsw( coord );
|
||||
if ( !((ChunkProviderServer)server.chunkProvider).unloadQueue.contains( coord ) && server.isChunkLoaded( x, z, true ) )
|
||||
{
|
||||
i += server.getChunkAt( x, z ).entityCount.get( oClass );
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
// Spigot end
|
||||
|
||||
public int a(WorldServer worldserver, boolean flag, boolean flag1, boolean flag2) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("check for eligible spawn chunks"); // Paper - At least until we figure out what is calling this async
|
||||
if (!flag && !flag1) {
|
||||
return 0;
|
||||
} else {
|
||||
this.b.clear();
|
||||
int i = 0;
|
||||
Iterator iterator = worldserver.players.iterator();
|
||||
|
||||
int j;
|
||||
int k;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EntityHuman entityhuman = (EntityHuman) iterator.next();
|
||||
|
||||
if (!entityhuman.isSpectator() && entityhuman.affectsSpawning) {
|
||||
int l = MathHelper.floor(entityhuman.locX / 16.0D);
|
||||
|
||||
j = MathHelper.floor(entityhuman.locZ / 16.0D);
|
||||
boolean flag3 = true;
|
||||
// Spigot Start
|
||||
byte b0 = worldserver.spigotConfig.mobSpawnRange;
|
||||
b0 = ( b0 > worldserver.spigotConfig.viewDistance ) ? (byte) worldserver.spigotConfig.viewDistance : b0;
|
||||
b0 = ( b0 > 8 ) ? 8 : b0;
|
||||
// Paper start
|
||||
com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
|
||||
event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(
|
||||
(org.bukkit.entity.Player) entityhuman.getBukkitEntity(), b0);
|
||||
if (!event.callEvent()) {
|
||||
continue;
|
||||
}
|
||||
b0 = event.getSpawnRadius();
|
||||
// Paperr end
|
||||
|
||||
for (int i1 = -b0; i1 <= b0; ++i1) {
|
||||
for (k = -b0; k <= b0; ++k) {
|
||||
boolean flag4 = i1 == -b0 || i1 == b0 || k == -b0 || k == b0;
|
||||
// Spigot End
|
||||
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i1 + l, k + j);
|
||||
|
||||
// CraftBukkit start - use LongHash and LongHashSet
|
||||
long chunkCoords = LongHash.toLong(chunkcoordintpair.x, chunkcoordintpair.z);
|
||||
if (!this.b.contains(chunkCoords)) {
|
||||
++i;
|
||||
if (!flag4 && worldserver.isChunkLoaded(chunkcoordintpair.x, chunkcoordintpair.z, true) && worldserver.getWorldBorder().isInBounds(chunkcoordintpair)) {
|
||||
PlayerChunk playerchunk = worldserver.getPlayerChunkMap().getChunk(chunkcoordintpair.x, chunkcoordintpair.z);
|
||||
|
||||
if (playerchunk != null && playerchunk.e()) {
|
||||
this.b.add(chunkCoords);
|
||||
// CraftBukkit end
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int j1 = 0;
|
||||
BlockPosition blockposition = worldserver.getSpawn();
|
||||
EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values();
|
||||
|
||||
j = aenumcreaturetype.length;
|
||||
|
||||
for (int k1 = 0; k1 < j; ++k1) {
|
||||
EnumCreatureType enumcreaturetype = aenumcreaturetype[k1];
|
||||
|
||||
// CraftBukkit start - Use per-world spawn limits
|
||||
int limit = enumcreaturetype.b();
|
||||
switch (enumcreaturetype) {
|
||||
case MONSTER:
|
||||
limit = worldserver.getWorld().getMonsterSpawnLimit();
|
||||
break;
|
||||
case CREATURE:
|
||||
limit = worldserver.getWorld().getAnimalSpawnLimit();
|
||||
break;
|
||||
case WATER_CREATURE:
|
||||
limit = worldserver.getWorld().getWaterAnimalSpawnLimit();
|
||||
break;
|
||||
case AMBIENT:
|
||||
limit = worldserver.getWorld().getAmbientSpawnLimit();
|
||||
break;
|
||||
}
|
||||
|
||||
if (limit == 0) {
|
||||
continue;
|
||||
}
|
||||
int mobcnt = 0; // Spigot
|
||||
// CraftBukkit end
|
||||
|
||||
if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && (!enumcreaturetype.e() || flag2)) {
|
||||
/* Paper start - As far as I can tell neither of these are even used
|
||||
k = worldserver.a(enumcreaturetype.a());
|
||||
int l1 = limit * i / a; // CraftBukkit - use per-world limits
|
||||
*/ // Paper end
|
||||
|
||||
if ((mobcnt = getEntityCount(worldserver, enumcreaturetype.a())) <= limit * i / 289) { // Paper - use 17x17 like vanilla (a at top of file)
|
||||
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
|
||||
Iterator iterator1 = this.b.iterator();
|
||||
|
||||
int moblimit = (limit * i / 256) - mobcnt + 1; // Spigot - up to 1 more than limit
|
||||
label120:
|
||||
while (iterator1.hasNext() && (moblimit > 0)) { // Spigot - while more allowed
|
||||
// CraftBukkit start = use LongHash and LongObjectHashMap
|
||||
long key = ((Long) iterator1.next()).longValue();
|
||||
BlockPosition blockposition1 = getRandomPosition(worldserver, LongHash.msw(key), LongHash.lsw(key));
|
||||
// CraftBukkit
|
||||
int i2 = blockposition1.getX();
|
||||
int j2 = blockposition1.getY();
|
||||
int k2 = blockposition1.getZ();
|
||||
IBlockData iblockdata = worldserver.getWorldBorder().isInBounds(blockposition1) ? worldserver.getTypeIfLoaded(blockposition1) : null; // Paper
|
||||
|
||||
if (iblockdata != null && !iblockdata.l()) { // Paper
|
||||
int l2 = 0;
|
||||
int i3 = 0;
|
||||
|
||||
while (i3 < 3) {
|
||||
int j3 = i2;
|
||||
int k3 = j2;
|
||||
int l3 = k2;
|
||||
boolean flag5 = true;
|
||||
BiomeBase.BiomeMeta biomebase_biomemeta = null;
|
||||
GroupDataEntity groupdataentity = null;
|
||||
int i4 = MathHelper.f(Math.random() * 4.0D);
|
||||
int j4 = 0;
|
||||
|
||||
while (true) {
|
||||
if (j4 < i4) {
|
||||
label113: {
|
||||
j3 += worldserver.random.nextInt(6) - worldserver.random.nextInt(6);
|
||||
k3 += worldserver.random.nextInt(1) - worldserver.random.nextInt(1);
|
||||
l3 += worldserver.random.nextInt(6) - worldserver.random.nextInt(6);
|
||||
blockposition_mutableblockposition.c(j3, k3, l3);
|
||||
float f = (float) j3 + 0.5F;
|
||||
float f1 = (float) l3 + 0.5F;
|
||||
|
||||
if (worldserver.getWorldBorder().isInBounds(blockposition_mutableblockposition) && worldserver.getChunkIfLoaded(blockposition_mutableblockposition) != null && !worldserver.isPlayerNearby((double) f, (double) k3, (double) f1, 24.0D) && blockposition.distanceSquared((double) f, (double) k3, (double) f1) >= 576.0D) { // Paper - Prevent mob spawning from loading/generating chunks
|
||||
if (biomebase_biomemeta == null) {
|
||||
biomebase_biomemeta = worldserver.a(enumcreaturetype, (BlockPosition) blockposition_mutableblockposition);
|
||||
if (biomebase_biomemeta == null) {
|
||||
break label113;
|
||||
}
|
||||
}
|
||||
|
||||
if (worldserver.a(enumcreaturetype, biomebase_biomemeta, (BlockPosition) blockposition_mutableblockposition) && a(EntityPositionTypes.a(biomebase_biomemeta.b), worldserver, blockposition_mutableblockposition)) {
|
||||
// Paper start
|
||||
com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
|
||||
Class<? extends EntityInsentient> cls = biomebase_biomemeta.b;
|
||||
org.bukkit.entity.EntityType type = EntityTypes.clsToTypeMap.get(cls);
|
||||
if (type != null) {
|
||||
event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
MCUtil.toLocation(worldserver, blockposition_mutableblockposition),
|
||||
type, SpawnReason.NATURAL
|
||||
);
|
||||
if (!event.callEvent()) {
|
||||
if (event.shouldAbortSpawn()) {
|
||||
continue label120;
|
||||
}
|
||||
j1 += l2;
|
||||
++j4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
EntityInsentient entityinsentient;
|
||||
|
||||
try {
|
||||
entityinsentient = (EntityInsentient) biomebase_biomemeta.b.getConstructor(new Class[] { World.class}).newInstance(new Object[] { worldserver});
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
ServerInternalException.reportInternalException(exception); // Paper
|
||||
return j1;
|
||||
}
|
||||
|
||||
entityinsentient.setPositionRotation((double) f, (double) k3, (double) f1, worldserver.random.nextFloat() * 360.0F, 0.0F);
|
||||
if (entityinsentient.P() && entityinsentient.canSpawn()) {
|
||||
groupdataentity = entityinsentient.prepare(worldserver.D(new BlockPosition(entityinsentient)), groupdataentity);
|
||||
if (entityinsentient.canSpawn()) {
|
||||
// CraftBukkit start
|
||||
if (worldserver.addEntity(entityinsentient, SpawnReason.NATURAL)) {
|
||||
++l2;
|
||||
moblimit--; // Spigot
|
||||
}
|
||||
// CraftBukkit end
|
||||
} else {
|
||||
entityinsentient.die();
|
||||
}
|
||||
|
||||
// Spigot start
|
||||
if ( moblimit <= 0 ) {
|
||||
// If we're past limit, stop spawn
|
||||
// Spigot end
|
||||
continue label120;
|
||||
}
|
||||
}
|
||||
|
||||
j1 += l2;
|
||||
}
|
||||
}
|
||||
|
||||
++j4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++i3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return j1;
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockPosition getRandomPosition(World world, int i, int j) {
|
||||
Chunk chunk = world.getChunkAt(i, j);
|
||||
int k = i * 16 + world.random.nextInt(16);
|
||||
int l = j * 16 + world.random.nextInt(16);
|
||||
int i1 = MathHelper.c(chunk.e(new BlockPosition(k, 0, l)) + 1, 16);
|
||||
int j1 = world.random.nextInt(i1 > 0 ? i1 : chunk.g() + 16 - 1);
|
||||
|
||||
return new BlockPosition(k, j1, l);
|
||||
}
|
||||
|
||||
public static boolean a(IBlockData iblockdata) {
|
||||
return iblockdata.k() ? false : (iblockdata.m() ? false : (iblockdata.getMaterial().isLiquid() ? false : !BlockMinecartTrackAbstract.i(iblockdata)));
|
||||
}
|
||||
|
||||
public static boolean a(EntityInsentient.EnumEntityPositionType entityinsentient_enumentitypositiontype, World world, BlockPosition blockposition) {
|
||||
if (!world.getWorldBorder().a(blockposition)) {
|
||||
return false;
|
||||
} else {
|
||||
IBlockData iblockdata = world.getType(blockposition);
|
||||
|
||||
if (entityinsentient_enumentitypositiontype == EntityInsentient.EnumEntityPositionType.IN_WATER) {
|
||||
return iblockdata.getMaterial() == Material.WATER && world.getType(blockposition.down()).getMaterial() == Material.WATER && !world.getType(blockposition.up()).l();
|
||||
} else {
|
||||
BlockPosition blockposition1 = blockposition.down();
|
||||
|
||||
if (!world.getType(blockposition1).q()) {
|
||||
return false;
|
||||
} else {
|
||||
Block block = world.getType(blockposition1).getBlock();
|
||||
boolean flag = block != Blocks.BEDROCK && block != Blocks.BARRIER;
|
||||
|
||||
return flag && a(iblockdata) && a(world.getType(blockposition.up()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void a(World world, BiomeBase biomebase, int i, int j, int k, int l, Random random) {
|
||||
List list = biomebase.getMobs(EnumCreatureType.CREATURE);
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
while (random.nextFloat() < biomebase.f()) {
|
||||
BiomeBase.BiomeMeta biomebase_biomemeta = (BiomeBase.BiomeMeta) WeightedRandom.a(world.random, list);
|
||||
int i1 = biomebase_biomemeta.c + random.nextInt(1 + biomebase_biomemeta.d - biomebase_biomemeta.c);
|
||||
GroupDataEntity groupdataentity = null;
|
||||
int j1 = i + random.nextInt(k);
|
||||
int k1 = j + random.nextInt(l);
|
||||
int l1 = j1;
|
||||
int i2 = k1;
|
||||
|
||||
for (int j2 = 0; j2 < i1; ++j2) {
|
||||
boolean flag = false;
|
||||
|
||||
for (int k2 = 0; !flag && k2 < 4; ++k2) {
|
||||
BlockPosition blockposition = world.q(new BlockPosition(j1, 0, k1));
|
||||
|
||||
if (a(EntityInsentient.EnumEntityPositionType.ON_GROUND, world, blockposition)) {
|
||||
EntityInsentient entityinsentient;
|
||||
|
||||
try {
|
||||
entityinsentient = (EntityInsentient) biomebase_biomemeta.b.getConstructor(new Class[] { World.class}).newInstance(new Object[] { world});
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
ServerInternalException.reportInternalException(exception); // Paper
|
||||
continue;
|
||||
}
|
||||
|
||||
entityinsentient.setPositionRotation((double) ((float) j1 + 0.5F), (double) blockposition.getY(), (double) ((float) k1 + 0.5F), random.nextFloat() * 360.0F, 0.0F);
|
||||
// CraftBukkit start - Added a reason for spawning this creature, moved entityinsentient.prepare(groupdataentity) up
|
||||
groupdataentity = entityinsentient.prepare(world.D(new BlockPosition(entityinsentient)), groupdataentity);
|
||||
world.addEntity(entityinsentient, SpawnReason.CHUNK_GEN);
|
||||
// CraftBukkit end
|
||||
flag = true;
|
||||
}
|
||||
|
||||
j1 += random.nextInt(5) - random.nextInt(5);
|
||||
|
||||
for (k1 += random.nextInt(5) - random.nextInt(5); j1 < i || j1 >= i + k || k1 < j || k1 >= j + k; k1 = i2 + random.nextInt(5) - random.nextInt(5)) {
|
||||
j1 = l1 + random.nextInt(5) - random.nextInt(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.Iterator;
|
||||
// CraftBukkit start
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.event.inventory.FurnaceBurnEvent;
|
||||
import org.bukkit.event.inventory.FurnaceSmeltEvent;
|
||||
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
// CraftBukkit end
|
||||
|
||||
public class TileEntityFurnace extends TileEntityContainer implements ITickable, IWorldInventory {
|
||||
|
||||
private static final int[] a = new int[] { 0};
|
||||
private static final int[] f = new int[] { 2, 1};
|
||||
private static final int[] g = new int[] { 1};
|
||||
private NonNullList<ItemStack> items;
|
||||
private int burnTime;
|
||||
private int ticksForCurrentFuel;
|
||||
private int cookTime;
|
||||
private int cookTimeTotal;
|
||||
private String m;
|
||||
|
||||
// CraftBukkit start - add fields and methods
|
||||
private int lastTick = MinecraftServer.currentTick;
|
||||
private int maxStack = MAX_STACK;
|
||||
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
|
||||
public List<ItemStack> getContents() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public void onOpen(CraftHumanEntity who) {
|
||||
transaction.add(who);
|
||||
}
|
||||
|
||||
public void onClose(CraftHumanEntity who) {
|
||||
transaction.remove(who);
|
||||
}
|
||||
|
||||
public List<HumanEntity> getViewers() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public void setMaxStackSize(int size) {
|
||||
maxStack = size;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
public TileEntityFurnace() {
|
||||
this.items = NonNullList.a(3, ItemStack.a);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return this.items.size();
|
||||
}
|
||||
|
||||
public boolean x_() {
|
||||
Iterator iterator = this.items.iterator();
|
||||
|
||||
ItemStack itemstack;
|
||||
|
||||
do {
|
||||
if (!iterator.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
itemstack = (ItemStack) iterator.next();
|
||||
} while (itemstack.isEmpty());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ItemStack getItem(int i) {
|
||||
return (ItemStack) this.items.get(i);
|
||||
}
|
||||
|
||||
public ItemStack splitStack(int i, int j) {
|
||||
return ContainerUtil.a(this.items, i, j);
|
||||
}
|
||||
|
||||
public ItemStack splitWithoutUpdate(int i) {
|
||||
return ContainerUtil.a(this.items, i);
|
||||
}
|
||||
|
||||
public void setItem(int i, ItemStack itemstack) {
|
||||
ItemStack itemstack1 = (ItemStack) this.items.get(i);
|
||||
boolean flag = !itemstack.isEmpty() && itemstack.doMaterialsMatch(itemstack1) && ItemStack.equals(itemstack, itemstack1);
|
||||
|
||||
this.items.set(i, itemstack);
|
||||
if (itemstack.getCount() > this.getMaxStackSize()) {
|
||||
itemstack.setCount(this.getMaxStackSize());
|
||||
}
|
||||
|
||||
if (i == 0 && !flag) {
|
||||
this.cookTimeTotal = this.a(itemstack);
|
||||
this.cookTime = 0;
|
||||
this.update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.hasCustomName() ? this.m : "container.furnace";
|
||||
}
|
||||
|
||||
public boolean hasCustomName() {
|
||||
return this.m != null && !this.m.isEmpty();
|
||||
}
|
||||
|
||||
public void setCustomName(String s) {
|
||||
this.m = s;
|
||||
}
|
||||
|
||||
public static void a(DataConverterManager dataconvertermanager) {
|
||||
dataconvertermanager.a(DataConverterTypes.BLOCK_ENTITY, (DataInspector) (new DataInspectorItemList(TileEntityFurnace.class, new String[] { "Items"})));
|
||||
}
|
||||
|
||||
public void load(NBTTagCompound nbttagcompound) {
|
||||
super.load(nbttagcompound);
|
||||
this.items = NonNullList.a(this.getSize(), ItemStack.a);
|
||||
ContainerUtil.b(nbttagcompound, this.items);
|
||||
this.burnTime = nbttagcompound.getShort("BurnTime");
|
||||
this.cookTime = nbttagcompound.getShort("CookTime");
|
||||
this.cookTimeTotal = nbttagcompound.getShort("CookTimeTotal");
|
||||
this.ticksForCurrentFuel = fuelTime((ItemStack) this.items.get(1));
|
||||
if (nbttagcompound.hasKeyOfType("CustomName", 8)) {
|
||||
this.m = nbttagcompound.getString("CustomName");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
|
||||
super.save(nbttagcompound);
|
||||
nbttagcompound.setShort("BurnTime", (short) this.burnTime);
|
||||
nbttagcompound.setShort("CookTime", (short) this.cookTime);
|
||||
nbttagcompound.setShort("CookTimeTotal", (short) this.cookTimeTotal);
|
||||
ContainerUtil.a(nbttagcompound, this.items);
|
||||
if (this.hasCustomName()) {
|
||||
nbttagcompound.setString("CustomName", this.m);
|
||||
}
|
||||
|
||||
return nbttagcompound;
|
||||
}
|
||||
|
||||
public int getMaxStackSize() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
public boolean isBurning() {
|
||||
return this.burnTime > 0;
|
||||
}
|
||||
|
||||
public void e() {
|
||||
boolean flag = (this.getBlock() == Blocks.LIT_FURNACE); // CraftBukkit - SPIGOT-844 - Check if furnace block is lit using the block instead of burn time
|
||||
boolean flag1 = false;
|
||||
|
||||
// CraftBukkit start - Use wall time instead of ticks for cooking
|
||||
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
|
||||
// CraftBukkit - moved from below - edited for wall time
|
||||
if (this.isBurning() && this.canBurn()) {
|
||||
this.cookTime += elapsedTicks;
|
||||
if (this.cookTime >= this.cookTimeTotal) {
|
||||
this.cookTime -= this.cookTimeTotal; // Paper
|
||||
this.cookTimeTotal = this.a((ItemStack) this.items.get(0));
|
||||
this.burn();
|
||||
flag1 = true;
|
||||
}
|
||||
} else {
|
||||
this.cookTime = 0;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.isBurning()) {
|
||||
this.burnTime -= elapsedTicks; // CraftBukkit - use elapsedTicks in place of constant
|
||||
}
|
||||
|
||||
if (!this.world.isClientSide) {
|
||||
ItemStack itemstack = (ItemStack) this.items.get(1);
|
||||
|
||||
if (!this.isBurning() && (itemstack.isEmpty() || ((ItemStack) this.items.get(0)).isEmpty())) {
|
||||
if (!this.isBurning() && this.cookTime > 0) {
|
||||
this.cookTime = MathHelper.clamp(this.cookTime - 2, 0, this.cookTimeTotal);
|
||||
}
|
||||
} else if(this.items.get(1) != null && this.items.get(1).getItem() != Items.BUCKET) {
|
||||
// CraftBukkit start - Handle multiple elapsed ticks
|
||||
if (this.burnTime <= 0 && this.canBurn()) { // CraftBukkit - == to <=
|
||||
CraftItemStack fuel = CraftItemStack.asCraftMirror(itemstack);
|
||||
|
||||
FurnaceBurnEvent furnaceBurnEvent = new FurnaceBurnEvent(this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), fuel, fuelTime(itemstack));
|
||||
this.world.getServer().getPluginManager().callEvent(furnaceBurnEvent);
|
||||
|
||||
if (furnaceBurnEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.ticksForCurrentFuel = furnaceBurnEvent.getBurnTime();
|
||||
this.burnTime += this.ticksForCurrentFuel;
|
||||
if (this.burnTime > 0 && furnaceBurnEvent.isBurning()) {
|
||||
// CraftBukkit end
|
||||
flag1 = true;
|
||||
if (!itemstack.isEmpty()) {
|
||||
Item item = itemstack.getItem();
|
||||
|
||||
itemstack.subtract(1);
|
||||
if (itemstack.isEmpty()) {
|
||||
Item item1 = item.q();
|
||||
|
||||
this.items.set(1, item1 == null ? ItemStack.a : new ItemStack(item1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* CraftBukkit start - Moved up
|
||||
if (this.isBurning() && this.canBurn()) {
|
||||
++this.cookTime;
|
||||
if (this.cookTime == this.cookTimeTotal) {
|
||||
this.cookTime = 0;
|
||||
this.cookTimeTotal = this.a((ItemStack) this.items.get(0));
|
||||
this.burn();
|
||||
flag1 = true;
|
||||
}
|
||||
} else {
|
||||
this.cookTime = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (flag != this.isBurning()) {
|
||||
flag1 = true;
|
||||
BlockFurnace.a(this.isBurning(), this.world, this.position);
|
||||
this.invalidateBlockCache(); // CraftBukkit - Invalidate tile entity's cached block type
|
||||
}
|
||||
}
|
||||
|
||||
if (flag1) {
|
||||
this.update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int a(ItemStack itemstack) {
|
||||
return 200;
|
||||
}
|
||||
|
||||
private boolean canBurn() {
|
||||
if (((ItemStack) this.items.get(0)).isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
ItemStack itemstack = RecipesFurnace.getInstance().getResult((ItemStack) this.items.get(0));
|
||||
|
||||
if (itemstack.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
ItemStack itemstack1 = (ItemStack) this.items.get(2);
|
||||
|
||||
// CraftBukkit - consider resultant count instead of current count
|
||||
return itemstack1.isEmpty() ? true : (!itemstack1.doMaterialsMatch(itemstack) ? false : (itemstack1.getCount() + itemstack.getCount() <= this.getMaxStackSize() && itemstack1.getCount() + itemstack.getCount() < itemstack1.getMaxStackSize() ? true : itemstack1.getCount() + itemstack.getCount() <= itemstack.getMaxStackSize()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void burn() {
|
||||
if (this.canBurn()) {
|
||||
ItemStack itemstack = (ItemStack) this.items.get(0);
|
||||
ItemStack itemstack1 = RecipesFurnace.getInstance().getResult(itemstack);
|
||||
ItemStack itemstack2 = (ItemStack) this.items.get(2);
|
||||
|
||||
// CraftBukkit start - fire FurnaceSmeltEvent
|
||||
CraftItemStack source = CraftItemStack.asCraftMirror(itemstack);
|
||||
org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1);
|
||||
|
||||
FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), source, result);
|
||||
this.world.getServer().getPluginManager().callEvent(furnaceSmeltEvent);
|
||||
|
||||
if (furnaceSmeltEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
result = furnaceSmeltEvent.getResult();
|
||||
itemstack1 = CraftItemStack.asNMSCopy(result);
|
||||
|
||||
if (!itemstack1.isEmpty()) {
|
||||
if (itemstack2.isEmpty()) {
|
||||
this.items.set(2, itemstack1.cloneItemStack());
|
||||
} else if (CraftItemStack.asCraftMirror(itemstack2).isSimilar(result)) {
|
||||
itemstack2.add(itemstack1.getCount());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (itemstack2.isEmpty()) {
|
||||
this.items.set(2, itemstack1.cloneItemStack());
|
||||
} else if (itemstack2.getItem() == itemstack1.getItem()) {
|
||||
itemstack2.add(1);
|
||||
}
|
||||
*/
|
||||
// CraftBukkit end
|
||||
|
||||
if (itemstack.getItem() == Item.getItemOf(Blocks.SPONGE) && itemstack.getData() == 1 && !((ItemStack) this.items.get(1)).isEmpty() && ((ItemStack) this.items.get(1)).getItem() == Items.BUCKET) {
|
||||
this.items.set(1, new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
|
||||
itemstack.subtract(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static int fuelTime(ItemStack itemstack) {
|
||||
if (itemstack.isEmpty()) {
|
||||
return 0;
|
||||
} else {
|
||||
Item item = itemstack.getItem();
|
||||
|
||||
return item == Item.getItemOf(Blocks.WOODEN_SLAB) ? 150 : (item == Item.getItemOf(Blocks.WOOL) ? 100 : (item == Item.getItemOf(Blocks.CARPET) ? 67 : (item == Item.getItemOf(Blocks.LADDER) ? 300 : (item == Item.getItemOf(Blocks.WOODEN_BUTTON) ? 100 : (Block.asBlock(item).getBlockData().getMaterial() == Material.WOOD ? 300 : (item == Item.getItemOf(Blocks.COAL_BLOCK) ? 16000 : (item instanceof ItemTool && "WOOD".equals(((ItemTool) item).h()) ? 200 : (item instanceof ItemSword && "WOOD".equals(((ItemSword) item).h()) ? 200 : (item instanceof ItemHoe && "WOOD".equals(((ItemHoe) item).g()) ? 200 : (item == Items.STICK ? 100 : (item != Items.BOW && item != Items.FISHING_ROD ? (item == Items.SIGN ? 200 : (item == Items.COAL ? 1600 : (item == Items.LAVA_BUCKET ? 20000 : (item != Item.getItemOf(Blocks.SAPLING) && item != Items.BOWL ? (item == Items.BLAZE_ROD ? 2400 : (item instanceof ItemDoor && item != Items.IRON_DOOR ? 200 : (item instanceof ItemBoat ? 400 : 0))) : 100)))) : 300)))))))))));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFuel(ItemStack itemstack) {
|
||||
return fuelTime(itemstack) > 0;
|
||||
}
|
||||
|
||||
public boolean a(EntityHuman entityhuman) {
|
||||
return this.world.getTileEntity(this.position) != this ? false : entityhuman.d((double) this.position.getX() + 0.5D, (double) this.position.getY() + 0.5D, (double) this.position.getZ() + 0.5D) <= 64.0D;
|
||||
}
|
||||
|
||||
public void startOpen(EntityHuman entityhuman) {}
|
||||
|
||||
public void closeContainer(EntityHuman entityhuman) {}
|
||||
|
||||
public boolean b(int i, ItemStack itemstack) {
|
||||
if (i == 2) {
|
||||
return false;
|
||||
} else if (i != 1) {
|
||||
return true;
|
||||
} else {
|
||||
ItemStack itemstack1 = (ItemStack) this.items.get(1);
|
||||
|
||||
return isFuel(itemstack) || SlotFurnaceFuel.d_(itemstack) && itemstack1.getItem() != Items.BUCKET;
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getSlotsForFace(EnumDirection enumdirection) {
|
||||
return enumdirection == EnumDirection.DOWN ? TileEntityFurnace.f : (enumdirection == EnumDirection.UP ? TileEntityFurnace.a : TileEntityFurnace.g);
|
||||
}
|
||||
|
||||
public boolean canPlaceItemThroughFace(int i, ItemStack itemstack, EnumDirection enumdirection) {
|
||||
return this.b(i, itemstack);
|
||||
}
|
||||
|
||||
public boolean canTakeItemThroughFace(int i, ItemStack itemstack, EnumDirection enumdirection) {
|
||||
if (enumdirection == EnumDirection.DOWN && i == 1) {
|
||||
Item item = itemstack.getItem();
|
||||
|
||||
if (item != Items.WATER_BUCKET && item != Items.BUCKET) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getContainerName() {
|
||||
return "minecraft:furnace";
|
||||
}
|
||||
|
||||
public Container createContainer(PlayerInventory playerinventory, EntityHuman entityhuman) {
|
||||
return new ContainerFurnace(playerinventory, this);
|
||||
}
|
||||
|
||||
public int getProperty(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return this.burnTime;
|
||||
|
||||
case 1:
|
||||
return this.ticksForCurrentFuel;
|
||||
|
||||
case 2:
|
||||
return this.cookTime;
|
||||
|
||||
case 3:
|
||||
return this.cookTimeTotal;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void setProperty(int i, int j) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
this.burnTime = j;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
this.ticksForCurrentFuel = j;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this.cookTime = j;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
this.cookTimeTotal = j;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int h() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.items.clear();
|
||||
}
|
||||
}
|
||||
784
sources/src/main/java/net/minecraft/server/TileEntityHopper.java
Normal file
784
sources/src/main/java/net/minecraft/server/TileEntityHopper.java
Normal file
@@ -0,0 +1,784 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
// CraftBukkit start
|
||||
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryPickupItemEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
// CraftBukkit end
|
||||
|
||||
public class TileEntityHopper extends TileEntityLootable implements IHopper, ITickable {
|
||||
|
||||
private NonNullList<ItemStack> items;
|
||||
private int f;
|
||||
private long g;
|
||||
|
||||
// CraftBukkit start - add fields and methods
|
||||
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
private int maxStack = MAX_STACK;
|
||||
|
||||
public List<ItemStack> getContents() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public void onOpen(CraftHumanEntity who) {
|
||||
transaction.add(who);
|
||||
}
|
||||
|
||||
public void onClose(CraftHumanEntity who) {
|
||||
transaction.remove(who);
|
||||
}
|
||||
|
||||
public List<HumanEntity> getViewers() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public void setMaxStackSize(int size) {
|
||||
maxStack = size;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
public TileEntityHopper() {
|
||||
this.items = NonNullList.a(5, ItemStack.a);
|
||||
this.f = -1;
|
||||
}
|
||||
|
||||
public static void a(DataConverterManager dataconvertermanager) {
|
||||
dataconvertermanager.a(DataConverterTypes.BLOCK_ENTITY, (DataInspector) (new DataInspectorItemList(TileEntityHopper.class, new String[] { "Items"})));
|
||||
}
|
||||
|
||||
public void load(NBTTagCompound nbttagcompound) {
|
||||
super.load(nbttagcompound);
|
||||
this.items = NonNullList.a(this.getSize(), ItemStack.a);
|
||||
if (!this.c(nbttagcompound)) {
|
||||
ContainerUtil.b(nbttagcompound, this.items);
|
||||
}
|
||||
|
||||
if (nbttagcompound.hasKeyOfType("CustomName", 8)) {
|
||||
this.o = nbttagcompound.getString("CustomName");
|
||||
}
|
||||
|
||||
this.f = nbttagcompound.getInt("TransferCooldown");
|
||||
}
|
||||
|
||||
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
|
||||
super.save(nbttagcompound);
|
||||
if (!this.d(nbttagcompound)) {
|
||||
ContainerUtil.a(nbttagcompound, this.items);
|
||||
}
|
||||
|
||||
nbttagcompound.setInt("TransferCooldown", this.f);
|
||||
if (this.hasCustomName()) {
|
||||
nbttagcompound.setString("CustomName", this.o);
|
||||
}
|
||||
|
||||
return nbttagcompound;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return this.items.size();
|
||||
}
|
||||
|
||||
public ItemStack splitStack(int i, int j) {
|
||||
this.d((EntityHuman) null);
|
||||
ItemStack itemstack = ContainerUtil.a(this.q(), i, j);
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
public void setItem(int i, ItemStack itemstack) {
|
||||
this.d((EntityHuman) null);
|
||||
this.q().set(i, itemstack);
|
||||
if (itemstack.getCount() > this.getMaxStackSize()) {
|
||||
itemstack.setCount(this.getMaxStackSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.hasCustomName() ? this.o : "container.hopper";
|
||||
}
|
||||
|
||||
public int getMaxStackSize() {
|
||||
return maxStack; // CraftBukkit
|
||||
}
|
||||
|
||||
public void e() {
|
||||
if (this.world != null && !this.world.isClientSide) {
|
||||
--this.f;
|
||||
this.g = this.world.getTime();
|
||||
if (!this.J()) {
|
||||
this.setCooldown(0);
|
||||
// Spigot start
|
||||
if (!this.o() && this.world.spigotConfig.hopperCheck > 1) {
|
||||
this.setCooldown(this.world.spigotConfig.hopperCheck);
|
||||
}
|
||||
// Spigot end
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean o() {
|
||||
mayAcceptItems = false; // Paper - at the beginning of a tick, assume we can't accept items
|
||||
if (this.world != null && !this.world.isClientSide) {
|
||||
if (!this.J() && BlockHopper.f(this.v())) {
|
||||
boolean flag = false;
|
||||
|
||||
if (!this.p()) {
|
||||
flag = this.s();
|
||||
}
|
||||
|
||||
if (!this.r()) {
|
||||
mayAcceptItems = true; // Paper - flag this hopper to be able to accept items
|
||||
flag = a((IHopper) this) || flag;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
this.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
|
||||
this.update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private boolean mayAcceptItems = false;
|
||||
|
||||
public boolean canAcceptItems() {
|
||||
return mayAcceptItems;
|
||||
}
|
||||
// Paper end
|
||||
|
||||
private boolean p() {
|
||||
Iterator iterator = this.items.iterator();
|
||||
|
||||
ItemStack itemstack;
|
||||
|
||||
do {
|
||||
if (!iterator.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
itemstack = (ItemStack) iterator.next();
|
||||
} while (itemstack.isEmpty());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean x_() {
|
||||
return this.p();
|
||||
}
|
||||
|
||||
private boolean r() {
|
||||
Iterator iterator = this.items.iterator();
|
||||
|
||||
ItemStack itemstack;
|
||||
|
||||
do {
|
||||
if (!iterator.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
itemstack = (ItemStack) iterator.next();
|
||||
} while (!itemstack.isEmpty() && itemstack.getCount() == itemstack.getMaxStackSize());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Paper start - Optimize Hoppers
|
||||
private static boolean skipPullModeEventFire = false;
|
||||
private static boolean skipPushModeEventFire = false;
|
||||
static boolean skipHopperEvents = false;
|
||||
|
||||
private boolean hopperPush(IInventory iinventory, EnumDirection enumdirection) {
|
||||
skipPushModeEventFire = skipHopperEvents;
|
||||
boolean foundItem = false;
|
||||
for (int i = 0; i < this.getSize(); ++i) {
|
||||
if (!this.getItem(i).isEmpty()) {
|
||||
foundItem = true;
|
||||
ItemStack origItemStack = this.getItem(i);
|
||||
ItemStack itemstack = origItemStack;
|
||||
|
||||
final int origCount = origItemStack.getCount();
|
||||
final int moved = Math.min(world.spigotConfig.hopperAmount, origCount);
|
||||
origItemStack.setCount(moved);
|
||||
|
||||
// We only need to fire the event once to give protection plugins a chance to cancel this event
|
||||
// Because nothing uses getItem, every event call should end up the same result.
|
||||
if (!skipPushModeEventFire) {
|
||||
itemstack = callPushMoveEvent(iinventory, itemstack);
|
||||
if (itemstack == null) { // cancelled
|
||||
origItemStack.setCount(origCount);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
final ItemStack itemstack2 = addItem(this, iinventory, itemstack, enumdirection);
|
||||
final int remaining = itemstack2.getCount();
|
||||
if (remaining != moved) {
|
||||
origItemStack = origItemStack.cloneItemStack();
|
||||
origItemStack.setCount(origCount - moved + remaining);
|
||||
this.setItem(i, origItemStack);
|
||||
iinventory.update();
|
||||
return true;
|
||||
}
|
||||
origItemStack.setCount(origCount);
|
||||
}
|
||||
}
|
||||
if (foundItem && world.paperConfig.cooldownHopperWhenFull) { // Inventory was full - cooldown
|
||||
this.setCooldown(world.spigotConfig.hopperTransfer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hopperPull(IHopper ihopper, IInventory iinventory, int i) {
|
||||
ItemStack origItemStack = iinventory.getItem(i);
|
||||
ItemStack itemstack = origItemStack;
|
||||
final int origCount = origItemStack.getCount();
|
||||
final World world = ihopper.getWorld();
|
||||
final int moved = Math.min(world.spigotConfig.hopperAmount, origCount);
|
||||
itemstack.setCount(moved);
|
||||
|
||||
if (!skipPullModeEventFire) {
|
||||
itemstack = callPullMoveEvent(ihopper, iinventory, itemstack);
|
||||
if (itemstack == null) { // cancelled
|
||||
origItemStack.setCount(origCount);
|
||||
// Drastically improve performance by returning true.
|
||||
// No plugin could of relied on the behavior of false as the other call
|
||||
// site for IMIE did not exhibit the same behavior
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
final ItemStack itemstack2 = addItem(iinventory, ihopper, itemstack, null);
|
||||
final int remaining = itemstack2.getCount();
|
||||
if (remaining != moved) {
|
||||
origItemStack = origItemStack.cloneItemStack();
|
||||
origItemStack.setCount(origCount - moved + remaining);
|
||||
IGNORE_TILE_UPDATES = true;
|
||||
iinventory.setItem(i, origItemStack);
|
||||
IGNORE_TILE_UPDATES = false;
|
||||
iinventory.update();
|
||||
return true;
|
||||
}
|
||||
origItemStack.setCount(origCount);
|
||||
|
||||
if (world.paperConfig.cooldownHopperWhenFull) {
|
||||
cooldownHopper(ihopper);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private ItemStack callPushMoveEvent(IInventory iinventory, ItemStack itemstack) {
|
||||
Inventory destinationInventory = getInventory(iinventory);
|
||||
InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner(false).getInventory(),
|
||||
CraftItemStack.asCraftMirror(itemstack), destinationInventory, true);
|
||||
boolean result = event.callEvent();
|
||||
if (!event.calledGetItem && !event.calledSetItem) {
|
||||
skipPushModeEventFire = true;
|
||||
}
|
||||
if (!result) {
|
||||
cooldownHopper(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (event.calledSetItem) {
|
||||
return CraftItemStack.asNMSCopy(event.getItem());
|
||||
} else {
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
private static ItemStack callPullMoveEvent(IHopper hopper, IInventory iinventory, ItemStack itemstack) {
|
||||
Inventory sourceInventory = getInventory(iinventory);
|
||||
Inventory destination = getInventory(hopper);
|
||||
|
||||
InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory,
|
||||
// Mirror is safe as we no plugins ever use this item
|
||||
CraftItemStack.asCraftMirror(itemstack), destination, false);
|
||||
boolean result = event.callEvent();
|
||||
if (!event.calledGetItem && !event.calledSetItem) {
|
||||
skipPullModeEventFire = true;
|
||||
}
|
||||
if (!result) {
|
||||
cooldownHopper(hopper);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (event.calledSetItem) {
|
||||
return CraftItemStack.asNMSCopy(event.getItem());
|
||||
} else {
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
|
||||
private static Inventory getInventory(IInventory iinventory) {
|
||||
Inventory sourceInventory;// Have to special case large chests as they work oddly
|
||||
if (iinventory instanceof InventoryLargeChest) {
|
||||
sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
|
||||
} else if (iinventory instanceof TileEntity) {
|
||||
sourceInventory = ((TileEntity) iinventory).getOwner(false).getInventory();
|
||||
} else {
|
||||
sourceInventory = iinventory.getOwner().getInventory();
|
||||
}
|
||||
return sourceInventory;
|
||||
}
|
||||
|
||||
private static void cooldownHopper(IHopper hopper) {
|
||||
if (hopper instanceof TileEntityHopper) {
|
||||
((TileEntityHopper) hopper).setCooldown(hopper.getWorld().spigotConfig.hopperTransfer);
|
||||
} else if (hopper instanceof EntityMinecartHopper) {
|
||||
((EntityMinecartHopper) hopper).setCooldown(hopper.getWorld().spigotConfig.hopperTransfer / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Paper end
|
||||
private boolean s() {
|
||||
IInventory iinventory = this.I();
|
||||
|
||||
if (iinventory == null) {
|
||||
return false;
|
||||
} else {
|
||||
EnumDirection enumdirection = BlockHopper.b(this.v()).opposite();
|
||||
|
||||
if (this.a(iinventory, enumdirection)) {
|
||||
return false;
|
||||
} else {
|
||||
return hopperPush(iinventory, enumdirection); /* // Paper - disable rest
|
||||
for (int i = 0; i < this.getSize(); ++i) {
|
||||
if (!this.getItem(i).isEmpty()) {
|
||||
ItemStack itemstack = this.getItem(i).cloneItemStack();
|
||||
// ItemStack itemstack1 = addItem(this, iinventory, this.splitStack(i, 1), enumdirection);
|
||||
|
||||
// CraftBukkit start - Call event when pushing items into other inventories
|
||||
CraftItemStack oitemstack = CraftItemStack.asCraftMirror(this.splitStack(i, world.spigotConfig.hopperAmount)); // Spigot
|
||||
|
||||
Inventory destinationInventory;
|
||||
// Have to special case large chests as they work oddly
|
||||
if (iinventory instanceof InventoryLargeChest) {
|
||||
destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
|
||||
} else {
|
||||
destinationInventory = iinventory.getOwner().getInventory();
|
||||
}
|
||||
|
||||
InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
|
||||
this.getWorld().getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
this.setItem(i, itemstack);
|
||||
this.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
|
||||
return false;
|
||||
}
|
||||
int origCount = event.getItem().getAmount(); // Spigot
|
||||
ItemStack itemstack1 = addItem(this, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
|
||||
|
||||
if (itemstack1.isEmpty()) {
|
||||
if (event.getItem().equals(oitemstack)) {
|
||||
iinventory.update();
|
||||
} else {
|
||||
this.setItem(i, itemstack);
|
||||
}
|
||||
// CraftBukkit end
|
||||
return true;
|
||||
}
|
||||
|
||||
itemstack.subtract(origCount - itemstack1.getCount()); // Spigot
|
||||
this.setItem(i, itemstack);
|
||||
}
|
||||
}
|
||||
|
||||
return false;*/ // Paper - end commenting out replaced block for Hopper Optimizations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean a(IInventory iinventory, EnumDirection enumdirection) {
|
||||
if (iinventory instanceof IWorldInventory) {
|
||||
IWorldInventory iworldinventory = (IWorldInventory) iinventory;
|
||||
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
|
||||
int[] aint1 = aint;
|
||||
int i = aint.length;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
int k = aint1[j];
|
||||
ItemStack itemstack = iworldinventory.getItem(k);
|
||||
|
||||
if (itemstack.isEmpty() || itemstack.getCount() != itemstack.getMaxStackSize()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int l = iinventory.getSize();
|
||||
|
||||
for (int i1 = 0; i1 < l; ++i1) {
|
||||
ItemStack itemstack1 = iinventory.getItem(i1);
|
||||
|
||||
if (itemstack1.isEmpty() || itemstack1.getCount() != itemstack1.getMaxStackSize()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean b(IInventory iinventory, EnumDirection enumdirection) {
|
||||
if (iinventory instanceof IWorldInventory) {
|
||||
IWorldInventory iworldinventory = (IWorldInventory) iinventory;
|
||||
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
|
||||
int[] aint1 = aint;
|
||||
int i = aint.length;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
int k = aint1[j];
|
||||
|
||||
if (!iworldinventory.getItem(k).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int l = iinventory.getSize();
|
||||
|
||||
for (int i1 = 0; i1 < l; ++i1) {
|
||||
if (!iinventory.getItem(i1).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Paper start - split methods, and only do entity lookup if in pull mode
|
||||
public static boolean a(IHopper ihopper) {
|
||||
IInventory iinventory = getInventory(ihopper, !(ihopper instanceof TileEntityHopper) || !ihopper.getWorld().paperConfig.isHopperPushBased);
|
||||
|
||||
return acceptItem(ihopper, iinventory);
|
||||
}
|
||||
|
||||
public static boolean acceptItem(IHopper ihopper, IInventory iinventory) {
|
||||
// Paper end
|
||||
|
||||
if (iinventory != null) {
|
||||
EnumDirection enumdirection = EnumDirection.DOWN;
|
||||
|
||||
if (b(iinventory, enumdirection)) {
|
||||
return false;
|
||||
}
|
||||
skipPullModeEventFire = skipHopperEvents; // Paper
|
||||
|
||||
if (iinventory instanceof IWorldInventory) {
|
||||
IWorldInventory iworldinventory = (IWorldInventory) iinventory;
|
||||
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
|
||||
int[] aint1 = aint;
|
||||
int i = aint.length;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
int k = aint1[j];
|
||||
|
||||
if (a(ihopper, iinventory, k, enumdirection)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int l = iinventory.getSize();
|
||||
|
||||
for (int i1 = 0; i1 < l; ++i1) {
|
||||
if (a(ihopper, iinventory, i1, enumdirection)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!ihopper.getWorld().paperConfig.isHopperPushBased || !(ihopper instanceof TileEntityHopper)) { // Paper - only search for entities in 'pull mode'
|
||||
Iterator iterator = a(ihopper.getWorld(), ihopper.E(), ihopper.F(), ihopper.G()).iterator(); // Change getHopperLookupBoundingBox() if this ever changes
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
EntityItem entityitem = (EntityItem) iterator.next();
|
||||
|
||||
if (a((IInventory) null, ihopper, entityitem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean a(IHopper ihopper, IInventory iinventory, int i, EnumDirection enumdirection) {
|
||||
ItemStack itemstack = iinventory.getItem(i);
|
||||
|
||||
if (!itemstack.isEmpty() && b(iinventory, itemstack, i, enumdirection)) {
|
||||
return hopperPull(ihopper, iinventory, i); /* // Paper - disable rest
|
||||
ItemStack itemstack1 = itemstack.cloneItemStack();
|
||||
// ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.splitStack(i, 1), (EnumDirection) null);
|
||||
// CraftBukkit start - Call event on collection of items from inventories into the hopper
|
||||
CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.splitStack(i, ihopper.getWorld().spigotConfig.hopperAmount)); // Spigot
|
||||
|
||||
Inventory sourceInventory;
|
||||
// Have to special case large chests as they work oddly
|
||||
if (iinventory instanceof InventoryLargeChest) {
|
||||
sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
|
||||
} else {
|
||||
sourceInventory = iinventory.getOwner().getInventory();
|
||||
}
|
||||
|
||||
InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
|
||||
|
||||
ihopper.getWorld().getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
iinventory.setItem(i, itemstack1);
|
||||
|
||||
if (ihopper instanceof TileEntityHopper) {
|
||||
((TileEntityHopper) ihopper).setCooldown(ihopper.getWorld().spigotConfig.hopperTransfer); // Spigot
|
||||
} else if (ihopper instanceof EntityMinecartHopper) {
|
||||
((EntityMinecartHopper) ihopper).setCooldown(ihopper.getWorld().spigotConfig.hopperTransfer / 2); // Spigot
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int origCount = event.getItem().getAmount(); // Spigot
|
||||
ItemStack itemstack2 = addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
|
||||
|
||||
if (itemstack2.isEmpty()) {
|
||||
if (event.getItem().equals(oitemstack)) {
|
||||
iinventory.update();
|
||||
} else {
|
||||
iinventory.setItem(i, itemstack1);
|
||||
}
|
||||
// CraftBukkit end
|
||||
return true;
|
||||
}
|
||||
|
||||
itemstack1.subtract(origCount - itemstack2.getCount()); // Spigot
|
||||
iinventory.setItem(i, itemstack1);*/ // Paper - end commenting out replaced block for Hopper Optimizations
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean putDropInInventory(IInventory iinventory, IInventory iinventory1, EntityItem entityitem) { return a(iinventory, iinventory1, entityitem); } // Paper - OBFHELPER
|
||||
public static boolean a(IInventory iinventory, IInventory iinventory1, EntityItem entityitem) {
|
||||
boolean flag = false;
|
||||
|
||||
if (entityitem == null) {
|
||||
return false;
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(iinventory1), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); // Paper - avoid snapshot creation
|
||||
entityitem.world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
// CraftBukkit end
|
||||
ItemStack itemstack = entityitem.getItemStack().cloneItemStack();
|
||||
ItemStack itemstack1 = addItem(iinventory, iinventory1, itemstack, (EnumDirection) null);
|
||||
|
||||
if (itemstack1.isEmpty()) {
|
||||
flag = true;
|
||||
entityitem.die();
|
||||
} else {
|
||||
entityitem.setItemStack(itemstack1);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack addItem(IInventory iinventory, IInventory iinventory1, ItemStack itemstack, @Nullable EnumDirection enumdirection) {
|
||||
if (iinventory1 instanceof IWorldInventory && enumdirection != null) {
|
||||
IWorldInventory iworldinventory = (IWorldInventory) iinventory1;
|
||||
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
|
||||
|
||||
for (int i = 0; i < aint.length && !itemstack.isEmpty(); ++i) {
|
||||
itemstack = a(iinventory, iinventory1, itemstack, aint[i], enumdirection);
|
||||
}
|
||||
} else {
|
||||
int j = iinventory1.getSize();
|
||||
|
||||
for (int k = 0; k < j && !itemstack.isEmpty(); ++k) {
|
||||
itemstack = a(iinventory, iinventory1, itemstack, k, enumdirection);
|
||||
}
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
private static boolean a(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) {
|
||||
return !iinventory.b(i, itemstack) ? false : !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canPlaceItemThroughFace(i, itemstack, enumdirection);
|
||||
}
|
||||
|
||||
private static boolean b(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) {
|
||||
return !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canTakeItemThroughFace(i, itemstack, enumdirection);
|
||||
}
|
||||
|
||||
private static ItemStack a(IInventory iinventory, IInventory iinventory1, ItemStack itemstack, int i, EnumDirection enumdirection) {
|
||||
ItemStack itemstack1 = iinventory1.getItem(i);
|
||||
|
||||
if (a(iinventory1, itemstack, i, enumdirection)) {
|
||||
boolean flag = false;
|
||||
boolean flag1 = iinventory1.x_();
|
||||
|
||||
if (itemstack1.isEmpty()) {
|
||||
IGNORE_TILE_UPDATES = true; // Paper
|
||||
iinventory1.setItem(i, itemstack);
|
||||
IGNORE_TILE_UPDATES = false; // Paper
|
||||
itemstack = ItemStack.a;
|
||||
flag = true;
|
||||
} else if (a(itemstack1, itemstack)) {
|
||||
int j = itemstack.getMaxStackSize() - itemstack1.getCount();
|
||||
int k = Math.min(itemstack.getCount(), j);
|
||||
|
||||
itemstack.subtract(k);
|
||||
itemstack1.add(k);
|
||||
flag = k > 0;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
if (flag1 && iinventory1 instanceof TileEntityHopper) {
|
||||
TileEntityHopper tileentityhopper = (TileEntityHopper) iinventory1;
|
||||
|
||||
if (!tileentityhopper.K()) {
|
||||
byte b0 = 0;
|
||||
|
||||
if (iinventory != null && iinventory instanceof TileEntityHopper) {
|
||||
TileEntityHopper tileentityhopper1 = (TileEntityHopper) iinventory;
|
||||
|
||||
if (tileentityhopper.g >= tileentityhopper1.g) {
|
||||
b0 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
tileentityhopper.setCooldown(tileentityhopper.world.spigotConfig.hopperTransfer - b0); // Spigot
|
||||
}
|
||||
}
|
||||
|
||||
iinventory1.update();
|
||||
}
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
private IInventory I() {
|
||||
EnumDirection enumdirection = BlockHopper.b(this.v());
|
||||
|
||||
// Paper start - don't search for entities in push mode
|
||||
World world = getWorld();
|
||||
return getInventory(world, this.E() + (double) enumdirection.getAdjacentX(), this.F() + (double) enumdirection.getAdjacentY(), this.G() + (double) enumdirection.getAdjacentZ(), !world.paperConfig.isHopperPushBased);
|
||||
// Paper end
|
||||
}
|
||||
|
||||
// Paper start - add option to search for entities
|
||||
public static IInventory b(IHopper hopper) {
|
||||
return getInventory(hopper, true);
|
||||
}
|
||||
|
||||
public static IInventory getInventory(IHopper ihopper, boolean searchForEntities) {
|
||||
return getInventory(ihopper.getWorld(), ihopper.E(), ihopper.F() + 1.0D, ihopper.G(), searchForEntities);
|
||||
// Paper end
|
||||
}
|
||||
|
||||
public static List<EntityItem> a(World world, double d0, double d1, double d2) {
|
||||
return world.a(EntityItem.class, new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D), IEntitySelector.a); // Change getHopperLookupBoundingBox(double, double, double) if the bounding box calculation is ever changed
|
||||
}
|
||||
|
||||
// Paper start
|
||||
public AxisAlignedBB getHopperLookupBoundingBox() {
|
||||
return getHopperLookupBoundingBox(this.getX(), this.getY(), this.getZ());
|
||||
}
|
||||
|
||||
private static AxisAlignedBB getHopperLookupBoundingBox(double d0, double d1, double d2) {
|
||||
// Change this if a(World, double, double, double) above ever changes
|
||||
return new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
// Paper start - add option to searchForEntities
|
||||
public static IInventory b(World world, double d0, double d1, double d2) {
|
||||
return getInventory(world, d0, d1, d2, true);
|
||||
}
|
||||
|
||||
public static IInventory getInventory(World world, double d0, double d1, double d2, boolean searchForEntities) {
|
||||
// Paper end
|
||||
Object object = null;
|
||||
int i = MathHelper.floor(d0);
|
||||
int j = MathHelper.floor(d1);
|
||||
int k = MathHelper.floor(d2);
|
||||
BlockPosition blockposition = new BlockPosition(i, j, k);
|
||||
if ( !world.isLoaded( blockposition ) ) return null; // Spigot
|
||||
Block block = world.getType(blockposition).getBlock();
|
||||
|
||||
if (block.isTileEntity()) {
|
||||
TileEntity tileentity = world.getTileEntity(blockposition);
|
||||
|
||||
if (tileentity instanceof IInventory) {
|
||||
object = (IInventory) tileentity;
|
||||
if (object instanceof TileEntityChest && block instanceof BlockChest) {
|
||||
object = ((BlockChest) block).a(world, blockposition, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net.minecraft.server.Chunk chunk = world.getChunkAtWorldCoords(blockposition);
|
||||
|
||||
if (object == null && searchForEntities && !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding() && chunk.getItemCount(blockposition) > 0) { // Paper - only if searchForEntities
|
||||
List list = world.getEntities((Entity) null, new AxisAlignedBB(d0 - 0.5D, d1 - 0.5D, d2 - 0.5D, d0 + 0.5D, d1 + 0.5D, d2 + 0.5D), IEntitySelector.c);
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
object = (IInventory) list.get(world.random.nextInt(list.size()));
|
||||
}
|
||||
}
|
||||
|
||||
return (IInventory) object;
|
||||
}
|
||||
|
||||
private static boolean a(ItemStack itemstack, ItemStack itemstack1) {
|
||||
return itemstack.getItem() != itemstack1.getItem() ? false : (itemstack.getData() != itemstack1.getData() ? false : (itemstack.getCount() > itemstack.getMaxStackSize() ? false : ItemStack.equals(itemstack, itemstack1)));
|
||||
}
|
||||
|
||||
public double E() {
|
||||
return (double) this.position.getX() + 0.5D;
|
||||
}
|
||||
|
||||
public double F() {
|
||||
return (double) this.position.getY() + 0.5D;
|
||||
}
|
||||
|
||||
public double G() {
|
||||
return (double) this.position.getZ() + 0.5D;
|
||||
}
|
||||
|
||||
private void setCooldown(int i) {
|
||||
this.f = i;
|
||||
}
|
||||
|
||||
private boolean J() {
|
||||
return this.f > 0;
|
||||
}
|
||||
|
||||
private boolean K() {
|
||||
return this.f > 8;
|
||||
}
|
||||
|
||||
public String getContainerName() {
|
||||
return "minecraft:hopper";
|
||||
}
|
||||
|
||||
public Container createContainer(PlayerInventory playerinventory, EntityHuman entityhuman) {
|
||||
this.d(entityhuman);
|
||||
return new ContainerHopper(playerinventory, this, entityhuman);
|
||||
}
|
||||
|
||||
protected NonNullList<ItemStack> q() {
|
||||
return this.items;
|
||||
}
|
||||
}
|
||||
@@ -587,7 +587,9 @@ public abstract class World implements IBlockAccess {
|
||||
|
||||
public void a(BlockPosition blockposition, final Block block, BlockPosition blockposition1) {
|
||||
if (!this.isClientSide) {
|
||||
IBlockData iblockdata = this.getType(blockposition);
|
||||
//IBlockData iblockdata = this.getType(blockposition);
|
||||
IBlockData iblockdata = this.getTypeIfLoaded(blockposition); // NeonPaper Don't load chunks for physics
|
||||
if (iblockdata == null) return; // NeonPaper Don't load chunks for physics
|
||||
|
||||
try {
|
||||
// CraftBukkit start
|
||||
@@ -697,7 +699,7 @@ public abstract class World implements IBlockAccess {
|
||||
if (blockposition.getY() >= 256) {
|
||||
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
|
||||
}
|
||||
|
||||
if (!this.isLoaded(blockposition)) return 0; // Paper
|
||||
return this.getChunkAtWorldCoords(blockposition).a(blockposition, 0);
|
||||
}
|
||||
}
|
||||
@@ -1891,7 +1893,7 @@ public abstract class World implements IBlockAccess {
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
Entity entity1 = (Entity) list.get(i);
|
||||
|
||||
if (!entity1.dead && entity1.i && entity1 != entity && (entity == null || entity1.x(entity))) {
|
||||
if (!entity1.dead && entity1.i && entity1 != entity && (entity == null || !entity1.x(entity))) { // Reaper - Fix MC-103516
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
101
sources/src/main/java/net/minecraft/server/WorldManager.java
Normal file
101
sources/src/main/java/net/minecraft/server/WorldManager.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class WorldManager implements IWorldAccess {
|
||||
|
||||
private final MinecraftServer a;
|
||||
private final WorldServer world;
|
||||
|
||||
public WorldManager(MinecraftServer minecraftserver, WorldServer worldserver) {
|
||||
this.a = minecraftserver;
|
||||
this.world = worldserver;
|
||||
}
|
||||
|
||||
public void a(int i, boolean flag, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {}
|
||||
|
||||
public void a(int i, boolean flag, boolean flag1, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {}
|
||||
|
||||
public void a(Entity entity) {
|
||||
this.world.getTracker().track(entity);
|
||||
if (entity instanceof EntityPlayer) {
|
||||
this.world.worldProvider.a((EntityPlayer) entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void b(Entity entity) {
|
||||
this.world.getTracker().untrackEntity(entity);
|
||||
this.world.getScoreboard().a(entity);
|
||||
if (entity instanceof EntityPlayer) {
|
||||
this.world.worldProvider.b((EntityPlayer) entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a(@Nullable EntityHuman entityhuman, SoundEffect soundeffect, SoundCategory soundcategory, double d0, double d1, double d2, float f, float f1) {
|
||||
// CraftBukkit - this.world.dimension, // Paper - this.world.dimension -> this.world
|
||||
this.a.getPlayerList().sendPacketNearby(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world, new PacketPlayOutNamedSoundEffect(soundeffect, soundcategory, d0, d1, d2, f, f1));
|
||||
}
|
||||
|
||||
public void a(int i, int j, int k, int l, int i1, int j1) {}
|
||||
|
||||
public void a(World world, BlockPosition blockposition, IBlockData iblockdata, IBlockData iblockdata1, int i) {
|
||||
this.world.getPlayerChunkMap().flagDirty(blockposition);
|
||||
}
|
||||
|
||||
public void a(BlockPosition blockposition) {}
|
||||
|
||||
public void a(SoundEffect soundeffect, BlockPosition blockposition) {}
|
||||
|
||||
public void a(EntityHuman entityhuman, int i, BlockPosition blockposition, int j) {
|
||||
// CraftBukkit - this.world.dimension
|
||||
this.a.getPlayerList().sendPacketNearby(entityhuman, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 64.0D, this.world, new PacketPlayOutWorldEvent(i, blockposition, j, false));
|
||||
}
|
||||
|
||||
public void a(int i, BlockPosition blockposition, int j) {
|
||||
this.a.getPlayerList().sendAll(new PacketPlayOutWorldEvent(i, blockposition, j, true));
|
||||
}
|
||||
|
||||
public void b(int i, BlockPosition blockposition, int j) {
|
||||
// Iterator iterator = this.a.getPlayerList().v().iterator(); // Paper
|
||||
|
||||
// CraftBukkit start
|
||||
EntityHuman entityhuman = null;
|
||||
Entity entity = world.getEntity(i);
|
||||
if (entity instanceof EntityHuman) entityhuman = (EntityHuman) entity;
|
||||
// CraftBukkit end
|
||||
|
||||
// Paper start
|
||||
java.util.List<? extends EntityHuman> list = entity != null ? entity.world.players : this.a.getPlayerList().v();
|
||||
Iterator<? extends EntityHuman> iterator = list.iterator();
|
||||
PacketPlayOutBlockBreakAnimation packet = null; // NeonPaper - cache packet
|
||||
while (iterator.hasNext()) {
|
||||
EntityHuman human = iterator.next();
|
||||
if (!(human instanceof EntityPlayer)) continue;
|
||||
EntityPlayer entityplayer = (EntityPlayer) human;
|
||||
// Paper end
|
||||
|
||||
if (entityplayer != null && entityplayer.world == this.world && entityplayer.getId() != i) {
|
||||
double d0 = (double) blockposition.getX() - entityplayer.locX;
|
||||
double d1 = (double) blockposition.getY() - entityplayer.locY;
|
||||
double d2 = (double) blockposition.getZ() - entityplayer.locZ;
|
||||
|
||||
// CraftBukkit start
|
||||
if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) {
|
||||
continue;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
||||
// NeonPaper start
|
||||
if (packet == null) packet = new PacketPlayOutBlockBreakAnimation(i, blockposition, j);
|
||||
entityplayer.playerConnection.sendPacket(packet);
|
||||
// NeonPaper end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -424,33 +424,13 @@ public class WorldServer extends World implements IAsyncTaskHandler {
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
// Dionysus
|
||||
// Fixes MC-47080 and simplifies the logic
|
||||
public boolean everyoneDeeplySleeping() {
|
||||
if (this.Q && !this.isClientSide) {
|
||||
Iterator iterator = this.players.iterator();
|
||||
|
||||
// CraftBukkit - This allows us to assume that some people are in bed but not really, allowing time to pass in spite of AFKers
|
||||
boolean foundActualSleepers = false;
|
||||
|
||||
EntityHuman entityhuman;
|
||||
|
||||
do {
|
||||
if (!iterator.hasNext()) {
|
||||
return foundActualSleepers;
|
||||
}
|
||||
|
||||
entityhuman = (EntityHuman) iterator.next();
|
||||
|
||||
// CraftBukkit start
|
||||
if (entityhuman.isDeeplySleeping()) {
|
||||
foundActualSleepers = true;
|
||||
}
|
||||
} while (!entityhuman.isSpectator() || entityhuman.isDeeplySleeping() || entityhuman.fauxSleeping);
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.players.size() == 0 || this.isClientSide || !this.Q) {
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
return this.players.stream().allMatch(p -> p.isSpectator() || p.isDeeplySleeping() || p.fauxSleeping);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
317
sources/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
Normal file
317
sources/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
Normal file
@@ -0,0 +1,317 @@
|
||||
package org.bukkit.craftbukkit;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.Random;
|
||||
import net.minecraft.server.*;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
|
||||
public class CraftChunk implements Chunk {
|
||||
private WeakReference<net.minecraft.server.Chunk> weakChunk;
|
||||
private final WorldServer worldServer;
|
||||
private final int x;
|
||||
private final int z;
|
||||
private static final byte[] emptyData = new byte[2048];
|
||||
private static final short[] emptyBlockIDs = new short[4096];
|
||||
private static final byte[] emptySkyLight = new byte[2048];
|
||||
|
||||
public CraftChunk(net.minecraft.server.Chunk chunk) {
|
||||
this.weakChunk = new WeakReference<net.minecraft.server.Chunk>(chunk);
|
||||
|
||||
worldServer = (WorldServer) getHandle().world;
|
||||
x = getHandle().locX;
|
||||
z = getHandle().locZ;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return worldServer.getWorld();
|
||||
}
|
||||
|
||||
public CraftWorld getCraftWorld() {
|
||||
return (CraftWorld) getWorld();
|
||||
}
|
||||
|
||||
public net.minecraft.server.Chunk getHandle() {
|
||||
net.minecraft.server.Chunk c = weakChunk.get();
|
||||
|
||||
if (c == null) {
|
||||
c = worldServer.getChunkAt(x, z);
|
||||
|
||||
weakChunk = new WeakReference<net.minecraft.server.Chunk>(c);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void breakLink() {
|
||||
weakChunk.clear();
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftChunk{" + "x=" + getX() + "z=" + getZ() + '}';
|
||||
}
|
||||
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
return new CraftBlock(this, (getX() << 4) | (x & 0xF), y, (getZ() << 4) | (z & 0xF));
|
||||
}
|
||||
|
||||
public Entity[] getEntities() {
|
||||
int count = 0, index = 0;
|
||||
net.minecraft.server.Chunk chunk = getHandle();
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
count += chunk.entitySlices[i].size();
|
||||
}
|
||||
|
||||
Entity[] entities = new Entity[count];
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
|
||||
//for (Object obj : chunk.entitySlices[i].toArray()) {
|
||||
// if (!(obj instanceof net.minecraft.server.Entity)) {
|
||||
// NeonPaper start - speed up (was with chunk.entitySlices[i].toArray() and cast checks which costs a lot of performance if called often)
|
||||
for (net.minecraft.server.Entity entity : chunk.entitySlices[i]) {
|
||||
if (entity == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//entities[index++] = ((net.minecraft.server.Entity) obj).getBukkitEntity();
|
||||
entities[index++] = entity.getBukkitEntity();
|
||||
}
|
||||
//NeonPaper end
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
public BlockState[] getTileEntities() {
|
||||
int index = 0;
|
||||
net.minecraft.server.Chunk chunk = getHandle();
|
||||
|
||||
BlockState[] entities = new BlockState[chunk.tileEntities.size()];
|
||||
|
||||
for (Object obj : chunk.tileEntities.keySet().toArray()) {
|
||||
if (!(obj instanceof BlockPosition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockPosition position = (BlockPosition) obj;
|
||||
entities[index++] = worldServer.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()).getState();
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return getWorld().isChunkLoaded(this);
|
||||
}
|
||||
|
||||
public boolean load() {
|
||||
return getWorld().loadChunk(getX(), getZ(), true);
|
||||
}
|
||||
|
||||
public boolean load(boolean generate) {
|
||||
return getWorld().loadChunk(getX(), getZ(), generate);
|
||||
}
|
||||
|
||||
public boolean unload() {
|
||||
return getWorld().unloadChunk(getX(), getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSlimeChunk() {
|
||||
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
|
||||
return getHandle().a(worldServer.spigotConfig.slimeSeed).nextInt(10) == 0;
|
||||
}
|
||||
|
||||
public boolean unload(boolean save) {
|
||||
return getWorld().unloadChunk(getX(), getZ(), save);
|
||||
}
|
||||
|
||||
public boolean unload(boolean save, boolean safe) {
|
||||
return getWorld().unloadChunk(getX(), getZ(), save, safe);
|
||||
}
|
||||
|
||||
public ChunkSnapshot getChunkSnapshot() {
|
||||
return getChunkSnapshot(true, false, false);
|
||||
}
|
||||
|
||||
public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain) {
|
||||
net.minecraft.server.Chunk chunk = getHandle();
|
||||
|
||||
ChunkSection[] cs = chunk.getSections();
|
||||
short[][] sectionBlockIDs = new short[cs.length][];
|
||||
byte[][] sectionBlockData = new byte[cs.length][];
|
||||
byte[][] sectionSkyLights = new byte[cs.length][];
|
||||
byte[][] sectionEmitLights = new byte[cs.length][];
|
||||
boolean[] sectionEmpty = new boolean[cs.length];
|
||||
|
||||
for (int i = 0; i < cs.length; i++) {
|
||||
if (cs[i] == null) { // Section is empty?
|
||||
sectionBlockIDs[i] = emptyBlockIDs;
|
||||
sectionBlockData[i] = emptyData;
|
||||
sectionSkyLights[i] = emptySkyLight;
|
||||
sectionEmitLights[i] = emptyData;
|
||||
sectionEmpty[i] = true;
|
||||
} else { // Not empty
|
||||
short[] blockids = new short[4096];
|
||||
|
||||
byte[] rawIds = new byte[4096];
|
||||
NibbleArray data = new NibbleArray();
|
||||
cs[i].getBlocks().exportData(rawIds, data);
|
||||
|
||||
byte[] dataValues = sectionBlockData[i] = data.asBytes();
|
||||
|
||||
// Copy base IDs
|
||||
for (int j = 0; j < 4096; j++) {
|
||||
blockids[j] = (short) (rawIds[j] & 0xFF);
|
||||
}
|
||||
|
||||
sectionBlockIDs[i] = blockids;
|
||||
|
||||
if (cs[i].getSkyLightArray() == null) {
|
||||
sectionSkyLights[i] = emptyData;
|
||||
} else {
|
||||
sectionSkyLights[i] = new byte[2048];
|
||||
System.arraycopy(cs[i].getSkyLightArray().asBytes(), 0, sectionSkyLights[i], 0, 2048);
|
||||
}
|
||||
sectionEmitLights[i] = new byte[2048];
|
||||
System.arraycopy(cs[i].getEmittedLightArray().asBytes(), 0, sectionEmitLights[i], 0, 2048);
|
||||
}
|
||||
}
|
||||
|
||||
int[] hmap = null;
|
||||
|
||||
if (includeMaxBlockY) {
|
||||
hmap = new int[256]; // Get copy of height map
|
||||
System.arraycopy(chunk.heightMap, 0, hmap, 0, 256);
|
||||
}
|
||||
|
||||
BiomeBase[] biome = null;
|
||||
double[] biomeTemp = null;
|
||||
double[] biomeRain = null;
|
||||
|
||||
if (includeBiome || includeBiomeTempRain) {
|
||||
WorldChunkManager wcm = chunk.world.getWorldChunkManager();
|
||||
|
||||
if (includeBiome) {
|
||||
biome = new BiomeBase[256];
|
||||
for (int i = 0; i < 256; i++) {
|
||||
biome[i] = chunk.getBiome(new BlockPosition(i & 0xF, 0, i >> 4), wcm);
|
||||
}
|
||||
}
|
||||
|
||||
if (includeBiomeTempRain) {
|
||||
biomeTemp = new double[256];
|
||||
biomeRain = new double[256];
|
||||
float[] dat = getTemperatures(wcm, getX() << 4, getZ() << 4);
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
biomeTemp[i] = dat[i];
|
||||
}
|
||||
|
||||
/* Removed 15w46a
|
||||
dat = wcm.getWetness(null, getX() << 4, getZ() << 4, 16, 16);
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
biomeRain[i] = dat[i];
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
World world = getWorld();
|
||||
return new CraftChunkSnapshot(getX(), getZ(), world.getName(), world.getFullTime(), sectionBlockIDs, sectionBlockData, sectionSkyLights, sectionEmitLights, sectionEmpty, hmap, biome, biomeTemp, biomeRain);
|
||||
}
|
||||
|
||||
public static ChunkSnapshot getEmptyChunkSnapshot(int x, int z, CraftWorld world, boolean includeBiome, boolean includeBiomeTempRain) {
|
||||
BiomeBase[] biome = null;
|
||||
double[] biomeTemp = null;
|
||||
double[] biomeRain = null;
|
||||
|
||||
if (includeBiome || includeBiomeTempRain) {
|
||||
WorldChunkManager wcm = world.getHandle().getWorldChunkManager();
|
||||
|
||||
if (includeBiome) {
|
||||
biome = new BiomeBase[256];
|
||||
for (int i = 0; i < 256; i++) {
|
||||
biome[i] = world.getHandle().getBiome(new BlockPosition((x << 4) + (i & 0xF), 0, (z << 4) + (i >> 4)));
|
||||
}
|
||||
}
|
||||
|
||||
if (includeBiomeTempRain) {
|
||||
biomeTemp = new double[256];
|
||||
biomeRain = new double[256];
|
||||
float[] dat = getTemperatures(wcm, x << 4, z << 4);
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
biomeTemp[i] = dat[i];
|
||||
}
|
||||
|
||||
/* Removed 15w46a
|
||||
dat = wcm.getWetness(null, x << 4, z << 4, 16, 16);
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
biomeRain[i] = dat[i];
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill with empty data */
|
||||
int hSection = world.getMaxHeight() >> 4;
|
||||
short[][] blockIDs = new short[hSection][];
|
||||
byte[][] skyLight = new byte[hSection][];
|
||||
byte[][] emitLight = new byte[hSection][];
|
||||
byte[][] blockData = new byte[hSection][];
|
||||
boolean[] empty = new boolean[hSection];
|
||||
|
||||
for (int i = 0; i < hSection; i++) {
|
||||
blockIDs[i] = emptyBlockIDs;
|
||||
skyLight[i] = emptySkyLight;
|
||||
emitLight[i] = emptyData;
|
||||
blockData[i] = emptyData;
|
||||
empty[i] = true;
|
||||
}
|
||||
|
||||
return new CraftChunkSnapshot(x, z, world.getName(), world.getFullTime(), blockIDs, blockData, skyLight, emitLight, empty, new int[256], biome, biomeTemp, biomeRain);
|
||||
}
|
||||
|
||||
private static float[] getTemperatures(WorldChunkManager chunkmanager, int chunkX, int chunkZ) {
|
||||
BiomeBase[] biomes = chunkmanager.getBiomes(null, chunkX, chunkZ, 16, 16);
|
||||
float[] temps = new float[biomes.length];
|
||||
|
||||
for (int i = 0; i < biomes.length; i++) {
|
||||
float temp = biomes[i].getTemperature(); // Vanilla of olde: ((int) biomes[i].temperature * 65536.0F) / 65536.0F
|
||||
|
||||
if (temp > 1F) {
|
||||
temp = 1F;
|
||||
}
|
||||
|
||||
temps[i] = temp;
|
||||
}
|
||||
|
||||
return temps;
|
||||
}
|
||||
|
||||
static {
|
||||
Arrays.fill(emptySkyLight, (byte) 0xFF);
|
||||
}
|
||||
}
|
||||
@@ -1488,11 +1488,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public int getNoDamageTicks() {
|
||||
if (getHandle().invulnerableTicks > 0) {
|
||||
return Math.max(getHandle().invulnerableTicks, getHandle().noDamageTicks);
|
||||
} else {
|
||||
return getHandle().noDamageTicks;
|
||||
}
|
||||
// TacoSpigot start - fix incorrect calculation of getNoDamageTicks
|
||||
/*
|
||||
if (getHandle().invulnerableTicks > 0) {
|
||||
return Math.max(getHandle().invulnerableTicks, getHandle().noDamageTicks);
|
||||
} else {
|
||||
return getHandle().noDamageTicks;
|
||||
}
|
||||
*/
|
||||
return Math.max(getHandle().invulnerableTicks, Math.max(0, getHandle().noDamageTicks - (getHandle().maxNoDamageTicks >> 1)));
|
||||
// TacoSpigot end
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
405
sources/src/main/java/org/spigotmc/SpigotConfig.java
Normal file
405
sources/src/main/java/org/spigotmc/SpigotConfig.java
Normal file
@@ -0,0 +1,405 @@
|
||||
package org.spigotmc;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import gnu.trove.map.hash.TObjectIntHashMap;
|
||||
import net.minecraft.server.AttributeRanged;
|
||||
import net.minecraft.server.GenericAttributes;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.StatisticList;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.config.Configuration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class SpigotConfig
|
||||
{
|
||||
|
||||
private static File CONFIG_FILE;
|
||||
private static final String HEADER = "This is the main configuration file for Spigot.\n"
|
||||
+ "As you can see, there's tons to configure. Some options may impact gameplay, so use\n"
|
||||
+ "with caution, and make sure you know what each option does before configuring.\n"
|
||||
+ "For a reference for any variable inside this file, check out the Spigot wiki at\n"
|
||||
+ "http://www.spigotmc.org/wiki/spigot-configuration/\n"
|
||||
+ "\n"
|
||||
+ "If you need help with the configuration or have any questions related to Spigot,\n"
|
||||
+ "join us at the IRC or drop by our forums and leave a post.\n"
|
||||
+ "\n"
|
||||
+ "IRC: #spigot @ irc.spi.gt ( http://www.spigotmc.org/pages/irc/ )\n"
|
||||
+ "Forums: http://www.spigotmc.org/\n";
|
||||
/*========================================================================*/
|
||||
public static YamlConfiguration config;
|
||||
static int version;
|
||||
static Map<String, Command> commands;
|
||||
/*========================================================================*/
|
||||
private static Metrics metrics;
|
||||
|
||||
public static void init(File configFile)
|
||||
{
|
||||
CONFIG_FILE = configFile;
|
||||
config = new YamlConfiguration();
|
||||
try
|
||||
{
|
||||
config.load( CONFIG_FILE );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
} catch ( InvalidConfigurationException ex )
|
||||
{
|
||||
Bukkit.getLogger().log( Level.SEVERE, "Could not load spigot.yml, please correct your syntax errors", ex );
|
||||
throw Throwables.propagate( ex );
|
||||
}
|
||||
|
||||
config.options().header( HEADER );
|
||||
config.options().copyDefaults( true );
|
||||
|
||||
commands = new HashMap<String, Command>();
|
||||
commands.put( "spigot", new SpigotCommand( "spigot" ) );
|
||||
|
||||
version = getInt( "config-version", 11 );
|
||||
set( "config-version", 11 );
|
||||
readConfig( SpigotConfig.class, null );
|
||||
}
|
||||
|
||||
public static void registerCommands()
|
||||
{
|
||||
for ( Map.Entry<String, Command> entry : commands.entrySet() )
|
||||
{
|
||||
MinecraftServer.getServer().server.getCommandMap().register( entry.getKey(), "Spigot", entry.getValue() );
|
||||
}
|
||||
|
||||
/* // Paper - Replace with our own
|
||||
if ( metrics == null )
|
||||
{
|
||||
try
|
||||
{
|
||||
metrics = new Metrics();
|
||||
metrics.start();
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
Bukkit.getServer().getLogger().log( Level.SEVERE, "Could not start metrics service", ex );
|
||||
}
|
||||
}
|
||||
*/ // Paper end
|
||||
}
|
||||
|
||||
static void readConfig(Class<?> clazz, Object instance)
|
||||
{
|
||||
for ( Method method : clazz.getDeclaredMethods() )
|
||||
{
|
||||
if ( Modifier.isPrivate( method.getModifiers() ) )
|
||||
{
|
||||
if ( method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE )
|
||||
{
|
||||
try
|
||||
{
|
||||
method.setAccessible( true );
|
||||
method.invoke( instance );
|
||||
} catch ( InvocationTargetException ex )
|
||||
{
|
||||
throw Throwables.propagate( ex.getCause() );
|
||||
} catch ( Exception ex )
|
||||
{
|
||||
Bukkit.getLogger().log( Level.SEVERE, "Error invoking " + method, ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
config.save( CONFIG_FILE );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
Bukkit.getLogger().log( Level.SEVERE, "Could not save " + CONFIG_FILE, ex );
|
||||
}
|
||||
}
|
||||
|
||||
private static void set(String path, Object val)
|
||||
{
|
||||
config.set( path, val );
|
||||
}
|
||||
|
||||
private static boolean getBoolean(String path, boolean def)
|
||||
{
|
||||
config.addDefault( path, def );
|
||||
return config.getBoolean( path, config.getBoolean( path ) );
|
||||
}
|
||||
|
||||
private static int getInt(String path, int def)
|
||||
{
|
||||
config.addDefault( path, def );
|
||||
return config.getInt( path, config.getInt( path ) );
|
||||
}
|
||||
|
||||
private static <T> List getList(String path, T def)
|
||||
{
|
||||
config.addDefault( path, def );
|
||||
return (List<T>) config.getList( path, config.getList( path ) );
|
||||
}
|
||||
|
||||
private static String getString(String path, String def)
|
||||
{
|
||||
config.addDefault( path, def );
|
||||
return config.getString( path, config.getString( path ) );
|
||||
}
|
||||
|
||||
private static double getDouble(String path, double def)
|
||||
{
|
||||
config.addDefault( path, def );
|
||||
return config.getDouble( path, config.getDouble( path ) );
|
||||
}
|
||||
|
||||
public static boolean logCommands;
|
||||
private static void logCommands()
|
||||
{
|
||||
logCommands = getBoolean( "commands.log", true );
|
||||
}
|
||||
|
||||
public static int tabComplete;
|
||||
private static void tabComplete()
|
||||
{
|
||||
if ( version < 6 )
|
||||
{
|
||||
boolean oldValue = getBoolean( "commands.tab-complete", true );
|
||||
if ( oldValue )
|
||||
{
|
||||
set( "commands.tab-complete", 0 );
|
||||
} else
|
||||
{
|
||||
set( "commands.tab-complete", -1 );
|
||||
}
|
||||
}
|
||||
tabComplete = getInt( "commands.tab-complete", 0 );
|
||||
}
|
||||
|
||||
public static String whitelistMessage;
|
||||
public static String unknownCommandMessage;
|
||||
public static String serverFullMessage;
|
||||
public static String outdatedClientMessage = "Outdated client! Please use {0}";
|
||||
public static String outdatedServerMessage = "Outdated server! I\'m still on {0}";
|
||||
private static String transform(String s)
|
||||
{
|
||||
return ChatColor.translateAlternateColorCodes( '&', s ).replaceAll( "\\\\n", "\n" );
|
||||
}
|
||||
private static void messages()
|
||||
{
|
||||
if (version < 8)
|
||||
{
|
||||
set( "messages.outdated-client", outdatedClientMessage );
|
||||
set( "messages.outdated-server", outdatedServerMessage );
|
||||
}
|
||||
|
||||
whitelistMessage = transform( getString( "messages.whitelist", "You are not whitelisted on this server!" ) );
|
||||
unknownCommandMessage = transform( getString( "messages.unknown-command", "Unknown command. Type \"/help\" for help." ) );
|
||||
serverFullMessage = transform( getString( "messages.server-full", "The server is full!" ) );
|
||||
outdatedClientMessage = transform( getString( "messages.outdated-client", outdatedClientMessage ) );
|
||||
outdatedServerMessage = transform( getString( "messages.outdated-server", outdatedServerMessage ) );
|
||||
}
|
||||
|
||||
public static int timeoutTime = 60;
|
||||
public static boolean restartOnCrash = true;
|
||||
public static String restartScript = "./start.sh";
|
||||
public static String restartMessage;
|
||||
private static void watchdog()
|
||||
{
|
||||
timeoutTime = getInt( "settings.timeout-time", timeoutTime );
|
||||
restartOnCrash = getBoolean( "settings.restart-on-crash", restartOnCrash );
|
||||
restartScript = getString( "settings.restart-script", restartScript );
|
||||
restartMessage = transform( getString( "messages.restart", "Server is restarting" ) );
|
||||
commands.put( "restart", new RestartCommand( "restart" ) );
|
||||
//WatchdogThread.doStart( timeoutTime, restartOnCrash ); // Paper - moved to PaperConfig
|
||||
}
|
||||
|
||||
public static boolean bungee;
|
||||
private static void bungee() {
|
||||
if ( version < 4 )
|
||||
{
|
||||
set( "settings.bungeecord", false );
|
||||
System.out.println( "Oudated config, disabling BungeeCord support!" );
|
||||
}
|
||||
bungee = getBoolean( "settings.bungeecord", false );
|
||||
}
|
||||
|
||||
private static void nettyThreads()
|
||||
{
|
||||
int count = getInt( "settings.netty-threads", 4 );
|
||||
System.setProperty( "io.netty.eventLoopThreads", Integer.toString( count ) );
|
||||
Bukkit.getLogger().log( Level.INFO, "Using {0} threads for Netty based IO", count );
|
||||
}
|
||||
|
||||
public static boolean lateBind;
|
||||
private static void lateBind() {
|
||||
lateBind = getBoolean( "settings.late-bind", false );
|
||||
}
|
||||
|
||||
public static boolean disableStatSaving;
|
||||
public static Object2IntOpenHashMap<String> forcedStats = new Object2IntOpenHashMap<String>();
|
||||
private static void stats()
|
||||
{
|
||||
disableStatSaving = getBoolean( "stats.disable-saving", false );
|
||||
|
||||
if ( !config.contains( "stats.forced-stats" ) ) {
|
||||
config.createSection( "stats.forced-stats" );
|
||||
}
|
||||
|
||||
ConfigurationSection section = config.getConfigurationSection( "stats.forced-stats" );
|
||||
for ( String name : section.getKeys( true ) )
|
||||
{
|
||||
if ( section.isInt( name ) )
|
||||
{
|
||||
if ( StatisticList.getStatistic(name) == null )
|
||||
{
|
||||
Bukkit.getLogger().log(Level.WARNING, "Ignoring non existent stats.forced-stats " + name);
|
||||
continue;
|
||||
}
|
||||
forcedStats.put( name, section.getInt( name ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void tpsCommand()
|
||||
{
|
||||
commands.put( "tps", new TicksPerSecondCommand( "tps" ) );
|
||||
}
|
||||
|
||||
public static int playerSample;
|
||||
private static void playerSample()
|
||||
{
|
||||
playerSample = Math.max(getInt( "settings.sample-count", 12 ), 0); // Paper - Avoid negative counts
|
||||
Bukkit.getLogger().log( Level.INFO, "Server Ping Player Sample Count: {0}", playerSample ); // Paper - Use logger
|
||||
}
|
||||
|
||||
public static int playerShuffle;
|
||||
private static void playerShuffle()
|
||||
{
|
||||
playerShuffle = getInt( "settings.player-shuffle", 0 );
|
||||
}
|
||||
|
||||
public static List<String> spamExclusions;
|
||||
private static void spamExclusions()
|
||||
{
|
||||
spamExclusions = getList( "commands.spam-exclusions", Arrays.asList( new String[]
|
||||
{
|
||||
"/skill"
|
||||
} ) );
|
||||
}
|
||||
|
||||
public static boolean silentCommandBlocks;
|
||||
private static void silentCommandBlocks()
|
||||
{
|
||||
silentCommandBlocks = getBoolean( "commands.silent-commandblock-console", false );
|
||||
}
|
||||
|
||||
public static boolean filterCreativeItems;
|
||||
private static void filterCreativeItems()
|
||||
{
|
||||
filterCreativeItems = getBoolean( "settings.filter-creative-items", true );
|
||||
}
|
||||
|
||||
public static Set<String> replaceCommands;
|
||||
private static void replaceCommands()
|
||||
{
|
||||
if ( config.contains( "replace-commands" ) )
|
||||
{
|
||||
set( "commands.replace-commands", config.getStringList( "replace-commands" ) );
|
||||
config.set( "replace-commands", null );
|
||||
}
|
||||
replaceCommands = new HashSet<String>( (List<String>) getList( "commands.replace-commands",
|
||||
Arrays.asList( "setblock", "summon", "testforblock", "tellraw" ) ) );
|
||||
}
|
||||
|
||||
public static int userCacheCap;
|
||||
private static void userCacheCap()
|
||||
{
|
||||
userCacheCap = getInt( "settings.user-cache-size", 1000 );
|
||||
}
|
||||
|
||||
public static boolean saveUserCacheOnStopOnly;
|
||||
private static void saveUserCacheOnStopOnly()
|
||||
{
|
||||
saveUserCacheOnStopOnly = getBoolean( "settings.save-user-cache-on-stop-only", false );
|
||||
}
|
||||
|
||||
public static int intCacheLimit;
|
||||
private static void intCacheLimit()
|
||||
{
|
||||
intCacheLimit = getInt( "settings.int-cache-limit", 1024 );
|
||||
}
|
||||
|
||||
public static double movedWronglyThreshold;
|
||||
private static void movedWronglyThreshold()
|
||||
{
|
||||
movedWronglyThreshold = getDouble( "settings.moved-wrongly-threshold", 0.0625D );
|
||||
}
|
||||
|
||||
public static double movedTooQuicklyMultiplier;
|
||||
private static void movedTooQuicklyMultiplier()
|
||||
{
|
||||
movedTooQuicklyMultiplier = getDouble( "settings.moved-too-quickly-multiplier", 10.0D );
|
||||
}
|
||||
|
||||
public static double maxHealth = 2048;
|
||||
public static double movementSpeed = 2048;
|
||||
public static double attackDamage = 2048;
|
||||
private static void attributeMaxes()
|
||||
{
|
||||
maxHealth = getDouble( "settings.attribute.maxHealth.max", maxHealth );
|
||||
( (AttributeRanged) GenericAttributes.maxHealth ).b = maxHealth;
|
||||
movementSpeed = getDouble( "settings.attribute.movementSpeed.max", movementSpeed );
|
||||
( (AttributeRanged) GenericAttributes.MOVEMENT_SPEED ).b = movementSpeed;
|
||||
attackDamage = getDouble( "settings.attribute.attackDamage.max", attackDamage );
|
||||
( (AttributeRanged) GenericAttributes.ATTACK_DAMAGE ).b = attackDamage;
|
||||
}
|
||||
|
||||
public static boolean debug;
|
||||
private static void debug()
|
||||
{
|
||||
debug = getBoolean( "settings.debug", false );
|
||||
|
||||
if ( debug && !LogManager.getRootLogger().isTraceEnabled() )
|
||||
{
|
||||
// Enable debug logging
|
||||
LoggerContext ctx = (LoggerContext) LogManager.getContext( false );
|
||||
Configuration conf = ctx.getConfiguration();
|
||||
conf.getLoggerConfig( LogManager.ROOT_LOGGER_NAME ).setLevel( org.apache.logging.log4j.Level.ALL );
|
||||
ctx.updateLoggers( conf );
|
||||
}
|
||||
|
||||
if ( LogManager.getRootLogger().isTraceEnabled() )
|
||||
{
|
||||
Bukkit.getLogger().info( "Debug logging is enabled" );
|
||||
} else
|
||||
{
|
||||
Bukkit.getLogger().info( "Debug logging is disabled" );
|
||||
}
|
||||
}
|
||||
|
||||
public static int itemDirtyTicks;
|
||||
private static void itemDirtyTicks() {
|
||||
itemDirtyTicks = getInt("settings.item-dirty-ticks", 20);
|
||||
}
|
||||
|
||||
public static boolean disableAdvancementSaving;
|
||||
public static List<String> disabledAdvancements;
|
||||
private static void disabledAdvancements() {
|
||||
disableAdvancementSaving = getBoolean("advancements.disable-saving", false);
|
||||
disabledAdvancements = getList("advancements.disabled", Arrays.asList(new String[]{"minecraft:story/disabled"}));
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
"core.MixinCommandBanIp",
|
||||
"core.MixinChunkSection",
|
||||
"core.MixinAsyncCatcher",
|
||||
"core.MixinTimingHandler",
|
||||
"core.MixinVersionCommand",
|
||||
"core.MixinMinecraftServer",
|
||||
"core.MixinChunkIOExecutor",
|
||||
@@ -41,4 +40,4 @@
|
||||
"optimization.MixinPersistentCollection",
|
||||
"optimization.MixinTileEntityEnchantTable"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Submodule work/Paper updated: 2916428449...e39995d213
Reference in New Issue
Block a user