add item commands

This commit is contained in:
2026-04-05 19:44:57 +08:00
commit 4b890ea7ec
27 changed files with 2517 additions and 0 deletions

339
LICENSE Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
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; either version 2 of the License, or
(at your option) any later version.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

48
README.md Normal file
View File

@@ -0,0 +1,48 @@
# BedwarsXP
[![License](https://img.shields.io/github/license/SakuraKoi/BedwarsXP?style=flat-square)](LICENSE)
BedwarsXP - BedwarsRel addon (A Minecraft Server Plugin)
BedwarsRel起床战争小游戏插件的经验起床Addon
## 功能特性
- **经验经济系统**:将 BedwarsRel 的资源经济转换为经验值经济
- **资源兑换商店**:添加经验兑换分类,允许玩家将资源转换为经验
- **命令商店物品支持**:支持配置执行命令的商店物品(如权限、传送等命令)
- **全经验模式**:支持将所有商店物品转换为经验交易
## 最近更新
### 新增:命令商店物品支持
现在支持在商店中配置执行命令的物品,而非仅给予物品:
```yaml
shop:
- item1:
type: EXP_BOTTLE
amount: 10
reward:
type: STONE
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: §eVIP权限
commands:
- "lp user %player% parent add vip"
```
- `%player%` 变量会被替换为购买玩家的名称
- 支持 XP 交易和传统物品交易两种模式
- 购买时会自动扣除相应的经验或资源
## 协议
本项目基于 [GPL-2.0](LICENSE) 协议开源。
> 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; either version 2 of the License, or
> (at your option) any later version.

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sakura.kooi</groupId>
<artifactId>BedwarsXP</artifactId>
<version>2.1.3</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>sakura.kooi.utils.lib.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spigot</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
</exclusion>
<exclusion>
<artifactId>json-simple</artifactId>
<groupId>com.googlecode.json-simple</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
<exclusion>
<artifactId>gson</artifactId>
<groupId>com.google.code.gson</groupId>
</exclusion>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
<exclusion>
<artifactId>bungeecord-chat</artifactId>
<groupId>net.md-5</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.github.bedwarsrel</groupId>
<artifactId>BedwarsRel</artifactId>
<version>1.3.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

87
pom.xml Normal file
View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>sakura.kooi</groupId>
<artifactId>BedwarsXP</artifactId>
<version>2.1.3</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>spigot</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.bedwarsrel</groupId>
<artifactId>BedwarsRel</artifactId>
<version>1.3.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>sakura.kooi.utils.lib.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,105 @@
package ldcr.BedwarsXP;
import ldcr.BedwarsXP.command.BedwarsXPCommandListener;
import ldcr.BedwarsXP.command.EditXPCommandListener;
import ldcr.BedwarsXP.utils.ActionBarUtils;
import ldcr.BedwarsXP.utils.ReflectionUtils;
import lombok.Getter;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import sakura.kooi.utils.GithubUpdateChecker.UpdateChecker;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class BedwarsXP extends JavaPlugin {
@Getter
private static final Map<String, String> l18nCache = new HashMap<>();
@Getter
private static BedwarsXP instance;
@Getter
private static CommandSender consoleSender;
@Getter
private static String updateUrl = null;
public static String l18n(String key, String... replacement) {
String message;
if (l18nCache.containsKey(key)) {
message = l18nCache.get(key);
} else {
message = Config.getLanguageYaml().getString(key, "LANG_NOT_FOUND_" + key);
l18nCache.put(key, message);
}
for (int i = 0, length = replacement.length / 2; i < length; i++) {
message = message.replace(replacement[i * 2], replacement[i * 2 + 1]);
}
return message;
}
public static void sendConsoleMessage(String str) {
consoleSender.sendMessage("§6§lBedwarsXP §7>> " + str);
}
@Override
public void onEnable() {
instance = this;
consoleSender = Bukkit.getConsoleSender();
try {
sendConsoleMessage("§bLoading BedwarsXP... Version." + getDescription().getVersion());
Config.loadConfig();
if (!detectBedwarsRelVersion()) {
Bukkit.getPluginManager().disablePlugin(this);
return;
}
ActionBarUtils.load();
Bukkit.getPluginManager().registerEvents(new EventListeners(), this);
getCommand("bedwarsxp").setExecutor(new BedwarsXPCommandListener());
getCommand("bedwarsxpedit").setExecutor(new EditXPCommandListener());
} catch (Exception e) {
sendConsoleMessage("§c§lERROR: §c-----------------------------------");
e.printStackTrace();
sendConsoleMessage("§c§lERROR: §c-----------------------------------");
sendConsoleMessage("§c§lERROR: §c" + l18n("ERROR_OCCURRED_WHILE_LOADING"));
sendConsoleMessage("§c§lERROR: §e ↓↓ << " + l18n("REPORT_ISSUE_HERE") + " >> ↓↓ ");
sendConsoleMessage("§c§lERROR: §c https://github.com/SakuraKoi/BedwarsXP/issues/1");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
sendConsoleMessage("§b" + l18n("SUCCESSFULLY_LOADED") + " By.SakuraKooi");
sendConsoleMessage("§e ↓↓ << " + l18n("REPORT_ISSUE_AND_SUGGESTION_HERE") + " >> ↓↓ ");
sendConsoleMessage("§c https://github.com/SakuraKoi/BedwarsXP/issues/1");
// Update checker and metrics
if (!Config.disableUpdateChecker) {
Bukkit.getScheduler().runTaskLater(this, () -> {
try {
new UpdateChecker("SakuraKoi", "BedwarsXP", "v" + getDescription().getVersion(), link -> {
updateUrl = link;
sendConsoleMessage("§b" + l18n("HAS_UPDATE", "%link%", link));
}).check();
} catch (IOException ignored) {}
}, 100);
}
try {
new Metrics(this, 3999);
} catch (Exception ignored) {}
}
private boolean detectBedwarsRelVersion() {
sendConsoleMessage("§a" + l18n("FINDING_BEDWARSREL"));
if (ReflectionUtils.isClassFound("io.github.yannici.bedwars.Main") || ReflectionUtils.isClassFound("io.github.bedwarsrel.BedwarsRel.Main")) {
sendConsoleMessage("§c" + l18n("BEDWARSREL_NOT_SUPPORTED"));
sendConsoleMessage("§c" + l18n("PLEASE_UPDATE_BEDWARSREL"));
return false;
} else if (ReflectionUtils.isClassFound("io.github.bedwarsrel.BedwarsRel")) {
sendConsoleMessage("§a" + l18n("BEDWARSREL_SUPPORTED"));
return true;
} else {
sendConsoleMessage("§c§lERROR: §c" + l18n("BEDWARSREL_NOT_FOUND"));
return false;
}
}
}

View File

@@ -0,0 +1,145 @@
package ldcr.BedwarsXP;
import ldcr.BedwarsXP.utils.YamlUtils;
import lombok.Getter;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import java.io.File;
import java.io.IOException;
import java.util.*;
public class Config {
public static final Map<Material, Integer> resources = new EnumMap<>(Material.class);
public static final Set<String> resourceskey = new HashSet<>();
private static final int CONFIG_VERSION = 2;
private static final Set<String> enabledGameList = new HashSet<>();
public static boolean disableUpdateChecker;
public static String xpMessage;
public static boolean addResShop;
public static double deathCost;
public static double deathDrop;
public static boolean dontDropExpBottle;
public static int maxXP;
public static String maxXPMessage;
public static boolean fullXPBedwars;
private static YamlConfiguration enabledGamesYaml;
private static File enabledGamesFile;
@Getter
private static YamlConfiguration languageYaml;
public static void loadConfig() {
BedwarsXP.sendConsoleMessage("§b正在加载语言文件... | Loading language configuration...");
File languageFile = new File("plugins/BedwarsXP/language.yml");
if (!languageFile.exists()) {
BedwarsXP.sendConsoleMessage("§b语言文件不存在,正在创建...");
BedwarsXP.sendConsoleMessage("§bWanna english? Just overwrites language.yml with language-en.yml :)");
BedwarsXP.getInstance().saveResource("language.yml", true);
BedwarsXP.getInstance().saveResource("language-en.yml", true);
}
try {
languageYaml = YamlUtils.loadYamlUTF8(languageFile);
} catch (IOException e) {
languageYaml = new YamlConfiguration();
BedwarsXP.sendConsoleMessage("§c语言文件加载失败 | Failed to load language");
e.printStackTrace();
}
BedwarsXP.sendConsoleMessage("§b" + BedwarsXP.l18n("LOADING_CONFIGURATION"));
File configFile = new File("plugins/BedwarsXP/config.yml");
if (!configFile.exists()) {
BedwarsXP.sendConsoleMessage("§b" + BedwarsXP.l18n("CONFIGURATION_FILE_NOT_EXISTS"));
BedwarsXP.getInstance().saveResource("config.yml", true);
}
YamlConfiguration configYaml = YamlConfiguration.loadConfiguration(configFile);
if (configYaml.getInt("ConfigVersion") < CONFIG_VERSION) {
BedwarsXP.sendConsoleMessage("§4" + BedwarsXP.l18n("OLD_VERSION_CONFIGURATION"));
configFile.renameTo(new File("plugins/BedwarsXP/config.bak.yml"));
BedwarsXP.sendConsoleMessage("§c" + BedwarsXP.l18n("OLD_CONFIGURATION_BACKUPED"));
BedwarsXP.getInstance().saveResource("config.yml", true);
BedwarsXP.sendConsoleMessage("§a" + BedwarsXP.l18n("NEW_CONFIGURATION_SAVED"));
configFile = new File("plugins/BedwarsXP/config.yml");
configYaml = YamlConfiguration.loadConfiguration(configFile);
}
disableUpdateChecker = configYaml.getBoolean("Disable_UpdateChecker", true);
xpMessage = configYaml.getString("Message").replaceAll("&", "§").replaceAll("§§", "§");
addResShop = configYaml.getBoolean("Add_Res_Shop");
if (addResShop) {
BedwarsXP.sendConsoleMessage("§a" + BedwarsXP.l18n("RESOURCE_SHOP_ENABLED"));
}
deathCost = configYaml.getInt("DeathCostXP", 0) / 100.0;
BedwarsXP.sendConsoleMessage("§a" + BedwarsXP.l18n("DEATH_COST_XP_PERCENT", "%percent%", String.valueOf(deathCost * 100)));
deathDrop = configYaml.getInt("DeathDropXP", 0) / 100.0;
BedwarsXP.sendConsoleMessage(
"§6§lBedwarsXP §7>> §a" + (deathDrop == 0 ? BedwarsXP.l18n("DEATH_DROP_XP_DISABLED") : BedwarsXP.l18n("DEATH_DROP_XP_PERCEMT", "%percent%", String.valueOf(deathDrop * 100))));
dontDropExpBottle = configYaml.getBoolean("DontDropExpBottle", false);
if (dontDropExpBottle)
BedwarsXP.sendConsoleMessage("§a" + BedwarsXP.l18n("DEATH_DROP_EXP_BOTTLE_DISABLED"));
maxXP = configYaml.getInt("MaxXP");
maxXPMessage = configYaml.getString("MaxXPMessage").replaceAll("&", "§").replaceAll("§§", "§");
BedwarsXP.sendConsoleMessage("§a" + (maxXP == 0 ? BedwarsXP.l18n("MAX_XP_LIMIT_DISABLED") : BedwarsXP.l18n("MAX_XP_LIMIT_ENABLED", "%value%", String.valueOf(maxXP))));
fullXPBedwars = configYaml.getBoolean("Full_XP_Bedwars");
if (fullXPBedwars) {
BedwarsXP.sendConsoleMessage("§a" + BedwarsXP.l18n("ALL_TRADES_USE_XP_ENABLED"));
}
BedwarsXP.sendConsoleMessage("§a" + BedwarsXP.l18n("LOADING_RESOURCES_VALUE"));
ConfigurationSection resourceSection = io.github.bedwarsrel.BedwarsRel.getInstance().getConfig()
.getConfigurationSection("resource");
for (String key : resourceSection.getKeys(false)) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> resourceList = (List<Map<String, Object>>) io.github.bedwarsrel.BedwarsRel
.getInstance().getConfig().getList("resource." + key + ".item");
for (Map<String, Object> resource : resourceList) {
ItemStack itemStack = ItemStack.deserialize(resource);
Material mat = itemStack.getType();
int xp = configYaml.getInt("XP." + key, 0);
resources.put(mat, xp);
resourceskey.add(key);
BedwarsXP.sendConsoleMessage("§a" + BedwarsXP.l18n("FOUNDED_RESOURCE",
"%resource%", key,
"%material%", mat.toString(),
"%value%", String.valueOf(xp)));
}
}
enabledGamesFile = new File("plugins/BedwarsXP/enabledGames.yml");
if (!enabledGamesFile.exists()) {
BedwarsXP.sendConsoleMessage("§c" + BedwarsXP.l18n("WARN_YOU_NEEDS_ENABLE_BEDWARSXP_MANUALLY"));
BedwarsXP.getInstance().saveResource("enabledGames.yml", true);
}
enabledGamesYaml = YamlConfiguration.loadConfiguration(enabledGamesFile);
enabledGameList.addAll(enabledGamesYaml.getStringList("enabledGame"));
}
public static String setGameEnableXP(String bw, boolean isEnabled) {
if (isEnabled) {
enabledGameList.add(bw);
} else {
enabledGameList.remove(bw);
}
enabledGamesYaml.set("enabledGame", new ArrayList<>(enabledGameList));
try {
enabledGamesYaml.save(enabledGamesFile);
} catch (IOException e) {
e.printStackTrace();
return e.getLocalizedMessage();
}
return "";
}
public static boolean isGameEnabledXP(String bw) {
return enabledGameList.contains(bw);
}
}

View File

@@ -0,0 +1,208 @@
package ldcr.BedwarsXP;
import io.github.bedwarsrel.BedwarsRel;
import io.github.bedwarsrel.events.BedwarsGameEndEvent;
import io.github.bedwarsrel.events.BedwarsGameStartEvent;
import io.github.bedwarsrel.game.Game;
import ldcr.BedwarsXP.XPShop.ShopReplacer;
import ldcr.BedwarsXP.api.XPManager;
import ldcr.BedwarsXP.api.events.BedwarsXPDeathDropXPEvent;
import ldcr.BedwarsXP.utils.ResourceUtils;
import ldcr.BedwarsXP.utils.SoundMachine;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Collections;
public class EventListeners implements Listener {
@SuppressWarnings("deprecation")
@EventHandler
public void onItemPickup(PlayerPickupItemEvent e) {
Player p = e.getPlayer();
Game bw = checkGame(p);
if (bw == null) return;
Item entity = e.getItem();
ItemStack stack = entity.getItemStack();
if (stack == null) return;
Integer count;
if (stack.hasItemMeta() && stack.getItemMeta().getDisplayName() != null && stack.getItemMeta().getDisplayName().equals("§b§l&BedwarsXP_DroppedXP")) {
count = Integer.parseInt(stack.getItemMeta().getLore().get(0));
} else {
count = ResourceUtils.convertResToXP(stack);
}
if (count == null)
return;
if (pickupXP(bw, p, count)) {
e.setCancelled(true);
entity.remove();
} else {
e.setCancelled(true);
entity.setPickupDelay(10);
}
}
private boolean pickupXP(Game bw, Player player, int count) {
if (count <= 0) return true;
XPManager xpman = XPManager.getXPManager(bw.getName());
// if current XP > maxXP -> deny pickup
if (Config.maxXP != 0 && xpman.getXP(player) >= Config.maxXP) {
xpman.sendMaxXPMessage(player);
return false;
}
int added = xpman.getXP(player) + count;
int leftXP = 0;
// if after pickup XP>maxXP -> set XP = maxXP
if (Config.maxXP != 0 && added > Config.maxXP) {
leftXP = added - Config.maxXP;
added = Config.maxXP;
}
xpman.setXP(player, added);
player.playSound(player.getLocation(), SoundMachine.get("ORB_PICKUP", "ENTITY_EXPERIENCE_ORB_PICKUP"), 0.2F, 1.5F);
xpman.sendXPMessage(player, count);
if (leftXP > 0) {
dropXPBottle(player, leftXP);
}
return true;
}
private void dropXPBottle(Player player, int xp) {
ItemStack dropStack = new ItemStack(Material.EXP_BOTTLE, 16);
ItemMeta meta = dropStack.getItemMeta();
meta.setDisplayName("§b§l&BedwarsXP_DroppedXP");
meta.setLore(Collections.singletonList(String.valueOf(xp)));
meta.addEnchant(Enchantment.LOOT_BONUS_MOBS, 1, true);
dropStack.setItemMeta(meta);
Item droppedItem = player.getWorld().dropItemNaturally(player.getLocation().add(0, 1, 0), dropStack);
droppedItem.setPickupDelay(40);
}
@EventHandler
public void onAnvilOpen(InventoryOpenEvent e) {
if (e.getPlayer() == null)
return;
if (e.getInventory() == null)
return;
Game bw = checkGame((Player) e.getPlayer());
if (bw == null) return;
if (e.getInventory().getType().equals(InventoryType.ANVIL)) {
e.setCancelled(true);
}
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent e) {
Player p = e.getEntity();
Game bw = checkGame(p);
if (bw == null) return;
XPManager xpman = XPManager.getXPManager(bw.getName());
// 计算死亡扣除经验值
int costed = (int) (xpman.getXP(p) * Config.deathCost);
// 计算死亡掉落经验值
int dropped = 0;
if (Config.deathDrop > 0) {
dropped = (int) (costed * Config.deathDrop);
}
BedwarsXPDeathDropXPEvent event = new BedwarsXPDeathDropXPEvent(bw.getName(), p, dropped, costed);
Bukkit.getPluginManager().callEvent(event);
costed = event.getXPCost();
dropped = event.getXPDropped();
// 扣除经验
int to = xpman.getXP(p) - costed;
if (to < 0) {
to = 0;
}
e.setNewLevel(to);
xpman.setXP(p, to);
// 掉落经验
if (dropped < 1)
return;
if (Config.dontDropExpBottle) {
EntityDamageEvent ev = p.getLastDamageCause();
if (ev instanceof EntityDamageByEntityEvent) {
Object killer = ((EntityDamageByEntityEvent) ev).getDamager();
if (killer instanceof Projectile) {
killer = ((Projectile) killer).getShooter();
}
if (killer instanceof Player) {
pickupXP(bw, (Player) killer, dropped);
return;
}
}
}
dropXPBottle(p, dropped);
}
@EventHandler
public void onBedWarsStart(BedwarsGameStartEvent e) {
if (e.isCancelled())
return;
if (!Config.isGameEnabledXP(e.getGame().getName()))
return;
ShopReplacer.replaceShop(e.getGame().getName(), BedwarsXP.getConsoleSender());
}
@EventHandler
public void onBedWarsEnd(BedwarsGameEndEvent e) {
if (!Config.isGameEnabledXP(e.getGame().getName()))
return;
XPManager.reset(e.getGame().getName());
}
@EventHandler
public void onPlayerTeleport(PlayerTeleportEvent e) { // 在玩家传送后更新经验条
Player p = e.getPlayer();
Game bw = checkGame(p);
if (bw == null) return;
Bukkit.getScheduler().runTaskLater(BedwarsXP.getInstance(),
() -> XPManager.getXPManager(bw.getName()).updateXPBar(p), 5);
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent e) {
Game bw = checkGame(e.getPlayer());
if (bw == null) return;
XPManager.getXPManager(bw.getName()).updateXPBar(e.getPlayer());
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
if (BedwarsXP.getUpdateUrl() != null && e.getPlayer().hasPermission("bedwarsxp.admin")) {
Bukkit.getScheduler().runTaskLater(BedwarsXP.getInstance(), () -> {
if (e.getPlayer().isOnline())
e.getPlayer().sendMessage("§6§lBedwarsXP §7>> §b" + BedwarsXP.l18n("HAS_UPDATE", "%link%", BedwarsXP.getUpdateUrl()));
}, 30);
}
}
private Game checkGame(Player player) {
Game bw = BedwarsRel.getInstance().getGameManager().getGameOfPlayer(player);
if (bw == null)
return null;
if (!Config.isGameEnabledXP(bw.getName()))
return null;
return bw;
}
}

View File

@@ -0,0 +1,102 @@
package ldcr.BedwarsXP.XPShop;
import io.github.bedwarsrel.BedwarsRel;
import io.github.bedwarsrel.game.Game;
import io.github.bedwarsrel.shop.NewItemShop;
import io.github.bedwarsrel.villager.MerchantCategory;
import io.github.bedwarsrel.villager.MerchantCategoryComparator;
import io.github.bedwarsrel.villager.VillagerTrade;
import ldcr.BedwarsXP.BedwarsXP;
import ldcr.BedwarsXP.Config;
import ldcr.BedwarsXP.utils.ReflectionUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Field;
import java.util.*;
import java.util.Map.Entry;
public class ShopReplacer implements Runnable {
private final Game game;
private final CommandSender s;
private ShopReplacer(String e, CommandSender sender) {
s = sender;
game = BedwarsRel.getInstance().getGameManager().getGame(e);
}
public static void replaceShop(String bw, CommandSender sender) {
if (!Config.isGameEnabledXP(bw))
return;
Bukkit.getScheduler().runTaskLater(BedwarsXP.getInstance(), new ShopReplacer(bw, sender), 20);
}
@Override
public void run() {
HashMap<Material, MerchantCategory> map = game.getItemShopCategories();
if (Config.fullXPBedwars) {
for (Entry<Material, MerchantCategory> en : map.entrySet()) {
MerchantCategory m = en.getValue();
ArrayList<VillagerTrade> t = m.getOffers();
ArrayList<XPVillagerTrade> n = new ArrayList<>();
for (VillagerTrade villagerTrade : t) {
if (villagerTrade == null)
continue;
n.add(new XPVillagerTrade(villagerTrade));
}
try {
ReflectionUtils.setPrivateValue(m, "offers", n);
} catch (Exception e1) {
s.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("ERROR_OCCURRED_REPLACE_SHOP", "%game%", game.getName()));
e1.printStackTrace();
}
map.put(en.getKey(), m);
}
}
if (Config.addResShop) {
ArrayList<VillagerTrade> trades = new ArrayList<>();
for (String key : Config.resourceskey) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> resourceList = (List<Map<String, Object>>) io.github.bedwarsrel.BedwarsRel.getInstance().getConfig().getList("resource." + key + ".item");
for (Map<String, Object> resource : resourceList) {
ItemStack itemStack = ItemStack.deserialize(resource);
if (itemStack != null) {
trades.add(new XPVillagerTrade(itemStack));
}
}
}
MerchantCategory mc = new MerchantCategory(BedwarsXP.l18n("SHOP_XP_EXCHANGE_TITLE"), Material.EXP_BOTTLE, trades, Collections.singletonList(BedwarsXP.l18n("SHOP_XP_EXCHANGE_LORE")), 3, "bw.base");
map.put(Material.EXP_BOTTLE, mc);
}
// 检查并显示带命令的物品数量
int commandItems = 0;
for (MerchantCategory cat : map.values()) {
for (VillagerTrade trade : cat.getOffers()) {
if (trade.hasCommands()) {
commandItems++;
}
}
}
if (commandItems > 0) {
s.sendMessage("§6§lBedwarsXP §7>> §a检测到 " + commandItems + " 个命令商店物品");
}
try {
Field itemshops = ReflectionUtils.getField(game, "newItemShops");
itemshops.setAccessible(true);
HashMap<Player, NewItemShop> shops = new HashMap<>();
List<MerchantCategory> order = new ArrayList<>(map.values());
order.sort(new MerchantCategoryComparator());
for (Player pl : game.getPlayers()) {
shops.put(pl, new XPItemShop(order, game));
}
ReflectionUtils.setPrivateValue(game, "newItemShops", shops);
s.sendMessage("§6§lBedwarsXP §7>> §b" + BedwarsXP.l18n("SUCCESSFULLY_REPLACED_SHOP", "%game%", game.getName()));
} catch (Exception e) {
s.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("ERROR_OCCURRED_WHILE_INITALIZING_XP_SHOP", "%game%", game.getName()));
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,502 @@
package ldcr.BedwarsXP.XPShop;
import io.github.bedwarsrel.BedwarsRel;
import io.github.bedwarsrel.game.Game;
import io.github.bedwarsrel.shop.NewItemShop;
import io.github.bedwarsrel.utils.ChatWriter;
import io.github.bedwarsrel.utils.Utils;
import io.github.bedwarsrel.villager.MerchantCategory;
import io.github.bedwarsrel.villager.VillagerTrade;
import ldcr.BedwarsXP.BedwarsXP;
import ldcr.BedwarsXP.api.XPManager;
import ldcr.BedwarsXP.utils.SoundMachine;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
public class XPItemShop extends NewItemShop {
private final Game bedwars;
private final List<MerchantCategory> categories;
private MerchantCategory currentCategory = null;
XPItemShop(List<MerchantCategory> cate, Game bw) {
super(cate);
categories = cate;
bedwars = bw;
}
@Override
public List<MerchantCategory> getCategories() {
return categories;
}
@Override
public boolean hasOpenCategory() {
return currentCategory != null;
}
@Override
public boolean hasOpenCategory(MerchantCategory category) {
if (currentCategory == null)
return false;
return currentCategory.equals(category);
}
private int getCategoriesSize(Player player) {
int size = 0;
for (MerchantCategory cat : categories) {
if (cat.getMaterial() != null && (player == null || player.hasPermission(cat.getPermission()))) {
size++;
}
}
return size;
}
@Override
public void openCategoryInventory(Player player) {
int catSize = getCategoriesSize(player);
int nom = catSize % 9 == 0 ? 9 : catSize % 9;
int size = catSize + 9 - nom + 9;
Inventory inventory = Bukkit.createInventory(player, size, BedwarsRel._l("ingame.shop.name"));
addCategoriesToInventory(inventory, player);
Game game = BedwarsRel.getInstance().getGameManager().getGameOfPlayer(player);
ItemStack stack;
if (game != null) {
if (game.getPlayerSettings(player).oneStackPerShift()) {
stack = new ItemStack(Material.BUCKET, 1);
ItemMeta meta = stack.getItemMeta();
meta.setDisplayName(ChatColor.AQUA + BedwarsRel._l("default.currently") + ": " + ChatColor.WHITE + BedwarsRel._l("ingame.shop.onestackpershift"));
meta.setLore(new ArrayList<>());
stack.setItemMeta(meta);
} else {
stack = new ItemStack(Material.LAVA_BUCKET, 1);
ItemMeta meta = stack.getItemMeta();
meta.setDisplayName(ChatColor.AQUA + BedwarsRel._l("default.currently") + ": " + ChatColor.WHITE + BedwarsRel._l("ingame.shop.fullstackpershift"));
meta.setLore(new ArrayList<>());
stack.setItemMeta(meta);
}
inventory.setItem(size - 4, stack);
}
player.openInventory(inventory);
}
private void addCategoriesToInventory(Inventory inventory, Player player) {
for (MerchantCategory category : categories) {
if (category.getMaterial() == null) {
BedwarsRel.getInstance().getServer().getConsoleSender().sendMessage(ChatWriter.pluginMessage(ChatColor.RED + "Careful: Not supported material in shop category '" + category.getName() + "'"));
} else if (player == null || player.hasPermission(category.getPermission())) {
ItemStack is = new ItemStack(category.getMaterial(), 1);
ItemMeta im = is.getItemMeta();
if (currentCategory != null && currentCategory.equals(category)) {
im.addEnchant(Enchantment.DAMAGE_ALL, 1, true);
}
im.setDisplayName(category.getName());
im.setLore(category.getLores());
is.setItemMeta(im);
inventory.addItem(is);
}
}
}
private int getInventorySize(int itemAmount) {
int nom = itemAmount % 9 == 0 ? 9 : itemAmount % 9;
return itemAmount + 9 - nom;
}
@Override
public void handleInventoryClick(InventoryClickEvent ice, Game game, Player player) {
if (!hasOpenCategory()) {
handleCategoryInventoryClick(ice, game, player);
} else {
handleBuyInventoryClick(ice, game, player);
}
}
private void handleCategoryInventoryClick(InventoryClickEvent ice, Game game, Player player) {
int catSize = getCategoriesSize(player);
int sizeCategories = getInventorySize(catSize) + 9;
int rawSlot = ice.getRawSlot();
if (rawSlot >= getInventorySize(catSize) && rawSlot < sizeCategories) {
ice.setCancelled(true);
if (ice.getCurrentItem().getType() == Material.BUCKET) {
game.getPlayerSettings(player).setOneStackPerShift(false);
player.playSound(player.getLocation(), SoundMachine.get("CLICK", "UI_BUTTON_CLICK"), 10.0F, 1.0F);
openCategoryInventory(player);
return;
}
if (ice.getCurrentItem().getType() == Material.LAVA_BUCKET) {
game.getPlayerSettings(player).setOneStackPerShift(true);
player.playSound(player.getLocation(), SoundMachine.get("CLICK", "UI_BUTTON_CLICK"), 10.0F, 1.0F);
openCategoryInventory(player);
return;
}
}
if (rawSlot >= sizeCategories) {
if (ice.isShiftClick()) {
ice.setCancelled(true);
return;
}
ice.setCancelled(false);
return;
}
MerchantCategory clickedCategory = getCategoryByMaterial(ice.getCurrentItem().getType());
if (clickedCategory == null) {
if (ice.isShiftClick()) {
ice.setCancelled(true);
return;
}
ice.setCancelled(false);
return;
}
openBuyInventory(clickedCategory, player, game);
}
private void openBuyInventory(MerchantCategory category, Player player, Game game) {
ArrayList<VillagerTrade> offers = category.getOffers();
int sizeCategories = getCategoriesSize(player);
int sizeItems = offers.size();
int invSize = getBuyInventorySize(sizeCategories, sizeItems);
player.playSound(player.getLocation(), SoundMachine.get("CLICK", "UI_BUTTON_CLICK"), 10.0F, 1.0F);
currentCategory = category;
Inventory buyInventory = Bukkit.createInventory(player, invSize, BedwarsRel._l("ingame.shop.name"));
addCategoriesToInventory(buyInventory, player);
for (int i = 0; i < offers.size(); i++) {
VillagerTrade trade = offers.get(i);
if (trade.getItem1().getType() != Material.AIR || trade.getRewardItem().getType() != Material.AIR) {
int slot = getInventorySize(sizeCategories) + i;
ItemStack tradeStack = toItemStack(trade, player, game);
buyInventory.setItem(slot, tradeStack);
}
}
player.openInventory(buyInventory);
}
private int getBuyInventorySize(int sizeCategories, int sizeOffers) {
return getInventorySize(sizeCategories) + getInventorySize(sizeOffers);
}
@SuppressWarnings("deprecation")
private ItemStack toItemStack(VillagerTrade trade, Player player, Game game) {
ItemStack tradeStack = trade.getRewardItem().clone();
Method colorable = Utils.getColorableMethod(tradeStack.getType());
ItemMeta meta = tradeStack.getItemMeta();
ItemStack item1 = trade.getItem1();
ItemStack item2 = trade.getItem2();
if (tradeStack.getType().equals(Material.STAINED_GLASS) || tradeStack.getType().equals(Material.WOOL) || tradeStack.getType().equals(Material.STAINED_CLAY)) {
tradeStack.setDurability(game.getPlayerTeam(player).getColor().getDyeColor().getWoolData());
} else if (colorable != null) {
colorable.setAccessible(true);
try {
colorable.invoke(meta, game.getPlayerTeam(player).getColor().getColor());
} catch (Exception e) {
e.printStackTrace();
}
}
List<String> lores = meta.getLore();
if (lores == null) {
lores = new ArrayList<>();
}
if (trade instanceof XPVillagerTrade) {
lores.add(BedwarsXP.l18n("SHOP_TRADE_XP", "%xp%", String.valueOf(((XPVillagerTrade) trade).getXp())));
} else {
lores.add(ChatColor.WHITE + String.valueOf(item1.getAmount()) + " " + item1.getItemMeta().getDisplayName());
if (item2 != null) {
lores.add(ChatColor.WHITE + String.valueOf(item2.getAmount()) + " " + item2.getItemMeta().getDisplayName());
}
}
meta.setLore(lores);
tradeStack.setItemMeta(meta);
return tradeStack;
}
private void handleBuyInventoryClick(InventoryClickEvent ice, Game game, Player player) {
int sizeCategories = getCategoriesSize(player);
ArrayList<VillagerTrade> offers = currentCategory.getOffers();
int sizeItems = offers.size();
int totalSize = getBuyInventorySize(sizeCategories, sizeItems);
ItemStack item = ice.getCurrentItem();
boolean cancel = false;
int bought = 0;
boolean oneStackPerShift = game.getPlayerSettings(player).oneStackPerShift();
if (currentCategory == null) {
player.closeInventory();
return;
}
if (ice.getRawSlot() < sizeCategories) {
ice.setCancelled(true);
if (item == null)
return;
if (item.getType().equals(currentCategory.getMaterial())) {
currentCategory = null;
openCategoryInventory(player);
} else {
handleCategoryInventoryClick(ice, game, player);
}
} else if (ice.getRawSlot() < totalSize) {
ice.setCancelled(true);
if (item == null || item.getType() == Material.AIR)
return;
MerchantCategory category = currentCategory;
VillagerTrade trade = getTradingItem(category, item, game, player);
if (trade == null) {
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] getTradingItem returned null!");
return;
}
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] getTradingItem returned trade: " + trade.getClass().getName());
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] trade.hasCommands in handleBuy: " + trade.hasCommands());
if (trade.getRewardItem() != null) {
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] reward item: " + trade.getRewardItem().getType());
}
player.playSound(player.getLocation(), SoundMachine.get("ITEM_PICKUP", "ENTITY_ITEM_PICKUP"), 10.0F, 1.0F);
if (!hasEnoughRessource(player, trade)) {
player.sendMessage(ChatWriter.pluginMessage(ChatColor.RED + BedwarsRel._l("errors.notenoughress")));
return;
}
if (ice.isShiftClick()) {
while (hasEnoughRessource(player, trade) && !cancel) {
cancel = !buyItem(trade, ice.getCurrentItem(), player);
if (!cancel && oneStackPerShift) {
bought += item.getAmount();
cancel = bought + item.getAmount() > 64;
}
}
} else {
buyItem(trade, ice.getCurrentItem(), player);
}
} else {
ice.setCancelled(ice.isShiftClick());
}
}
private boolean buyItem(VillagerTrade trade, ItemStack item, Player player) {
PlayerInventory inventory = player.getInventory();
boolean success = true;
// 调试输出
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] buyItem called, trade class: " + trade.getClass().getName());
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] trade.hasCommands(): " + trade.hasCommands());
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] trade.getCommands(): " + trade.getCommands());
// 检查是否有命令,如果有则执行命令而不是给予物品
if (trade.hasCommands()) {
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop] 执行命令物品,玩家: " + player.getName() + ", 命令数: " + trade.getCommands().size());
if (!(trade instanceof XPVillagerTrade)) {
// 非XP trade 扣除物品
int item1ToPay = trade.getItem1().getAmount();
Iterator<?> stackIterator = inventory.all(trade.getItem1().getType()).entrySet().iterator();
int firstItem1 = inventory.first(trade.getItem1());
takeItem(inventory, item1ToPay, stackIterator, firstItem1);
if (trade.getItem2() != null) {
int item2ToPay = trade.getItem2().getAmount();
stackIterator = inventory.all(trade.getItem2().getType()).entrySet().iterator();
int firstItem2 = inventory.first(trade.getItem2());
takeItem(inventory, item2ToPay, stackIterator, firstItem2);
}
} else {
// XP trade 扣除经验
XPManager.getXPManager(bedwars.getName()).takeXP(player, ((XPVillagerTrade) trade).getXp());
}
// 执行命令
for (String command : trade.getCommands()) {
String formattedCommand = command.replace("%player%", player.getName());
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop] 执行命令: " + formattedCommand);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), formattedCommand);
}
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop] 命令执行完成");
return success;
}
// 没有命令,正常给予物品
if (!(trade instanceof XPVillagerTrade)) {
// 非XPtrade 使用旧式购买
int item1ToPay = trade.getItem1().getAmount();
Iterator<?> stackIterator = inventory.all(trade.getItem1().getType()).entrySet().iterator();
int firstItem1 = inventory.first(trade.getItem1());
takeItem(inventory, item1ToPay, stackIterator, firstItem1);
if (trade.getItem2() != null) {
int item2ToPay = trade.getItem2().getAmount();
stackIterator = inventory.all(trade.getItem2().getType()).entrySet().iterator();
int firstItem2 = inventory.first(trade.getItem2());
takeItem(inventory, item2ToPay, stackIterator, firstItem2);
}
} else {
// Already checked has enough XP
XPManager.getXPManager(bedwars.getName()).takeXP(player, ((XPVillagerTrade) trade).getXp());
}
ItemStack addingItem = item.clone();
ItemMeta meta = addingItem.getItemMeta();
List<String> lore = meta.getLore();
if (!lore.isEmpty()) {
lore.remove(lore.size() - 1);
if (trade.getItem2() != null && !(trade instanceof XPVillagerTrade)) {
lore.remove(lore.size() - 1);
}
}
meta.setLore(lore);
addingItem.setItemMeta(meta);
HashMap<Integer, ? extends ItemStack> notStored = inventory.addItem(addingItem);
if (notStored.size() > 0) {
ItemStack notAddedItem = notStored.get(0);
int removingAmount = addingItem.getAmount() - notAddedItem.getAmount();
addingItem.setAmount(removingAmount);
inventory.removeItem(addingItem);
inventory.addItem(trade.getItem1());
if (trade.getItem2() != null) {
inventory.addItem(trade.getItem2());
}
success = false;
}
player.updateInventory();
return success;
}
private void takeItem(PlayerInventory inventory, int item1ToPay, Iterator<?> stackIterator, int firstItem1) {
if (firstItem1 > -1) {
inventory.clear(firstItem1);
} else {
while (stackIterator.hasNext()) {
Entry<?, ?> entry = (Entry<?, ?>) stackIterator.next();
ItemStack stack = (ItemStack) entry.getValue();
int endAmount = stack.getAmount() - item1ToPay;
if (endAmount < 0) {
endAmount = 0;
}
item1ToPay -= stack.getAmount();
stack.setAmount(endAmount);
inventory.setItem((Integer) entry.getKey(), stack);
if (item1ToPay <= 0) {
break;
}
}
}
}
private boolean hasEnoughRessource(Player player, VillagerTrade trade) {
if (trade instanceof XPVillagerTrade)
return XPManager.getXPManager(bedwars.getName()).hasEnoughXP(player, ((XPVillagerTrade) trade).getXp());
else {
ItemStack item1 = trade.getItem1();
ItemStack item2 = trade.getItem2();
PlayerInventory inventory = player.getInventory();
if (item2 != null) {
return inventory.contains(item1.getType(), item1.getAmount()) && inventory.contains(item2.getType(), item2.getAmount());
} else return inventory.contains(item1.getType(), item1.getAmount());
}
}
private VillagerTrade getTradingItem(MerchantCategory category, ItemStack stack, Game game, Player player) {
for (VillagerTrade trade : category.getOffers()) {
if (trade.getItem1().getType() != Material.AIR || trade.getRewardItem().getType() != Material.AIR) {
// 获取原始 reward 物品(不经过 toItemStack 处理)
ItemStack reward = trade.getRewardItem();
// 首先比较类型
if (reward.getType() != stack.getType()) {
continue;
}
// 对于末影箱特殊处理
if (reward.getType() == Material.ENDER_CHEST && stack.getType() == Material.ENDER_CHEST)
return trade;
// 对于药水类特殊处理
if (reward.getType() == Material.POTION ||
(!BedwarsRel.getInstance().getCurrentVersion().startsWith("v1_9") &&
(reward.getType().equals(Material.valueOf("TIPPED_ARROW")) ||
reward.getType().equals(Material.valueOf("LINGERING_POTION")) ||
reward.getType().equals(Material.valueOf("SPLASH_POTION"))))) {
if (((PotionMeta) reward.getItemMeta()).getCustomEffects().equals(((PotionMeta) stack.getItemMeta()).getCustomEffects()))
return trade;
}
// 对于普通物品,比较显示名
ItemMeta rewardMeta = reward.getItemMeta();
ItemMeta stackMeta = stack.getItemMeta();
String rewardName = rewardMeta != null ? rewardMeta.getDisplayName() : null;
String stackName = stackMeta != null ? stackMeta.getDisplayName() : null;
if ((rewardName == null && stackName == null) ||
(rewardName != null && rewardName.equals(stackName))) {
Bukkit.getConsoleSender().sendMessage("[BW-XP-Shop-DEBUG] Matched trade: name=" + rewardName + ", hasCommands=" + trade.hasCommands());
return trade;
}
}
}
return null;
}
private MerchantCategory getCategoryByMaterial(Material material) {
for (MerchantCategory category : categories) {
if (category.getMaterial() == material)
return category;
}
return null;
}
@Override
public void setCurrentCategory(MerchantCategory category) {
currentCategory = category;
}
}

View File

@@ -0,0 +1,46 @@
package ldcr.BedwarsXP.XPShop;
import io.github.bedwarsrel.villager.VillagerTrade;
import ldcr.BedwarsXP.utils.ResourceUtils;
import lombok.Setter;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class XPVillagerTrade extends VillagerTrade {
@Setter
private int xp = 0;
public XPVillagerTrade(VillagerTrade t) {
super(t.getItem1(), t.getItem2(), t.getRewardItem(), t.getCommands());
setXp(ResourceUtils.convertResToXPExact(t.getItem1()) + ResourceUtils.convertResToXPExact(t.getItem2()));
}
public XPVillagerTrade(ItemStack convert) {
super(convert, null, convert);
setXp(ResourceUtils.convertResToXP(convert));
}
public XPVillagerTrade(int xp, ItemStack rewardItem) {
super(new ItemStack(Material.EXP_BOTTLE, xp), rewardItem);
setXp(xp);
}
public XPVillagerTrade(int xp, ItemStack rewardItem, List<String> commands) {
super(new ItemStack(Material.EXP_BOTTLE, xp), rewardItem, commands);
setXp(xp);
}
/**
* @deprecated It will be removed in later version, use getXp() instead
*/
@Deprecated
public int getXP() {
return this.xp;
}
public int getXp() {
return this.xp;
}
}

View File

@@ -0,0 +1,92 @@
package ldcr.BedwarsXP.api;
import ldcr.BedwarsXP.Config;
import ldcr.BedwarsXP.utils.ActionBarUtils;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class XPManager {
private static final Map<String, XPManager> managerMap = new HashMap<>();
private final Map<UUID, Integer> xp = new HashMap<>();
private final HashMap<UUID, Long> messageTimeMap = new HashMap<>();
private final HashMap<UUID, Integer> messageCountMap = new HashMap<>();
public static XPManager getXPManager(String bedwarsGame) {
if (!managerMap.containsKey(bedwarsGame)) {
managerMap.put(bedwarsGame, new XPManager());
}
return managerMap.get(bedwarsGame);
}
public static void reset(String bedwarsGame) {
managerMap.remove(bedwarsGame);
}
public void updateXPBar(Player player) {
player.setLevel(get(player));
}
private void set(Player player, int count) {
xp.put(player.getUniqueId(), count);
updateXPBar(player);
}
private int get(Player player) {
Integer value = xp.get(player.getUniqueId());
if (value == null) {
value = 0;
xp.put(player.getUniqueId(), 0);
}
return value;
}
public void setXP(Player player, int count) {
set(player, count);
}
public int getXP(Player player) {
return get(player);
}
public void addXP(Player player, int count) {
set(player, get(player) + count);
}
public boolean takeXP(Player player, int count) {
if (!hasEnoughXP(player, count))
return false;
set(player, get(player) - count);
return true;
}
public boolean hasEnoughXP(Player player, int count) {
return get(player) >= count;
}
public void sendXPMessage(Player player, int count) {
if (!messageTimeMap.containsKey(player.getUniqueId())) {
messageTimeMap.put(player.getUniqueId(), System.currentTimeMillis());
}
if (!messageCountMap.containsKey(player.getUniqueId())) {
messageCountMap.put(player.getUniqueId(), 0);
}
if (System.currentTimeMillis() - messageTimeMap.get(player.getUniqueId()) > 500) {
messageCountMap.put(player.getUniqueId(), 0);
}
messageTimeMap.put(player.getUniqueId(), System.currentTimeMillis());
int c = messageCountMap.get(player.getUniqueId()) + count;
messageCountMap.put(player.getUniqueId(), c);
if (!Config.xpMessage.isEmpty()) {
ActionBarUtils.sendActionBar(player, Config.xpMessage.replaceAll("%xp%", Integer.toString(c)));
}
}
public void sendMaxXPMessage(Player player) {
if (!Config.maxXPMessage.isEmpty()) {
ActionBarUtils.sendActionBar(player, Config.maxXPMessage);
}
}
}

View File

@@ -0,0 +1,58 @@
package ldcr.BedwarsXP.api.events;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class BedwarsXPDeathDropXPEvent extends Event {
private final String game;
private final Player player;
private int deathCost;
private int deathDropped;
public BedwarsXPDeathDropXPEvent(String game, Player p, int dropped, int cost) {
this.game = game;
player = p;
deathCost = cost;
deathDropped = dropped;
}
@Override
public HandlerList getHandlers() {
return new HandlerList();
}
public String getGameName() {
return game;
}
public Player getDeadPlayer() {
return player;
}
public int getXPCost() {
return deathCost;
}
public void setXPCost(int drop) {
deathCost = drop;
}
public int getXPDropped() {
return deathDropped;
}
public void setXPDropped(int deathDropped) {
this.deathDropped = deathDropped;
}
@Deprecated
public int getXPCosted() {
return deathCost;
}
@Deprecated
public void setXPCosted(int drop) {
deathCost = drop;
}
}

View File

@@ -0,0 +1,91 @@
package ldcr.BedwarsXP.command;
import ldcr.BedwarsXP.BedwarsXP;
import ldcr.BedwarsXP.Config;
import ldcr.BedwarsXP.utils.BedwarsGameUtils;
import ldcr.BedwarsXP.utils.SendMessageUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
public class BedwarsXPCommandListener implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command arg1, String arg2, String[] args) {
if (args.length == 0) {
SendMessageUtils.sendMessage(sender,
"§6§lBedwarsXP §7>> §bBedwarsXP v." + BedwarsXP.getInstance().getDescription().getVersion() + " §lBy.SakuraKooi",
"§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_RELOAD"),
"§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_ENABLE"),
"§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_DISABLE"));
return true;
}
if (!sender.hasPermission("bedwarsxp.admin")) {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("YOU_DONT_HAVE_PERMISSION_TO_EXECUTE_THIS_COMMAND"));
return true;
}
switch (args[0].toLowerCase()) {
case "reload": {
Config.loadConfig();
BedwarsXP.getL18nCache().clear();
sender.sendMessage("§6§lBedwarsXP §7>> §b" + BedwarsXP.l18n("SUCCESSFULLY_RELOADED"));
if (BedwarsGameUtils.isAnyBedwarsRunning()) {
SendMessageUtils.sendMessage(sender,
"§6§lBedwarsXP §7>> §b" + BedwarsXP.l18n("RELOAD_GAME_RUNNING"),
"§6§lBedwarsXP §7>> §b" + BedwarsXP.l18n("UPDATE_RUNNING_GAME"));
BedwarsGameUtils.replaceAllShop(sender);
}
return true;
}
case "enable": {
if (args.length != 2) {
sender.sendMessage("§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_ENABLE"));
return true;
}
if (!BedwarsGameUtils.isGameExists(args[1])) {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("ERROR_GAME_NOT_FOUND", "%game%", args[1]));
return true;
}
String result = Config.setGameEnableXP(args[1], true);
if (result.equals("")) {
sender.sendMessage("§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("GAME_XP_ENABLED", "%game%", args[1]));
if (BedwarsGameUtils.isGameRunning(args[1])) {
sender.sendMessage("§6§lBedwarsXP §7>> §4" + BedwarsXP.l18n("GAME_IS_RUNNING_RESTART_REQUIRED", "%game%", args[1]));
}
} else {
SendMessageUtils.sendMessage(sender, "§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("ERROR_OCCURRED"), "§6§lBedwarsXP §7>> §c" + result);
}
return true;
}
case "disable": {
if (args.length != 2) {
sender.sendMessage("§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_DISABLE"));
return true;
}
if (!BedwarsGameUtils.isGameExists(args[1])) {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("ERROR_GAME_NOT_FOUND", "%game%", args[1]));
return true;
}
String result = Config.setGameEnableXP(args[1], false);
if (result.equals("")) {
sender.sendMessage("§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("GAME_XP_DISABLED", "%game%", args[1]));
if (BedwarsGameUtils.isGameRunning(args[1])) {
sender.sendMessage("§6§lBedwarsXP §7>> §4" + BedwarsXP.l18n("GAME_IS_RUNNING_RESTART_REQUIRED", "%game%", args[1]));
}
} else {
SendMessageUtils.sendMessage(sender, "§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("ERROR_OCCURRED"), "§6§lBedwarsXP §7>> §c" + result);
}
return true;
}
default: {
SendMessageUtils.sendMessage(sender,
"§6§lBedwarsXP §7>> §bBedwarsXP v." + BedwarsXP.getInstance().getDescription().getVersion() + " §lBy.SakuraKooi",
"§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_RELOAD"),
"§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_ENABLE"),
"§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_MAIN_DISABLE"));
return true;
}
}
}
}

View File

@@ -0,0 +1,74 @@
package ldcr.BedwarsXP.command;
import io.github.bedwarsrel.BedwarsRel;
import io.github.bedwarsrel.game.Game;
import ldcr.BedwarsXP.BedwarsXP;
import ldcr.BedwarsXP.Config;
import ldcr.BedwarsXP.api.XPManager;
import ldcr.BedwarsXP.utils.SendMessageUtils;
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.entity.Player;
public class EditXPCommandListener implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command arg1, String arg2, String[] args) {
if (args.length < 3) {
SendMessageUtils.sendMessage(sender,
"§6§lBedwarsXP §7>> §bBedwarsXP v." + BedwarsXP.getInstance().getDescription().getVersion() + " §lBy.SakuraKooi",
"§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("HELP_EDITXP"));
return true;
}
if (!sender.hasPermission("bedwarsxp.admin")) {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("YOU_DONT_HAVE_PERMISSION_TO_EXECUTE_THIS_COMMAND"));
return true;
}
String user = args[1];
OfflinePlayer offPlayer = Bukkit.getPlayer(user);
if (offPlayer != null) {
if (offPlayer.isOnline()) {
Player p = offPlayer.getPlayer();
Game bw = BedwarsRel.getInstance().getGameManager().getGameOfPlayer(p);
if (bw == null) {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("EDITXP_PLAYER_NOT_IN_GAME", "%player%", p.getName()));
return true;
}
if (!Config.isGameEnabledXP(bw.getName())) {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("EDITXP_GAME_IS_NOT_XP_MODE", "%player%", p.getName()));
return true;
}
int xp;
try {
xp = Integer.parseInt(args[2]);
} catch (NumberFormatException e) {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("EDITXP_XP_IS_NOT_A_NUMBER"));
return true;
}
if ("set".equalsIgnoreCase(args[0])) {
XPManager.getXPManager(bw.getName()).setXP(p, xp);
sender.sendMessage("§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("EDITXP_XP_HAS_BEEN_SET_TO", "%player%", p.getName(), "%xp%", String.valueOf(xp)));
} else if ("add".equalsIgnoreCase(args[0])) {
int current = XPManager.getXPManager(bw.getName()).getXP(p);
XPManager.getXPManager(bw.getName()).setXP(p, current + xp);
sender.sendMessage("§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("EDITXP_XP_HAS_BEEN_SET_TO", "%player%", p.getName(), "%xp%", String.valueOf(current + xp)));
} else if ("take".equalsIgnoreCase(args[0])) {
int current = XPManager.getXPManager(bw.getName()).getXP(p);
XPManager.getXPManager(bw.getName()).setXP(p, current - xp);
sender.sendMessage("§6§lBedwarsXP §7>> §a" + BedwarsXP.l18n("EDITXP_XP_HAS_BEEN_SET_TO", "%player%", p.getName(), "%xp%", String.valueOf(current - xp)));
} else {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("HELP_EDITXP"));
}
} else {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("EDITXP_PLAYER_NOT_IN_GAME", "%player%", offPlayer.getName()));
}
} else {
sender.sendMessage("§6§lBedwarsXP §7>> §c" + BedwarsXP.l18n("EDITXP_PLAYER_NOT_IN_GAME", "%player%", args[1]));
}
return true;
}
}

View File

@@ -0,0 +1,108 @@
package ldcr.BedwarsXP.utils;
import ldcr.BedwarsXP.BedwarsXP;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ActionBarUtils {
private static boolean USE_CHAT = false;
private static boolean USE_1_7_NMS = false;
private static boolean USE_1_8_NMS = false;
private static boolean USE_1_11_API = false;
private static Class<?> classCraftPlayer;
private static Class<?> classPacketPlayOutChat;
private static Class<?> classPacket;
private static Class<?> classChatSerializer;
private static Method methodSerializeMessage;
private static Class<?> classIChatBaseComponent;
private static Class<?> classChatComponentText;
private static Method methodGetHandle = null;
private static Field fieldPlayerConnection = null;
private static Method methodSendPacket = null;
public static void load() {
String NMS_VERSION = Bukkit.getServer().getClass().getPackage().getName();
NMS_VERSION = NMS_VERSION.substring(NMS_VERSION.lastIndexOf('.') + 1);
if (NMS_VERSION.equalsIgnoreCase("v1_8_R1") || NMS_VERSION.equalsIgnoreCase("v1_7_")) {
USE_1_7_NMS = true;
} else {
try {
int ver = Integer.parseInt(NMS_VERSION.split("_")[1]);
if (ver >= 11) {
USE_1_11_API = true;
} else {
USE_1_8_NMS = true;
}
} catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
BedwarsXP.sendConsoleMessage("§cERROR: " + BedwarsXP.l18n("ERROR_UNSUPPORTED_VERSION_ACTIONBAR_MAY_NOT_WORK"));
USE_CHAT = true;
}
}
if (USE_1_7_NMS || USE_1_8_NMS) {
try {
classCraftPlayer = Class.forName("org.bukkit.craftbukkit." + NMS_VERSION + ".entity.CraftPlayer");
classPacketPlayOutChat = Class.forName("net.minecraft.server." + NMS_VERSION + ".PacketPlayOutChat");
classIChatBaseComponent = Class.forName("net.minecraft.server." + NMS_VERSION + ".IChatBaseComponent");
classPacket = Class.forName("net.minecraft.server." + NMS_VERSION + ".Packet");
if (USE_1_7_NMS) {
classChatSerializer = Class.forName("net.minecraft.server." + NMS_VERSION + ".ChatSerializer");
methodSerializeMessage = classChatSerializer.getDeclaredMethod("a", String.class);
} else {
classChatComponentText = Class.forName("net.minecraft.server." + NMS_VERSION + ".ChatComponentText");
}
} catch (ReflectiveOperationException e) {
BedwarsXP.sendConsoleMessage("§cERROR: " + BedwarsXP.l18n("ERROR_UNSUPPORTED_VERSION_ACTIONBAR_MAY_NOT_WORK"));
USE_1_7_NMS = false;
USE_1_8_NMS = false;
USE_CHAT = true;
}
}
}
public static void sendActionBar(Player player, String message) {
if (USE_CHAT) {
player.sendMessage(message);
} else if (USE_1_11_API) {
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
} else if (USE_1_7_NMS || USE_1_8_NMS) {
try {
Object objectCraftPlayer = classCraftPlayer.cast(player);
Object objectPacketChat;
Object objectChatComponent;
if (USE_1_7_NMS) {
objectChatComponent = classIChatBaseComponent.cast(methodSerializeMessage.invoke(classChatSerializer, "{\"text\": \"" + message + "\"}"));
} else {
objectChatComponent = classChatComponentText.getConstructor(String.class).newInstance(message);
}
objectPacketChat = classPacketPlayOutChat.getConstructor(classIChatBaseComponent, byte.class).newInstance(objectChatComponent, (byte) 2);
if (methodGetHandle == null)
methodGetHandle = classCraftPlayer.getDeclaredMethod("getHandle");
Object objectEntityPlayer = methodGetHandle.invoke(objectCraftPlayer);
if (fieldPlayerConnection == null)
fieldPlayerConnection = objectEntityPlayer.getClass().getDeclaredField("playerConnection");
Object objectPlayerConnection = fieldPlayerConnection.get(objectEntityPlayer);
if (methodSendPacket == null)
methodSendPacket = objectPlayerConnection.getClass().getDeclaredMethod("sendPacket", classPacket);
methodSendPacket.invoke(objectPlayerConnection, objectPacketChat);
} catch (ReflectiveOperationException e) { // Reflection exception caught -> dont retry, switch to backend
e.printStackTrace();
USE_1_7_NMS = false;
USE_1_8_NMS = false;
USE_CHAT = true;
player.sendMessage(message);
} catch (Exception e) { // send message to chat instead, retry actionbar later
e.printStackTrace();
player.sendMessage(message);
}
}
}
}

View File

@@ -0,0 +1,37 @@
package ldcr.BedwarsXP.utils;
import io.github.bedwarsrel.BedwarsRel;
import io.github.bedwarsrel.game.Game;
import io.github.bedwarsrel.game.GameState;
import ldcr.BedwarsXP.XPShop.ShopReplacer;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
public class BedwarsGameUtils {
public static boolean isGameExists(String bw) {
return BedwarsRel.getInstance().getGameManager().getGame(bw) != null;
}
public static boolean isGameRunning(String bw) {
return BedwarsRel.getInstance().getGameManager().getGame(bw).getState().equals(GameState.RUNNING);
}
public static boolean isAnyBedwarsRunning() {
ArrayList<Game> bw = BedwarsRel.getInstance().getGameManager().getGames();
for (Game game : bw) {
if (game.getState().equals(GameState.RUNNING))
return true;
}
return false;
}
public static void replaceAllShop(CommandSender sender) {
ArrayList<Game> bw = BedwarsRel.getInstance().getGameManager().getGames();
for (Game game : bw) {
if (game.getState().equals(GameState.RUNNING)) {
ShopReplacer.replaceShop(game.getName(), sender);
}
}
}
}

View File

@@ -0,0 +1,30 @@
package ldcr.BedwarsXP.utils;
import java.lang.reflect.Field;
public class ReflectionUtils {
private ReflectionUtils() {
}
public static <T, R> void setPrivateValue(T r, String f, R value) throws ReflectiveOperationException {
Class<?> clazz = r.getClass();
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
field.set(r, value);
field.setAccessible(false);
}
public static <T> Field getField(T r, String f) throws ReflectiveOperationException {
Class<?> clazz = r.getClass();
return clazz.getDeclaredField(f);
}
public static boolean isClassFound(String className) {
try {
Class.forName(className);
} catch (ClassNotFoundException e) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,19 @@
package ldcr.BedwarsXP.utils;
import ldcr.BedwarsXP.Config;
import org.bukkit.inventory.ItemStack;
public class ResourceUtils {
public static Integer convertResToXP(ItemStack stack) {
if (stack == null)
return null;
if (Config.resources.containsKey(stack.getType()))
return Config.resources.get(stack.getType()) * stack.getAmount();
return null;
}
public static int convertResToXPExact(ItemStack item) {
Integer result = convertResToXP(item);
return result == null ? 0 : result;
}
}

View File

@@ -0,0 +1,9 @@
package ldcr.BedwarsXP.utils;
import org.bukkit.command.CommandSender;
public class SendMessageUtils {
public static void sendMessage(CommandSender sender, String... message) {
sender.sendMessage(message);
}
}

View File

@@ -0,0 +1,21 @@
package ldcr.BedwarsXP.utils;
import org.bukkit.Sound;
public class SoundMachine {
public static Sound get(String v18, String v19) {
try {
// Try get old sound name
return Sound.valueOf(v18);
} catch (IllegalArgumentException e1) {
try {
// Try get new sound name
return Sound.valueOf(v19);
} catch (IllegalArgumentException e2) {
// not found
return null;
}
}
}
}

View File

@@ -0,0 +1,17 @@
package ldcr.BedwarsXP.utils;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
public class YamlUtils {
public static YamlConfiguration loadYamlUTF8(File file) throws IOException {
String yaml = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
StringReader sr = new StringReader(yaml);
return YamlConfiguration.loadConfiguration(sr);
}
}

View File

@@ -0,0 +1,44 @@
package sakura.kooi.utils.GithubUpdateChecker;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.AllArgsConstructor;
import lombok.Cleanup;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.function.Consumer;
@AllArgsConstructor
public class UpdateChecker {
private String user;
private String repo;
private String currentVersion;
private Consumer<String> callback;
public void check() throws IOException {
URL url = new URL("https://api.github.com/repos/" + user + "/" + repo + "/releases/latest");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
@Cleanup BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
StringBuilder result = new StringBuilder();
while ((line = rd.readLine()) != null) {
result.append(line);
}
JsonParser parser = new JsonParser();
JsonObject json = parser.parse(result.toString()).getAsJsonObject();
if (json.has("tag_name") && json.has("html_url")) {
String tag = json.get("tag_name").getAsString();
String link = json.get("html_url").getAsString();
if (currentVersion.compareTo(tag) < 0) {
callback.accept(link);
}
}
}
}

View File

@@ -0,0 +1,62 @@
###############################
# BedwarsXP 经验起床插件 #
# By.SakuraKooi #
###############################
# 关闭更新检查
Disable_UpdateChecker: false
#设置资源可兑换为的XP数
XP:
# 铜可兑换为的XP
bronze: 1
# 铁可兑换为的XP
iron: 5
# 金可兑换为的XP
gold: 10
# 如有其他自行添加的资源也可以在此处按格式添加
#custom: 233
# 请务必保证起床插件中配置的资源在此处都有对应经验值
#获得XP的提示
# 使用%xp%代替获得的XP
# 插件会尝试使用ActionBar来发送,如发送失败(版本不匹配等原因)会使用聊天发送
# 更改为空('')来禁用发送信息
Message: '&a你获得了 &6&l%xp% &a点经验'
#是否在商店新增将经验重新兑换回铜铁金的菜单
Add_Res_Shop: true
#玩家死亡扣除经验
# 扣除的经验 = 玩家拥有经验 x (DeathCostXP)%
# 请填写0-100 (百分比)
# 设置为0关闭此功能
# 固定扣除功能已被移除
DeathCostXP: 0
#玩家死亡掉落经验
# 开启此项后玩家死亡扣除的经验将掉在地上, 可以被其他玩家捡起
# 掉落的经验 = 玩家拥有经验 x (DeathCostXP)% x (DeathDropXP)%
# 请填写0-100 (百分比)
# 设置为0关闭此功能
DeathDropXP: 100
#死亡直接把经验添加给击杀者而不是掉落经验瓶
DontDropExpBottle: false
#玩家可携带的最大经验
# 超过该经验将无法捡取
# 设置为0关闭此功能
MaxXP: 0
MaxXPMessage: '&4你携带的经验已达上限'
#完全经验起床模式
# 设置为false : 玩家捡取资源获得经验,在商店将经验重新兑换回铜铁金购买东西
# 设置为true : 玩家捡取资源获得经验,并可以在商店直接使用经验购买东西
Full_XP_Bedwars: true
#配置文件版本
# 请务必不要动这个
# 乱动此项导致配置文件被重置概不负责→_→
ConfigVersion: 2

View File

@@ -0,0 +1 @@
enabledGame:

View File

@@ -0,0 +1,81 @@
# Wanna English? Just overwrites language.yml with this file :)
# You should replace single quote(') with two single quote('')
# eg: player's -> player''s
# Loading configuration
LOADING_CONFIGURATION: 'Loading configuration...'
CONFIGURATION_FILE_NOT_EXISTS: 'Configuration file not exists, create it...'
OLD_VERSION_CONFIGURATION: 'Your configuration is outdated and cannot be load!'
OLD_CONFIGURATION_BACKUPED: 'Your configuration has been renamed to [config.bak.yml], creating new one...'
NEW_CONFIGURATION_SAVED: 'New configuration is created, continue...'
RESOURCE_SHOP_ENABLED: 'Enabled XP-Resource shop'
DEATH_COST_XP_PERCENT: 'Death will take %percent%% XP'
DEATH_DROP_XP_DISABLED: 'Disabled Death-drop-XP'
DEATH_DROP_XP_PERCEMT: 'Death will drop %percent%% XP'
DEATH_DROP_EXP_BOTTLE_DISABLED: 'Disabled Death-drop-ExpBottle (Directly add to killer instead)'
MAX_XP_LIMIT_DISABLED: 'Disabled Max-XP-limit'
MAX_XP_LIMIT_ENABLED: 'Max XP limit is %value%'
ALL_TRADES_USE_XP_ENABLED: 'Enabled All-trade-use-XP'
LOADING_RESOURCES_VALUE: 'Loading resource data...'
FOUNDED_RESOURCE: 'Resource %resource% (%material%) = %value%XP'
WARN_YOU_NEEDS_ENABLE_BEDWARSXP_MANUALLY: 'You need to use [/bwxp enable] to enable XP mode for a game!'
# Enabling plugin
FINDING_BEDWARSREL: 'Finding BedwarsRel...'
BEDWARSREL_NOT_SUPPORTED: 'Sorry, Your BedwarsRel is not supported!'
PLEASE_UPDATE_BEDWARSREL: 'Please update your BedwarsRel.'
BEDWARSREL_SUPPORTED: 'Supported BedwarsRel found!'
BEDWARSREL_NOT_FOUND: 'BedwarsRel not found!'
ERROR_OCCURED_WHILE_LOADING: 'An error occurred while loading BedwarsXP'
REPORT_ISSUE_HERE: 'Report it at here'
SUCCESSFULLY_LOADED: 'BedwarsXP has been successfully loaded!'
REPORT_ISSUE_AND_SUGGESTION_HERE: 'BUG Report | Suggestions'
# Commands
YOU_DONT_HAVE_PERMISSION_TO_EXECUTE_THIS_COMMAND: 'You dont have permission to execute this command'
UNEXCEPTED_EXCEPTION_CAUGHT: 'An unexpected error caught while executing the command.'
ERROR_OCCURED: 'Sorry, An error occurred.'
# Main command
HELP_MAIN_RELOAD: '/bwxp reload Reload BedwarsXP'
HELP_MAIN_ENABLE: '/bwxp enable <map> Enable XP mode'
HELP_MAIN_DISABLE: '/bwxp disable <map> Disable XP mode'
SUCCESSFULLY_RELOADED: 'BedwarsXP reloaded~'
RELOAD_GAME_RUNNING: 'Some map is running!'
UPDATE_RUNNING_GAME: 'Updating running games...'
ERROR_GAME_NOT_FOUND: 'Sorry, Map %game% cannot be found'
GAME_XP_ENABLED: 'Enabled XP mode for map %game% !'
GAME_XP_DISABLED: 'Disabled XP mode for map %game% !'
GAME_IS_RUNNING_RESTART_REQUIRED: 'Map %game% is running, please restart it manually!'
# Edit XP command
HELP_EDITXP: '/editxp <set/add/take> <player> <xp> Modify a player''s XP'
EDITXP_PLAYER_NOT_IN_GAME: 'Player %player% is not in game!'
EDITXP_GAME_IS_NOT_XP_MODE: 'The map that %player% playing is not in XP mode!'
EDITXP_XP_IS_NOT_A_NUMBER: 'The XP you typed is not a valid number!'
EDITXP_XP_HAS_BEEN_SET_TO: 'Player %player%''s XP has been set to %xp%'
# Shop replacer
ERROR_OCCURED_REPLACE_SHOP: 'Failed to replace shop for map %game%'
SUCCESSFULLY_REPLACED_SHOP: 'Successfully replaced shop for map %game%!'
ERROR_OCCURED_WHILE_INITALIZING_XP_SHOP: 'An error occurred while initializing XP shop for map %game%'
SHOP_XP_EXCHANGE_TITLE: '§6§lXP Shop'
SHOP_XP_EXCHANGE_LORE: '§aBuy resource with XP'
SHOP_TRADE_XP: '§a%xp% XP'
# Update checker
HAS_UPDATE: 'Your BedwarsXP is outdated! Update now -> %link%'
# Others
ERROR_UNSUPPORTED_VERSION_ACTIONBAR_MAY_NOT_WORK: 'Unsupported server version, ActionBar may not works'
ERROR_OCCURRED_WHILE_LOADING: 'An unexpected error occurred while loading plugin'

View File

@@ -0,0 +1,77 @@
# Loading configuration
LOADING_CONFIGURATION: '正在加载配置文件...'
CONFIGURATION_FILE_NOT_EXISTS: '配置文件不存在, 正在创建...'
OLD_VERSION_CONFIGURATION: '您的配置文件版本过老无法加载'
OLD_CONFIGURATION_BACKUPED: '已备份您的配置文件为 [config.bak.yml] ,开始初始化新版本配置文件'
NEW_CONFIGURATION_SAVED: '配置文件初始化完成, 继续加载配置...'
RESOURCE_SHOP_ENABLED: '已启用经验兑换资源商店'
DEATH_COST_XP_PERCENT: '死亡扣除 %percent%% 经验'
DEATH_DROP_XP_DISABLED: '死亡掉落经验已关闭'
DEATH_DROP_XP_PERCEMT: '死亡掉落经验占扣除经验 %percent%%'
DEATH_DROP_EXP_BOTTLE_DISABLED: '死亡掉落经验瓶已关闭 (直接添加给击杀者)'
MAX_XP_LIMIT_DISABLED: '最大经验限制已关闭'
MAX_XP_LIMIT_ENABLED: '最大经验限制设置为 %value%'
ALL_TRADES_USE_XP_ENABLED: '完全经验起床模式已启动'
LOADING_RESOURCES_VALUE: '开始加载资源价值数据'
FOUNDED_RESOURCE: '发现资源 %resource% 物品:%material% 价值 %value%'
WARN_YOU_NEEDS_ENABLE_BEDWARSXP_MANUALLY: '注意,在新版本中你需要手动使用/bwxp enable来启用游戏的经验起床模式'
# Enabling plugin
FINDING_BEDWARSREL: '正在寻找BedwarsRel插件...'
BEDWARSREL_NOT_SUPPORTED: '抱歉, BedwarsXP不再支持旧版BedwarsRel!'
PLEASE_UPDATE_BEDWARSREL: '请更新你的BedwarsRel至1.3.6以上版本.'
BEDWARSREL_SUPPORTED: '已发现受支持的BedwarsRel插件!'
BEDWARSREL_NOT_FOUND: '没有找到支持的BedwarsRel! 你可能没有安装或使用了不受支持的版本!'
ERROR_OCCURED_WHILE_LOADING: 'BedwarsXP加载出错'
REPORT_ISSUE_HERE: '请前往此处反馈'
SUCCESSFULLY_LOADED: '成功加载BedwarsXP经验起床插件'
REPORT_ISSUE_AND_SUGGESTION_HERE: 'BUG反馈 | 提交建议'
# Commands
YOU_DONT_HAVE_PERMISSION_TO_EXECUTE_THIS_COMMAND: '你没有权限执行此命令'
UNEXCEPTED_EXCEPTION_CAUGHT: '在执行您的命令时出现了异常错误'
ERROR_OCCURED: '错误: 在执行您的操作时发生了错误'
# Main command
HELP_MAIN_RELOAD: '/bwxp reload 重载插件配置'
HELP_MAIN_ENABLE: '/bwxp enable <游戏> 激活指定游戏的经验起床模式'
HELP_MAIN_DISABLE: '/bwxp disable <游戏> 禁用指定游戏的经验起床模式'
SUCCESSFULLY_RELOADED: '成功重载配置文件~'
RELOAD_GAME_RUNNING: '当前有游戏正在运行'
UPDATE_RUNNING_GAME: '开始更新运行中的游戏的经验商店'
ERROR_GAME_NOT_FOUND: '错误: 找不到游戏 %game%'
GAME_XP_ENABLED: '成功激活了游戏 %game% 的经验起床模式'
GAME_XP_DISABLED: '成功禁用了游戏 %game% 的经验起床模式'
GAME_IS_RUNNING_RESTART_REQUIRED: '游戏 %game% 正在运行,请手动重启游戏'
# Edit XP command
HELP_EDITXP: '/editxp <set/add/take> <玩家> <经验值> 设置其他玩家的经验值'
EDITXP_PLAYER_NOT_IN_GAME: '玩家 %player% 不在游戏中!'
EDITXP_GAME_IS_NOT_XP_MODE: '玩家 %player% 所在的游戏没有开启经验起床模式!'
EDITXP_XP_IS_NOT_A_NUMBER: '输入经验值的不是一个有效数字!'
EDITXP_XP_HAS_BEEN_SET_TO: '玩家 %player% 的经验值已被设置为 %xp%'
# Shop replacer
ERROR_OCCURED_REPLACE_SHOP: '为地图 %game% 替换原始商店为经验商店失败'
SUCCESSFULLY_REPLACED_SHOP: '为地图 %game% 替换经验商店成功!'
ERROR_OCCURED_WHILE_INITALIZING_XP_SHOP: '为地图 %game% 初始化经验商店时出错'
SHOP_XP_EXCHANGE_TITLE: '§6§l经验兑换资源'
SHOP_XP_EXCHANGE_LORE: '§a将你的经验兑换成物品'
SHOP_TRADE_XP: '§a%xp% 经验'
# Update checker
HAS_UPDATE: 'BedwarsXP 发布了新版本! 下载 -> %link%'
# Others
ERROR_UNSUPPORTED_VERSION_ACTIONBAR_MAY_NOT_WORK: '解析服务端版本失败, ActionBar提示可能出错'
ERROR_OCCURRED_WHILE_LOADING: '加载插件时发生了异常错误'

View File

@@ -0,0 +1,18 @@
name: BedwarsXP
main: ldcr.BedwarsXP.BedwarsXP
version: 2.1.3
author: SakuraKooi
depend: [BedwarsRel]
commands:
bedwarsxp:
description: 经验起床
usage: /bedwarsxp
aliases: [bwxp]
bedwarsxpedit:
description: 修改玩家经验值
usage: /bedwarsxpedit
aliases: [editxp]
permissions:
bedwarsxp.admin:
description: 经验起床相关管理权限.
default: op