Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d0084b4265 | |||
| 113f0a1ede |
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@ -1,4 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
/CopilotChatHistory.xml
|
||||
|
||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<list size="1">
|
||||
@ -12,5 +13,5 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="21" project-jdk-type="JavaSDK" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="temurin-1.8" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
37
pom.xml
37
pom.xml
@ -10,10 +10,10 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<mc.version>1.20.6+</mc.version>
|
||||
<java.version>21</java.version>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<mc.version>1.9.4+</mc.version>
|
||||
<java.version>8</java.version>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@ -31,8 +31,8 @@
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
<configuration>
|
||||
<outputDirectory>E:\SpigotMC\test1206\plugins</outputDirectory>
|
||||
<finalName>FMCCore-${version}+${mc.version}.jar</finalName>
|
||||
<outputDirectory>E:\SpigotMC\test194\plugins</outputDirectory>
|
||||
<finalName>FMCCore-${version}.jar</finalName>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
@ -53,34 +53,19 @@
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.20.6-R0.1-20240613.150924-57</version>
|
||||
<version>1.9.4-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.imyeyu.inject</groupId>
|
||||
<artifactId>timi-inject</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.34</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.objecthunter</groupId>
|
||||
<artifactId>exp4j</artifactId>
|
||||
<version>0.4.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.36</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.1.4</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>xml-apis</groupId>
|
||||
<artifactId>xml-apis</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -2,16 +2,12 @@ package cn.forevermc.spigot.core;
|
||||
|
||||
import cn.forevermc.spigot.core.command.FMCCommand;
|
||||
import cn.forevermc.spigot.core.command.FMCCommandExecutor;
|
||||
import com.imyeyu.inject.TimiInject;
|
||||
import com.imyeyu.inject.annotation.IOCReturn;
|
||||
import com.imyeyu.inject.annotation.Inject;
|
||||
import com.imyeyu.inject.annotation.TimiInjectApplication;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -19,33 +15,30 @@ import java.util.logging.Logger;
|
||||
* @author 夜雨
|
||||
* @since 2024-10-10 15:05
|
||||
*/
|
||||
@TimiInjectApplication
|
||||
public final class FMCCore extends JavaPlugin {
|
||||
|
||||
@Inject
|
||||
private FMCCommand fmcCommand;
|
||||
|
||||
@Inject
|
||||
private FMCCommandExecutor commandExecutor;
|
||||
|
||||
private static final List<FMCPlugin> FMC_PLUGIN_LIST = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private static FMCCore instance;
|
||||
|
||||
@Getter
|
||||
private FMCCommand fmcCommand;
|
||||
|
||||
public static <T extends FMCPlugin> void register(T fmcPlugin) {
|
||||
FMC_PLUGIN_LIST.add(fmcPlugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
// 扫描插件
|
||||
TimiInject.run(this);
|
||||
instance = this;
|
||||
|
||||
fmcCommand = new FMCCommand();
|
||||
|
||||
FMCCommandExecutor commandExecutor = new FMCCommandExecutor();
|
||||
for (int i = 0; i < FMC_PLUGIN_LIST.size(); i++) {
|
||||
FMC_PLUGIN_LIST.get(i).fmcCommand = fmcCommand;
|
||||
}
|
||||
Objects.requireNonNull(getCommand("fmc")).setExecutor(commandExecutor);
|
||||
}
|
||||
|
||||
@IOCReturn
|
||||
public Logger log() {
|
||||
return getLogger();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,13 +2,16 @@ package cn.forevermc.spigot.core;
|
||||
|
||||
import cn.forevermc.spigot.core.bean.ConfigPath;
|
||||
import cn.forevermc.spigot.core.command.FMCCommand;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.java.ref.Ref;
|
||||
import cn.forevermc.spigot.core.util.Ref;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -25,12 +28,40 @@ public abstract class FMCPlugin extends JavaPlugin {
|
||||
public FMCPlugin() {
|
||||
}
|
||||
|
||||
protected final void defaultConfig(String path) {
|
||||
try {
|
||||
InputStream is = getClass().getClassLoader().getResourceAsStream(path);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
assert is != null;
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
InputStreamReader isr = new InputStreamReader(bis, StandardCharsets.UTF_8);
|
||||
char[] buffer = new char[4096];
|
||||
int l;
|
||||
while ((l = isr.read(buffer)) != -1) {
|
||||
sb.append(buffer, 0, l);
|
||||
}
|
||||
isr.close();
|
||||
bis.close();
|
||||
is.close();
|
||||
|
||||
FileConfiguration config = getConfig();
|
||||
YamlConfiguration defConfig = new YamlConfiguration();
|
||||
defConfig.options().indent(4);
|
||||
defConfig.loadFromString(sb.toString());
|
||||
config.addDefaults(defConfig);
|
||||
config.options().copyDefaults(true);
|
||||
super.saveConfig();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void saveConfigAs(Object obj, FileConfiguration config) {
|
||||
try {
|
||||
serializeConfig(obj, config);
|
||||
super.saveConfig();
|
||||
} catch (Exception e) {
|
||||
throw new TimiException(TimiCode.ERROR, "serialize config error", e);
|
||||
throw new RuntimeException("serialize config error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +71,7 @@ public abstract class FMCPlugin extends JavaPlugin {
|
||||
deserializeConfig(t, config);
|
||||
return t;
|
||||
} catch (Exception e) {
|
||||
throw new TimiException(TimiCode.ERROR, "deserialize config error", e);
|
||||
throw new RuntimeException("deserialize config error", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
437
src/main/java/cn/forevermc/spigot/core/bean/BoundingBox.java
Normal file
437
src/main/java/cn/forevermc/spigot/core/bean/BoundingBox.java
Normal file
@ -0,0 +1,437 @@
|
||||
package cn.forevermc.spigot.core.bean;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.SerializableAs;
|
||||
import org.bukkit.util.NumberConversions;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/** Copy for 1.13.2 org.bukkit.util.BoundingBox */
|
||||
@Getter
|
||||
@SerializableAs("BoundingBox")
|
||||
public class BoundingBox implements Cloneable, ConfigurationSerializable {
|
||||
|
||||
private double minX;
|
||||
private double minY;
|
||||
private double minZ;
|
||||
private double maxX;
|
||||
private double maxY;
|
||||
private double maxZ;
|
||||
|
||||
public static BoundingBox of(Vector corner1, Vector corner2) {
|
||||
Validate.notNull(corner1, "Corner1 is null!");
|
||||
Validate.notNull(corner2, "Corner2 is null!");
|
||||
return new BoundingBox(corner1.getX(), corner1.getY(), corner1.getZ(), corner2.getX(), corner2.getY(), corner2.getZ());
|
||||
}
|
||||
|
||||
public static BoundingBox of(Location corner1, Location corner2) {
|
||||
Validate.notNull(corner1, "Corner1 is null!");
|
||||
Validate.notNull(corner2, "Corner2 is null!");
|
||||
Validate.isTrue(Objects.equals(corner1.getWorld(), corner2.getWorld()), "Locations from different worlds!");
|
||||
return new BoundingBox(corner1.getX(), corner1.getY(), corner1.getZ(), corner2.getX(), corner2.getY(), corner2.getZ());
|
||||
}
|
||||
|
||||
public static BoundingBox of(Block corner1, Block corner2) {
|
||||
Validate.notNull(corner1, "Corner1 is null!");
|
||||
Validate.notNull(corner2, "Corner2 is null!");
|
||||
Validate.isTrue(Objects.equals(corner1.getWorld(), corner2.getWorld()), "Blocks from different worlds!");
|
||||
int x1 = corner1.getX();
|
||||
int y1 = corner1.getY();
|
||||
int z1 = corner1.getZ();
|
||||
int x2 = corner2.getX();
|
||||
int y2 = corner2.getY();
|
||||
int z2 = corner2.getZ();
|
||||
int minX = Math.min(x1, x2);
|
||||
int minY = Math.min(y1, y2);
|
||||
int minZ = Math.min(z1, z2);
|
||||
int maxX = Math.max(x1, x2) + 1;
|
||||
int maxY = Math.max(y1, y2) + 1;
|
||||
int maxZ = Math.max(z1, z2) + 1;
|
||||
return new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
public static BoundingBox of(Block block) {
|
||||
Validate.notNull(block, "Block is null!");
|
||||
return new BoundingBox(block.getX(), block.getY(), block.getZ(), block.getX() + 1, block.getY() + 1, block.getZ() + 1);
|
||||
}
|
||||
|
||||
public static BoundingBox of(Vector center, double x, double y, double z) {
|
||||
Validate.notNull(center, "Center is null!");
|
||||
return new BoundingBox(center.getX() - x, center.getY() - y, center.getZ() - z, center.getX() + x, center.getY() + y, center.getZ() + z);
|
||||
}
|
||||
|
||||
public static BoundingBox of(Location center, double x, double y, double z) {
|
||||
Validate.notNull(center, "Center is null!");
|
||||
return new BoundingBox(center.getX() - x, center.getY() - y, center.getZ() - z, center.getX() + x, center.getY() + y, center.getZ() + z);
|
||||
}
|
||||
|
||||
public BoundingBox() {
|
||||
this.resize(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
public BoundingBox(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
this.resize(x1, y1, z1, x2, y2, z2);
|
||||
}
|
||||
|
||||
public BoundingBox resize(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
NumberConversions.checkFinite(x1, "x1 not finite");
|
||||
NumberConversions.checkFinite(y1, "y1 not finite");
|
||||
NumberConversions.checkFinite(z1, "z1 not finite");
|
||||
NumberConversions.checkFinite(x2, "x2 not finite");
|
||||
NumberConversions.checkFinite(y2, "y2 not finite");
|
||||
NumberConversions.checkFinite(z2, "z2 not finite");
|
||||
this.minX = Math.min(x1, x2);
|
||||
this.minY = Math.min(y1, y2);
|
||||
this.minZ = Math.min(z1, z2);
|
||||
this.maxX = Math.max(x1, x2);
|
||||
this.maxY = Math.max(y1, y2);
|
||||
this.maxZ = Math.max(z1, z2);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector getMin() {
|
||||
return new Vector(this.minX, this.minY, this.minZ);
|
||||
}
|
||||
|
||||
public Vector getMax() {
|
||||
return new Vector(this.maxX, this.maxY, this.maxZ);
|
||||
}
|
||||
|
||||
public double getWidthX() {
|
||||
return this.maxX - this.minX;
|
||||
}
|
||||
|
||||
public double getWidthZ() {
|
||||
return this.maxZ - this.minZ;
|
||||
}
|
||||
|
||||
public double getHeight() {
|
||||
return this.maxY - this.minY;
|
||||
}
|
||||
|
||||
public double getVolume() {
|
||||
return this.getHeight() * this.getWidthX() * this.getWidthZ();
|
||||
}
|
||||
|
||||
public double getCenterX() {
|
||||
return this.minX + this.getWidthX() * 0.5;
|
||||
}
|
||||
|
||||
public double getCenterY() {
|
||||
return this.minY + this.getHeight() * 0.5;
|
||||
}
|
||||
|
||||
public double getCenterZ() {
|
||||
return this.minZ + this.getWidthZ() * 0.5;
|
||||
}
|
||||
|
||||
public Vector getCenter() {
|
||||
return new Vector(this.getCenterX(), this.getCenterY(), this.getCenterZ());
|
||||
}
|
||||
|
||||
public BoundingBox copy(BoundingBox other) {
|
||||
Validate.notNull(other, "Other bounding box is null!");
|
||||
return this.resize(other.getMinX(), other.getMinY(), other.getMinZ(), other.getMaxX(), other.getMaxY(), other.getMaxZ());
|
||||
}
|
||||
|
||||
public BoundingBox expand(double negativeX, double negativeY, double negativeZ, double positiveX, double positiveY, double positiveZ) {
|
||||
if (negativeX == 0.0 && negativeY == 0.0 && negativeZ == 0.0 && positiveX == 0.0 && positiveY == 0.0 && positiveZ == 0.0) {
|
||||
return this;
|
||||
} else {
|
||||
double newMinX = this.minX - negativeX;
|
||||
double newMinY = this.minY - negativeY;
|
||||
double newMinZ = this.minZ - negativeZ;
|
||||
double newMaxX = this.maxX + positiveX;
|
||||
double newMaxY = this.maxY + positiveY;
|
||||
double newMaxZ = this.maxZ + positiveZ;
|
||||
double centerZ;
|
||||
if (newMinX > newMaxX) {
|
||||
centerZ = this.getCenterX();
|
||||
if (newMaxX >= centerZ) {
|
||||
newMinX = newMaxX;
|
||||
} else if (newMinX <= centerZ) {
|
||||
newMaxX = newMinX;
|
||||
} else {
|
||||
newMinX = centerZ;
|
||||
newMaxX = centerZ;
|
||||
}
|
||||
}
|
||||
if (newMinY > newMaxY) {
|
||||
centerZ = this.getCenterY();
|
||||
if (newMaxY >= centerZ) {
|
||||
newMinY = newMaxY;
|
||||
} else if (newMinY <= centerZ) {
|
||||
newMaxY = newMinY;
|
||||
} else {
|
||||
newMinY = centerZ;
|
||||
newMaxY = centerZ;
|
||||
}
|
||||
}
|
||||
if (newMinZ > newMaxZ) {
|
||||
centerZ = this.getCenterZ();
|
||||
if (newMaxZ >= centerZ) {
|
||||
newMinZ = newMaxZ;
|
||||
} else if (newMinZ <= centerZ) {
|
||||
newMaxZ = newMinZ;
|
||||
} else {
|
||||
newMinZ = centerZ;
|
||||
newMaxZ = centerZ;
|
||||
}
|
||||
}
|
||||
|
||||
return this.resize(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ);
|
||||
}
|
||||
}
|
||||
|
||||
public BoundingBox expand(double x, double y, double z) {
|
||||
return this.expand(x, y, z, x, y, z);
|
||||
}
|
||||
|
||||
public BoundingBox expand(Vector expansion) {
|
||||
Validate.notNull(expansion, "Expansion is null!");
|
||||
double x = expansion.getX();
|
||||
double y = expansion.getY();
|
||||
double z = expansion.getZ();
|
||||
return this.expand(x, y, z, x, y, z);
|
||||
}
|
||||
|
||||
public BoundingBox expand(double expansion) {
|
||||
return this.expand(expansion, expansion, expansion, expansion, expansion, expansion);
|
||||
}
|
||||
|
||||
public BoundingBox expand(double dirX, double dirY, double dirZ, double expansion) {
|
||||
if (expansion == 0.0) {
|
||||
return this;
|
||||
} else if (dirX == 0.0 && dirY == 0.0 && dirZ == 0.0) {
|
||||
return this;
|
||||
} else {
|
||||
double negativeX = dirX < 0.0 ? -dirX * expansion : 0.0;
|
||||
double negativeY = dirY < 0.0 ? -dirY * expansion : 0.0;
|
||||
double negativeZ = dirZ < 0.0 ? -dirZ * expansion : 0.0;
|
||||
double positiveX = dirX > 0.0 ? dirX * expansion : 0.0;
|
||||
double positiveY = dirY > 0.0 ? dirY * expansion : 0.0;
|
||||
double positiveZ = dirZ > 0.0 ? dirZ * expansion : 0.0;
|
||||
return this.expand(negativeX, negativeY, negativeZ, positiveX, positiveY, positiveZ);
|
||||
}
|
||||
}
|
||||
|
||||
public BoundingBox expand(Vector direction, double expansion) {
|
||||
Validate.notNull(direction, "Direction is null!");
|
||||
return this.expand(direction.getX(), direction.getY(), direction.getZ(), expansion);
|
||||
}
|
||||
|
||||
public BoundingBox expandDirectional(double dirX, double dirY, double dirZ) {
|
||||
return this.expand(dirX, dirY, dirZ, 1.0);
|
||||
}
|
||||
|
||||
public BoundingBox expandDirectional(Vector direction) {
|
||||
Validate.notNull(direction, "Expansion is null!");
|
||||
return this.expand(direction.getX(), direction.getY(), direction.getZ(), 1.0);
|
||||
}
|
||||
|
||||
public BoundingBox union(double posX, double posY, double posZ) {
|
||||
double newMinX = Math.min(this.minX, posX);
|
||||
double newMinY = Math.min(this.minY, posY);
|
||||
double newMinZ = Math.min(this.minZ, posZ);
|
||||
double newMaxX = Math.max(this.maxX, posX);
|
||||
double newMaxY = Math.max(this.maxY, posY);
|
||||
double newMaxZ = Math.max(this.maxZ, posZ);
|
||||
return newMinX == this.minX && newMinY == this.minY && newMinZ == this.minZ && newMaxX == this.maxX && newMaxY == this.maxY && newMaxZ == this.maxZ ? this : this.resize(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ);
|
||||
}
|
||||
|
||||
public BoundingBox union(Vector position) {
|
||||
Validate.notNull(position, "Position is null!");
|
||||
return this.union(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
public BoundingBox union(Location position) {
|
||||
Validate.notNull(position, "Position is null!");
|
||||
return this.union(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
public BoundingBox union(BoundingBox other) {
|
||||
Validate.notNull(other, "Other bounding box is null!");
|
||||
if (this.contains(other)) {
|
||||
return this;
|
||||
} else {
|
||||
double newMinX = Math.min(this.minX, other.minX);
|
||||
double newMinY = Math.min(this.minY, other.minY);
|
||||
double newMinZ = Math.min(this.minZ, other.minZ);
|
||||
double newMaxX = Math.max(this.maxX, other.maxX);
|
||||
double newMaxY = Math.max(this.maxY, other.maxY);
|
||||
double newMaxZ = Math.max(this.maxZ, other.maxZ);
|
||||
return this.resize(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ);
|
||||
}
|
||||
}
|
||||
|
||||
public BoundingBox intersection(BoundingBox other) {
|
||||
Validate.notNull(other, "Other bounding box is null!");
|
||||
Validate.isTrue(this.overlaps(other), "The bounding boxes do not overlap!");
|
||||
double newMinX = Math.max(this.minX, other.minX);
|
||||
double newMinY = Math.max(this.minY, other.minY);
|
||||
double newMinZ = Math.max(this.minZ, other.minZ);
|
||||
double newMaxX = Math.min(this.maxX, other.maxX);
|
||||
double newMaxY = Math.min(this.maxY, other.maxY);
|
||||
double newMaxZ = Math.min(this.maxZ, other.maxZ);
|
||||
return this.resize(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ);
|
||||
}
|
||||
|
||||
public BoundingBox shift(double shiftX, double shiftY, double shiftZ) {
|
||||
return shiftX == 0.0 && shiftY == 0.0 && shiftZ == 0.0 ? this : this.resize(this.minX + shiftX, this.minY + shiftY, this.minZ + shiftZ, this.maxX + shiftX, this.maxY + shiftY, this.maxZ + shiftZ);
|
||||
}
|
||||
|
||||
public BoundingBox shift(Vector shift) {
|
||||
Validate.notNull(shift, "Shift is null!");
|
||||
return this.shift(shift.getX(), shift.getY(), shift.getZ());
|
||||
}
|
||||
|
||||
public BoundingBox shift(Location shift) {
|
||||
Validate.notNull(shift, "Shift is null!");
|
||||
return this.shift(shift.getX(), shift.getY(), shift.getZ());
|
||||
}
|
||||
|
||||
private boolean overlaps(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
return this.minX < maxX && this.maxX > minX && this.minY < maxY && this.maxY > minY && this.minZ < maxZ && this.maxZ > minZ;
|
||||
}
|
||||
|
||||
public boolean overlaps(BoundingBox other) {
|
||||
Validate.notNull(other, "Other bounding box is null!");
|
||||
return this.overlaps(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ);
|
||||
}
|
||||
|
||||
public boolean overlaps(Vector min, Vector max) {
|
||||
Validate.notNull(min, "Min is null!");
|
||||
Validate.notNull(max, "Max is null!");
|
||||
double x1 = min.getX();
|
||||
double y1 = min.getY();
|
||||
double z1 = min.getZ();
|
||||
double x2 = max.getX();
|
||||
double y2 = max.getY();
|
||||
double z2 = max.getZ();
|
||||
return this.overlaps(Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2), Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2));
|
||||
}
|
||||
|
||||
public boolean contains(double x, double y, double z) {
|
||||
return x >= this.minX && x < this.maxX && y >= this.minY && y < this.maxY && z >= this.minZ && z < this.maxZ;
|
||||
}
|
||||
|
||||
public boolean contains(Vector position) {
|
||||
Validate.notNull(position, "Position is null!");
|
||||
return this.contains(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
private boolean contains(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
return this.minX <= minX && this.maxX >= maxX && this.minY <= minY && this.maxY >= maxY && this.minZ <= minZ && this.maxZ >= maxZ;
|
||||
}
|
||||
|
||||
public boolean contains(BoundingBox other) {
|
||||
Validate.notNull(other, "Other bounding box is null!");
|
||||
return this.contains(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ);
|
||||
}
|
||||
|
||||
public boolean contains(Vector min, Vector max) {
|
||||
Validate.notNull(min, "Min is null!");
|
||||
Validate.notNull(max, "Max is null!");
|
||||
double x1 = min.getX();
|
||||
double y1 = min.getY();
|
||||
double z1 = min.getZ();
|
||||
double x2 = max.getX();
|
||||
double y2 = max.getY();
|
||||
double z2 = max.getZ();
|
||||
return this.contains(Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2), Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
long temp = Double.doubleToLongBits(this.maxX);
|
||||
result = 31 * result + (int) (temp ^ temp >>> 32);
|
||||
temp = Double.doubleToLongBits(this.maxY);
|
||||
result = 31 * result + (int) (temp ^ temp >>> 32);
|
||||
temp = Double.doubleToLongBits(this.maxZ);
|
||||
result = 31 * result + (int) (temp ^ temp >>> 32);
|
||||
temp = Double.doubleToLongBits(this.minX);
|
||||
result = 31 * result + (int) (temp ^ temp >>> 32);
|
||||
temp = Double.doubleToLongBits(this.minY);
|
||||
result = 31 * result + (int) (temp ^ temp >>> 32);
|
||||
temp = Double.doubleToLongBits(this.minZ);
|
||||
result = 31 * result + (int) (temp ^ temp >>> 32);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
} else if (!(obj instanceof BoundingBox)) {
|
||||
return false;
|
||||
} else {
|
||||
BoundingBox other = (BoundingBox) obj;
|
||||
if (Double.doubleToLongBits(this.maxX) != Double.doubleToLongBits(other.maxX)) {
|
||||
return false;
|
||||
} else if (Double.doubleToLongBits(this.maxY) != Double.doubleToLongBits(other.maxY)) {
|
||||
return false;
|
||||
} else if (Double.doubleToLongBits(this.maxZ) != Double.doubleToLongBits(other.maxZ)) {
|
||||
return false;
|
||||
} else if (Double.doubleToLongBits(this.minX) != Double.doubleToLongBits(other.minX)) {
|
||||
return false;
|
||||
} else if (Double.doubleToLongBits(this.minY) != Double.doubleToLongBits(other.minY)) {
|
||||
return false;
|
||||
} else {
|
||||
return Double.doubleToLongBits(this.minZ) == Double.doubleToLongBits(other.minZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BoundingBox clone() {
|
||||
try {
|
||||
return (BoundingBox) super.clone();
|
||||
} catch (CloneNotSupportedException var2) {
|
||||
throw new Error(var2);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> serialize() {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("minX", this.minX);
|
||||
result.put("minY", this.minY);
|
||||
result.put("minZ", this.minZ);
|
||||
result.put("maxX", this.maxX);
|
||||
result.put("maxY", this.maxY);
|
||||
result.put("maxZ", this.maxZ);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static BoundingBox deserialize(Map<String, Object> args) {
|
||||
double minX = 0.0;
|
||||
double minY = 0.0;
|
||||
double minZ = 0.0;
|
||||
double maxX = 0.0;
|
||||
double maxY = 0.0;
|
||||
double maxZ = 0.0;
|
||||
if (args.containsKey("minX")) {
|
||||
minX = ((Number) args.get("minX")).doubleValue();
|
||||
}
|
||||
if (args.containsKey("minY")) {
|
||||
minY = ((Number) args.get("minY")).doubleValue();
|
||||
}
|
||||
if (args.containsKey("minZ")) {
|
||||
minZ = ((Number) args.get("minZ")).doubleValue();
|
||||
}
|
||||
if (args.containsKey("maxX")) {
|
||||
maxX = ((Number) args.get("maxX")).doubleValue();
|
||||
}
|
||||
if (args.containsKey("maxY")) {
|
||||
maxY = ((Number) args.get("maxY")).doubleValue();
|
||||
}
|
||||
if (args.containsKey("maxZ")) {
|
||||
maxZ = ((Number) args.get("maxZ")).doubleValue();
|
||||
}
|
||||
return new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
}
|
||||
@ -1,170 +0,0 @@
|
||||
package cn.forevermc.spigot.core.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 可交互消息,发送给玩家可操作的消息
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-09-04 14:46
|
||||
*/
|
||||
@Data
|
||||
public class InteractiveMsg {
|
||||
|
||||
/** 模板 */
|
||||
private String path;
|
||||
|
||||
/** 模板内容 */
|
||||
private String data;
|
||||
|
||||
/** 行列表 */
|
||||
private List<Line> lineList;
|
||||
|
||||
/**
|
||||
* 换行
|
||||
*
|
||||
* @return 本对象
|
||||
*/
|
||||
public InteractiveMsg breakLine() {
|
||||
return appendLine("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加行
|
||||
*
|
||||
* @param line 行内容
|
||||
* @return 本对象
|
||||
*/
|
||||
public InteractiveMsg appendLine(String line) {
|
||||
return appendLine(new Line(line));
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加行
|
||||
*
|
||||
* @param line 行对象
|
||||
* @return 本对象
|
||||
*/
|
||||
public InteractiveMsg appendLine(Line line) {
|
||||
if (lineList == null) {
|
||||
lineList = new ArrayList<>();
|
||||
}
|
||||
lineList.add(line);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 可交互消息行
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-09-04 14:46
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class Line {
|
||||
|
||||
/** 行内容列表 */
|
||||
private List<Text> textList;
|
||||
|
||||
/** @param text 行内容 */
|
||||
public Line(String text) {
|
||||
appendText(text);
|
||||
}
|
||||
|
||||
/** @param text 行内容对象 */
|
||||
public Line(Text text) {
|
||||
appendText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加行内文本
|
||||
*
|
||||
* @param text 行内文本
|
||||
* @return 行对象
|
||||
*/
|
||||
public Line appendText(String text) {
|
||||
return appendText(new Text(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加行内文本
|
||||
*
|
||||
* @param text 行内文本对象
|
||||
* @return 行对象
|
||||
*/
|
||||
public Line appendText(Text text) {
|
||||
if (textList == null) {
|
||||
textList = new ArrayList<>();
|
||||
}
|
||||
textList.add(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 行内文本
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-09-04 14:46
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class Text {
|
||||
|
||||
/**
|
||||
* 对齐方式
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-09-05 00:34
|
||||
*/
|
||||
public enum Align {
|
||||
|
||||
/** 左对齐 */
|
||||
LEFT,
|
||||
|
||||
/** 居中 */
|
||||
CENTER,
|
||||
|
||||
/** 右对齐 */
|
||||
RIGHT
|
||||
}
|
||||
|
||||
/** 条件 */
|
||||
private String condition;
|
||||
|
||||
/** 字符宽度 */
|
||||
private int width;
|
||||
|
||||
/** 对齐方式 */
|
||||
private Align align = Align.LEFT;
|
||||
|
||||
/** 点击事件 */
|
||||
private ClickEvent.Action action;
|
||||
|
||||
/** 点击事件值 */
|
||||
private String actionValue;
|
||||
|
||||
/** true 为加粗 */
|
||||
private boolean bold;
|
||||
|
||||
/** 指向事件 */
|
||||
private HoverEvent.Action hoverType;
|
||||
|
||||
/** 指向事件值 */
|
||||
private String hoverValue;
|
||||
|
||||
/** 内容 */
|
||||
private String content;
|
||||
|
||||
/** @param content 行内文本 */
|
||||
public Text(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,9 @@
|
||||
package cn.forevermc.spigot.core.bean;
|
||||
|
||||
import cn.forevermc.spigot.core.FMCCore;
|
||||
import cn.forevermc.spigot.core.util.Util;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.imyeyu.inject.annotation.Inject;
|
||||
import com.imyeyu.inject.annotation.StaticInject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
@ -19,13 +18,10 @@ import java.util.UUID;
|
||||
* @author 夜雨
|
||||
* @since 2024-08-29 16:50
|
||||
*/
|
||||
@StaticInject
|
||||
public class NameEntity {
|
||||
|
||||
@Inject
|
||||
private static FMCCore fmcCore;
|
||||
|
||||
/** 实体 UUID */
|
||||
@Getter
|
||||
protected String uuid;
|
||||
|
||||
/** 名称 */
|
||||
@ -67,7 +63,7 @@ public class NameEntity {
|
||||
*/
|
||||
public void glowing(int ttl) {
|
||||
entity.setGlowing(true);
|
||||
Bukkit.getScheduler().runTaskLater(fmcCore, () -> entity.setGlowing(false), ttl);
|
||||
Bukkit.getScheduler().runTaskLater(FMCCore.getInstance(), () -> entity.setGlowing(false), ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,7 +101,7 @@ public class NameEntity {
|
||||
|
||||
/** @return 获取实体 */
|
||||
public Entity get() {
|
||||
return Bukkit.getEntity(getUID());
|
||||
return Util.getEntityByUID(getUID());
|
||||
}
|
||||
|
||||
/** @return 实体 UUID */
|
||||
@ -131,9 +127,4 @@ public class NameEntity {
|
||||
this.uuidObj = entity.getUniqueId();
|
||||
this.uuid = this.uuidObj.toString();
|
||||
}
|
||||
|
||||
public String getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,87 +0,0 @@
|
||||
package cn.forevermc.spigot.core.bean;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import com.imyeyu.utils.Calc;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页列表
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-09-16 22:21
|
||||
*/
|
||||
@Data
|
||||
public class PageList<T extends PageList.Item> {
|
||||
|
||||
/** 标题 */
|
||||
private String title;
|
||||
|
||||
/** 当前索引 */
|
||||
private int index = 0;
|
||||
|
||||
/** 单页数量 */
|
||||
private int size = 5;
|
||||
|
||||
/** 总数据列表 */
|
||||
private List<T> items;
|
||||
|
||||
/** 上一页 */
|
||||
public void previous() {
|
||||
index = Math.max(index - 1, 0);
|
||||
}
|
||||
|
||||
/** 下一页 */
|
||||
public void next() {
|
||||
index = Math.min(index + 1, getPages() - 1);
|
||||
}
|
||||
|
||||
/** @return 获取当前分页数据 */
|
||||
public List<T> getIndexItems() {
|
||||
if (items == null) {
|
||||
throw new NullPointerException("not found items");
|
||||
}
|
||||
int fromIndex = index * size;
|
||||
return items.subList(fromIndex, Math.min(fromIndex + size, items.size()));
|
||||
}
|
||||
|
||||
/** @return 页面数量 */
|
||||
public int getPages() {
|
||||
return Calc.ceil(1D * items.size() / size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现分页的数据对象
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-09-16 23:03
|
||||
*/
|
||||
public interface Item {
|
||||
|
||||
/** @return 数据对象可交互操作列表 */
|
||||
List<ItemAction> pageItemActionList();
|
||||
|
||||
/** @return 数据对象内容 */
|
||||
String pageItemContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据对象可交互操作
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-09-16 23:03
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ItemAction {
|
||||
|
||||
/** 显示名 */
|
||||
private String name;
|
||||
|
||||
/** 点击触发指令 */
|
||||
private String command;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
package cn.forevermc.spigot.core.bean;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -34,6 +35,8 @@ public class Region implements Cloneable {
|
||||
}
|
||||
|
||||
/** 区域顶点 */
|
||||
@Setter
|
||||
@Getter
|
||||
private Location left, right;
|
||||
|
||||
/** 碰撞箱 */
|
||||
@ -173,20 +176,4 @@ public class Region implements Cloneable {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Location getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setLeft(Location left) {
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
public Location getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public void setRight(Location right) {
|
||||
this.right = right;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
package cn.forevermc.spigot.core.command;
|
||||
|
||||
import cn.forevermc.spigot.core.FMCCore;
|
||||
import cn.forevermc.spigot.core.exception.ArgsValueException;
|
||||
import com.imyeyu.inject.annotation.Inject;
|
||||
import com.imyeyu.inject.annotation.StaticInject;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
@ -12,12 +10,12 @@ import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 抽象指令
|
||||
@ -25,16 +23,12 @@ import java.util.logging.Logger;
|
||||
* @author 夜雨
|
||||
* @since 2024-08-15 09:59
|
||||
*/
|
||||
@StaticInject
|
||||
public abstract class AbstractCommand {
|
||||
|
||||
@Inject
|
||||
private static Logger log;
|
||||
|
||||
/** 指令参数提示(子级) */
|
||||
protected final Map<Integer, Collection<String>> argsTabCompleterMap = new HashMap<>();
|
||||
|
||||
/** 子级 */ // TODO 不可直接操作,需要使用 register 防止覆盖注册
|
||||
/** 子级 */
|
||||
protected final Map<String, AbstractCommand> childrenCommandMap = new HashMap<>();
|
||||
|
||||
// ---------- 实时参数(每次触发更新) ----------
|
||||
@ -52,11 +46,7 @@ public abstract class AbstractCommand {
|
||||
final void run0(CommandSender sender, String[] args) {
|
||||
this.sender = sender;
|
||||
// 发送对象
|
||||
if (this instanceof ConsolePlayerCommand) {
|
||||
if (sender instanceof Player player && !player.isOp()) {
|
||||
error("没有权限操作");
|
||||
}
|
||||
} else {
|
||||
if (!(this instanceof ConsolePlayerCommand)) {
|
||||
if (this instanceof PlayerCommand && !Player.class.isAssignableFrom(sender.getClass())) {
|
||||
error("不允许的执行对象");
|
||||
} else {
|
||||
@ -90,7 +80,7 @@ public abstract class AbstractCommand {
|
||||
protected abstract void run(String[] args) throws ArgsValueException;
|
||||
|
||||
protected void appendArgsTabCompleter(String... tips) {
|
||||
appendArgsTabCompleter(List.of(tips));
|
||||
appendArgsTabCompleter(Arrays.asList(tips));
|
||||
}
|
||||
|
||||
protected void appendArgsTabCompleter(Collection<String> list) {
|
||||
@ -110,12 +100,13 @@ public abstract class AbstractCommand {
|
||||
}
|
||||
|
||||
protected void msg(Level level, String msg) {
|
||||
if (sender instanceof Player player) {
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
ChatColor color = level == Level.INFO ? ChatColor.GREEN : ChatColor.RED;
|
||||
player.spawnParticle(Particle.SMOKE, new Location(player.getWorld(), 0, 0, 0), 10);
|
||||
player.spawnParticle(Particle.SMOKE_NORMAL, new Location(player.getWorld(), 0, 0, 0), 10);
|
||||
player.sendMessage(color + msg);
|
||||
} else {
|
||||
log.log(level, msg);
|
||||
FMCCore.getInstance().getLogger().log(level, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,12 +115,12 @@ public abstract class AbstractCommand {
|
||||
}
|
||||
|
||||
public final boolean hasChildren() {
|
||||
return TimiJava.isNotEmpty(childrenCommandMap);
|
||||
return !childrenCommandMap.isEmpty();
|
||||
}
|
||||
|
||||
public List<String> getTabCompleterList(CommandSender sender) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if (sender instanceof Player player && !player.isOp()) {
|
||||
if (sender instanceof Player && !sender.isOp()) {
|
||||
for (Map.Entry<String, AbstractCommand> item : childrenCommandMap.entrySet()) {
|
||||
if (!OPCommand.class.isAssignableFrom(item.getValue().getClass())) {
|
||||
result.add(item.getKey());
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
package cn.forevermc.spigot.core.command;
|
||||
|
||||
import com.imyeyu.inject.annotation.Component;
|
||||
|
||||
/**
|
||||
* ForeverMC 指令
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-08-15 10:21
|
||||
*/
|
||||
@Component
|
||||
public class FMCCommand extends AbstractCommand {
|
||||
|
||||
public FMCCommand() {
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
package cn.forevermc.spigot.core.command;
|
||||
|
||||
import cn.forevermc.spigot.core.FMCCore;
|
||||
import com.imyeyu.inject.annotation.Component;
|
||||
import com.imyeyu.inject.annotation.Inject;
|
||||
import com.imyeyu.inject.annotation.InvokeForInjected;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -13,7 +9,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 指令执行器
|
||||
@ -21,30 +17,20 @@ import java.util.logging.Logger;
|
||||
* @author 夜雨
|
||||
* @since 2024-08-15 19:39
|
||||
*/
|
||||
@Component
|
||||
public class FMCCommandExecutor implements CommandExecutor {
|
||||
|
||||
@Inject
|
||||
private Logger log;
|
||||
|
||||
@Inject
|
||||
private FMCCore fmcCore;
|
||||
|
||||
@Inject
|
||||
private FMCCommand fmcCommand;
|
||||
|
||||
@InvokeForInjected
|
||||
private void injected() {
|
||||
public FMCCommandExecutor() {
|
||||
FMCCore fmcCore = FMCCore.getInstance();
|
||||
// 指令提示
|
||||
Objects.requireNonNull(fmcCore.getCommand("fmc")).setTabCompleter((sender, command, label, args) -> {
|
||||
AbstractCommand cmd = fmcCommand;
|
||||
AbstractCommand cmd = fmcCore.getFmcCommand();
|
||||
int i = 0;
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
while (TimiJava.isNotEmpty(cmd.childrenCommandMap)) {
|
||||
while (!cmd.childrenCommandMap.isEmpty()) {
|
||||
final int j = i;
|
||||
if (i == args.length - 1) {
|
||||
result.addAll(cmd.getTabCompleterList(sender).stream().filter(item -> item.contains(args[j])).toList());
|
||||
result.addAll(cmd.getTabCompleterList(sender).stream().filter(item -> item.contains(args[j])).collect(Collectors.toList()));
|
||||
break;
|
||||
}
|
||||
if (cmd.getCommand(args[i]) == null) {
|
||||
@ -54,11 +40,11 @@ public class FMCCommandExecutor implements CommandExecutor {
|
||||
i++;
|
||||
}
|
||||
// 无子级指令
|
||||
if (TimiJava.isNotEmpty(cmd.argsTabCompleterMap)) {
|
||||
if (!cmd.argsTabCompleterMap.isEmpty()) {
|
||||
Collection<String> argsTabCompleterList = cmd.argsTabCompleterMap.get(args.length - 1 - i);
|
||||
if (argsTabCompleterList != null) {
|
||||
final String key = args[args.length - 1];
|
||||
result.addAll(argsTabCompleterList.stream().filter(item -> item != null && item.contains(key)).toList());
|
||||
result.addAll(argsTabCompleterList.stream().filter(item -> item != null && item.contains(key)).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -68,8 +54,8 @@ public class FMCCommandExecutor implements CommandExecutor {
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
List<String> action = new ArrayList<>();
|
||||
AbstractCommand cmd = fmcCommand;
|
||||
if (TimiJava.isEmpty(args)) {
|
||||
AbstractCommand cmd = FMCCore.getInstance().getFmcCommand();
|
||||
if (args == null || args.length == 0) {
|
||||
cmd.run0(sender, new String[0]);
|
||||
} else {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
package cn.forevermc.spigot.core.exception;
|
||||
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author 夜雨
|
||||
* @since 2024-08-31 00:20
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class ArgsValueException extends Exception {
|
||||
|
||||
public ArgsValueException() {
|
||||
}
|
||||
|
||||
public ArgsValueException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@ -8,8 +8,6 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.imyeyu.inject.annotation.Inject;
|
||||
import com.imyeyu.inject.annotation.StaticInject;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
@ -23,17 +21,13 @@ import java.util.UUID;
|
||||
* @author 夜雨
|
||||
* @since 2024-08-29 10:21
|
||||
*/
|
||||
@StaticInject
|
||||
public class LocationSerializer implements JsonSerializer<Location>, JsonDeserializer<Location> {
|
||||
|
||||
@Inject
|
||||
private static FMCCore fmcCore;
|
||||
|
||||
@Override
|
||||
public Location deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
|
||||
World world = fmcCore.getServer().getWorld(UUID.fromString(obj.get("world").getAsString()));
|
||||
World world = FMCCore.getInstance().getServer().getWorld(UUID.fromString(obj.get("world").getAsString()));
|
||||
Location location = new Location(world, obj.get("x").getAsDouble(), obj.get("y").getAsDouble(), obj.get("z").getAsDouble());
|
||||
location.setYaw(obj.get("yaw").getAsFloat());
|
||||
location.setPitch(obj.get("pitch").getAsFloat());
|
||||
|
||||
@ -9,8 +9,6 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.imyeyu.inject.annotation.Inject;
|
||||
import com.imyeyu.inject.annotation.StaticInject;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
@ -19,27 +17,25 @@ import java.lang.reflect.Type;
|
||||
* @author 夜雨
|
||||
* @since 2024-08-29 10:05
|
||||
*/
|
||||
@StaticInject
|
||||
public class RegionSerializer implements JsonSerializer<Region>, JsonDeserializer<Region> {
|
||||
|
||||
@Inject
|
||||
private static Gson gson;
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
@Override
|
||||
public Region deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
Region region = new Region();
|
||||
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
region.setLeft(gson.fromJson(obj.get("p1"), Location.class));
|
||||
region.setRight(gson.fromJson(obj.get("p2"), Location.class));
|
||||
region.setLeft(GSON.fromJson(obj.get("p1"), Location.class));
|
||||
region.setRight(GSON.fromJson(obj.get("p2"), Location.class));
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Region src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.add("p1", gson.toJsonTree(src.getP1()));
|
||||
obj.add("p2", gson.toJsonTree(src.getP2()));
|
||||
obj.add("p1", GSON.toJsonTree(src.getP1()));
|
||||
obj.add("p2", GSON.toJsonTree(src.getP2()));
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,253 +0,0 @@
|
||||
package cn.forevermc.spigot.core.service;
|
||||
|
||||
import cn.forevermc.spigot.core.FMCCore;
|
||||
import cn.forevermc.spigot.core.bean.InteractiveMsg;
|
||||
import cn.forevermc.spigot.core.bean.PageList;
|
||||
import cn.forevermc.spigot.core.util.FMCUtil;
|
||||
import com.imyeyu.inject.annotation.Inject;
|
||||
import com.imyeyu.inject.annotation.Service;
|
||||
import com.imyeyu.io.IO;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.ref.Ref;
|
||||
import com.imyeyu.utils.StringInterpolator;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author 夜雨
|
||||
* @since 2024-09-04 14:44
|
||||
*/
|
||||
@Service
|
||||
public class InteractiveMsgService {
|
||||
|
||||
public static final String ACTION_CMD_FLAG = "#INTERACTIVE_MSG";
|
||||
|
||||
private static final String TEMPLATE_PATH = "msg_template/";
|
||||
private static final TextComponent BREAK = new TextComponent("\n");
|
||||
private static final StringInterpolator ARG_INTERPOLATOR = new StringInterpolator(StringInterpolator.DOLLAR_OBJ);
|
||||
|
||||
@Inject
|
||||
private FMCCore fmcCore;
|
||||
|
||||
static {
|
||||
ARG_INTERPOLATOR.putFilter("nullable", arg -> {
|
||||
if (TimiJava.isEmpty(arg)) {
|
||||
return "N/A";
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
ARG_INTERPOLATOR.putFilter("command", arg -> {
|
||||
if (TimiJava.isEmpty(arg)) {
|
||||
return "N/A";
|
||||
}
|
||||
return "/" + arg;
|
||||
});
|
||||
}
|
||||
|
||||
private final Map<String, InteractiveMsg> cache;
|
||||
|
||||
public InteractiveMsgService() {
|
||||
cache = new HashMap<>();
|
||||
}
|
||||
|
||||
public InteractiveMsg get(String path) {
|
||||
try {
|
||||
InteractiveMsg interactiveMsg = cache.get(path);
|
||||
if (interactiveMsg == null) {
|
||||
interactiveMsg = build(path);
|
||||
cache.put(path, interactiveMsg);
|
||||
}
|
||||
return interactiveMsg;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("构建模板消息失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends PageList.Item> TextComponent build(PageList<T> pageList) {
|
||||
InteractiveMsg msg = new InteractiveMsg();
|
||||
msg.breakLine().breakLine().breakLine();
|
||||
// 标题
|
||||
msg.appendLine(pageList.getTitle());
|
||||
// 列表
|
||||
{
|
||||
List<T> indexItems = pageList.getIndexItems();
|
||||
for (int i = 0; i < indexItems.size(); i++) {
|
||||
T item = indexItems.get(i);
|
||||
|
||||
InteractiveMsg.Line line = new InteractiveMsg.Line();
|
||||
List<PageList.ItemAction> actionList = item.pageItemActionList();
|
||||
if (TimiJava.isNotEmpty(actionList)) {
|
||||
for (int j = 0; j < actionList.size(); j++) {
|
||||
PageList.ItemAction itemAction = actionList.get(j);
|
||||
|
||||
InteractiveMsg.Line.Text text = new InteractiveMsg.Line.Text();
|
||||
text.setContent(FMCUtil.colorMsg(itemAction.getName()));
|
||||
text.setAction(ClickEvent.Action.RUN_COMMAND);
|
||||
text.setActionValue(itemAction.getCommand());
|
||||
line.appendText(text);
|
||||
}
|
||||
line.appendText(" ");
|
||||
}
|
||||
line.appendText(FMCUtil.colorMsg(item.pageItemContent()));
|
||||
msg.appendLine(line);
|
||||
}
|
||||
// 填充空项
|
||||
for (int i = 0, l = pageList.getSize() - indexItems.size(); i < l; i++) {
|
||||
msg.breakLine();
|
||||
}
|
||||
}
|
||||
// 分页
|
||||
{
|
||||
InteractiveMsg.Line line = new InteractiveMsg.Line();
|
||||
{
|
||||
InteractiveMsg.Line.Text previous = new InteractiveMsg.Line.Text();
|
||||
previous.setContent("&a[上一页]");
|
||||
previous.setAction(ClickEvent.Action.RUN_COMMAND);
|
||||
previous.setActionValue("/fmc page previous");
|
||||
line.appendText(previous);
|
||||
}
|
||||
{
|
||||
InteractiveMsg.Line.Text previous = new InteractiveMsg.Line.Text();
|
||||
previous.setContent("&a[下一页]");
|
||||
previous.setAction(ClickEvent.Action.RUN_COMMAND);
|
||||
previous.setActionValue("/fmc page next");
|
||||
line.appendText(previous);
|
||||
}
|
||||
line.appendText(" [&e%s/%s&f]".formatted(pageList.getIndex() + 1, pageList.getPages()));
|
||||
msg.appendLine(line);
|
||||
}
|
||||
return build(msg, new HashMap<>());
|
||||
}
|
||||
|
||||
public TextComponent build(String path, Map<String, Object> argsMap) {
|
||||
return build(get(path), argsMap);
|
||||
}
|
||||
|
||||
public TextComponent build(InteractiveMsg msg, Map<String, Object> argsMap) {
|
||||
TextComponent textComponent = new TextComponent();
|
||||
List<InteractiveMsg.Line> lineList = msg.getLineList();
|
||||
for (int i = 0; i < lineList.size(); i++) {
|
||||
// 行
|
||||
InteractiveMsg.Line line = lineList.get(i);
|
||||
ComponentBuilder lineBuilder = new ComponentBuilder();
|
||||
|
||||
List<InteractiveMsg.Line.Text> textList = line.getTextList();
|
||||
if (TimiJava.isNotEmpty(textList)) {
|
||||
for (int j = 0; j < textList.size(); j++) {
|
||||
// 行内文本
|
||||
ComponentBuilder textBuilder = new ComponentBuilder();
|
||||
InteractiveMsg.Line.Text text = textList.get(j);
|
||||
if (text.getCondition() != null && !Boolean.parseBoolean(argsMap.get(text.getCondition()).toString())) {
|
||||
// 不符合条件
|
||||
continue;
|
||||
}
|
||||
{
|
||||
// 内容
|
||||
String content = ARG_INTERPOLATOR.inject(text.getContent(), argsMap);
|
||||
if (text.getAlign() != null && content.length() < text.getWidth()) {
|
||||
int totalSpace = text.getWidth() - content.length();
|
||||
content = switch (text.getAlign()) {
|
||||
case LEFT -> com.imyeyu.utils.Text.paddedSpaceEnd(content, text.getWidth());
|
||||
case RIGHT -> com.imyeyu.utils.Text.paddedSpaceStart(content, text.getWidth());
|
||||
case CENTER -> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int k = 0; k < totalSpace; k++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.insert(totalSpace / 2, content);
|
||||
yield sb.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
textBuilder.append(FMCUtil.colorMsg(content));
|
||||
}
|
||||
// 事件
|
||||
if (text.getAction() != null) {
|
||||
String actionValue = ARG_INTERPOLATOR.inject(text.getActionValue(), argsMap);
|
||||
if (text.getAction() == ClickEvent.Action.RUN_COMMAND) {
|
||||
// 追加触发来源标记
|
||||
actionValue += " " + ACTION_CMD_FLAG;
|
||||
}
|
||||
textBuilder.event(new ClickEvent(text.getAction(), actionValue));
|
||||
}
|
||||
// 样式
|
||||
if (text.getHoverType() != null) {
|
||||
HoverEvent event = new HoverEvent(text.getHoverType(), new Text(""));
|
||||
if (Objects.requireNonNull(text.getHoverType()) == HoverEvent.Action.SHOW_TEXT) {
|
||||
event.addContent(new Text(text.getHoverValue()));
|
||||
}
|
||||
textBuilder.event(event);
|
||||
}
|
||||
textBuilder.bold(text.isBold());
|
||||
|
||||
lineBuilder.append(textBuilder.build());
|
||||
}
|
||||
}
|
||||
textComponent.addExtra(lineBuilder.build());
|
||||
if (i != lineList.size() - 1) {
|
||||
textComponent.addExtra(BREAK);
|
||||
}
|
||||
}
|
||||
return textComponent;
|
||||
}
|
||||
|
||||
private InteractiveMsg build(String path) throws DocumentException {
|
||||
InteractiveMsg msg = new InteractiveMsg();
|
||||
msg.breakLine();
|
||||
msg.breakLine();
|
||||
msg.breakLine();
|
||||
|
||||
String data = IO.resourceToString(getClass(), path);
|
||||
msg.setData(data);
|
||||
|
||||
SAXReader reader = new SAXReader();
|
||||
reader.setEntityResolver((publicId, systemId) -> {
|
||||
// 忽略 dtd
|
||||
if (systemId != null && systemId.contains(".dtd")) {
|
||||
return new InputSource(new StringReader(""));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Element root = reader.read(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8))).getRootElement();
|
||||
List<Element> linesEl = root.elements("line");
|
||||
for (int i = 0; i < linesEl.size(); i++) {
|
||||
Element lineEl = linesEl.get(i);
|
||||
|
||||
InteractiveMsg.Line line = new InteractiveMsg.Line();
|
||||
List<Element> textsEl = lineEl.elements("text");
|
||||
for (int j = 0; j < textsEl.size(); j++) {
|
||||
Element textEl = textsEl.get(j);
|
||||
InteractiveMsg.Line.Text text = new InteractiveMsg.Line.Text();
|
||||
text.setCondition(textEl.attributeValue("if"));
|
||||
text.setWidth(Integer.parseInt(TimiJava.firstNotNull(textEl.attributeValue("width"), "-1")));
|
||||
text.setAlign(Ref.toType(InteractiveMsg.Line.Text.Align.class, textEl.attributeValue("align")));
|
||||
text.setAction(Ref.toType(ClickEvent.Action.class, textEl.attributeValue("action")));
|
||||
text.setActionValue(textEl.attributeValue("actionValue"));
|
||||
text.setHoverType(Ref.toType(HoverEvent.Action.class, textEl.attributeValue("hoverType")));
|
||||
text.setHoverValue(textEl.attributeValue("hoverValue"));
|
||||
text.setBold(Boolean.parseBoolean(textEl.attributeValue("bold")));
|
||||
text.setContent(textEl.getText());
|
||||
|
||||
line.appendText(text);
|
||||
}
|
||||
msg.appendLine(line);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
255
src/main/java/cn/forevermc/spigot/core/util/Ref.java
Normal file
255
src/main/java/cn/forevermc/spigot/core/util/Ref.java
Normal file
@ -0,0 +1,255 @@
|
||||
package cn.forevermc.spigot.core.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 反射相关
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2023-05-04 15:05
|
||||
*/
|
||||
public class Ref {
|
||||
|
||||
/**
|
||||
* 获取类字段列表
|
||||
*
|
||||
* @param clazz 类
|
||||
* @return 字段列表
|
||||
*/
|
||||
public static List<Field> listFields(Class<?> clazz) {
|
||||
return listFields(clazz, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类字段列表
|
||||
*
|
||||
* @param clazz 类
|
||||
* @param fieldType 字段类过滤
|
||||
* @return 字段列表
|
||||
*/
|
||||
public static List<Field> listFields(Class<?> clazz, Class<?> fieldType) {
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
if (fieldType == null) {
|
||||
return Arrays.asList(fields);
|
||||
}
|
||||
return Arrays.stream(fields).filter(f -> fieldType.isAssignableFrom(f.getType())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param keyName
|
||||
* @return
|
||||
*/
|
||||
public static String getFieldName(String keyName) {
|
||||
String[] splits = {"-", "_", " "};
|
||||
StringBuilder full = new StringBuilder(keyName.substring(0, 1).toUpperCase() + keyName.substring(1));
|
||||
for (int i = 0; i < splits.length; i++) {
|
||||
if (keyName.contains(splits[i])) {
|
||||
// 存在分隔符
|
||||
full.setLength(0);
|
||||
String[] word = keyName.split(splits[i]);
|
||||
for (int j = 0; j < word.length; j++) {
|
||||
full.append(word[j].substring(0, 1).toUpperCase()).append(word[j].substring(1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return String.valueOf(full.charAt(0)).toLowerCase() + full.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射获取对象字段,包括父级类,直至 {@link Object},如果都不存在则返回 null
|
||||
*
|
||||
* @param clazz 类
|
||||
* @param fieldName 字段名
|
||||
* @return 字段
|
||||
*/
|
||||
public static Field getField(Class<?> clazz, String fieldName) {
|
||||
do {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
} catch (NoSuchFieldException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
} while (clazz != Object.class);
|
||||
throw new NullPointerException(String.format("not found field: %s in %s", fieldName, clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射获取对象字段值,包括父级类,直至 {@link Object}
|
||||
*
|
||||
* @param object 对象
|
||||
* @param fieldName 字段名
|
||||
* @param toClass 返回类
|
||||
* @param <T> 返回类型
|
||||
* @return 字段值
|
||||
* @throws IllegalAccessException 反射访问失败
|
||||
* @throws NullPointerException 向上反射直至 {@link Object} 也找不到该字段
|
||||
*/
|
||||
public static <T> T getFieldValue(Object object, String fieldName, Class<? extends T> toClass) throws IllegalAccessException, NullPointerException {
|
||||
return getFieldValue(object, getField(object.getClass(), fieldName), toClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射获取对象字段值
|
||||
*
|
||||
* @param object 对象
|
||||
* @param field 字段
|
||||
* @param toClass 返回类
|
||||
* @param <T> 返回类型
|
||||
* @return 字段值
|
||||
* @throws IllegalAccessException 反射访问失败
|
||||
* @throws NullPointerException 向上反射直至 {@link Object} 也找不到该字段
|
||||
*/
|
||||
public static <T> T getFieldValue(Object object, Field field, Class<? extends T> toClass) throws IllegalAccessException, NullPointerException {
|
||||
if (field == null) {
|
||||
throw new NullPointerException("field can not be null");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
return toClass.cast(field.get(object));
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射获取类字段
|
||||
*
|
||||
* @param objectClass 类
|
||||
* @param fieldName 字段名
|
||||
* @return 字段
|
||||
*/
|
||||
public static Field getClassField(Class<?> objectClass, String fieldName) {
|
||||
try {
|
||||
Field field = objectClass.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
} catch (NoSuchFieldException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射获取指定类字段值
|
||||
*
|
||||
* @param object 对象
|
||||
* @param objectClass 类
|
||||
* @param fieldName 字段名
|
||||
* @param toClass 值类型
|
||||
* @param <T> 值类型
|
||||
* @return 字段值
|
||||
* @throws IllegalAccessException 反射访问失败
|
||||
* @throws NoSuchFieldException 字段不存在
|
||||
*/
|
||||
public static <T> T getClassFieldValue(Object object, Class<?> objectClass, String fieldName, Class<T> toClass) throws IllegalAccessException, NoSuchFieldException {
|
||||
Field field = getClassField(objectClass, fieldName);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException("not found " + fieldName + " field in " + objectClass.getSimpleName());
|
||||
}
|
||||
field.setAccessible(true);
|
||||
return toClass.cast(field.get(object));
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射设置对象字段值,包括父级类,直至 {@link Object}
|
||||
*
|
||||
* @param object 对象
|
||||
* @param fieldName 字段名
|
||||
* @param value 字段值
|
||||
* @throws IllegalAccessException 反射访问失败
|
||||
* @throws NoSuchFieldException 向上反射直至 {@link Object} 也找不到该字段
|
||||
*/
|
||||
public static void setFieldValue(Object object, String fieldName, Object value) throws IllegalAccessException, NoSuchFieldException {
|
||||
Field field = getField(object.getClass(), fieldName);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException("not found " + fieldName + " field in " + object.getClass().getSimpleName());
|
||||
}
|
||||
setFieldValue(object, field, value);
|
||||
}
|
||||
|
||||
public static void setFieldValue(Object object, Field field, Object value) throws IllegalAccessException {
|
||||
field.setAccessible(true);
|
||||
field.set(object, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射设置对象字段值
|
||||
*
|
||||
* @param object 对象
|
||||
* @param objectClass 类
|
||||
* @param fieldName 字段名
|
||||
* @param value 字段值
|
||||
* @throws IllegalAccessException 反射访问失败
|
||||
* @throws NullPointerException 字段不存在
|
||||
*/
|
||||
public static void setClassFieldValue(Object object, Class<?> objectClass, String fieldName, Object value) throws IllegalAccessException, NullPointerException {
|
||||
Field field = getClassField(objectClass, fieldName);
|
||||
if (field == null) {
|
||||
throw new NullPointerException("not found " + fieldName + " field in " + objectClass.getSimpleName() + " class");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
field.set(object, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射查找方法,包括父级类,直至 {@link Object},如果都不存在则返回 null
|
||||
*
|
||||
* @param clazz 类
|
||||
* @param methodName 方法名
|
||||
* @param parameterTypes 可选参
|
||||
* @return 方法对象
|
||||
*/
|
||||
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
|
||||
if (clazz == null) {
|
||||
throw new NullPointerException("class can not be null");
|
||||
}
|
||||
do {
|
||||
try {
|
||||
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
} while (clazz != Object.class);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转枚举
|
||||
*
|
||||
* @param clazz 枚举类
|
||||
* @param string 字符串
|
||||
* @param <T> 泛型
|
||||
* @return 泛型
|
||||
*/
|
||||
public static <T extends Enum<?>> T toType(Class<T> clazz, String string) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
T[] ts = clazz.getEnumConstants();
|
||||
if (ts == null) {
|
||||
throw new IllegalArgumentException(clazz.getName() + " is not an enum type");
|
||||
}
|
||||
for (int i = 0; i < ts.length; i++) {
|
||||
if (ts[i].name().equalsIgnoreCase(string)) {
|
||||
return ts[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
* @param <T>
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T> T newInstance(Class<T> type) throws Exception {
|
||||
return type.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package cn.forevermc.spigot.core.util;
|
||||
|
||||
import cn.forevermc.spigot.core.exception.ArgsValueException;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import net.objecthunter.exp4j.ExpressionBuilder;
|
||||
import net.objecthunter.exp4j.function.Function;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -23,7 +22,7 @@ import java.util.UUID;
|
||||
* @author 夜雨
|
||||
* @since 2024-08-19 15:05
|
||||
*/
|
||||
public class FMCUtil {
|
||||
public class Util {
|
||||
|
||||
private static final Function EXPRESSION_ROUND = new Function("round") {
|
||||
|
||||
@ -33,6 +32,19 @@ public class FMCUtil {
|
||||
}
|
||||
};
|
||||
|
||||
public static Entity getEntityByUID(UUID uuid) {
|
||||
List<World> worldList = Bukkit.getWorlds();
|
||||
for (int i = 0; i < worldList.size(); i++) {
|
||||
List<Entity> entityList = worldList.get(i).getEntities();
|
||||
for (int j = 0; j < entityList.size(); j++) {
|
||||
if (entityList.get(j).getUniqueId().equals(uuid)) {
|
||||
return entityList.get(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 看向某个位置
|
||||
*
|
||||
@ -78,7 +90,7 @@ public class FMCUtil {
|
||||
* @return
|
||||
*/
|
||||
public static double argExpression(String expression) {
|
||||
return new ExpressionBuilder("round(%s)".formatted(expression)).function(EXPRESSION_ROUND).build().evaluate();
|
||||
return new ExpressionBuilder(String.format("round(%s)", expression)).function(EXPRESSION_ROUND).build().evaluate();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,11 +114,11 @@ public class FMCUtil {
|
||||
*/
|
||||
public static String argsValueRequired(String[] args, int index, String name) throws ArgsValueException {
|
||||
if (args.length - 1 < index) {
|
||||
throw new ArgsValueException("缺少 %s".formatted(name));
|
||||
throw new ArgsValueException(String.format("缺少 %s", name));
|
||||
}
|
||||
String value = args[index];
|
||||
if (TimiJava.isEmpty(value)) {
|
||||
throw new ArgsValueException("缺少 %s".formatted(name));
|
||||
if (value.isEmpty()) {
|
||||
throw new ArgsValueException(String.format("缺少 %s", name));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -123,7 +135,7 @@ public class FMCUtil {
|
||||
return null;
|
||||
}
|
||||
String value = args[index];
|
||||
if (TimiJava.isEmpty(value)) {
|
||||
if (value.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
@ -1,7 +1,7 @@
|
||||
name: fmc-core
|
||||
name: FMCCore
|
||||
version: '0.0.1'
|
||||
main: cn.forevermc.spigot.core.FMCCore
|
||||
api-version: '1.20'
|
||||
api-version: '1.9'
|
||||
|
||||
commands:
|
||||
fmc:
|
||||
|
||||
Reference in New Issue
Block a user