mirror of
https://github.com/CarmJos/UserPrefix.git
synced 2026-06-05 09:01:39 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ac3cea7c0 | |||
| 3f14294e67 | |||
| 93521f6621 | |||
| 43a4fb08a6 | |||
| 3dd6398afa | |||
| 799bb4e52b | |||
| 7ea3934db9 |
+233
@@ -0,0 +1,233 @@
|
||||

|
||||
|
||||
# UserPrefix Plugin
|
||||
|
||||
[](https://www.codefactor.io/repository/github/carmjos/userprefix)
|
||||
[](https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml)
|
||||

|
||||
|
||||
Lightweight, efficient, and real-time user prefix system.
|
||||
|
||||
This plugin is implemented based on Spigot ,**Theoretically** support ALL MineCraft Versions.
|
||||
|
||||
The development of this plugin is based on Chinese which purpose is to help Chinese developers learn Bukkit plugin
|
||||
development.
|
||||
|
||||
本插件已在 [MCBBS](https://www.mcbbs.net/forum.php?mod=viewthread&tid=1261503) 上发布,欢迎中文用户来这里下载。
|
||||
|
||||
## Examples
|
||||
|
||||

|
||||
|
||||
## Dependencies
|
||||
|
||||
- **[Necessary]** Plugin developed based on [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT)
|
||||
and [BukkitAPI](http://bukkit.org/).
|
||||
- **[Necessary]** Plugin data storage base on [LuckPerms](https://www.spigotmc.org/resources/luckperms.28140/).
|
||||
- **[Recommend]** Placeholders based on [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) .
|
||||
|
||||
For development dependencies, please see [Dependencies](https://github.com/CarmJos/UserPrefix/network/dependencies) .
|
||||
|
||||
## Features
|
||||
|
||||
- **Theoretically** support ALL MineCraft Versions.
|
||||
- Reloading the configuration will automatically refresh the prefix of all players.
|
||||
- Real-time judgment and feedback to the player when permissions are changed.
|
||||
- Configurable sounds and messages.
|
||||
- The prefix icon can be configured as "Selected", "Has Permission" and “No Permission”.
|
||||
- Item configuration is natively configured through ItemStack, which supports all MC settings!
|
||||
- TabList is automatically sorted according to the weight of the prefix (if there is a conflict, it can be turned off)
|
||||
- The prefix display on the player name (can be turned off if there is a conflict)
|
||||
- GUI with automatic sorting and page turning!
|
||||
- Support PlaceholderAPI variables!
|
||||
- Support Hex color! (Version 1.16 and above) `&(#Color)`
|
||||
- Example: LightSlateBlue `&(#8470FF)` 、 DarkSlateBlue `&(#483D8B)`
|
||||
|
||||
## Notice
|
||||
|
||||
### 1. Version support issues
|
||||
|
||||
This plugin theoretically supports all versions.
|
||||
|
||||
If the icon does not load, the sound cannot be played, etc.,
|
||||
please check whether the type of the item and sound in the configuration file exists in the current version.
|
||||
|
||||
Take the SOUND as an example.
|
||||
The sound that the villager said "OK" is "`VILLAGER_YES`" in the lower version, but it becomes "`ENTITY_VILLAGER_YES`" in the higher version.
|
||||
|
||||
### 2. Scoreboard exception problem
|
||||
|
||||
The display of the prefix on the head and the sorting of the TabList both use the scoreboard API.
|
||||
|
||||
Please turn of the `functions.OnNamePrefix` in the configuration if there is a conflict.
|
||||
|
||||
### 3. Item icon configuration problem
|
||||
|
||||
Items are read through the ItemStack serialization method provided by Bukkit. For related configuration methods, please refer to [ItemStack Serialization](https://www.spigotmc.org/wiki/itemstack-serialization/).
|
||||
|
||||
## Commands
|
||||
|
||||
This plugin's Commands are based on Chinese!
|
||||
**May support multi-language in the future.**
|
||||
|
||||
```text
|
||||
/UserPrefix or /prefix #Open prefix GUI
|
||||
/UserPrefixAdmin # View Admin Command Help
|
||||
/UserPrefixAdmin reload # Reload Config
|
||||
/UserPrefixAdmin list # List all configured prefixes.~~~~
|
||||
```
|
||||
|
||||
## Placeholders (PlaceholderAPI)
|
||||
|
||||
After installed the [PlaceholderAPI](https://github.com/PlaceholderAPI/PlaceholderAPI) , you can
|
||||
type `/papi info UserPrefix` to see all the placeholders.
|
||||
|
||||
```text
|
||||
# %UserPrefix_prefix%
|
||||
- Get the content of the current prefix
|
||||
# %UserPrefix_weight%
|
||||
- Get the weight of the current prefix.
|
||||
# %UserPrefix_identifier%
|
||||
- Get the identifier of the current prefix.
|
||||
# %UserPrefix_name%
|
||||
- Get the name of the current prefix.
|
||||
# %UserPrefix_has_<Identifier>%
|
||||
- Determine whether the player has a certain prefix(true/false)
|
||||
```
|
||||
|
||||
## Sample [configuration file](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/config-en.yml)
|
||||
|
||||
Notice: The default configuration is based on Chinese.
|
||||
You can find the [English Version here](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/config-en.yml).
|
||||
|
||||
```yaml
|
||||
version: 1.0.0-SNAPSHOT # DO NOT EDIT IT
|
||||
|
||||
debug: false #DEBUG OUT PUT
|
||||
|
||||
GUI:
|
||||
title: "&f&lMy Prefixes List" # Title of the GUI
|
||||
|
||||
functions:
|
||||
# Whether to add a prefix to the top of the head,
|
||||
# this method uses the scoreboard above the head,
|
||||
# please turn it off if there is a conflict.
|
||||
OnNamePrefix: true
|
||||
# Automatic prefix select.
|
||||
# When the player does not choose a prefix by himself,
|
||||
# the prefix with the highest weight will be used automatically
|
||||
autoUsePrefix: true
|
||||
|
||||
messages:
|
||||
selected:
|
||||
- "&7You have selected the &f%(name) &7as current prefix."
|
||||
expired:
|
||||
- "&7Your prefix &f%(oldName) &7has expired,"
|
||||
- "&7Now the prefix is changed to &f%(newName) &7."
|
||||
reload:
|
||||
- "&a&lReload completed!&7costs &f%(time)ms&7."
|
||||
help:
|
||||
- "&3&lUserPrefixAdmin &fHelp"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7Show configured prefixes."
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7Reload configuration."
|
||||
list-title:
|
||||
- "&3&lUserPrefixAdmin &fList"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7Name &r%(name) &7Perm &r%(permission)"
|
||||
- "&8- &7Example&r %(content) %(sender_name)"
|
||||
|
||||
Sounds:
|
||||
# Format is [SOUND_NAME:Volume:Pitch] or [SOUND_NAME:Volume] or [SOUND_NAME]
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
guiClick: "UI_BUTTON_CLICK"
|
||||
prefixChange: "ENTITY_VILLAGER_YES"
|
||||
prefixExpired: "ENTITY_VILLAGER_NO"
|
||||
|
||||
# The default prefix's weight is 0.
|
||||
defaultPrefix:
|
||||
name: "Default prefix"
|
||||
content: "&b"
|
||||
itemNotUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix §f(Click to select)"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
|
||||
prefixes:
|
||||
VIP:
|
||||
name: "&b&lPro&b" # [Necessary] Name (Using in messages)
|
||||
content: "§b§lPro §b" # [Necessary] What to display before the name
|
||||
# [Necessary] Weight, used for sorting in the GUI
|
||||
# (the larger is displayed at the back) and the automatic prefix display
|
||||
weight: 1
|
||||
# [Necessary] If there is no permission for detection, everyone can use it,
|
||||
# which means there is no need to configure "itemNoPermission"
|
||||
# (because it is impossible to display items without permission at all)
|
||||
permission: "yc.pro"
|
||||
itemHasPermission:
|
||||
# [Necessary] This Item will be displayed when player has permission
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
# [Not Necessary] This Item will be displayed when the prefix is selected.
|
||||
# If there is no such configuration, it will automatically display "itemHasPermission".
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #Add an enchantment so it looks like it’s selected
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
itemNoPermission:
|
||||
# [Not Necessary] If player doesn't have the permission,this item will be displayed.
|
||||
# If this item is not configured, it will not be displayed in the GUI when the player does not have permission to use it.
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP §c(Buy it!)"
|
||||
lore:
|
||||
- ""
|
||||
- "§e✯ Buy the VIP to use it!"
|
||||
```
|
||||
|
||||
## Support and Donation
|
||||
|
||||
This project is support by the [YourCraft(你的世界)](https://www.ycraft.cn) .
|
||||

|
||||
|
||||
## Open source agreement
|
||||
|
||||
The source code of this project uses [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0) License.
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
本插件基于Spigot实现,**理论上支持全版本**。
|
||||
|
||||
本插件已在 [MCBBS](https://www.mcbbs.net/forum.php?mod=viewthread&tid=1261503) 上发布。
|
||||
本插件已在 [MCBBS](https://www.mcbbs.net/forum.php?mod=viewthread&tid=1261503) 与 [SpigotMC](https://www.spigotmc.org/resources/userprefix-hex-color-support-all-version.96277/) 上发布。
|
||||
|
||||
The English version of the introduction is [here](https://github.com/CarmJos/UserPrefix/blob/master/README-en.md).
|
||||
|
||||
## 示例
|
||||
|
||||
@@ -88,7 +90,7 @@
|
||||
- 判断玩家是否拥有某个前缀(true/false)
|
||||
```
|
||||
|
||||
## 配置文件示例
|
||||
## [配置文件](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/config.yml)示例
|
||||
|
||||
```yaml
|
||||
version: 1.0.0-SNAPSHOT # 配置文件版本,一般不会动。
|
||||
@@ -99,12 +101,29 @@ functions:
|
||||
OnNamePrefix: true # 是否给头顶上添加前缀,该方法用到了头顶的那个计分板,如有冲突请关掉哦~
|
||||
autoUsePrefix: true # 自动前缀显示 当玩家没有自己选择一个前缀的时候,会自动使用所拥有的的前缀中权重最高的那一个
|
||||
|
||||
GUI:
|
||||
title: "&f&l我的前缀 &8| 列表"
|
||||
|
||||
messages:
|
||||
selected:
|
||||
- "&7您选择了 &f%(name) &7作为当前显示的前缀。"
|
||||
expired:
|
||||
- "&7您先前使用的前缀 &f%(oldName) &7已到期。"
|
||||
- "&7现在已为您重新调整为 &f%(newName) &7。"
|
||||
reload:
|
||||
- "&a&l重载完成!&7共耗时 &f%(time)ms&7。"
|
||||
help:
|
||||
- "&3&l用户前缀系统 &f帮助"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7查看当前前缀列表。"
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7重载前缀配置。"
|
||||
list-title:
|
||||
- "&3&l用户前缀系统 &f前缀列表"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7显示名 &r%(name) &7权限 &r%(permission)"
|
||||
- "&8- &7内容示例&r %(content) %(sender_name)"
|
||||
|
||||
Sounds: #相关的声音,注释掉则不播放声音
|
||||
# 格式为 【声音名:音量:音调】 或 【声音名:音量】 或 【声音名】
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>cc.carm.plugin</groupId>
|
||||
<artifactId>UserPrefix</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<version>1.2.5</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cc.carm.plugin.userprefix.command;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import cc.carm.plugin.userprefix.manager.PrefixManager;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
@@ -21,11 +22,21 @@ public class UserPrefixAdminCommand implements CommandExecutor {
|
||||
if (args.length == 1) {
|
||||
String aim = args[0];
|
||||
if (aim.equalsIgnoreCase("list")) {
|
||||
MessageUtil.send(sender, "&3&l用户前缀系统 &f前缀列表");
|
||||
MessageUtil.sendWithPlaceholders(sender, PrefixConfig.Messages.LIST_TITLE.get());
|
||||
for (ConfiguredPrefix value : PrefixManager.getPrefixes().values()) {
|
||||
MessageUtil.send(sender, "&8#" + value.getWeight() + " &f" + value.getIdentifier());
|
||||
MessageUtil.send(sender, "&8- &7显示名 &r" + value.getName() + " &7权限&r " + value.getPermission());
|
||||
MessageUtil.send(sender, "&8- &7内容示例&r " + value.getContent() + sender.getName());
|
||||
MessageUtil.sendWithPlaceholders(
|
||||
sender, PrefixConfig.Messages.LIST_VALUE.get(),
|
||||
new String[]{
|
||||
"%(weight)", "%(identifier)",
|
||||
"%(name)", "%(permission)",
|
||||
"%(content)", "%(sender_name)"
|
||||
},
|
||||
new Object[]{
|
||||
value.getWeight(), value.getIdentifier(),
|
||||
value.getName(), value.getPermission(),
|
||||
value.getContent(), sender.getName()
|
||||
}
|
||||
);
|
||||
}
|
||||
return true;
|
||||
} else if (aim.equalsIgnoreCase("reload")) {
|
||||
@@ -42,7 +53,10 @@ public class UserPrefixAdminCommand implements CommandExecutor {
|
||||
*/
|
||||
UserManager.updatePrefixView(onlinePlayer, false);
|
||||
}
|
||||
MessageUtil.send(sender, "&a&l重载完成!&7共耗时 &f" + (System.currentTimeMillis() - s1) + " ms&7。");
|
||||
MessageUtil.sendWithPlaceholders(
|
||||
sender, PrefixConfig.Messages.RELOAD.get(),
|
||||
new String[]{"%(time)"}, new Object[]{(System.currentTimeMillis() - s1)}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return help(sender);
|
||||
@@ -51,11 +65,7 @@ public class UserPrefixAdminCommand implements CommandExecutor {
|
||||
}
|
||||
|
||||
public static boolean help(CommandSender sender) {
|
||||
MessageUtil.send(sender, "&3&l用户前缀系统 &f帮助");
|
||||
MessageUtil.send(sender, "&8#&f list");
|
||||
MessageUtil.send(sender, "&8- &7查看当前前缀列表。");
|
||||
MessageUtil.send(sender, "&8#&f reload");
|
||||
MessageUtil.send(sender, "&8- &7重载前缀配置。");
|
||||
MessageUtil.send(sender, PrefixConfig.Messages.HELP.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,22 @@ public class PrefixConfig {
|
||||
|
||||
}
|
||||
|
||||
public static class GUI {
|
||||
|
||||
public static ConfigValue<String> TITLE = new ConfigValue<>("GUI.title", String.class, "&f&l我的前缀 &8| 列表");
|
||||
|
||||
}
|
||||
|
||||
public static class Messages {
|
||||
|
||||
public static ConfigValueList<String> SELECTED = new ConfigValueList<>("messages.selected", String.class);
|
||||
public static ConfigValueList<String> EXPIRED = new ConfigValueList<>("messages.expired", String.class);
|
||||
|
||||
public static ConfigValueList<String> RELOAD = new ConfigValueList<>("messages.reload", String.class);
|
||||
public static ConfigValueList<String> HELP = new ConfigValueList<>("messages.help", String.class);
|
||||
|
||||
public static ConfigValueList<String> LIST_TITLE = new ConfigValueList<>("messages.list-title", String.class);
|
||||
public static ConfigValueList<String> LIST_VALUE = new ConfigValueList<>("messages.list-value", String.class);
|
||||
}
|
||||
|
||||
public static class Sounds {
|
||||
|
||||
+6
@@ -1,6 +1,7 @@
|
||||
package cc.carm.plugin.userprefix.listener.processor;
|
||||
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.ui.PrefixSelectGUI;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -11,6 +12,11 @@ public class UserNodeUpdateProcessor {
|
||||
Player player = Bukkit.getPlayer(event.getUser().getUniqueId());
|
||||
if (player == null) return;
|
||||
UserManager.checkPrefix(player, true);
|
||||
if (PrefixSelectGUI.openingUsers.contains(player)) {
|
||||
// 玩家权限更新,关闭其GUI,以令其重新打开刷新自己的前缀。
|
||||
player.closeInventory();
|
||||
PrefixSelectGUI.removeOpening(player);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PrefixManager {
|
||||
ConfigurationSection configuredPrefixSection = prefixesSection.getConfigurationSection(prefixIdentifier);
|
||||
if (configuredPrefixSection == null) continue;
|
||||
try {
|
||||
String name = configuredPrefixSection.getString("name", "前缀名配置错误");
|
||||
String name = configuredPrefixSection.getString("name", "ERROR");
|
||||
String content = configuredPrefixSection.getString("content", "&r");
|
||||
String permission = configuredPrefixSection.getString("permission");
|
||||
int weight = configuredPrefixSection.getInt("weight", 1);
|
||||
@@ -58,7 +58,7 @@ public class PrefixManager {
|
||||
|
||||
dataPrefixes.put(prefixIdentifier, new ConfiguredPrefix(prefixIdentifier, name, content, weight, permission, itemHasPermission, itemNoPermission, itemUsing));
|
||||
} catch (Exception exception) {
|
||||
Main.log("在加载前缀 " + prefixIdentifier + " 时出错,请检查配置!");
|
||||
Main.log("Error occurred when loading prefix #" + prefixIdentifier + " !");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ public class UserManager {
|
||||
* @return 若前缀标识不存在,则返回false;若前缀为默认前缀,或该前缀无权限,或玩家有该前缀的权限,则返回true。
|
||||
*/
|
||||
public static boolean isPrefixUsable(Player player, ConfiguredPrefix configuredPrefix) {
|
||||
return configuredPrefix.getPermission() == null //为null的话说明无需权限了
|
||||
return configuredPrefix.isPublic()
|
||||
|| ServiceManager.hasPermission(ServiceManager.getUser(player), configuredPrefix.getPermission());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package cc.carm.plugin.userprefix.model;
|
||||
|
||||
import cc.carm.plugin.userprefix.util.ColorParser;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ConfiguredPrefix {
|
||||
|
||||
@@ -18,7 +20,13 @@ public class ConfiguredPrefix {
|
||||
ItemStack itemNoPermission;
|
||||
ItemStack itemWhenUsing;
|
||||
|
||||
public ConfiguredPrefix(String identifier, String name, String content, int weight, String permission, ItemStack itemHasPermission, ItemStack itemNoPermission, ItemStack itemWhenUsing) {
|
||||
public ConfiguredPrefix(@NotNull String identifier,
|
||||
@NotNull String name,
|
||||
@NotNull String content,
|
||||
int weight, @Nullable String permission,
|
||||
@NotNull ItemStack itemHasPermission,
|
||||
@Nullable ItemStack itemNoPermission,
|
||||
@Nullable ItemStack itemWhenUsing) {
|
||||
this.identifier = identifier;
|
||||
this.name = name;
|
||||
this.content = content;
|
||||
@@ -29,14 +37,17 @@ public class ConfiguredPrefix {
|
||||
this.itemWhenUsing = itemWhenUsing;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getContent() {
|
||||
return ColorParser.parse(content);
|
||||
}
|
||||
@@ -45,22 +56,30 @@ public class ConfiguredPrefix {
|
||||
return weight;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getItemHasPermission() {
|
||||
return itemHasPermission;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getItemNoPermission() {
|
||||
return itemNoPermission;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getItemWhenUsing() {
|
||||
return itemWhenUsing;
|
||||
}
|
||||
|
||||
public boolean isPublic() {
|
||||
return getPermission() == null;
|
||||
}
|
||||
|
||||
public boolean isVisibleNoPermission() {
|
||||
return this.itemNoPermission != null;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package cc.carm.plugin.userprefix.ui;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import cc.carm.plugin.userprefix.util.gui.GUIType;
|
||||
import cc.carm.plugin.userprefix.manager.PrefixManager;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.model.ConfiguredPrefix;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import cc.carm.plugin.userprefix.util.gui.AutoPagedGUI;
|
||||
import cc.carm.plugin.userprefix.util.gui.GUIItem;
|
||||
import cc.carm.plugin.userprefix.util.gui.GUIType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
@@ -22,7 +22,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
Player player;
|
||||
|
||||
public PrefixSelectGUI(Player player) {
|
||||
super(GUIType.SIXBYNINE, "&f&l我的前缀 &8| 列表", 10, 43);
|
||||
super(GUIType.SIXBYNINE, PrefixConfig.GUI.TITLE.get(), 10, 43);
|
||||
this.player = player;
|
||||
|
||||
setPreviousPageSlot(18);
|
||||
@@ -38,7 +38,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
public void loadItems() {
|
||||
List<ConfiguredPrefix> prefixList = new ArrayList<>();
|
||||
prefixList.add(PrefixManager.getDefaultPrefix());
|
||||
prefixList.addAll(PrefixManager.getVisiblePrefix());
|
||||
prefixList.addAll(PrefixManager.getVisiblePrefix()); //只需要读取看得见的
|
||||
|
||||
ConfiguredPrefix usingPrefix = UserManager.getPrefix(getPlayer());
|
||||
|
||||
@@ -49,7 +49,8 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
addItem(new GUIItem(prefix.getItemHasPermission()) {
|
||||
@Override
|
||||
public void onClick(ClickType type) {
|
||||
if (UserManager.isPrefixUsable(player, prefix)) { //再次检查,防止打开GUI后、选择前的时间段内权限消失
|
||||
//再次检查,防止打开GUI后、选择前的时间段内权限消失
|
||||
if (UserManager.isPrefixUsable(player, prefix)) {
|
||||
player.closeInventory();
|
||||
UserManager.setPrefix(player, prefix, true);
|
||||
|
||||
@@ -71,7 +72,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
openingUsers.remove(player);
|
||||
removeOpening(player);
|
||||
}
|
||||
|
||||
public static void removeOpening(Player player) {
|
||||
@@ -82,6 +83,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
for (Player player : new HashSet<>(openingUsers)) {
|
||||
player.closeInventory();
|
||||
}
|
||||
openingUsers.clear();
|
||||
}
|
||||
|
||||
public static void open(Player player) {
|
||||
|
||||
@@ -28,6 +28,7 @@ public class MessageUtil {
|
||||
}
|
||||
|
||||
public static void sendWithPlaceholders(CommandSender sender, List<String> messages) {
|
||||
if (messages == null || messages.isEmpty()) return;
|
||||
if (hasPlaceholderAPI() && sender instanceof Player) {
|
||||
send(sender, PlaceholderAPI.setPlaceholders((Player) sender, messages));
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
version: ${project.version} # DO NOT EDIT IT
|
||||
|
||||
debug: false #DEBUG OUT PUT
|
||||
|
||||
GUI:
|
||||
title: "&f&lMy Prefixes List" # Title of the GUI
|
||||
|
||||
functions:
|
||||
# Whether to add a prefix to the top of the head,
|
||||
# this method uses the scoreboard above the head,
|
||||
# please turn it off if there is a conflict.
|
||||
OnNamePrefix: true
|
||||
# Automatic prefix select.
|
||||
# When the player does not choose a prefix by himself,
|
||||
# the prefix with the highest weight will be used automatically
|
||||
autoUsePrefix: true
|
||||
|
||||
messages:
|
||||
selected:
|
||||
- "&7You have selected the &f%(name) &7as current prefix."
|
||||
expired:
|
||||
- "&7Your prefix &f%(oldName) &7has expired,"
|
||||
- "&7Now the prefix is changed to &f%(newName) &7."
|
||||
reload:
|
||||
- "&a&lReload completed!&7costs &f%(time)ms&7."
|
||||
help:
|
||||
- "&3&lUserPrefixAdmin &fHelp"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7Show configured prefixes."
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7Reload configuration."
|
||||
list-title:
|
||||
- "&3&lUserPrefixAdmin &fList"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7Name &r%(name) &7Perm &r%(permission)"
|
||||
- "&8- &7Example&r %(content) %(sender_name)"
|
||||
|
||||
|
||||
Sounds:
|
||||
# Format is [SOUND_NAME:Volume:Pitch] or [SOUND_NAME:Volume] or [SOUND_NAME]
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
guiClick: "UI_BUTTON_CLICK"
|
||||
prefixChange: "ENTITY_VILLAGER_YES"
|
||||
prefixExpired: "ENTITY_VILLAGER_NO"
|
||||
|
||||
# The default prefix's weight is 0.
|
||||
defaultPrefix:
|
||||
name: "Default prefix"
|
||||
content: "&b"
|
||||
itemNotUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix §f(Click to select)"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
|
||||
prefixes:
|
||||
VIP:
|
||||
name: "&b&lPro&b" # [Necessary] Name (Using in messages)
|
||||
content: "§b§lPro §b" # [Necessary] What to display before the name
|
||||
# [Necessary] Weight, used for sorting in the GUI
|
||||
# (the larger is displayed at the back) and the automatic prefix display
|
||||
weight: 1
|
||||
# [Necessary] If there is no permission for detection, everyone can use it,
|
||||
# which means there is no need to configure "itemNoPermission"
|
||||
# (because it is impossible to display items without permission at all)
|
||||
permission: "yc.pro"
|
||||
itemHasPermission:
|
||||
# [Necessary] This Item will be displayed when player has permission
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
# [Not Necessary] This Item will be displayed when the prefix is selected.
|
||||
# If there is no such configuration, it will automatically display "itemHasPermission".
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #Add an enchantment so it looks like it’s selected
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
itemNoPermission:
|
||||
# [Not Necessary] If player doesn't have the permission,this item will be displayed.
|
||||
# If this item is not configured, it will not be displayed in the GUI when the player does not have permission to use it.
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP §c(Buy it!)"
|
||||
lore:
|
||||
- ""
|
||||
- "§e✯ Buy the VIP to use it!"
|
||||
@@ -6,12 +6,29 @@ functions:
|
||||
OnNamePrefix: true # 是否给头顶上添加前缀,该方法用到了头顶的那个计分板,如有冲突请关掉哦~
|
||||
autoUsePrefix: true # 自动前缀显示 当玩家没有自己选择一个前缀的时候,会自动使用所拥有的的前缀中权重最高的那一个
|
||||
|
||||
GUI:
|
||||
title: "&f&l我的前缀 &8| 列表"
|
||||
|
||||
messages:
|
||||
selected:
|
||||
- "&7您选择了 &f%(name) &7作为当前显示的前缀。"
|
||||
expired:
|
||||
- "&7您先前使用的前缀 &f%(oldName) &7已到期。"
|
||||
- "&7现在已为您重新调整为 &f%(newName) &7。"
|
||||
reload:
|
||||
- "&a&l重载完成!&7共耗时 &f%(time)ms&7。"
|
||||
help:
|
||||
- "&3&l用户前缀系统 &f帮助"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7查看当前前缀列表。"
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7重载前缀配置。"
|
||||
list-title:
|
||||
- "&3&l用户前缀系统 &f前缀列表"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7显示名 &r%(name) &7权限 &r%(permission)"
|
||||
- "&8- &7内容示例&r %(content) %(sender_name)"
|
||||
|
||||
Sounds: #相关的声音,注释掉则不播放声音 格式为 【声音名:音量:音调】 或 【声音名:音量】 或 【声音名】
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
|
||||
+1
-1
@@ -172,7 +172,7 @@ prefixes:
|
||||
|
||||
[hr]
|
||||
[size=3][b]最新版本 1.2.3[/b][/size][attach]1905406[/attach]
|
||||
[size=3]更新内容: [/size][quote][size=3]1. 支持支持Hex颜色!(1.16以上版本) 格式 [u]&(#颜色代码)[/u] 。[/size]
|
||||
[size=3]更新内容: [/size][quote][size=3]1. 支持Hex颜色!(1.16以上版本) 格式 [u]&(#颜色代码)[/u] 。[/size]
|
||||
[size=3][backcolor=initial]- 如 [/backcolor][/size][backcolor=initial][size=3]LightSlateBlue &(#8470FF) 、 DarkSlateBlue &(#483D8B)[/size][/backcolor]
|
||||
[backcolor=initial][size=3]2. 修复未安装PlaceholderAPI的情况下可能导致的部分报错。[/size][/backcolor]
|
||||
[backcolor=initial][size=3]
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
[URL='https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/banner.png'][IMG]https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/banner.png[/IMG][/URL]
|
||||
|
||||
[SIZE=6][B]UserPrefix Plugin[/B][/SIZE]
|
||||
[URL='https://www.codefactor.io/repository/github/carmjos/userprefix'][IMG]https://camo.githubusercontent.com/6040f5c07ea04f9cb666459d6b6f08d19971fc29a26183cdc6595297b287234b/68747470733a2f2f7777772e636f6465666163746f722e696f2f7265706f7369746f72792f6769746875622f6361726d6a6f732f757365727072656669782f62616467653f733d62373666656331663634373236623566313939383961616365366164623566383566646162383430[/IMG][/URL] [URL='https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml'][IMG]https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml/badge.svg?branch=master[/IMG][/URL] [URL='https://camo.githubusercontent.com/75543844e4f92947d837bd45ab75d5a268e63ff485cd7b354cf69f52e60be28d/68747470733a2f2f76697369746f722d62616467652e676c697463682e6d652f62616467653f706167655f69643d757365727072656669782e726561646d65'][IMG]https://camo.githubusercontent.com/75543844e4f92947d837bd45ab75d5a268e63ff485cd7b354cf69f52e60be28d/68747470733a2f2f76697369746f722d62616467652e676c697463682e6d652f62616467653f706167655f69643d757365727072656669782e726561646d65[/IMG][/URL]
|
||||
|
||||
Lightweight, efficient, and real-time user prefix system.
|
||||
|
||||
This plugin is implemented based on Spigot ,Theoretically support ALL MineCraft Versions.
|
||||
|
||||
The development of this plugin is based on Chinese, which purpose is to help Chinese developers learn Bukkit plugin development.
|
||||
|
||||
[QUOTE]
|
||||
本插件已在 [URL='https://www.mcbbs.net/forum.php?mod=viewthread&tid=1261503']MCBBS[/URL] 上发布,欢迎中文用户来这里下载。
|
||||
[/QUOTE]
|
||||
|
||||
[SIZE=5][B]Examples[/B][/SIZE]
|
||||
[URL='https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/using-example.png'][IMG]https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/using-example.png[/IMG][/URL]
|
||||
|
||||
[SIZE=5][B]Dependencies[/B][/SIZE]
|
||||
[LIST]
|
||||
[*][B][Necessary][/B] Plugin developed based on [URL='https://hub.spigotmc.org/stash/projects/SPIGOT']Spigot-API[/URL] and [URL='http://bukkit.org/']BukkitAPI[/URL].
|
||||
[*][B][Necessary][/B] Plugin data storage base on [URL='https://www.spigotmc.org/resources/luckperms.28140/']LuckPerms[/URL].
|
||||
[*][Recommend] Placeholders based on [URL='https://www.spigotmc.org/resources/6245/']PlaceholderAPI[/URL] .
|
||||
[/LIST]
|
||||
For development dependencies, please see [URL='https://github.com/CarmJos/UserPrefix/network/dependencies']Dependencies[/URL] .
|
||||
|
||||
[SIZE=5][B]Features[/B][/SIZE]
|
||||
[LIST]
|
||||
[*]Theoretically support ALL MineCraft Versions.
|
||||
[*]Reloading the configuration will automatically refresh the prefix of all players.
|
||||
[*]Real-time judgment and feedback to the player when permissions are changed.
|
||||
[*]Configurable sounds and messages.
|
||||
[*]The prefix icon can be configured as "Selected", "Has Permission" and “No Permission”.
|
||||
[LIST]
|
||||
[*]Item configuration is natively configured through ItemStack, which supports all MC settings!
|
||||
[/LIST]
|
||||
[*]TabList is automatically sorted according to the weight of the prefix (if there is a conflict, it can be turned off)
|
||||
[*]The prefix display on the player name (can be turned off if there is a conflict)
|
||||
[*]GUI with automatic sorting and page turning!
|
||||
[*]Support PlaceholderAPI variables!
|
||||
[*]Support Hex color! (Version 1.16 and above) [U]&(#Color)[/U]
|
||||
[LIST]
|
||||
[*]Example: LightSlateBlue [U]&(#8470FF)[/U] 、 DarkSlateBlue [U]&(#483D8B)[/U]
|
||||
[/LIST]
|
||||
[/LIST]
|
||||
[SIZE=5][B]Notice[/B][/SIZE]
|
||||
[SIZE=4][B]1. Version support issues[/B][/SIZE]
|
||||
This plugin theoretically supports all versions.
|
||||
|
||||
If the icon does not load, the sound cannot be played, etc., please check whether the type of the item and sound in the configuration file exists in the current version.
|
||||
|
||||
Take the SOUND as an example. The sound that the villager said "OK" is "[U]VILLAGER_YES[/U]" in the lower version, but it becomes "[U]ENTITY_VILLAGER_YES[/U]" in the higher version.
|
||||
|
||||
[SIZE=4][B]2. Scoreboard exception problem[/B][/SIZE]
|
||||
The display of the prefix on the head and the sorting of the TabList both use the scoreboard API.
|
||||
|
||||
Please turn of the [U]functions.OnNamePrefix[/U] in the configuration if there is a conflict.
|
||||
|
||||
[SIZE=4][B]3. Item icon configuration problem[/B][/SIZE]
|
||||
Items are read through the ItemStack serialization method provided by Bukkit. For related configuration methods, please refer to [URL='https://www.spigotmc.org/wiki/itemstack-serialization/']ItemStack Serialization[/URL].
|
||||
|
||||
[SIZE=5][B]Commands[/B][/SIZE]
|
||||
This plugin's Commands are based on Chinese! May support multi-language in the future.
|
||||
|
||||
[code]
|
||||
/UserPrefix or /prefix #Open prefix GUI
|
||||
/UserPrefixAdmin # View Admin Command Help
|
||||
/UserPrefixAdmin reload # Reload Config
|
||||
/UserPrefixAdmin list # List all configured prefixes.
|
||||
[/code]
|
||||
|
||||
[SIZE=5][B]Placeholders (PlaceholderAPI)[/B][/SIZE]
|
||||
After installed the [URL='https://github.com/PlaceholderAPI/PlaceholderAPI']PlaceholderAPI[/URL] , you can type /papi info UserPrefix to see all the placeholders.
|
||||
|
||||
[code]
|
||||
# %UserPrefix_prefix%
|
||||
- Get the content of the current prefix
|
||||
# %UserPrefix_weight%
|
||||
- Get the weight of the current prefix.
|
||||
# %UserPrefix_identifier%
|
||||
- Get the identifier of the current prefix.
|
||||
# %UserPrefix_name%
|
||||
- Get the name of the current prefix.
|
||||
# %UserPrefix_has_<Identifier>%
|
||||
- Determine whether the player has a certain prefix(true/false)
|
||||
[/code]
|
||||
|
||||
[B][SIZE=5][URL='https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/config-en.yml']Configuration File[/URL] Example[/SIZE][/B]
|
||||
Notice: The default configuration is based on Chinese. You can find the English Version [URL='https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/config-en.yml']here[/URL].
|
||||
|
||||
[code=YAML]
|
||||
version: 1.0.0-SNAPSHOT # DO NOT EDIT IT
|
||||
|
||||
debug: false #DEBUG OUT PUT
|
||||
|
||||
GUI:
|
||||
title: "&f&lMy Prefixes List" # Title of the GUI
|
||||
functions:
|
||||
# Whether to add a prefix to the top of the head,
|
||||
# this method uses the scoreboard above the head,
|
||||
# please turn it off if there is a conflict.
|
||||
OnNamePrefix: true
|
||||
# Automatic prefix select.
|
||||
# When the player does not choose a prefix by himself,
|
||||
# the prefix with the highest weight will be used automatically
|
||||
autoUsePrefix: true
|
||||
|
||||
messages:
|
||||
selected:
|
||||
- "&7You have selected the &f%(name) &7as current prefix."
|
||||
expired:
|
||||
- "&7Your prefix &f%(oldName) &7has expired,"
|
||||
- "&7Now the prefix is changed to &f%(newName) &7."
|
||||
reload:
|
||||
- "&a&lReload completed!&7costs &f%(time)ms&7."
|
||||
help:
|
||||
- "&3&lUserPrefixAdmin &fHelp"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7Show configured prefixes."
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7Reload configuration."
|
||||
list-title:
|
||||
- "&3&lUserPrefixAdmin &fList"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7Name &r%(name) &7Perm &r%(permission)"
|
||||
- "&8- &7Example&r %(content) %(sender_name)"
|
||||
|
||||
Sounds:
|
||||
# Format is [SOUND_NAME:Volume:Pitch] or [SOUND_NAME:Volume] or [SOUND_NAME]
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
guiClick: "UI_BUTTON_CLICK"
|
||||
prefixChange: "ENTITY_VILLAGER_YES"
|
||||
prefixExpired: "ENTITY_VILLAGER_NO"
|
||||
|
||||
# The default prefix's weight is 0.
|
||||
defaultPrefix:
|
||||
name: "Default prefix"
|
||||
content: "&b"
|
||||
itemNotUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix §f(Click to select)"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
|
||||
prefixes:
|
||||
VIP:
|
||||
name: "&b&lPro&b" # [Necessary] Name (Using in messages)
|
||||
content: "§b§lPro §b" # [Necessary] What to display before the name
|
||||
# [Necessary] Weight, used for sorting in the GUI
|
||||
# (the larger is displayed at the back) and the automatic prefix display
|
||||
weight: 1
|
||||
# [Necessary] If there is no permission for detection, everyone can use it,
|
||||
# which means there is no need to configure "itemNoPermission"
|
||||
# (because it is impossible to display items without permission at all)
|
||||
permission: "yc.pro"
|
||||
itemHasPermission:
|
||||
# [Necessary] This Item will be displayed when player has permission
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
# [Not Necessary] This Item will be displayed when the prefix is selected.
|
||||
# If there is no such configuration, it will automatically display "itemHasPermission".
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #Add an enchantment so it looks like it’s selected
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
itemNoPermission:
|
||||
# [Not Necessary] If player doesn't have the permission,this item will be displayed.
|
||||
# If this item is not configured, it will not be displayed in the GUI when the player does not have permission to use it.
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP §c(Buy it!)"
|
||||
lore:
|
||||
- ""
|
||||
- "§e✯ Buy the VIP to use it!"
|
||||
[/code]
|
||||
|
||||
[SIZE=5][B]Support and Donation[/B][/SIZE]
|
||||
This project is support by the [URL='https://www.ycraft.cn/']YourCraft(你的世界)[/URL] . [URL='https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/team-logo.png'][IMG]https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/team-logo.png[/IMG][/URL]
|
||||
|
||||
[SIZE=5][B]Open source agreement[/B][/SIZE]
|
||||
The source code of this project uses [URL='https://opensource.org/licenses/GPL-3.0']GNU General Public License v3.0[/URL] License.
|
||||
Reference in New Issue
Block a user