Compare commits

...

16 Commits
v1.4 ... master

Author SHA1 Message Date
710d2679a6 更新版本
All checks were successful
Java CI-CD with Maven / build (push) Successful in 6m48s
2024-08-24 19:24:26 +08:00
a6a710f671 Merge remote-tracking branch 'origin/master' 2024-08-24 19:18:19 +08:00
dfb821ca23 新增获取图片时的报错提示
All checks were successful
Java CI-CD with Maven / build (push) Successful in 6m54s
2024-08-24 19:17:47 +08:00
9c462690dc 更新 README.md 2024-08-20 20:48:17 +08:00
7744442575 修复启用经济后加载时报错的问题
All checks were successful
Java CI-CD with Maven / build (push) Successful in 22m22s
2024-08-13 15:50:59 +08:00
78bb6c9447 新增图床地址白名单
All checks were successful
Java CI-CD with Maven / build (push) Successful in 12m23s
2024-08-05 16:43:08 +08:00
5896a30928 更新文档 不支持spigot! 2024-07-30 17:34:38 +08:00
67b39b6ae2 修复spigot无法生成地图画的问题
All checks were successful
Java CI-CD with Maven / build (push) Successful in 6m51s
2024-07-30 16:11:02 +08:00
b8a3dbddd5 修复spigot无法生成地图画的问题 2024-07-30 16:10:19 +08:00
71bf3ed675 修复spigot无法生成地图画的问题 2024-07-30 16:08:40 +08:00
ecabf4a8bc 更新文档 2024-07-30 15:35:38 +08:00
f89765f024 更新文档 2024-07-30 15:29:21 +08:00
23e723c236 新增缩略图功能
新增原图保存与玩家操作记录(方便查图)
2024-07-30 15:14:43 +08:00
20af309966 完善文档 2024-07-28 18:06:32 +08:00
ddc47c4a8f 新增权限节点 colorfulmap.tomap
All checks were successful
Java CI-CD with Maven / build (push) Successful in 11m11s
2024-07-25 16:27:46 +08:00
d7d989eb6b 更新了下载提示信息 2024-05-01 10:07:27 +08:00
28 changed files with 852 additions and 263 deletions

View File

@ -37,7 +37,7 @@ jobs:
- name: "Release" - name: "Release"
uses: https://ssl.lunadeer.cn:14446/zhangyuheng/release-action@main uses: https://ssl.lunadeer.cn:14446/zhangyuheng/release-action@main
with: with:
note: "提示:带 original- 前缀的文件无法用于运行,请下载不带此前缀的版本。" note: "带 `original-` 前缀的文件无法用于运行,请下载不带此前缀的版本。"
files: |- files: |-
staging/*.jar staging/*.jar
api_key: '${{secrets.RELEASE_TOKEN}}' api_key: '${{secrets.RELEASE_TOKEN}}'

View File

@ -1,24 +1,31 @@
<div align="center">
# ColorfulMap # ColorfulMap
<img src="https://ssl.lunadeer.cn:14437/i/2024/02/21/65d5e0d10b7d5.png" alt="" width="70%">
### [开源地址](https://ssl.lunadeer.cn:14446/zhangyuheng/ColorfulMap) | [文档地址](https://ssl.lunadeer.cn:14448/doc/26/) ### [开源地址](https://ssl.lunadeer.cn:14446/zhangyuheng/ColorfulMap) | [文档地址](https://ssl.lunadeer.cn:14448/doc/26/)
### [下载页面](https://ssl.lunadeer.cn:14446/zhangyuheng/ColorfulMap/releases) ### [下载页面](https://ssl.lunadeer.cn:14446/zhangyuheng/ColorfulMap/releases)
### [统计页面](https://bstats.org/plugin/bukkit/ColorfulMap/21443) | [Hangar](https://hangar.papermc.io/zhangyuheng/ColorfulMap) ### [统计页面](https://bstats.org/plugin/bukkit/ColorfulMap/21443) | [Hangar](https://hangar.papermc.io/zhangyuheng/ColorfulMap)
## 简介 </div>
![](https://ssl.lunadeer.cn:14437/i/2024/02/21/65d5e0d10b7d5.png) ## 简介
用于将图片转换为地图画,悬挂在展示框上增添装饰。 用于将图片转换为地图画,悬挂在展示框上增添装饰。
## 说明 ## 说明
本插件大约相当于 [ImageFrame](https://github.com/LOOHP/ImageFrame) 的简版以及 [ImageMaps](https://github.com/SydMontague/ImageMaps) 的高版本重制版。前者功能丰富,不过可能由于项目体量较大,对于新版本的兼容较慢,后者在 1.18 开始就停止了更新,切不支持 Folia 核心。 本插件大约相当于 [ImageFrame](https://github.com/LOOHP/ImageFrame)的简版以及 [ImageMaps](https://github.com/SydMontague/ImageMaps) 的高版本重制版。前者功能丰富,不过可能由于项目体量较大,对于新版本的兼容较慢,后者在1.18 开始就停止了更新,且不支持 Folia 核心。
## 功能介绍 ## 功能介绍
- 将图片转换为地图画; - 将图片转换为地图画;
- 图片缩放; - 图片缩放;
- 自动放置; - 自动放置;
- 支持消耗金钱生成地图画(需要 Vault 前置);
## 支持版本 ## 支持版本
@ -33,54 +40,65 @@
## 玩家使用方法 ## 玩家使用方法
1. 首先需要将你想要转换的图片上传到 [图床](https://ssl.lunadeer.cn:14437/) ,便于本插件从网络读取图片内容。上传完成后会得到一个图片的网络地址,复制此地址。 1. 首先需要将你想要转换的图片上传到 [图床](https://ssl.lunadeer.cn:14437/) ,便于本插件从网络读取图片内容。上传完成后会得到一个图片的网络地址,复制此地址。
2. 在游戏中输入指令:`/tomap <图片地址>` 即可获得一张地图。地图的左上角会显示这张地图画所需的展示框阵列的尺寸,如下图所示 5x4 代表你需要在墙上准备一组长5格宽4格的展示框阵列才能摆的下这张地图画。 2. 在游戏中输入指令:`/tomap <图片地址>` 即可获得一张地图
![](https://ssl.lunadeer.cn:14437/i/2024/02/21/65d5ef7e8d676.png) ![](https://ssl.lunadeer.cn:14437/i/2024/07/30/66a89345ca899.png)
地图的lore中记录了此地图画的大小下图中的 8x10 表明此地图画需要长8格、高10格的展示框阵列才能放置。
![](https://ssl.lunadeer.cn:14437/i/2024/07/30/66a893ba56d7d.png)
3. 对着展示框阵列的**左下角展示框**摆放此地图,则会自动在墙上的剩余展示框内放置对应的地图。 3. 对着展示框阵列的**左下角展示框**摆放此地图,则会自动在墙上的剩余展示框内放置对应的地图。
4. 如果图片太大或太小可以尝试在指令后加入缩放倍率,例如 `/tomap <图片地址> 0.5`表示将以原图的50%大小渲染。如果你希望将图片填满所有地图边缘处没有留白,那么你需要保证你的图片的长宽分辨率均为**128的倍数**因为在MC中一张地图的分辨率为128x128。 4. 如果图片太大或太小可以尝试在指令后加入缩放倍率,例如 `/tomap <图片地址> 0.5` 表示将以原图的50%大小渲染。如果你希望将图片填满所有地图边缘处没有留白,那么你需要保证你的图片的长宽分辨率均为**128的倍数**因为在MC中一张地图的分辨率为128x128。
## 管理员指南 ## 管理员指南
## 指令 ### 指令 & 权限节点
> 以下指令中尖括号 `<>` 表示必填,方括号 `[]` 表示选填。 > 以下指令中尖括号 `<>` 表示必填,方括号 `[]` 表示选填。
### 玩家指令 | 功能 | 指令 | 权限节点 | 默认 |
|-------|------------------------|--------------------|------|
| 生成地图画 | `/tomap <图片地址> [缩放倍率]` | colorfulmap.tomap | true |
| 重载配置 | `/reloadColorfulMap` | colorfulmap.reload | op |
### 如何查图
| 功能 | 指令 | 2.0版本开始地图画会保存一份玩家获取图片的原图,路径为 `plugins/ColorfulMap/maps/{图片uuid}/raw.png` ,方便服主快速查阅图片内容。
|-------|------------------------|
| 生成地图画 | `/tomap <图片地址> [缩放倍率]` |
当玩家放置地图后还会同时保存一份元数据文件,`plugins/ColorfulMap/maps/{图片uuid}/meta.txt`,此文件记录了放置地图的玩家、放置时间、地图画的位置等信息。
### 配置文件参考
### 管理员指令
## 配置文件参考
```yaml ```yaml
# 地图画阵列的最大尺寸 宽
MaxFrameX: 32 MaxFrameX: 32
# 地图画阵列的最大尺寸 高
MaxFrameY: 18 MaxFrameY: 18
# 是否启用经济系统 消耗玩家金钱生成地图画
Economy:
Enable: false
CostPerMap: 100.0 # 每张地图画的单价 - 3*3的地图画需要9张地图画 也就是 9*100 = 900
# 图床地址白名单,不在白名单中的图床将无法使用,留空表示不启用地址白名单
AddressWhiteList: []
CheckUpdate: true CheckUpdate: true
Debug: false Debug: false
``` ```
## TODO
## 建议与反馈 ## 建议与反馈
Mail: [zhangyuheng@lunadeer.cn](mailto:zhangyuheng@lunadeer.cn) Mail: [zhangyuheng@lunadeer.cn](mailto:zhangyuheng@lunadeer.cn)
QQ群309428300 QQ群309428300
## 统计 ## 统计
![bstats](https://bstats.org/signatures/bukkit/ColorfulMap.svg) ![bstats](https://bstats.org/signatures/bukkit/ColorfulMap.svg)

27
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>cn.lunadeer</groupId> <groupId>cn.lunadeer</groupId>
<artifactId>ColorfulMap</artifactId> <artifactId>ColorfulMap</artifactId>
<version>1.4</version> <version>2.5</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>ColorfulMap</name> <name>ColorfulMap</name>
@ -62,6 +62,14 @@
<id>papermc</id> <id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url> <url>https://repo.papermc.io/repository/maven-public/</url>
</repository> </repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
@ -71,5 +79,22 @@
<version>1.20.1-R0.1-SNAPSHOT</version> <version>1.20.1-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bukkit</artifactId>
<version>4.3.3</version>
</dependency>
<dependency>
<groupId>com.github.MilkBowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultUnlockedAPI</artifactId>
<version>2.2</version><!-- Validate this is the most recent version from the CI -->
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,8 +1,8 @@
package cn.lunadeer.colorfulmap; package cn.lunadeer.colorfulmap;
import cn.lunadeer.colorfulmap.commands.Reload;
import cn.lunadeer.colorfulmap.commands.ToMap; import cn.lunadeer.colorfulmap.commands.ToMap;
import cn.lunadeer.colorfulmap.utils.GiteaReleaseCheck; import cn.lunadeer.colorfulmap.utils.*;
import cn.lunadeer.colorfulmap.utils.XLogger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
@ -14,14 +14,20 @@ public final class ColorfulMap extends JavaPlugin {
public void onEnable() { public void onEnable() {
// Plugin startup logic // Plugin startup logic
instance = this; instance = this;
new XLogger(this);
config = new Configuration(this); config = new Configuration(this);
XLogger.setDebug(config.isDebug());
new Notification(this);
new Scheduler(this);
Objects.requireNonNull(Bukkit.getPluginCommand("tomap")).setExecutor(new ToMap()); Objects.requireNonNull(Bukkit.getPluginCommand("tomap")).setExecutor(new ToMap());
Objects.requireNonNull(Bukkit.getPluginCommand("reloadColorfulMap")).setExecutor(new Reload());
Bukkit.getPluginManager().registerEvents(new Events(), this); Bukkit.getPluginManager().registerEvents(new Events(), this);
new MapManager().init(); new MapManager().init();
Metrics metrics = new Metrics(this, 21443); bStatsMetrics metrics = new bStatsMetrics(this, 21443);
if (config.isCheckUpdate()) { if (config.isCheckUpdate()) {
giteaReleaseCheck = new GiteaReleaseCheck(this, giteaReleaseCheck = new GiteaReleaseCheck(this,
"https://ssl.lunadeer.cn:14446", "https://ssl.lunadeer.cn:14446",
@ -30,7 +36,7 @@ public final class ColorfulMap extends JavaPlugin {
} }
XLogger.info("ColorfulMap 已加载"); XLogger.info("ColorfulMap 已加载");
XLogger.info("版本: " + getPluginMeta().getVersion()); XLogger.info("版本: " + this.getDescription().getVersion());
// https://patorjk.com/software/taag/#p=display&f=Big&t=ColorfulMap // https://patorjk.com/software/taag/#p=display&f=Big&t=ColorfulMap
XLogger.info(" _____ _ __ _ __ __"); XLogger.info(" _____ _ __ _ __ __");
XLogger.info(" / ____| | | / _| | | \\/ |"); XLogger.info(" / ____| | | / _| | | \\/ |");

View File

@ -1,7 +1,11 @@
package cn.lunadeer.colorfulmap; package cn.lunadeer.colorfulmap;
import cn.lunadeer.colorfulmap.utils.VaultConnect.VaultConnect;
import cn.lunadeer.colorfulmap.utils.XLogger;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import java.util.List;
public class Configuration { public class Configuration {
public Configuration(ColorfulMap plugin) { public Configuration(ColorfulMap plugin) {
@ -18,6 +22,25 @@ public class Configuration {
_max_frame_x = _file.getInt("MaxFrameX", 32); _max_frame_x = _file.getInt("MaxFrameX", 32);
_max_frame_y = _file.getInt("MaxFrameY", 18); _max_frame_y = _file.getInt("MaxFrameY", 18);
_check_update = _file.getBoolean("CheckUpdate", true); _check_update = _file.getBoolean("CheckUpdate", true);
_economy_enable = _file.getBoolean("Economy.Enable", false);
_price = (float) _file.getDouble("Economy.CostPerMap", 100.0);
_address_white_list = _file.getStringList("AddressWhiteList");
if (_economy_enable) {
XLogger.info("已启用经济系统");
new VaultConnect(_plugin);
}
saveAll();
}
public void saveAll() {
_file.set("Debug", _debug);
_file.set("MaxFrameX", _max_frame_x);
_file.set("MaxFrameY", _max_frame_y);
_file.set("CheckUpdate", _check_update);
_file.set("Economy.Enable", _economy_enable);
_file.set("Economy.CostPerMap", _price);
_file.set("AddressWhiteList", _address_white_list);
_plugin.saveConfig();
} }
public Boolean isDebug() { public Boolean isDebug() {
@ -54,10 +77,49 @@ public class Configuration {
return _check_update; return _check_update;
} }
public void setCheckUpdate(Boolean check_update) {
_check_update = check_update;
_file.set("CheckUpdate", check_update);
_plugin.saveConfig();
}
public Boolean isEconomyEnable() {
return _economy_enable;
}
public void setEconomyEnable(Boolean economy_enable) {
_economy_enable = economy_enable;
_file.set("Economy.Enable", economy_enable);
_plugin.saveConfig();
}
public Float getPrice() {
return _price;
}
public void setPrice(Float price) {
_price = price;
_file.set("Economy.CostPerMap", price);
_plugin.saveConfig();
}
public List<String> getAddressWhiteList() {
return _address_white_list;
}
public void setAddressWhiteList(List<String> address_white_list) {
_address_white_list = address_white_list;
_file.set("AddressWhiteList", address_white_list);
_plugin.saveConfig();
}
private final ColorfulMap _plugin; private final ColorfulMap _plugin;
private FileConfiguration _file; private FileConfiguration _file;
private Boolean _debug; private Boolean _debug;
private Integer _max_frame_x; private Integer _max_frame_x;
private Integer _max_frame_y; private Integer _max_frame_y;
private Boolean _check_update; private Boolean _check_update;
private Boolean _economy_enable;
private Float _price;
private List<String > _address_white_list;
} }

View File

@ -2,6 +2,7 @@ package cn.lunadeer.colorfulmap;
import cn.lunadeer.colorfulmap.generator.ImageRenderer; import cn.lunadeer.colorfulmap.generator.ImageRenderer;
import cn.lunadeer.colorfulmap.utils.Notification; import cn.lunadeer.colorfulmap.utils.Notification;
import cn.lunadeer.colorfulmap.utils.VaultConnect.VaultConnect;
import cn.lunadeer.colorfulmap.utils.XLogger; import cn.lunadeer.colorfulmap.utils.XLogger;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextComponent;
@ -16,11 +17,15 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.time.LocalTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import static cn.lunadeer.colorfulmap.Apis.getItemFrameMatrix; import static cn.lunadeer.colorfulmap.Apis.getItemFrameMatrix;
import static cn.lunadeer.colorfulmap.StorageMaps.getImageTilePath;
import static cn.lunadeer.colorfulmap.StorageMaps.writeMeta;
public class Events implements Listener { public class Events implements Listener {
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
@ -47,13 +52,23 @@ public class Events implements Listener {
Player player = event.getPlayer(); Player player = event.getPlayer();
List<Component> lore = item.getItemMeta().lore(); List<Component> lore = item.getItemMeta().lore();
XLogger.debug("PlayerInteractEntityEvent"); XLogger.debug("PlayerInteractEntityEvent");
if (lore == null || lore.size() != 3) { if (lore == null || lore.size() != 1) {
return; return;
} }
XLogger.debug("putImageMapsOnItemFrame"); XLogger.debug("putImageMapsOnItemFrame");
UUID uuid = UUID.fromString(((TextComponent) lore.get(0)).content()); /*
int count_x = Integer.parseInt(((TextComponent) lore.get(1)).content()); MapMeta meta = (MapMeta) mapItem.getItemMeta();
int count_y = Integer.parseInt(((TextComponent) lore.get(2)).content()); List<Component> lore = new ArrayList<>();
String size_info = "size: " + x_count + "x" + y_count;
lore.add(Component.text(size_info).hoverEvent(Component.text(map_images_uuid.toString())));
meta.lore(lore);
mapItem.setItemMeta(meta);
*/
TextComponent textComponent = (TextComponent) lore.get(0);
UUID uuid = UUID.fromString(((TextComponent) Objects.requireNonNull(textComponent.hoverEvent()).value()).content());
String[] size = textComponent.content().split(": ")[1].split("x");
int count_x = Integer.parseInt(size[0]);
int count_y = Integer.parseInt(size[1]);
XLogger.debug("uuid: " + uuid); XLogger.debug("uuid: " + uuid);
XLogger.debug("count_x: " + count_x); XLogger.debug("count_x: " + count_x);
XLogger.debug("count_y: " + count_y); XLogger.debug("count_y: " + count_y);
@ -67,10 +82,25 @@ public class Events implements Listener {
return; return;
} }
if (ColorfulMap.config.isEconomyEnable()) {
float cost = ColorfulMap.config.getPrice() * count_x * count_y;
if (!VaultConnect.instance.economyAvailable()) {
Notification.error(player, "无法放置地图画: 无法连接到经济插件");
return;
}
if (VaultConnect.instance.getBalance(player) < cost) {
Notification.error(player, "无法放置地图画: 余额不足");
Notification.error(player, "此图片尺寸为 %d x %d 个展示框,单价 %f总价 %f你的余额为 %f",
count_x, count_y, ColorfulMap.config.getPrice(), cost, VaultConnect.instance.getBalance(player));
return;
}
VaultConnect.instance.withdrawPlayer(player, cost);
}
List<ItemStack> maps = new ArrayList<>(); List<ItemStack> maps = new ArrayList<>();
for (int y = 0; y < count_y; y++) { for (int y = 0; y < count_y; y++) {
for (int x = 0; x < count_x; x++) { for (int x = 0; x < count_x; x++) {
String path = "maps/" + uuid + "/" + x + "_" + y + ".png"; String path = getImageTilePath(uuid, x, y);
ItemStack map = ImageRenderer.getMapItemFromImageTile(player, path); ItemStack map = ImageRenderer.getMapItemFromImageTile(player, path);
if (map == null) { if (map == null) {
Notification.error(player, "无法加载地图,原始路径丢失:" + path); Notification.error(player, "无法加载地图,原始路径丢失:" + path);
@ -80,6 +110,15 @@ public class Events implements Listener {
} }
} }
// 记录操作信息
List<String> imageMeta = new ArrayList<>();
imageMeta.add("Player: " + player.getName() + "(" + player.getUniqueId() + ")");
imageMeta.add("Time: " + LocalTime.now());
imageMeta.add("Location: " + item_frame.getLocation());
imageMeta.add("Size: " + count_x + "x" + count_y);
imageMeta.add("ImageUUID: " + uuid);
writeMeta(uuid, imageMeta);
XLogger.debug("maps size: " + maps.size()); XLogger.debug("maps size: " + maps.size());
XLogger.debug("item_frames size: " + item_frames.size()); XLogger.debug("item_frames size: " + item_frames.size());
for (int i = 0; i < item_frames.size(); i++) { for (int i = 0; i < item_frames.size(); i++) {

View File

@ -16,9 +16,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import java.util.Objects;
public class MapManager implements Listener { public class MapManager implements Listener {
@ -40,7 +38,7 @@ public class MapManager implements Listener {
public void init() { public void init() {
MapManager.instance = this; MapManager.instance = this;
Bukkit.getPluginManager().registerEvents(this, ColorfulMap.instance); Bukkit.getPluginManager().registerEvents(this, ColorfulMap.instance);
loadImages(); reloadImages();
} }
@ -86,8 +84,9 @@ public class MapManager implements Listener {
/*** /***
* Loads images from data file to HashMap. * Loads images from data file to HashMap.
*/ */
private void loadImages() { public void reloadImages() {
FileConfiguration config = dataFile.getConfig(); FileConfiguration config = dataFile.getConfig();
List<String> recordToDelete = new ArrayList<>();
for (String world : config.getKeys(false)) { for (String world : config.getKeys(false)) {
for (String id : Objects.requireNonNull(config.getConfigurationSection(world)).getKeys(false)) { for (String id : Objects.requireNonNull(config.getConfigurationSection(world)).getKeys(false)) {
String path = config.getString(world + "." + id); String path = config.getString(world + "." + id);
@ -96,7 +95,8 @@ public class MapManager implements Listener {
} }
BufferedImage image = StorageMaps.load(path); BufferedImage image = StorageMaps.load(path);
if (image == null) { if (image == null) {
XLogger.err("无法加载图片: " + path); XLogger.err("无法加载图片: %s 已移除记录", path);
recordToDelete.add(world + "." + id);
continue; continue;
} }
if (!savedImages.containsKey(world)) { if (!savedImages.containsKey(world)) {
@ -105,6 +105,11 @@ public class MapManager implements Listener {
savedImages.get(world).put(Integer.parseInt(id), image); savedImages.get(world).put(Integer.parseInt(id), image);
} }
} }
// 删除无效记录
for (String record : recordToDelete) {
config.set(record, null);
}
dataFile.saveConfig();
} }

View File

@ -1,6 +1,7 @@
package cn.lunadeer.colorfulmap; package cn.lunadeer.colorfulmap;
import cn.lunadeer.colorfulmap.utils.Notification; import cn.lunadeer.colorfulmap.utils.Notification;
import cn.lunadeer.colorfulmap.utils.XLogger;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -16,26 +17,36 @@ public class StorageMaps {
/** /**
* save images to plugins/ColorfulMap/maps/{map_uuid}/x_y.png * save images to plugins/ColorfulMap/maps/{map_uuid}/x_y.png
* *
* @param player player * @param player player
* @param images images * @param images images
* @param x_count x_count * @param x_count x_count
* @param y_count y_count * @param y_count y_count
*/ */
public static UUID save(Player player, List<BufferedImage> images, int x_count, int y_count) { public static UUID save(Player player, BufferedImage raw, BufferedImage thumb,
List<BufferedImage> images, int x_count, int y_count) {
if (images.size() != x_count * y_count) { if (images.size() != x_count * y_count) {
return null; return null;
} }
UUID map_uuid = UUID.randomUUID(); UUID map_uuid = UUID.randomUUID();
File map_folder = new File(data_folder, "maps/" + map_uuid);
if (!map_folder.exists()) {
if (!map_folder.mkdirs()) {
Notification.error(player, "Failed to save map: failed to create map folder");
return null;
}
}
File raw_file = new File(map_folder, "raw.png");
File thumb_file = new File(map_folder, "thumb.png");
try {
ImageIO.write(raw, "png", raw_file);
ImageIO.write(thumb, "png", thumb_file);
} catch (Exception e) {
Notification.error(player, "Failed to save map: " + e.getMessage());
return null;
}
for (int y = 0; y < y_count; y++) { for (int y = 0; y < y_count; y++) {
for (int x = 0; x < x_count; x++) { for (int x = 0; x < x_count; x++) {
BufferedImage image = images.get(y * x_count + x); BufferedImage image = images.get(y * x_count + x);
File map_folder = new File(data_folder, "maps/" + map_uuid);
if (!map_folder.exists()) {
if (!map_folder.mkdirs()) {
Notification.error(player, "Failed to save map: failed to create map folder");
return null;
}
}
File image_file = new File(map_folder, x + "_" + y + ".png"); File image_file = new File(map_folder, x + "_" + y + ".png");
try { try {
ImageIO.write(image, "png", image_file); ImageIO.write(image, "png", image_file);
@ -48,13 +59,30 @@ public class StorageMaps {
return map_uuid; return map_uuid;
} }
public static String getThumbnailPath(UUID map_uuid) {
return "maps/" + map_uuid + "/thumb.png";
}
public static String getImageTilePath(UUID map_uuid, int x, int y) {
return "maps/" + map_uuid + "/" + x + "_" + y + ".png";
}
public static void writeMeta(UUID map_uuid, List<String> info) {
File meta_file = new File(data_folder, "maps/" + map_uuid + "/meta.txt");
try {
java.nio.file.Files.write(meta_file.toPath(), info);
} catch (Exception e) {
XLogger.err("写入地图画操作记录失败:%s", e.getMessage());
}
}
/** /**
* load images from plugins/ColorfulMap/maps/{map_uuid}/x_y.png * load images from plugins/ColorfulMap/maps/{map_uuid}/x_y.png
* *
* @param player player * @param player player
* @param map_uuid map_uuid * @param map_uuid map_uuid
* @param x_count x_count * @param x_count x_count
* @param y_count y_count * @param y_count y_count
* @return images * @return images
*/ */
public static List<BufferedImage> load(Player player, UUID map_uuid, int x_count, int y_count) { public static List<BufferedImage> load(Player player, UUID map_uuid, int x_count, int y_count) {

View File

@ -0,0 +1,19 @@
package cn.lunadeer.colorfulmap.commands;
import cn.lunadeer.colorfulmap.ColorfulMap;
import cn.lunadeer.colorfulmap.MapManager;
import cn.lunadeer.colorfulmap.utils.Notification;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class Reload implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
ColorfulMap.config.reload();
MapManager.instance.reloadImages();
Notification.info(sender, "重载成功");
return true;
}
}

View File

@ -1,9 +1,8 @@
package cn.lunadeer.colorfulmap.commands; package cn.lunadeer.colorfulmap.commands;
import cn.lunadeer.colorfulmap.ColorfulMap;
import cn.lunadeer.colorfulmap.generator.Multi; import cn.lunadeer.colorfulmap.generator.Multi;
import cn.lunadeer.colorfulmap.utils.Notification; import cn.lunadeer.colorfulmap.utils.Notification;
import cn.lunadeer.colorfulmap.utils.Time; import cn.lunadeer.colorfulmap.utils.Scheduler;
import cn.lunadeer.colorfulmap.utils.XLogger; import cn.lunadeer.colorfulmap.utils.XLogger;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
@ -46,14 +45,8 @@ public class ToMap implements CommandExecutor {
return true; return true;
} }
} }
// ItemStack mapImage = Multi.generate(player, url, scale);
// if (mapImage == null){
// Notification.error(player, "生成地图失败");
// return true;
// }
// player.getInventory().addItem(mapImage);
float finalScale = scale; float finalScale = scale;
Time.runAsync(ColorfulMap.instance, () -> { Scheduler.runTaskAsync(() -> {
ItemStack mapImage = Multi.generate(player, url, finalScale); ItemStack mapImage = Multi.generate(player, url, finalScale);
if (mapImage == null) { if (mapImage == null) {
Notification.error(player, "生成地图失败"); Notification.error(player, "生成地图失败");

View File

@ -2,7 +2,10 @@ package cn.lunadeer.colorfulmap.generator;
import cn.lunadeer.colorfulmap.ColorfulMap; import cn.lunadeer.colorfulmap.ColorfulMap;
import cn.lunadeer.colorfulmap.StorageMaps; import cn.lunadeer.colorfulmap.StorageMaps;
import cn.lunadeer.colorfulmap.utils.ImageTool;
import cn.lunadeer.colorfulmap.utils.Notification; import cn.lunadeer.colorfulmap.utils.Notification;
import cn.lunadeer.colorfulmap.utils.UrlTools;
import cn.lunadeer.colorfulmap.utils.VaultConnect.VaultConnect;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -15,25 +18,31 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static cn.lunadeer.colorfulmap.generator.TextRenderer.applyTextToMap; import static cn.lunadeer.colorfulmap.StorageMaps.getThumbnailPath;
import static cn.lunadeer.colorfulmap.generator.ImageRenderer.getMapItemFromImageTile;
public class Multi { public class Multi {
public static ItemStack generate(Player player, String url, Float scale) { public static ItemStack generate(Player player, String url, Float scale) {
try { try {
URL _url = new URL(url); if (!UrlTools.isInWhiteList(url)) {
BufferedImage image = ImageIO.read(_url); Notification.error(player, "无法生成地图画: 此图床地址不被允许使用");
if (scale != 1.0) { return null;
int width = image.getWidth();
int height = image.getHeight();
int new_width = (int) (width * scale);
int new_height = (int) (height * scale);
BufferedImage newImage = new BufferedImage(new_width, new_height, BufferedImage.TYPE_INT_ARGB);
newImage.getGraphics().drawImage(image, 0, 0, new_width, new_height, null);
image = newImage;
} }
int image_width = image.getWidth(); URL _url = new URL(url);
int image_height = image.getHeight(); BufferedImage raw_image = ImageIO.read(_url);
if (raw_image == null) {
Notification.error(player, "无法读取有效图片,请检查图片地址是否正确或者更换图床");
return null;
}
BufferedImage resized_image;
if (scale != 1.0) {
resized_image = ImageTool.resize(raw_image, scale);
} else {
resized_image = raw_image;
}
int image_width = resized_image.getWidth();
int image_height = resized_image.getHeight();
int x_count = (int) Math.ceil(image_width / 128.0); int x_count = (int) Math.ceil(image_width / 128.0);
int y_count = (int) Math.ceil(image_height / 128.0); int y_count = (int) Math.ceil(image_height / 128.0);
if (x_count > ColorfulMap.config.getMaxFrameX() || y_count > ColorfulMap.config.getMaxFrameY()) { if (x_count > ColorfulMap.config.getMaxFrameX() || y_count > ColorfulMap.config.getMaxFrameY()) {
@ -42,17 +51,15 @@ public class Multi {
} }
int new_width = x_count * 128; int new_width = x_count * 128;
int new_height = y_count * 128; int new_height = y_count * 128;
BufferedImage newImage = new BufferedImage(new_width, new_height, BufferedImage.TYPE_INT_ARGB); resized_image = ImageTool.center(resized_image, new_width, new_height);
newImage.getGraphics().drawImage(image, (new_width - image_width) / 2, (new_height - image_height) / 2, null); image_width = resized_image.getWidth();
image = newImage; image_height = resized_image.getHeight();
image_width = image.getWidth();
image_height = image.getHeight();
List<BufferedImage> split_images = new ArrayList<>(); List<BufferedImage> split_images = new ArrayList<>();
for (int y = 0; y < y_count; y++) { for (int y = 0; y < y_count; y++) {
for (int x = 0; x < x_count; x++) { for (int x = 0; x < x_count; x++) {
int width = Math.min(128, image_width - x * 128); int width = Math.min(128, image_width - x * 128);
int height = Math.min(128, image_height - y * 128); int height = Math.min(128, image_height - y * 128);
BufferedImage sub_image = image.getSubimage(x * 128, y * 128, width, height); BufferedImage sub_image = resized_image.getSubimage(x * 128, y * 128, width, height);
split_images.add(sub_image); split_images.add(sub_image);
} }
} }
@ -60,20 +67,21 @@ public class Multi {
Notification.error(player, "无法生成地图画: 图片为空"); Notification.error(player, "无法生成地图画: 图片为空");
return null; return null;
} }
UUID map_images_uuid = StorageMaps.save(player, split_images, x_count, y_count);
UUID map_images_uuid = StorageMaps.save(player, raw_image, ImageTool.thumb(raw_image), split_images, x_count, y_count);
if (map_images_uuid == null) { if (map_images_uuid == null) {
Notification.error(player, "无法生成地图画: 无法保存图片"); Notification.error(player, "无法生成地图画: 无法保存图片");
return null; return null;
} }
List<String> map_info = new ArrayList<>(); ItemStack mapItem = getMapItemFromImageTile(player, getThumbnailPath(map_images_uuid));
map_info.add("size: " + x_count + "x" + y_count); if (mapItem == null) {
ItemStack mapItem = applyTextToMap(player, map_info); Notification.error(player, "无法生成地图画: 无法生成地图");
// add lore to map item (uuid, x_count, y_count) return null;
}
MapMeta meta = (MapMeta) mapItem.getItemMeta(); MapMeta meta = (MapMeta) mapItem.getItemMeta();
List<Component> lore = new ArrayList<>(); List<Component> lore = new ArrayList<>();
lore.add(Component.text(map_images_uuid.toString())); String size_info = "size: " + x_count + "x" + y_count;
lore.add(Component.text(String.valueOf(x_count))); lore.add(Component.text(size_info).hoverEvent(Component.text(map_images_uuid.toString())));
lore.add(Component.text(String.valueOf(y_count)));
meta.lore(lore); meta.lore(lore);
mapItem.setItemMeta(meta); mapItem.setItemMeta(meta);
return mapItem; return mapItem;

View File

@ -1,55 +0,0 @@
package cn.lunadeer.colorfulmap.generator;
import cn.lunadeer.colorfulmap.utils.Notification;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
import org.bukkit.map.MinecraftFont;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class TextRenderer extends MapRenderer {
public TextRenderer(List<String> text) {
this.text = text;
}
private final List<String> text;
/**
* Render to the given map.
*
* @param map The MapView being rendered to.
* @param canvas The canvas to use for rendering.
* @param player The player who triggered the rendering.
*/
@Override
public void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player) {
try {
int y = 0;
for (String line : text) {
canvas.drawText(0, y, MinecraftFont.Font, line);
y += 10;
}
} catch (Exception e) {
Notification.error(player, "Failed to render text: " + e.getMessage());
}
}
public static ItemStack applyTextToMap(Player player, List<String> text){
ItemStack mapItem = new ItemStack(Material.FILLED_MAP, 1);
MapMeta meta = (MapMeta) mapItem.getItemMeta();
MapView mapView = Bukkit.createMap(player.getWorld());
TextRenderer renderer = new TextRenderer(text);
mapView.addRenderer(renderer);
meta.setMapView(mapView);
mapItem.setItemMeta(meta);
return mapItem;
}
}

View File

@ -0,0 +1,14 @@
package cn.lunadeer.colorfulmap.utils;
public class Common {
public static boolean isPaper() {
try {
Class.forName("io.papermc.paper.threadedregions.scheduler.ScheduledTask");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}

View File

@ -1,5 +1,11 @@
package cn.lunadeer.colorfulmap.utils; package cn.lunadeer.colorfulmap.utils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
@ -12,9 +18,9 @@ import java.io.File;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.concurrent.TimeUnit; import java.util.Random;
public class GiteaReleaseCheck { public class GiteaReleaseCheck implements Listener {
private static class GiteaRelease { private static class GiteaRelease {
public String tag_name; public String tag_name;
public String message; public String message;
@ -22,19 +28,23 @@ public class GiteaReleaseCheck {
public String download_url; public String download_url;
} }
private static GiteaReleaseCheck instance = null;
public GiteaReleaseCheck(JavaPlugin plugin, String giteaServer, String owner, String repo) { public GiteaReleaseCheck(JavaPlugin plugin, String giteaServer, String owner, String repo) {
instance = this;
this.gitea_server = giteaServer; this.gitea_server = giteaServer;
this.owner = owner; this.owner = owner;
this.repo = repo; this.repo = repo;
this.plugin = plugin; this.plugin = plugin;
this.current_version = plugin.getPluginMeta().getVersion(); this.current_version = plugin.getDescription().getVersion();
this.plugin.getServer().getPluginManager().registerEvents(this, plugin);
// 异步每12小时检查一次更新 // 异步每12小时检查一次更新
plugin.getServer().getAsyncScheduler().runAtFixedRate(plugin, (instance) -> { Scheduler.runTaskRepeatAsync(() -> {
getLatestRelease(); getLatestRelease();
if (auto_update) { if (auto_update) {
downloadUpdate(); downloadUpdate();
} }
}, 10, 60 * 60 * 12, TimeUnit.SECONDS); }, (10 + new Random().nextInt(10)) * 20, (60 * 60 * 12 + new Random().nextInt(60)) * 20);
} }
public void enableAutoUpdate() { public void enableAutoUpdate() {
@ -169,11 +179,24 @@ public class GiteaReleaseCheck {
} }
} }
private String gitea_server; @EventHandler
private String owner; private void onPlayerJoin(PlayerJoinEvent event) {
private String repo; if (!event.getPlayer().isOp()) {
private JavaPlugin plugin; return;
private String current_version; }
Player player = event.getPlayer();
if (latest_release != null && isNewVersion(current_version, latest_release.tag_name)) {
Notification.info(player, "发现新版本:" + latest_release.tag_name + " 详细内容请查看控制台或点击下方链接");
Component download = Component.text(latest_release.html_url).clickEvent(ClickEvent.openUrl(latest_release.html_url)).hoverEvent(Component.text("点击打开"));
Notification.info(player,download);
}
}
private final String gitea_server;
private final String owner;
private final String repo;
private final JavaPlugin plugin;
private final String current_version;
private GiteaRelease latest_release = null; private GiteaRelease latest_release = null;
private boolean auto_update = false; private boolean auto_update = false;

View File

@ -0,0 +1,33 @@
package cn.lunadeer.colorfulmap.utils;
import java.awt.image.BufferedImage;
public class ImageTool {
public static BufferedImage resize(BufferedImage image, float scale) {
int new_width = (int) (image.getWidth() * scale);
int new_height = (int) (image.getHeight() * scale);
BufferedImage newImage = new BufferedImage(new_width, new_height, BufferedImage.TYPE_INT_ARGB);
newImage.getGraphics().drawImage(image, 0, 0, new_width, new_height, null);
return newImage;
}
public static BufferedImage center(BufferedImage image, int width, int height) {
int image_width = image.getWidth();
int image_height = image.getHeight();
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
newImage.getGraphics().drawImage(image, (width - image_width) / 2, (height - image_height) / 2, null);
return newImage;
}
public static BufferedImage thumb(BufferedImage img) {
double scale;
if (img.getWidth() > img.getHeight()) {
scale = 128.0 / img.getWidth();
} else {
scale = 128.0 / img.getHeight();
}
return center(resize(img, (float) scale), 128, 128);
}
}

View File

@ -5,59 +5,125 @@ import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public class Notification { public class Notification {
public static Notification instance;
public final SendMessageAbstract sender;
public Notification(JavaPlugin plugin) {
instance = this;
this.plugin = plugin;
this.prefix = "[" + plugin.getName() + "]";
this.sender = new SendMessageAbstract(plugin);
}
private static final Style i_style = Style.style(TextColor.color(139, 255, 123)); private static final Style i_style = Style.style(TextColor.color(139, 255, 123));
private static final Style w_style = Style.style(TextColor.color(255, 185, 69)); private static final Style w_style = Style.style(TextColor.color(255, 185, 69));
private static final Style e_style = Style.style(TextColor.color(255, 96, 72)); private static final Style e_style = Style.style(TextColor.color(255, 96, 72));
private static final Style d_style = Style.style(TextColor.color(0, 255, 255));
private static final String prefix = "[ColorfulMap] "; private String prefix;
private JavaPlugin plugin;
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public static void info(Player player, String msg) { public static void info(Player player, String msg) {
player.sendMessage(Component.text(prefix + msg, i_style)); instance.sender.sendMessage(player, Component.text(instance.prefix + " " + msg, i_style));
}
public static void info(Player player, String msg, Object... args) {
instance.sender.sendMessage(player, Component.text(instance.prefix + " " + String.format(msg, args), i_style));
} }
public static void warn(Player player, String msg) { public static void warn(Player player, String msg) {
player.sendMessage(Component.text(prefix + msg, w_style)); instance.sender.sendMessage(player, Component.text(instance.prefix + " " + msg, w_style));
}
public static void warn(Player player, String msg, Object... args) {
instance.sender.sendMessage(player, Component.text(instance.prefix + " " + String.format(msg, args), w_style));
} }
public static void error(Player player, String msg) { public static void error(Player player, String msg) {
player.sendMessage(Component.text(prefix + msg, e_style)); instance.sender.sendMessage(player, Component.text(instance.prefix + " " + msg, e_style));
}
public static void error(Player player, String msg, Object... args) {
instance.sender.sendMessage(player, Component.text(instance.prefix + " " + String.format(msg, args), e_style));
} }
public static void info(CommandSender sender, String msg) { public static void info(CommandSender sender, String msg) {
sender.sendMessage(Component.text(prefix + msg, i_style)); instance.sender.sendMessage(sender, Component.text(instance.prefix + " " + msg, i_style));
}
public static void info(CommandSender sender, String msg, Object... args) {
instance.sender.sendMessage(sender, Component.text(instance.prefix + " " + String.format(msg, args), i_style));
} }
public static void warn(CommandSender sender, String msg) { public static void warn(CommandSender sender, String msg) {
sender.sendMessage(Component.text(prefix + msg, w_style)); instance.sender.sendMessage(sender, Component.text(instance.prefix + " " + msg, w_style));
}
public static void warn(CommandSender sender, String msg, Object... args) {
instance.sender.sendMessage(sender, Component.text(instance.prefix + " " + String.format(msg, args), w_style));
} }
public static void error(CommandSender sender, String msg) { public static void error(CommandSender sender, String msg) {
sender.sendMessage(Component.text(prefix + msg, e_style)); instance.sender.sendMessage(sender, Component.text(instance.prefix + " " + msg, e_style));
}
public static void error(CommandSender sender, String msg, Object... args) {
instance.sender.sendMessage(sender, Component.text(instance.prefix + " " + String.format(msg, args), e_style));
} }
public static void info(Player player, Component msg) { public static void info(Player player, Component msg) {
player.sendMessage(Component.text(prefix, i_style).append(msg)); instance.sender.sendMessage(player, Component.text(instance.prefix, i_style).append(Component.text(" ")).append(msg));
} }
public static void warn(Player player, Component msg) { public static void warn(Player player, Component msg) {
player.sendMessage(Component.text(prefix, w_style).append(msg)); instance.sender.sendMessage(player, Component.text(instance.prefix, w_style).append(Component.text(" ")).append(msg));
} }
public static void error(Player player, Component msg) { public static void error(Player player, Component msg) {
player.sendMessage(Component.text(prefix, e_style).append(msg)); instance.sender.sendMessage(player, Component.text(instance.prefix, e_style).append(Component.text(" ")).append(msg));
} }
public static void info(CommandSender player, Component msg) { public static void info(CommandSender player, Component msg) {
player.sendMessage(Component.text(prefix, i_style).append(msg)); instance.sender.sendMessage(player, Component.text(instance.prefix, i_style).append(Component.text(" ")).append(msg));
} }
public static void warn(CommandSender player, Component msg) { public static void warn(CommandSender player, Component msg) {
player.sendMessage(Component.text(prefix, w_style).append(msg)); instance.sender.sendMessage(player, Component.text(instance.prefix, w_style).append(Component.text(" ")).append(msg));
} }
public static void error(CommandSender player, Component msg) { public static void error(CommandSender player, Component msg) {
player.sendMessage(Component.text(prefix, e_style).append(msg)); instance.sender.sendMessage(player, Component.text(instance.prefix, e_style).append(Component.text(" ")).append(msg));
}
public static void all(String msg) {
instance.sender.broadcast(Component.text(instance.prefix + " " + msg, i_style));
}
public static void all(Component msg) {
instance.sender.broadcast(Component.text(instance.prefix, i_style).append(Component.text(" ")).append(msg));
}
public static void all(String msg, Object... args) {
instance.sender.broadcast(Component.text(instance.prefix + " " + String.format(msg, args), i_style));
}
public static void actionBar(Player player, String msg) {
instance.sender.sendActionBar(player, Component.text(msg));
}
public static void actionBar(Player player, String msg, Object... args) {
instance.sender.sendActionBar(player, Component.text(String.format(msg, args)));
}
public static void actionBar(Player player, Component msg) {
instance.sender.sendActionBar(player, msg);
} }
} }

View File

@ -0,0 +1,58 @@
package cn.lunadeer.colorfulmap.utils;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.TimeUnit;
import static cn.lunadeer.colorfulmap.utils.Common.isPaper;
public class Scheduler {
public static Scheduler instance;
private final JavaPlugin plugin;
private boolean isPaper = false;
public Scheduler(JavaPlugin plugin) {
instance = this;
this.plugin = plugin;
this.isPaper = isPaper();
}
public static void cancelAll() {
if (instance.isPaper) {
instance.plugin.getServer().getGlobalRegionScheduler().cancelTasks(instance.plugin);
instance.plugin.getServer().getGlobalRegionScheduler().cancelTasks(instance.plugin);
} else {
instance.plugin.getServer().getScheduler().cancelTasks(instance.plugin);
}
}
/**
* Run a task asynchronously
*
* @param task The task to run
* @return The scheduled task
*/
public static void runTaskAsync(Runnable task) {
if (instance.isPaper) {
instance.plugin.getServer().getAsyncScheduler().runNow(instance.plugin, (plugin) -> task.run());
} else {
instance.plugin.getServer().getScheduler().runTask(instance.plugin, task);
}
}
/**
* Run a task repeatedly asynchronously
*
* @param task The task to run
* @param delay The delay in milliseconds
* @param period The period in milliseconds
* @return The scheduled task
*/
public static void runTaskRepeatAsync(Runnable task, long delay, long period) {
if (instance.isPaper) {
instance.plugin.getServer().getAsyncScheduler().runAtFixedRate(instance.plugin, (plugin) -> task.run(), delay * 50, period * 50, TimeUnit.MILLISECONDS);
} else {
instance.plugin.getServer().getScheduler().runTaskTimerAsynchronously(instance.plugin, task, delay, period);
}
}
}

View File

@ -0,0 +1,52 @@
package cn.lunadeer.colorfulmap.utils;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public class SendMessageAbstract {
private BukkitAudiences adventure = null;
private JavaPlugin plugin;
public SendMessageAbstract(JavaPlugin plugin) {
this.plugin = plugin;
if (!Common.isPaper()) {
this.adventure = BukkitAudiences.create(plugin);
}
}
public void sendMessage(Player player, Component msg) {
if (this.adventure == null) {
player.sendMessage(msg);
} else {
this.adventure.player(player).sendMessage(msg);
}
}
public void sendMessage(CommandSender sender, Component msg) {
if (this.adventure == null) {
sender.sendMessage(msg);
} else {
this.adventure.sender(sender).sendMessage(msg);
}
}
public void broadcast(Component msg) {
if (this.adventure == null) {
plugin.getServer().broadcast(msg);
} else {
adventure.all().sendMessage(msg);
}
}
public void sendActionBar(Player player, Component msg) {
if (this.adventure == null) {
player.sendActionBar(msg);
} else {
this.adventure.player(player).sendActionBar(msg);
}
}
}

View File

@ -1,67 +0,0 @@
package cn.lunadeer.colorfulmap.utils;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Time {
public static String nowStr() {
// yyyy-MM-dd HH:mm:ss
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
/**
* 尝试获取folia的调度器
*
* @return 是否成功
*/
private static boolean tryFolia() {
try {
Bukkit.getAsyncScheduler();
return true;
} catch (Throwable ignored) {
}
return false;
}
private static Boolean IS_FOLIA = null;
/**
* 判断是否是folia核心
*
* @return 是否是folia核心
*/
public static Boolean isFolia() {
if (IS_FOLIA == null) IS_FOLIA = tryFolia();
return IS_FOLIA;
}
/**
* 定时异步任务
*
* @param plugin 插件
* @param runnable 任务
* @param ticks 间隔
*/
public static void runAtFixedRateAsync(Plugin plugin, Runnable runnable, int ticks) {
if (isFolia())
Bukkit.getAsyncScheduler().runAtFixedRate(plugin, (task) -> runnable.run(), ticks / 20, ticks / 20, TimeUnit.SECONDS);
else Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, ticks, ticks);
}
public static void runLater(Plugin plugin, Runnable runnable, int ticks) {
if (isFolia())
Bukkit.getAsyncScheduler().runDelayed(plugin, (task) -> runnable.run(), ticks / 20, TimeUnit.SECONDS);
else Bukkit.getScheduler().runTaskLater(plugin, runnable, ticks);
}
public static void runAsync(Plugin plugin, Runnable runnable) {
if (isFolia())
Bukkit.getAsyncScheduler().runNow(plugin, (task) -> runnable.run());
else Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable);
}
}

View File

@ -0,0 +1,25 @@
package cn.lunadeer.colorfulmap.utils;
import cn.lunadeer.colorfulmap.ColorfulMap;
public class UrlTools {
public static boolean isInWhiteList(String url) {
if (ColorfulMap.config.getAddressWhiteList().isEmpty()) {
return true;
}
for (String whiteUrl : ColorfulMap.config.getAddressWhiteList()) {
if (url.startsWith(whiteUrl)) {
return true;
}
if (url.startsWith("http://" + whiteUrl)) {
return true;
}
if (url.startsWith("https://" + whiteUrl)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,48 @@
package cn.lunadeer.colorfulmap.utils.VaultConnect;
import cn.lunadeer.colorfulmap.utils.XLogger;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
public class Vault implements VaultInterface {
private Economy econ = null;
@Override
public boolean init(JavaPlugin plugin) {
RegisteredServiceProvider<Economy> rsp = plugin.getServer().getServicesManager().getRegistration(Economy.class);
if (rsp != null) {
econ = rsp.getProvider();
return true;
}
XLogger.err("Vault 不可用");
return false;
}
@Override
public String currencyNamePlural() {
return econ.currencyNamePlural();
}
@Override
public String currencyNameSingular() {
return econ.currencyNameSingular();
}
@Override
public void withdrawPlayer(Player player, double amount) {
econ.withdrawPlayer(player, amount);
}
@Override
public void depositPlayer(Player player, double amount) {
econ.depositPlayer(player, amount);
}
@Override
public double getBalance(Player player) {
return econ.getBalance(player);
}
}

View File

@ -0,0 +1,50 @@
package cn.lunadeer.colorfulmap.utils.VaultConnect;
import cn.lunadeer.colorfulmap.utils.XLogger;
import net.milkbowl.vault2.economy.Economy;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import java.math.BigDecimal;
public class Vault2 implements VaultInterface {
private Economy econ = null;
@Override
public boolean init(JavaPlugin plugin) {
RegisteredServiceProvider<Economy> rsp = plugin.getServer().getServicesManager().getRegistration(Economy.class);
if (rsp != null) {
econ = rsp.getProvider();
return true;
}
XLogger.err("VaultUnlocked 不可用");
return false;
}
@Override
public String currencyNamePlural() {
return econ.defaultCurrencyNamePlural();
}
@Override
public String currencyNameSingular() {
return econ.defaultCurrencyNameSingular();
}
@Override
public void withdrawPlayer(Player player, double amount) {
econ.withdraw("MPU", player.getUniqueId(), BigDecimal.valueOf(amount));
}
@Override
public void depositPlayer(Player player, double amount) {
econ.deposit("MPU", player.getUniqueId(), BigDecimal.valueOf(amount));
}
@Override
public double getBalance(Player player) {
return econ.getBalance("MPU", player.getUniqueId()).doubleValue();
}
}

View File

@ -0,0 +1,94 @@
package cn.lunadeer.colorfulmap.utils.VaultConnect;
import cn.lunadeer.colorfulmap.utils.XLogger;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.server.ServiceRegisterEvent;
import org.bukkit.plugin.java.JavaPlugin;
public class VaultConnect implements Listener {
public static VaultConnect instance;
private VaultInterface vaultInstance = null;
private JavaPlugin plugin;
public VaultConnect(JavaPlugin plugin) {
this.plugin = plugin;
instance = this;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onEnable(ServiceRegisterEvent event) {
}
public boolean economyAvailable() {
if (vaultInstance == null) {
if (foundClass("net.milkbowl.vault.economy.Economy")) {
vaultInstance = new Vault();
} else if (foundClass("net.milkbowl.vault2.economy.Economy")) {
vaultInstance = new Vault2();
} else {
XLogger.err("没有可用的经济插件");
return false;
}
if (!vaultInstance.init(plugin)) {
vaultInstance = null;
XLogger.err("没有可用的经济插件");
return false;
}
}
return true;
}
public String currencyNamePlural() {
if (economyAvailable()) {
return vaultInstance.currencyNamePlural();
}
XLogger.warn("没有可用的经济插件");
return "";
}
public String currencyNameSingular() {
if (economyAvailable()) {
return vaultInstance.currencyNameSingular();
}
XLogger.warn("没有可用的经济插件");
return "";
}
public void withdrawPlayer(Player player, double amount) {
if (economyAvailable()) {
vaultInstance.withdrawPlayer(player, amount);
return;
}
XLogger.warn("没有可用的经济插件");
}
public void depositPlayer(Player player, double amount) {
if (economyAvailable()) {
vaultInstance.depositPlayer(player, amount);
return;
}
XLogger.warn("没有可用的经济插件");
}
public double getBalance(Player player) {
if (economyAvailable()) {
return vaultInstance.getBalance(player);
}
XLogger.warn("没有可用的经济插件");
return 0;
}
private static boolean foundClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}

View File

@ -0,0 +1,21 @@
package cn.lunadeer.colorfulmap.utils.VaultConnect;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public interface VaultInterface {
public boolean init(JavaPlugin plugin);
public String currencyNamePlural();
public String currencyNameSingular();
public void withdrawPlayer(Player player, double amount);
public void depositPlayer(Player player, double amount);
public double getBalance(Player player);
}

View File

@ -1,56 +1,62 @@
package cn.lunadeer.colorfulmap.utils; package cn.lunadeer.colorfulmap.utils;
import cn.lunadeer.colorfulmap.ColorfulMap; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.entity.Player; import org.jetbrains.annotations.Nullable;
import java.util.logging.Logger; import java.util.logging.Logger;
public class XLogger { public class XLogger {
private static final ColorfulMap _plugin = ColorfulMap.instance; public static XLogger instance;
private static final Logger _logger = _plugin.getLogger();
private static final String prefix = "[ColorfulMap] "; public XLogger() {
instance = this;
public static void info(Player player, String message) { this._logger = Logger.getLogger("Lunadeer");
Notification.info(player, prefix + "I | " + message);
if (ColorfulMap.config.isDebug())
debug("来自玩家[ " + player.getName() + " ] 的信息 | " + message);
} }
public XLogger(@Nullable JavaPlugin plugin) {
instance = this;
this._logger = plugin != null ? plugin.getLogger() : Logger.getLogger("Lunadeer");
}
public static XLogger setDebug(boolean debug) {
instance._debug = debug;
return instance;
}
private final Logger _logger;
private boolean _debug = false;
public static void info(String message) { public static void info(String message) {
_logger.info(" I | " + message); instance._logger.info(" I | " + message);
} }
public static void warn(Player player, String message) { public static void info(String message, Object... args) {
Notification.warn(player, prefix + "W | " + message); instance._logger.info(" I | " + String.format(message, args));
if (ColorfulMap.config.isDebug())
debug("来自玩家[ " + player.getName() + " ] 的警告 | " + message);
} }
public static void warn(String message) { public static void warn(String message) {
_logger.info(" W | " + message); instance._logger.warning(" W | " + message);
} }
public static void err(Player player, String message) { public static void warn(String message, Object... args) {
Notification.error(player, prefix + "E | " + message); instance._logger.warning(" W | " + String.format(message, args));
if (ColorfulMap.config.isDebug())
debug("来自玩家[ " + player.getName() + " ] 的报错 | " + message);
} }
public static void err(String message) { public static void err(String message) {
_logger.info(" E | " + message); instance._logger.severe(" E | " + message);
} }
public static void debug(Player player, String message) { public static void err(String message, Object... args) {
if (!ColorfulMap.config.isDebug()) return; instance._logger.severe(" E | " + String.format(message, args));
if (player.isOp())
Notification.info(player, prefix + "D | " + message);
else
debug("来自玩家[ " + player.getName() + " ] 的调试 | " + message);
} }
public static void debug(String message) { public static void debug(String message) {
if (!ColorfulMap.config.isDebug()) return; if (!instance._debug) return;
_logger.info(" D | " + message); instance._logger.info(" D | " + message);
}
public static void debug(String message, Object... args) {
if (!instance._debug) return;
instance._logger.info(" D | " + String.format(message, args));
} }
} }

View File

@ -1,4 +1,4 @@
package cn.lunadeer.colorfulmap; package cn.lunadeer.colorfulmap.utils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
@ -23,7 +23,7 @@ import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
public class Metrics { public class bStatsMetrics {
private final Plugin plugin; private final Plugin plugin;
private final MetricsBase metricsBase; private final MetricsBase metricsBase;
@ -35,7 +35,7 @@ public class Metrics {
* @param serviceId The id of the service. It can be found at <a * @param serviceId The id of the service. It can be found at <a
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a> * href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
*/ */
public Metrics(JavaPlugin plugin, int serviceId) { public bStatsMetrics(JavaPlugin plugin, int serviceId) {
this.plugin = plugin; this.plugin = plugin;
// Get the config file // Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");

View File

@ -2,6 +2,12 @@ MaxFrameX: 32
MaxFrameY: 18 MaxFrameY: 18
Economy:
Enable: false
CostPerMap: 100.0
AddressWhiteList: []
CheckUpdate: true CheckUpdate: true
Debug: false Debug: false

View File

@ -8,3 +8,15 @@ commands:
tomap: tomap:
description: 将图片转换为地图画 description: 将图片转换为地图画
usage: /tomap <图片url> [缩放比例(默认1)] usage: /tomap <图片url> [缩放比例(默认1)]
permission: colorfulmap.tomap
reloadColorfulMap:
description: 重载ColorfulMap配置
usage: /reloadColorfulMap
permission: colorfulmap.reload
permissions:
colorfulmap.tomap:
description: 允许使用/tomap命令
default: true
colorfulmap.reload:
description: 允许使用/reloadColorfulMap命令
default: op