Compare commits
270 Commits
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 | ||
|
4f40459b96 | ||
|
791368b100 | ||
|
5dd3f5bbd7 | ||
|
d1d60e55d5 | ||
|
471b631838 | ||
|
2f1fd87435 | ||
|
a03c73f8d6 | ||
|
f7029e5ee2 | ||
|
802e405c4e | ||
|
55deabe56b | ||
|
f8e4e69e53 | ||
|
3c7d1696ff | ||
|
902def1dd7 | ||
|
f260ed1175 | ||
|
bc40e91215 | ||
|
120b35d394 | ||
|
ded568ec3f | ||
|
e958059572 | ||
|
d988becf1f | ||
|
e8476d5b05 | ||
|
1ea0307156 | ||
|
4ae47b09dc | ||
|
3e9bb63894 | ||
|
dce86d9c69 | ||
|
4013098201 | ||
|
56f633d58b | ||
|
6c1fb14cda | ||
|
ad0e55cf4c | ||
|
c4fb5489fa | ||
|
3d3006c681 | ||
|
a9d983ddc6 | ||
|
f6554a2a51 | ||
|
ec3426b827 | ||
|
d0494aa2e7 | ||
|
6adcd491db | ||
|
bc709336e1 | ||
|
7d56a04283 | ||
|
7851404d69 | ||
|
30b5acc3b4 | ||
|
29b0bc980f | ||
|
b05279ed4b | ||
|
88f3cb0a3f | ||
|
f48fdac085 |
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)."
|
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
**/.settings
|
||||
**/.project
|
||||
**/.classpath
|
||||
**/.idea/
|
||||
**.iml
|
||||
**/target/
|
||||
**/bin/
|
||||
**/out/
|
||||
**/dependency-reduced-pom.xml
|
||||
**/pom.xml.versionsBackup
|
@@ -1,3 +0,0 @@
|
||||
#Wed Jun 01 17:38:54 EDT 2011
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
|
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);
|
||||
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
||||
* 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.
|
||||
* 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
|
||||
* 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
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.lishid.openinv.internal;
|
||||
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
public interface ISpecialEnderChest extends ISpecialInventory {
|
||||
|
||||
public interface IInventoryAccess {
|
||||
public boolean check(Inventory inventory, HumanEntity player);
|
||||
}
|
@@ -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();
|
||||
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2014 lishid. All rights reserved.
|
||||
* 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.
|
||||
* 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
|
||||
* 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
|
||||
@@ -16,11 +16,6 @@
|
||||
|
||||
package com.lishid.openinv.internal;
|
||||
|
||||
import java.util.UUID;
|
||||
public interface ISpecialPlayerInventory extends ISpecialInventory {
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface IPlayerDataManager {
|
||||
public Player loadPlayer(String name);
|
||||
public Player loadPlayer(UUID uuid);
|
||||
}
|
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%'
|
104
pom.xml
Normal file
104
pom.xml
Normal file
@@ -0,0 +1,104 @@
|
||||
<!--
|
||||
~ 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>
|
||||
|
||||
<groupId>com.lishid</groupId>
|
||||
<artifactId>openinvparent</artifactId>
|
||||
<name>OpenInvParent</name>
|
||||
<url>http://dev.bukkit.org/bukkit-plugins/openinv/</url>
|
||||
<version>4.1.6-SNAPSHOT</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>api</module>
|
||||
<module>plugin</module>
|
||||
<module>internal</module>
|
||||
<module>assembly</module>
|
||||
</modules>
|
||||
|
||||
<profiles>
|
||||
|
||||
<!--
|
||||
~ N.B.: All version-specific code is handled in submodules of the internal module.
|
||||
~
|
||||
~ Internal submodules built by each profile are handled in internal/pom.xml
|
||||
-->
|
||||
|
||||
<profile>
|
||||
<id>all</id>
|
||||
<activation>
|
||||
<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,206 +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.logging.Logger;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
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.*;
|
||||
import com.lishid.openinv.internal.IAnySilentChest;
|
||||
import com.lishid.openinv.internal.IInventoryAccess;
|
||||
import com.lishid.openinv.internal.IPlayerDataManager;
|
||||
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||
import com.lishid.openinv.internal.InternalAccessor;
|
||||
import com.lishid.openinv.utils.UpdateManager;
|
||||
|
||||
/**
|
||||
* Open other player's inventory
|
||||
*
|
||||
* @author lishid
|
||||
*/
|
||||
public class OpenInv extends JavaPlugin {
|
||||
public static final Logger logger = Logger.getLogger("Minecraft.OpenInv");
|
||||
|
||||
public static HashMap<String, ISpecialPlayerInventory> inventories = new HashMap<String, ISpecialPlayerInventory>();
|
||||
public static HashMap<String, ISpecialEnderChest> enderChests = new HashMap<String, ISpecialEnderChest>();
|
||||
|
||||
private UpdateManager updater = new UpdateManager();
|
||||
|
||||
public static OpenInv mainPlugin;
|
||||
|
||||
public static IPlayerDataManager playerLoader;
|
||||
public static IInventoryAccess inventoryAccess;
|
||||
public static IAnySilentChest anySilentChest;
|
||||
|
||||
public void onEnable() {
|
||||
// Get plugin manager
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
|
||||
// Version check
|
||||
boolean success = InternalAccessor.Initialize(this.getServer());
|
||||
|
||||
if (!success) {
|
||||
OpenInv.log("Your version of CraftBukkit is not supported.");
|
||||
OpenInv.log("Please look for an updated version of OpenInv.");
|
||||
pm.disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
playerLoader = InternalAccessor.Instance.newPlayerDataManager();
|
||||
inventoryAccess = InternalAccessor.Instance.newInventoryAccess();
|
||||
anySilentChest = InternalAccessor.Instance.newAnySilentChest();
|
||||
|
||||
mainPlugin = this;
|
||||
FileConfiguration config = getConfig();
|
||||
config.set("CheckForUpdates", config.getBoolean("CheckForUpdates", true));
|
||||
config.set("NotifySilentChest", config.getBoolean("NotifySilentChest", true));
|
||||
config.set("NotifyAnyChest", config.getBoolean("NotifyAnyChest", true));
|
||||
config.set("ItemOpenInvItemID", config.getInt("ItemOpenInvItemID", 280));
|
||||
config.addDefault("ItemOpenInvItemID", 280);
|
||||
config.addDefault("CheckForUpdates", true);
|
||||
config.addDefault("NotifySilentChest", true);
|
||||
config.addDefault("NotifyAnyChest", true);
|
||||
config.options().copyDefaults(true);
|
||||
saveConfig();
|
||||
|
||||
pm.registerEvents(new OpenInvPlayerListener(), this);
|
||||
pm.registerEvents(new OpenInvEntityListener(), this);
|
||||
pm.registerEvents(new OpenInvInventoryListener(), this);
|
||||
|
||||
getCommand("openinv").setExecutor(new OpenInvPluginCommand(this));
|
||||
getCommand("searchinv").setExecutor(new SearchInvPluginCommand());
|
||||
getCommand("toggleopeninv").setExecutor(new ToggleOpenInvPluginCommand());
|
||||
getCommand("silentchest").setExecutor(new SilentChestPluginCommand(this));
|
||||
getCommand("anychest").setExecutor(new AnyChestPluginCommand(this));
|
||||
getCommand("openender").setExecutor(new OpenEnderPluginCommand(this));
|
||||
|
||||
updater.Initialize(this, getFile());
|
||||
}
|
||||
|
||||
public static boolean NotifySilentChest() {
|
||||
return mainPlugin.getConfig().getBoolean("NotifySilentChest", true);
|
||||
}
|
||||
|
||||
public static boolean NotifyAnyChest() {
|
||||
return mainPlugin.getConfig().getBoolean("NotifyAnyChest", true);
|
||||
}
|
||||
|
||||
public static boolean GetCheckForUpdates() {
|
||||
return mainPlugin.getConfig().getBoolean("CheckForUpdates", true);
|
||||
}
|
||||
|
||||
public static boolean GetPlayerItemOpenInvStatus(String name) {
|
||||
return mainPlugin.getConfig().getBoolean("ItemOpenInv." + name.toLowerCase() + ".toggle", false);
|
||||
}
|
||||
|
||||
public static void SetPlayerItemOpenInvStatus(String name, boolean status) {
|
||||
mainPlugin.getConfig().set("ItemOpenInv." + name.toLowerCase() + ".toggle", status);
|
||||
mainPlugin.saveConfig();
|
||||
}
|
||||
|
||||
public static boolean GetPlayerSilentChestStatus(String name) {
|
||||
return mainPlugin.getConfig().getBoolean("SilentChest." + name.toLowerCase() + ".toggle", false);
|
||||
}
|
||||
|
||||
public static void SetPlayerSilentChestStatus(String name, boolean status) {
|
||||
mainPlugin.getConfig().set("SilentChest." + name.toLowerCase() + ".toggle", status);
|
||||
mainPlugin.saveConfig();
|
||||
}
|
||||
|
||||
public static boolean GetPlayerAnyChestStatus(String name) {
|
||||
return mainPlugin.getConfig().getBoolean("AnyChest." + name.toLowerCase() + ".toggle", true);
|
||||
}
|
||||
|
||||
public static void SetPlayerAnyChestStatus(String name, boolean status) {
|
||||
mainPlugin.getConfig().set("AnyChest." + name.toLowerCase() + ".toggle", status);
|
||||
mainPlugin.saveConfig();
|
||||
}
|
||||
|
||||
public static int GetItemOpenInvItem() {
|
||||
if (mainPlugin.getConfig().get("ItemOpenInvItemID") == null) {
|
||||
SaveToConfig("ItemOpenInvItemID", 280);
|
||||
}
|
||||
return mainPlugin.getConfig().getInt("ItemOpenInvItemID", 280);
|
||||
}
|
||||
|
||||
public static Object GetFromConfig(String data, Object defaultValue) {
|
||||
Object val = mainPlugin.getConfig().get(data);
|
||||
if (val == null) {
|
||||
mainPlugin.getConfig().set(data, defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveToConfig(String data, Object value) {
|
||||
mainPlugin.getConfig().set(data, value);
|
||||
mainPlugin.saveConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an information
|
||||
*/
|
||||
public static void log(String text) {
|
||||
logger.info("[OpenInv] " + text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error
|
||||
*/
|
||||
public static void log(Throwable e) {
|
||||
logger.severe("[OpenInv] " + e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
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 enderchest");
|
||||
player.sendMessage(ChatColor.GREEN + " (aliases: oe, enderchest)");
|
||||
player.sendMessage(ChatColor.GREEN + "/toggleopeninv - Toggle item openinv function");
|
||||
player.sendMessage(ChatColor.GREEN + " (aliases: toi, toggleoi, toggleinv)");
|
||||
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, search)");
|
||||
player.sendMessage(ChatColor.GREEN + "/anychest - Toggle anychest function");
|
||||
player.sendMessage(ChatColor.GREEN + " (aliases: ac)");
|
||||
player.sendMessage(ChatColor.GREEN + "/silentchest - Toggle 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,52 +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 org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class OpenInvEntityListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onEntityDamage(EntityDamageEvent event) {
|
||||
if (event instanceof EntityDamageByEntityEvent) {
|
||||
EntityDamageByEntityEvent evt = (EntityDamageByEntityEvent) event;
|
||||
Entity attacker = evt.getDamager();
|
||||
Entity defender = evt.getEntity();
|
||||
|
||||
if (!(attacker instanceof Player) || !(defender instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = (Player) attacker;
|
||||
|
||||
if (!(player.getItemInHand().getType().getId() == OpenInv.GetItemOpenInvItem()) || (!OpenInv.GetPlayerItemOpenInvStatus(player.getName())) || !OpenInv.hasPermission(player, "OpenInv.openinv")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player target = (Player) defender;
|
||||
player.performCommand("openinv " + target.getName());
|
||||
|
||||
evt.setDamage(0);
|
||||
evt.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,35 +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 org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
public class OpenInvInventoryListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
// If this is the top inventory
|
||||
// if (event.getView().convertSlot(event.getRawSlot()) == event.getRawSlot())
|
||||
// {
|
||||
if (!OpenInv.inventoryAccess.check(event.getInventory(), event.getWhoClicked())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
@@ -1,133 +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 org.bukkit.ChatColor;
|
||||
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.internal.ISpecialEnderChest;
|
||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||
|
||||
public class OpenInvPlayerListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
ISpecialPlayerInventory inventory = OpenInv.inventories.get(event.getPlayer().getName().toLowerCase());
|
||||
|
||||
if (inventory != null) {
|
||||
inventory.PlayerGoOnline(event.getPlayer());
|
||||
}
|
||||
|
||||
ISpecialEnderChest chest = OpenInv.enderChests.get(event.getPlayer().getName().toLowerCase());
|
||||
|
||||
if (chest != null) {
|
||||
chest.PlayerGoOnline(event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
ISpecialPlayerInventory inventory = OpenInv.inventories.get(event.getPlayer().getName().toLowerCase());
|
||||
if (inventory != null) {
|
||||
inventory.PlayerGoOffline();
|
||||
}
|
||||
ISpecialEnderChest chest = OpenInv.enderChests.get(event.getPlayer().getName().toLowerCase());
|
||||
if (chest != null) {
|
||||
chest.PlayerGoOffline();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (event.getPlayer().isSneaking()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.useInteractedBlock() == Result.DENY) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == org.bukkit.Material.ENDER_CHEST) {
|
||||
if (OpenInv.hasPermission(player, Permissions.PERM_SILENT) && OpenInv.GetPlayerSilentChestStatus(player.getName())) {
|
||||
event.setCancelled(true);
|
||||
player.openInventory(player.getEnderChest());
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getState() instanceof Chest) {
|
||||
boolean silentchest = false;
|
||||
boolean anychest = false;
|
||||
int x = event.getClickedBlock().getX();
|
||||
int y = event.getClickedBlock().getY();
|
||||
int z = event.getClickedBlock().getZ();
|
||||
|
||||
if (OpenInv.hasPermission(player, Permissions.PERM_SILENT) && OpenInv.GetPlayerSilentChestStatus(player.getName())) {
|
||||
silentchest = true;
|
||||
}
|
||||
|
||||
if (OpenInv.hasPermission(player, Permissions.PERM_ANYCHEST) && OpenInv.GetPlayerAnyChestStatus(player.getName())) {
|
||||
try {
|
||||
anychest = OpenInv.anySilentChest.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.anySilentChest.ActivateChest(player, anychest, silentchest, x, y, z)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getState() instanceof Sign) {
|
||||
try {
|
||||
Sign sign = ((Sign) event.getClickedBlock().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 ex) {
|
||||
player.sendMessage("Internal Error.");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
if (!(player.getItemInHand().getType().getId() == OpenInv.GetItemOpenInvItem()) || (!OpenInv.GetPlayerItemOpenInvStatus(player.getName())) || !OpenInv.hasPermission(player, Permissions.PERM_OPENINV)) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.performCommand("openinv");
|
||||
}
|
||||
}
|
||||
}
|
@@ -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,57 +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 AnyChestPluginCommand implements CommandExecutor {
|
||||
public AnyChestPluginCommand(OpenInv plugin) {
|
||||
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "You can't use this from the console.");
|
||||
return true;
|
||||
}
|
||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_ANYCHEST)) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission to use anychest.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
if (args[0].equalsIgnoreCase("check")) {
|
||||
if (OpenInv.GetPlayerAnyChestStatus(sender.getName()))
|
||||
sender.sendMessage("AnyChest is ON.");
|
||||
else
|
||||
sender.sendMessage("AnyChest is OFF.");
|
||||
}
|
||||
}
|
||||
|
||||
OpenInv.SetPlayerAnyChestStatus(sender.getName(), !OpenInv.GetPlayerAnyChestStatus(sender.getName()));
|
||||
sender.sendMessage("AnyChest is now " + (OpenInv.GetPlayerAnyChestStatus(sender.getName()) ? "On" : "Off") + ".");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,147 +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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.Permissions;
|
||||
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||
import com.lishid.openinv.internal.InternalAccessor;
|
||||
|
||||
public class OpenEnderPluginCommand implements CommandExecutor {
|
||||
private final OpenInv plugin;
|
||||
public static HashMap<Player, String> openEnderHistory = new HashMap<Player, String>();
|
||||
|
||||
public OpenEnderPluginCommand(OpenInv plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "You can't use this from the console.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_ENDERCHEST)) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission to access player enderchest");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("?")) {
|
||||
OpenInv.ShowHelp((Player) sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
final Player player = (Player) sender;
|
||||
|
||||
// History management
|
||||
String history = openEnderHistory.get(player);
|
||||
|
||||
if (history == null || history == "") {
|
||||
history = player.getName();
|
||||
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];
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.GREEN + "Starting inventory lookup.");
|
||||
final UUID senderID = player.getUniqueId();
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<Player> matches = Bukkit.matchPlayer(name);
|
||||
if (!matches.isEmpty()) {
|
||||
openInventory(player, matches.get(0).getUniqueId());
|
||||
return;
|
||||
}
|
||||
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name);
|
||||
if (Bukkit.getPlayer(senderID) == null) {
|
||||
return;
|
||||
}
|
||||
if (offlinePlayer == null || !offlinePlayer.hasPlayedBefore()) {
|
||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
||||
return;
|
||||
}
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (Bukkit.getPlayer(senderID) == null) {
|
||||
return;
|
||||
}
|
||||
openInventory(player, offlinePlayer.getUniqueId());
|
||||
}
|
||||
}.runTask(plugin);
|
||||
}
|
||||
}.runTaskAsynchronously(plugin);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void openInventory(Player player, UUID uuid) {
|
||||
|
||||
Player target = this.plugin.getServer().getPlayer(uuid);
|
||||
|
||||
if (target == null) {
|
||||
// Try loading the player's data
|
||||
target = OpenInv.playerLoader.loadPlayer(uuid);
|
||||
|
||||
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 enderchest");
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the target
|
||||
openEnderHistory.put(player, target.getName());
|
||||
|
||||
// Create the inventory
|
||||
ISpecialEnderChest chest = OpenInv.enderChests.get(target.getName().toLowerCase());
|
||||
if (chest == null) {
|
||||
chest = InternalAccessor.Instance.newSpecialEnderChest(target, !target.isOnline());
|
||||
}
|
||||
|
||||
// Open the inventory
|
||||
player.openInventory(chest.getBukkitInventory());
|
||||
}
|
||||
}
|
@@ -1,157 +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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.Permissions;
|
||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||
import com.lishid.openinv.internal.InternalAccessor;
|
||||
|
||||
public class OpenInvPluginCommand implements CommandExecutor {
|
||||
private final OpenInv plugin;
|
||||
public static HashMap<Player, String> openInvHistory = new HashMap<Player, String>();
|
||||
|
||||
public OpenInvPluginCommand(OpenInv plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "You can't use this 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
|
||||
String history = openInvHistory.get(player);
|
||||
|
||||
if (history == null || history == "") {
|
||||
history = player.getName();
|
||||
openInvHistory.put(player, history);
|
||||
}
|
||||
|
||||
final String name;
|
||||
|
||||
// Read from history if target is not named
|
||||
if (args.length < 1) {
|
||||
name = history;
|
||||
}
|
||||
else {
|
||||
name = args[0];
|
||||
}
|
||||
|
||||
final UUID senderID = player.getUniqueId();
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<Player> matches = Bukkit.matchPlayer(name);
|
||||
if (!matches.isEmpty()) {
|
||||
openInventory(player, matches.get(0).getUniqueId());
|
||||
return;
|
||||
}
|
||||
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name);
|
||||
if (Bukkit.getPlayer(senderID) == null) {
|
||||
return;
|
||||
}
|
||||
if (offlinePlayer == null || !offlinePlayer.hasPlayedBefore()) {
|
||||
player.sendMessage(ChatColor.RED + "Player not found!");
|
||||
return;
|
||||
}
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (Bukkit.getPlayer(senderID) == null) {
|
||||
return;
|
||||
}
|
||||
openInventory(player, offlinePlayer.getUniqueId());
|
||||
}
|
||||
}.runTask(plugin);
|
||||
}
|
||||
}.runTaskAsynchronously(plugin);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void openInventory(Player player, UUID uuid) {
|
||||
|
||||
Player target = this.plugin.getServer().getPlayer(uuid);
|
||||
|
||||
if (target == null) {
|
||||
// Try loading the player's data
|
||||
target = OpenInv.playerLoader.loadPlayer(uuid);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Crosswork 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, target.getName());
|
||||
|
||||
// Create the inventory
|
||||
ISpecialPlayerInventory inv = OpenInv.inventories.get(target.getName().toLowerCase());
|
||||
if (inv == null) {
|
||||
inv = InternalAccessor.Instance.newSpecialPlayerInventory(target, !target.isOnline());
|
||||
}
|
||||
|
||||
// Open the inventory
|
||||
player.openInventory(inv.getBukkitInventory());
|
||||
}
|
||||
}
|
@@ -1,77 +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 SearchInvPluginCommand implements CommandExecutor {
|
||||
public SearchInvPluginCommand() {
|
||||
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender instanceof Player) {
|
||||
if (!OpenInv.hasPermission(sender, Permissions.PERM_SEARCH)) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission to access player inventories");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String PlayerList = "";
|
||||
|
||||
Material material = null;
|
||||
int count = 1;
|
||||
|
||||
if (args.length >= 1) {
|
||||
String[] gData = null;
|
||||
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;
|
||||
}
|
||||
|
||||
for (Player templayer : Bukkit.getServer().getOnlinePlayers()) {
|
||||
if (templayer.getInventory().contains(material, count)) {
|
||||
PlayerList += templayer.getName() + " ";
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage("Players with the item " + material.toString() + ": " + PlayerList);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,57 +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 SilentChestPluginCommand implements CommandExecutor {
|
||||
public SilentChestPluginCommand(OpenInv plugin) {
|
||||
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "You can't use this 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;
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
if (args[0].equalsIgnoreCase("check")) {
|
||||
if (OpenInv.GetPlayerSilentChestStatus(sender.getName()))
|
||||
sender.sendMessage("SilentChest is ON.");
|
||||
else
|
||||
sender.sendMessage("SilentChest is OFF.");
|
||||
}
|
||||
}
|
||||
|
||||
OpenInv.SetPlayerSilentChestStatus(sender.getName(), !OpenInv.GetPlayerSilentChestStatus(sender.getName()));
|
||||
sender.sendMessage("SilentChest is now " + (OpenInv.GetPlayerSilentChestStatus(sender.getName()) ? "On" : "Off") + ".");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -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.commands;
|
||||
|
||||
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 ToggleOpenInvPluginCommand implements CommandExecutor {
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "You can't use this 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")) {
|
||||
if (OpenInv.GetPlayerItemOpenInvStatus(player.getName()))
|
||||
player.sendMessage("OpenInv with " + Material.getMaterial(OpenInv.GetItemOpenInvItem()).toString() + " is ON.");
|
||||
else
|
||||
player.sendMessage("OpenInv with " + Material.getMaterial(OpenInv.GetItemOpenInvItem()).toString() + " is OFF.");
|
||||
}
|
||||
}
|
||||
if (OpenInv.GetPlayerItemOpenInvStatus(player.getName())) {
|
||||
OpenInv.SetPlayerItemOpenInvStatus(player.getName(), false);
|
||||
player.sendMessage("OpenInv with " + Material.getMaterial(OpenInv.GetItemOpenInvItem()).toString() + " is OFF.");
|
||||
}
|
||||
else {
|
||||
OpenInv.SetPlayerItemOpenInvStatus(player.getName(), true);
|
||||
player.sendMessage("OpenInv with " + Material.getMaterial(OpenInv.GetItemOpenInvItem()).toString() + " is ON.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,25 +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;
|
||||
|
||||
public interface IAnySilentChest {
|
||||
public boolean IsAnyChestNeeded(Player p, int x, int y, int z);
|
||||
|
||||
public boolean ActivateChest(Player p, boolean anychest, boolean silentchest, int x, int y, int z);
|
||||
}
|
@@ -1,31 +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;
|
||||
|
||||
public interface ISpecialEnderChest {
|
||||
public Inventory getBukkitInventory();
|
||||
|
||||
public void InventoryRemovalCheck();
|
||||
|
||||
public void PlayerGoOnline(Player p);
|
||||
|
||||
public void PlayerGoOffline();
|
||||
|
||||
}
|
@@ -1,30 +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;
|
||||
|
||||
public interface ISpecialPlayerInventory {
|
||||
public Inventory getBukkitInventory();
|
||||
|
||||
public void InventoryRemovalCheck();
|
||||
|
||||
public void PlayerGoOnline(Player p);
|
||||
|
||||
public void PlayerGoOffline();
|
||||
}
|
@@ -1,105 +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.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
|
||||
public class InternalAccessor {
|
||||
public static InternalAccessor Instance;
|
||||
private String version;
|
||||
|
||||
/*
|
||||
* Returns false if version not supported
|
||||
*/
|
||||
public static boolean Initialize(Server server) {
|
||||
Instance = new InternalAccessor();
|
||||
String packageName = server.getClass().getPackage().getName();
|
||||
Instance.version = packageName.substring(packageName.lastIndexOf('.') + 1);
|
||||
|
||||
try {
|
||||
Class.forName("com.lishid.openinv.internal." + Instance.version + ".AnySilentChest");
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void PrintError() {
|
||||
OpenInv.log("OpenInv encountered an error with the CraftBukkit version \"" + Instance.version + "\". Please look for an updated version of OpenInv.");
|
||||
}
|
||||
|
||||
public IPlayerDataManager newPlayerDataManager() {
|
||||
return (IPlayerDataManager) createObject(IPlayerDataManager.class, "PlayerDataManager");
|
||||
}
|
||||
|
||||
public IInventoryAccess newInventoryAccess() {
|
||||
return (IInventoryAccess) createObject(IInventoryAccess.class, "InventoryAccess");
|
||||
}
|
||||
|
||||
public IAnySilentChest newAnySilentChest() {
|
||||
return (IAnySilentChest) createObject(IAnySilentChest.class, "AnySilentChest");
|
||||
}
|
||||
|
||||
public ISpecialPlayerInventory newSpecialPlayerInventory(Player player, boolean offline) {
|
||||
try {
|
||||
Class<?> internalClass = Class.forName("com.lishid.openinv.internal." + version + ".SpecialPlayerInventory");
|
||||
if (ISpecialPlayerInventory.class.isAssignableFrom(internalClass)) {
|
||||
return (ISpecialPlayerInventory) internalClass.getConstructor(Player.class, Boolean.class).newInstance(player, offline);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
PrintError();
|
||||
OpenInv.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ISpecialEnderChest newSpecialEnderChest(Player player, boolean offline) {
|
||||
try {
|
||||
Class<?> internalClass = Class.forName("com.lishid.openinv.internal." + version + ".SpecialEnderChest");
|
||||
if (ISpecialEnderChest.class.isAssignableFrom(internalClass)) {
|
||||
return (ISpecialEnderChest) internalClass.getConstructor(Player.class, Boolean.class).newInstance(player, offline);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
PrintError();
|
||||
OpenInv.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object createObject(Class<? extends Object> assignableClass, String className) {
|
||||
try {
|
||||
Class<?> internalClass = Class.forName("com.lishid.openinv.internal." + version + "." + className);
|
||||
if (assignableClass.isAssignableFrom(internalClass)) {
|
||||
return internalClass.getConstructor().newInstance();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
PrintError();
|
||||
OpenInv.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,124 +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.v1_8_R2;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.internal.IAnySilentChest;
|
||||
|
||||
//Volatile
|
||||
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer;
|
||||
|
||||
import net.minecraft.server.v1_8_R2.Block;
|
||||
import net.minecraft.server.v1_8_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_8_R2.EntityPlayer;
|
||||
import net.minecraft.server.v1_8_R2.IInventory;
|
||||
import net.minecraft.server.v1_8_R2.ITileInventory;
|
||||
import net.minecraft.server.v1_8_R2.InventoryLargeChest;
|
||||
import net.minecraft.server.v1_8_R2.PacketPlayOutOpenWindow;
|
||||
import net.minecraft.server.v1_8_R2.TileEntityChest;
|
||||
import net.minecraft.server.v1_8_R2.World;
|
||||
|
||||
public class AnySilentChest implements IAnySilentChest {
|
||||
@Override
|
||||
public boolean IsAnyChestNeeded(Player p, int x, int y, int z) {
|
||||
// FOR REFERENCE, LOOK AT net.minecraft.server.BlockChest
|
||||
EntityPlayer player = ((CraftPlayer) p).getHandle();
|
||||
World world = player.world;
|
||||
// If block on top
|
||||
if (world.getType(new BlockPosition(x, y + 1, z)).getBlock().c())
|
||||
return true;
|
||||
|
||||
int id = Block.getId(world.getType(new BlockPosition(x, y, z)).getBlock());
|
||||
|
||||
// If block next to chest is chest and has a block on top
|
||||
if ((Block.getId(world.getType(new BlockPosition(x - 1, y, z)).getBlock()) == id) && (world.getType(new BlockPosition(x - 1, y + 1, z)).getBlock().c()))
|
||||
return true;
|
||||
if ((Block.getId(world.getType(new BlockPosition(x + 1, y, z)).getBlock()) == id) && (world.getType(new BlockPosition(x + 1, y + 1, z)).getBlock().c()))
|
||||
return true;
|
||||
if ((Block.getId(world.getType(new BlockPosition(x, y, z - 1)).getBlock()) == id) && (world.getType(new BlockPosition(x, y + 1, z - 1)).getBlock().c()))
|
||||
return true;
|
||||
if ((Block.getId(world.getType(new BlockPosition(x, y, z + 1)).getBlock()) == id) && (world.getType(new BlockPosition(x, y + 1, z + 1)).getBlock().c()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ActivateChest(Player p, boolean anychest, boolean silentchest, int x, int y, int z) {
|
||||
EntityPlayer player = ((CraftPlayer) p).getHandle();
|
||||
World world = player.world;
|
||||
Object chest = world.getTileEntity(new BlockPosition(x, y, z));
|
||||
if (chest == null)
|
||||
return true;
|
||||
|
||||
int id = Block.getId(world.getType(new BlockPosition(x, y, z)).getBlock());
|
||||
|
||||
if (!anychest) {
|
||||
if (world.getType(new BlockPosition(x, y + 1, z)).getBlock().c())
|
||||
return true;
|
||||
if ((Block.getId(world.getType(new BlockPosition(x - 1, y, z)).getBlock()) == id) && (world.getType(new BlockPosition(x - 1, y + 1, z)).getBlock().c()))
|
||||
return true;
|
||||
if ((Block.getId(world.getType(new BlockPosition(x + 1, y, z)).getBlock()) == id) && (world.getType(new BlockPosition(x + 1, y + 1, z)).getBlock().c()))
|
||||
return true;
|
||||
if ((Block.getId(world.getType(new BlockPosition(x, y, z - 1)).getBlock()) == id) && (world.getType(new BlockPosition(x, y + 1, z - 1)).getBlock().c()))
|
||||
return true;
|
||||
if ((Block.getId(world.getType(new BlockPosition(x, y, z + 1)).getBlock()) == id) && (world.getType(new BlockPosition(x, y + 1, z + 1)).getBlock().c()))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Block.getId(world.getType(new BlockPosition(x - 1, y, z)).getBlock()) == id)
|
||||
chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(new BlockPosition(x - 1, y, z)), (ITileInventory) chest);
|
||||
if (Block.getId(world.getType(new BlockPosition(x + 1, y, z)).getBlock()) == id)
|
||||
chest = new InventoryLargeChest("Large chest", (ITileInventory) chest, (TileEntityChest) world.getTileEntity(new BlockPosition(x + 1, y, z)));
|
||||
if (Block.getId(world.getType(new BlockPosition(x, y, z - 1)).getBlock()) == id)
|
||||
chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(new BlockPosition(x, y, z - 1)), (ITileInventory) chest);
|
||||
if (Block.getId(world.getType(new BlockPosition(x, y, z + 1)).getBlock()) == id)
|
||||
chest = new InventoryLargeChest("Large chest", (ITileInventory) chest, (TileEntityChest) world.getTileEntity(new BlockPosition(x, y, z + 1)));
|
||||
|
||||
boolean returnValue = true;
|
||||
if (!silentchest) {
|
||||
player.openContainer((IInventory) chest);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
SilentContainerChest silentContainerChest = new SilentContainerChest(player.inventory, ((IInventory) chest), player);
|
||||
int windowId = player.nextContainerCounter();
|
||||
player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(windowId, "minecraft:chest", ((IInventory) chest).getScoreboardDisplayName(), ((IInventory) chest).getSize()));
|
||||
player.activeContainer = silentContainerChest;
|
||||
player.activeContainer.windowId = windowId;
|
||||
player.activeContainer.addSlotListener(player);
|
||||
if (OpenInv.NotifySilentChest()) {
|
||||
p.sendMessage("You are opening a chest silently.");
|
||||
}
|
||||
returnValue = false;
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
p.sendMessage(ChatColor.RED + "Error while sending silent chest.");
|
||||
}
|
||||
}
|
||||
|
||||
if (anychest && OpenInv.NotifyAnyChest()) {
|
||||
p.sendMessage("You are opening a blocked chest.");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
}
|
@@ -1,74 +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.v1_8_R2;
|
||||
|
||||
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;
|
||||
import com.lishid.openinv.internal.IInventoryAccess;
|
||||
|
||||
import org.bukkit.craftbukkit.v1_8_R2.inventory.CraftInventory;
|
||||
|
||||
//Volatile
|
||||
import net.minecraft.server.v1_8_R2.IInventory;
|
||||
|
||||
public class InventoryAccess implements IInventoryAccess {
|
||||
@Override
|
||||
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 iiventory
|
||||
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,132 +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.v1_8_R2;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.internal.IPlayerDataManager;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import org.bukkit.craftbukkit.v1_8_R2.CraftServer;
|
||||
|
||||
import net.minecraft.server.v1_8_R2.EntityPlayer;
|
||||
//Volatile
|
||||
import net.minecraft.server.v1_8_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_8_R2.PlayerInteractManager;
|
||||
|
||||
public class PlayerDataManager implements IPlayerDataManager {
|
||||
@Override
|
||||
public Player loadPlayer(String name) {
|
||||
try {
|
||||
UUID uuid = matchUser(name);
|
||||
if (uuid == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Default player folder
|
||||
File playerfolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "playerdata");
|
||||
if (!playerfolder.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
OfflinePlayer player = Bukkit.getOfflinePlayer(uuid);
|
||||
if (player == null) {
|
||||
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 == null) ? null : entity.getBukkitEntity();
|
||||
if (target != null) {
|
||||
// Load data
|
||||
target.loadData();
|
||||
// Return the entity
|
||||
return target;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
OpenInv.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static UUID matchUser(String search) {
|
||||
UUID found = null;
|
||||
|
||||
String lowerSearch = search.toLowerCase();
|
||||
int delta = 2147483647;
|
||||
|
||||
OfflinePlayer[] offlinePlayers = Bukkit.getOfflinePlayers();
|
||||
for (OfflinePlayer player : offlinePlayers) {
|
||||
String name = player.getName();
|
||||
|
||||
if (name == null){
|
||||
continue;
|
||||
}
|
||||
if (name.equalsIgnoreCase(search)){
|
||||
return player.getUniqueId();
|
||||
}
|
||||
if (name.toLowerCase().startsWith(lowerSearch)) {
|
||||
int curDelta = name.length() - lowerSearch.length();
|
||||
if (curDelta < delta) {
|
||||
found = player.getUniqueId();
|
||||
delta = curDelta;
|
||||
}
|
||||
if (curDelta == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.lishid.openinv.internal.IPlayerDataManager#loadPlayer(java.util.UUID)
|
||||
*/
|
||||
@Override
|
||||
public Player loadPlayer(UUID uuid) {
|
||||
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 == null) ? null : entity.getBukkitEntity();
|
||||
if (target != null) {
|
||||
// Load data
|
||||
target.loadData();
|
||||
// Return the entity
|
||||
return target;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,38 +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.v1_8_R2;
|
||||
|
||||
//Volatile
|
||||
import net.minecraft.server.v1_8_R2.ContainerChest;
|
||||
import net.minecraft.server.v1_8_R2.EntityHuman;
|
||||
import net.minecraft.server.v1_8_R2.IInventory;
|
||||
|
||||
public class SilentContainerChest extends ContainerChest {
|
||||
public IInventory inv;
|
||||
|
||||
public SilentContainerChest(IInventory i1, IInventory i2, EntityHuman e1) {
|
||||
super(i1, i2, e1);
|
||||
inv = i2;
|
||||
// close signal
|
||||
inv.closeContainer(e1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b(EntityHuman paramEntityHuman) {
|
||||
// Don't send close signal twice, might screw up
|
||||
}
|
||||
}
|
@@ -1,145 +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.v1_8_R2;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||
|
||||
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftHumanEntity;
|
||||
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_8_R2.inventory.CraftInventory;
|
||||
|
||||
//Volatile
|
||||
import net.minecraft.server.v1_8_R2.EntityHuman;
|
||||
import net.minecraft.server.v1_8_R2.IInventory;
|
||||
import net.minecraft.server.v1_8_R2.InventoryEnderChest;
|
||||
import net.minecraft.server.v1_8_R2.InventorySubcontainer;
|
||||
import net.minecraft.server.v1_8_R2.ItemStack;
|
||||
|
||||
public class SpecialEnderChest extends InventorySubcontainer implements IInventory, ISpecialEnderChest {
|
||||
public List<HumanEntity> transaction = new ArrayList<HumanEntity>();
|
||||
public boolean playerOnline = false;
|
||||
private final CraftPlayer owner;
|
||||
private final InventoryEnderChest enderChest;
|
||||
private int maxStack = MAX_STACK;
|
||||
private final CraftInventory inventory = new CraftInventory(this);
|
||||
|
||||
public SpecialEnderChest(Player p, Boolean online) {
|
||||
super(((CraftPlayer) p).getHandle().getEnderChest().getName(), ((CraftPlayer) p).getHandle().getEnderChest().hasCustomName(), ((CraftPlayer) p).getHandle().getEnderChest().getSize());
|
||||
CraftPlayer player = (CraftPlayer) p;
|
||||
this.enderChest = player.getHandle().getEnderChest();
|
||||
this.owner = player;
|
||||
this.items = enderChest.getContents();
|
||||
OpenInv.enderChests.put(owner.getName().toLowerCase(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getBukkitInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void InventoryRemovalCheck() {
|
||||
owner.saveData();
|
||||
if (transaction.isEmpty() && !playerOnline) {
|
||||
OpenInv.enderChests.remove(owner.getName().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void PlayerGoOnline(Player p) {
|
||||
if (!playerOnline) {
|
||||
try {
|
||||
InventoryEnderChest playerEnderChest = ((CraftPlayer) p).getHandle().getEnderChest();
|
||||
Field field = playerEnderChest.getClass().getField("items");
|
||||
field.setAccessible(true);
|
||||
field.set(playerEnderChest, this.items);
|
||||
}
|
||||
catch (Exception e) {}
|
||||
p.saveData();
|
||||
playerOnline = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void PlayerGoOffline() {
|
||||
playerOnline = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getContents() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(CraftHumanEntity who) {
|
||||
transaction.add(who);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(CraftHumanEntity who) {
|
||||
transaction.remove(who);
|
||||
this.InventoryRemovalCheck();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HumanEntity> getViewers() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryHolder getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxStackSize(int size) {
|
||||
maxStack = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return maxStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean a(EntityHuman entityhuman) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void startOpen() {
|
||||
|
||||
}
|
||||
|
||||
public void f() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
enderChest.update();
|
||||
}
|
||||
}
|
@@ -1,257 +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.v1_8_R2;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||
|
||||
//Volatile
|
||||
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftHumanEntity;
|
||||
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_8_R2.inventory.CraftInventory;
|
||||
|
||||
import net.minecraft.server.v1_8_R2.EntityHuman;
|
||||
import net.minecraft.server.v1_8_R2.ItemStack;
|
||||
import net.minecraft.server.v1_8_R2.PlayerInventory;
|
||||
|
||||
public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory {
|
||||
CraftPlayer owner;
|
||||
public boolean playerOnline = false;
|
||||
private final ItemStack[] extra = new ItemStack[5];
|
||||
private final CraftInventory inventory = new CraftInventory(this);
|
||||
|
||||
public SpecialPlayerInventory(Player p, Boolean online) {
|
||||
super(((CraftPlayer) p).getHandle());
|
||||
this.owner = ((CraftPlayer) p);
|
||||
this.playerOnline = online;
|
||||
this.items = player.inventory.items;
|
||||
this.armor = player.inventory.armor;
|
||||
OpenInv.inventories.put(owner.getName().toLowerCase(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getBukkitInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void InventoryRemovalCheck() {
|
||||
owner.saveData();
|
||||
if (transaction.isEmpty() && !playerOnline) {
|
||||
OpenInv.inventories.remove(owner.getName().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void PlayerGoOnline(Player player) {
|
||||
if (!playerOnline) {
|
||||
CraftPlayer p = (CraftPlayer) player;
|
||||
p.getHandle().inventory.items = this.items;
|
||||
p.getHandle().inventory.armor = this.armor;
|
||||
p.saveData();
|
||||
playerOnline = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void PlayerGoOffline() {
|
||||
playerOnline = false;
|
||||
this.InventoryRemovalCheck();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(CraftHumanEntity who) {
|
||||
super.onClose(who);
|
||||
this.InventoryRemovalCheck();
|
||||
}
|
||||
|
||||
@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 String getName() {
|
||||
if (player.getName().length() > 16) {
|
||||
return player.getName().substring(0, 16);
|
||||
}
|
||||
return player.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean a(EntityHuman entityhuman) {
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,510 +0,0 @@
|
||||
package com.lishid.openinv.utils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public final class ReflectionUtil {
|
||||
private ReflectionUtil() {}
|
||||
|
||||
public static Class<?> getClass(String name, PackageType type) throws Exception {
|
||||
return Class.forName(type + "." + name);
|
||||
}
|
||||
|
||||
public static Class<?> getClass(String name, SubPackageType type) throws Exception {
|
||||
return Class.forName(type + "." + name);
|
||||
}
|
||||
|
||||
public static Constructor<?> getConstructor(Class<?> clazz, Class<?>... parameterTypes) {
|
||||
Class<?>[] p = DataType.convertToPrimitive(parameterTypes);
|
||||
for (Constructor<?> c : clazz.getConstructors())
|
||||
if (DataType.equalsArray(DataType.convertToPrimitive(c.getParameterTypes()), p))
|
||||
return c;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Constructor<?> getConstructor(String className, PackageType type, Class<?>... parameterTypes) throws Exception {
|
||||
return getConstructor(getClass(className, type), parameterTypes);
|
||||
}
|
||||
|
||||
public static Constructor<?> getConstructor(String className, SubPackageType type, Class<?>... parameterTypes) throws Exception {
|
||||
return getConstructor(getClass(className, type), parameterTypes);
|
||||
}
|
||||
|
||||
public static Object newInstance(Class<?> clazz, Object... args) throws Exception {
|
||||
return getConstructor(clazz, DataType.convertToPrimitive(args)).newInstance(args);
|
||||
}
|
||||
|
||||
public static Object newInstance(String className, PackageType type, Object... args) throws Exception {
|
||||
return newInstance(getClass(className, type), args);
|
||||
}
|
||||
|
||||
public static Object newInstance(String className, SubPackageType type, Object... args) throws Exception {
|
||||
return newInstance(getClass(className, type), args);
|
||||
}
|
||||
|
||||
public static Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {
|
||||
Class<?>[] p = DataType.convertToPrimitive(parameterTypes);
|
||||
for (Method m : clazz.getMethods())
|
||||
if (m.getName().equals(name) && DataType.equalsArray(DataType.convertToPrimitive(m.getParameterTypes()), p))
|
||||
return m;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Method getMethod(String className, PackageType type, String name, Class<?>... parameterTypes) throws Exception {
|
||||
return getMethod(getClass(className, type), name, parameterTypes);
|
||||
}
|
||||
|
||||
public static Method getMethod(String className, SubPackageType type, String name, Class<?>... parameterTypes) throws Exception {
|
||||
return getMethod(getClass(className, type), name, parameterTypes);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(String name, Object instance, Object... args) throws Exception {
|
||||
return getMethod(instance.getClass(), name, DataType.convertToPrimitive(args)).invoke(instance, args);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Class<?> clazz, String name, Object instance, Object... args) throws Exception {
|
||||
return getMethod(clazz, name, DataType.convertToPrimitive(args)).invoke(instance, args);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(String className, PackageType type, String name, Object instance, Object... args) throws Exception {
|
||||
return invokeMethod(getClass(className, type), name, instance, args);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(String className, SubPackageType type, String name, Object instance, Object... args) throws Exception {
|
||||
return invokeMethod(getClass(className, type), name, instance, args);
|
||||
}
|
||||
|
||||
public static Field getField(Class<?> clazz, String name) throws Exception {
|
||||
Field f = clazz.getField(name);
|
||||
f.setAccessible(true);
|
||||
return f;
|
||||
}
|
||||
|
||||
public static Field getField(String className, PackageType type, String name) throws Exception {
|
||||
return getField(getClass(className, type), name);
|
||||
}
|
||||
|
||||
public static Field getField(String className, SubPackageType type, String name) throws Exception {
|
||||
return getField(getClass(className, type), name);
|
||||
}
|
||||
|
||||
public static Field getDeclaredField(Class<?> clazz, String name) throws Exception {
|
||||
Field f = clazz.getDeclaredField(name);
|
||||
f.setAccessible(true);
|
||||
return f;
|
||||
}
|
||||
|
||||
public static Field getDeclaredField(String className, PackageType type, String name) throws Exception {
|
||||
return getDeclaredField(getClass(className, type), name);
|
||||
}
|
||||
|
||||
public static Field getDeclaredField(String className, SubPackageType type, String name) throws Exception {
|
||||
return getDeclaredField(getClass(className, type), name);
|
||||
}
|
||||
|
||||
public static Object getValue(Object instance, String fieldName) throws Exception {
|
||||
return getField(instance.getClass(), fieldName).get(instance);
|
||||
}
|
||||
|
||||
public static Object getValue(Class<?> clazz, Object instance, String fieldName) throws Exception {
|
||||
return getField(clazz, fieldName).get(instance);
|
||||
}
|
||||
|
||||
public static Object getValue(String className, PackageType type, Object instance, String fieldName) throws Exception {
|
||||
return getValue(getClass(className, type), instance, fieldName);
|
||||
}
|
||||
|
||||
public static Object getValue(String className, SubPackageType type, Object instance, String fieldName) throws Exception {
|
||||
return getValue(getClass(className, type), instance, fieldName);
|
||||
}
|
||||
|
||||
public static Object getDeclaredValue(Object instance, String fieldName) throws Exception {
|
||||
return getDeclaredField(instance.getClass(), fieldName).get(instance);
|
||||
}
|
||||
|
||||
public static Object getDeclaredValue(Class<?> clazz, Object instance, String fieldName) throws Exception {
|
||||
return getDeclaredField(clazz, fieldName).get(instance);
|
||||
}
|
||||
|
||||
public static Object getDeclaredValue(String className, PackageType type, Object instance, String fieldName) throws Exception {
|
||||
return getDeclaredValue(getClass(className, type), instance, fieldName);
|
||||
}
|
||||
|
||||
public static Object getDeclaredValue(String className, SubPackageType type, Object instance, String fieldName) throws Exception {
|
||||
return getDeclaredValue(getClass(className, type), instance, fieldName);
|
||||
}
|
||||
|
||||
public static void setValue(Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
Field f = getField(instance.getClass(), fieldName);
|
||||
f.set(instance, fieldValue);
|
||||
}
|
||||
|
||||
public static void setValue(Object instance, FieldPair pair) throws Exception {
|
||||
setValue(instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setValue(Class<?> clazz, Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
Field f = getField(clazz, fieldName);
|
||||
f.set(instance, fieldValue);
|
||||
}
|
||||
|
||||
public static void setValue(Class<?> clazz, Object instance, FieldPair pair) throws Exception {
|
||||
setValue(clazz, instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setValue(String className, PackageType type, Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
setValue(getClass(className, type), instance, fieldName, fieldValue);
|
||||
}
|
||||
|
||||
public static void setValue(String className, PackageType type, Object instance, FieldPair pair) throws Exception {
|
||||
setValue(className, type, instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setValue(String className, SubPackageType type, Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
setValue(getClass(className, type), instance, fieldName, fieldValue);
|
||||
}
|
||||
|
||||
public static void setValue(String className, SubPackageType type, Object instance, FieldPair pair) throws Exception {
|
||||
setValue(className, type, instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setValues(Object instance, FieldPair... pairs) throws Exception {
|
||||
for (FieldPair pair : pairs)
|
||||
setValue(instance, pair);
|
||||
}
|
||||
|
||||
public static void setValues(Class<?> clazz, Object instance, FieldPair... pairs) throws Exception {
|
||||
for (FieldPair pair : pairs)
|
||||
setValue(clazz, instance, pair);
|
||||
}
|
||||
|
||||
public static void setValues(String className, PackageType type, Object instance, FieldPair... pairs) throws Exception {
|
||||
setValues(getClass(className, type), instance, pairs);
|
||||
}
|
||||
|
||||
public static void setValues(String className, SubPackageType type, Object instance, FieldPair... pairs) throws Exception {
|
||||
setValues(getClass(className, type), instance, pairs);
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
Field f = getDeclaredField(instance.getClass(), fieldName);
|
||||
f.set(instance, fieldValue);
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(Object instance, FieldPair pair) throws Exception {
|
||||
setDeclaredValue(instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(Class<?> clazz, Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
Field f = getDeclaredField(clazz, fieldName);
|
||||
f.set(instance, fieldValue);
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(Class<?> clazz, Object instance, FieldPair pair) throws Exception {
|
||||
setDeclaredValue(clazz, instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(String className, PackageType type, Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
setDeclaredValue(getClass(className, type), instance, fieldName, fieldValue);
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(String className, PackageType type, Object instance, FieldPair pair) throws Exception {
|
||||
setDeclaredValue(className, type, instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(String className, SubPackageType type, Object instance, String fieldName, Object fieldValue) throws Exception {
|
||||
setDeclaredValue(getClass(className, type), instance, fieldName, fieldValue);
|
||||
}
|
||||
|
||||
public static void setDeclaredValue(String className, SubPackageType type, Object instance, FieldPair pair) throws Exception {
|
||||
setDeclaredValue(className, type, instance, pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
public static void setDeclaredValues(Object instance, FieldPair... pairs) throws Exception {
|
||||
for (FieldPair pair : pairs)
|
||||
setDeclaredValue(instance, pair);
|
||||
}
|
||||
|
||||
public static void setDeclaredValues(Class<?> clazz, Object instance, FieldPair... pairs) throws Exception {
|
||||
for (FieldPair pair : pairs)
|
||||
setDeclaredValue(clazz, instance, pair);
|
||||
}
|
||||
|
||||
public static void setDeclaredValues(String className, PackageType type, Object instance, FieldPair... pairs) throws Exception {
|
||||
setDeclaredValues(getClass(className, type), instance, pairs);
|
||||
}
|
||||
|
||||
public static void setDeclaredValues(String className, SubPackageType type, Object instance, FieldPair... pairs) throws Exception {
|
||||
setDeclaredValues(getClass(className, type), instance, pairs);
|
||||
}
|
||||
|
||||
public enum DataType {
|
||||
BYTE(byte.class, Byte.class),
|
||||
SHORT(short.class, Short.class),
|
||||
INTEGER(int.class, Integer.class),
|
||||
LONG(long.class, Long.class),
|
||||
CHARACTER(char.class, Character.class),
|
||||
FLOAT(float.class, Float.class),
|
||||
DOUBLE(double.class, Double.class),
|
||||
BOOLEAN(boolean.class, Boolean.class);
|
||||
|
||||
private static final Map<Class<?>, DataType> CLASS_MAP = new HashMap<Class<?>, DataType>();
|
||||
private final Class<?> primitive;
|
||||
private final Class<?> reference;
|
||||
|
||||
static {
|
||||
for (DataType t : values()) {
|
||||
CLASS_MAP.put(t.primitive, t);
|
||||
CLASS_MAP.put(t.reference, t);
|
||||
}
|
||||
}
|
||||
|
||||
private DataType(Class<?> primitive, Class<?> reference) {
|
||||
this.primitive = primitive;
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
public Class<?> getPrimitive() {
|
||||
return this.primitive;
|
||||
}
|
||||
|
||||
public Class<?> getReference() {
|
||||
return this.reference;
|
||||
}
|
||||
|
||||
public static DataType fromClass(Class<?> c) {
|
||||
return CLASS_MAP.get(c);
|
||||
}
|
||||
|
||||
public static Class<?> getPrimitive(Class<?> c) {
|
||||
DataType t = fromClass(c);
|
||||
return t == null ? c : t.getPrimitive();
|
||||
}
|
||||
|
||||
public static Class<?> getReference(Class<?> c) {
|
||||
DataType t = fromClass(c);
|
||||
return t == null ? c : t.getReference();
|
||||
}
|
||||
|
||||
public static Class<?>[] convertToPrimitive(Class<?>[] classes) {
|
||||
int length = classes == null ? 0 : classes.length;
|
||||
Class<?>[] types = new Class<?>[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
types[i] = getPrimitive(classes[i]);
|
||||
return types;
|
||||
}
|
||||
|
||||
public static Class<?>[] convertToPrimitive(Object[] objects) {
|
||||
int length = objects == null ? 0 : objects.length;
|
||||
Class<?>[] types = new Class<?>[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
types[i] = getPrimitive(objects[i].getClass());
|
||||
return types;
|
||||
}
|
||||
|
||||
public static boolean equalsArray(Class<?>[] a1, Class<?>[] a2) {
|
||||
if (a1 == null || a2 == null || a1.length != a2.length)
|
||||
return false;
|
||||
for (int i = 0; i < a1.length; i++)
|
||||
if (!a1[i].equals(a2[i]) && !a1[i].isAssignableFrom(a2[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public final class FieldPair {
|
||||
private final String name;
|
||||
private final Object value;
|
||||
|
||||
public FieldPair(String name, Object value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PackageType {
|
||||
MINECRAFT_SERVER("net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().substring(23)),
|
||||
CRAFTBUKKIT(Bukkit.getServer().getClass().getPackage().getName());
|
||||
|
||||
private final String name;
|
||||
|
||||
private PackageType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SubPackageType {
|
||||
BLOCK,
|
||||
CHUNKIO,
|
||||
COMMAND,
|
||||
CONVERSATIONS,
|
||||
ENCHANTMENS,
|
||||
ENTITY,
|
||||
EVENT,
|
||||
GENERATOR,
|
||||
HELP,
|
||||
INVENTORY,
|
||||
MAP,
|
||||
METADATA,
|
||||
POTION,
|
||||
PROJECTILES,
|
||||
SCHEDULER,
|
||||
SCOREBOARD,
|
||||
UPDATER,
|
||||
UTIL;
|
||||
|
||||
private final String name;
|
||||
|
||||
private SubPackageType() {
|
||||
name = PackageType.CRAFTBUKKIT + "." + name().toLowerCase();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PacketType {
|
||||
HANDSHAKING_IN_SET_PROTOCOL("PacketHandshakingInSetProtocol"),
|
||||
LOGIN_IN_ENCRYPTION_BEGIN("PacketLoginInEncryptionBegin"),
|
||||
LOGIN_IN_START("PacketLoginInStart"),
|
||||
LOGIN_OUT_DISCONNECT("PacketLoginOutDisconnect"),
|
||||
LOGIN_OUT_ENCRYPTION_BEGIN("PacketLoginOutEncryptionBegin"),
|
||||
LOGIN_OUT_SUCCESS("PacketLoginOutSuccess"),
|
||||
PLAY_IN_ABILITIES("PacketPlayInAbilities"),
|
||||
PLAY_IN_ARM_ANIMATION("PacketPlayInArmAnimation"),
|
||||
PLAY_IN_BLOCK_DIG("PacketPlayInBlockDig"),
|
||||
PLAY_IN_BLOCK_PLACE("PacketPlayInBlockPlace"),
|
||||
PLAY_IN_CHAT("PacketPlayInChat"),
|
||||
PLAY_IN_CLIENT_COMMAND("PacketPlayInClientCommand"),
|
||||
PLAY_IN_CLOSE_WINDOW("PacketPlayInCloseWindow"),
|
||||
PLAY_IN_CUSTOM_PAYLOAD("PacketPlayInCustomPayload"),
|
||||
PLAY_IN_ENCHANT_ITEM("PacketPlayInEnchantItem"),
|
||||
PLAY_IN_ENTITY_ACTION("PacketPlayInEntityAction"),
|
||||
PLAY_IN_FLYING("PacketPlayInFlying"),
|
||||
PLAY_IN_HELD_ITEM_SLOT("PacketPlayInHeldItemSlot"),
|
||||
PLAY_IN_KEEP_ALIVE("PacketPlayInKeepAlive"),
|
||||
PLAY_IN_LOOK("PacketPlayInLook"),
|
||||
PLAY_IN_POSITION("PacketPlayInPosition"),
|
||||
PLAY_IN_POSITION_LOOK("PacketPlayInPositionLook"),
|
||||
PLAY_IN_SET_CREATIVE_SLOT("PacketPlayInSetCreativeSlot "),
|
||||
PLAY_IN_SETTINGS("PacketPlayInSettings"),
|
||||
PLAY_IN_STEER_VEHICLE("PacketPlayInSteerVehicle"),
|
||||
PLAY_IN_TAB_COMPLETE("PacketPlayInTabComplete"),
|
||||
PLAY_IN_TRANSACTION("PacketPlayInTransaction"),
|
||||
PLAY_IN_UPDATE_SIGN("PacketPlayInUpdateSign"),
|
||||
PLAY_IN_USE_ENTITY("PacketPlayInUseEntity"),
|
||||
PLAY_IN_WINDOW_CLICK("PacketPlayInWindowClick"),
|
||||
PLAY_OUT_ABILITIES("PacketPlayOutAbilities"),
|
||||
PLAY_OUT_ANIMATION("PacketPlayOutAnimation"),
|
||||
PLAY_OUT_ATTACH_ENTITY("PacketPlayOutAttachEntity"),
|
||||
PLAY_OUT_BED("PacketPlayOutBed"),
|
||||
PLAY_OUT_BLOCK_ACTION("PacketPlayOutBlockAction"),
|
||||
PLAY_OUT_BLOCK_BREAK_ANIMATION("PacketPlayOutBlockBreakAnimation"),
|
||||
PLAY_OUT_BLOCK_CHANGE("PacketPlayOutBlockChange"),
|
||||
PLAY_OUT_CHAT("PacketPlayOutChat"),
|
||||
PLAY_OUT_CLOSE_WINDOW("PacketPlayOutCloseWindow"),
|
||||
PLAY_OUT_COLLECT("PacketPlayOutCollect"),
|
||||
PLAY_OUT_CRAFT_PROGRESS_BAR("PacketPlayOutCraftProgressBar"),
|
||||
PLAY_OUT_CUSTOM_PAYLOAD("PacketPlayOutCustomPayload"),
|
||||
PLAY_OUT_ENTITY("PacketPlayOutEntity"),
|
||||
PLAY_OUT_ENTITY_DESTROY("PacketPlayOutEntityDestroy"),
|
||||
PLAY_OUT_ENTITY_EFFECT("PacketPlayOutEntityEffect"),
|
||||
PLAY_OUT_ENTITY_EQUIPMENT("PacketPlayOutEntityEquipment"),
|
||||
PLAY_OUT_ENTITY_HEAD_ROTATION("PacketPlayOutEntityHeadRotation"),
|
||||
PLAY_OUT_ENTITY_LOOK("PacketPlayOutEntityLook"),
|
||||
PLAY_OUT_ENTITY_METADATA("PacketPlayOutEntityMetadata"),
|
||||
PLAY_OUT_ENTITY_STATUS("PacketPlayOutEntityStatus"),
|
||||
PLAY_OUT_ENTITY_TELEPORT("PacketPlayOutEntityTeleport"),
|
||||
PLAY_OUT_ENTITY_VELOCITY("PacketPlayOutEntityVelocity"),
|
||||
PLAY_OUT_EXPERIENCE("PacketPlayOutExperience"),
|
||||
PLAY_OUT_EXPLOSION("PacketPlayOutExplosion"),
|
||||
PLAY_OUT_GAME_STATE_CHANGE("PacketPlayOutGameStateChange"),
|
||||
PLAY_OUT_HELD_ITEM_SLOT("PacketPlayOutHeldItemSlot"),
|
||||
PLAY_OUT_KEEP_ALIVE("PacketPlayOutKeepAlive"),
|
||||
PLAY_OUT_KICK_DISCONNECT("PacketPlayOutKickDisconnect"),
|
||||
PLAY_OUT_LOGIN("PacketPlayOutLogin"),
|
||||
PLAY_OUT_MAP("PacketPlayOutMap"),
|
||||
PLAY_OUT_MAP_CHUNK("PacketPlayOutMapChunk"),
|
||||
PLAY_OUT_MAP_CHUNK_BULK("PacketPlayOutMapChunkBulk"),
|
||||
PLAY_OUT_MULTI_BLOCK_CHANGE("PacketPlayOutMultiBlockChange"),
|
||||
PLAY_OUT_NAMED_ENTITY_SPAWN("PacketPlayOutNamedEntitySpawn"),
|
||||
PLAY_OUT_NAMED_SOUND_EFFECT("PacketPlayOutNamedSoundEffect"),
|
||||
PLAY_OUT_OPEN_SIGN_EDITOR("PacketPlayOutOpenSignEditor"),
|
||||
PLAY_OUT_OPEN_WINDOW("PacketPlayOutOpenWindow"),
|
||||
PLAY_OUT_PLAYER_INFO("PacketPlayOutPlayerInfo"),
|
||||
PLAY_OUT_POSITION("PacketPlayOutPosition"),
|
||||
PLAY_OUT_REL_ENTITY_MOVE("PacketPlayOutRelEntityMove"),
|
||||
PLAY_OUT_REL_ENTITY_MOVE_LOOK("PacketPlayOutRelEntityMoveLook"),
|
||||
PLAY_OUT_REMOVE_ENTITY_EFFECT("PacketPlayOutRemoveEntityEffect"),
|
||||
PLAY_OUT_RESPAWN("PacketPlayOutRespawn"),
|
||||
PLAY_OUT_SCOREBOARD_DISPLAY_OBJECTIVE("PacketPlayOutScoreboardDisplayObjective"),
|
||||
PLAY_OUT_SCOREBOARD_OBJECTIVE("PacketPlayOutScoreboardObjective"),
|
||||
PLAY_OUT_SCOREBOARD_SCORE("PacketPlayOutScoreboardScore"),
|
||||
PLAY_OUT_SCOREBOARD_TEAM("PacketPlayOutScoreboardTeam"),
|
||||
PLAY_OUT_SET_SLOT("PacketPlayOutSetSlot"),
|
||||
PLAY_OUT_SPAWN_ENTITY("PacketPlayOutSpawnEntity"),
|
||||
PLAY_OUT_SPAWN_ENTITY_EXPERIENCE_ORB("PacketPlayOutSpawnEntityExperienceOrb"),
|
||||
PLAY_OUT_SPAWN_ENTITY_LIVING("PacketPlayOutSpawnEntityLiving"),
|
||||
PLAY_OUT_SPAWN_ENTITY_PAINTING("PacketPlayOutSpawnEntityPainting"),
|
||||
PLAY_OUT_SPAWN_ENTITY_WEATHER("PacketPlayOutSpawnEntityWeather"),
|
||||
PLAY_OUT_SPAWN_POSITION("PacketPlayOutSpawnPosition"),
|
||||
PLAY_OUT_STATISTIC("PacketPlayOutStatistic"),
|
||||
PLAY_OUT_TAB_COMPLETE("PacketPlayOutTabComplete"),
|
||||
PLAY_OUT_TILE_ENTITY_DATA("PacketPlayOutTileEntityData"),
|
||||
PLAY_OUT_TRANSACTION("PacketPlayOutTransaction"),
|
||||
PLAY_OUT_UPDATE_ATTRIBUTES("PacketPlayOutUpdateAttributes"),
|
||||
PLAY_OUT_UPDATE_HEALTH("PacketPlayOutUpdateHealth"),
|
||||
PLAY_OUT_UPDATE_SIGN("PacketPlayOutUpdateSign"),
|
||||
PLAY_OUT_UPDATE_TIME("PacketPlayOutUpdateTime"),
|
||||
PLAY_OUT_WINDOW_ITEMS("PacketPlayOutWindowItems"),
|
||||
PLAY_OUT_WORLD_EVENT("PacketPlayOutWorldEvent"),
|
||||
PLAY_OUT_WORLD_PARTICLES("PacketPlayOutWorldParticles"),
|
||||
STATUS_IN_PING("PacketStatusInPing"),
|
||||
STATUS_IN_START("PacketStatusInStart"),
|
||||
STATUS_OUT_PONG("PacketStatusOutPong"),
|
||||
STATUS_OUT_SERVER_INFO("PacketStatusOutServerInfo");
|
||||
|
||||
private final String name;
|
||||
private Class<?> packet;
|
||||
|
||||
private PacketType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
public Class<?> getPacket() throws Exception {
|
||||
return packet == null ? packet = ReflectionUtil.getClass(name, PackageType.MINECRAFT_SERVER) : packet;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
package com.lishid.openinv.utils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.utils.Updater.UpdateResult;
|
||||
|
||||
public class UpdateManager {
|
||||
public Updater updater;
|
||||
|
||||
public void Initialize(OpenInv plugin, File file) {
|
||||
updater = new Updater(plugin, 31432, file);
|
||||
|
||||
// Create task to update
|
||||
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Check for updates
|
||||
if (OpenInv.GetCheckForUpdates()) {
|
||||
UpdateResult result = updater.update();
|
||||
if (result != UpdateResult.NO_UPDATE) {
|
||||
if (result == UpdateResult.SUCCESS) {
|
||||
OpenInv.log("Update found! Downloaded new version.");
|
||||
OpenInv.log("This behaviour can be disabled in the config.yml");
|
||||
}
|
||||
else {
|
||||
OpenInv.log("Update failed, reason: " + result.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, 20 * 60 * 1000); // Update every once a while
|
||||
}
|
||||
}
|
@@ -1,412 +0,0 @@
|
||||
/*
|
||||
* Updater for Bukkit.
|
||||
*
|
||||
* This class provides the means to safely and easily update a plugin, or check to see if it is updated using dev.bukkit.org
|
||||
*/
|
||||
|
||||
package com.lishid.openinv.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/**
|
||||
* Check dev.bukkit.org to find updates for a given plugin, and download the updates if needed.
|
||||
* <p/>
|
||||
* <b>VERY, VERY IMPORTANT</b>: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed
|
||||
* auto-updating. <br>
|
||||
* It is a <b>BUKKIT POLICY</b> that you include a boolean value in your config that prevents the auto-updater from running <b>AT ALL</b>. <br>
|
||||
* If you fail to include this option in your config, your plugin will be <b>REJECTED</b> when you attempt to submit it to dev.bukkit.org.
|
||||
* <p/>
|
||||
* An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater. <br>
|
||||
* If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l
|
||||
*
|
||||
* @author Gravity
|
||||
* @version 2.0
|
||||
*/
|
||||
|
||||
public class Updater {
|
||||
|
||||
private Plugin plugin;
|
||||
private String versionName;
|
||||
private String versionLink;
|
||||
@SuppressWarnings("unused")
|
||||
private String versionType;
|
||||
@SuppressWarnings("unused")
|
||||
private String versionGameVersion;
|
||||
|
||||
private boolean announce; // Whether to announce file downloads
|
||||
|
||||
private URL url; // Connecting to RSS
|
||||
private File file; // The plugin's file
|
||||
|
||||
private int id = 31432; // Project's Curse ID
|
||||
// SEE https://dev.bukkit.org/home/servermods-apikey/
|
||||
private String apiKey = null; // BukkitDev ServerMods API key
|
||||
private static final String TITLE_VALUE = "name"; // Gets remote file's title
|
||||
private static final String LINK_VALUE = "downloadUrl"; // Gets remote file's download link
|
||||
private static final String TYPE_VALUE = "releaseType"; // Gets remote file's release type
|
||||
private static final String VERSION_VALUE = "gameVersion"; // Gets remote file's build version
|
||||
private static final String QUERY = "/servermods/files?projectIds="; // Path to GET
|
||||
private static final String HOST = "https://api.curseforge.com"; // Slugs will be appended to this to get to the project's RSS feed
|
||||
|
||||
private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" }; // If the version number contains one of these, don't update.
|
||||
private static final int BYTE_SIZE = 1024; // Used for downloading files
|
||||
private String updateFolder;// The folder that downloads will be placed in
|
||||
private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS; // Used for determining the outcome of the update process
|
||||
|
||||
/**
|
||||
* Gives the dev the result of the update process. Can be obtained by called getResult().
|
||||
*/
|
||||
public enum UpdateResult {
|
||||
/**
|
||||
* The updater found an update, and has readied it to be loaded the next time the server restarts/reloads.
|
||||
*/
|
||||
SUCCESS,
|
||||
/**
|
||||
* The updater did not find an update, and nothing was downloaded.
|
||||
*/
|
||||
NO_UPDATE,
|
||||
/**
|
||||
* The server administrator has disabled the updating system
|
||||
*/
|
||||
DISABLED,
|
||||
/**
|
||||
* The updater found an update, but was unable to download it.
|
||||
*/
|
||||
FAIL_DOWNLOAD,
|
||||
/**
|
||||
* For some reason, the updater was unable to contact dev.bukkit.org to download the file.
|
||||
*/
|
||||
FAIL_DBO,
|
||||
/**
|
||||
* When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'.
|
||||
*/
|
||||
FAIL_NOVERSION,
|
||||
/**
|
||||
* The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
|
||||
*/
|
||||
FAIL_BADID,
|
||||
/**
|
||||
* The server administrator has improperly configured their API key in the configuration
|
||||
*/
|
||||
FAIL_APIKEY,
|
||||
/**
|
||||
* The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.
|
||||
*/
|
||||
UPDATE_AVAILABLE
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the updater
|
||||
*
|
||||
* @param plugin The plugin that is checking for an update.
|
||||
* @param id The dev.bukkit.org id of the project
|
||||
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
|
||||
*/
|
||||
public Updater(Plugin plugin, int id, File file) {
|
||||
this.plugin = plugin;
|
||||
this.file = file;
|
||||
this.id = id;
|
||||
this.updateFolder = plugin.getServer().getUpdateFolder();
|
||||
|
||||
try {
|
||||
this.url = new URL(Updater.HOST + Updater.QUERY + id);
|
||||
}
|
||||
catch (final MalformedURLException e) {
|
||||
plugin.getLogger().severe("The project ID provided for updating, " + id + " is invalid.");
|
||||
this.result = UpdateResult.FAIL_BADID;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an update from dev.bukkit.org into the server's update folder.
|
||||
*/
|
||||
private void saveFile(File folder, String file, String u) {
|
||||
if (!folder.exists()) {
|
||||
folder.mkdir();
|
||||
}
|
||||
BufferedInputStream in = null;
|
||||
FileOutputStream fout = null;
|
||||
try {
|
||||
// Download the file
|
||||
final URL url = new URL(u);
|
||||
final int fileLength = url.openConnection().getContentLength();
|
||||
in = new BufferedInputStream(url.openStream());
|
||||
fout = new FileOutputStream(folder.getAbsolutePath() + "/" + file);
|
||||
|
||||
final byte[] data = new byte[Updater.BYTE_SIZE];
|
||||
int count;
|
||||
if (this.announce) {
|
||||
this.plugin.getLogger().info("About to download a new update: " + this.versionName);
|
||||
}
|
||||
long downloaded = 0;
|
||||
while ((count = in.read(data, 0, Updater.BYTE_SIZE)) != -1) {
|
||||
downloaded += count;
|
||||
fout.write(data, 0, count);
|
||||
final int percent = (int) ((downloaded * 100) / fileLength);
|
||||
if (this.announce && ((percent % 10) == 0)) {
|
||||
this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes.");
|
||||
}
|
||||
}
|
||||
// Just a quick check to make sure we didn't leave any files from last time...
|
||||
for (final File xFile : new File(this.plugin.getDataFolder().getParent(), this.updateFolder).listFiles()) {
|
||||
if (xFile.getName().endsWith(".zip")) {
|
||||
xFile.delete();
|
||||
}
|
||||
}
|
||||
// Check to see if it's a zip file, if it is, unzip it.
|
||||
final File dFile = new File(folder.getAbsolutePath() + "/" + file);
|
||||
if (dFile.getName().endsWith(".zip")) {
|
||||
// Unzip
|
||||
this.unzip(dFile.getCanonicalPath());
|
||||
}
|
||||
if (this.announce) {
|
||||
this.plugin.getLogger().info("Finished updating.");
|
||||
}
|
||||
}
|
||||
catch (final Exception ex) {
|
||||
this.plugin.getLogger().warning("The auto-updater tried to download a new update, but was unsuccessful.");
|
||||
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
if (fout != null) {
|
||||
fout.close();
|
||||
}
|
||||
}
|
||||
catch (final Exception ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of Zip-File-Extractor, modified by Gravity for use with Bukkit
|
||||
*/
|
||||
private void unzip(String file) {
|
||||
try {
|
||||
final File fSourceZip = new File(file);
|
||||
final String zipPath = file.substring(0, file.length() - 4);
|
||||
ZipFile zipFile = new ZipFile(fSourceZip);
|
||||
Enumeration<? extends ZipEntry> e = zipFile.entries();
|
||||
while (e.hasMoreElements()) {
|
||||
ZipEntry entry = e.nextElement();
|
||||
File destinationFilePath = new File(zipPath, entry.getName());
|
||||
destinationFilePath.getParentFile().mkdirs();
|
||||
if (entry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
|
||||
int b;
|
||||
final byte buffer[] = new byte[Updater.BYTE_SIZE];
|
||||
final FileOutputStream fos = new FileOutputStream(destinationFilePath);
|
||||
final BufferedOutputStream bos = new BufferedOutputStream(fos, Updater.BYTE_SIZE);
|
||||
while ((b = bis.read(buffer, 0, Updater.BYTE_SIZE)) != -1) {
|
||||
bos.write(buffer, 0, b);
|
||||
}
|
||||
bos.flush();
|
||||
bos.close();
|
||||
bis.close();
|
||||
final String name = destinationFilePath.getName();
|
||||
if (name.endsWith(".jar") && this.pluginFile(name)) {
|
||||
destinationFilePath.renameTo(new File(this.plugin.getDataFolder().getParent(), this.updateFolder + "/" + name));
|
||||
}
|
||||
}
|
||||
entry = null;
|
||||
destinationFilePath = null;
|
||||
}
|
||||
e = null;
|
||||
zipFile.close();
|
||||
zipFile = null;
|
||||
|
||||
// Move any plugin data folders that were included to the right place, Bukkit won't do this for us.
|
||||
for (final File dFile : new File(zipPath).listFiles()) {
|
||||
if (dFile.isDirectory()) {
|
||||
if (this.pluginFile(dFile.getName())) {
|
||||
final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName()); // Get current dir
|
||||
final File[] contents = oFile.listFiles(); // List of existing files in the current dir
|
||||
for (final File cFile : dFile.listFiles()) // Loop through all the files in the new dir
|
||||
{
|
||||
boolean found = false;
|
||||
for (final File xFile : contents) // Loop through contents to see if it exists
|
||||
{
|
||||
if (xFile.getName().equals(cFile.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// Move the new file into the current dir
|
||||
cFile.renameTo(new File(oFile.getCanonicalFile() + "/" + cFile.getName()));
|
||||
}
|
||||
else {
|
||||
// This file already exists, so we don't need it anymore.
|
||||
cFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dFile.delete();
|
||||
}
|
||||
new File(zipPath).delete();
|
||||
fSourceZip.delete();
|
||||
}
|
||||
catch (final IOException ex) {
|
||||
this.plugin.getLogger().warning("The auto-updater tried to unzip a new update file, but was unsuccessful.");
|
||||
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
|
||||
ex.printStackTrace();
|
||||
}
|
||||
new File(file).delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip.
|
||||
*/
|
||||
private boolean pluginFile(String name) {
|
||||
for (final File file : new File("plugins").listFiles()) {
|
||||
if (file.getName().equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the program should continue by evaluation whether the plugin is already updated, or shouldn't be updated
|
||||
*/
|
||||
private boolean versionCheck(String title) {
|
||||
final String version = this.plugin.getDescription().getVersion();
|
||||
if (title.split(" ").length == 2) {
|
||||
final String remoteVersion = title.split(" ")[1].split(" ")[0]; // Get the newest file's version number
|
||||
|
||||
if (this.hasTag(version) || version.equalsIgnoreCase(remoteVersion) || !isNewer(version, remoteVersion)) {
|
||||
// We already have the latest version, or this build is tagged for no-update
|
||||
this.result = Updater.UpdateResult.NO_UPDATE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.plugin.getLogger().warning("File versions should follow the format 'PluginName VERSION'");
|
||||
this.result = Updater.UpdateResult.FAIL_NOVERSION;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate whether the version number is marked showing that it should not be updated by this program
|
||||
*/
|
||||
private boolean hasTag(String version) {
|
||||
for (final String string : Updater.NO_UPDATE_TAG) {
|
||||
if (version.contains(string)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean read() {
|
||||
try {
|
||||
final URLConnection conn = this.url.openConnection();
|
||||
conn.setConnectTimeout(5000);
|
||||
|
||||
if (this.apiKey != null) {
|
||||
conn.addRequestProperty("X-API-Key", this.apiKey);
|
||||
}
|
||||
conn.addRequestProperty("User-Agent", "Updater");
|
||||
|
||||
conn.setDoOutput(true);
|
||||
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
final String response = reader.readLine();
|
||||
|
||||
final JSONArray array = (JSONArray) JSONValue.parse(response);
|
||||
|
||||
if (array.size() == 0) {
|
||||
this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id);
|
||||
this.result = UpdateResult.FAIL_BADID;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.versionName = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.TITLE_VALUE);
|
||||
this.versionLink = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.LINK_VALUE);
|
||||
this.versionType = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.TYPE_VALUE);
|
||||
this.versionGameVersion = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.VERSION_VALUE);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (final IOException e) {
|
||||
if (e.getMessage().contains("HTTP response code: 403")) {
|
||||
this.plugin.getLogger().warning("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml");
|
||||
this.plugin.getLogger().warning("Please double-check your configuration to ensure it is correct.");
|
||||
this.result = UpdateResult.FAIL_APIKEY;
|
||||
}
|
||||
else {
|
||||
this.plugin.getLogger().warning("The updater could not contact curse for updating.");
|
||||
this.result = UpdateResult.FAIL_DBO;
|
||||
}
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNewer(String oldVers, String newVers) {
|
||||
String s1 = normalisedVersion(oldVers);
|
||||
String s2 = normalisedVersion(newVers);
|
||||
int cmp = s1.compareTo(s2);
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
public static String normalisedVersion(String version) {
|
||||
return normalisedVersion(version, ".", 3);
|
||||
}
|
||||
|
||||
public static String normalisedVersion(String version, String sep, int maxWidth) {
|
||||
String[] split = Pattern.compile(sep, Pattern.LITERAL).split(version);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : split) {
|
||||
sb.append(String.format("%" + maxWidth + 's', s));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public UpdateResult update() {
|
||||
if (Updater.this.url != null) {
|
||||
// Obtain the results of the project's file feed
|
||||
if (Updater.this.read()) {
|
||||
if (Updater.this.versionCheck(Updater.this.versionName)) {
|
||||
if (Updater.this.versionLink != null) {
|
||||
String name = Updater.this.file.getName();
|
||||
// If it's a zip file, it shouldn't be downloaded as the plugin's name
|
||||
if (Updater.this.versionLink.endsWith(".zip")) {
|
||||
final String[] split = Updater.this.versionLink.split("/");
|
||||
name = split[split.length - 1];
|
||||
}
|
||||
Updater.this.saveFile(new File(Updater.this.plugin.getDataFolder().getParent(), Updater.this.updateFolder), name, Updater.this.versionLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.result;
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
name: OpenInv
|
||||
main: com.lishid.openinv.OpenInv
|
||||
version: 2.2.7
|
||||
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: Open a player's inventory
|
||||
usage: |
|
||||
/<command> - Open last person's inventory
|
||||
/<command> <Player> - Open a player's inventory
|
||||
openender:
|
||||
aliases: [oe]
|
||||
description: Opens the enderchest of a player
|
||||
usage: |
|
||||
/<command> <Player> - Opens a player's enderchest
|
||||
searchinv:
|
||||
aliases: [si]
|
||||
description: Search and list players having a specific item
|
||||
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: Toggle item openinv function
|
||||
usage: |
|
||||
/<command> [Check] - Checks whether item openinv is enabled
|
||||
silentchest:
|
||||
aliases: [sc, silent]
|
||||
description: Toggle 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
|
||||
anychest:
|
||||
aliases: [ac]
|
||||
description: Toggle anychest function, which allows opening of blocked chests.
|
||||
usage: |
|
||||
/<command> [Check] - Checks whether anychest is enabled
|
Reference in New Issue
Block a user