Compare commits
227 Commits
uuid-rewor
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
1c579564bc | ||
|
eae4021138 | ||
|
6563b4f6ce | ||
|
1d5a836fd0 | ||
|
3ba82683ec | ||
|
6e5c332272 | ||
|
1c9d133ed1 | ||
|
dad1e16c18 | ||
|
519dd7da33 | ||
|
1bd7932cc5 | ||
|
dad00d2d9c | ||
|
502f661be3 | ||
|
804d30bcc7 | ||
|
db8b67082b | ||
|
b2156edcc7 | ||
|
45de495699 | ||
|
f45d332727 | ||
|
9705cb156b | ||
|
1c45ef517f | ||
|
3fee84fc58 | ||
|
00113cc4d4 | ||
|
788f022e74 | ||
|
da55790fd2 | ||
|
1a6d513603 | ||
|
a5b02ab26a | ||
|
0c3ce2dfb3 | ||
|
a1f4649a09 | ||
|
100d0e12cd | ||
|
3e629798e5 | ||
|
7c1f15974c | ||
|
d992237766 | ||
|
c93464e643 | ||
|
56afefc82b | ||
|
f0a66570d2 | ||
|
201a3578bf | ||
|
1228fc2de2 | ||
|
2561e75ae5 | ||
|
80661b9465 | ||
|
53701da34f | ||
|
9cf4712813 | ||
|
abe8fccdb5 | ||
|
4499bb5453 | ||
|
5405b7d7b9 | ||
|
34199d12a4 | ||
|
67131ab9f9 | ||
|
723381cb2b | ||
|
34e7252d77 | ||
|
a1b2df74cc | ||
|
7210f9153e | ||
|
dcdfac0d3b | ||
|
c7b4554a6c | ||
|
c51acb4e72 | ||
|
23d41cd6c8 | ||
|
8bc389496b | ||
|
1cc36d08bd | ||
|
c8938f451d | ||
|
4f2665fedc | ||
|
7d93bb06ad | ||
|
19c491411f | ||
|
65c6eb2693 | ||
|
ab1f4ace8a | ||
|
e7dc52bee4 | ||
|
a9c5799677 | ||
|
6d6257720a | ||
|
3e235fa688 | ||
|
dd02355ac2 | ||
|
4d3f5d67a8 | ||
|
7ad5faa2ce | ||
|
c28383ef36 | ||
|
5fbab1ab8f | ||
|
d97b092978 | ||
|
154bf56c2a | ||
|
d65a9caeb2 | ||
|
b3c4253606 | ||
|
b64000e89b | ||
|
3faf41ef18 | ||
|
db27d25a93 | ||
|
0f02e6fe66 | ||
|
ec07637e9f | ||
|
b269f3509c | ||
|
f2e4c8a3ad | ||
|
35839f1548 | ||
|
a4a462a1fa | ||
|
b9f901af66 | ||
|
1333056613 | ||
|
fb23df313a | ||
|
96dc400c83 | ||
|
b801d36f12 | ||
|
4c27599dd9 | ||
|
64ad0a5267 | ||
|
cba7f44192 | ||
|
e8ace6bd06 | ||
|
fd70f260ba | ||
|
be9874ba1d | ||
|
096faef161 | ||
|
df96d5106a | ||
|
fe77a1d2e7 | ||
|
3096e43540 | ||
|
2939551d65 | ||
|
fb74fd3ced | ||
|
393fe1d837 | ||
|
f80df9d83b | ||
|
5c006f8ebd | ||
|
57097e626e | ||
|
0f266c8a64 | ||
|
185f037254 | ||
|
e4d0020296 | ||
|
9e37cbbca8 | ||
|
adc35e9ad5 | ||
|
a469c732cc | ||
|
c5c1f47167 | ||
|
dc59356f76 | ||
|
d497772ad7 | ||
|
4f4d46974a | ||
|
96c38895e2 | ||
|
5753648d77 | ||
|
3725711b94 | ||
|
c22e18c096 | ||
|
6bff759d72 | ||
|
582c7201dd | ||
|
59a8ed70bb | ||
|
27812c133d | ||
|
165f3fb00e | ||
|
60dcb64558 | ||
|
077b34d304 | ||
|
8ce6e2f8d3 | ||
|
f5dce23f18 | ||
|
669cfd72aa | ||
|
9e66885690 | ||
|
a802769265 | ||
|
50c45b6616 | ||
|
eaf01fa32c | ||
|
4abaa6ea51 | ||
|
7c621bf899 | ||
|
f5c682ff2b | ||
|
e652b43670 | ||
|
f07cef5621 | ||
|
ded6421e33 | ||
|
cbb2b4d232 | ||
|
48c61eeb82 | ||
|
e3d1af010b | ||
|
2195677651 | ||
|
c72af5dbac | ||
|
931cdb6fb1 | ||
|
9db18613a1 | ||
|
784935a975 | ||
|
d9abe76531 | ||
|
ca85a392aa | ||
|
307f47e4d3 | ||
|
96c59f163d | ||
|
01f147b13c | ||
|
1c104b775f | ||
|
9a53e46dd3 | ||
|
6744e71127 | ||
|
12c3ebb798 | ||
|
32ec8d8147 | ||
|
443e0c489e | ||
|
7ab0003b62 | ||
|
12c0cac311 | ||
|
f54481e872 | ||
|
f27dd8a233 | ||
|
d6df1a0871 | ||
|
e34e51d127 | ||
|
5ca2ae461a | ||
|
4095e8039d | ||
|
73f390ab20 | ||
|
2f7d3bc235 | ||
|
ef486032f1 | ||
|
72ef873772 | ||
|
9b6e32a775 | ||
|
f05110c9b8 | ||
|
a41f89b011 | ||
|
d24827ffcb | ||
|
802ce28103 | ||
|
f31356b227 | ||
|
7942466863 | ||
|
db2cade4e2 | ||
|
718b4bb5dd | ||
|
6aa25dd2dc | ||
|
0bbcf6cdb2 | ||
|
f11d60f78c | ||
|
8a6b98614f | ||
|
d7eec528e4 | ||
|
a10c61168a | ||
|
5c4886c66b | ||
|
4335b8dc2c | ||
|
3bf7225712 | ||
|
b76440ab9a | ||
|
3152605bca | ||
|
eaabd30dc2 | ||
|
de0d28b12d | ||
|
c3a8bc9486 | ||
|
5b77404597 | ||
|
d9c1b00b50 | ||
|
2fc439b306 | ||
|
2cb1b01fbf | ||
|
d16cca9847 | ||
|
e39f009661 | ||
|
1d622b653d | ||
|
582a958195 | ||
|
9245b4cc27 | ||
|
ba9396ad5c | ||
|
27de16cba9 | ||
|
90ea073089 | ||
|
4811e53d12 | ||
|
c7f38adb3f | ||
|
99a7359be3 | ||
|
d42cc3e275 | ||
|
b8f4589b87 | ||
|
f9ac6804b2 | ||
|
62f5d54676 | ||
|
8feca3fb21 | ||
|
7b16140ee1 | ||
|
14ec280d26 | ||
|
71ac05ae85 | ||
|
c4a9cb0a4a | ||
|
7ae87d1dbe | ||
|
346036b7e7 | ||
|
69c355c8cd | ||
|
8dbbe80dbf | ||
|
77e6ce8c7c | ||
|
cd405a9b9e | ||
|
b5d6cf047c | ||
|
aaa9c4e190 | ||
|
6ea09dc964 | ||
|
eace5ca8fb | ||
|
03308be7f5 |
13
.github/workflows/close-issue.yml
vendored
Normal file
13
.github/workflows/close-issue.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
name: Close Issue
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: peter-evans/close-issue@v1.0.3
|
||||||
|
with:
|
||||||
|
comment: "Per the notice in the readme, OpenInv is now being maintained at [Jikoo/OpenInv](https://github.com/Jikoo/OpenInv)."
|
13
.github/workflows/close-pr.yml
vendored
Normal file
13
.github/workflows/close-pr.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
name: Close Pull Request
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: superbrothers/close-pull-request@v3.1.0
|
||||||
|
with:
|
||||||
|
comment: "Per the notice in the readme, OpenInv is now being maintained at [Jikoo/OpenInv](https://github.com/Jikoo/OpenInv)."
|
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,9 +1,10 @@
|
|||||||
/.settings
|
**/.settings
|
||||||
/.gitignore
|
**/.project
|
||||||
/.project
|
**/.classpath
|
||||||
/.classpath
|
**/.idea/
|
||||||
/.idea
|
**.iml
|
||||||
/target
|
**/target/
|
||||||
/bin
|
**/bin/
|
||||||
/lib
|
**/out/
|
||||||
/out
|
**/dependency-reduced-pom.xml
|
||||||
|
**/pom.xml.versionsBackup
|
||||||
|
13
README
13
README
@@ -1,13 +0,0 @@
|
|||||||
Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, version 3.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
175
README.MD
Normal file
175
README.MD
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
## Notice
|
||||||
|
I am now maintaining OpenInv over at [Jikoo/OpenInv](https://github.com/Jikoo/OpenInv) because I needed higher levels of access to add secrets to the repository for Github Actions. It feels ruder to send an email saying what amounts to "pls op" than to redirect people to my fork, though neither option is polite. Existing issues will remain open here until resolved (you can't transfer issues across organizations/users), but any new issues in this repo will be closed without resolution.
|
||||||
|
|
||||||
|
## About
|
||||||
|
OpenInv is a [Bukkit plugin](https://dev.bukkit.org/bukkit-plugins/openinv/) which allows users to open and edit anyone's inventory or ender chest - online or not!
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- **OpenInv**: Open anyone's inventory, even if they're offline.
|
||||||
|
- Read-only mode! No edits allowed! Don't grant the permission `OpenInv.editinv`
|
||||||
|
- Cross-world support! Don't grant `OpenInv.crossworld`
|
||||||
|
- No self-opening! Don't grant `OpenInv.openself`
|
||||||
|
- Drop items as the player! Place items in the unused slots to the right of the armor to drop them
|
||||||
|
- **OpenEnder**: Open anyone's ender chest, even if they're offline.
|
||||||
|
- Read-only mode! No edits allowed! Don't grant `OpenInv.editender`
|
||||||
|
- Cross-world support! Don't grant `OpenInv.crossworld`
|
||||||
|
- No opening others! Don't grant `OpenInv.openenderall`
|
||||||
|
- **SilentContainer**: Open containers without displaying an animation or making sound.
|
||||||
|
- **AnyContainer**: Open containers, even if blocked by ocelots or blocks.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
<table width=100%>
|
||||||
|
<tr>
|
||||||
|
<th width=175px>Command</th>
|
||||||
|
<th>Aliases</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>/openinv [player]</td>
|
||||||
|
<td>oi, inv, open</td>
|
||||||
|
<td>Open a player's inventory. If unspecified, will select last player opened or own if none opened previously.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>/openender [player]</td>
|
||||||
|
<td>oe</td>
|
||||||
|
<td>Open a player's ender chest. If unspecified, will select last player opened or own if none opened previously.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>/searchinv <item> [minAmount]</td>
|
||||||
|
<td>si</td>
|
||||||
|
<td>Lists all online players that have a certain item in their inventory.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>/searchender <item> [minAmount]</td>
|
||||||
|
<td>se</td>
|
||||||
|
<td>Lists all online players that have a certain item in their ender chest.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>/searchenchant <[enchantment] [MinLevel]></td>
|
||||||
|
<td>searchenchants</td>
|
||||||
|
<td>Lists all online players with a specific enchantment.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>/anycontainer [check]</td>
|
||||||
|
<td>ac, anychest</td>
|
||||||
|
<td>Check or toggle the AnyContainer function, allowing opening blocked containers.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>/silentcontainer [check]</td>
|
||||||
|
<td>sc, silentchest</td>
|
||||||
|
<td>Check or toggle the SilentContainer function, allowing opening containers silently.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## Permissions
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Node</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.*</td>
|
||||||
|
<td>Gives permission to use all of OpenInv.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.openinv</td>
|
||||||
|
<td>Required to use /openinv.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.openself</td>
|
||||||
|
<td>Required to open own inventory.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.editinv</td>
|
||||||
|
<td>Required to make changes to open inventories.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.openonline</td>
|
||||||
|
<td>Allows users to open online players' inventories. For compatibility reasons this is granted by the nodes OpenInv.openinv and OpenInv.openender.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.openoffline</td>
|
||||||
|
<td>Allows users to open offline players' inventories. For compatibility reasons this is granted by the nodes OpenInv.openinv and OpenInv.openender.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.openender</td>
|
||||||
|
<td>Required to use /openender.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.editender</td>
|
||||||
|
<td>Required to make changes to open ender chests.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.openenderall</td>
|
||||||
|
<td>Allows users to open others' ender chests. Without it, users can only open their own.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.exempt</td>
|
||||||
|
<td>Prevents the player's inventory being opened by others.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.override</td>
|
||||||
|
<td>Allows bypassing of the exempt permission.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.crossworld</td>
|
||||||
|
<td>Allows cross-world usage of /openinv and /openender.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.search</td>
|
||||||
|
<td>Required to use /searchinv and /searchender.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.searchenchant</td>
|
||||||
|
<td>Required to use /searchenchant.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.anychest</td>
|
||||||
|
<td>Required to use /anychest.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.any.default</td>
|
||||||
|
<td>Cause AnyContainer to be enabled by default.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.silent</td>
|
||||||
|
<td>Required to use /silentcontainer.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.silent.default</td>
|
||||||
|
<td>Cause SilentContainer to be enabled by default.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenInv.spectate</td>
|
||||||
|
<td>Allows users in spectate gamemode to edit inventories.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## For Developers
|
||||||
|
To compile, the relevant Craftbukkit/Spigot jars must be installed in your local repository using the install plugin.
|
||||||
|
Ex: `mvn install:install-file -Dpackaging=jar -Dfile=spigot-1.8-R0.1-SNAPSHOT.jar -DgroupId=org.spigotmc -DartifactId=spigot -Dversion=1.8-R0.1-SNAPSHOT`
|
||||||
|
|
||||||
|
To compile for a single version, specify the NMS revision you are targeting: `mvn -pl <NMS module> -am clean install`
|
||||||
|
|
||||||
|
To compile for a set of versions, you'll need to use a profile. The only provided profile is `all`. Select a profile using the `-P` argument: `mvn clean package -am -P all`
|
||||||
|
|
||||||
|
For more information, check out the [official Maven guide](http://maven.apache.org/guides/introduction/introduction-to-profiles.html).
|
||||||
|
|
||||||
|
The final file is `target/OpenInv.jar`
|
||||||
|
|
||||||
|
## License
|
||||||
|
```
|
||||||
|
Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, version 3.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
```
|
57
api/pom.xml
Normal file
57
api/pom.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.lishid</groupId>
|
||||||
|
<artifactId>openinvparent</artifactId>
|
||||||
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>openinvapi</artifactId>
|
||||||
|
<name>OpenInvAPI</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains</groupId>
|
||||||
|
<artifactId>annotations</artifactId>
|
||||||
|
<version>17.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.16.5-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
309
api/src/main/java/com/lishid/openinv/IOpenInv.java
Normal file
309
api/src/main/java/com/lishid/openinv/IOpenInv.java
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv;
|
||||||
|
|
||||||
|
import com.lishid.openinv.internal.IAnySilentContainer;
|
||||||
|
import com.lishid.openinv.internal.IInventoryAccess;
|
||||||
|
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||||
|
import com.lishid.openinv.internal.ISpecialInventory;
|
||||||
|
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||||
|
import com.lishid.openinv.util.InventoryAccess;
|
||||||
|
import com.lishid.openinv.util.StringMetric;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface defining behavior for the OpenInv plugin.
|
||||||
|
*
|
||||||
|
* @author Jikoo
|
||||||
|
*/
|
||||||
|
public interface IOpenInv {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the configuration value for whether or not OpenInv saves player data when unloading
|
||||||
|
* players. This is exclusively for users who do not allow editing of inventories, only viewing,
|
||||||
|
* and wish to prevent any possibility of bugs such as lishid#40. If true, OpenInv will not ever
|
||||||
|
* save any edits made to players.
|
||||||
|
*
|
||||||
|
* @return false unless configured otherwise
|
||||||
|
*/
|
||||||
|
boolean disableSaving();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the active ISilentContainer implementation.
|
||||||
|
*
|
||||||
|
* @return the ISilentContainer
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
@NotNull IAnySilentContainer getAnySilentContainer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the active IInventoryAccess implementation.
|
||||||
|
*
|
||||||
|
* @return the IInventoryAccess
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default @NotNull IInventoryAccess getInventoryAccess() {
|
||||||
|
return new InventoryAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the provided player's AnyChest setting.
|
||||||
|
*
|
||||||
|
* @param player the OfflinePlayer
|
||||||
|
* @return true if AnyChest is enabled
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
boolean getPlayerAnyChestStatus(@NotNull OfflinePlayer player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a unique identifier by which the OfflinePlayer can be referenced. Using the value
|
||||||
|
* returned to look up a Player will generally be much faster for later implementations.
|
||||||
|
*
|
||||||
|
* @param offline the OfflinePlayer
|
||||||
|
* @return the identifier
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
default @NotNull String getPlayerID(@NotNull OfflinePlayer offline) {
|
||||||
|
return offline.getUniqueId().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a player's SilentChest setting.
|
||||||
|
*
|
||||||
|
* @param offline the OfflinePlayer
|
||||||
|
* @return true if SilentChest is enabled
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
boolean getPlayerSilentChestStatus(@NotNull OfflinePlayer offline);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an ISpecialEnderChest for the given Player.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @param online true if the Player is currently online
|
||||||
|
* @return the ISpecialEnderChest
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
* @throws InstantiationException if the ISpecialEnderChest could not be instantiated
|
||||||
|
*/
|
||||||
|
@NotNull ISpecialEnderChest getSpecialEnderChest(@NotNull Player player, boolean online) throws InstantiationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an ISpecialPlayerInventory for the given Player.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @param online true if the Player is currently online
|
||||||
|
* @return the ISpecialPlayerInventory
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
* @throws InstantiationException if the ISpecialPlayerInventory could not be instantiated
|
||||||
|
*/
|
||||||
|
@NotNull ISpecialPlayerInventory getSpecialInventory(@NotNull Player player, boolean online) throws InstantiationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the server version is supported by OpenInv.
|
||||||
|
*
|
||||||
|
* @return true if the server version is supported
|
||||||
|
*/
|
||||||
|
boolean isSupportedVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a Player from an OfflinePlayer. May return null under some circumstances.
|
||||||
|
*
|
||||||
|
* @param offline the OfflinePlayer to load a Player for
|
||||||
|
* @return the Player, or null
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
@Nullable Player loadPlayer(@NotNull final OfflinePlayer offline);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an OfflinePlayer by name.
|
||||||
|
* <p>
|
||||||
|
* Note: This method is potentially very heavily blocking. It should not ever be called on the
|
||||||
|
* main thread, and if it is, a stack trace will be displayed alerting server owners to the
|
||||||
|
* call.
|
||||||
|
*
|
||||||
|
* @param name the name of the Player
|
||||||
|
* @return the OfflinePlayer with the closest matching name or null if no players have ever logged in
|
||||||
|
*/
|
||||||
|
default @Nullable OfflinePlayer matchPlayer(@NotNull String name) {
|
||||||
|
|
||||||
|
// Warn if called on the main thread - if we resort to searching offline players, this may take several seconds.
|
||||||
|
if (Bukkit.getServer().isPrimaryThread()) {
|
||||||
|
this.getLogger().warning("Call to OpenInv#matchPlayer made on the main thread!");
|
||||||
|
this.getLogger().warning("This can cause the server to hang, potentially severely.");
|
||||||
|
this.getLogger().warning("Trace:");
|
||||||
|
for (StackTraceElement element : new Throwable().fillInStackTrace().getStackTrace()) {
|
||||||
|
this.getLogger().warning(element.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflinePlayer player;
|
||||||
|
|
||||||
|
try {
|
||||||
|
UUID uuid = UUID.fromString(name);
|
||||||
|
player = Bukkit.getOfflinePlayer(uuid);
|
||||||
|
// Ensure player is a real player, otherwise return null
|
||||||
|
if (player.hasPlayedBefore() || player.isOnline()) {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
// Not a UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure name is valid if server is in online mode to avoid unnecessary searching
|
||||||
|
if (Bukkit.getServer().getOnlineMode() && !name.matches("[a-zA-Z0-9_]{3,16}")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
player = Bukkit.getServer().getPlayerExact(name);
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
player = Bukkit.getServer().getOfflinePlayer(name);
|
||||||
|
|
||||||
|
if (player.hasPlayedBefore()) {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
player = Bukkit.getServer().getPlayer(name);
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
float bestMatch = 0;
|
||||||
|
for (OfflinePlayer offline : Bukkit.getServer().getOfflinePlayers()) {
|
||||||
|
if (offline.getName() == null) {
|
||||||
|
// Loaded by UUID only, name has never been looked up.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float currentMatch = StringMetric.compareJaroWinkler(name, offline.getName());
|
||||||
|
|
||||||
|
if (currentMatch == 1.0F) {
|
||||||
|
return offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMatch > bestMatch) {
|
||||||
|
bestMatch = currentMatch;
|
||||||
|
player = offline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only null if no players have played ever, otherwise even the worst match will do.
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open an ISpecialInventory for a Player.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @param inventory the ISpecialInventory
|
||||||
|
* @return the InventoryView for the opened ISpecialInventory
|
||||||
|
*/
|
||||||
|
@Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the configuration value for whether or not OpenInv displays a notification to the user
|
||||||
|
* when a container is activated with AnyChest.
|
||||||
|
*
|
||||||
|
* @return true unless configured otherwise
|
||||||
|
*/
|
||||||
|
boolean notifyAnyChest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the configuration value for whether or not OpenInv displays a notification to the user
|
||||||
|
* when a container is activated with SilentChest.
|
||||||
|
*
|
||||||
|
* @return true unless configured otherwise
|
||||||
|
*/
|
||||||
|
boolean notifySilentChest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a Player as no longer in use by a Plugin to allow OpenInv to remove it from the cache
|
||||||
|
* when eligible.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @param plugin the Plugin no longer holding a reference to the Player
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
void releasePlayer(@NotNull Player player, @NotNull Plugin plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a Player as in use by a Plugin to prevent it from being removed from the cache. Used to
|
||||||
|
* prevent issues with multiple copies of the same Player being loaded such as lishid#49.
|
||||||
|
* Changes made to loaded copies overwrite changes to the others when saved, leading to
|
||||||
|
* duplication bugs and more.
|
||||||
|
* <p>
|
||||||
|
* When finished with the Player object, be sure to call {@link #releasePlayer(Player, Plugin)}
|
||||||
|
* to prevent the cache from keeping it stored until the plugin is disabled.
|
||||||
|
* <p>
|
||||||
|
* When using a Player object from OpenInv, you must handle the Player coming online, replacing
|
||||||
|
* your Player reference with the Player from the PlayerJoinEvent. In addition, you must change
|
||||||
|
* any values in the Player to reflect any unsaved alterations to the existing Player which do
|
||||||
|
* not affect the inventory or ender chest contents.
|
||||||
|
* <p>
|
||||||
|
* OpenInv only saves player data when unloading a Player from the cache, and then only if
|
||||||
|
* {@link #disableSaving()} returns false. If you are making changes that OpenInv does not cause
|
||||||
|
* to persist when a Player logs in as noted above, it is suggested that you manually call
|
||||||
|
* {@link Player#saveData()} when releasing your reference to ensure your changes persist.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @param plugin the Plugin holding the reference to the Player
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
void retainPlayer(@NotNull Player player, @NotNull Plugin plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a player's AnyChest setting.
|
||||||
|
*
|
||||||
|
* @param offline the OfflinePlayer
|
||||||
|
* @param status the status
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
void setPlayerAnyChestStatus(@NotNull OfflinePlayer offline, boolean status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a player's SilentChest setting.
|
||||||
|
*
|
||||||
|
* @param offline the OfflinePlayer
|
||||||
|
* @param status the status
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
void setPlayerSilentChestStatus(@NotNull OfflinePlayer offline, boolean status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcibly unload a cached Player's data.
|
||||||
|
*
|
||||||
|
* @param offline the OfflinePlayer to unload
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
void unload(@NotNull OfflinePlayer offline);
|
||||||
|
|
||||||
|
Logger getLogger();
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal;
|
||||||
|
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public interface IAnySilentContainer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the container at the given coordinates for the Player. If you do not want blocked
|
||||||
|
* containers to open, be sure to check {@link #isAnyContainerNeeded(Player, Block)}
|
||||||
|
* first.
|
||||||
|
*
|
||||||
|
* @param player the Player opening the container
|
||||||
|
* @param silent whether the container's noise is to be silenced
|
||||||
|
* @param block the Block
|
||||||
|
* @return true if the container can be opened
|
||||||
|
*/
|
||||||
|
boolean activateContainer(@NotNull Player player, boolean silent, @NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the Player's currently open container silently, if necessary.
|
||||||
|
*
|
||||||
|
* @param player the Player closing a container
|
||||||
|
*/
|
||||||
|
void deactivateContainer(@NotNull Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the container at the given coordinates is blocked.
|
||||||
|
*
|
||||||
|
* @param player the Player opening the container
|
||||||
|
* @param block the Block
|
||||||
|
* @return true if the container is blocked
|
||||||
|
*/
|
||||||
|
boolean isAnyContainerNeeded(@NotNull Player player, @NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given block is a container which can be unblocked or silenced.
|
||||||
|
*
|
||||||
|
* @param block the BlockState
|
||||||
|
* @return true if the Block is a supported container
|
||||||
|
*/
|
||||||
|
boolean isAnySilentContainer(@NotNull Block block);
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal;
|
||||||
|
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public interface IInventoryAccess {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an ISpecialEnderChest from an Inventory or null if the Inventory is not backed by an
|
||||||
|
* ISpecialEnderChest.
|
||||||
|
*
|
||||||
|
* @param inventory the Inventory
|
||||||
|
* @return the ISpecialEnderChest or null
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@Nullable ISpecialEnderChest getSpecialEnderChest(@NotNull Inventory inventory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an ISpecialPlayerInventory from an Inventory or null if the Inventory is not backed by
|
||||||
|
* an ISpecialPlayerInventory.
|
||||||
|
*
|
||||||
|
* @param inventory the Inventory
|
||||||
|
* @return the ISpecialPlayerInventory or null
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@Nullable ISpecialPlayerInventory getSpecialPlayerInventory(@NotNull Inventory inventory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an Inventory is an ISpecialEnderChest implementation.
|
||||||
|
*
|
||||||
|
* @param inventory the Inventory
|
||||||
|
* @return true if the Inventory is backed by an ISpecialEnderChest
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
boolean isSpecialEnderChest(@NotNull Inventory inventory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an Inventory is an ISpecialPlayerInventory implementation.
|
||||||
|
*
|
||||||
|
* @param inventory the Inventory
|
||||||
|
* @return true if the Inventory is backed by an ISpecialPlayerInventory
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
boolean isSpecialPlayerInventory(@NotNull Inventory inventory);
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal;
|
||||||
|
|
||||||
|
public interface ISpecialEnderChest extends ISpecialInventory {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public interface ISpecialInventory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Inventory associated with this ISpecialInventory.
|
||||||
|
*
|
||||||
|
* @return the Inventory
|
||||||
|
*/
|
||||||
|
@NotNull Inventory getBukkitInventory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Player associated with this ISpecialInventory online.
|
||||||
|
*
|
||||||
|
* @param player the Player coming online
|
||||||
|
*/
|
||||||
|
void setPlayerOnline(@NotNull Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Player associated with this ISpecialInventory offline.
|
||||||
|
*/
|
||||||
|
void setPlayerOffline();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether or not this ISpecialInventory is in use.
|
||||||
|
*
|
||||||
|
* @return true if the ISpecialInventory is in use
|
||||||
|
*/
|
||||||
|
boolean isInUse();
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal;
|
||||||
|
|
||||||
|
public interface ISpecialPlayerInventory extends ISpecialInventory {
|
||||||
|
|
||||||
|
}
|
134
api/src/main/java/com/lishid/openinv/util/InventoryAccess.java
Normal file
134
api/src/main/java/com/lishid/openinv/util/InventoryAccess.java
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
import com.lishid.openinv.internal.IInventoryAccess;
|
||||||
|
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||||
|
import com.lishid.openinv.internal.ISpecialInventory;
|
||||||
|
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class InventoryAccess implements IInventoryAccess {
|
||||||
|
|
||||||
|
private static Class<?> craftInventory = null;
|
||||||
|
private static Method getInventory = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||||
|
try {
|
||||||
|
craftInventory = Class.forName(packageName + ".inventory.CraftInventory");
|
||||||
|
} catch (ClassNotFoundException ignored) {}
|
||||||
|
try {
|
||||||
|
getInventory = craftInventory.getDeclaredMethod("getInventory");
|
||||||
|
} catch (NoSuchMethodException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #isUsable()}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean isUseable() {
|
||||||
|
return isUsable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isUsable() {
|
||||||
|
return craftInventory != null && getInventory != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPlayerInventory(@NotNull Inventory inventory) {
|
||||||
|
return getPlayerInventory(inventory) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable ISpecialPlayerInventory getPlayerInventory(@NotNull Inventory inventory) {
|
||||||
|
return getSpecialInventory(ISpecialPlayerInventory.class, inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnderChest(@NotNull Inventory inventory) {
|
||||||
|
return getEnderChest(inventory) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable ISpecialEnderChest getEnderChest(@NotNull Inventory inventory) {
|
||||||
|
return getSpecialInventory(ISpecialEnderChest.class, inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends ISpecialInventory> @Nullable T getSpecialInventory(@NotNull Class<T> expected, @NotNull Inventory inventory) {
|
||||||
|
Object inv;
|
||||||
|
if (craftInventory != null && getInventory != null && craftInventory.isAssignableFrom(inventory.getClass())) {
|
||||||
|
try {
|
||||||
|
inv = getInventory.invoke(inventory);
|
||||||
|
if (expected.isInstance(inv)) {
|
||||||
|
return expected.cast(inv);
|
||||||
|
}
|
||||||
|
} catch (ReflectiveOperationException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
inv = grabFieldOfTypeFromObject(expected, inventory);
|
||||||
|
|
||||||
|
if (expected.isInstance(inv)) {
|
||||||
|
return expected.cast(inv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> @Nullable T grabFieldOfTypeFromObject(final Class<T> type, final Object object) {
|
||||||
|
// Use reflection to find the IInventory
|
||||||
|
Class<?> clazz = object.getClass();
|
||||||
|
T result = null;
|
||||||
|
for (Field f : clazz.getDeclaredFields()) {
|
||||||
|
f.setAccessible(true);
|
||||||
|
if (type.isAssignableFrom(f.getDeclaringClass())) {
|
||||||
|
try {
|
||||||
|
result = type.cast(f.get(object));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public @Nullable ISpecialEnderChest getSpecialEnderChest(@NotNull Inventory inventory) {
|
||||||
|
return getEnderChest(inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public @Nullable ISpecialPlayerInventory getSpecialPlayerInventory(@NotNull Inventory inventory) {
|
||||||
|
return getPlayerInventory(inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public boolean isSpecialEnderChest(@NotNull Inventory inventory) {
|
||||||
|
return isEnderChest(inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public boolean isSpecialPlayerInventory(@NotNull Inventory inventory) {
|
||||||
|
return isPlayerInventory(inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
150
api/src/main/java/com/lishid/openinv/util/StringMetric.java
Normal file
150
api/src/main/java/com/lishid/openinv/util/StringMetric.java
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
public class StringMetric {
|
||||||
|
|
||||||
|
public static float compareJaroWinkler(String a, String b) {
|
||||||
|
final float jaroScore = compareJaro(a, b);
|
||||||
|
|
||||||
|
if (jaroScore < (float) 0.7) {
|
||||||
|
return jaroScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
String prefix = commonPrefix(a, b);
|
||||||
|
int prefixLength = Math.min(prefix.codePointCount(0, prefix.length()), 4);
|
||||||
|
|
||||||
|
return jaroScore + (prefixLength * (float) 0.1 * (1.0f - jaroScore));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float compareJaro(String a, String b) {
|
||||||
|
if (a.isEmpty() && b.isEmpty()) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.isEmpty() || b.isEmpty()) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int[] charsA = a.codePoints().toArray();
|
||||||
|
final int[] charsB = b.codePoints().toArray();
|
||||||
|
|
||||||
|
// Intentional integer division to round down.
|
||||||
|
final int halfLength = Math.max(0, Math.max(charsA.length, charsB.length) / 2 - 1);
|
||||||
|
|
||||||
|
final int[] commonA = getCommonCodePoints(charsA, charsB, halfLength);
|
||||||
|
final int[] commonB = getCommonCodePoints(charsB, charsA, halfLength);
|
||||||
|
|
||||||
|
// commonA and commonB will always contain the same multi-set of
|
||||||
|
// characters. Because getCommonCharacters has been optimized, commonA
|
||||||
|
// and commonB are -1-padded. So in this loop we count transposition
|
||||||
|
// and use commonCharacters to determine the length of the multi-set.
|
||||||
|
float transpositions = 0;
|
||||||
|
int commonCharacters = 0;
|
||||||
|
for (int length = commonA.length; commonCharacters < length
|
||||||
|
&& commonA[commonCharacters] > -1; commonCharacters++) {
|
||||||
|
if (commonA[commonCharacters] != commonB[commonCharacters]) {
|
||||||
|
transpositions++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commonCharacters == 0) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float aCommonRatio = commonCharacters / (float) charsA.length;
|
||||||
|
float bCommonRatio = commonCharacters / (float) charsB.length;
|
||||||
|
float transpositionRatio = (commonCharacters - transpositions / 2.0f) / commonCharacters;
|
||||||
|
|
||||||
|
return (aCommonRatio + bCommonRatio + transpositionRatio) / 3.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an array of code points from a within b. A character in b is
|
||||||
|
* counted as common when it is within separation distance from the position
|
||||||
|
* in a.
|
||||||
|
*/
|
||||||
|
private static int[] getCommonCodePoints(final int[] charsA, final int[] charsB, final int separation) {
|
||||||
|
final int[] common = new int[Math.min(charsA.length, charsB.length)];
|
||||||
|
final boolean[] matched = new boolean[charsB.length];
|
||||||
|
|
||||||
|
// Iterate of string a and find all characters that occur in b within
|
||||||
|
// the separation distance. Mark any matches found to avoid
|
||||||
|
// duplicate matchings.
|
||||||
|
int commonIndex = 0;
|
||||||
|
for (int i = 0, length = charsA.length; i < length; i++) {
|
||||||
|
final int character = charsA[i];
|
||||||
|
final int index = indexOf(character, charsB, i - separation, i
|
||||||
|
+ separation + 1, matched);
|
||||||
|
if (index > -1) {
|
||||||
|
common[commonIndex++] = character;
|
||||||
|
matched[index] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commonIndex < common.length) {
|
||||||
|
common[commonIndex] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both invocations will yield the same multi-set terminated by -1, so
|
||||||
|
// they can be compared for transposition without making a copy.
|
||||||
|
return common;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for code point in buffer starting at fromIndex to toIndex - 1.
|
||||||
|
*
|
||||||
|
* Returns -1 when not found.
|
||||||
|
*/
|
||||||
|
private static int indexOf(int character, int[] buffer, int fromIndex, int toIndex, boolean[] matched) {
|
||||||
|
|
||||||
|
// compare char with range of characters to either side
|
||||||
|
for (int j = Math.max(0, fromIndex), length = Math.min(toIndex, buffer.length); j < length; j++) {
|
||||||
|
// check if found
|
||||||
|
if (buffer[j] == character && !matched[j]) {
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String commonPrefix(CharSequence a, CharSequence b) {
|
||||||
|
int maxPrefixLength = Math.min(a.length(), b.length());
|
||||||
|
|
||||||
|
int p;
|
||||||
|
|
||||||
|
p = 0;
|
||||||
|
while (p < maxPrefixLength && a.charAt(p) == b.charAt(p)) {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validSurrogatePairAt(a, p - 1) || validSurrogatePairAt(b, p - 1)) {
|
||||||
|
--p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.subSequence(0, p).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean validSurrogatePairAt(CharSequence string, int index) {
|
||||||
|
return index >= 0 && index <= string.length() - 2 && Character.isHighSurrogate(string.charAt(index)) && Character.isLowSurrogate(string.charAt(index + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private StringMetric(){}
|
||||||
|
|
||||||
|
}
|
58
assembly/pom.xml
Normal file
58
assembly/pom.xml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.lishid</groupId>
|
||||||
|
<artifactId>openinvparent</artifactId>
|
||||||
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>openinvassembly</artifactId>
|
||||||
|
<name>OpenInvAssembly</name>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<directory>../target</directory>
|
||||||
|
<finalName>OpenInv</finalName>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>reactor-uberjar</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>src/assembly/reactor-uberjar.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
44
assembly/src/assembly/reactor-uberjar.xml
Normal file
44
assembly/src/assembly/reactor-uberjar.xml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||||
|
|
||||||
|
<id>reactor-uberjar</id>
|
||||||
|
|
||||||
|
<formats>
|
||||||
|
<format>jar</format>
|
||||||
|
</formats>
|
||||||
|
|
||||||
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
|
|
||||||
|
<moduleSets>
|
||||||
|
<moduleSet>
|
||||||
|
|
||||||
|
<useAllReactorProjects>true</useAllReactorProjects>
|
||||||
|
|
||||||
|
<binaries>
|
||||||
|
<outputDirectory>/</outputDirectory>
|
||||||
|
<unpack>true</unpack>
|
||||||
|
<!-- unpackOptions must be present or build breaks. -->
|
||||||
|
<unpackOptions/>
|
||||||
|
</binaries>
|
||||||
|
|
||||||
|
</moduleSet>
|
||||||
|
</moduleSets>
|
||||||
|
|
||||||
|
</assembly>
|
42
internal/pom.xml
Normal file
42
internal/pom.xml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.lishid</groupId>
|
||||||
|
<artifactId>openinvparent</artifactId>
|
||||||
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>openinvinternal</artifactId>
|
||||||
|
<name>OpenInvInternal</name>
|
||||||
|
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>all</id>
|
||||||
|
<modules>
|
||||||
|
<module>v1_16_R3</module>
|
||||||
|
</modules>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
</project>
|
75
internal/v1_16_R3/pom.xml
Normal file
75
internal/v1_16_R3/pom.xml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.lishid</groupId>
|
||||||
|
<artifactId>openinvinternal</artifactId>
|
||||||
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>openinvadapter1_16_R3</artifactId>
|
||||||
|
<name>OpenInvAdapter1_16_R3</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot</artifactId>
|
||||||
|
<version>1.16.5-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lishid</groupId>
|
||||||
|
<artifactId>openinvplugincore</artifactId>
|
||||||
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.2</version>
|
||||||
|
<configuration>
|
||||||
|
<minimizeJar>true</minimizeJar>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal.v1_16_R3;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.internal.IAnySilentContainer;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import net.minecraft.server.v1_16_R3.Block;
|
||||||
|
import net.minecraft.server.v1_16_R3.BlockBarrel;
|
||||||
|
import net.minecraft.server.v1_16_R3.BlockChest;
|
||||||
|
import net.minecraft.server.v1_16_R3.BlockChestTrapped;
|
||||||
|
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||||
|
import net.minecraft.server.v1_16_R3.BlockPropertyChestType;
|
||||||
|
import net.minecraft.server.v1_16_R3.BlockShulkerBox;
|
||||||
|
import net.minecraft.server.v1_16_R3.ChatMessage;
|
||||||
|
import net.minecraft.server.v1_16_R3.Container;
|
||||||
|
import net.minecraft.server.v1_16_R3.ContainerChest;
|
||||||
|
import net.minecraft.server.v1_16_R3.Containers;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityHuman;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||||
|
import net.minecraft.server.v1_16_R3.EnumGamemode;
|
||||||
|
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||||
|
import net.minecraft.server.v1_16_R3.IChatBaseComponent;
|
||||||
|
import net.minecraft.server.v1_16_R3.ITileInventory;
|
||||||
|
import net.minecraft.server.v1_16_R3.InventoryEnderChest;
|
||||||
|
import net.minecraft.server.v1_16_R3.InventoryLargeChest;
|
||||||
|
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
|
||||||
|
import net.minecraft.server.v1_16_R3.PlayerInventory;
|
||||||
|
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||||
|
import net.minecraft.server.v1_16_R3.TileEntityChest;
|
||||||
|
import net.minecraft.server.v1_16_R3.TileEntityEnderChest;
|
||||||
|
import net.minecraft.server.v1_16_R3.TileEntityLootable;
|
||||||
|
import net.minecraft.server.v1_16_R3.TileInventory;
|
||||||
|
import net.minecraft.server.v1_16_R3.World;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Statistic;
|
||||||
|
import org.bukkit.block.Barrel;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.bukkit.block.EnderChest;
|
||||||
|
import org.bukkit.block.ShulkerBox;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.block.data.Directional;
|
||||||
|
import org.bukkit.block.data.type.Chest;
|
||||||
|
import org.bukkit.entity.Cat;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class AnySilentContainer implements IAnySilentContainer {
|
||||||
|
|
||||||
|
private Field playerInteractManagerGamemode;
|
||||||
|
|
||||||
|
public AnySilentContainer() {
|
||||||
|
try {
|
||||||
|
this.playerInteractManagerGamemode = PlayerInteractManager.class.getDeclaredField("gamemode");
|
||||||
|
this.playerInteractManagerGamemode.setAccessible(true);
|
||||||
|
} catch (NoSuchFieldException | SecurityException e) {
|
||||||
|
System.err.println("[OpenInv] Unable to directly write player gamemode! SilentChest will fail.");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAnySilentContainer(@NotNull final org.bukkit.block.Block bukkitBlock) {
|
||||||
|
if (bukkitBlock.getType() == Material.ENDER_CHEST) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
BlockState state = bukkitBlock.getState();
|
||||||
|
return state instanceof org.bukkit.block.Chest
|
||||||
|
|| state instanceof org.bukkit.block.ShulkerBox
|
||||||
|
|| state instanceof org.bukkit.block.Barrel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAnyContainerNeeded(@NotNull final Player p, @NotNull final org.bukkit.block.Block block) {
|
||||||
|
BlockState blockState = block.getState();
|
||||||
|
|
||||||
|
// Barrels do not require AnyContainer.
|
||||||
|
if (blockState instanceof Barrel) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enderchests require a non-occluding block on top to open.
|
||||||
|
if (blockState instanceof EnderChest) {
|
||||||
|
return block.getRelative(0, 1, 0).getType().isOccluding();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shulker boxes require 1/2 a block clear in the direction they open.
|
||||||
|
if (blockState instanceof ShulkerBox) {
|
||||||
|
BoundingBox boundingBox = block.getBoundingBox();
|
||||||
|
if (boundingBox.getVolume() > 1) {
|
||||||
|
// Shulker box is already open.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockData blockData = block.getBlockData();
|
||||||
|
if (!(blockData instanceof Directional)) {
|
||||||
|
// Shouldn't be possible. Just in case, demand AnyChest.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Directional directional = (Directional) blockData;
|
||||||
|
BlockFace face = directional.getFacing();
|
||||||
|
boundingBox.shift(face.getDirection());
|
||||||
|
// Return whether or not bounding boxes overlap.
|
||||||
|
return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(blockState instanceof org.bukkit.block.Chest)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlockedChest(block)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockData blockData = block.getBlockData();
|
||||||
|
if (!(blockData instanceof Chest) || ((Chest) blockData).getType() == Chest.Type.SINGLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chest chest = (Chest) blockData;
|
||||||
|
int ordinal = (chest.getFacing().ordinal() + 4 + (chest.getType() == Chest.Type.RIGHT ? -1 : 1)) % 4;
|
||||||
|
BlockFace relativeFace = BlockFace.values()[ordinal];
|
||||||
|
org.bukkit.block.Block relative = block.getRelative(relativeFace);
|
||||||
|
|
||||||
|
if (relative.getType() != block.getType()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockData relativeData = relative.getBlockData();
|
||||||
|
if (!(relativeData instanceof Chest)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chest relativeChest = (Chest) relativeData;
|
||||||
|
if (relativeChest.getFacing() != chest.getFacing()
|
||||||
|
|| relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isBlockedChest(relative);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedChest(org.bukkit.block.Block block) {
|
||||||
|
org.bukkit.block.Block relative = block.getRelative(0, 1, 0);
|
||||||
|
return relative.getType().isOccluding()
|
||||||
|
|| block.getWorld().getNearbyEntities(BoundingBox.of(relative), entity -> entity instanceof Cat).size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean activateContainer(@NotNull final Player bukkitPlayer, final boolean silentchest,
|
||||||
|
@NotNull final org.bukkit.block.Block bukkitBlock) {
|
||||||
|
|
||||||
|
// Silent ender chest is API-only
|
||||||
|
if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) {
|
||||||
|
bukkitPlayer.openInventory(bukkitPlayer.getEnderChest());
|
||||||
|
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer);
|
||||||
|
|
||||||
|
final World world = player.world;
|
||||||
|
final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());
|
||||||
|
final TileEntity tile = world.getTileEntity(blockPosition);
|
||||||
|
|
||||||
|
if (tile == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tile instanceof TileEntityEnderChest) {
|
||||||
|
// Anychest ender chest. See net.minecraft.server.BlockEnderChest
|
||||||
|
InventoryEnderChest enderChest = player.getEnderChest();
|
||||||
|
enderChest.a((TileEntityEnderChest) tile);
|
||||||
|
player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> {
|
||||||
|
Containers<?> containers = PlayerDataManager.getContainers(enderChest.getSize());
|
||||||
|
int rows = enderChest.getSize() / 9;
|
||||||
|
return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows);
|
||||||
|
}, new ChatMessage("container.enderchest")));
|
||||||
|
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(tile instanceof ITileInventory)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITileInventory tileInventory = (ITileInventory) tile;
|
||||||
|
IBlockData blockData = world.getType(blockPosition);
|
||||||
|
Block block = blockData.getBlock();
|
||||||
|
|
||||||
|
if (block instanceof BlockChest) {
|
||||||
|
|
||||||
|
BlockPropertyChestType chestType = blockData.get(BlockChest.c);
|
||||||
|
|
||||||
|
if (chestType != BlockPropertyChestType.SINGLE) {
|
||||||
|
|
||||||
|
BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.h(blockData));
|
||||||
|
IBlockData adjacentBlockData = world.getType(adjacentBlockPosition);
|
||||||
|
|
||||||
|
if (adjacentBlockData.getBlock() == block) {
|
||||||
|
|
||||||
|
BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.c);
|
||||||
|
|
||||||
|
if (adjacentChestType != BlockPropertyChestType.SINGLE && chestType != adjacentChestType
|
||||||
|
&& adjacentBlockData.get(BlockChest.FACING) == blockData.get(BlockChest.FACING)) {
|
||||||
|
|
||||||
|
TileEntity adjacentTile = world.getTileEntity(adjacentBlockPosition);
|
||||||
|
|
||||||
|
if (adjacentTile instanceof TileEntityChest && tileInventory instanceof TileEntityChest) {
|
||||||
|
TileEntityChest rightChest = chestType == BlockPropertyChestType.RIGHT ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile;
|
||||||
|
TileEntityChest leftChest = chestType == BlockPropertyChestType.RIGHT ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory);
|
||||||
|
|
||||||
|
if (silentchest && (rightChest.lootTable != null || leftChest.lootTable != null)) {
|
||||||
|
OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tileInventory = new ITileInventory() {
|
||||||
|
public Container createMenu(int containerCounter, PlayerInventory playerInventory, EntityHuman entityHuman) {
|
||||||
|
leftChest.d(playerInventory.player);
|
||||||
|
rightChest.d(playerInventory.player);
|
||||||
|
return ContainerChest.b(containerCounter, playerInventory, new InventoryLargeChest(rightChest, leftChest));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IChatBaseComponent getScoreboardDisplayName() {
|
||||||
|
if (leftChest.hasCustomName()) {
|
||||||
|
return leftChest.getScoreboardDisplayName();
|
||||||
|
}
|
||||||
|
if (rightChest.hasCustomName()) {
|
||||||
|
return rightChest.getScoreboardDisplayName();
|
||||||
|
}
|
||||||
|
return new ChatMessage("container.chestDouble");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof BlockChestTrapped) {
|
||||||
|
bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED);
|
||||||
|
} else {
|
||||||
|
bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof BlockShulkerBox) {
|
||||||
|
bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof BlockBarrel) {
|
||||||
|
bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnyChest only - SilentChest not active, container unsupported, or unnecessary.
|
||||||
|
if (!silentchest || player.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR) {
|
||||||
|
player.openContainer(tileInventory);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SilentChest requires access to setting players' gamemode directly.
|
||||||
|
if (this.playerInteractManagerGamemode == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tile instanceof TileEntityLootable) {
|
||||||
|
TileEntityLootable lootable = (TileEntityLootable) tile;
|
||||||
|
if (lootable.lootTable != null) {
|
||||||
|
OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumGamemode gamemode = player.playerInteractManager.getGameMode();
|
||||||
|
this.forceGameMode(player, EnumGamemode.SPECTATOR);
|
||||||
|
player.openContainer(tileInventory);
|
||||||
|
this.forceGameMode(player, gamemode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deactivateContainer(@NotNull final Player bukkitPlayer) {
|
||||||
|
if (this.playerInteractManagerGamemode == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryView view = bukkitPlayer.getOpenInventory();
|
||||||
|
switch (view.getType()) {
|
||||||
|
case CHEST:
|
||||||
|
case ENDER_CHEST:
|
||||||
|
case SHULKER_BOX:
|
||||||
|
case BARREL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer);
|
||||||
|
|
||||||
|
EnumGamemode gamemode = player.playerInteractManager.getGameMode();
|
||||||
|
this.forceGameMode(player, EnumGamemode.SPECTATOR);
|
||||||
|
player.activeContainer.b(player);
|
||||||
|
player.activeContainer.a(player, false);
|
||||||
|
player.activeContainer.transferTo(player.defaultContainer, player.getBukkitEntity());
|
||||||
|
player.activeContainer = player.defaultContainer;
|
||||||
|
this.forceGameMode(player, gamemode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceGameMode(final EntityPlayer player, final EnumGamemode gameMode) {
|
||||||
|
if (this.playerInteractManagerGamemode == null) {
|
||||||
|
// No need to warn repeatedly, error on startup and lack of function should be enough.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!this.playerInteractManagerGamemode.isAccessible()) {
|
||||||
|
// Just in case, ensure accessible.
|
||||||
|
this.playerInteractManagerGamemode.setAccessible(true);
|
||||||
|
}
|
||||||
|
this.playerInteractManagerGamemode.set(player.playerInteractManager, gameMode);
|
||||||
|
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2021 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal.v1_16_R3;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||||
|
import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools;
|
||||||
|
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||||
|
import net.minecraft.server.v1_16_R3.WorldNBTStorage;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
||||||
|
|
||||||
|
public class OpenPlayer extends CraftPlayer {
|
||||||
|
|
||||||
|
public OpenPlayer(CraftServer server, EntityPlayer entity) {
|
||||||
|
super(server, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveData() {
|
||||||
|
super.saveData();
|
||||||
|
EntityPlayer player = this.getHandle();
|
||||||
|
// See net.minecraft.server.WorldNBTStorage#save(EntityPlayer)
|
||||||
|
try {
|
||||||
|
WorldNBTStorage worldNBTStorage = player.server.getPlayerList().playerFileData;
|
||||||
|
|
||||||
|
NBTTagCompound playerData = player.save(new NBTTagCompound());
|
||||||
|
|
||||||
|
if (!isOnline()) {
|
||||||
|
// Special case: save old vehicle data
|
||||||
|
NBTTagCompound oldData = worldNBTStorage.load(player);
|
||||||
|
|
||||||
|
if (oldData != null && oldData.hasKeyOfType("RootVehicle", 10)) {
|
||||||
|
// See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound)
|
||||||
|
playerData.set("RootVehicle", oldData.getCompound("RootVehicle"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat.tmp");
|
||||||
|
File file1 = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat");
|
||||||
|
|
||||||
|
NBTCompressedStreamTools.a(playerData, new FileOutputStream(file));
|
||||||
|
|
||||||
|
if (file1.exists() && !file1.delete() || !file.renameTo(file1)) {
|
||||||
|
LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,237 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal.v1_16_R3;
|
||||||
|
|
||||||
|
import com.lishid.openinv.internal.IPlayerDataManager;
|
||||||
|
import com.lishid.openinv.internal.ISpecialInventory;
|
||||||
|
import com.lishid.openinv.internal.OpenInventoryView;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import net.minecraft.server.v1_16_R3.ChatComponentText;
|
||||||
|
import net.minecraft.server.v1_16_R3.Container;
|
||||||
|
import net.minecraft.server.v1_16_R3.Containers;
|
||||||
|
import net.minecraft.server.v1_16_R3.Entity;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||||
|
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
||||||
|
import net.minecraft.server.v1_16_R3.PacketPlayOutOpenWindow;
|
||||||
|
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
|
||||||
|
import net.minecraft.server.v1_16_R3.World;
|
||||||
|
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class PlayerDataManager implements IPlayerDataManager {
|
||||||
|
|
||||||
|
private @Nullable Field bukkitEntity;
|
||||||
|
|
||||||
|
public PlayerDataManager() {
|
||||||
|
try {
|
||||||
|
bukkitEntity = Entity.class.getDeclaredField("bukkitEntity");
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
System.out.println("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded.");
|
||||||
|
e.printStackTrace();
|
||||||
|
bukkitEntity = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static EntityPlayer getHandle(final Player player) {
|
||||||
|
if (player instanceof CraftPlayer) {
|
||||||
|
return ((CraftPlayer) player).getHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
Server server = player.getServer();
|
||||||
|
EntityPlayer nmsPlayer = null;
|
||||||
|
|
||||||
|
if (server instanceof CraftServer) {
|
||||||
|
nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nmsPlayer == null) {
|
||||||
|
// Could use reflection to examine fields, but it's honestly not worth the bother.
|
||||||
|
throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation");
|
||||||
|
}
|
||||||
|
|
||||||
|
return nmsPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Player loadPlayer(@NotNull final OfflinePlayer offline) {
|
||||||
|
// Ensure player has data
|
||||||
|
if (!offline.hasPlayedBefore()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a profile and entity to load the player data
|
||||||
|
// See net.minecraft.server.PlayerList#attemptLogin
|
||||||
|
GameProfile profile = new GameProfile(offline.getUniqueId(),
|
||||||
|
offline.getName() != null ? offline.getName() : offline.getUniqueId().toString());
|
||||||
|
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
|
||||||
|
WorldServer worldServer = server.getWorldServer(World.OVERWORLD);
|
||||||
|
|
||||||
|
if (worldServer == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityPlayer entity = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer));
|
||||||
|
|
||||||
|
try {
|
||||||
|
injectPlayer(entity);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the bukkit entity
|
||||||
|
Player target = entity.getBukkitEntity();
|
||||||
|
if (target != null) {
|
||||||
|
// Load data
|
||||||
|
target.loadData();
|
||||||
|
}
|
||||||
|
// Return the entity
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void injectPlayer(EntityPlayer player) throws IllegalAccessException {
|
||||||
|
if (bukkitEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bukkitEntity.setAccessible(true);
|
||||||
|
|
||||||
|
bukkitEntity.set(player, new OpenPlayer(player.server.server, player));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Player inject(@NotNull Player player) {
|
||||||
|
try {
|
||||||
|
EntityPlayer nmsPlayer = getHandle(player);
|
||||||
|
injectPlayer(nmsPlayer);
|
||||||
|
return nmsPlayer.getBukkitEntity();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) {
|
||||||
|
|
||||||
|
EntityPlayer nmsPlayer = getHandle(player);
|
||||||
|
|
||||||
|
if (nmsPlayer.playerConnection == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryView view = getView(player, inventory);
|
||||||
|
|
||||||
|
if (view == null) {
|
||||||
|
return player.openInventory(inventory.getBukkitInventory());
|
||||||
|
}
|
||||||
|
|
||||||
|
Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) {
|
||||||
|
@Override
|
||||||
|
public Containers<?> getType() {
|
||||||
|
return getContainers(inventory.getBukkitInventory().getSize());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
container.setTitle(new ChatComponentText(view.getTitle()));
|
||||||
|
container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
|
||||||
|
|
||||||
|
if (container == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
nmsPlayer.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, container.getType(),
|
||||||
|
new ChatComponentText(container.getBukkitView().getTitle())));
|
||||||
|
nmsPlayer.activeContainer = container;
|
||||||
|
container.addSlotListener(nmsPlayer);
|
||||||
|
|
||||||
|
return container.getBukkitView();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) {
|
||||||
|
if (inventory instanceof SpecialEnderChest) {
|
||||||
|
return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest");
|
||||||
|
} else if (inventory instanceof SpecialPlayerInventory) {
|
||||||
|
return new OpenInventoryView(player, inventory, "container.player", "'s Inventory");
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static @NotNull Containers<?> getContainers(int inventorySize) {
|
||||||
|
switch (inventorySize) {
|
||||||
|
case 9:
|
||||||
|
return Containers.GENERIC_9X1;
|
||||||
|
case 18:
|
||||||
|
return Containers.GENERIC_9X2;
|
||||||
|
case 36:
|
||||||
|
return Containers.GENERIC_9X4;
|
||||||
|
case 41: // PLAYER
|
||||||
|
case 45:
|
||||||
|
return Containers.GENERIC_9X5;
|
||||||
|
case 54:
|
||||||
|
return Containers.GENERIC_9X6;
|
||||||
|
case 27:
|
||||||
|
default:
|
||||||
|
return Containers.GENERIC_9X3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int convertToPlayerSlot(InventoryView view, int rawSlot) {
|
||||||
|
int topSize = view.getTopInventory().getSize();
|
||||||
|
if (topSize <= rawSlot) {
|
||||||
|
// Slot is not inside special inventory, use Bukkit logic.
|
||||||
|
return view.convertSlot(rawSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main inventory, slots 0-26 -> 9-35
|
||||||
|
if (rawSlot < 27) {
|
||||||
|
return rawSlot + 9;
|
||||||
|
}
|
||||||
|
// Hotbar, slots 27-35 -> 0-8
|
||||||
|
if (rawSlot < 36) {
|
||||||
|
return rawSlot - 27;
|
||||||
|
}
|
||||||
|
// Armor, slots 36-39 -> 39-36
|
||||||
|
if (rawSlot < 40) {
|
||||||
|
return 36 + (39 - rawSlot);
|
||||||
|
}
|
||||||
|
// Off hand
|
||||||
|
if (rawSlot == 40) {
|
||||||
|
return 40;
|
||||||
|
}
|
||||||
|
// Drop slots, "out of inventory"
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal.v1_16_R3;
|
||||||
|
|
||||||
|
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.server.v1_16_R3.AutoRecipeStackManager;
|
||||||
|
import net.minecraft.server.v1_16_R3.ContainerUtil;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityHuman;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||||
|
import net.minecraft.server.v1_16_R3.IInventoryListener;
|
||||||
|
import net.minecraft.server.v1_16_R3.InventoryEnderChest;
|
||||||
|
import net.minecraft.server.v1_16_R3.ItemStack;
|
||||||
|
import net.minecraft.server.v1_16_R3.NonNullList;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftHumanEntity;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventory;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest {
|
||||||
|
|
||||||
|
private final CraftInventory inventory;
|
||||||
|
private EntityPlayer owner;
|
||||||
|
private NonNullList<ItemStack> items;
|
||||||
|
private boolean playerOnline;
|
||||||
|
|
||||||
|
public SpecialEnderChest(final Player player, final Boolean online) {
|
||||||
|
super(PlayerDataManager.getHandle(player));
|
||||||
|
this.inventory = new CraftInventory(this);
|
||||||
|
this.owner = PlayerDataManager.getHandle(player);
|
||||||
|
this.playerOnline = online;
|
||||||
|
this.items = this.owner.getEnderChest().items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull CraftInventory getBukkitInventory() {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInUse() {
|
||||||
|
return !this.getViewers().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerOffline() {
|
||||||
|
this.playerOnline = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerOnline(@NotNull final Player player) {
|
||||||
|
if (!this.playerOnline) {
|
||||||
|
try {
|
||||||
|
this.owner = PlayerDataManager.getHandle(player);
|
||||||
|
InventoryEnderChest enderChest = owner.getEnderChest();
|
||||||
|
for (int i = 0; i < enderChest.getSize(); ++i) {
|
||||||
|
enderChest.setItem(i, this.items.get(i));
|
||||||
|
}
|
||||||
|
this.items = enderChest.items;
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
this.playerOnline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
this.owner.getEnderChest().update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getContents() {
|
||||||
|
return this.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(CraftHumanEntity who) {
|
||||||
|
this.owner.getEnderChest().onOpen(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose(CraftHumanEntity who) {
|
||||||
|
this.owner.getEnderChest().onClose(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HumanEntity> getViewers() {
|
||||||
|
return this.owner.getEnderChest().getViewers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxStackSize(int i) {
|
||||||
|
this.owner.getEnderChest().setMaxStackSize(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InventoryHolder getOwner() {
|
||||||
|
return this.owner.getEnderChest().getOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Location getLocation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void a(IInventoryListener iinventorylistener) {
|
||||||
|
this.owner.getEnderChest().a(iinventorylistener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void b(IInventoryListener iinventorylistener) {
|
||||||
|
this.owner.getEnderChest().b(iinventorylistener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack getItem(int i) {
|
||||||
|
return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack splitStack(int i, int j) {
|
||||||
|
ItemStack itemstack = ContainerUtil.a(this.items, i, j);
|
||||||
|
if (!itemstack.isEmpty()) {
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemstack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack a(ItemStack itemstack) {
|
||||||
|
ItemStack itemstack1 = itemstack.cloneItemStack();
|
||||||
|
|
||||||
|
for (int i = 0; i < this.getSize(); ++i) {
|
||||||
|
ItemStack itemstack2 = this.getItem(i);
|
||||||
|
if (itemstack2.isEmpty()) {
|
||||||
|
this.setItem(i, itemstack1);
|
||||||
|
this.update();
|
||||||
|
return ItemStack.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ItemStack.c(itemstack2, itemstack1)) {
|
||||||
|
int j = Math.min(this.getMaxStackSize(), itemstack2.getMaxStackSize());
|
||||||
|
int k = Math.min(itemstack1.getCount(), j - itemstack2.getCount());
|
||||||
|
if (k > 0) {
|
||||||
|
itemstack2.add(k);
|
||||||
|
itemstack1.subtract(k);
|
||||||
|
if (itemstack1.isEmpty()) {
|
||||||
|
this.update();
|
||||||
|
return ItemStack.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemstack1.getCount() != itemstack.getCount()) {
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemstack1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack splitWithoutUpdate(int i) {
|
||||||
|
ItemStack itemstack = this.items.get(i);
|
||||||
|
if (itemstack.isEmpty()) {
|
||||||
|
return ItemStack.b;
|
||||||
|
} else {
|
||||||
|
this.items.set(i, ItemStack.b);
|
||||||
|
return itemstack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setItem(int i, ItemStack itemstack) {
|
||||||
|
this.items.set(i, itemstack);
|
||||||
|
if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) {
|
||||||
|
itemstack.setCount(this.getMaxStackSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return this.owner.getEnderChest().getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
|
||||||
|
for (ItemStack itemstack : this.items) {
|
||||||
|
if (!itemstack.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxStackSize() {
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean a(EntityHuman entityhuman) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startOpen(EntityHuman entityhuman) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeContainer(EntityHuman entityhuman) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean b(int i, ItemStack itemstack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
this.items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void a(AutoRecipeStackManager autorecipestackmanager) {
|
||||||
|
|
||||||
|
for (ItemStack itemstack : this.items) {
|
||||||
|
autorecipestackmanager.b(itemstack);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,733 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal.v1_16_R3;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import net.minecraft.server.v1_16_R3.AutoRecipeStackManager;
|
||||||
|
import net.minecraft.server.v1_16_R3.ChatMessage;
|
||||||
|
import net.minecraft.server.v1_16_R3.ContainerUtil;
|
||||||
|
import net.minecraft.server.v1_16_R3.CrashReport;
|
||||||
|
import net.minecraft.server.v1_16_R3.CrashReportSystemDetails;
|
||||||
|
import net.minecraft.server.v1_16_R3.DamageSource;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityHuman;
|
||||||
|
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||||
|
import net.minecraft.server.v1_16_R3.EnumItemSlot;
|
||||||
|
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||||
|
import net.minecraft.server.v1_16_R3.IChatBaseComponent;
|
||||||
|
import net.minecraft.server.v1_16_R3.IInventory;
|
||||||
|
import net.minecraft.server.v1_16_R3.Item;
|
||||||
|
import net.minecraft.server.v1_16_R3.ItemArmor;
|
||||||
|
import net.minecraft.server.v1_16_R3.ItemStack;
|
||||||
|
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||||
|
import net.minecraft.server.v1_16_R3.NBTTagList;
|
||||||
|
import net.minecraft.server.v1_16_R3.NonNullList;
|
||||||
|
import net.minecraft.server.v1_16_R3.PacketPlayOutSetSlot;
|
||||||
|
import net.minecraft.server.v1_16_R3.PlayerInventory;
|
||||||
|
import net.minecraft.server.v1_16_R3.ReportedException;
|
||||||
|
import net.minecraft.server.v1_16_R3.World;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftHumanEntity;
|
||||||
|
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventory;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory {
|
||||||
|
|
||||||
|
private final CraftInventory inventory;
|
||||||
|
private boolean playerOnline;
|
||||||
|
private EntityHuman player;
|
||||||
|
private NonNullList<ItemStack> items, armor, extraSlots;
|
||||||
|
private List<NonNullList<ItemStack>> f;
|
||||||
|
|
||||||
|
public SpecialPlayerInventory(final Player bukkitPlayer, final Boolean online) {
|
||||||
|
super(PlayerDataManager.getHandle(bukkitPlayer));
|
||||||
|
this.inventory = new CraftInventory(this);
|
||||||
|
this.playerOnline = online;
|
||||||
|
this.player = super.player;
|
||||||
|
this.items = this.player.inventory.items;
|
||||||
|
this.armor = this.player.inventory.armor;
|
||||||
|
this.extraSlots = this.player.inventory.extraSlots;
|
||||||
|
this.f = ImmutableList.of(this.items, this.armor, this.extraSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerOnline(@NotNull final Player player) {
|
||||||
|
if (!this.playerOnline) {
|
||||||
|
EntityPlayer entityPlayer = PlayerDataManager.getHandle(player);
|
||||||
|
entityPlayer.inventory.transaction.addAll(this.transaction);
|
||||||
|
this.player = entityPlayer;
|
||||||
|
for (int i = 0; i < getSize(); ++i) {
|
||||||
|
this.player.inventory.setItem(i, getRawItem(i));
|
||||||
|
}
|
||||||
|
this.player.inventory.itemInHandIndex = this.itemInHandIndex;
|
||||||
|
this.items = this.player.inventory.items;
|
||||||
|
this.armor = this.player.inventory.armor;
|
||||||
|
this.extraSlots = this.player.inventory.extraSlots;
|
||||||
|
this.f = ImmutableList.of(this.items, this.armor, this.extraSlots);
|
||||||
|
this.playerOnline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean a(final EntityHuman entityhuman) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull CraftInventory getBukkitInventory() {
|
||||||
|
return this.inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack getItem(int i) {
|
||||||
|
List<ItemStack> list = this.items;
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.armor;
|
||||||
|
} else {
|
||||||
|
i = this.getReversedItemSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.extraSlots;
|
||||||
|
} else if (list == this.armor) {
|
||||||
|
i = this.getReversedArmorSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
return ItemStack.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack getRawItem(int i) {
|
||||||
|
NonNullList<ItemStack> list = null;
|
||||||
|
for (NonNullList<ItemStack> next : this.f) {
|
||||||
|
if (i < next.size()) {
|
||||||
|
list = next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i -= next.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list == null ? ItemStack.b : list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IChatBaseComponent getDisplayName() {
|
||||||
|
return new ChatMessage(this.player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCustomName() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getReversedArmorSlotNum(final int i) {
|
||||||
|
if (i == 0) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (i == 1) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (i == 2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (i == 3) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getReversedItemSlotNum(final int i) {
|
||||||
|
if (i >= 27) {
|
||||||
|
return i - 27;
|
||||||
|
}
|
||||||
|
return i + 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return 45;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInUse() {
|
||||||
|
return !this.getViewers().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setItem(int i, final ItemStack itemstack) {
|
||||||
|
List<ItemStack> list = this.items;
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.armor;
|
||||||
|
} else {
|
||||||
|
i = this.getReversedItemSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.extraSlots;
|
||||||
|
} else if (list == this.armor) {
|
||||||
|
i = this.getReversedArmorSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
this.player.drop(itemstack, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.set(i, itemstack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerOffline() {
|
||||||
|
this.playerOnline = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack splitStack(int i, final int j) {
|
||||||
|
List<ItemStack> list = this.items;
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.armor;
|
||||||
|
} else {
|
||||||
|
i = this.getReversedItemSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.extraSlots;
|
||||||
|
} else if (list == this.armor) {
|
||||||
|
i = this.getReversedArmorSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
return ItemStack.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.get(i).isEmpty() ? ItemStack.b : ContainerUtil.a(list, i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack splitWithoutUpdate(int i) {
|
||||||
|
List<ItemStack> list = this.items;
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.armor;
|
||||||
|
} else {
|
||||||
|
i = this.getReversedItemSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
i -= list.size();
|
||||||
|
list = this.extraSlots;
|
||||||
|
} else if (list == this.armor) {
|
||||||
|
i = this.getReversedArmorSlotNum(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= list.size()) {
|
||||||
|
return ItemStack.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list.get(i).isEmpty()) {
|
||||||
|
ItemStack itemstack = list.get(i);
|
||||||
|
|
||||||
|
list.set(i, ItemStack.b);
|
||||||
|
return itemstack;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ItemStack.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getContents() {
|
||||||
|
return this.f.stream().flatMap(List::stream).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getArmorContents() {
|
||||||
|
return this.armor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(CraftHumanEntity who) {
|
||||||
|
this.transaction.add(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose(CraftHumanEntity who) {
|
||||||
|
this.transaction.remove(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HumanEntity> getViewers() {
|
||||||
|
return this.transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InventoryHolder getOwner() {
|
||||||
|
return this.player.getBukkitEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getLocation() {
|
||||||
|
return this.player.getBukkitEntity().getLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack getItemInHand() {
|
||||||
|
return d(this.itemInHandIndex) ? this.items.get(this.itemInHandIndex) : ItemStack.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSimilarAndNotFull(ItemStack itemstack, ItemStack itemstack1) {
|
||||||
|
return !itemstack.isEmpty() && this.b(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean b(ItemStack itemstack, ItemStack itemstack1) {
|
||||||
|
return itemstack.getItem() == itemstack1.getItem() && ItemStack.equals(itemstack, itemstack1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int canHold(ItemStack itemstack) {
|
||||||
|
int remains = itemstack.getCount();
|
||||||
|
|
||||||
|
for (int i = 0; i < this.items.size(); ++i) {
|
||||||
|
ItemStack itemstack1 = this.getItem(i);
|
||||||
|
if (itemstack1.isEmpty()) {
|
||||||
|
return itemstack.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isSimilarAndNotFull(itemstack, itemstack1)) {
|
||||||
|
remains -= Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize()) - itemstack1.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remains <= 0) {
|
||||||
|
return itemstack.getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack offhandItemStack = this.getItem(this.items.size() + this.armor.size());
|
||||||
|
if (this.isSimilarAndNotFull(offhandItemStack, itemstack)) {
|
||||||
|
remains -= Math.min(offhandItemStack.getMaxStackSize(), this.getMaxStackSize()) - offhandItemStack.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemstack.getCount() - remains;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirstEmptySlotIndex() {
|
||||||
|
for (int i = 0; i < this.items.size(); ++i) {
|
||||||
|
if (this.items.get(i).isEmpty()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void c(int i) {
|
||||||
|
this.itemInHandIndex = this.i();
|
||||||
|
ItemStack itemstack = this.items.get(this.itemInHandIndex);
|
||||||
|
this.items.set(this.itemInHandIndex, this.items.get(i));
|
||||||
|
this.items.set(i, itemstack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int c(ItemStack itemstack) {
|
||||||
|
for (int i = 0; i < this.items.size(); ++i) {
|
||||||
|
ItemStack itemstack1 = this.items.get(i);
|
||||||
|
if (!this.items.get(i).isEmpty() && this.b(itemstack, this.items.get(i)) && !this.items.get(i).f() && !itemstack1.hasEnchantments() && !itemstack1.hasName()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int i() {
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < 9; ++j) {
|
||||||
|
i = (this.itemInHandIndex + j) % 9;
|
||||||
|
if (this.items.get(i).isEmpty()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < 9; ++j) {
|
||||||
|
i = (this.itemInHandIndex + j) % 9;
|
||||||
|
if (!this.items.get(i).hasEnchantments()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.itemInHandIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int a(Predicate<ItemStack> predicate, int i, IInventory iinventory) {
|
||||||
|
byte b0 = 0;
|
||||||
|
boolean flag = i == 0;
|
||||||
|
int j = b0 + ContainerUtil.a(this, predicate, i - b0, flag);
|
||||||
|
j += ContainerUtil.a(iinventory, predicate, i - j, flag);
|
||||||
|
j += ContainerUtil.a(this.getCarried(), predicate, i - j, flag);
|
||||||
|
if (this.getCarried().isEmpty()) {
|
||||||
|
this.setCarried(ItemStack.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int i(ItemStack itemstack) {
|
||||||
|
int i = this.firstPartial(itemstack);
|
||||||
|
if (i == -1) {
|
||||||
|
i = this.getFirstEmptySlotIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
return i == -1 ? itemstack.getCount() : this.d(i, itemstack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int d(int i, ItemStack itemstack) {
|
||||||
|
Item item = itemstack.getItem();
|
||||||
|
int j = itemstack.getCount();
|
||||||
|
ItemStack itemstack1 = this.getItem(i);
|
||||||
|
if (itemstack1.isEmpty()) {
|
||||||
|
itemstack1 = new ItemStack(item, 0);
|
||||||
|
NBTTagCompound tag = itemstack.getTag();
|
||||||
|
if (tag != null) {
|
||||||
|
itemstack1.setTag(tag.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setItem(i, itemstack1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int k = j;
|
||||||
|
if (j > itemstack1.getMaxStackSize() - itemstack1.getCount()) {
|
||||||
|
k = itemstack1.getMaxStackSize() - itemstack1.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k > this.getMaxStackSize() - itemstack1.getCount()) {
|
||||||
|
k = this.getMaxStackSize() - itemstack1.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k != 0) {
|
||||||
|
j -= k;
|
||||||
|
itemstack1.add(k);
|
||||||
|
itemstack1.d(5);
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int firstPartial(ItemStack itemstack) {
|
||||||
|
if (this.isSimilarAndNotFull(this.getItem(this.itemInHandIndex), itemstack)) {
|
||||||
|
return this.itemInHandIndex;
|
||||||
|
} else if (this.isSimilarAndNotFull(this.getItem(40), itemstack)) {
|
||||||
|
return 40;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < this.items.size(); ++i) {
|
||||||
|
if (this.isSimilarAndNotFull(this.items.get(i), itemstack)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void j() {
|
||||||
|
|
||||||
|
for (List<ItemStack> itemStacks : this.f) {
|
||||||
|
for (int i = 0; i < itemStacks.size(); ++i) {
|
||||||
|
if (!itemStacks.get(i).isEmpty()) {
|
||||||
|
itemStacks.get(i).a(this.player.world, this.player, i, this.itemInHandIndex == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pickup(ItemStack itemstack) {
|
||||||
|
return this.c(-1, itemstack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean c(int i, ItemStack itemstack) {
|
||||||
|
if (itemstack.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
if (itemstack.f()) {
|
||||||
|
if (i == -1) {
|
||||||
|
i = this.getFirstEmptySlotIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= 0) {
|
||||||
|
this.items.set(i, itemstack.cloneItemStack());
|
||||||
|
this.items.get(i).d(5);
|
||||||
|
itemstack.setCount(0);
|
||||||
|
return true;
|
||||||
|
} else if (this.player.abilities.canInstantlyBuild) {
|
||||||
|
itemstack.setCount(0);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int j;
|
||||||
|
do {
|
||||||
|
j = itemstack.getCount();
|
||||||
|
if (i == -1) {
|
||||||
|
itemstack.setCount(this.i(itemstack));
|
||||||
|
} else {
|
||||||
|
itemstack.setCount(this.d(i, itemstack));
|
||||||
|
}
|
||||||
|
} while(!itemstack.isEmpty() && itemstack.getCount() < j);
|
||||||
|
|
||||||
|
if (itemstack.getCount() == j && this.player.abilities.canInstantlyBuild) {
|
||||||
|
itemstack.setCount(0);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return itemstack.getCount() < j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable var6) {
|
||||||
|
CrashReport crashreport = CrashReport.a(var6, "Adding item to inventory");
|
||||||
|
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Item being added");
|
||||||
|
crashreportsystemdetails.a("Item ID", Item.getId(itemstack.getItem()));
|
||||||
|
crashreportsystemdetails.a("Item data", itemstack.getDamage());
|
||||||
|
crashreportsystemdetails.a("Item name", () -> itemstack.getName().getString());
|
||||||
|
throw new ReportedException(crashreport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void a(World world, ItemStack itemstack) {
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
while(!itemstack.isEmpty()) {
|
||||||
|
int i = this.firstPartial(itemstack);
|
||||||
|
if (i == -1) {
|
||||||
|
i = this.getFirstEmptySlotIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == -1) {
|
||||||
|
this.player.drop(itemstack, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int j = itemstack.getMaxStackSize() - this.getItem(i).getCount();
|
||||||
|
if (this.c(i, itemstack.cloneAndSubtract(j))) {
|
||||||
|
((EntityPlayer)this.player).playerConnection.sendPacket(new PacketPlayOutSetSlot(-2, i, this.getItem(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void f(ItemStack itemstack) {
|
||||||
|
|
||||||
|
for (List<ItemStack> list : this.f) {
|
||||||
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
|
if (list.get(i) == itemstack) {
|
||||||
|
list.set(i, ItemStack.b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float a(IBlockData iblockdata) {
|
||||||
|
return this.items.get(this.itemInHandIndex).a(iblockdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NBTTagList a(NBTTagList nbttaglist) {
|
||||||
|
NBTTagCompound nbttagcompound;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < this.items.size(); ++i) {
|
||||||
|
if (!this.items.get(i).isEmpty()) {
|
||||||
|
nbttagcompound = new NBTTagCompound();
|
||||||
|
nbttagcompound.setByte("Slot", (byte) i);
|
||||||
|
this.items.get(i).save(nbttagcompound);
|
||||||
|
nbttaglist.add(nbttagcompound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < this.armor.size(); ++i) {
|
||||||
|
if (!this.armor.get(i).isEmpty()) {
|
||||||
|
nbttagcompound = new NBTTagCompound();
|
||||||
|
nbttagcompound.setByte("Slot", (byte) (i + 100));
|
||||||
|
this.armor.get(i).save(nbttagcompound);
|
||||||
|
nbttaglist.add(nbttagcompound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < this.extraSlots.size(); ++i) {
|
||||||
|
if (!this.extraSlots.get(i).isEmpty()) {
|
||||||
|
nbttagcompound = new NBTTagCompound();
|
||||||
|
nbttagcompound.setByte("Slot", (byte) (i + 150));
|
||||||
|
this.extraSlots.get(i).save(nbttagcompound);
|
||||||
|
nbttaglist.add(nbttagcompound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nbttaglist;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void b(NBTTagList nbttaglist) {
|
||||||
|
this.items.clear();
|
||||||
|
this.armor.clear();
|
||||||
|
this.extraSlots.clear();
|
||||||
|
|
||||||
|
for(int i = 0; i < nbttaglist.size(); ++i) {
|
||||||
|
NBTTagCompound nbttagcompound = nbttaglist.getCompound(i);
|
||||||
|
int j = nbttagcompound.getByte("Slot") & 255;
|
||||||
|
ItemStack itemstack = ItemStack.a(nbttagcompound);
|
||||||
|
if (!itemstack.isEmpty()) {
|
||||||
|
if (j < this.items.size()) {
|
||||||
|
this.items.set(j, itemstack);
|
||||||
|
} else if (j >= 100 && j < this.armor.size() + 100) {
|
||||||
|
this.armor.set(j - 100, itemstack);
|
||||||
|
} else if (j >= 150 && j < this.extraSlots.size() + 150) {
|
||||||
|
this.extraSlots.set(j - 150, itemstack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
Iterator<ItemStack> iterator = this.items.iterator();
|
||||||
|
|
||||||
|
ItemStack itemstack;
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
itemstack = iterator.next();
|
||||||
|
if (!itemstack.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator = this.armor.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
itemstack = iterator.next();
|
||||||
|
if (!itemstack.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator = this.extraSlots.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
itemstack = iterator.next();
|
||||||
|
if (!itemstack.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IChatBaseComponent getCustomName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void a(DamageSource damagesource, float f) {
|
||||||
|
if (f > 0.0F) {
|
||||||
|
f /= 4.0F;
|
||||||
|
if (f < 1.0F) {
|
||||||
|
f = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.armor.size(); ++i) {
|
||||||
|
ItemStack itemstack = this.armor.get(0);
|
||||||
|
int index = i;
|
||||||
|
if ((!damagesource.isFire() || !itemstack.getItem().u()) && itemstack.getItem() instanceof ItemArmor) {
|
||||||
|
itemstack.damage((int) f, this.player, (entityHuman) -> entityHuman.broadcastItemBreak(EnumItemSlot.a(EnumItemSlot.Function.ARMOR, index)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dropContents() {
|
||||||
|
for (List<ItemStack> itemStacks : this.f) {
|
||||||
|
for (int i = 0; i < itemStacks.size(); ++i) {
|
||||||
|
ItemStack itemstack = itemStacks.get(i);
|
||||||
|
if (!itemstack.isEmpty()) {
|
||||||
|
itemStacks.set(i, ItemStack.b);
|
||||||
|
this.player.a(itemstack, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean h(ItemStack itemstack) {
|
||||||
|
return this.f.stream().flatMap(List::stream).anyMatch(itemStack1 -> !itemStack1.isEmpty() && itemStack1.doMaterialsMatch(itemstack));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void a(PlayerInventory playerinventory) {
|
||||||
|
for (int i = 0; i < playerinventory.getSize(); ++i) {
|
||||||
|
this.setItem(i, playerinventory.getItem(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.itemInHandIndex = playerinventory.itemInHandIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
this.f.forEach(List::clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void a(AutoRecipeStackManager autorecipestackmanager) {
|
||||||
|
for (ItemStack itemstack : this.items) {
|
||||||
|
autorecipestackmanager.a(itemstack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
80
plugin/pom.xml
Normal file
80
plugin/pom.xml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.lishid</groupId>
|
||||||
|
<artifactId>openinvparent</artifactId>
|
||||||
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>openinvplugincore</artifactId>
|
||||||
|
<name>OpenInvPlugin</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lishid</groupId>
|
||||||
|
<artifactId>openinvapi</artifactId>
|
||||||
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.15.2-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.2</version>
|
||||||
|
<configuration>
|
||||||
|
<minimizeJar>true</minimizeJar>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
567
plugin/src/main/java/com/lishid/openinv/OpenInv.java
Normal file
567
plugin/src/main/java/com/lishid/openinv/OpenInv.java
Normal file
@@ -0,0 +1,567 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.lishid.openinv.commands.ContainerSettingCommand;
|
||||||
|
import com.lishid.openinv.commands.OpenInvCommand;
|
||||||
|
import com.lishid.openinv.commands.SearchContainerCommand;
|
||||||
|
import com.lishid.openinv.commands.SearchEnchantCommand;
|
||||||
|
import com.lishid.openinv.commands.SearchInvCommand;
|
||||||
|
import com.lishid.openinv.internal.IAnySilentContainer;
|
||||||
|
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||||
|
import com.lishid.openinv.internal.ISpecialInventory;
|
||||||
|
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||||
|
import com.lishid.openinv.listeners.InventoryListener;
|
||||||
|
import com.lishid.openinv.listeners.PlayerListener;
|
||||||
|
import com.lishid.openinv.listeners.PluginListener;
|
||||||
|
import com.lishid.openinv.util.Cache;
|
||||||
|
import com.lishid.openinv.util.ConfigUpdater;
|
||||||
|
import com.lishid.openinv.util.InternalAccessor;
|
||||||
|
import com.lishid.openinv.util.LanguageManager;
|
||||||
|
import com.lishid.openinv.util.Permissions;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.PluginCommand;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open other player's inventory
|
||||||
|
*
|
||||||
|
* @author lishid
|
||||||
|
*/
|
||||||
|
public class OpenInv extends JavaPlugin implements IOpenInv {
|
||||||
|
|
||||||
|
private final Map<String, ISpecialPlayerInventory> inventories = new HashMap<>();
|
||||||
|
private final Map<String, ISpecialEnderChest> enderChests = new HashMap<>();
|
||||||
|
private final Multimap<String, Class<? extends Plugin>> pluginUsage = HashMultimap.create();
|
||||||
|
|
||||||
|
private final Cache<String, Player> playerCache = new Cache<>(300000L,
|
||||||
|
value -> {
|
||||||
|
String key = OpenInv.this.getPlayerID(value);
|
||||||
|
|
||||||
|
return OpenInv.this.inventories.containsKey(key)
|
||||||
|
&& OpenInv.this.inventories.get(key).isInUse()
|
||||||
|
|| OpenInv.this.enderChests.containsKey(key)
|
||||||
|
&& OpenInv.this.enderChests.get(key).isInUse()
|
||||||
|
|| OpenInv.this.pluginUsage.containsKey(key);
|
||||||
|
},
|
||||||
|
value -> {
|
||||||
|
String key = OpenInv.this.getPlayerID(value);
|
||||||
|
|
||||||
|
// Check if inventory is stored, and if it is, remove it and eject all viewers
|
||||||
|
if (OpenInv.this.inventories.containsKey(key)) {
|
||||||
|
Inventory inv = OpenInv.this.inventories.remove(key).getBukkitInventory();
|
||||||
|
List<HumanEntity> viewers = inv.getViewers();
|
||||||
|
for (HumanEntity entity : viewers.toArray(new HumanEntity[0])) {
|
||||||
|
entity.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if ender chest is stored, and if it is, remove it and eject all viewers
|
||||||
|
if (OpenInv.this.enderChests.containsKey(key)) {
|
||||||
|
Inventory inv = OpenInv.this.enderChests.remove(key).getBukkitInventory();
|
||||||
|
List<HumanEntity> viewers = inv.getViewers();
|
||||||
|
for (HumanEntity entity : viewers.toArray(new HumanEntity[0])) {
|
||||||
|
entity.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!OpenInv.this.disableSaving() && !value.isOnline()) {
|
||||||
|
value.saveData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private InternalAccessor accessor;
|
||||||
|
private LanguageManager languageManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evicts all viewers lacking cross-world permissions from a Player's inventory.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
*/
|
||||||
|
public void changeWorld(final Player player) {
|
||||||
|
|
||||||
|
String key = this.getPlayerID(player);
|
||||||
|
|
||||||
|
// Check if the player is cached. If not, neither of their inventories is open.
|
||||||
|
if (!this.playerCache.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.inventories.containsKey(key)) {
|
||||||
|
Iterator<HumanEntity> iterator = this.inventories.get(key).getBukkitInventory().getViewers().iterator();
|
||||||
|
//noinspection WhileLoopReplaceableByForEach
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
HumanEntity human = iterator.next();
|
||||||
|
// If player has permission or is in the same world, allow continued access
|
||||||
|
// Just in case, also allow null worlds.
|
||||||
|
if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
human.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.enderChests.containsKey(key)) {
|
||||||
|
Iterator<HumanEntity> iterator = this.enderChests.get(key).getBukkitInventory().getViewers().iterator();
|
||||||
|
//noinspection WhileLoopReplaceableByForEach
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
HumanEntity human = iterator.next();
|
||||||
|
if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
human.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a raw slot number into a player inventory slot number.
|
||||||
|
*
|
||||||
|
* <p>Note that this method is specifically for converting an ISpecialPlayerInventory slot number into a regular
|
||||||
|
* player inventory slot number.
|
||||||
|
*
|
||||||
|
* @param view the open inventory view
|
||||||
|
* @param rawSlot the raw slot in the view
|
||||||
|
* @return the converted slot number
|
||||||
|
*/
|
||||||
|
public int convertToPlayerSlot(InventoryView view, int rawSlot) {
|
||||||
|
return this.accessor.getPlayerDataManager().convertToPlayerSlot(view, rawSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean disableSaving() {
|
||||||
|
return this.getConfig().getBoolean("settings.disable-saving", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public IAnySilentContainer getAnySilentContainer() {
|
||||||
|
return this.accessor.getAnySilentContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getPlayerAnyChestStatus(@NotNull final OfflinePlayer player) {
|
||||||
|
boolean defaultState = false;
|
||||||
|
|
||||||
|
if (player.isOnline()) {
|
||||||
|
Player onlinePlayer = player.getPlayer();
|
||||||
|
if (onlinePlayer != null) {
|
||||||
|
defaultState = Permissions.ANY_DEFAULT.hasPermission(onlinePlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getConfig().getBoolean("toggles.any-chest." + this.getPlayerID(player), defaultState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getPlayerSilentChestStatus(@NotNull final OfflinePlayer offline) {
|
||||||
|
boolean defaultState = false;
|
||||||
|
|
||||||
|
if (offline.isOnline()) {
|
||||||
|
Player onlinePlayer = offline.getPlayer();
|
||||||
|
if (onlinePlayer != null) {
|
||||||
|
defaultState = Permissions.SILENT_DEFAULT.hasPermission(onlinePlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getConfig().getBoolean("toggles.silent-chest." + this.getPlayerID(offline), defaultState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ISpecialEnderChest getSpecialEnderChest(@NotNull final Player player, final boolean online)
|
||||||
|
throws InstantiationException {
|
||||||
|
String id = this.getPlayerID(player);
|
||||||
|
if (this.enderChests.containsKey(id)) {
|
||||||
|
return this.enderChests.get(id);
|
||||||
|
}
|
||||||
|
ISpecialEnderChest inv = this.accessor.newSpecialEnderChest(player, online);
|
||||||
|
this.enderChests.put(id, inv);
|
||||||
|
this.playerCache.put(id, player);
|
||||||
|
return inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ISpecialPlayerInventory getSpecialInventory(@NotNull final Player player, final boolean online)
|
||||||
|
throws InstantiationException {
|
||||||
|
String id = this.getPlayerID(player);
|
||||||
|
if (this.inventories.containsKey(id)) {
|
||||||
|
return this.inventories.get(id);
|
||||||
|
}
|
||||||
|
ISpecialPlayerInventory inv = this.accessor.newSpecialPlayerInventory(player, online);
|
||||||
|
this.inventories.put(id, inv);
|
||||||
|
this.playerCache.put(id, player);
|
||||||
|
return inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupportedVersion() {
|
||||||
|
return this.accessor != null && this.accessor.isSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) {
|
||||||
|
|
||||||
|
String key = this.getPlayerID(offline);
|
||||||
|
if (this.playerCache.containsKey(key)) {
|
||||||
|
return this.playerCache.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = offline.getPlayer();
|
||||||
|
if (player != null) {
|
||||||
|
this.playerCache.put(key, player);
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isSupportedVersion()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Bukkit.isPrimaryThread()) {
|
||||||
|
return this.accessor.getPlayerDataManager().loadPlayer(offline);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Player> future = Bukkit.getScheduler().callSyncMethod(this,
|
||||||
|
() -> OpenInv.this.accessor.getPlayerDataManager().loadPlayer(offline));
|
||||||
|
|
||||||
|
try {
|
||||||
|
player = future.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
this.playerCache.put(key, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) {
|
||||||
|
return this.accessor.getPlayerDataManager().openInventory(player, inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(@NotNull CommandSender sender, @NotNull String key) {
|
||||||
|
String message = this.languageManager.getValue(key, getLocale(sender));
|
||||||
|
|
||||||
|
if (message != null && !message.isEmpty()) {
|
||||||
|
sender.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(@NotNull CommandSender sender, @NotNull String key, String... replacements) {
|
||||||
|
String message = this.languageManager.getValue(key, getLocale(sender), replacements);
|
||||||
|
|
||||||
|
if (message != null && !message.isEmpty()) {
|
||||||
|
sender.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendSystemMessage(@NotNull Player player, @NotNull String key) {
|
||||||
|
String message = this.languageManager.getValue(key, getLocale(player));
|
||||||
|
|
||||||
|
if (message == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newline = message.indexOf('\n');
|
||||||
|
if (newline != -1) {
|
||||||
|
// No newlines in action bar chat.
|
||||||
|
message = message.substring(0, newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getLocalizedMessage(@NotNull CommandSender sender, @NotNull String key) {
|
||||||
|
return this.languageManager.getValue(key, getLocale(sender));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getLocalizedMessage(@NotNull CommandSender sender, @NotNull String key, String... replacements) {
|
||||||
|
return this.languageManager.getValue(key, getLocale(sender), replacements);
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable String getLocale(@NotNull CommandSender sender) {
|
||||||
|
if (sender instanceof Player) {
|
||||||
|
return ((Player) sender).getLocale();
|
||||||
|
} else {
|
||||||
|
return this.getConfig().getString("settings.locale", "en_us");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean notifyAnyChest() {
|
||||||
|
return this.getConfig().getBoolean("notify.any-chest", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean notifySilentChest() {
|
||||||
|
return this.getConfig().getBoolean("notify.silent-chest", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
|
||||||
|
if (this.disableSaving()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isSupportedVersion()) {
|
||||||
|
this.playerCache.invalidateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
|
||||||
|
// Save default configuration if not present.
|
||||||
|
this.saveDefaultConfig();
|
||||||
|
|
||||||
|
// Get plugin manager
|
||||||
|
PluginManager pm = this.getServer().getPluginManager();
|
||||||
|
|
||||||
|
this.accessor = new InternalAccessor(this);
|
||||||
|
|
||||||
|
this.languageManager = new LanguageManager(this, "en_us");
|
||||||
|
|
||||||
|
// Version check
|
||||||
|
if (this.accessor.isSupported()) {
|
||||||
|
// Update existing configuration. May require internal access.
|
||||||
|
new ConfigUpdater(this).checkForUpdates();
|
||||||
|
|
||||||
|
// Register listeners
|
||||||
|
pm.registerEvents(new PlayerListener(this), this);
|
||||||
|
pm.registerEvents(new PluginListener(this), this);
|
||||||
|
pm.registerEvents(new InventoryListener(this), this);
|
||||||
|
|
||||||
|
// Register commands to their executors
|
||||||
|
this.setCommandExecutor(new OpenInvCommand(this), "openinv", "openender");
|
||||||
|
this.setCommandExecutor(new SearchContainerCommand(this), "searchcontainer");
|
||||||
|
this.setCommandExecutor(new SearchInvCommand(this), "searchinv", "searchender");
|
||||||
|
this.setCommandExecutor(new SearchEnchantCommand(this), "searchenchant");
|
||||||
|
this.setCommandExecutor(new ContainerSettingCommand(this), "silentcontainer", "anycontainer");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.sendVersionError(this.getLogger()::warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendVersionError(Consumer<String> messageMethod) {
|
||||||
|
messageMethod.accept("Your server version (" + this.accessor.getVersion() + ") is not supported.");
|
||||||
|
messageMethod.accept("Please obtain an appropriate version here: " + accessor.getReleasesLink());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCommandExecutor(CommandExecutor executor, String... commands) {
|
||||||
|
for (String commandName : commands) {
|
||||||
|
PluginCommand command = this.getCommand(commandName);
|
||||||
|
if (command != null) {
|
||||||
|
command.setExecutor(executor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!this.accessor.isSupported()) {
|
||||||
|
this.sendVersionError(sender::sendMessage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void releaseAllPlayers(final Plugin plugin) {
|
||||||
|
Iterator<Map.Entry<String, Class<? extends Plugin>>> iterator = this.pluginUsage.entries().iterator();
|
||||||
|
|
||||||
|
if (!iterator.hasNext()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, Class<? extends Plugin>> entry = iterator.next(); iterator.hasNext(); entry = iterator.next()) {
|
||||||
|
if (entry.getValue().equals(plugin.getClass())) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void releasePlayer(@NotNull final Player player, @NotNull final Plugin plugin) {
|
||||||
|
String key = this.getPlayerID(player);
|
||||||
|
|
||||||
|
if (!this.pluginUsage.containsEntry(key, plugin.getClass())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pluginUsage.remove(key, plugin.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void retainPlayer(@NotNull final Player player, @NotNull final Plugin plugin) {
|
||||||
|
String key = this.getPlayerID(player);
|
||||||
|
|
||||||
|
if (this.pluginUsage.containsEntry(key, plugin.getClass())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pluginUsage.put(key, plugin.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerAnyChestStatus(@NotNull final OfflinePlayer offline, final boolean status) {
|
||||||
|
this.getConfig().set("toggles.any-chest." + this.getPlayerID(offline), status);
|
||||||
|
this.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for handling a Player going offline.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
public void setPlayerOffline(final Player player) {
|
||||||
|
|
||||||
|
String key = this.getPlayerID(player);
|
||||||
|
|
||||||
|
// Check if the player is cached. If not, neither of their inventories is open.
|
||||||
|
if (!this.playerCache.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace stored player with our own version
|
||||||
|
this.playerCache.put(key, this.accessor.getPlayerDataManager().inject(player));
|
||||||
|
|
||||||
|
if (this.inventories.containsKey(key)) {
|
||||||
|
this.inventories.get(key).setPlayerOffline();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.enderChests.containsKey(key)) {
|
||||||
|
this.enderChests.get(key).setPlayerOffline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for handling a Player coming online.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @throws IllegalStateException if the server version is unsupported
|
||||||
|
*/
|
||||||
|
public void setPlayerOnline(final Player player) {
|
||||||
|
|
||||||
|
String key = this.getPlayerID(player);
|
||||||
|
|
||||||
|
// Check if the player is cached. If not, neither of their inventories is open.
|
||||||
|
if (!this.playerCache.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playerCache.put(key, player);
|
||||||
|
|
||||||
|
if (this.inventories.containsKey(key)) {
|
||||||
|
this.inventories.get(key).setPlayerOnline(player);
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (player.isOnline()) {
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTask(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.enderChests.containsKey(key)) {
|
||||||
|
this.enderChests.get(key).setPlayerOnline(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerSilentChestStatus(@NotNull final OfflinePlayer offline, final boolean status) {
|
||||||
|
this.getConfig().set("toggles.silent-chest." + this.getPlayerID(offline), status);
|
||||||
|
this.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays all applicable help for OpenInv commands.
|
||||||
|
*
|
||||||
|
* @param player the Player to help
|
||||||
|
*/
|
||||||
|
public void showHelp(final Player player) {
|
||||||
|
// Get registered commands
|
||||||
|
for (String commandName : this.getDescription().getCommands().keySet()) {
|
||||||
|
PluginCommand command = this.getCommand(commandName);
|
||||||
|
|
||||||
|
// Ensure command is successfully registered and player can use it
|
||||||
|
if (command == null || !command.testPermissionSilent(player)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send usage
|
||||||
|
player.sendMessage(command.getUsage().replace("<command>", commandName));
|
||||||
|
|
||||||
|
List<String> aliases = command.getAliases();
|
||||||
|
if (aliases.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble alias list
|
||||||
|
StringBuilder aliasBuilder = new StringBuilder(" (aliases: ");
|
||||||
|
for (String alias : aliases) {
|
||||||
|
aliasBuilder.append(alias).append(", ");
|
||||||
|
}
|
||||||
|
aliasBuilder.delete(aliasBuilder.length() - 2, aliasBuilder.length()).append(')');
|
||||||
|
|
||||||
|
// Send all aliases
|
||||||
|
player.sendMessage(aliasBuilder.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unload(@NotNull final OfflinePlayer offline) {
|
||||||
|
this.playerCache.invalidate(this.getPlayerID(offline));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.commands;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.util.TabCompleter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class ContainerSettingCommand implements TabExecutor {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public ContainerSettingCommand(final OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
plugin.sendMessage(sender, "messages.error.consoleUnsupported");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player) sender;
|
||||||
|
boolean any = command.getName().startsWith("any");
|
||||||
|
Predicate<Player> getSetting = any ? plugin::getPlayerAnyChestStatus : plugin::getPlayerSilentChestStatus;
|
||||||
|
BiConsumer<OfflinePlayer, Boolean> setSetting = any ? plugin::setPlayerAnyChestStatus : plugin::setPlayerSilentChestStatus;
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
|
args[0] = args[0].toLowerCase();
|
||||||
|
|
||||||
|
if (args[0].equals("on")) {
|
||||||
|
setSetting.accept(player, true);
|
||||||
|
} else if (args[0].equals("off")) {
|
||||||
|
setSetting.accept(player, false);
|
||||||
|
} else if (!args[0].equals("check")) {
|
||||||
|
// Invalid argument, show usage.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setSetting.accept(player, !getSetting.test(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
String onOff = plugin.getLocalizedMessage(player, getSetting.test(player) ? "messages.info.on" : "messages.info.off");
|
||||||
|
if (onOff == null) {
|
||||||
|
onOff = String.valueOf(getSetting.test(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.sendMessage(sender, "messages.info.settingState","%setting%", any ? "AnyContainer" : "SilentContainer", "%state%", onOff);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!command.testPermissionSilent(sender) || args.length != 1) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return TabCompleter.completeString(args[0], new String[] {"check", "on", "off"});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.commands;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.internal.ISpecialInventory;
|
||||||
|
import com.lishid.openinv.util.Permissions;
|
||||||
|
import com.lishid.openinv.util.TabCompleter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class OpenInvCommand implements TabExecutor {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
private final HashMap<Player, String> openInvHistory = new HashMap<>();
|
||||||
|
private final HashMap<Player, String> openEnderHistory = new HashMap<>();
|
||||||
|
|
||||||
|
public OpenInvCommand(final OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull final CommandSender sender, @NotNull final Command command, @NotNull final String label, @NotNull final String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
plugin.sendMessage(sender, "messages.error.consoleUnsupported");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length > 0 && (args[0].equalsIgnoreCase("help") || args[0].equals("?"))) {
|
||||||
|
this.plugin.showHelp((Player) sender);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Player player = (Player) sender;
|
||||||
|
final boolean openinv = command.getName().equals("openinv");
|
||||||
|
|
||||||
|
// History management
|
||||||
|
String history = (openinv ? this.openInvHistory : this.openEnderHistory).get(player);
|
||||||
|
|
||||||
|
if (history == null || history.isEmpty()) {
|
||||||
|
history = player.getName();
|
||||||
|
(openinv ? this.openInvHistory : this.openEnderHistory).put(player, history);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
// Read from history if target is not named
|
||||||
|
if (args.length < 1) {
|
||||||
|
name = history;
|
||||||
|
} else {
|
||||||
|
name = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final OfflinePlayer offlinePlayer = OpenInvCommand.this.plugin.matchPlayer(name);
|
||||||
|
|
||||||
|
if (offlinePlayer == null || !offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) {
|
||||||
|
plugin.sendMessage(player, "messages.error.invalidPlayer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!player.isOnline()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OpenInvCommand.this.openInventory(player, offlinePlayer, openinv);
|
||||||
|
}
|
||||||
|
}.runTask(OpenInvCommand.this.plugin);
|
||||||
|
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(this.plugin);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openInventory(final Player player, final OfflinePlayer target, boolean openinv) {
|
||||||
|
Player onlineTarget;
|
||||||
|
boolean online = target.isOnline();
|
||||||
|
|
||||||
|
if (!online) {
|
||||||
|
if (Permissions.OPENOFFLINE.hasPermission(player)) {
|
||||||
|
// Try loading the player's data
|
||||||
|
onlineTarget = this.plugin.loadPlayer(target);
|
||||||
|
} else {
|
||||||
|
plugin.sendMessage(player, "messages.error.permissionPlayerOffline");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Permissions.OPENONLINE.hasPermission(player)) {
|
||||||
|
onlineTarget = target.getPlayer();
|
||||||
|
} else {
|
||||||
|
plugin.sendMessage(player, "messages.error.permissionPlayerOnline");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onlineTarget == null) {
|
||||||
|
plugin.sendMessage(player, "messages.error.invalidPlayer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permissions checks
|
||||||
|
if (onlineTarget.equals(player)) {
|
||||||
|
// Inventory: Additional permission required to open own inventory
|
||||||
|
if (openinv && !Permissions.OPENSELF.hasPermission(player)) {
|
||||||
|
plugin.sendMessage(player, "messages.error.permissionOpenSelf");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Enderchest: Additional permission required to open others' ender chests
|
||||||
|
if (!openinv && !Permissions.ENDERCHEST_ALL.hasPermission(player)) {
|
||||||
|
plugin.sendMessage(player, "messages.error.permissionEnderAll");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protected check
|
||||||
|
if (!Permissions.OVERRIDE.hasPermission(player)
|
||||||
|
&& Permissions.EXEMPT.hasPermission(onlineTarget)) {
|
||||||
|
plugin.sendMessage(player, "messages.error.permissionExempt",
|
||||||
|
"%target%", onlineTarget.getDisplayName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crossworld check
|
||||||
|
if (!Permissions.CROSSWORLD.hasPermission(player)
|
||||||
|
&& !onlineTarget.getWorld().equals(player.getWorld())) {
|
||||||
|
plugin.sendMessage(player, "messages.error.permissionCrossWorld",
|
||||||
|
"%target%", onlineTarget.getDisplayName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the target
|
||||||
|
(openinv ? this.openInvHistory : this.openEnderHistory).put(player, this.plugin.getPlayerID(target));
|
||||||
|
|
||||||
|
// Create the inventory
|
||||||
|
final ISpecialInventory inv;
|
||||||
|
try {
|
||||||
|
inv = openinv ? this.plugin.getSpecialInventory(onlineTarget, online) : this.plugin.getSpecialEnderChest(onlineTarget, online);
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.sendMessage(player, "messages.error.commandException");
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the inventory
|
||||||
|
plugin.openInventory(player, inv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!command.testPermissionSilent(sender) || args.length != 1) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return TabCompleter.completeOnlinePlayer(sender, args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.commands;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.util.TabCompleter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for searching containers in a radius of chunks.
|
||||||
|
*/
|
||||||
|
public class SearchContainerCommand implements TabExecutor {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public SearchContainerCommand(OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
plugin.sendMessage(sender, "messages.error.consoleUnsupported");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 1) {
|
||||||
|
// Must supply material
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material material = Material.getMaterial(args[0].toUpperCase());
|
||||||
|
|
||||||
|
if (material == null) {
|
||||||
|
plugin.sendMessage(sender, "messages.error.invalidMaterial", "%target%", args[0]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius = 5;
|
||||||
|
|
||||||
|
if (args.length > 1) {
|
||||||
|
try {
|
||||||
|
radius = Integer.parseInt(args[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// Invalid radius supplied
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Player senderPlayer = (Player) sender;
|
||||||
|
World world = senderPlayer.getWorld();
|
||||||
|
Chunk centerChunk = senderPlayer.getLocation().getChunk();
|
||||||
|
StringBuilder locations = new StringBuilder();
|
||||||
|
|
||||||
|
for (int dX = -radius; dX <= radius; ++dX) {
|
||||||
|
for (int dZ = -radius; dZ <= radius; ++dZ) {
|
||||||
|
if (!world.loadChunk(centerChunk.getX() + dX, centerChunk.getZ() + dZ, false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Chunk chunk = world.getChunkAt(centerChunk.getX() + dX, centerChunk.getZ() + dZ);
|
||||||
|
for (BlockState tileEntity : chunk.getTileEntities()) {
|
||||||
|
if (!(tileEntity instanceof InventoryHolder)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
InventoryHolder holder = (InventoryHolder) tileEntity;
|
||||||
|
if (!holder.getInventory().contains(material)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
locations.append(holder.getInventory().getType().name().toLowerCase()).append(" (")
|
||||||
|
.append(tileEntity.getX()).append(',').append(tileEntity.getY()).append(',')
|
||||||
|
.append(tileEntity.getZ()).append("), ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches found, delete trailing comma and space
|
||||||
|
if (locations.length() > 0) {
|
||||||
|
locations.delete(locations.length() - 2, locations.length());
|
||||||
|
} else {
|
||||||
|
plugin.sendMessage(sender, "messages.info.container.noMatches",
|
||||||
|
"%target%", material.name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.sendMessage(sender, "messages.info.container.matches",
|
||||||
|
"%target%", material.name(), "%detail%", locations.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
|
||||||
|
if (args.length < 1 || args.length > 2 || !command.testPermissionSilent(sender)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String argument = args[args.length - 1];
|
||||||
|
if (args.length == 1) {
|
||||||
|
return TabCompleter.completeEnum(argument, Material.class);
|
||||||
|
} else {
|
||||||
|
return TabCompleter.completeInteger(argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.commands;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.util.TabCompleter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command adding the ability to search online players' inventories for enchantments of a specific
|
||||||
|
* type at or above the level specified.
|
||||||
|
*
|
||||||
|
* @author Jikoo
|
||||||
|
*/
|
||||||
|
public class SearchEnchantCommand implements TabExecutor {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public SearchEnchantCommand(OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (args.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enchantment enchant = null;
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
for (String argument : args) {
|
||||||
|
try {
|
||||||
|
level = Integer.parseInt(argument);
|
||||||
|
continue;
|
||||||
|
} catch (NumberFormatException ignored) {}
|
||||||
|
|
||||||
|
argument = argument.toLowerCase();
|
||||||
|
int colon = argument.indexOf(':');
|
||||||
|
NamespacedKey key;
|
||||||
|
try {
|
||||||
|
if (colon > -1 && colon < argument.length() - 1) {
|
||||||
|
key = new NamespacedKey(argument.substring(0, colon), argument.substring(colon + 1));
|
||||||
|
} else {
|
||||||
|
key = NamespacedKey.minecraft(argument);
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enchantment localEnchant = Enchantment.getByKey(key);
|
||||||
|
if (localEnchant != null) {
|
||||||
|
enchant = localEnchant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arguments not set correctly
|
||||||
|
if (level == 0 && enchant == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder players = new StringBuilder();
|
||||||
|
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||||
|
boolean flagInventory = containsEnchantment(player.getInventory(), enchant, level);
|
||||||
|
boolean flagEnder = containsEnchantment(player.getEnderChest(), enchant, level);
|
||||||
|
|
||||||
|
// No matches, continue
|
||||||
|
if (!flagInventory && !flagEnder) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches, append details
|
||||||
|
players.append(player.getName()).append(" (");
|
||||||
|
if (flagInventory) {
|
||||||
|
players.append("inv");
|
||||||
|
}
|
||||||
|
if (flagEnder) {
|
||||||
|
if (flagInventory) {
|
||||||
|
players.append(',');
|
||||||
|
}
|
||||||
|
players.append("ender");
|
||||||
|
}
|
||||||
|
players.append("), ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (players.length() > 0) {
|
||||||
|
// Matches found, delete trailing comma and space
|
||||||
|
players.delete(players.length() - 2, players.length());
|
||||||
|
} else {
|
||||||
|
plugin.sendMessage(sender, "messages.info.player.noMatches",
|
||||||
|
"%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.sendMessage(sender, "messages.info.player.matches",
|
||||||
|
"%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level,
|
||||||
|
"%detail%", players.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsEnchantment(Inventory inventory, @Nullable Enchantment enchant, int minLevel) {
|
||||||
|
for (ItemStack item : inventory.getContents()) {
|
||||||
|
//noinspection ConstantConditions // Spigot improperly annotated, should be ItemStack @NotNull []
|
||||||
|
if (item == null || item.getType() == Material.AIR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (enchant != null) {
|
||||||
|
if (item.containsEnchantment(enchant) && item.getEnchantmentLevel(enchant) >= minLevel) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!item.hasItemMeta()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null || !meta.hasEnchants()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int enchLevel : meta.getEnchants().values()) {
|
||||||
|
if (enchLevel >= minLevel) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!command.testPermissionSilent(sender) || args.length < 1 || args.length > 2) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
return TabCompleter.completeObject(args[0], enchantment -> enchantment.getKey().toString(), Enchantment.values());
|
||||||
|
} else {
|
||||||
|
return TabCompleter.completeInteger(args[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.commands;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.util.TabCompleter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class SearchInvCommand implements TabExecutor {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public SearchInvCommand(OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
|
||||||
|
Material material = null;
|
||||||
|
|
||||||
|
if (args.length >= 1) {
|
||||||
|
material = Material.getMaterial(args[0].toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (material == null) {
|
||||||
|
plugin.sendMessage(sender, "messages.error.invalidMaterial", "%target%", args.length > 0 ? args[0] : "null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
if (args.length >= 2) {
|
||||||
|
try {
|
||||||
|
count = Integer.parseInt(args[1]);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
plugin.sendMessage(sender, "messages.error.invalidNumber", "%target%", args[1]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder players = new StringBuilder();
|
||||||
|
boolean searchInv = command.getName().equals("searchinv");
|
||||||
|
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||||
|
Inventory inventory = searchInv ? player.getInventory() : player.getEnderChest();
|
||||||
|
if (inventory.contains(material, count)) {
|
||||||
|
players.append(player.getName()).append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches found, delete trailing comma and space
|
||||||
|
if (players.length() > 0) {
|
||||||
|
players.delete(players.length() - 2, players.length());
|
||||||
|
} else {
|
||||||
|
plugin.sendMessage(sender, "messages.info.player.noMatches",
|
||||||
|
"%target%", material.name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.sendMessage(sender, "messages.info.player.matches",
|
||||||
|
"%target%", material.name(), "%detail%", players.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (args.length < 1 || args.length > 2 || !command.testPermissionSilent(sender)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String argument = args[args.length - 1];
|
||||||
|
if (args.length == 1) {
|
||||||
|
return TabCompleter.completeEnum(argument, Material.class);
|
||||||
|
} else {
|
||||||
|
return TabCompleter.completeInteger(argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal;
|
||||||
|
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public interface IPlayerDataManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a Player for an OfflinePlayer.
|
||||||
|
* </p>
|
||||||
|
* This method is potentially blocking, and should not be called on the main thread.
|
||||||
|
*
|
||||||
|
* @param offline the OfflinePlayer
|
||||||
|
* @return the Player loaded
|
||||||
|
*/
|
||||||
|
@Nullable Player loadPlayer(@NotNull OfflinePlayer offline);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Player from an existing one that will function slightly better offline.
|
||||||
|
*
|
||||||
|
* @return the Player
|
||||||
|
*/
|
||||||
|
@NotNull Player inject(@NotNull Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an ISpecialInventory for a Player.
|
||||||
|
*
|
||||||
|
* @param player the Player opening the ISpecialInventory
|
||||||
|
* @param inventory the Inventory
|
||||||
|
*`
|
||||||
|
* @return the InventoryView opened
|
||||||
|
*/
|
||||||
|
@Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a raw slot number into a player inventory slot number.
|
||||||
|
*
|
||||||
|
* <p>Note that this method is specifically for converting an ISpecialPlayerInventory slot number into a regular
|
||||||
|
* player inventory slot number.
|
||||||
|
*
|
||||||
|
* @param view the open inventory view
|
||||||
|
* @param rawSlot the raw slot in the view
|
||||||
|
* @return the converted slot number
|
||||||
|
*/
|
||||||
|
int convertToPlayerSlot(InventoryView view, int rawSlot);
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2021 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.internal;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class OpenInventoryView extends InventoryView {
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
|
private final ISpecialInventory inventory;
|
||||||
|
private final String titleKey;
|
||||||
|
private final String titleDefaultSuffix;
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
public OpenInventoryView(Player player, ISpecialInventory inventory, String titleKey, String titleDefaultSuffix) {
|
||||||
|
this.player = player;
|
||||||
|
this.inventory = inventory;
|
||||||
|
this.titleKey = titleKey;
|
||||||
|
this.titleDefaultSuffix = titleDefaultSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Inventory getTopInventory() {
|
||||||
|
return inventory.getBukkitInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Inventory getBottomInventory() {
|
||||||
|
return getPlayer().getInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull HumanEntity getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull InventoryType getType() {
|
||||||
|
return inventory.getBukkitInventory().getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getTitle() {
|
||||||
|
if (title == null) {
|
||||||
|
HumanEntity owner = getPlayer();
|
||||||
|
|
||||||
|
String localTitle = OpenInv.getPlugin(OpenInv.class)
|
||||||
|
.getLocalizedMessage(
|
||||||
|
owner,
|
||||||
|
titleKey,
|
||||||
|
"%player%",
|
||||||
|
owner.getName());
|
||||||
|
if (localTitle != null) {
|
||||||
|
title = localTitle;
|
||||||
|
} else {
|
||||||
|
title = owner.getName() + titleDefaultSuffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.listeners;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||||
|
import com.lishid.openinv.util.InventoryAccess;
|
||||||
|
import com.lishid.openinv.util.Permissions;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.inventory.InventoryAction;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryInteractEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for inventory-related events to prevent modification of inventories where not allowed.
|
||||||
|
*
|
||||||
|
* @author Jikoo
|
||||||
|
*/
|
||||||
|
public class InventoryListener implements Listener {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public InventoryListener(final OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInventoryClose(@NotNull final InventoryCloseEvent event) {
|
||||||
|
if (!(event.getPlayer() instanceof Player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player) event.getPlayer();
|
||||||
|
|
||||||
|
if (this.plugin.getPlayerSilentChestStatus(player)) {
|
||||||
|
this.plugin.getAnySilentContainer().deactivateContainer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onInventoryClick(@NotNull final InventoryClickEvent event) {
|
||||||
|
if (handleInventoryInteract(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe cast - has to be a player to be the holder of a special player inventory.
|
||||||
|
Player player = (Player) event.getWhoClicked();
|
||||||
|
|
||||||
|
if (event.getAction() != InventoryAction.MOVE_TO_OTHER_INVENTORY) {
|
||||||
|
// All own-inventory interactions require updates to display properly.
|
||||||
|
// Update in same tick after event completion.
|
||||||
|
this.plugin.getServer().getScheduler().runTask(this.plugin, player::updateInventory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extra handling for MOVE_TO_OTHER_INVENTORY - apparently Mojang no longer removes the item from the target
|
||||||
|
// inventory prior to adding it to existing stacks.
|
||||||
|
ItemStack currentItem = event.getCurrentItem();
|
||||||
|
if (currentItem == null) {
|
||||||
|
// Other plugin doing some sort of handling (would be NOTHING for null item otherwise), ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack clone = currentItem.clone();
|
||||||
|
event.setCurrentItem(null);
|
||||||
|
|
||||||
|
// Complete add action in same tick after event completion.
|
||||||
|
this.plugin.getServer().getScheduler().runTask(this.plugin, () -> {
|
||||||
|
player.getInventory().addItem(clone);
|
||||||
|
player.updateInventory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onInventoryDrag(@NotNull final InventoryDragEvent event) {
|
||||||
|
if (handleInventoryInteract(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryView view = event.getView();
|
||||||
|
int topSize = view.getTopInventory().getSize();
|
||||||
|
|
||||||
|
// Get bottom inventory active slots as player inventory slots.
|
||||||
|
Set<Integer> slots = event.getRawSlots().stream()
|
||||||
|
.filter(slot -> slot >= topSize)
|
||||||
|
.map(slot -> plugin.convertToPlayerSlot(view, slot)).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
int overlapLosses = 0;
|
||||||
|
|
||||||
|
// Count overlapping slots.
|
||||||
|
for (Map.Entry<Integer, ItemStack> newItem : event.getNewItems().entrySet()) {
|
||||||
|
int rawSlot = newItem.getKey();
|
||||||
|
|
||||||
|
// Skip bottom inventory slots.
|
||||||
|
if (rawSlot >= topSize) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convertedSlot = plugin.convertToPlayerSlot(view, rawSlot);
|
||||||
|
|
||||||
|
if (slots.contains(convertedSlot)) {
|
||||||
|
overlapLosses += getCountDiff(view.getItem(rawSlot), newItem.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow no overlap to proceed as usual.
|
||||||
|
if (overlapLosses < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack cursor = event.getCursor();
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.setAmount(cursor.getAmount() + overlapLosses);
|
||||||
|
} else {
|
||||||
|
cursor = event.getOldCursor().clone();
|
||||||
|
cursor.setAmount(overlapLosses);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.setCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCountDiff(@Nullable ItemStack original, @NotNull ItemStack result) {
|
||||||
|
if (original == null || original.getType() != result.getType()) {
|
||||||
|
return result.getAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.getAmount() - original.getAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle common InventoryInteractEvent functions.
|
||||||
|
*
|
||||||
|
* @param event the InventoryInteractEvent
|
||||||
|
* @return true unless the top inventory is the holder's own inventory
|
||||||
|
*/
|
||||||
|
private boolean handleInventoryInteract(@NotNull final InventoryInteractEvent event) {
|
||||||
|
HumanEntity entity = event.getWhoClicked();
|
||||||
|
|
||||||
|
// Un-cancel spectator interactions.
|
||||||
|
if (Permissions.SPECTATE.hasPermission(entity) && entity.getGameMode() == GameMode.SPECTATOR) {
|
||||||
|
event.setCancelled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory inventory = event.getView().getTopInventory();
|
||||||
|
|
||||||
|
// Is the inventory a special ender chest?
|
||||||
|
if (InventoryAccess.isEnderChest(inventory)) {
|
||||||
|
// Disallow ender chest interaction for users without edit permission.
|
||||||
|
if (!Permissions.EDITENDER.hasPermission(entity)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISpecialPlayerInventory playerInventory = InventoryAccess.getPlayerInventory(inventory);
|
||||||
|
|
||||||
|
// Ignore inventories other than special player inventories.
|
||||||
|
if (playerInventory == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallow player inventory interaction for users without edit permission.
|
||||||
|
if (!Permissions.EDITINV.hasPermission(entity)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only specially handle actions in the player's own inventory.
|
||||||
|
return !event.getWhoClicked().equals(event.getView().getTopInventory().getHolder());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.listeners;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import com.lishid.openinv.util.Permissions;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event.Result;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
public class PlayerListener implements Listener {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public PlayerListener(OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||||
|
plugin.setPlayerOnline(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
plugin.setPlayerOffline(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onWorldChange(PlayerChangedWorldEvent event) {
|
||||||
|
plugin.changeWorld(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
|
|
||||||
|
// Do not cancel 3rd party plugins' custom events
|
||||||
|
if (!PlayerInteractEvent.class.equals(event.getClass())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getPlayer().isSneaking()
|
||||||
|
|| event.useInteractedBlock() == Result.DENY || event.getClickedBlock() == null
|
||||||
|
|| !plugin.getAnySilentContainer().isAnySilentContainer(event.getClickedBlock())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
boolean any = Permissions.ANYCHEST.hasPermission(player) && plugin.getPlayerAnyChestStatus(player);
|
||||||
|
boolean needsAny = plugin.getAnySilentContainer().isAnyContainerNeeded(player, event.getClickedBlock());
|
||||||
|
|
||||||
|
if (!any && needsAny) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean silent = Permissions.SILENT.hasPermission(player) && plugin.getPlayerSilentChestStatus(player);
|
||||||
|
|
||||||
|
// If anycontainer or silentcontainer is active
|
||||||
|
if (any || silent) {
|
||||||
|
if (plugin.getAnySilentContainer().activateContainer(player, silent, event.getClickedBlock())) {
|
||||||
|
if (silent && plugin.notifySilentChest() && needsAny && plugin.notifyAnyChest()) {
|
||||||
|
plugin.sendSystemMessage(player, "messages.info.containerBlockedSilent");
|
||||||
|
} else if (needsAny && plugin.notifyAnyChest()) {
|
||||||
|
plugin.sendSystemMessage(player, "messages.info.containerBlocked");
|
||||||
|
} else if (silent && plugin.notifySilentChest()) {
|
||||||
|
plugin.sendSystemMessage(player, "messages.info.containerSilent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.listeners;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.server.PluginDisableEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for plugin-related events.
|
||||||
|
*
|
||||||
|
* @author Jikoo
|
||||||
|
*/
|
||||||
|
public class PluginListener implements Listener {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public PluginListener(OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPluginDisable(PluginDisableEvent event) {
|
||||||
|
plugin.releaseAllPlayers(event.getPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
187
plugin/src/main/java/com/lishid/openinv/util/Cache.java
Normal file
187
plugin/src/main/java/com/lishid/openinv/util/Cache.java
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.collect.TreeMultimap;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A minimal thread-safe time-based cache implementation backed by a HashMap and TreeMultimap.
|
||||||
|
*
|
||||||
|
* @author Jikoo
|
||||||
|
*/
|
||||||
|
public class Cache<K, V> {
|
||||||
|
|
||||||
|
private final Map<K, V> internal;
|
||||||
|
private final Multimap<Long, K> expiry;
|
||||||
|
private final long retention;
|
||||||
|
private final Predicate<V> inUseCheck;
|
||||||
|
private final Consumer<V> postRemoval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Cache with the specified retention duration, in use function, and post-removal function.
|
||||||
|
*
|
||||||
|
* @param retention duration after which keys are automatically invalidated if not in use
|
||||||
|
* @param inUseCheck Predicate used to check if a key is considered in use
|
||||||
|
* @param postRemoval Consumer used to perform any operations required when a key is invalidated
|
||||||
|
*/
|
||||||
|
public Cache(final long retention, final Predicate<V> inUseCheck, final Consumer<V> postRemoval) {
|
||||||
|
this.internal = new HashMap<>();
|
||||||
|
|
||||||
|
this.expiry = TreeMultimap.create(Long::compareTo, (k1, k2) -> Objects.equals(k1, k2) ? 0 : 1);
|
||||||
|
|
||||||
|
this.retention = retention;
|
||||||
|
this.inUseCheck = inUseCheck;
|
||||||
|
this.postRemoval = postRemoval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a key and value pair. Keys are unique. Using an existing key will cause the old value to
|
||||||
|
* be overwritten and the expiration timer to be reset.
|
||||||
|
*
|
||||||
|
* @param key key with which the specified value is to be associated
|
||||||
|
* @param value value to be associated with the specified key
|
||||||
|
*/
|
||||||
|
public void put(final K key, final V value) {
|
||||||
|
// Invalidate key - runs lazy check and ensures value won't be cleaned up early
|
||||||
|
this.invalidate(key);
|
||||||
|
|
||||||
|
synchronized (this.internal) {
|
||||||
|
this.internal.put(key, value);
|
||||||
|
this.expiry.put(System.currentTimeMillis() + this.retention, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value to which the specified key is mapped, or null if no value is mapped for the key.
|
||||||
|
*
|
||||||
|
* @param key the key whose associated value is to be returned
|
||||||
|
* @return the value to which the specified key is mapped, or null if no value is mapped for the key
|
||||||
|
*/
|
||||||
|
public V get(final K key) {
|
||||||
|
// Run lazy check to clean cache
|
||||||
|
this.lazyCheck();
|
||||||
|
|
||||||
|
synchronized (this.internal) {
|
||||||
|
return this.internal.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the specified key is mapped to a value.
|
||||||
|
*
|
||||||
|
* @param key key to check if a mapping exists for
|
||||||
|
* @return true if a mapping exists for the specified key
|
||||||
|
*/
|
||||||
|
public boolean containsKey(final K key) {
|
||||||
|
// Run lazy check to clean cache
|
||||||
|
this.lazyCheck();
|
||||||
|
|
||||||
|
synchronized (this.internal) {
|
||||||
|
return this.internal.containsKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcibly invalidates a key, even if it is considered to be in use.
|
||||||
|
*
|
||||||
|
* @param key key to invalidate
|
||||||
|
*/
|
||||||
|
public void invalidate(final K key) {
|
||||||
|
// Run lazy check to clean cache
|
||||||
|
this.lazyCheck();
|
||||||
|
|
||||||
|
synchronized (this.internal) {
|
||||||
|
if (!this.internal.containsKey(key)) {
|
||||||
|
// Value either not present or cleaned by lazy check. Either way, we're good
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stored object
|
||||||
|
this.internal.remove(key);
|
||||||
|
|
||||||
|
// Remove expiration entry - prevents more work later, plus prevents issues with values invalidating early
|
||||||
|
for (Iterator<Map.Entry<Long, K>> iterator = this.expiry.entries().iterator(); iterator.hasNext();) {
|
||||||
|
if (key.equals(iterator.next().getValue())) {
|
||||||
|
iterator.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcibly invalidates all keys, even if they are considered to be in use.
|
||||||
|
*/
|
||||||
|
public void invalidateAll() {
|
||||||
|
synchronized (this.internal) {
|
||||||
|
for (V value : this.internal.values()) {
|
||||||
|
this.postRemoval.accept(value);
|
||||||
|
}
|
||||||
|
this.expiry.clear();
|
||||||
|
this.internal.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate all expired keys that are not considered in use. If a key is expired but is
|
||||||
|
* considered in use by the provided Function, its expiration time is reset.
|
||||||
|
*/
|
||||||
|
private void lazyCheck() {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
synchronized (this.internal) {
|
||||||
|
List<K> inUse = new ArrayList<>();
|
||||||
|
for (Iterator<Map.Entry<Long, K>> iterator = this.expiry.entries().iterator(); iterator
|
||||||
|
.hasNext();) {
|
||||||
|
Map.Entry<Long, K> entry = iterator.next();
|
||||||
|
|
||||||
|
if (entry.getKey() > now) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator.remove();
|
||||||
|
|
||||||
|
if (this.inUseCheck.test(this.internal.get(entry.getValue()))) {
|
||||||
|
inUse.add(entry.getValue());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
V value = this.internal.remove(entry.getValue());
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.postRemoval.accept(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
long nextExpiry = now + this.retention;
|
||||||
|
for (K value : inUse) {
|
||||||
|
this.expiry.put(nextExpiry, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
147
plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java
Normal file
147
plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
|
public class ConfigUpdater {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
|
||||||
|
public ConfigUpdater(OpenInv plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkForUpdates() {
|
||||||
|
final int version = plugin.getConfig().getInt("config-version", 1);
|
||||||
|
ConfigurationSection defaults = plugin.getConfig().getDefaults();
|
||||||
|
if (defaults == null || version >= defaults.getInt("config-version")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getLogger().info("Configuration update found! Performing update...");
|
||||||
|
|
||||||
|
// Backup the old config file
|
||||||
|
try {
|
||||||
|
plugin.getConfig().save(new File(plugin.getDataFolder(), "config_old.yml"));
|
||||||
|
plugin.getLogger().info("Backed up config.yml to config_old.yml before updating.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().warning("Could not back up config.yml before updating!");
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
if (version < 2) {
|
||||||
|
updateConfig1To2();
|
||||||
|
}
|
||||||
|
if (version < 3) {
|
||||||
|
updateConfig2To3();
|
||||||
|
}
|
||||||
|
if (version < 4) {
|
||||||
|
updateConfig3To4();
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||||
|
plugin.saveConfig();
|
||||||
|
plugin.getLogger().info("Configuration update complete!");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfig3To4() {
|
||||||
|
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||||
|
plugin.getConfig().set("notify", null);
|
||||||
|
plugin.getConfig().set("settings.locale", "en_US");
|
||||||
|
plugin.getConfig().set("config-version", 4);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfig2To3() {
|
||||||
|
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||||
|
plugin.getConfig().set("config-version", 3);
|
||||||
|
plugin.getConfig().set("items.open-inv", null);
|
||||||
|
plugin.getConfig().set("ItemOpenInv", null);
|
||||||
|
plugin.getConfig().set("toggles.items.open-inv", null);
|
||||||
|
plugin.getConfig().set("settings.disable-saving",
|
||||||
|
plugin.getConfig().getBoolean("DisableSaving", false));
|
||||||
|
plugin.getConfig().set("DisableSaving", null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfig1To2() {
|
||||||
|
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||||
|
// Get the old config settings
|
||||||
|
boolean notifySilentChest = plugin.getConfig().getBoolean("NotifySilentChest", true);
|
||||||
|
boolean notifyAnyChest = plugin.getConfig().getBoolean("NotifyAnyChest", true);
|
||||||
|
plugin.getConfig().set("ItemOpenInvItemID", null);
|
||||||
|
plugin.getConfig().set("NotifySilentChest", null);
|
||||||
|
plugin.getConfig().set("NotifyAnyChest", null);
|
||||||
|
plugin.getConfig().set("config-version", 2);
|
||||||
|
plugin.getConfig().set("notify.any-chest", notifyAnyChest);
|
||||||
|
plugin.getConfig().set("notify.silent-chest", notifySilentChest);
|
||||||
|
});
|
||||||
|
|
||||||
|
updateToggles("AnyChest", "toggles.any-chest");
|
||||||
|
updateToggles("SilentChest", "toggles.silent-chest");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateToggles(final String sectionName, final String newSectionName) {
|
||||||
|
ConfigurationSection section = plugin.getConfig().getConfigurationSection(sectionName);
|
||||||
|
// Ensure section exists
|
||||||
|
if (section == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> keys = section.getKeys(false);
|
||||||
|
|
||||||
|
// Ensure section has content
|
||||||
|
if (keys.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, Boolean> toggles = new HashMap<>();
|
||||||
|
|
||||||
|
for (String playerName : keys) {
|
||||||
|
OfflinePlayer player = plugin.matchPlayer(playerName);
|
||||||
|
if (player != null) {
|
||||||
|
toggles.put(plugin.getPlayerID(player), section.getBoolean(playerName + ".toggle", false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||||
|
// Wipe old ConfigurationSection
|
||||||
|
plugin.getConfig().set(sectionName, null);
|
||||||
|
|
||||||
|
// Prepare new ConfigurationSection
|
||||||
|
ConfigurationSection newSection = plugin.getConfig().getConfigurationSection(newSectionName);
|
||||||
|
if (newSection == null) {
|
||||||
|
newSection = plugin.getConfig().createSection(newSectionName);
|
||||||
|
}
|
||||||
|
// Set new values
|
||||||
|
for (Map.Entry<String, Boolean> entry : toggles.entrySet()) {
|
||||||
|
newSection.set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
import com.lishid.openinv.internal.IAnySilentContainer;
|
||||||
|
import com.lishid.openinv.internal.IPlayerDataManager;
|
||||||
|
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||||
|
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class InternalAccessor {
|
||||||
|
|
||||||
|
private final Plugin plugin;
|
||||||
|
private final String version;
|
||||||
|
private boolean supported = false;
|
||||||
|
private IPlayerDataManager playerDataManager;
|
||||||
|
private IAnySilentContainer anySilentContainer;
|
||||||
|
|
||||||
|
public InternalAccessor(final Plugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
String packageName = plugin.getServer().getClass().getPackage().getName();
|
||||||
|
this.version = packageName.substring(packageName.lastIndexOf('.') + 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialPlayerInventory");
|
||||||
|
Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialEnderChest");
|
||||||
|
this.playerDataManager = this.createObject(IPlayerDataManager.class, "PlayerDataManager");
|
||||||
|
this.anySilentContainer = this.createObject(IAnySilentContainer.class, "AnySilentContainer");
|
||||||
|
this.supported = InventoryAccess.isUsable();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReleasesLink() {
|
||||||
|
switch (version) {
|
||||||
|
case "1_4_5":
|
||||||
|
case "1_4_6":
|
||||||
|
case "v1_4_R1":
|
||||||
|
case "v1_5_R2":
|
||||||
|
case "v1_5_R3":
|
||||||
|
case "v1_6_R1":
|
||||||
|
case "v1_6_R2":
|
||||||
|
case "v1_6_R3":
|
||||||
|
case "v1_7_R1":
|
||||||
|
case "v1_7_R2":
|
||||||
|
case "v1_7_R3":
|
||||||
|
case "v1_7_R4":
|
||||||
|
case "v1_8_R1":
|
||||||
|
case "v1_8_R2":
|
||||||
|
case "v1_9_R1":
|
||||||
|
case "v1_9_R2":
|
||||||
|
case "v1_10_R1":
|
||||||
|
case "v1_11_R1":
|
||||||
|
case "v1_12_R1":
|
||||||
|
return "https://github.com/lishid/OpenInv/releases/tag/4.0.0 (OpenInv-legacy)";
|
||||||
|
case "v1_13_R1":
|
||||||
|
return "https://github.com/lishid/OpenInv/releases/tag/4.0.0";
|
||||||
|
case "v1_13_R2":
|
||||||
|
return "https://github.com/lishid/OpenInv/releases/tag/4.0.7";
|
||||||
|
case "v1_14_R1":
|
||||||
|
return "https://github.com/lishid/OpenInv/releases/tag/4.1.1";
|
||||||
|
case "v1_16_R1":
|
||||||
|
return "https://github.com/lishid/OpenInv/releases/tag/4.1.4";
|
||||||
|
case "v1_8_R3":
|
||||||
|
case "v1_15_R1":
|
||||||
|
case "v1_16_R2":
|
||||||
|
return "https://github.com/lishid/OpenInv/releases/tag/4.1.5";
|
||||||
|
case "v1_16_R3":
|
||||||
|
default:
|
||||||
|
return "https://github.com/lishid/OpenInv/releases";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T createObject(final Class<? extends T> assignableClass, final String className,
|
||||||
|
final Object... params) throws ClassCastException, ClassNotFoundException,
|
||||||
|
InstantiationException, IllegalAccessException, IllegalArgumentException,
|
||||||
|
InvocationTargetException, NoSuchMethodException, SecurityException {
|
||||||
|
// Fetch internal class if it exists.
|
||||||
|
Class<?> internalClass = Class.forName("com.lishid.openinv.internal." + this.version + "." + className);
|
||||||
|
if (!assignableClass.isAssignableFrom(internalClass)) {
|
||||||
|
String message = String.format("Found class %s but cannot cast to %s!", internalClass.getName(), assignableClass.getName());
|
||||||
|
this.plugin.getLogger().warning(message);
|
||||||
|
throw new IllegalStateException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick return: no parameters, no need to fiddle about finding the correct constructor.
|
||||||
|
if (params.length == 0) {
|
||||||
|
return assignableClass.cast(internalClass.getConstructor().newInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search constructors for one matching the given parameters
|
||||||
|
nextConstructor: for (Constructor<?> constructor : internalClass.getConstructors()) {
|
||||||
|
Class<?>[] requiredClasses = constructor.getParameterTypes();
|
||||||
|
if (requiredClasses.length != params.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < params.length; ++i) {
|
||||||
|
if (!requiredClasses[i].isAssignableFrom(params[i].getClass())) {
|
||||||
|
continue nextConstructor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assignableClass.cast(constructor.newInstance(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder("Found class ").append(internalClass.getName())
|
||||||
|
.append(" but cannot find any matching constructors for [");
|
||||||
|
for (Object object : params) {
|
||||||
|
builder.append(object.getClass().getName()).append(", ");
|
||||||
|
}
|
||||||
|
builder.delete(builder.length() - 2, builder.length());
|
||||||
|
|
||||||
|
String message = builder.append(']').toString();
|
||||||
|
this.plugin.getLogger().warning(message);
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the IAnySilentContainer implementation for the current server version.
|
||||||
|
*
|
||||||
|
* @return the IAnySilentContainer
|
||||||
|
* @throws IllegalStateException if server version is unsupported
|
||||||
|
*/
|
||||||
|
public IAnySilentContainer getAnySilentContainer() {
|
||||||
|
if (!this.supported) {
|
||||||
|
throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
|
||||||
|
}
|
||||||
|
return this.anySilentContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the IPlayerDataManager implementation for the current server version.
|
||||||
|
*
|
||||||
|
* @return the IPlayerDataManager
|
||||||
|
* @throws IllegalStateException if server version is unsupported
|
||||||
|
*/
|
||||||
|
public IPlayerDataManager getPlayerDataManager() {
|
||||||
|
if (!this.supported) {
|
||||||
|
throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
|
||||||
|
}
|
||||||
|
return this.playerDataManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server implementation version. If not initialized, returns the string "null"
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* @return the version, or "null"
|
||||||
|
*/
|
||||||
|
public String getVersion() {
|
||||||
|
return this.version != null ? this.version : "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the server implementation is supported.
|
||||||
|
*
|
||||||
|
* @return true if initialized for a supported server version
|
||||||
|
*/
|
||||||
|
public boolean isSupported() {
|
||||||
|
return this.supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the ISpecialEnderChest implementation for the given Player, or
|
||||||
|
* null if the current version is unsupported.
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @param online true if the Player is online
|
||||||
|
* @return the ISpecialEnderChest created
|
||||||
|
* @throws InstantiationException if the ISpecialEnderChest could not be instantiated
|
||||||
|
*/
|
||||||
|
public ISpecialEnderChest newSpecialEnderChest(final Player player, final boolean online) throws InstantiationException {
|
||||||
|
if (!this.supported) {
|
||||||
|
throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return this.createObject(ISpecialEnderChest.class, "SpecialEnderChest", player, online);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InstantiationException(String.format("Unable to create a new ISpecialEnderChest: %s", e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the ISpecialPlayerInventory implementation for the given Player..
|
||||||
|
*
|
||||||
|
* @param player the Player
|
||||||
|
* @param online true if the Player is online
|
||||||
|
* @return the ISpecialPlayerInventory created
|
||||||
|
* @throws InstantiationException if the ISpecialPlayerInventory could not be instantiated
|
||||||
|
*/
|
||||||
|
public ISpecialPlayerInventory newSpecialPlayerInventory(final Player player, final boolean online) throws InstantiationException {
|
||||||
|
if (!this.supported) {
|
||||||
|
throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return this.createObject(ISpecialPlayerInventory.class, "SpecialPlayerInventory", player, online);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InstantiationException(String.format("Unable to create a new ISpecialPlayerInventory: %s", e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 Jikoo. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
import com.lishid.openinv.OpenInv;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple language manager supporting both custom and bundled languages.
|
||||||
|
*
|
||||||
|
* @author Jikoo
|
||||||
|
*/
|
||||||
|
public class LanguageManager {
|
||||||
|
|
||||||
|
private final OpenInv plugin;
|
||||||
|
private final String defaultLocale;
|
||||||
|
private final Map<String, YamlConfiguration> locales;
|
||||||
|
|
||||||
|
public LanguageManager(@NotNull OpenInv plugin, @NotNull String defaultLocale) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.defaultLocale = defaultLocale;
|
||||||
|
this.locales = new HashMap<>();
|
||||||
|
getOrLoadLocale(defaultLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private YamlConfiguration getOrLoadLocale(@NotNull String locale) {
|
||||||
|
YamlConfiguration loaded = locales.get(locale);
|
||||||
|
if (loaded != null) {
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream resourceStream = plugin.getResource(locale + ".yml");
|
||||||
|
YamlConfiguration localeConfigDefaults;
|
||||||
|
if (resourceStream == null) {
|
||||||
|
localeConfigDefaults = new YamlConfiguration();
|
||||||
|
} else {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream))) {
|
||||||
|
localeConfigDefaults = YamlConfiguration.loadConfiguration(reader);
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to load resource " + locale + ".yml", e);
|
||||||
|
localeConfigDefaults = new YamlConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(plugin.getDataFolder(), locale + ".yml");
|
||||||
|
YamlConfiguration localeConfig;
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
localeConfig = localeConfigDefaults;
|
||||||
|
try {
|
||||||
|
localeConfigDefaults.save(file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to save resource " + locale + ".yml", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
localeConfig = YamlConfiguration.loadConfiguration(file);
|
||||||
|
|
||||||
|
// Add new language keys
|
||||||
|
List<String> newKeys = new ArrayList<>();
|
||||||
|
for (String key : localeConfigDefaults.getKeys(true)) {
|
||||||
|
if (localeConfigDefaults.isConfigurationSection(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localeConfig.isSet(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
localeConfig.set(key, localeConfigDefaults.get(key));
|
||||||
|
newKeys.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newKeys.isEmpty()) {
|
||||||
|
plugin.getLogger().info("[LanguageManager] Added new language keys: " + String.join(", ", newKeys));
|
||||||
|
try {
|
||||||
|
localeConfig.save(file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to save resource " + locale + ".yml", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!locale.equals(defaultLocale)) {
|
||||||
|
localeConfigDefaults = locales.get(defaultLocale);
|
||||||
|
|
||||||
|
// Check for missing keys
|
||||||
|
List<String> newKeys = new ArrayList<>();
|
||||||
|
for (String key : localeConfigDefaults.getKeys(true)) {
|
||||||
|
if (localeConfigDefaults.isConfigurationSection(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localeConfig.isSet(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newKeys.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newKeys.isEmpty()) {
|
||||||
|
plugin.getLogger().info("[LanguageManager] Missing translations from " + locale + ".yml: " + String.join(", ", newKeys));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall through to default locale
|
||||||
|
localeConfig.setDefaults(localeConfigDefaults);
|
||||||
|
}
|
||||||
|
|
||||||
|
locales.put(locale, localeConfig);
|
||||||
|
return localeConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getValue(@NotNull String key, @Nullable String locale) {
|
||||||
|
String value = getOrLoadLocale(locale == null ? defaultLocale : locale.toLowerCase()).getString(key);
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = ChatColor.translateAlternateColorCodes('&', value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getValue(@NotNull String key, @Nullable String locale, @NotNull String... replacements) {
|
||||||
|
if (replacements.length % 2 != 0) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "[LanguageManager] Replacement data is uneven", new Exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = getValue(key, locale);
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < replacements.length; i += 2) {
|
||||||
|
value = value.replace(replacements[i], replacements[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
import org.bukkit.permissions.Permissible;
|
||||||
|
|
||||||
|
public enum Permissions {
|
||||||
|
|
||||||
|
OPENINV("openinv"),
|
||||||
|
OVERRIDE("override"),
|
||||||
|
EXEMPT("exempt"),
|
||||||
|
CROSSWORLD("crossworld"),
|
||||||
|
SILENT("silent"),
|
||||||
|
SILENT_DEFAULT("silent.default", true),
|
||||||
|
ANYCHEST("anychest"),
|
||||||
|
ANY_DEFAULT("any.default", true),
|
||||||
|
ENDERCHEST("openender"),
|
||||||
|
ENDERCHEST_ALL("openenderall"),
|
||||||
|
SEARCH("search"),
|
||||||
|
EDITINV("editinv"),
|
||||||
|
EDITENDER("editender"),
|
||||||
|
OPENSELF("openself"),
|
||||||
|
OPENONLINE("openonline"),
|
||||||
|
OPENOFFLINE("openoffline"),
|
||||||
|
SPECTATE("spectate");
|
||||||
|
|
||||||
|
private final String permission;
|
||||||
|
private final boolean uninheritable;
|
||||||
|
|
||||||
|
Permissions(String permission) {
|
||||||
|
this(permission, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Permissions(String permission, boolean uninheritable) {
|
||||||
|
this.permission = "OpenInv." + permission;
|
||||||
|
this.uninheritable = uninheritable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(Permissible permissible) {
|
||||||
|
|
||||||
|
boolean hasPermission = permissible.hasPermission(permission);
|
||||||
|
if (uninheritable || hasPermission || permissible.isPermissionSet(permission)) {
|
||||||
|
return hasPermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder permissionDestroyer = new StringBuilder(permission);
|
||||||
|
for (int lastPeriod = permissionDestroyer.lastIndexOf("."); lastPeriod > 0;
|
||||||
|
lastPeriod = permissionDestroyer.lastIndexOf(".")) {
|
||||||
|
permissionDestroyer.delete(lastPeriod + 1, permissionDestroyer.length()).append('*');
|
||||||
|
|
||||||
|
hasPermission = permissible.hasPermission(permissionDestroyer.toString());
|
||||||
|
if (hasPermission || permissible.isPermissionSet(permissionDestroyer.toString())) {
|
||||||
|
return hasPermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionDestroyer.delete(lastPeriod, permissionDestroyer.length());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissible.hasPermission("*");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
147
plugin/src/main/java/com/lishid/openinv/util/TabCompleter.java
Normal file
147
plugin/src/main/java/com/lishid/openinv/util/TabCompleter.java
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.lishid.openinv.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for common tab completions.
|
||||||
|
*/
|
||||||
|
public class TabCompleter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer tab completions for whole numbers.
|
||||||
|
*
|
||||||
|
* @param argument the argument to complete
|
||||||
|
* @return integer options
|
||||||
|
*/
|
||||||
|
public static List<String> completeInteger(String argument) {
|
||||||
|
// Ensure existing argument is actually a number
|
||||||
|
if (!argument.isEmpty()) {
|
||||||
|
try {
|
||||||
|
Integer.parseInt(argument);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> completions = new ArrayList<>(10);
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
completions.add(argument + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer tab completions for a given Enum.
|
||||||
|
*
|
||||||
|
* @param argument the argument to complete
|
||||||
|
* @param enumClazz the Enum to complete for
|
||||||
|
* @return the matching Enum values
|
||||||
|
*/
|
||||||
|
public static List<String> completeEnum(String argument, Class<? extends Enum<?>> enumClazz) {
|
||||||
|
argument = argument.toLowerCase(Locale.ENGLISH);
|
||||||
|
List<String> completions = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Enum<?> enumConstant : enumClazz.getEnumConstants()) {
|
||||||
|
String name = enumConstant.name().toLowerCase();
|
||||||
|
if (name.startsWith(argument)) {
|
||||||
|
completions.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer tab completions for a given array of Strings.
|
||||||
|
*
|
||||||
|
* @param argument the argument to complete
|
||||||
|
* @param options the Strings which may be completed
|
||||||
|
* @return the matching Strings
|
||||||
|
*/
|
||||||
|
public static List<String> completeString(String argument, String[] options) {
|
||||||
|
argument = argument.toLowerCase(Locale.ENGLISH);
|
||||||
|
List<String> completions = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String option : options) {
|
||||||
|
if (option.startsWith(argument)) {
|
||||||
|
completions.add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer tab completions for visible online Players' names.
|
||||||
|
*
|
||||||
|
* @param sender the command's sender
|
||||||
|
* @param argument the argument to complete
|
||||||
|
* @return the matching Players' names
|
||||||
|
*/
|
||||||
|
public static List<String> completeOnlinePlayer(CommandSender sender, String argument) {
|
||||||
|
List<String> completions = new ArrayList<>();
|
||||||
|
Player senderPlayer = sender instanceof Player ? (Player) sender : null;
|
||||||
|
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (senderPlayer != null && !senderPlayer.canSee(player)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtil.startsWithIgnoreCase(player.getName(), argument)) {
|
||||||
|
completions.add(player.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer tab completions for a given array of Objects.
|
||||||
|
*
|
||||||
|
* @param argument the argument to complete
|
||||||
|
* @param converter the Function for converting the Object into a comparable String
|
||||||
|
* @param options the Objects which may be completed
|
||||||
|
* @return the matching Strings
|
||||||
|
*/
|
||||||
|
public static <T> List<String> completeObject(String argument, Function<T, String> converter, T[] options) {
|
||||||
|
argument = argument.toLowerCase(Locale.ENGLISH);
|
||||||
|
List<String> completions = new ArrayList<>();
|
||||||
|
|
||||||
|
for (T option : options) {
|
||||||
|
String optionString = converter.apply(option).toLowerCase();
|
||||||
|
if (optionString.startsWith(argument)) {
|
||||||
|
completions.add(optionString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TabCompleter() {}
|
||||||
|
|
||||||
|
}
|
4
plugin/src/main/resources/config.yml
Normal file
4
plugin/src/main/resources/config.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
config-version: 4
|
||||||
|
settings:
|
||||||
|
disable-saving: false
|
||||||
|
locale: 'en_us'
|
30
plugin/src/main/resources/de_de.yml
Normal file
30
plugin/src/main/resources/de_de.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
messages:
|
||||||
|
error:
|
||||||
|
consoleUnsupported: 'Du kannst diesen Befehl nicht von der Konsole ausführen.'
|
||||||
|
lootNotGenerated: '&cBeute noch nicht erstellt! Bitte schalte &b/silentcontainer&c aus.'
|
||||||
|
invalidMaterial: '&cUngültiges Material: "%target%"'
|
||||||
|
invalidNumber: '&cUngültige Nummer: "%target%"'
|
||||||
|
invalidPlayer: '&cSpieler nicht gefunden.'
|
||||||
|
permissionOpenSelf: '&cDu darfst dein eigenes Inventar nicht öffnen.'
|
||||||
|
permissionEnderAll: '&cDu darfst die Endertruhen von anderen Spielern nicht öffnen.'
|
||||||
|
permissionExempt: '&c%target%''s Inventar ist geschützt.'
|
||||||
|
permissionCrossWorld: '&c%target% ist nicht in der selben Welt wie du.'
|
||||||
|
permissionPlayerOnline: '&cDu darfst keine Inventare von Spielern öffnen, die online sind.'
|
||||||
|
permissionPlayerOffline: '&cDu darfst keine Inventare von Spielern öffnen, die offline sind.'
|
||||||
|
commandException: '&cAn error occurred. Please check console for details.'
|
||||||
|
info:
|
||||||
|
containerBlocked: 'Du öffnest einen gesperrten Container.'
|
||||||
|
containerBlockedSilent: 'Du öffnest einen gesperrten Container lautlos.'
|
||||||
|
containerSilent: 'Du öffnest einen Container lautlos.'
|
||||||
|
settingState: '%setting%: %state%'
|
||||||
|
player:
|
||||||
|
noMatches: 'Keine Spieler mit %target% gefunden.'
|
||||||
|
matches: 'Spieler hält %target%: %detail%'
|
||||||
|
container:
|
||||||
|
noMatches: 'Keine Container mit %target% gefunden.'
|
||||||
|
matches: 'Container hat %target%: %detail%'
|
||||||
|
on: 'an'
|
||||||
|
off: 'aus'
|
||||||
|
container:
|
||||||
|
player: '%player%''s Inventar'
|
||||||
|
enderchest: '%player%''s Endertruhe'
|
30
plugin/src/main/resources/en_us.yml
Normal file
30
plugin/src/main/resources/en_us.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
messages:
|
||||||
|
error:
|
||||||
|
consoleUnsupported: 'You cannot use this command from console.'
|
||||||
|
lootNotGenerated: '&cLoot not generated! Please disable &b/silentcontainer&c.'
|
||||||
|
invalidMaterial: '&cInvalid material: "%target%"'
|
||||||
|
invalidNumber: '&cInvalid number: "%target%"'
|
||||||
|
invalidPlayer: '&cPlayer not found!'
|
||||||
|
permissionOpenSelf: '&cYou''re not allowed to open your own inventory.'
|
||||||
|
permissionEnderAll: '&cYou''re not allowed to access other players'' ender chests.'
|
||||||
|
permissionExempt: '&c%target%''s inventory is protected.'
|
||||||
|
permissionCrossWorld: '&c%target% is not in your world.'
|
||||||
|
permissionPlayerOnline: '&cYou''re not allowed to open the inventory of online players.'
|
||||||
|
permissionPlayerOffline: '&cYou''re not allowed to open the inventory of offline players.'
|
||||||
|
commandException: '&cAn error occurred. Please check console for details.'
|
||||||
|
info:
|
||||||
|
containerBlocked: 'You are opening a blocked container.'
|
||||||
|
containerBlockedSilent: 'You are opening a blocked container silently.'
|
||||||
|
containerSilent: 'You are opening a container silently.'
|
||||||
|
settingState: '%setting%: %state%'
|
||||||
|
player:
|
||||||
|
noMatches: 'No players found with %target%.'
|
||||||
|
matches: 'Players holding %target%: %detail%'
|
||||||
|
container:
|
||||||
|
noMatches: 'No containers found with %target%.'
|
||||||
|
matches: 'Containers holding %target%: %detail%'
|
||||||
|
on: 'on'
|
||||||
|
off: 'off'
|
||||||
|
container:
|
||||||
|
player: '%player%''s Inventory'
|
||||||
|
enderchest: '%player%''s Ender Chest'
|
31
plugin/src/main/resources/es_es.yml
Normal file
31
plugin/src/main/resources/es_es.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
messages:
|
||||||
|
error:
|
||||||
|
consoleUnsupported: 'No puedes usar este comando desde la consola.'
|
||||||
|
lootNotGenerated: '&c¡Botín no generado! Desactiva &b/silentcontainer&c.'
|
||||||
|
invalidMaterial: '&cMaterial no válido: "%target%"'
|
||||||
|
invalidNumber: '&cNúmero no válido: "%target%"'
|
||||||
|
invalidPlayer: '&cJugador no encontrado'
|
||||||
|
permissionOpenSelf: '&cNo tienes permisos para abrir tu inventario de esa forma.'
|
||||||
|
permissionEnderAll: '&cNo tienes permiso para abrir cofres de ender de otros jugadores.'
|
||||||
|
permissionExempt: '&c El inventario de %target% está protegido.'
|
||||||
|
permissionCrossWorld: '&c%target% no está en tu dimensión.'
|
||||||
|
permissionPlayerOnline: '&cNo estás autorizado para abrir inventarios de jugadores conectados.'
|
||||||
|
permissionPlayerOffline: '&cNo estás autorizado para abrir inventarios de jugadores desconectados.'
|
||||||
|
commandException: '&cSe ha producido un error, lee la consola para mas información.'
|
||||||
|
info:
|
||||||
|
containerBlocked: 'Estás abriendo un contenedor protegido.'
|
||||||
|
containerBlockedSilent: 'Estás abriendo sigilosamente un contenedor protegido.'
|
||||||
|
containerSilent: 'Estás abriendo un contenedor sigilosamente.'
|
||||||
|
settingState: '%setting%: %state%'
|
||||||
|
player:
|
||||||
|
noMatches: 'No se encontraron jugadores con %target%.'
|
||||||
|
matches: 'Jugadores con %target%: %detail%'
|
||||||
|
container:
|
||||||
|
noMatches: 'No se encontraron contenedores con %target%.'
|
||||||
|
matches: 'Contenedores con %target%: %detail%'
|
||||||
|
on: 'activado'
|
||||||
|
off: 'desactivado'
|
||||||
|
container:
|
||||||
|
player: 'Inventario de %player%'
|
||||||
|
enderchest: 'Cofre de Ender de %player%'
|
||||||
|
|
89
plugin/src/main/resources/plugin.yml
Normal file
89
plugin/src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
name: OpenInv
|
||||||
|
main: com.lishid.openinv.OpenInv
|
||||||
|
version: ${project.version}
|
||||||
|
author: lishid
|
||||||
|
authors: [Jikoo, ShadowRanger]
|
||||||
|
description: >
|
||||||
|
This plugin allows you to open a player's inventory as a chest and interact with it in real time.
|
||||||
|
api-version: "1.16"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
OpenInv.any.default:
|
||||||
|
description: Permission for AnyContainer to default on prior to toggling.
|
||||||
|
default: false
|
||||||
|
OpenInv.silent.default:
|
||||||
|
description: Permission for SilentContainer to default on prior to toggling.
|
||||||
|
default: false
|
||||||
|
OpenInv.*:
|
||||||
|
description: Permission for all OpenInv features.
|
||||||
|
default: op
|
||||||
|
children:
|
||||||
|
OpenInv.openinv: true
|
||||||
|
OpenInv.openender: true
|
||||||
|
OpenInv.search: true
|
||||||
|
OpenInv.silent: true
|
||||||
|
OpenInv.anychest: true
|
||||||
|
OpenInv.searchenchant: true
|
||||||
|
OpenInv.searchcontainer: true
|
||||||
|
OpenInv.openonline: true
|
||||||
|
OpenInv.openoffline: true
|
||||||
|
OpenInv.spectate: true
|
||||||
|
OpenInv.openinv:
|
||||||
|
default: op
|
||||||
|
children:
|
||||||
|
OpenInv.openonline: true
|
||||||
|
OpenInv.openoffline: true
|
||||||
|
OpenInv.openender:
|
||||||
|
default: op
|
||||||
|
children:
|
||||||
|
OpenInv.openonline: true
|
||||||
|
OpenInv.openoffline: true
|
||||||
|
|
||||||
|
commands:
|
||||||
|
openinv:
|
||||||
|
aliases: [oi, inv, open]
|
||||||
|
description: Open a player's inventory
|
||||||
|
permission: OpenInv.openinv
|
||||||
|
usage: |-
|
||||||
|
/<command> [Player] - Open a player's inventory
|
||||||
|
openender:
|
||||||
|
aliases: [oe]
|
||||||
|
description: Opens the enderchest of a player
|
||||||
|
permission: OpenInv.openender
|
||||||
|
usage: |-
|
||||||
|
/<command> [Player] - Open a player's enderchest
|
||||||
|
searchinv:
|
||||||
|
aliases: [si]
|
||||||
|
description: Search and list players having a specific item
|
||||||
|
permission: OpenInv.search
|
||||||
|
usage: |-
|
||||||
|
/<command> <Material> [MinAmount] - MinAmount is optional, the minimum amount required
|
||||||
|
searchender:
|
||||||
|
aliases: [se]
|
||||||
|
permission: OpenInv.search
|
||||||
|
description: Searches and lists players having a specific item in their ender chest
|
||||||
|
usage: |-
|
||||||
|
/<command> <Material> [MinAmount] - MinAmount is optional, the minimum amount required
|
||||||
|
silentcontainer:
|
||||||
|
aliases: [sc, silent, silentchest]
|
||||||
|
description: SilentContainer stops sounds and animations when using containers.
|
||||||
|
permission: OpenInv.silent
|
||||||
|
usage: |-
|
||||||
|
/<command> [check|on|off] - Check, toggle, or set SilentContainer
|
||||||
|
anycontainer:
|
||||||
|
aliases: [ac, anychest]
|
||||||
|
description: AnyContainer allows using blocked containers.
|
||||||
|
permission: OpenInv.anychest
|
||||||
|
usage: |-
|
||||||
|
/<command> [check|on|off] - Check, toggle, or set AnyContainer
|
||||||
|
searchenchant:
|
||||||
|
aliases: [searchenchants]
|
||||||
|
description: Search and list players with a specific enchantment.
|
||||||
|
permission: OpenInv.searchenchant
|
||||||
|
usage: |-
|
||||||
|
/<command> <[Enchantment] [MinLevel]> - Enchantment is the enchantment type, MinLevel is the minimum level. One is optional
|
||||||
|
searchcontainer:
|
||||||
|
aliases: [searchchest]
|
||||||
|
description: Search and list containers with a specific material.
|
||||||
|
permission: OpenInv.searchcontainer
|
||||||
|
usage: /<command> <Material> [ChunkRadius] - ChunkRadius is optional, the length that will be searched for matching items. Default 5
|
30
plugin/src/main/resources/pt_br.yml
Normal file
30
plugin/src/main/resources/pt_br.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
messages:
|
||||||
|
error:
|
||||||
|
consoleUnsupported: 'Voce nao consegue usar esse comando pelo console.'
|
||||||
|
lootNotGenerated: '&cPilhagem nao gerada! Por favor desabilite &b/silentcontainer&c.'
|
||||||
|
invalidMaterial: '&cMaterial invalido: "%target%"'
|
||||||
|
invalidNumber: '&cNumero invalido: "%target%"'
|
||||||
|
invalidPlayer: '&cJogador nao encontrado!'
|
||||||
|
permissionOpenSelf: '&cVoce nao pode abrir seu proprio inventario.'
|
||||||
|
permissionEnderAll: '&cVoce nao tem permissao para abrir baus de ender de outros jogadores.'
|
||||||
|
permissionExempt: '&cO inventario de %target% e protegido.'
|
||||||
|
permissionCrossWorld: '&c%target% nao esta no seu mundo.'
|
||||||
|
permissionPlayerOnline: '&cVoce nao tem permissao para abrir o inventario de jogadores online.'
|
||||||
|
permissionPlayerOffline: '&cVoce nao tem permissao para abrir o inventario de jogadores offline.'
|
||||||
|
commandException: '&cUm erro ocorreu. Por favor cheque o console para detalhes.'
|
||||||
|
info:
|
||||||
|
containerBlocked: 'Voce esta abrindo um recipiente bloqueado.'
|
||||||
|
containerBlockedSilent: 'Voce esta abrindo um recipiente bloqueado silenciosamente.'
|
||||||
|
containerSilent: 'Voce esta abrindo um recipiente silenciosamente.'
|
||||||
|
settingState: '%setting%: %state%'
|
||||||
|
player:
|
||||||
|
noMatches: 'Nenhum jogador encontrado com %target%.'
|
||||||
|
matches: 'Jogadores segurando %target%: %detail%'
|
||||||
|
container:
|
||||||
|
noMatches: 'Nenhum recipiente encontrado com %target%.'
|
||||||
|
matches: 'Recipientes contendo %target%: %detail%'
|
||||||
|
on: 'ligado'
|
||||||
|
off: 'desligado'
|
||||||
|
container:
|
||||||
|
player: 'Inventario de %player%'
|
||||||
|
enderchest: 'Bau de Ender de %player%'
|
154
pom.xml
154
pom.xml
@@ -1,62 +1,104 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<!--
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
~ Copyright (C) 2011-2020 lishid. All rights reserved.
|
||||||
<modelVersion>4.0.0</modelVersion>
|
~
|
||||||
<groupId>com.lishid</groupId>
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
<artifactId>openinv</artifactId>
|
~ it under the terms of the GNU General Public License as published by
|
||||||
<packaging>jar</packaging>
|
~ the Free Software Foundation, version 3.
|
||||||
<version>2.3.1</version>
|
~
|
||||||
<name>OpenInv</name>
|
~ This program is distributed in the hope that it will be useful,
|
||||||
<url>http://dev.bukkit.org/bukkit-plugins/openinv/</url>
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<properties>
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
</properties>
|
|
||||||
|
|
||||||
<repositories>
|
<groupId>com.lishid</groupId>
|
||||||
<repository>
|
<artifactId>openinvparent</artifactId>
|
||||||
<id>bukkit-repo</id>
|
<name>OpenInvParent</name>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
<url>http://dev.bukkit.org/bukkit-plugins/openinv/</url>
|
||||||
</repository>
|
<version>4.1.6-SNAPSHOT</version>
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<dependencies>
|
<packaging>pom</packaging>
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>bukkit</artifactId>
|
|
||||||
<version>1.8.7-R0.1-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<properties>
|
||||||
<groupId>org.bukkit</groupId>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<artifactId>craftbukkit</artifactId>
|
</properties>
|
||||||
<version>1.8.7-R0.1-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
<modules>
|
||||||
<defaultGoal>clean install</defaultGoal>
|
<module>api</module>
|
||||||
<sourceDirectory>src/main/java</sourceDirectory>
|
<module>plugin</module>
|
||||||
<resources>
|
<module>internal</module>
|
||||||
<resource>
|
<module>assembly</module>
|
||||||
<directory>src/main/resources</directory>
|
</modules>
|
||||||
<filtering>true</filtering>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
|
|
||||||
<plugins>
|
<profiles>
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<!--
|
||||||
<version>2.3.2</version>
|
~ N.B.: All version-specific code is handled in submodules of the internal module.
|
||||||
<configuration>
|
~
|
||||||
<source>1.6</source>
|
~ Internal submodules built by each profile are handled in internal/pom.xml
|
||||||
<target>1.6</target>
|
-->
|
||||||
</configuration>
|
|
||||||
</plugin>
|
<profile>
|
||||||
</plugins>
|
<id>all</id>
|
||||||
</build>
|
<activation>
|
||||||
</project>
|
<property>
|
||||||
|
<name>all</name>
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spigot-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.2</version>
|
||||||
|
<configuration>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<!-- Keep the file clean, don't include every single pom from all modules -->
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/maven/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
67
scripts/generate_changelog.sh
Normal file
67
scripts/generate_changelog.sh
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011-2021 lishid. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, version 3.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
# A script for generating a changelog from Git.
|
||||||
|
#
|
||||||
|
# Note that this script is designed for use in GitHub Actions, and is not
|
||||||
|
# particularly robust nor configurable. Run from project parent directory.
|
||||||
|
|
||||||
|
# Query GitHub for the username of the given email address.
|
||||||
|
# Falls through to the given author name.
|
||||||
|
lookup_email_username() {
|
||||||
|
lookup=$(curl -G --data-urlencode "q=$1 in:email" https://api.github.com/search/users -H 'Accept: application/vnd.github.v3+json' | grep '"login":' | sed -e 's/^.*": "//g' -e 's/",.*$//g')
|
||||||
|
|
||||||
|
if [[ $lookup ]]; then
|
||||||
|
echo -n "@$lookup"
|
||||||
|
else
|
||||||
|
echo "$2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Use formatted log to pull authors list
|
||||||
|
authors_raw=$(git log --pretty=format:"%ae|%an" "$(git describe --tags --abbrev=0 @^)"..@)
|
||||||
|
readarray -t authors <<<"$authors_raw"
|
||||||
|
|
||||||
|
declare -A author_data
|
||||||
|
|
||||||
|
for author in "${authors[@]}"; do
|
||||||
|
# Match author email
|
||||||
|
author_email=${author%|*}
|
||||||
|
# Convert to lower case
|
||||||
|
author_email=${author_email,,}
|
||||||
|
# Match author name
|
||||||
|
author_name=${author##*|}
|
||||||
|
if [[ -n ${author_data[$author_email]} ]]; then
|
||||||
|
# Skip emails we already have data for
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fetch and store author GitHub username by email
|
||||||
|
author_data[$author_email]=$(lookup_email_username "$author_email" "$author_name")
|
||||||
|
done
|
||||||
|
|
||||||
|
# Fetch actual formatted changelog
|
||||||
|
changelog=$(git log --pretty=format:"%s (%h) - %ae" "$(git describe --tags --abbrev=0 @^)"..@)
|
||||||
|
|
||||||
|
for author_email in "${!author_data[@]}"; do
|
||||||
|
# Ignore case when matching
|
||||||
|
shopt -s nocasematch
|
||||||
|
# Match and replace email
|
||||||
|
changelog=${changelog//$author_email/${author_data[$author_email]}}
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "GENERATED_CHANGELOG<<EOF${changelog}EOF" >> "$GITHUB_ENV"
|
75
scripts/install_spigot_dependencies.sh
Normal file
75
scripts/install_spigot_dependencies.sh
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011-2021 lishid. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, version 3.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
# A script for installing required Spigot versions.
|
||||||
|
#
|
||||||
|
# Note that this script is designed for use in GitHub Actions, and is
|
||||||
|
# not particularly robust nor configurable.
|
||||||
|
# In its current state, the script must be run from OpenInv's parent
|
||||||
|
# project directory and will always install BuildTools to ~/buildtools.
|
||||||
|
|
||||||
|
buildtools_dir=~/buildtools
|
||||||
|
buildtools=$buildtools_dir/BuildTools.jar
|
||||||
|
|
||||||
|
get_spigot_versions () {
|
||||||
|
# Get all submodules of internal module
|
||||||
|
modules=$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all -pl internal | grep -oP '(?<=<string>)(.*)(?=<\/string>)')
|
||||||
|
for module in "${modules[@]}"; do
|
||||||
|
|
||||||
|
# Get number of dependencies declared in pom of specified internal module
|
||||||
|
max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl internal/"$module" | grep -c "<dependency>")
|
||||||
|
|
||||||
|
for ((i=0; i < max_index; i++)); do
|
||||||
|
# Get artifactId of dependency
|
||||||
|
artifact_id=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].artifactId -q -DforceStdout -P all -pl internal/"$module")
|
||||||
|
|
||||||
|
# Ensure dependency is spigot
|
||||||
|
if [[ "$artifact_id" == spigot ]]; then
|
||||||
|
# Get spigot version
|
||||||
|
spigot_version=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].version -q -DforceStdout -P all -pl internal/"$module")
|
||||||
|
echo "$spigot_version"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
get_buildtools () {
|
||||||
|
if [[ -d $buildtools_dir && -f $buildtools ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir $buildtools_dir
|
||||||
|
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O $buildtools
|
||||||
|
}
|
||||||
|
|
||||||
|
versions=$(get_spigot_versions)
|
||||||
|
echo Found Spigot dependencies: "$versions"
|
||||||
|
|
||||||
|
for version in "${versions[@]}"; do
|
||||||
|
set -e
|
||||||
|
exit_code=0
|
||||||
|
mvn dependency:get -Dartifact=org.spigotmc:spigot:"$version" -q -o || exit_code=$?
|
||||||
|
if [ $exit_code -ne 0 ]; then
|
||||||
|
echo Installing missing Spigot version "$version"
|
||||||
|
revision=$(echo "$version" | grep -oP '(\d+\.\d+(\.\d+)?)(?=-R[0-9\.]+-SNAPSHOT)')
|
||||||
|
get_buildtools
|
||||||
|
java -jar $buildtools -rev "$revision"
|
||||||
|
else
|
||||||
|
echo Spigot "$version" is already installed
|
||||||
|
fi
|
||||||
|
done
|
@@ -1,160 +0,0 @@
|
|||||||
package com.lishid.openinv;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
|
|
||||||
import com.lishid.openinv.utils.UUIDUtil;
|
|
||||||
|
|
||||||
public class ConfigUpdater {
|
|
||||||
private final OpenInv plugin;
|
|
||||||
|
|
||||||
private static final int CONFIG_VERSION = 2;
|
|
||||||
|
|
||||||
public ConfigUpdater(OpenInv plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getConfigVersion() {
|
|
||||||
return plugin.getConfig().getInt("config-version", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isConfigOutdated() {
|
|
||||||
return getConfigVersion() < CONFIG_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkForUpdates() {
|
|
||||||
if (isConfigOutdated()) {
|
|
||||||
plugin.getLogger().info("[Config] Update found! Performing update...");
|
|
||||||
performUpdate();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
plugin.getLogger().info("[Config] Update not required.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void performUpdate() {
|
|
||||||
// Update according to the right version
|
|
||||||
switch (getConfigVersion()) {
|
|
||||||
case 1:
|
|
||||||
updateConfig1To2();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateConfig1To2() {
|
|
||||||
FileConfiguration config = plugin.getConfig();
|
|
||||||
|
|
||||||
// Backup the old config file
|
|
||||||
File configFile = new File(plugin.getDataFolder(), "config.yml");
|
|
||||||
File oldConfigFile = new File(plugin.getDataFolder(), "config_old.yml");
|
|
||||||
|
|
||||||
configFile.renameTo(oldConfigFile);
|
|
||||||
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configFile.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.getLogger().info("[Config] Backup of old config.yml file created.");
|
|
||||||
|
|
||||||
// Get the old config settings
|
|
||||||
int itemOpenInvItemId = config.getInt("ItemOpenInvItemID", 280);
|
|
||||||
boolean notifySilentChest = config.getBoolean("NotifySilentChest", true);
|
|
||||||
boolean notifyAnyChest = config.getBoolean("NotifyAnyChest", true);
|
|
||||||
|
|
||||||
Map<UUID, Boolean> anyChestToggles = null;
|
|
||||||
Map<UUID, Boolean> itemOpenInvToggles = null;
|
|
||||||
Map<UUID, Boolean> silentChestToggles = null;
|
|
||||||
|
|
||||||
if (config.isSet("AnyChest")) {
|
|
||||||
anyChestToggles = updateToggles("AnyChest");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.isSet("ItemOpenInv")) {
|
|
||||||
itemOpenInvToggles = updateToggles("ItemOpenInv");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.isSet("SilentChest")) {
|
|
||||||
silentChestToggles = updateToggles("SilentChest");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the old config
|
|
||||||
for (String key : config.getKeys(false)) {
|
|
||||||
config.set(key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the new config options
|
|
||||||
plugin.saveDefaultConfig();
|
|
||||||
plugin.reloadConfig();
|
|
||||||
|
|
||||||
config = plugin.getConfig(); // Refresh the referenced plugin config
|
|
||||||
|
|
||||||
config.set("config-version", 2);
|
|
||||||
config.set("items.open-inv", getMaterialById(itemOpenInvItemId).toString());
|
|
||||||
config.set("notify.any-chest", notifyAnyChest);
|
|
||||||
config.set("notify.silent-chest", notifySilentChest);
|
|
||||||
|
|
||||||
if (anyChestToggles != null && !anyChestToggles.isEmpty()) {
|
|
||||||
for (Map.Entry<UUID, Boolean> entry : anyChestToggles.entrySet()) {
|
|
||||||
config.set("toggles.any-chest." + entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemOpenInvToggles != null && !itemOpenInvToggles.isEmpty()) {
|
|
||||||
for (Map.Entry<UUID, Boolean> entry : itemOpenInvToggles.entrySet()) {
|
|
||||||
config.set("toggles.items.open-inv." + entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (silentChestToggles != null && !silentChestToggles.isEmpty()) {
|
|
||||||
for (Map.Entry<UUID, Boolean> entry : silentChestToggles.entrySet()) {
|
|
||||||
config.set("toggles.silent-chest." + entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the new config
|
|
||||||
plugin.saveConfig();
|
|
||||||
plugin.getLogger().info("[Config] Update complete.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<UUID, Boolean> updateToggles(String sectionName) {
|
|
||||||
Map<UUID, Boolean> toggles = new HashMap<UUID, Boolean>();
|
|
||||||
|
|
||||||
ConfigurationSection section = plugin.getConfig().getConfigurationSection(sectionName);
|
|
||||||
Set<String> keys = section.getKeys(false);
|
|
||||||
if (keys == null || keys.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int total = keys.size();
|
|
||||||
int converted = 0;
|
|
||||||
|
|
||||||
for (String playerName : keys) {
|
|
||||||
UUID uuid = UUIDUtil.getUUIDOf(playerName);
|
|
||||||
if (uuid != null) {
|
|
||||||
boolean toggled = section.getBoolean(playerName + ".toggle", false);
|
|
||||||
toggles.put(uuid, toggled);
|
|
||||||
converted++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.getLogger().info("[Config] Converted (" + converted + "/" + total + ") " + sectionName + " toggle player usernames to UUIDs.");
|
|
||||||
|
|
||||||
return toggles;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private Material getMaterialById(int id) {
|
|
||||||
Material material = Material.getMaterial(id);
|
|
||||||
if (material == null) {
|
|
||||||
material = Material.STICK;
|
|
||||||
}
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,226 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.permissions.Permissible;
|
|
||||||
import org.bukkit.plugin.PluginManager;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
import com.lishid.openinv.commands.AnyChestCommand;
|
|
||||||
import com.lishid.openinv.commands.OpenEnderCommand;
|
|
||||||
import com.lishid.openinv.commands.OpenInvCommand;
|
|
||||||
import com.lishid.openinv.commands.SearchEnderCommand;
|
|
||||||
import com.lishid.openinv.commands.SearchInvCommand;
|
|
||||||
import com.lishid.openinv.commands.SilentChestCommand;
|
|
||||||
import com.lishid.openinv.commands.ToggleOpenInvCommand;
|
|
||||||
import com.lishid.openinv.internal.AnySilentChest;
|
|
||||||
import com.lishid.openinv.internal.InventoryAccess;
|
|
||||||
import com.lishid.openinv.internal.PlayerDataManager;
|
|
||||||
import com.lishid.openinv.internal.SpecialEnderChest;
|
|
||||||
import com.lishid.openinv.internal.SpecialPlayerInventory;
|
|
||||||
import com.lishid.openinv.listeners.OpenInvEntityListener;
|
|
||||||
import com.lishid.openinv.listeners.OpenInvInventoryListener;
|
|
||||||
import com.lishid.openinv.listeners.OpenInvPlayerListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open other player's inventory
|
|
||||||
*
|
|
||||||
* @author lishid
|
|
||||||
*/
|
|
||||||
public class OpenInv extends JavaPlugin {
|
|
||||||
public static final Map<UUID, SpecialPlayerInventory> inventories = new HashMap<UUID, SpecialPlayerInventory>();
|
|
||||||
public static final Map<UUID, SpecialEnderChest> enderChests = new HashMap<UUID, SpecialEnderChest>();
|
|
||||||
|
|
||||||
public static OpenInv mainPlugin;
|
|
||||||
|
|
||||||
private static PlayerDataManager playerLoader;
|
|
||||||
private static InventoryAccess inventoryAccess;
|
|
||||||
private static AnySilentChest anySilentChest;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
// Plugin
|
|
||||||
mainPlugin = this;
|
|
||||||
|
|
||||||
// Config Updater
|
|
||||||
ConfigUpdater configUpdater = new ConfigUpdater(this);
|
|
||||||
configUpdater.checkForUpdates();
|
|
||||||
|
|
||||||
// Initialize
|
|
||||||
playerLoader = new PlayerDataManager();
|
|
||||||
inventoryAccess = new InventoryAccess();
|
|
||||||
anySilentChest = new AnySilentChest();
|
|
||||||
|
|
||||||
// Save the default config.yml if it doesn't already exist
|
|
||||||
saveDefaultConfig();
|
|
||||||
|
|
||||||
// Register the plugin's events & commands
|
|
||||||
registerEvents();
|
|
||||||
registerCommands();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerEvents() {
|
|
||||||
PluginManager pm = getServer().getPluginManager();
|
|
||||||
|
|
||||||
pm.registerEvents(new OpenInvPlayerListener(), this);
|
|
||||||
pm.registerEvents(new OpenInvEntityListener(), this);
|
|
||||||
pm.registerEvents(new OpenInvInventoryListener(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerCommands() {
|
|
||||||
getCommand("openinv").setExecutor(new OpenInvCommand(this));
|
|
||||||
getCommand("openender").setExecutor(new OpenEnderCommand(this));
|
|
||||||
getCommand("searchinv").setExecutor(new SearchInvCommand());
|
|
||||||
getCommand("searchender").setExecutor(new SearchEnderCommand());
|
|
||||||
getCommand("toggleopeninv").setExecutor(new ToggleOpenInvCommand());
|
|
||||||
getCommand("anychest").setExecutor(new AnyChestCommand());
|
|
||||||
getCommand("silentchest").setExecutor(new SilentChestCommand());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PlayerDataManager getPlayerLoader() {
|
|
||||||
return playerLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InventoryAccess getInventoryAccess() {
|
|
||||||
return inventoryAccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AnySilentChest getAnySilentChest() {
|
|
||||||
return anySilentChest;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object getFromConfig(String path, Object defaultValue) {
|
|
||||||
Object val = mainPlugin.getConfig().get(path);
|
|
||||||
if (val == null) {
|
|
||||||
mainPlugin.getConfig().set(path, defaultValue);
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void saveToConfig(String path, Object value) {
|
|
||||||
mainPlugin.getConfig().set(path, value);
|
|
||||||
mainPlugin.saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Material getOpenInvItem() {
|
|
||||||
if (!mainPlugin.getConfig().isSet("items.open-inv")) {
|
|
||||||
saveToConfig("items.open-inv", "STICK");
|
|
||||||
}
|
|
||||||
|
|
||||||
String itemName = mainPlugin.getConfig().getString("items.open-inv", "STICK");
|
|
||||||
Material material = Material.getMaterial(itemName);
|
|
||||||
if (material == null) {
|
|
||||||
mainPlugin.getLogger().warning("OpenInv item '" + itemName + "' does not match to a valid item. Defaulting to stick.");
|
|
||||||
material = Material.STICK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean notifySilentChest() {
|
|
||||||
return mainPlugin.getConfig().getBoolean("notify.silent-chest", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean notifyAnyChest() {
|
|
||||||
return mainPlugin.getConfig().getBoolean("notify.any-chest", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getPlayerAnyChestStatus(Player player) {
|
|
||||||
return mainPlugin.getConfig().getBoolean("toggles.any-chest." + player.getUniqueId(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setPlayerAnyChestStatus(Player player, boolean status) {
|
|
||||||
saveToConfig("toggles.any-chest." + player.getUniqueId(), status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getPlayerItemOpenInvStatus(Player player) {
|
|
||||||
return mainPlugin.getConfig().getBoolean("toggles.items.open-inv" + player.getUniqueId(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setPlayerItemOpenInvStatus(Player player, boolean status) {
|
|
||||||
saveToConfig("toggles.items.open-inv." + player.getUniqueId(), status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getPlayerSilentChestStatus(Player player) {
|
|
||||||
return mainPlugin.getConfig().getBoolean("toggles.silent-chest." + player.getUniqueId(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setPlayerSilentChestStatus(Player player, boolean status) {
|
|
||||||
saveToConfig("toggles.silent-chest." + player.getUniqueId(), status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void log(String text) {
|
|
||||||
mainPlugin.getLogger().info("[OpenInv] " + text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void log(Throwable e) {
|
|
||||||
mainPlugin.getLogger().severe("[OpenInv] " + e.toString());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMessage(CommandSender sender, String message) {
|
|
||||||
sender.sendMessage(ChatColor.AQUA + "[OpenInv] " + ChatColor.WHITE + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showHelp(Player player) {
|
|
||||||
player.sendMessage(ChatColor.GREEN + "/openinv <player> - Open a player's inventory.");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " (aliases: oi, inv, open)");
|
|
||||||
|
|
||||||
player.sendMessage(ChatColor.GREEN + "/openender <player> - Open a player's ender chest.");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " (aliases: oe)");
|
|
||||||
|
|
||||||
player.sendMessage(ChatColor.GREEN + "/searchinv <item> [minAmount] -");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " Search and list players having a specific item.");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " (aliases: si)");
|
|
||||||
|
|
||||||
player.sendMessage(ChatColor.GREEN + "/searchender <item> [minAmount] -");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " Search and list players having a specific item.");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " (aliases: se)");
|
|
||||||
|
|
||||||
player.sendMessage(ChatColor.GREEN + "/toggleopeninv - Toggle the item openinv function.");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " (aliases: toi, toggleoi, toggleinv)");
|
|
||||||
|
|
||||||
player.sendMessage(ChatColor.GREEN + "/anychest - Toggle the any chest function.");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " (aliases: ac)");
|
|
||||||
|
|
||||||
player.sendMessage(ChatColor.GREEN + "/silentchest - Toggle the silent chest function.");
|
|
||||||
player.sendMessage(ChatColor.GREEN + " (aliases: sc, silent)");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasPermission(Permissible player, String permission) {
|
|
||||||
String[] parts = permission.split("\\.");
|
|
||||||
String perm = "";
|
|
||||||
for (int i = 0; i < parts.length; i++) {
|
|
||||||
if (player.hasPermission(perm + "*")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
perm += parts[i] + ".";
|
|
||||||
}
|
|
||||||
return player.hasPermission(permission);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
package com.lishid.openinv;
|
|
||||||
|
|
||||||
public class Permissions {
|
|
||||||
public static final String PERM_OPENINV = "OpenInv.openinv";
|
|
||||||
public static final String PERM_OVERRIDE = "OpenInv.override";
|
|
||||||
public static final String PERM_EXEMPT = "OpenInv.exempt";
|
|
||||||
public static final String PERM_CROSSWORLD = "OpenInv.crossworld";
|
|
||||||
public static final String PERM_SILENT = "OpenInv.silent";
|
|
||||||
public static final String PERM_ANYCHEST = "OpenInv.anychest";
|
|
||||||
public static final String PERM_ENDERCHEST = "OpenInv.openender";
|
|
||||||
public static final String PERM_ENDERCHEST_ALL = "OpenInv.openenderall";
|
|
||||||
public static final String PERM_SEARCH = "OpenInv.search";
|
|
||||||
public static final String PERM_EDITINV = "OpenInv.editinv";
|
|
||||||
public static final String PERM_EDITENDER = "OpenInv.editender";
|
|
||||||
public static final String PERM_OPENSELF = "OpenInv.openself";
|
|
||||||
}
|
|
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.commands;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
|
|
||||||
public class AnyChestCommand implements CommandExecutor {
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
if (command.getName().equalsIgnoreCase("anychest")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You can't use this command from the console.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_ANYCHEST)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to use any chest.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player player = (Player) sender;
|
|
||||||
|
|
||||||
if (args.length > 0) {
|
|
||||||
if (args[0].equalsIgnoreCase("check")) {
|
|
||||||
String status = OpenInv.getPlayerAnyChestStatus(player) ? ChatColor.GREEN + "ON" : ChatColor.RED + "OFF";
|
|
||||||
OpenInv.sendMessage(player, "Any Chest is " + status + ChatColor.RESET + ".");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenInv.setPlayerAnyChestStatus(player, !OpenInv.getPlayerAnyChestStatus(player));
|
|
||||||
|
|
||||||
String status = OpenInv.getPlayerAnyChestStatus(player) ? ChatColor.GREEN + "ON" : ChatColor.RED + "OFF";
|
|
||||||
OpenInv.sendMessage(player, "Any Chest is now " + status + ChatColor.RESET + ".");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,164 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.commands;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
import com.lishid.openinv.internal.SpecialEnderChest;
|
|
||||||
import com.lishid.openinv.utils.UUIDUtil;
|
|
||||||
|
|
||||||
public class OpenEnderCommand implements CommandExecutor {
|
|
||||||
private final OpenInv plugin;
|
|
||||||
private final Map<UUID, UUID> openEnderHistory = new ConcurrentHashMap<UUID, UUID>();
|
|
||||||
|
|
||||||
public OpenEnderCommand(OpenInv plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
if (command.getName().equalsIgnoreCase("openender")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You can't use this command from the console.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_ENDERCHEST)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to access player ender chests.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.length > 0 && args[0].equalsIgnoreCase("?")) {
|
|
||||||
OpenInv.showHelp((Player) sender);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Player player = (Player) sender;
|
|
||||||
|
|
||||||
// History management
|
|
||||||
UUID history = openEnderHistory.get(player.getUniqueId());
|
|
||||||
if (history == null) {
|
|
||||||
history = player.getUniqueId();
|
|
||||||
openEnderHistory.put(player.getUniqueId(), history);
|
|
||||||
}
|
|
||||||
|
|
||||||
final UUID uuid;
|
|
||||||
|
|
||||||
// Read from history if target is not named
|
|
||||||
if (args.length < 1) {
|
|
||||||
if (history != null) {
|
|
||||||
uuid = history;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sender.sendMessage(ChatColor.RED + "OpenEnder history is empty!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uuid = UUIDUtil.getUUIDOf(args[0]);
|
|
||||||
if (uuid == null) {
|
|
||||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final UUID playerUUID = player.getUniqueId();
|
|
||||||
|
|
||||||
Player target = Bukkit.getPlayer(uuid);
|
|
||||||
if (target == null) {
|
|
||||||
// Targeted player was not found online, start asynchronous lookup in files
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Try loading the player's data asynchronously
|
|
||||||
final Player target = OpenInv.getPlayerLoader().loadPlayer(uuid);
|
|
||||||
if (target == null) {
|
|
||||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open target's inventory synchronously
|
|
||||||
Bukkit.getScheduler().runTask(plugin, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Player player = Bukkit.getPlayer(playerUUID);
|
|
||||||
// If sender is no longer online after loading the target, abort!
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
openInventory(player, target);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
openInventory(player, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openInventory(Player player, Player target) {
|
|
||||||
if (target == null) {
|
|
||||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target != player && !OpenInv.hasPermission(player, Permissions.PERM_ENDERCHEST_ALL)) {
|
|
||||||
player.sendMessage(ChatColor.RED + "You do not have permission to access other player's ender chests.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permissions checks
|
|
||||||
if (!OpenInv.hasPermission(player, Permissions.PERM_OVERRIDE) && OpenInv.hasPermission(target, Permissions.PERM_EXEMPT)) {
|
|
||||||
player.sendMessage(ChatColor.RED + target.getDisplayName() + "'s ender chest is protected!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crossworld check
|
|
||||||
if ((!OpenInv.hasPermission(player, Permissions.PERM_CROSSWORLD) && !OpenInv.hasPermission(player, Permissions.PERM_OVERRIDE)) && target.getWorld() != player.getWorld()) {
|
|
||||||
player.sendMessage(ChatColor.RED + target.getDisplayName() + " is not in your world!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the target
|
|
||||||
openEnderHistory.put(player.getUniqueId(), target.getUniqueId());
|
|
||||||
|
|
||||||
// Create the inventory
|
|
||||||
SpecialEnderChest chest = OpenInv.enderChests.get(target.getUniqueId());
|
|
||||||
if (chest == null) {
|
|
||||||
chest = new SpecialEnderChest(target, target.isOnline());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the inventory
|
|
||||||
player.openInventory(chest.getBukkitInventory());
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.commands;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
import com.lishid.openinv.internal.SpecialPlayerInventory;
|
|
||||||
import com.lishid.openinv.utils.UUIDUtil;
|
|
||||||
|
|
||||||
public class OpenInvCommand implements CommandExecutor {
|
|
||||||
private final OpenInv plugin;
|
|
||||||
private final Map<UUID, UUID> openInvHistory = new ConcurrentHashMap<UUID, UUID>();
|
|
||||||
|
|
||||||
public OpenInvCommand(OpenInv plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
if (command.getName().equalsIgnoreCase("openinv")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You can't use this command from the console.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_OPENINV)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to access player inventories.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.length > 0 && args[0].equalsIgnoreCase("?")) {
|
|
||||||
OpenInv.showHelp((Player) sender);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Player player = (Player) sender;
|
|
||||||
|
|
||||||
// History management
|
|
||||||
UUID history = openInvHistory.get(player.getUniqueId());
|
|
||||||
if (history == null) {
|
|
||||||
history = player.getUniqueId();
|
|
||||||
openInvHistory.put(player.getUniqueId(), history);
|
|
||||||
}
|
|
||||||
|
|
||||||
final UUID uuid;
|
|
||||||
|
|
||||||
// Read from history if target is not named
|
|
||||||
if (args.length < 1) {
|
|
||||||
uuid = history;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uuid = UUIDUtil.getUUIDOf(args[0]);
|
|
||||||
if (uuid == null) {
|
|
||||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final UUID playerUUID = player.getUniqueId();
|
|
||||||
|
|
||||||
Player target = Bukkit.getPlayer(uuid);
|
|
||||||
if (target == null) {
|
|
||||||
// Targeted player was not found online, start asynchronous lookup in files
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Try loading the player's data asynchronously
|
|
||||||
final Player target = OpenInv.getPlayerLoader().loadPlayer(uuid);
|
|
||||||
if (target == null) {
|
|
||||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open target's inventory synchronously
|
|
||||||
Bukkit.getScheduler().runTask(plugin, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Player player = Bukkit.getPlayer(playerUUID);
|
|
||||||
// If sender is no longer online after loading the target, abort!
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
openInventory(player, target);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
openInventory(player, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openInventory(Player player, Player target) {
|
|
||||||
if (target == null) {
|
|
||||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permissions checks
|
|
||||||
if (!OpenInv.hasPermission(player, Permissions.PERM_OVERRIDE) && OpenInv.hasPermission(target, Permissions.PERM_EXEMPT)) {
|
|
||||||
player.sendMessage(ChatColor.RED + target.getDisplayName() + "'s inventory is protected!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crossworld check
|
|
||||||
if ((!OpenInv.hasPermission(player, Permissions.PERM_CROSSWORLD) && !OpenInv.hasPermission(player, Permissions.PERM_OVERRIDE)) && target.getWorld() != player.getWorld()) {
|
|
||||||
player.sendMessage(ChatColor.RED + target.getDisplayName() + " is not in your world!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Self-open check
|
|
||||||
if (!OpenInv.hasPermission(player, Permissions.PERM_OPENSELF) && target.equals(player)) {
|
|
||||||
player.sendMessage(ChatColor.RED + "You're not allowed to openinv yourself.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the target
|
|
||||||
openInvHistory.put(player.getUniqueId(), target.getUniqueId());
|
|
||||||
|
|
||||||
// Create the inventory
|
|
||||||
SpecialPlayerInventory inv = OpenInv.inventories.get(target.getUniqueId());
|
|
||||||
if (inv == null) {
|
|
||||||
inv = new SpecialPlayerInventory(target, target.isOnline());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the inventory
|
|
||||||
player.openInventory(inv.getBukkitInventory());
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,65 +0,0 @@
|
|||||||
package com.lishid.openinv.commands;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
|
|
||||||
public class SearchEnderCommand implements CommandExecutor {
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
if (command.getName().equalsIgnoreCase("searchender")) {
|
|
||||||
if (sender instanceof Player) {
|
|
||||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_SEARCH)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to search player ender chests.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Material material = null;
|
|
||||||
int count = 1;
|
|
||||||
|
|
||||||
if (args.length >= 1) {
|
|
||||||
String[] gData;
|
|
||||||
gData = args[0].split(":");
|
|
||||||
material = Material.matchMaterial(gData[0]);
|
|
||||||
}
|
|
||||||
if (args.length >= 2) {
|
|
||||||
try {
|
|
||||||
count = Integer.parseInt(args[1]);
|
|
||||||
}
|
|
||||||
catch (NumberFormatException ex) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "'" + args[1] + "' is not a number!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (material == null) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "Unknown item");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
for (Player onlinePlayer : Bukkit.getServer().getOnlinePlayers()) {
|
|
||||||
if (onlinePlayer.getEnderChest().contains(material, count)) {
|
|
||||||
sb.append(onlinePlayer.getName());
|
|
||||||
sb.append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String playerList = sb.toString();
|
|
||||||
sender.sendMessage("Players with the item " + ChatColor.GRAY + material.toString() + ChatColor.RESET + " in their ender chest: " + playerList);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.commands;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
|
|
||||||
public class SearchInvCommand implements CommandExecutor {
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
if (command.getName().equalsIgnoreCase("searchinv")) {
|
|
||||||
if (sender instanceof Player) {
|
|
||||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_SEARCH)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to search player inventories.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Material material = null;
|
|
||||||
int count = 1;
|
|
||||||
|
|
||||||
if (args.length >= 1) {
|
|
||||||
String[] gData;
|
|
||||||
gData = args[0].split(":");
|
|
||||||
material = Material.matchMaterial(gData[0]);
|
|
||||||
}
|
|
||||||
if (args.length >= 2) {
|
|
||||||
try {
|
|
||||||
count = Integer.parseInt(args[1]);
|
|
||||||
}
|
|
||||||
catch (NumberFormatException ex) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "'" + args[1] + "' is not a number!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (material == null) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "Unknown item");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
for (Player onlinePlayer : Bukkit.getServer().getOnlinePlayers()) {
|
|
||||||
if (onlinePlayer.getInventory().contains(material, count)) {
|
|
||||||
sb.append(onlinePlayer.getName());
|
|
||||||
sb.append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String playerList = sb.toString();
|
|
||||||
sender.sendMessage("Players with the item " + ChatColor.GRAY + material.toString() + ChatColor.RESET + " in their inventory: " + playerList);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.commands;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
|
|
||||||
public class SilentChestCommand implements CommandExecutor {
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
if (command.getName().equalsIgnoreCase("silentchest")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You can't use this command from the console.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_SILENT)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to use silent chest.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player player = (Player) sender;
|
|
||||||
|
|
||||||
if (args.length > 0) {
|
|
||||||
if (args[0].equalsIgnoreCase("check")) {
|
|
||||||
String status = OpenInv.getPlayerSilentChestStatus(player) ? ChatColor.GREEN + "ON" : ChatColor.RED + "OFF";
|
|
||||||
OpenInv.sendMessage(player, "Silent Chest is " + status + ChatColor.RESET + ".");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenInv.setPlayerSilentChestStatus(player, !OpenInv.getPlayerSilentChestStatus(player));
|
|
||||||
|
|
||||||
String status = OpenInv.getPlayerSilentChestStatus(player) ? ChatColor.GREEN + "ON" : ChatColor.RED + "OFF";
|
|
||||||
OpenInv.sendMessage(player, "Silent Chest is now " + status + ChatColor.RESET + ".");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.commands;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
|
|
||||||
public class ToggleOpenInvCommand implements CommandExecutor {
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
if (command.getName().equalsIgnoreCase("toggleopeninv")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You can't use this command from the console.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_OPENINV)) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to access player inventories.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player player = (Player) sender;
|
|
||||||
|
|
||||||
if (args.length > 0) {
|
|
||||||
if (args[0].equalsIgnoreCase("check")) {
|
|
||||||
String status = OpenInv.getPlayerItemOpenInvStatus(player) ? ChatColor.GREEN + "ON" : ChatColor.RED + "OFF";
|
|
||||||
OpenInv.sendMessage(player, "OpenInv with " + ChatColor.GRAY + OpenInv.getOpenInvItem() + ChatColor.RESET + status + ChatColor.RESET + ".");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenInv.setPlayerItemOpenInvStatus(player, !OpenInv.getPlayerItemOpenInvStatus(player));
|
|
||||||
|
|
||||||
String status = OpenInv.getPlayerItemOpenInvStatus(player) ? ChatColor.GREEN + "ON" : ChatColor.RED + "OFF";
|
|
||||||
OpenInv.sendMessage(player, "OpenInv with " + ChatColor.GRAY + OpenInv.getOpenInvItem() + ChatColor.RESET + " is now " + status + ChatColor.RESET + ".");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
|
|
||||||
// Volatile
|
|
||||||
import net.minecraft.server.v1_8_R3.*;
|
|
||||||
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.entity.*;
|
|
||||||
|
|
||||||
public class AnySilentChest {
|
|
||||||
public boolean isAnyChestNeeded(Player p, int x, int y, int z) {
|
|
||||||
// FOR REFERENCE, LOOK AT net.minecraft.server.BlockChest
|
|
||||||
BlockPosition position = new BlockPosition(x, y, z);
|
|
||||||
EntityPlayer player = ((CraftPlayer) p).getHandle();
|
|
||||||
World world = player.world;
|
|
||||||
BlockChest chest = (BlockChest) (((BlockChest) world.getType(position).getBlock()).b == 1 ?
|
|
||||||
Block.getByName("trapped_chest") : Block.getByName("chest"));
|
|
||||||
|
|
||||||
// If block on top
|
|
||||||
if (topBlocking(world, position)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If block next to chest is chest and has a block on top
|
|
||||||
for (EnumDirection direction : EnumDirectionList.HORIZONTAL) {
|
|
||||||
BlockPosition sidePosition = position.shift(direction);
|
|
||||||
Block var8 = world.getType(sidePosition).getBlock();
|
|
||||||
if (var8 == chest) {
|
|
||||||
if (this.topBlocking(world, sidePosition)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
private boolean topBlocking(World world, BlockPosition position) {
|
|
||||||
return this.blockOnTop(world, position) || this.ocelotOnTop(world, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean blockOnTop(World world, BlockPosition position) {
|
|
||||||
return world.getType(position.up()).getBlock().isOccluding();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean ocelotOnTop(World world, BlockPosition position) {
|
|
||||||
Iterator var3 = world.a(EntityOcelot.class,
|
|
||||||
new AxisAlignedBB((double) position.getX(), (double) (position.getY() + 1),
|
|
||||||
(double) position.getZ(), (double) (position.getX() + 1),
|
|
||||||
(double) (position.getY() + 2), (double) (position.getZ() + 1))).iterator();
|
|
||||||
|
|
||||||
EntityOcelot var5;
|
|
||||||
do {
|
|
||||||
if (!var3.hasNext()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity var4 = (Entity) var3.next();
|
|
||||||
var5 = (EntityOcelot) var4;
|
|
||||||
} while (!var5.isSitting());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean activateChest(Player p, boolean anyChest, boolean silentChest, int x, int y, int z) {
|
|
||||||
BlockPosition position = new BlockPosition(x, y, z);
|
|
||||||
EntityPlayer player = ((CraftPlayer) p).getHandle();
|
|
||||||
World world = player.world;
|
|
||||||
if (world.isClientSide) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockChest chest = (BlockChest) (((BlockChest) world.getType(position).getBlock()).b == 1 ?
|
|
||||||
Block.getByName("trapped_chest") : Block.getByName("chest"));
|
|
||||||
|
|
||||||
TileEntity tileEntity = world.getTileEntity(position);
|
|
||||||
if (!(tileEntity instanceof TileEntityChest)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ITileInventory tileInventory = (ITileInventory) tileEntity;
|
|
||||||
if (!anyChest && this.topBlocking(world, position)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (EnumDirection direction : EnumDirectionList.HORIZONTAL) {
|
|
||||||
BlockPosition side = position.shift(direction);
|
|
||||||
Block block = world.getType(side).getBlock();
|
|
||||||
if (block == chest) {
|
|
||||||
if (!anyChest && this.topBlocking(world, side)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TileEntity sideTileEntity = world.getTileEntity(side);
|
|
||||||
if (sideTileEntity instanceof TileEntityChest) {
|
|
||||||
if (direction != EnumDirection.WEST && direction != EnumDirection.NORTH) {
|
|
||||||
tileInventory = new InventoryLargeChest("container.chestDouble", tileInventory, (TileEntityChest) sideTileEntity);
|
|
||||||
} else {
|
|
||||||
tileInventory = new InventoryLargeChest("container.chestDouble", (TileEntityChest) sideTileEntity, tileInventory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean returnValue = true;
|
|
||||||
if (silentChest) {
|
|
||||||
tileInventory = new SilentInventory(tileInventory);
|
|
||||||
if (OpenInv.notifySilentChest()) {
|
|
||||||
OpenInv.sendMessage(p, "You are opening a chest silently.");
|
|
||||||
}
|
|
||||||
returnValue = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
player.openContainer(tileInventory);
|
|
||||||
|
|
||||||
if (anyChest && OpenInv.notifyAnyChest()) {
|
|
||||||
OpenInv.sendMessage(p, "You are opening a blocked chest.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,24 +0,0 @@
|
|||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_8_R3.EnumDirection;
|
|
||||||
import net.minecraft.server.v1_8_R3.EnumDirection.EnumDirectionLimit;
|
|
||||||
|
|
||||||
public enum EnumDirectionList implements Iterable<EnumDirection> {
|
|
||||||
HORIZONTAL(EnumDirectionLimit.HORIZONTAL),
|
|
||||||
VERTICAL(EnumDirectionLimit.VERTICAL);
|
|
||||||
|
|
||||||
private final EnumDirectionLimit list;
|
|
||||||
|
|
||||||
private EnumDirectionList(EnumDirectionLimit list) {
|
|
||||||
this.list = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<EnumDirection> iterator() {
|
|
||||||
return Iterators.forArray(list.a());
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
import org.bukkit.entity.HumanEntity;
|
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
|
|
||||||
// Volatile
|
|
||||||
import net.minecraft.server.v1_8_R3.*;
|
|
||||||
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.inventory.*;
|
|
||||||
|
|
||||||
public class InventoryAccess {
|
|
||||||
public boolean check(Inventory inventory, HumanEntity player) {
|
|
||||||
IInventory inv = grabInventory(inventory);
|
|
||||||
|
|
||||||
if (inv instanceof SpecialPlayerInventory) {
|
|
||||||
if (!OpenInv.hasPermission(player, Permissions.PERM_EDITINV)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (inv instanceof SpecialEnderChest) {
|
|
||||||
if (!OpenInv.hasPermission(player, Permissions.PERM_EDITENDER)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IInventory grabInventory(Inventory inventory) {
|
|
||||||
if(inventory instanceof CraftInventory) {
|
|
||||||
return ((CraftInventory) inventory).getInventory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use reflection to find the inventory
|
|
||||||
Class<? extends Inventory> clazz = inventory.getClass();
|
|
||||||
IInventory result = null;
|
|
||||||
for(Field f : clazz.getDeclaredFields()) {
|
|
||||||
f.setAccessible(true);
|
|
||||||
if(IInventory.class.isAssignableFrom(f.getDeclaringClass())) {
|
|
||||||
try {
|
|
||||||
result = (IInventory) f.get(inventory);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
OpenInv.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.mojang.authlib.GameProfile;
|
|
||||||
|
|
||||||
// Volatile
|
|
||||||
import net.minecraft.server.v1_8_R3.*;
|
|
||||||
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.*;
|
|
||||||
|
|
||||||
public class PlayerDataManager {
|
|
||||||
public Player loadPlayer(UUID uuid) {
|
|
||||||
try {
|
|
||||||
OfflinePlayer player = Bukkit.getOfflinePlayer(uuid);
|
|
||||||
if (player == null || !player.hasPlayedBefore()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
GameProfile profile = new GameProfile(uuid, player.getName());
|
|
||||||
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
|
|
||||||
// Create an entity to load the player data
|
|
||||||
EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), profile, new PlayerInteractManager(server.getWorldServer(0)));
|
|
||||||
|
|
||||||
// Get the bukkit entity
|
|
||||||
Player target = entity.getBukkitEntity();
|
|
||||||
if (target != null) {
|
|
||||||
// Load data
|
|
||||||
target.loadData();
|
|
||||||
// Return the entity
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
OpenInv.log(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
// Volatile
|
|
||||||
import net.minecraft.server.v1_8_R3.*;
|
|
||||||
|
|
||||||
public class SilentContainerChest extends ContainerChest {
|
|
||||||
public IInventory inv;
|
|
||||||
|
|
||||||
public SilentContainerChest(IInventory i1, IInventory i2, EntityHuman human) {
|
|
||||||
super(i1, i2, human);
|
|
||||||
inv = i2;
|
|
||||||
// Close signal
|
|
||||||
inv.closeContainer(human);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void b(EntityHuman paramEntityHuman) {
|
|
||||||
// Don't send close signal twice, might screw up
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,164 +0,0 @@
|
|||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftHumanEntity;
|
|
||||||
import org.bukkit.entity.HumanEntity;
|
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
|
||||||
|
|
||||||
// Volatile
|
|
||||||
import net.minecraft.server.v1_8_R3.*;
|
|
||||||
|
|
||||||
public class SilentInventory implements ITileInventory {
|
|
||||||
public ITileInventory inv;
|
|
||||||
|
|
||||||
public SilentInventory(ITileInventory inv) {
|
|
||||||
this.inv = inv;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean r_() {
|
|
||||||
return inv.r_();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void a(ChestLock chestLock) {
|
|
||||||
inv.a(chestLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChestLock i() {
|
|
||||||
return inv.i();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSize() {
|
|
||||||
return inv.getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack getItem(int i) {
|
|
||||||
return inv.getItem(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack splitStack(int i, int i1) {
|
|
||||||
return inv.splitStack(i, i1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack splitWithoutUpdate(int i) {
|
|
||||||
return inv.splitWithoutUpdate(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(int i, ItemStack itemStack) {
|
|
||||||
inv.setItem(i, itemStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMaxStackSize() {
|
|
||||||
return inv.getMaxStackSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
inv.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean a(EntityHuman entityHuman) {
|
|
||||||
return inv.a(entityHuman);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startOpen(EntityHuman entityHuman) {
|
|
||||||
// Don't do anything
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void closeContainer(EntityHuman entityHuman) {
|
|
||||||
// Don't do anything
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean b(int i, ItemStack itemStack) {
|
|
||||||
return inv.b(i, itemStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getProperty(int i) {
|
|
||||||
return inv.getProperty(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void b(int i, int i1) {
|
|
||||||
inv.b(i, i1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int g() {
|
|
||||||
return inv.g();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void l() {
|
|
||||||
inv.l();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack[] getContents() {
|
|
||||||
return inv.getContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOpen(CraftHumanEntity craftHumanEntity) {
|
|
||||||
inv.onOpen(craftHumanEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClose(CraftHumanEntity craftHumanEntity) {
|
|
||||||
inv.onClose(craftHumanEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<HumanEntity> getViewers() {
|
|
||||||
return inv.getViewers();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InventoryHolder getOwner() {
|
|
||||||
return inv.getOwner();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMaxStackSize(int i) {
|
|
||||||
inv.setMaxStackSize(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return inv.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasCustomName() {
|
|
||||||
return inv.hasCustomName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IChatBaseComponent getScoreboardDisplayName() {
|
|
||||||
return inv.getScoreboardDisplayName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Container createContainer(PlayerInventory playerInventory, EntityHuman entityHuman) {
|
|
||||||
// Don't let the chest itself create the container.
|
|
||||||
return new ContainerChest(playerInventory, this, entityHuman);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getContainerName() {
|
|
||||||
return inv.getContainerName();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
|
|
||||||
// Volatile
|
|
||||||
import net.minecraft.server.v1_8_R3.*;
|
|
||||||
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.entity.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.inventory.*;
|
|
||||||
|
|
||||||
public class SpecialEnderChest extends InventorySubcontainer {
|
|
||||||
private final CraftInventory inventory = new CraftInventory(this);
|
|
||||||
private final InventoryEnderChest enderChest;
|
|
||||||
private final CraftPlayer owner;
|
|
||||||
private boolean playerOnline;
|
|
||||||
|
|
||||||
public SpecialEnderChest(Player p, boolean online) {
|
|
||||||
this(p, ((CraftPlayer) p).getHandle().getEnderChest(), online);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SpecialEnderChest(Player p, InventoryEnderChest enderChest, boolean online) {
|
|
||||||
super(enderChest.getName(), enderChest.hasCustomName(), enderChest.getSize());
|
|
||||||
this.owner = (CraftPlayer) p;
|
|
||||||
this.enderChest = enderChest;
|
|
||||||
this.items = this.enderChest.getContents();
|
|
||||||
this.playerOnline = online;
|
|
||||||
OpenInv.enderChests.put(owner.getUniqueId(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveOnExit() {
|
|
||||||
if (transaction.isEmpty() && !playerOnline) {
|
|
||||||
owner.saveData();
|
|
||||||
OpenInv.enderChests.remove(owner.getUniqueId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void linkInventory(InventoryEnderChest inventory) {
|
|
||||||
inventory.items = this.items;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Inventory getBukkitInventory() {
|
|
||||||
return inventory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playerOnline(Player p) {
|
|
||||||
if (!playerOnline) {
|
|
||||||
linkInventory(((CraftPlayer) p).getHandle().getEnderChest());
|
|
||||||
p.saveData();
|
|
||||||
playerOnline = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playerOffline() {
|
|
||||||
playerOnline = false;
|
|
||||||
owner.loadData();
|
|
||||||
linkInventory(owner.getHandle().getEnderChest());
|
|
||||||
saveOnExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClose(CraftHumanEntity who) {
|
|
||||||
super.onClose(who);
|
|
||||||
saveOnExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InventoryHolder getOwner() {
|
|
||||||
return this.owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
super.update();
|
|
||||||
enderChest.update();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,252 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.internal;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
|
|
||||||
// Volatile
|
|
||||||
import net.minecraft.server.v1_8_R3.*;
|
|
||||||
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.entity.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.inventory.*;
|
|
||||||
|
|
||||||
public class SpecialPlayerInventory extends PlayerInventory {
|
|
||||||
private final CraftInventory inventory = new CraftInventory(this);
|
|
||||||
private final ItemStack[] extra = new ItemStack[5];
|
|
||||||
private final CraftPlayer owner;
|
|
||||||
private boolean playerOnline;
|
|
||||||
|
|
||||||
public SpecialPlayerInventory(Player p, boolean online) {
|
|
||||||
super(((CraftPlayer) p).getHandle());
|
|
||||||
this.owner = (CraftPlayer) p;
|
|
||||||
this.items = player.inventory.items;
|
|
||||||
this.armor = player.inventory.armor;
|
|
||||||
this.playerOnline = online;
|
|
||||||
OpenInv.inventories.put(owner.getUniqueId(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Inventory getBukkitInventory() {
|
|
||||||
return inventory;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveOnExit() {
|
|
||||||
if (transaction.isEmpty() && !playerOnline) {
|
|
||||||
owner.saveData();
|
|
||||||
OpenInv.inventories.remove(owner.getUniqueId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void linkInventory(PlayerInventory inventory) {
|
|
||||||
inventory.items = this.items;
|
|
||||||
inventory.armor = this.armor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playerOnline(Player player) {
|
|
||||||
if (!playerOnline) {
|
|
||||||
CraftPlayer p = (CraftPlayer) player;
|
|
||||||
linkInventory(p.getHandle().inventory);
|
|
||||||
p.saveData();
|
|
||||||
playerOnline = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playerOffline() {
|
|
||||||
playerOnline = false;
|
|
||||||
owner.loadData();
|
|
||||||
linkInventory(owner.getHandle().inventory);
|
|
||||||
saveOnExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClose(CraftHumanEntity who) {
|
|
||||||
super.onClose(who);
|
|
||||||
this.saveOnExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack[] getContents() {
|
|
||||||
ItemStack[] C = new ItemStack[getSize()];
|
|
||||||
System.arraycopy(items, 0, C, 0, items.length);
|
|
||||||
System.arraycopy(armor, 0, C, items.length, armor.length);
|
|
||||||
return C;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSize() {
|
|
||||||
return super.getSize() + 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack getItem(int i) {
|
|
||||||
ItemStack[] is = this.items;
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.armor;
|
|
||||||
} else {
|
|
||||||
i = getReversedItemSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.extra;
|
|
||||||
} else if (is == this.armor) {
|
|
||||||
i = getReversedArmorSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return is[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack splitStack(int i, int j) {
|
|
||||||
ItemStack[] is = this.items;
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.armor;
|
|
||||||
} else {
|
|
||||||
i = getReversedItemSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.extra;
|
|
||||||
} else if (is == this.armor) {
|
|
||||||
i = getReversedArmorSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is[i] != null) {
|
|
||||||
ItemStack itemstack;
|
|
||||||
|
|
||||||
if (is[i].count <= j) {
|
|
||||||
itemstack = is[i];
|
|
||||||
is[i] = null;
|
|
||||||
return itemstack;
|
|
||||||
} else {
|
|
||||||
itemstack = is[i].a(j);
|
|
||||||
if (is[i].count == 0) {
|
|
||||||
is[i] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return itemstack;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack splitWithoutUpdate(int i) {
|
|
||||||
ItemStack[] is = this.items;
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.armor;
|
|
||||||
} else {
|
|
||||||
i = getReversedItemSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.extra;
|
|
||||||
} else if (is == this.armor) {
|
|
||||||
i = getReversedArmorSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is[i] != null) {
|
|
||||||
ItemStack itemstack = is[i];
|
|
||||||
|
|
||||||
is[i] = null;
|
|
||||||
return itemstack;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(int i, ItemStack itemStack) {
|
|
||||||
ItemStack[] is = this.items;
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.armor;
|
|
||||||
} else {
|
|
||||||
i = getReversedItemSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= is.length) {
|
|
||||||
i -= is.length;
|
|
||||||
is = this.extra;
|
|
||||||
} else if (is == this.armor) {
|
|
||||||
i = getReversedArmorSlotNum(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Effects
|
|
||||||
if (is == this.extra) {
|
|
||||||
owner.getHandle().drop(itemStack, true);
|
|
||||||
itemStack = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
is[i] = itemStack;
|
|
||||||
|
|
||||||
owner.getHandle().defaultContainer.b();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getReversedItemSlotNum(int i) {
|
|
||||||
if (i >= 27)
|
|
||||||
return i - 27;
|
|
||||||
else
|
|
||||||
return i + 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getReversedArmorSlotNum(int i) {
|
|
||||||
if (i == 0)
|
|
||||||
return 3;
|
|
||||||
if (i == 1)
|
|
||||||
return 2;
|
|
||||||
if (i == 2)
|
|
||||||
return 1;
|
|
||||||
if (i == 3)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasCustomName() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return player.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean a(EntityHuman entityhuman) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
super.update();
|
|
||||||
player.inventory.update();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.listeners;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
|
|
||||||
public class OpenInvEntityListener implements Listener {
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
|
|
||||||
Entity attacker = event.getDamager();
|
|
||||||
Entity defender = event.getEntity();
|
|
||||||
|
|
||||||
if (!(attacker instanceof Player) || !(defender instanceof Player)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player player = (Player) attacker;
|
|
||||||
|
|
||||||
if (player.getItemInHand().getType() == OpenInv.getOpenInvItem()) {
|
|
||||||
if (!OpenInv.getPlayerItemOpenInvStatus(player) || !OpenInv.hasPermission(player, Permissions.PERM_OPENINV)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player target = (Player) defender;
|
|
||||||
|
|
||||||
event.setDamage(0);
|
|
||||||
event.setCancelled(true);
|
|
||||||
|
|
||||||
player.performCommand("openinv " + target.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.listeners;
|
|
||||||
|
|
||||||
import org.bukkit.entity.HumanEntity;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
|
|
||||||
public class OpenInvInventoryListener implements Listener {
|
|
||||||
@EventHandler
|
|
||||||
public void onInventoryClick(InventoryClickEvent event) {
|
|
||||||
Inventory inventory = event.getInventory();
|
|
||||||
HumanEntity player = event.getWhoClicked();
|
|
||||||
|
|
||||||
if (!OpenInv.getInventoryAccess().check(inventory, player)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.lishid.openinv.listeners;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.Chest;
|
|
||||||
import org.bukkit.block.Sign;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.Event.Result;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.block.Action;
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.Permissions;
|
|
||||||
import com.lishid.openinv.internal.SpecialEnderChest;
|
|
||||||
import com.lishid.openinv.internal.SpecialPlayerInventory;
|
|
||||||
|
|
||||||
public class OpenInvPlayerListener implements Listener {
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
Player player = event.getPlayer();
|
|
||||||
|
|
||||||
SpecialPlayerInventory inventory = OpenInv.inventories.get(player.getUniqueId());
|
|
||||||
if (inventory != null) {
|
|
||||||
inventory.playerOnline(event.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecialEnderChest chest = OpenInv.enderChests.get(player.getUniqueId());
|
|
||||||
if (chest != null) {
|
|
||||||
chest.playerOnline(event.getPlayer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
|
||||||
Player player = event.getPlayer();
|
|
||||||
|
|
||||||
SpecialPlayerInventory inventory = OpenInv.inventories.get(player.getUniqueId());
|
|
||||||
if (inventory != null) {
|
|
||||||
inventory.playerOffline();
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecialEnderChest chest = OpenInv.enderChests.get(player.getUniqueId());
|
|
||||||
if (chest != null) {
|
|
||||||
chest.playerOffline();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
|
||||||
Player player = event.getPlayer();
|
|
||||||
|
|
||||||
if (player.isSneaking()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Action action = event.getAction();
|
|
||||||
Block block = event.getClickedBlock();
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case RIGHT_CLICK_BLOCK:
|
|
||||||
if (event.useInteractedBlock() == Result.DENY) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ender Chests
|
|
||||||
if (block.getType() == Material.ENDER_CHEST) {
|
|
||||||
if (OpenInv.hasPermission(player, Permissions.PERM_SILENT) && OpenInv.getPlayerSilentChestStatus(player)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
player.openInventory(player.getEnderChest());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chests
|
|
||||||
if (block.getState() instanceof Chest) {
|
|
||||||
boolean silentChest = false;
|
|
||||||
boolean anyChest = false;
|
|
||||||
int x = block.getX();
|
|
||||||
int y = block.getY();
|
|
||||||
int z = block.getZ();
|
|
||||||
|
|
||||||
if (OpenInv.hasPermission(player, Permissions.PERM_SILENT) && OpenInv.getPlayerSilentChestStatus(player)) {
|
|
||||||
silentChest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OpenInv.hasPermission(player, Permissions.PERM_ANYCHEST) && OpenInv.getPlayerAnyChestStatus(player)) {
|
|
||||||
try {
|
|
||||||
anyChest = OpenInv.getAnySilentChest().isAnyChestNeeded(player, x, y, z);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
player.sendMessage(ChatColor.RED + "Error while executing openinv. Unsupported CraftBukkit.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the anyChest or silentChest is active
|
|
||||||
if (anyChest || silentChest) {
|
|
||||||
if (!OpenInv.getAnySilentChest().activateChest(player, anyChest, silentChest, x, y, z)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signs
|
|
||||||
if (block.getState() instanceof Sign) {
|
|
||||||
try {
|
|
||||||
Sign sign = ((Sign) block.getState());
|
|
||||||
if (OpenInv.hasPermission(player, Permissions.PERM_OPENINV) && sign.getLine(0).equalsIgnoreCase("[openinv]")) {
|
|
||||||
String text = sign.getLine(1).trim() + sign.getLine(2).trim() + sign.getLine(3).trim();
|
|
||||||
player.performCommand("openinv " + text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
player.sendMessage("Internal Error.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case RIGHT_CLICK_AIR:
|
|
||||||
// OpenInv item
|
|
||||||
if (player.getItemInHand().getType() == OpenInv.getOpenInvItem() && OpenInv.getPlayerItemOpenInvStatus(player) && OpenInv.hasPermission(player, Permissions.PERM_OPENINV)) {
|
|
||||||
player.performCommand("openinv");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,98 +0,0 @@
|
|||||||
package com.lishid.openinv.utils;
|
|
||||||
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.json.simple.parser.JSONParser;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
|
|
||||||
public class UUIDFetcher implements Callable<Map<String, UUID>> {
|
|
||||||
private static final double PROFILES_PER_REQUEST = 100;
|
|
||||||
private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
|
|
||||||
private final JSONParser jsonParser = new JSONParser();
|
|
||||||
private final List<String> names;
|
|
||||||
private final boolean rateLimiting;
|
|
||||||
|
|
||||||
public UUIDFetcher(List<String> names, boolean rateLimiting) {
|
|
||||||
this.names = ImmutableList.copyOf(names);
|
|
||||||
this.rateLimiting = rateLimiting;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUIDFetcher(List<String> names) {
|
|
||||||
this(names, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, UUID> call() throws Exception {
|
|
||||||
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
|
|
||||||
int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST);
|
|
||||||
for (int i = 0; i < requests; i++) {
|
|
||||||
HttpURLConnection connection = createConnection();
|
|
||||||
String body = JSONArray.toJSONString(names.subList(i * 100, Math.min((i + 1) * 100, names.size())));
|
|
||||||
writeBody(connection, body);
|
|
||||||
JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
|
|
||||||
for (Object profile : array) {
|
|
||||||
JSONObject jsonProfile = (JSONObject) profile;
|
|
||||||
String id = (String) jsonProfile.get("id");
|
|
||||||
String name = (String) jsonProfile.get("name");
|
|
||||||
UUID uuid = UUIDFetcher.getUUID(id);
|
|
||||||
uuidMap.put(name.toLowerCase(), uuid);
|
|
||||||
}
|
|
||||||
if (rateLimiting && i != requests - 1) {
|
|
||||||
Thread.sleep(100L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uuidMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeBody(HttpURLConnection connection, String body) throws Exception {
|
|
||||||
OutputStream stream = connection.getOutputStream();
|
|
||||||
stream.write(body.getBytes());
|
|
||||||
stream.flush();
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HttpURLConnection createConnection() throws Exception {
|
|
||||||
URL url = new URL(PROFILE_URL);
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
connection.setRequestMethod("POST");
|
|
||||||
connection.setRequestProperty("Content-Type", "application/json");
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
connection.setDoInput(true);
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UUID getUUID(String id) {
|
|
||||||
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +id.substring(20, 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] toBytes(UUID uuid) {
|
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
|
|
||||||
byteBuffer.putLong(uuid.getMostSignificantBits());
|
|
||||||
byteBuffer.putLong(uuid.getLeastSignificantBits());
|
|
||||||
return byteBuffer.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UUID fromBytes(byte[] array) {
|
|
||||||
if (array.length != 16) {
|
|
||||||
throw new IllegalArgumentException("Illegal byte array length: " + array.length);
|
|
||||||
}
|
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
|
|
||||||
long mostSignificant = byteBuffer.getLong();
|
|
||||||
long leastSignificant = byteBuffer.getLong();
|
|
||||||
return new UUID(mostSignificant, leastSignificant);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UUID getUUIDOf(String name) throws Exception {
|
|
||||||
return new UUIDFetcher(Arrays.asList(name)).call().get(name);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,72 +0,0 @@
|
|||||||
package com.lishid.openinv.utils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public class UUIDUtil {
|
|
||||||
private static Player getPlayer(String name) {
|
|
||||||
Validate.notNull(name, "Name cannot be null");
|
|
||||||
|
|
||||||
Player found = null;
|
|
||||||
String lowerName = name.toLowerCase();
|
|
||||||
int delta = Integer.MAX_VALUE;
|
|
||||||
|
|
||||||
Collection<? extends Player> players = Bukkit.getOnlinePlayers();
|
|
||||||
for (Player player : players) {
|
|
||||||
if (player.getName().toLowerCase().startsWith(lowerName)) {
|
|
||||||
int curDelta = player.getName().length() - lowerName.length();
|
|
||||||
if (curDelta < delta) {
|
|
||||||
found = player;
|
|
||||||
delta = curDelta;
|
|
||||||
}
|
|
||||||
if (curDelta == 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private static UUID getUUIDLocally(String name) {
|
|
||||||
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name);
|
|
||||||
return offlinePlayer.hasPlayedBefore() ? offlinePlayer.getUniqueId() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UUID getUUIDOf(String name) {
|
|
||||||
UUID uuid;
|
|
||||||
Player player = getPlayer(name);
|
|
||||||
|
|
||||||
if (player != null) {
|
|
||||||
uuid = player.getUniqueId();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (Bukkit.getServer().getOnlineMode()) {
|
|
||||||
if (!Bukkit.getServer().isPrimaryThread()) {
|
|
||||||
UUIDFetcher fetcher = new UUIDFetcher(Arrays.asList(name));
|
|
||||||
Map<String, UUID> response;
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = fetcher.call();
|
|
||||||
uuid = response.get(name.toLowerCase());
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
uuid = getUUIDLocally(name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uuid = getUUIDLocally(name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uuid = getUUIDLocally(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return uuid;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +0,0 @@
|
|||||||
config-version: 2
|
|
||||||
notify:
|
|
||||||
any-chest: true
|
|
||||||
silent-chest: true
|
|
||||||
items:
|
|
||||||
open-inv: STICK
|
|
@@ -1,44 +0,0 @@
|
|||||||
name: OpenInv
|
|
||||||
main: com.lishid.openinv.OpenInv
|
|
||||||
version: 2.3.1
|
|
||||||
author: lishid
|
|
||||||
description: >
|
|
||||||
This plugin allows you to open a player's inventory as a chest and interact with it in real time.
|
|
||||||
commands:
|
|
||||||
openinv:
|
|
||||||
aliases: [oi, inv, open]
|
|
||||||
description: Opens a player's inventory.
|
|
||||||
usage: |
|
|
||||||
/<command> - Opens last person's inventory.
|
|
||||||
/<command> <player> - Opens a player's inventory.
|
|
||||||
openender:
|
|
||||||
aliases: [oe]
|
|
||||||
description: Opens a player's ender chest.
|
|
||||||
usage: |
|
|
||||||
/<command> - Opens last person's ender chest.
|
|
||||||
/<command> <player> - Opens a player's ender chest.
|
|
||||||
searchinv:
|
|
||||||
aliases: [si]
|
|
||||||
description: Searches and lists players that have a specific item in their inventory.
|
|
||||||
usage: |
|
|
||||||
/<command> <item> [minAmount] - Item can be the Item ID or the CraftBukkit Item Name, minAmount is the minimum amount to be considered.
|
|
||||||
searchender:
|
|
||||||
aliases: [se]
|
|
||||||
description: Searches and lists players that have a specific item in their ender chest.
|
|
||||||
usage: |
|
|
||||||
/<command> <item> [minAmount] - Item can be the Item ID or the CraftBukkit Item Name, minAmount is the minimum amount to be considered.
|
|
||||||
toggleopeninv:
|
|
||||||
aliases: [toi, toggleoi, toggleinv]
|
|
||||||
description: Toggles the item openinv function.
|
|
||||||
usage: |
|
|
||||||
/<command> [check] - Checks whether item openinv is enabled.
|
|
||||||
anychest:
|
|
||||||
aliases: [ac]
|
|
||||||
description: Toggles the any chest function, which allows opening of blocked chests.
|
|
||||||
usage: |
|
|
||||||
/<command> [check] - Checks whether any chest is enabled.
|
|
||||||
silentchest:
|
|
||||||
aliases: [sc, silent]
|
|
||||||
description: Toggles the silent chest function, which hides the animation of a chest when opened or closed, and suppresses the sound.
|
|
||||||
usage: |
|
|
||||||
/<command> [check] - Checks whether silent chest is enabled.
|
|
Reference in New Issue
Block a user