Compare commits
307 Commits
parallel-w
...
1.12.2-R0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
679236cfb9 | ||
|
|
5fe93610c9 | ||
|
|
f73c20e342 | ||
|
|
8e6000c523 | ||
|
|
2f87a4c54e | ||
|
|
751fcb584d |
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.
|
||||
|
||||
|
||||
62
removed/com/destroystokyo/paper/antixray/DataBitsReader.java
Normal file
62
removed/com/destroystokyo/paper/antixray/DataBitsReader.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.destroystokyo.paper.antixray;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class DataBitsReader {
|
||||
|
||||
private ByteBuf dataBits; // Akarin
|
||||
private int bitsPerValue;
|
||||
private int mask;
|
||||
private int longInDataBitsIndex;
|
||||
private int bitInLongIndex;
|
||||
private long current;
|
||||
|
||||
public void setDataBits(ByteBuf dataBits) { // Akarin
|
||||
this.dataBits = dataBits;
|
||||
}
|
||||
|
||||
public void setBitsPerValue(int bitsPerValue) {
|
||||
this.bitsPerValue = bitsPerValue;
|
||||
mask = (1 << bitsPerValue) - 1;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.longInDataBitsIndex = index;
|
||||
bitInLongIndex = 0;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (dataBits.capacity() > longInDataBitsIndex + 7) { // Akarin
|
||||
// Akarin start
|
||||
dataBits.getLong(longInDataBitsIndex);
|
||||
/*
|
||||
current = ((((long) dataBits[longInDataBitsIndex]) << 56)
|
||||
| (((long) dataBits[longInDataBitsIndex + 1] & 0xff) << 48)
|
||||
| (((long) dataBits[longInDataBitsIndex + 2] & 0xff) << 40)
|
||||
| (((long) dataBits[longInDataBitsIndex + 3] & 0xff) << 32)
|
||||
| (((long) dataBits[longInDataBitsIndex + 4] & 0xff) << 24)
|
||||
| (((long) dataBits[longInDataBitsIndex + 5] & 0xff) << 16)
|
||||
| (((long) dataBits[longInDataBitsIndex + 6] & 0xff) << 8)
|
||||
| (((long) dataBits[longInDataBitsIndex + 7] & 0xff)));
|
||||
*/ // Akarin end
|
||||
}
|
||||
}
|
||||
|
||||
public int read() {
|
||||
int value = (int) (current >>> bitInLongIndex) & mask;
|
||||
bitInLongIndex += bitsPerValue;
|
||||
|
||||
if (bitInLongIndex > 63) {
|
||||
bitInLongIndex -= 64;
|
||||
longInDataBitsIndex += 8;
|
||||
init();
|
||||
|
||||
if (bitInLongIndex > 0) {
|
||||
value |= current << bitsPerValue - bitInLongIndex & mask;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
94
removed/com/destroystokyo/paper/antixray/DataBitsWriter.java
Normal file
94
removed/com/destroystokyo/paper/antixray/DataBitsWriter.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.destroystokyo.paper.antixray;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class DataBitsWriter {
|
||||
|
||||
private ByteBuf dataBits; // Akarin
|
||||
private int bitsPerValue;
|
||||
private long mask;
|
||||
private int longInDataBitsIndex;
|
||||
private int bitInLongIndex;
|
||||
private long current;
|
||||
private boolean dirty;
|
||||
|
||||
public void setDataBits(ByteBuf dataBits) { // Akarin
|
||||
this.dataBits = dataBits;
|
||||
}
|
||||
|
||||
public void setBitsPerValue(int bitsPerValue) {
|
||||
this.bitsPerValue = bitsPerValue;
|
||||
mask = (1 << bitsPerValue) - 1;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.longInDataBitsIndex = index;
|
||||
bitInLongIndex = 0;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (dataBits.capacity() > longInDataBitsIndex + 7) { // Akarin
|
||||
// Akarin start
|
||||
current = dataBits.getLong(longInDataBitsIndex);
|
||||
/*
|
||||
current = ((((long) dataBits[longInDataBitsIndex]) << 56)
|
||||
| (((long) dataBits[longInDataBitsIndex + 1] & 0xff) << 48)
|
||||
| (((long) dataBits[longInDataBitsIndex + 2] & 0xff) << 40)
|
||||
| (((long) dataBits[longInDataBitsIndex + 3] & 0xff) << 32)
|
||||
| (((long) dataBits[longInDataBitsIndex + 4] & 0xff) << 24)
|
||||
| (((long) dataBits[longInDataBitsIndex + 5] & 0xff) << 16)
|
||||
| (((long) dataBits[longInDataBitsIndex + 6] & 0xff) << 8)
|
||||
| (((long) dataBits[longInDataBitsIndex + 7] & 0xff)));
|
||||
*/ // Akarin end
|
||||
}
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
if (dirty && dataBits.capacity() > longInDataBitsIndex + 7) { // Akarin
|
||||
// Akarin start
|
||||
dataBits.setLong(longInDataBitsIndex, current);
|
||||
/*
|
||||
dataBits[longInDataBitsIndex] = (byte) (current >> 56 & 0xff);
|
||||
dataBits[longInDataBitsIndex + 1] = (byte) (current >> 48 & 0xff);
|
||||
dataBits[longInDataBitsIndex + 2] = (byte) (current >> 40 & 0xff);
|
||||
dataBits[longInDataBitsIndex + 3] = (byte) (current >> 32 & 0xff);
|
||||
dataBits[longInDataBitsIndex + 4] = (byte) (current >> 24 & 0xff);
|
||||
dataBits[longInDataBitsIndex + 5] = (byte) (current >> 16 & 0xff);
|
||||
dataBits[longInDataBitsIndex + 6] = (byte) (current >> 8 & 0xff);
|
||||
dataBits[longInDataBitsIndex + 7] = (byte) (current & 0xff);
|
||||
*/ // Akarin end
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int value) {
|
||||
current = current & ~(mask << bitInLongIndex) | (value & mask) << bitInLongIndex;
|
||||
dirty = true;
|
||||
bitInLongIndex += bitsPerValue;
|
||||
|
||||
if (bitInLongIndex > 63) {
|
||||
finish();
|
||||
bitInLongIndex -= 64;
|
||||
longInDataBitsIndex += 8;
|
||||
init();
|
||||
|
||||
if (bitInLongIndex > 0) {
|
||||
current = current & ~(mask >>> bitsPerValue - bitInLongIndex) | (value & mask) >>> bitsPerValue - bitInLongIndex;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void skip() {
|
||||
bitInLongIndex += bitsPerValue;
|
||||
|
||||
if (bitInLongIndex > 63) {
|
||||
finish();
|
||||
bitInLongIndex -= 64;
|
||||
longInDataBitsIndex += 8;
|
||||
init();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class PacketPlayOutMapChunkInfo {
|
||||
private final PacketPlayOutMapChunk packetPlayOutMapChunk;
|
||||
private final Chunk chunk;
|
||||
private final int chunkSectionSelector;
|
||||
private ByteBuf data; // Akarin - byte[] -> ByteBuf
|
||||
private ByteBuf data; // Akarin
|
||||
private final int[] bitsPerValue = new int[16];
|
||||
private final DataPalette[] dataPalettes = new DataPalette[16];
|
||||
private final int[] dataBitsIndexes = new int[16];
|
||||
@@ -39,11 +39,11 @@ public class PacketPlayOutMapChunkInfo {
|
||||
return chunkSectionSelector;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data.array(); // Akarin
|
||||
public ByteBuf getData() { // Akarin
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(ByteBuf data) { // Akarin - byte[] -> ByteBuf
|
||||
public void setData(ByteBuf data) { // Akarin
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
||||
packetdataserializer.writeInt(this.b);
|
||||
packetdataserializer.writeBoolean(this.f);
|
||||
packetdataserializer.d(this.c);
|
||||
packetdataserializer.d(this.d.array().length); // Akarin
|
||||
packetdataserializer.d(this.d.capacity()); // Akarin
|
||||
packetdataserializer.writeBytes(this.d.array()); // Akarin
|
||||
packetdataserializer.d(this.e.size());
|
||||
Iterator iterator = this.e.iterator();
|
||||
@@ -122,9 +122,9 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
||||
packetlistenerplayout.a(this);
|
||||
}
|
||||
|
||||
private ByteBuf allocateBuffer(int expectedCapacity) { return g(expectedCapacity); } // Akarin - OBFHELPER
|
||||
private ByteBuf g(int expectedCapacity) { // Akarin - added argument
|
||||
ByteBuf bytebuf = Unpooled.buffer(expectedCapacity); // Akarin
|
||||
private ByteBuf g() { return allocateBuffer(-1); } // Akarin
|
||||
private ByteBuf allocateBuffer(int expectedCapacity) { // Akarin - added argument
|
||||
ByteBuf bytebuf = expectedCapacity == -1 ? Unpooled.buffer() : Unpooled.buffer(expectedCapacity); // Akarin
|
||||
|
||||
bytebuf.writerIndex(0);
|
||||
return bytebuf;
|
||||
@@ -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
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
104
sources/pom.xml
104
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>
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -160,6 +160,11 @@ public class AkarinGlobalConfig {
|
||||
playersPerIOThread = getInt("core.players-per-chunk-io-thread", 50);
|
||||
}
|
||||
|
||||
public static boolean silentAsyncTimings;
|
||||
private static void silentAsyncTimings() {
|
||||
silentAsyncTimings = getBoolean("core.always-silent-async-timing", false);
|
||||
}
|
||||
|
||||
public static long timeUpdateInterval;
|
||||
private static void timeUpdateInterval() {
|
||||
timeUpdateInterval = getSeconds(getString("core.tick-rate.world-time-update-interval", "1s")) * 10;
|
||||
|
||||
@@ -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,63 +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 co.aikar.timings.Timing;
|
||||
import io.akarin.api.internal.Akari;
|
||||
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
|
||||
public Timing startTimingIfSync() {
|
||||
startTiming();
|
||||
return (Timing) this;
|
||||
}
|
||||
|
||||
@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 || --timingDepth != 0 || start == 0) return;
|
||||
if (!alreadySync) {
|
||||
Thread curThread = Thread.currentThread();
|
||||
if (curThread != MinecraftServer.getServer().primaryThread) {
|
||||
start = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Safety ensured
|
||||
addDiff(System.nanoTime() - start);
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
1551
sources/src/main/java/net/minecraft/server/Chunk.java
Normal file
1551
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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import co.aikar.timings.MinecraftTimings; // Paper
|
||||
import co.aikar.timings.Timing; // Paper
|
||||
import io.akarin.api.internal.Akari;
|
||||
import io.akarin.api.internal.mixin.IMixinWorldServer;
|
||||
|
||||
import org.bukkit.event.entity.EntityCombustByEntityEvent;
|
||||
@@ -65,7 +66,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
}
|
||||
}
|
||||
};
|
||||
Object entitySlice = null;
|
||||
List<Entity> entitySlice = null;
|
||||
// Paper end
|
||||
static boolean isLevelAtLeast(NBTTagCompound tag, int level) {
|
||||
return tag.hasKey("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
|
||||
@@ -210,7 +211,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
this.length = 1.8F;
|
||||
this.ax = 1;
|
||||
this.ay = 1.0F;
|
||||
this.random = ((IMixinWorldServer) world).rand(); // Paper // Akarin
|
||||
this.random = world == null ? SHARED_RANDOM : ((IMixinWorldServer) world).rand(); // Paper // Akarin
|
||||
this.fireTicks = -this.getMaxFireTicks();
|
||||
this.justCreated = true;
|
||||
this.uniqueID = MathHelper.a(this.random);
|
||||
@@ -1477,6 +1478,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
return false;
|
||||
}
|
||||
|
||||
public void runKillTrigger(Entity entity, int kills, DamageSource damageSource) { this.a(entity, kills, damageSource); } // Paper - OBFHELPER
|
||||
public void a(Entity entity, int i, DamageSource damagesource) {
|
||||
if (entity instanceof EntityPlayer) {
|
||||
CriterionTriggers.c.a((EntityPlayer) entity, this, damagesource);
|
||||
@@ -2273,6 +2275,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
|
||||
}
|
||||
|
||||
public void onKill(EntityLiving entityLiving) { this.b(entityLiving); } // Paper - OBFHELPER
|
||||
public void b(EntityLiving entityliving) {}
|
||||
|
||||
protected boolean i(double d0, double d1, double d2) {
|
||||
@@ -2971,6 +2974,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
return EnumPistonReaction.NORMAL;
|
||||
}
|
||||
|
||||
public SoundCategory getDeathSoundCategory() { return bK();} // Paper - OBFHELPER
|
||||
public SoundCategory bK() {
|
||||
return SoundCategory.NEUTRAL;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
}
|
||||
// Paper end
|
||||
private int containerUpdateDelay; // Paper
|
||||
// Paper start - cancellable death event
|
||||
public boolean queueHealthUpdatePacket = false;
|
||||
public net.minecraft.server.PacketPlayOutUpdateHealth queuedHealthUpdatePacket;
|
||||
// Paper end
|
||||
|
||||
// CraftBukkit start
|
||||
public String displayName;
|
||||
@@ -441,9 +445,10 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
public void die(DamageSource damagesource) {
|
||||
boolean flag = this.world.getGameRules().getBoolean("showDeathMessages");
|
||||
|
||||
this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.ENTITY_DIED, flag));
|
||||
//this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.ENTITY_DIED, flag)); // Paper - moved down for cancellable death event
|
||||
// CraftBukkit start - fire PlayerDeathEvent
|
||||
if (this.dead) {
|
||||
this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.ENTITY_DIED, flag)); // Paper - moved down for cancellable death event
|
||||
return;
|
||||
}
|
||||
java.util.List<org.bukkit.inventory.ItemStack> loot = new java.util.ArrayList<org.bukkit.inventory.ItemStack>(this.inventory.getSize());
|
||||
@@ -461,6 +466,16 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
|
||||
String deathmessage = chatmessage.toPlainText();
|
||||
org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory);
|
||||
// Paper start - cancellable death event
|
||||
if (event.isCancelled()) {
|
||||
// make compatible with plugins that might have already set the health in an event listener
|
||||
if (this.getHealth() <= 0) {
|
||||
this.setHealth((float) event.getReviveHealth());
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.playerConnection.sendPacket(new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.ENTITY_DIED, flag));
|
||||
// Paper end
|
||||
|
||||
String deathMessage = event.getDeathMessage();
|
||||
|
||||
@@ -614,7 +629,17 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
}
|
||||
}
|
||||
|
||||
return super.damageEntity(damagesource, f);
|
||||
// Paper start - cancellable death events
|
||||
//return super.damageEntity(damagesource, f);
|
||||
this.queueHealthUpdatePacket = true;
|
||||
boolean damaged = super.damageEntity(damagesource, f);
|
||||
this.queueHealthUpdatePacket = false;
|
||||
if (this.queuedHealthUpdatePacket != null) {
|
||||
this.playerConnection.sendPacket(this.queuedHealthUpdatePacket);
|
||||
this.queuedHealthUpdatePacket = null;
|
||||
}
|
||||
return damaged;
|
||||
// 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) {}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.primitives.Doubles;
|
||||
import com.google.common.primitives.Floats;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
import io.akarin.api.internal.Akari;
|
||||
import io.akarin.server.core.AkarinGlobalConfig;
|
||||
@@ -10,6 +12,8 @@ import io.netty.util.concurrent.GenericFutureListener;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -382,10 +386,13 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
}
|
||||
|
||||
entity.setLocation(d3, d4, d5, f, f1);
|
||||
Location curPos = getPlayer().getLocation(); // Paper
|
||||
player.setLocation(d3, d4, d5, f, f1); // Paper
|
||||
boolean flag2 = worldserver.getCubes(entity, entity.getBoundingBox().shrink(0.0625D)).isEmpty();
|
||||
|
||||
if (flag && (flag1 || !flag2)) {
|
||||
entity.setLocation(d0, d1, d2, f, f1);
|
||||
player.setLocation(d0, d1, d2, f, f1); // Paper
|
||||
this.networkManager.sendPacket(new PacketPlayOutVehicleMove(entity));
|
||||
return;
|
||||
}
|
||||
@@ -395,7 +402,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
// Spigot Start
|
||||
if ( !hasMoved )
|
||||
{
|
||||
Location curPos = player.getLocation();
|
||||
//Location curPos = player.getLocation(); // Paper - move up
|
||||
lastPosX = curPos.getX();
|
||||
lastPosY = curPos.getY();
|
||||
lastPosZ = curPos.getZ();
|
||||
@@ -2310,32 +2317,26 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
buffer, isCommand, blockpos != null ? MCUtil.toLocation(player.world, blockpos) : null);
|
||||
event.callEvent();
|
||||
completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
|
||||
if (event.isCancelled() || event.isHandled()) {
|
||||
// Still fire sync event with the provided completions, if someone is listening
|
||||
if (!event.isCancelled() && org.bukkit.event.server.TabCompleteEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
java.util.List<String> finalCompletions = completions;
|
||||
Waitable<java.util.List<String>> syncCompletions = new Waitable<java.util.List<String>>() {
|
||||
@Override
|
||||
protected java.util.List<String> evaluate() {
|
||||
org.bukkit.event.server.TabCompleteEvent syncEvent = new org.bukkit.event.server.TabCompleteEvent(PlayerConnection.this.getPlayer(), buffer, finalCompletions, isCommand, blockpos != null ? MCUtil.toLocation(player.world, blockpos) : null);
|
||||
return syncEvent.callEvent() ? syncEvent.getCompletions() : com.google.common.collect.ImmutableList.of();
|
||||
}
|
||||
};
|
||||
server.getServer().processQueue.add(syncCompletions);
|
||||
try {
|
||||
completions = syncCompletions.get();
|
||||
} catch (InterruptedException | ExecutionException e1) {
|
||||
e1.printStackTrace();
|
||||
if (!event.isHandled()) {
|
||||
// If the event isn't handled, we can assume that we have no completions, and so we'll ask the server
|
||||
|
||||
Waitable<java.util.List<String>> syncCompletions = new Waitable<java.util.List<String>>() {
|
||||
@Override
|
||||
protected java.util.List<String> evaluate() {
|
||||
return minecraftServer.tabCompleteCommand(player, buffer, blockpos, isCommand);
|
||||
}
|
||||
};
|
||||
server.getServer().processQueue.add(syncCompletions);
|
||||
try {
|
||||
completions = syncCompletions.get();
|
||||
} catch (InterruptedException | ExecutionException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutTabComplete(completions.toArray(new String[completions.size()])));
|
||||
return;
|
||||
} else if (!event.isCancelled()) {
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutTabComplete(completions.toArray(new String[completions.size()])));
|
||||
}
|
||||
minecraftServer.postToMainThread(() -> {
|
||||
java.util.List<String> syncCompletions = this.minecraftServer.tabCompleteCommand(this.player, buffer, blockpos, isCommand);
|
||||
this.player.playerConnection.sendPacket(new PacketPlayOutTabComplete(syncCompletions.toArray(new String[syncCompletions.size()])));
|
||||
});
|
||||
// Paper end
|
||||
}
|
||||
|
||||
@@ -2377,7 +2378,6 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
}
|
||||
|
||||
if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack.getItem() == itemstack1.getItem()) {
|
||||
itemstack1 = new ItemStack(Items.WRITABLE_BOOK); // CraftBukkit
|
||||
itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8));
|
||||
CraftEventFactory.handleEditBookEvent(player, itemstack1); // CraftBukkit
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.destroystokyo.paper.exception.ServerInternalException;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import com.destroystokyo.paper.PaperConfig; // Paper
|
||||
import java.util.LinkedHashMap; // Paper
|
||||
|
||||
/**
|
||||
* Akarin Changes Note
|
||||
* 1) Removes unneed synchronization (performance)
|
||||
*/
|
||||
public class RegionFileCache {
|
||||
|
||||
public static final Map<File, RegionFile> a = new LinkedHashMap(PaperConfig.regionFileCacheSize, 0.75f, true); // Spigot - private -> public, Paper - HashMap -> LinkedHashMap
|
||||
|
||||
public static synchronized RegionFile a(File file, int i, int j) {
|
||||
File file1 = new File(file, "region");
|
||||
File file2 = new File(file1, "r." + (i >> 5) + "." + (j >> 5) + ".mca");
|
||||
RegionFile regionfile = (RegionFile) RegionFileCache.a.get(file2);
|
||||
|
||||
if (regionfile != null) {
|
||||
return regionfile;
|
||||
} else {
|
||||
if (!file1.exists()) {
|
||||
file1.mkdirs();
|
||||
}
|
||||
|
||||
if (RegionFileCache.a.size() >= PaperConfig.regionFileCacheSize) { // Paper
|
||||
trimCache(); // Paper
|
||||
}
|
||||
|
||||
RegionFile regionfile1 = new RegionFile(file2);
|
||||
|
||||
RegionFileCache.a.put(file2, regionfile1);
|
||||
return regionfile1;
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized RegionFile b(File file, int i, int j) {
|
||||
File file1 = new File(file, "region");
|
||||
File file2 = new File(file1, "r." + (i >> 5) + "." + (j >> 5) + ".mca");
|
||||
RegionFile regionfile = (RegionFile) RegionFileCache.a.get(file2);
|
||||
|
||||
if (regionfile != null) {
|
||||
return regionfile;
|
||||
} else if (file1.exists() && file2.exists()) {
|
||||
if (RegionFileCache.a.size() >= 256) {
|
||||
a();
|
||||
}
|
||||
|
||||
RegionFile regionfile1 = new RegionFile(file2);
|
||||
|
||||
RegionFileCache.a.put(file2, regionfile1);
|
||||
return regionfile1;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Paper Start
|
||||
private static synchronized void trimCache() {
|
||||
Iterator<Map.Entry<File, RegionFile>> itr = RegionFileCache.a.entrySet().iterator();
|
||||
int count = RegionFileCache.a.size() - PaperConfig.regionFileCacheSize;
|
||||
while (count-- >= 0 && itr.hasNext()) {
|
||||
try {
|
||||
itr.next().getValue().c();
|
||||
} catch (IOException ioexception) {
|
||||
ioexception.printStackTrace();
|
||||
ServerInternalException.reportInternalException(ioexception);
|
||||
}
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
// Paper End
|
||||
|
||||
public static synchronized void a() {
|
||||
Iterator iterator = RegionFileCache.a.values().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
RegionFile regionfile = (RegionFile) iterator.next();
|
||||
|
||||
try {
|
||||
if (regionfile != null) {
|
||||
regionfile.c();
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
ioexception.printStackTrace();
|
||||
ServerInternalException.reportInternalException(ioexception); // Paper
|
||||
}
|
||||
}
|
||||
|
||||
RegionFileCache.a.clear();
|
||||
}
|
||||
|
||||
// CraftBukkit start - call sites hoisted for synchronization
|
||||
public static /*synchronized*/ NBTTagCompound d(File file, int i, int j) throws IOException { // Akarin - 1.13 backport - remove synchronization // OBFHELPER: read
|
||||
RegionFile regionfile = a(file, i, j);
|
||||
|
||||
DataInputStream datainputstream = regionfile.a(i & 31, j & 31);
|
||||
|
||||
if (datainputstream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return NBTCompressedStreamTools.a(datainputstream);
|
||||
}
|
||||
|
||||
public static /*synchronized*/ void e(File file, int i, int j, NBTTagCompound nbttagcompound) throws IOException { // Akarin - 1.13 backport - remove synchronization // OBFHELPER: write
|
||||
RegionFile regionfile = a(file, i, j);
|
||||
|
||||
DataOutputStream dataoutputstream = regionfile.b(i & 31, j & 31);
|
||||
NBTCompressedStreamTools.a(nbttagcompound, (java.io.DataOutput) dataoutputstream);
|
||||
dataoutputstream.close();
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
public static /*synchronized*/ boolean chunkExists(File file, int i, int j) { // Akarin - 1.13 backport - remove synchronization
|
||||
RegionFile regionfile = b(file, i, j);
|
||||
|
||||
return regionfile != null ? regionfile.c(i & 31, j & 31) : false;
|
||||
}
|
||||
}
|
||||
@@ -593,7 +593,7 @@ public abstract class World implements IBlockAccess {
|
||||
// CraftBukkit start
|
||||
CraftWorld world = ((WorldServer) this).getWorld();
|
||||
if (world != null && !((WorldServer)this).stopPhysicsEvent) { // Paper
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftMagicNumbers.getId(block));
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftMagicNumbers.getId(block), blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()); // Paper - add source block
|
||||
this.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
@@ -1184,7 +1184,7 @@ public abstract class World implements IBlockAccess {
|
||||
|
||||
int i = MathHelper.floor(entity.locX / 16.0D);
|
||||
int j = MathHelper.floor(entity.locZ / 16.0D);
|
||||
boolean flag = entity.attachedToPlayer;
|
||||
boolean flag = true; // Paper - always load chunks
|
||||
|
||||
// Paper start - Set origin location when the entity is being added to the world
|
||||
if (entity.origin == null) {
|
||||
@@ -1831,7 +1831,7 @@ public abstract class World implements IBlockAccess {
|
||||
this.getChunkAt(entity.ab, entity.ad).a(entity, entity.ac);
|
||||
}
|
||||
|
||||
if (false && !entity.bD() && !this.isChunkLoaded(i, k, true)) { // Paper - Always send entities into a new chunk, never lose them
|
||||
if (!entity.valid && !entity.bD() && !this.isChunkLoaded(i, k, true)) { // Paper - always load to new chunk if valid
|
||||
entity.aa = false;
|
||||
} else {
|
||||
this.getChunkAt(i, k).a(entity);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1622,7 +1622,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
|
||||
public void sendHealthUpdate() {
|
||||
getHandle().playerConnection.sendPacket(new PacketPlayOutUpdateHealth(getScaledHealth(), getHandle().getFoodData().getFoodLevel(), getHandle().getFoodData().getSaturationLevel()));
|
||||
// Paper start - cancellable death event
|
||||
//getHandle().playerConnection.sendPacket(new PacketPlayOutUpdateHealth(getScaledHealth(), getHandle().getFoodData().getFoodLevel(), getHandle().getFoodData().getSaturationLevel()));
|
||||
PacketPlayOutUpdateHealth packet = new PacketPlayOutUpdateHealth(getScaledHealth(), getHandle().getFoodData().getFoodLevel(), getHandle().getFoodData().getSaturationLevel());
|
||||
if (this.getHandle().queueHealthUpdatePacket) {
|
||||
this.getHandle().queuedHealthUpdatePacket = packet;
|
||||
} else {
|
||||
this.getHandle().playerConnection.sendPacket(packet);
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
|
||||
public void injectScaledMaxHealth(Collection<AttributeInstance> collection, boolean force) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
791
sources/src/main/java/org/bukkit/plugin/SimplePluginManager.java
Normal file
791
sources/src/main/java/org/bukkit/plugin/SimplePluginManager.java
Normal file
@@ -0,0 +1,791 @@
|
||||
package org.bukkit.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
||||
import com.destroystokyo.paper.exception.ServerEventException;
|
||||
import com.destroystokyo.paper.exception.ServerPluginEnableDisableException;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginCommandYamlParser;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.util.FileUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Akarin Changes Note
|
||||
* 1) Reverts Paper's changes to ensure event order (safety issue)
|
||||
*/
|
||||
/**
|
||||
* Handles all plugin management from the Server
|
||||
*/
|
||||
public final class SimplePluginManager implements PluginManager {
|
||||
private final Server server;
|
||||
private final Map<Pattern, PluginLoader> fileAssociations = new HashMap<Pattern, PluginLoader>();
|
||||
private final List<Plugin> plugins = new ArrayList<Plugin>();
|
||||
private final Map<String, Plugin> lookupNames = new HashMap<String, Plugin>();
|
||||
private File updateDirectory;
|
||||
private final SimpleCommandMap commandMap;
|
||||
private final Map<String, Permission> permissions = new HashMap<String, Permission>();
|
||||
private final Map<Boolean, Set<Permission>> defaultPerms = new LinkedHashMap<Boolean, Set<Permission>>();
|
||||
private final Map<String, Map<Permissible, Boolean>> permSubs = new HashMap<String, Map<Permissible, Boolean>>();
|
||||
private final Map<Boolean, Map<Permissible, Boolean>> defSubs = new HashMap<Boolean, Map<Permissible, Boolean>>();
|
||||
private boolean useTimings = false;
|
||||
|
||||
public SimplePluginManager(Server instance, SimpleCommandMap commandMap) {
|
||||
server = instance;
|
||||
this.commandMap = commandMap;
|
||||
|
||||
defaultPerms.put(true, new HashSet<Permission>());
|
||||
defaultPerms.put(false, new HashSet<Permission>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified plugin loader
|
||||
*
|
||||
* @param loader Class name of the PluginLoader to register
|
||||
* @throws IllegalArgumentException Thrown when the given Class is not a
|
||||
* valid PluginLoader
|
||||
*/
|
||||
public void registerInterface(Class<? extends PluginLoader> loader) throws IllegalArgumentException {
|
||||
PluginLoader instance;
|
||||
|
||||
if (PluginLoader.class.isAssignableFrom(loader)) {
|
||||
Constructor<? extends PluginLoader> constructor;
|
||||
|
||||
try {
|
||||
constructor = loader.getConstructor(Server.class);
|
||||
instance = constructor.newInstance(server);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
String className = loader.getName();
|
||||
|
||||
throw new IllegalArgumentException(String.format("Class %s does not have a public %s(Server) constructor", className, className), ex);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException(String.format("Unexpected exception %s while attempting to construct a new instance of %s", ex.getClass().getName(), loader.getName()), ex);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Class %s does not implement interface PluginLoader", loader.getName()));
|
||||
}
|
||||
|
||||
Pattern[] patterns = instance.getPluginFileFilters();
|
||||
|
||||
synchronized (this) {
|
||||
for (Pattern pattern : patterns) {
|
||||
fileAssociations.put(pattern, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the plugins contained within the specified directory
|
||||
*
|
||||
* @param directory Directory to check for plugins
|
||||
* @return A list of all plugins loaded
|
||||
*/
|
||||
public Plugin[] loadPlugins(File directory) {
|
||||
Validate.notNull(directory, "Directory cannot be null");
|
||||
Validate.isTrue(directory.isDirectory(), "Directory must be a directory");
|
||||
|
||||
List<Plugin> result = new ArrayList<Plugin>();
|
||||
Set<Pattern> filters = fileAssociations.keySet();
|
||||
|
||||
if (!(server.getUpdateFolder().equals(""))) {
|
||||
updateDirectory = new File(directory, server.getUpdateFolder());
|
||||
}
|
||||
|
||||
Map<String, File> plugins = new HashMap<String, File>();
|
||||
Set<String> loadedPlugins = new HashSet<String>();
|
||||
Map<String, Collection<String>> dependencies = new HashMap<String, Collection<String>>();
|
||||
Map<String, Collection<String>> softDependencies = new HashMap<String, Collection<String>>();
|
||||
|
||||
// This is where it figures out all possible plugins
|
||||
for (File file : directory.listFiles()) {
|
||||
PluginLoader loader = null;
|
||||
for (Pattern filter : filters) {
|
||||
Matcher match = filter.matcher(file.getName());
|
||||
if (match.find()) {
|
||||
loader = fileAssociations.get(filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (loader == null) continue;
|
||||
|
||||
PluginDescriptionFile description = null;
|
||||
try {
|
||||
description = loader.getPluginDescription(file);
|
||||
String name = description.getName();
|
||||
if (name.equalsIgnoreCase("bukkit") || name.equalsIgnoreCase("minecraft") || name.equalsIgnoreCase("mojang")) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': Restricted Name");
|
||||
continue;
|
||||
} else if (description.rawName.indexOf(' ') != -1) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': uses the space-character (0x20) in its name");
|
||||
continue;
|
||||
}
|
||||
} catch (InvalidDescriptionException ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
File replacedFile = plugins.put(description.getName(), file);
|
||||
if (replacedFile != null) {
|
||||
server.getLogger().severe(String.format(
|
||||
"Ambiguous plugin name `%s' for files `%s' and `%s' in `%s'",
|
||||
description.getName(),
|
||||
file.getPath(),
|
||||
replacedFile.getPath(),
|
||||
directory.getPath()
|
||||
));
|
||||
}
|
||||
|
||||
Collection<String> softDependencySet = description.getSoftDepend();
|
||||
if (softDependencySet != null && !softDependencySet.isEmpty()) {
|
||||
if (softDependencies.containsKey(description.getName())) {
|
||||
// Duplicates do not matter, they will be removed together if applicable
|
||||
softDependencies.get(description.getName()).addAll(softDependencySet);
|
||||
} else {
|
||||
softDependencies.put(description.getName(), new LinkedList<String>(softDependencySet));
|
||||
}
|
||||
}
|
||||
|
||||
Collection<String> dependencySet = description.getDepend();
|
||||
if (dependencySet != null && !dependencySet.isEmpty()) {
|
||||
dependencies.put(description.getName(), new LinkedList<String>(dependencySet));
|
||||
}
|
||||
|
||||
Collection<String> loadBeforeSet = description.getLoadBefore();
|
||||
if (loadBeforeSet != null && !loadBeforeSet.isEmpty()) {
|
||||
for (String loadBeforeTarget : loadBeforeSet) {
|
||||
if (softDependencies.containsKey(loadBeforeTarget)) {
|
||||
softDependencies.get(loadBeforeTarget).add(description.getName());
|
||||
} else {
|
||||
// softDependencies is never iterated, so 'ghost' plugins aren't an issue
|
||||
Collection<String> shortSoftDependency = new LinkedList<String>();
|
||||
shortSoftDependency.add(description.getName());
|
||||
softDependencies.put(loadBeforeTarget, shortSoftDependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!plugins.isEmpty()) {
|
||||
boolean missingDependency = true;
|
||||
Iterator<Map.Entry<String, File>> pluginIterator = plugins.entrySet().iterator();
|
||||
|
||||
while (pluginIterator.hasNext()) {
|
||||
Map.Entry<String, File> entry = pluginIterator.next();
|
||||
String plugin = entry.getKey();
|
||||
|
||||
if (dependencies.containsKey(plugin)) {
|
||||
Iterator<String> dependencyIterator = dependencies.get(plugin).iterator();
|
||||
|
||||
while (dependencyIterator.hasNext()) {
|
||||
String dependency = dependencyIterator.next();
|
||||
|
||||
// Dependency loaded
|
||||
if (loadedPlugins.contains(dependency)) {
|
||||
dependencyIterator.remove();
|
||||
|
||||
// We have a dependency not found
|
||||
} else if (!plugins.containsKey(dependency)) {
|
||||
missingDependency = false;
|
||||
pluginIterator.remove();
|
||||
softDependencies.remove(plugin);
|
||||
dependencies.remove(plugin);
|
||||
|
||||
server.getLogger().log(
|
||||
Level.SEVERE,
|
||||
"Could not load '" + entry.getValue().getPath() + "' in folder '" + directory.getPath() + "'",
|
||||
new UnknownDependencyException(dependency));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dependencies.containsKey(plugin) && dependencies.get(plugin).isEmpty()) {
|
||||
dependencies.remove(plugin);
|
||||
}
|
||||
}
|
||||
if (softDependencies.containsKey(plugin)) {
|
||||
Iterator<String> softDependencyIterator = softDependencies.get(plugin).iterator();
|
||||
|
||||
while (softDependencyIterator.hasNext()) {
|
||||
String softDependency = softDependencyIterator.next();
|
||||
|
||||
// Soft depend is no longer around
|
||||
if (!plugins.containsKey(softDependency)) {
|
||||
softDependencyIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (softDependencies.get(plugin).isEmpty()) {
|
||||
softDependencies.remove(plugin);
|
||||
}
|
||||
}
|
||||
if (!(dependencies.containsKey(plugin) || softDependencies.containsKey(plugin)) && plugins.containsKey(plugin)) {
|
||||
// We're clear to load, no more soft or hard dependencies left
|
||||
File file = plugins.get(plugin);
|
||||
pluginIterator.remove();
|
||||
missingDependency = false;
|
||||
|
||||
try {
|
||||
result.add(loadPlugin(file));
|
||||
loadedPlugins.add(plugin);
|
||||
continue;
|
||||
} catch (InvalidPluginException ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (missingDependency) {
|
||||
// We now iterate over plugins until something loads
|
||||
// This loop will ignore soft dependencies
|
||||
pluginIterator = plugins.entrySet().iterator();
|
||||
|
||||
while (pluginIterator.hasNext()) {
|
||||
Map.Entry<String, File> entry = pluginIterator.next();
|
||||
String plugin = entry.getKey();
|
||||
|
||||
if (!dependencies.containsKey(plugin)) {
|
||||
softDependencies.remove(plugin);
|
||||
missingDependency = false;
|
||||
File file = entry.getValue();
|
||||
pluginIterator.remove();
|
||||
|
||||
try {
|
||||
result.add(loadPlugin(file));
|
||||
loadedPlugins.add(plugin);
|
||||
break;
|
||||
} catch (InvalidPluginException ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We have no plugins left without a depend
|
||||
if (missingDependency) {
|
||||
softDependencies.clear();
|
||||
dependencies.clear();
|
||||
Iterator<File> failedPluginIterator = plugins.values().iterator();
|
||||
|
||||
while (failedPluginIterator.hasNext()) {
|
||||
File file = failedPluginIterator.next();
|
||||
failedPluginIterator.remove();
|
||||
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': circular dependency detected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new Plugin[result.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the plugin in the specified file
|
||||
* <p>
|
||||
* File must be valid according to the current enabled Plugin interfaces
|
||||
*
|
||||
* @param file File containing the plugin to load
|
||||
* @return The Plugin loaded, or null if it was invalid
|
||||
* @throws InvalidPluginException Thrown when the specified file is not a
|
||||
* valid plugin
|
||||
* @throws UnknownDependencyException If a required dependency could not
|
||||
* be found
|
||||
*/
|
||||
public synchronized Plugin loadPlugin(File file) throws InvalidPluginException, UnknownDependencyException {
|
||||
Validate.notNull(file, "File cannot be null");
|
||||
|
||||
checkUpdate(file);
|
||||
|
||||
Set<Pattern> filters = fileAssociations.keySet();
|
||||
Plugin result = null;
|
||||
|
||||
for (Pattern filter : filters) {
|
||||
String name = file.getName();
|
||||
Matcher match = filter.matcher(name);
|
||||
|
||||
if (match.find()) {
|
||||
PluginLoader loader = fileAssociations.get(filter);
|
||||
|
||||
result = loader.loadPlugin(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
plugins.add(result);
|
||||
lookupNames.put(result.getDescription().getName().toLowerCase(java.util.Locale.ENGLISH), result); // Spigot
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void checkUpdate(File file) {
|
||||
if (updateDirectory == null || !updateDirectory.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File updateFile = new File(updateDirectory, file.getName());
|
||||
if (updateFile.isFile() && FileUtil.copy(updateFile, file)) {
|
||||
updateFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given plugin is loaded and returns it when applicable
|
||||
* <p>
|
||||
* Please note that the name of the plugin is case-sensitive
|
||||
*
|
||||
* @param name Name of the plugin to check
|
||||
* @return Plugin if it exists, otherwise null
|
||||
*/
|
||||
public synchronized Plugin getPlugin(String name) {
|
||||
return lookupNames.get(name.replace(' ', '_').toLowerCase(java.util.Locale.ENGLISH)); // Spigot
|
||||
}
|
||||
|
||||
public synchronized Plugin[] getPlugins() {
|
||||
return plugins.toArray(new Plugin[plugins.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given plugin is enabled or not
|
||||
* <p>
|
||||
* Please note that the name of the plugin is case-sensitive.
|
||||
*
|
||||
* @param name Name of the plugin to check
|
||||
* @return true if the plugin is enabled, otherwise false
|
||||
*/
|
||||
public boolean isPluginEnabled(String name) {
|
||||
Plugin plugin = getPlugin(name);
|
||||
|
||||
return isPluginEnabled(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given plugin is enabled or not
|
||||
*
|
||||
* @param plugin Plugin to check
|
||||
* @return true if the plugin is enabled, otherwise false
|
||||
*/
|
||||
public synchronized boolean isPluginEnabled(Plugin plugin) { // Paper - synchronize
|
||||
if ((plugin != null) && (plugins.contains(plugin))) {
|
||||
return plugin.isEnabled();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void enablePlugin(final Plugin plugin) { // Paper - synchronize
|
||||
if (!plugin.isEnabled()) {
|
||||
List<Command> pluginCommands = PluginCommandYamlParser.parse(plugin);
|
||||
|
||||
if (!pluginCommands.isEmpty()) {
|
||||
commandMap.registerAll(plugin.getDescription().getName(), pluginCommands);
|
||||
}
|
||||
|
||||
try {
|
||||
plugin.getPluginLoader().enablePlugin(plugin);
|
||||
} catch (Throwable ex) {
|
||||
handlePluginException("Error occurred (in the plugin loader) while enabling "
|
||||
+ plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin);
|
||||
}
|
||||
|
||||
HandlerList.bakeAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Paper start - close Classloader on disable
|
||||
public void disablePlugins() {
|
||||
disablePlugins(false);
|
||||
}
|
||||
|
||||
public void disablePlugins(boolean closeClassloaders) {
|
||||
// Paper end - close Classloader on disable
|
||||
Plugin[] plugins = getPlugins();
|
||||
for (int i = plugins.length - 1; i >= 0; i--) {
|
||||
disablePlugin(plugins[i], closeClassloaders); // Paper - close Classloader on disable
|
||||
}
|
||||
}
|
||||
|
||||
// Paper start - close Classloader on disable
|
||||
public void disablePlugin(Plugin plugin) {
|
||||
disablePlugin(plugin, false);
|
||||
}
|
||||
|
||||
public synchronized void disablePlugin(final Plugin plugin, boolean closeClassloader) { // Paper - synchronize
|
||||
// Paper end - close Classloader on disable
|
||||
if (plugin.isEnabled()) {
|
||||
try {
|
||||
plugin.getPluginLoader().disablePlugin(plugin, closeClassloader); // Paper - close Classloader on disable
|
||||
} catch (Throwable ex) {
|
||||
handlePluginException("Error occurred (in the plugin loader) while disabling "
|
||||
+ plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
|
||||
}
|
||||
|
||||
try {
|
||||
server.getScheduler().cancelTasks(plugin);
|
||||
} catch (Throwable ex) {
|
||||
handlePluginException("Error occurred (in the plugin loader) while cancelling tasks for "
|
||||
+ plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
|
||||
}
|
||||
|
||||
try {
|
||||
server.getServicesManager().unregisterAll(plugin);
|
||||
} catch (Throwable ex) {
|
||||
handlePluginException("Error occurred (in the plugin loader) while unregistering services for "
|
||||
+ plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
|
||||
}
|
||||
|
||||
try {
|
||||
HandlerList.unregisterAll(plugin);
|
||||
} catch (Throwable ex) {
|
||||
handlePluginException("Error occurred (in the plugin loader) while unregistering events for "
|
||||
+ plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
|
||||
}
|
||||
|
||||
try {
|
||||
server.getMessenger().unregisterIncomingPluginChannel(plugin);
|
||||
server.getMessenger().unregisterOutgoingPluginChannel(plugin);
|
||||
} catch (Throwable ex) {
|
||||
handlePluginException("Error occurred (in the plugin loader) while unregistering plugin channels for "
|
||||
+ plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private void handlePluginException(String msg, Throwable ex, Plugin plugin) {
|
||||
server.getLogger().log(Level.SEVERE, msg, ex);
|
||||
callEvent(new ServerExceptionEvent(new ServerPluginEnableDisableException(msg, ex, plugin)));
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public void clearPlugins() {
|
||||
synchronized (this) {
|
||||
disablePlugins(true); // Paper - close Classloader on disable
|
||||
plugins.clear();
|
||||
lookupNames.clear();
|
||||
HandlerList.unregisterAll();
|
||||
fileAssociations.clear();
|
||||
permissions.clear();
|
||||
defaultPerms.get(true).clear();
|
||||
defaultPerms.get(false).clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an event with the given details.
|
||||
* <p>
|
||||
* This method only synchronizes when the event is not asynchronous.
|
||||
*
|
||||
* @param event Event details
|
||||
*/
|
||||
public void callEvent(Event event) {
|
||||
if (event.isAsynchronous()) {
|
||||
if (Thread.holdsLock(this)) {
|
||||
throw new IllegalStateException(event.getEventName() + " cannot be triggered asynchronously from inside synchronized code.");
|
||||
}
|
||||
if (server.isPrimaryThread()) {
|
||||
throw new IllegalStateException(event.getEventName() + " cannot be triggered asynchronously from primary server thread.");
|
||||
}
|
||||
fireEvent(event);
|
||||
} else {
|
||||
synchronized (this) {
|
||||
fireEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fireEvent(Event event) {
|
||||
HandlerList handlers = event.getHandlers();
|
||||
RegisteredListener[] listeners = handlers.getRegisteredListeners();
|
||||
|
||||
for (RegisteredListener registration : listeners) {
|
||||
if (!registration.getPlugin().isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
registration.callEvent(event);
|
||||
} catch (AuthorNagException ex) {
|
||||
Plugin plugin = registration.getPlugin();
|
||||
|
||||
if (plugin.isNaggable()) {
|
||||
plugin.setNaggable(false);
|
||||
|
||||
server.getLogger().log(Level.SEVERE, String.format(
|
||||
"Nag author(s): '%s' of '%s' about the following: %s",
|
||||
plugin.getDescription().getAuthors(),
|
||||
plugin.getDescription().getFullName(),
|
||||
ex.getMessage()
|
||||
));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
// Paper start - error reporting
|
||||
String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName();
|
||||
server.getLogger().log(Level.SEVERE, msg, ex);
|
||||
if (!(event instanceof ServerExceptionEvent)) { // We don't want to cause an endless event loop
|
||||
callEvent(new ServerExceptionEvent(new ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event)));
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerEvents(Listener listener, Plugin plugin) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register " + listener + " while not enabled");
|
||||
}
|
||||
|
||||
for (Map.Entry<Class<? extends Event>, Set<RegisteredListener>> entry : plugin.getPluginLoader().createRegisteredListeners(listener, plugin).entrySet()) {
|
||||
getEventListeners(getRegistrationClass(entry.getKey())).registerAll(entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void registerEvent(Class<? extends Event> event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin) {
|
||||
registerEvent(event, listener, priority, executor, plugin, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given event to the specified listener using a directly
|
||||
* passed EventExecutor
|
||||
*
|
||||
* @param event Event class to register
|
||||
* @param listener PlayerListener to register
|
||||
* @param priority Priority of this event
|
||||
* @param executor EventExecutor to register
|
||||
* @param plugin Plugin to register
|
||||
* @param ignoreCancelled Do not call executor if event was already
|
||||
* cancelled
|
||||
*/
|
||||
public void registerEvent(Class<? extends Event> event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin, boolean ignoreCancelled) {
|
||||
Validate.notNull(listener, "Listener cannot be null");
|
||||
Validate.notNull(priority, "Priority cannot be null");
|
||||
Validate.notNull(executor, "Executor cannot be null");
|
||||
Validate.notNull(plugin, "Plugin cannot be null");
|
||||
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled");
|
||||
}
|
||||
|
||||
executor = new co.aikar.timings.TimedEventExecutor(executor, plugin, null, event); // Spigot
|
||||
if (false) { // Spigot - RL handles useTimings check now
|
||||
getEventListeners(event).register(new TimedRegisteredListener(listener, executor, priority, plugin, ignoreCancelled));
|
||||
} else {
|
||||
getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled));
|
||||
}
|
||||
}
|
||||
|
||||
private HandlerList getEventListeners(Class<? extends Event> type) {
|
||||
try {
|
||||
Method method = getRegistrationClass(type).getDeclaredMethod("getHandlerList");
|
||||
method.setAccessible(true);
|
||||
return (HandlerList) method.invoke(null);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalPluginAccessException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private Class<? extends Event> getRegistrationClass(Class<? extends Event> clazz) {
|
||||
try {
|
||||
clazz.getDeclaredMethod("getHandlerList");
|
||||
return clazz;
|
||||
} catch (NoSuchMethodException e) {
|
||||
if (clazz.getSuperclass() != null
|
||||
&& !clazz.getSuperclass().equals(Event.class)
|
||||
&& Event.class.isAssignableFrom(clazz.getSuperclass())) {
|
||||
return getRegistrationClass(clazz.getSuperclass().asSubclass(Event.class));
|
||||
} else {
|
||||
throw new IllegalPluginAccessException("Unable to find handler list for event " + clazz.getName() + ". Static getHandlerList method required!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Permission getPermission(String name) {
|
||||
return permissions.get(name.toLowerCase(java.util.Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public void addPermission(Permission perm) {
|
||||
addPermission(perm, true);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addPermission(Permission perm, boolean dirty) {
|
||||
String name = perm.getName().toLowerCase(java.util.Locale.ENGLISH);
|
||||
|
||||
if (permissions.containsKey(name)) {
|
||||
throw new IllegalArgumentException("The permission " + name + " is already defined!");
|
||||
}
|
||||
|
||||
permissions.put(name, perm);
|
||||
calculatePermissionDefault(perm, dirty);
|
||||
}
|
||||
|
||||
public Set<Permission> getDefaultPermissions(boolean op) {
|
||||
return ImmutableSet.copyOf(defaultPerms.get(op));
|
||||
}
|
||||
|
||||
public void removePermission(Permission perm) {
|
||||
removePermission(perm.getName());
|
||||
}
|
||||
|
||||
public void removePermission(String name) {
|
||||
permissions.remove(name.toLowerCase(java.util.Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public void recalculatePermissionDefaults(Permission perm) {
|
||||
if (perm != null && permissions.containsKey(perm.getName().toLowerCase(java.util.Locale.ENGLISH))) {
|
||||
defaultPerms.get(true).remove(perm);
|
||||
defaultPerms.get(false).remove(perm);
|
||||
|
||||
calculatePermissionDefault(perm, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculatePermissionDefault(Permission perm, boolean dirty) {
|
||||
if ((perm.getDefault() == PermissionDefault.OP) || (perm.getDefault() == PermissionDefault.TRUE)) {
|
||||
defaultPerms.get(true).add(perm);
|
||||
if (dirty) {
|
||||
dirtyPermissibles(true);
|
||||
}
|
||||
}
|
||||
if ((perm.getDefault() == PermissionDefault.NOT_OP) || (perm.getDefault() == PermissionDefault.TRUE)) {
|
||||
defaultPerms.get(false).add(perm);
|
||||
if (dirty) {
|
||||
dirtyPermissibles(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void dirtyPermissibles() {
|
||||
dirtyPermissibles(true);
|
||||
dirtyPermissibles(false);
|
||||
}
|
||||
|
||||
private void dirtyPermissibles(boolean op) {
|
||||
Set<Permissible> permissibles = getDefaultPermSubscriptions(op);
|
||||
|
||||
for (Permissible p : permissibles) {
|
||||
p.recalculatePermissions();
|
||||
}
|
||||
}
|
||||
|
||||
public void subscribeToPermission(String permission, Permissible permissible) {
|
||||
String name = permission.toLowerCase(java.util.Locale.ENGLISH);
|
||||
Map<Permissible, Boolean> map = permSubs.get(name);
|
||||
|
||||
if (map == null) {
|
||||
map = new WeakHashMap<Permissible, Boolean>();
|
||||
permSubs.put(name, map);
|
||||
}
|
||||
|
||||
map.put(permissible, true);
|
||||
}
|
||||
|
||||
public void unsubscribeFromPermission(String permission, Permissible permissible) {
|
||||
String name = permission.toLowerCase(java.util.Locale.ENGLISH);
|
||||
Map<Permissible, Boolean> map = permSubs.get(name);
|
||||
|
||||
if (map != null) {
|
||||
map.remove(permissible);
|
||||
|
||||
if (map.isEmpty()) {
|
||||
permSubs.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Permissible> getPermissionSubscriptions(String permission) {
|
||||
String name = permission.toLowerCase(java.util.Locale.ENGLISH);
|
||||
Map<Permissible, Boolean> map = permSubs.get(name);
|
||||
|
||||
if (map == null) {
|
||||
return ImmutableSet.of();
|
||||
} else {
|
||||
return ImmutableSet.copyOf(map.keySet());
|
||||
}
|
||||
}
|
||||
|
||||
public void subscribeToDefaultPerms(boolean op, Permissible permissible) {
|
||||
Map<Permissible, Boolean> map = defSubs.get(op);
|
||||
|
||||
if (map == null) {
|
||||
map = new WeakHashMap<Permissible, Boolean>();
|
||||
defSubs.put(op, map);
|
||||
}
|
||||
|
||||
map.put(permissible, true);
|
||||
}
|
||||
|
||||
public void unsubscribeFromDefaultPerms(boolean op, Permissible permissible) {
|
||||
Map<Permissible, Boolean> map = defSubs.get(op);
|
||||
|
||||
if (map != null) {
|
||||
map.remove(permissible);
|
||||
|
||||
if (map.isEmpty()) {
|
||||
defSubs.remove(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Permissible> getDefaultPermSubscriptions(boolean op) {
|
||||
Map<Permissible, Boolean> map = defSubs.get(op);
|
||||
|
||||
if (map == null) {
|
||||
return ImmutableSet.of();
|
||||
} else {
|
||||
return ImmutableSet.copyOf(map.keySet());
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Permission> getPermissions() {
|
||||
return new HashSet<Permission>(permissions.values());
|
||||
}
|
||||
|
||||
public boolean useTimings() {
|
||||
return co.aikar.timings.Timings.isTimingsEnabled(); // Spigot
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not per event timing code should be used
|
||||
*
|
||||
* @param use True if per event timing code should be used
|
||||
*/
|
||||
public void useTimings(boolean use) {
|
||||
co.aikar.timings.Timings.setTimingsEnabled(use); // Spigot
|
||||
}
|
||||
|
||||
// Paper start
|
||||
public void clearPermissions() {
|
||||
permissions.clear();
|
||||
defaultPerms.get(true).clear();
|
||||
defaultPerms.get(false).clear();
|
||||
}
|
||||
// Paper end
|
||||
|
||||
}
|
||||
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: f7358c5cf7...e39995d213
Reference in New Issue
Block a user