Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24a6f74cc5 |
38
.gitignore
vendored
38
.gitignore
vendored
@ -1,38 +0,0 @@
|
|||||||
target/
|
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea/modules.xml
|
|
||||||
.idea/jarRepositories.xml
|
|
||||||
.idea/compiler.xml
|
|
||||||
.idea/libraries/
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### Eclipse ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
### Mac OS ###
|
|
||||||
.DS_Store
|
|
||||||
4
.idea/.gitignore
generated
vendored
4
.idea/.gitignore
generated
vendored
@ -1,4 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
/CopilotChatHistory.xml
|
|
||||||
7
.idea/encodings.xml
generated
7
.idea/encodings.xml
generated
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Encoding">
|
|
||||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
|
||||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
16
.idea/misc.xml
generated
16
.idea/misc.xml
generated
@ -1,16 +0,0 @@
|
|||||||
<project version="4">
|
|
||||||
<component name="EntryPointsManager">
|
|
||||||
<list size="1">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
|
||||||
</list>
|
|
||||||
</component>
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="MavenProjectsManager">
|
|
||||||
<option name="originalFiles">
|
|
||||||
<list>
|
|
||||||
<option value="$PROJECT_DIR$/pom.xml" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="21" project-jdk-type="JavaSDK" />
|
|
||||||
</project>
|
|
||||||
124
.idea/uiDesigner.xml
generated
124
.idea/uiDesigner.xml
generated
@ -1,124 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Palette2">
|
|
||||||
<group name="Swing">
|
|
||||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="Button" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="RadioButton" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="CheckBox" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="Label" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
|
||||||
<preferred-size width="150" height="-1" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
|
||||||
<preferred-size width="150" height="-1" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
|
||||||
<preferred-size width="150" height="-1" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
|
||||||
<preferred-size width="200" height="200" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
|
||||||
<preferred-size width="200" height="200" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
|
||||||
<preferred-size width="-1" height="20" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
|
||||||
</item>
|
|
||||||
</group>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
86
pom.xml
86
pom.xml
@ -1,86 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>cn.forevermc.spigot</groupId>
|
|
||||||
<artifactId>fmc-core</artifactId>
|
|
||||||
<version>0.0.1+${mc.version}</version>
|
|
||||||
<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>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>spigot-repo</id>
|
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
|
||||||
<version>3.7.1</version>
|
|
||||||
<configuration>
|
|
||||||
<outputDirectory>E:\SpigotMC\test1206\plugins</outputDirectory>
|
|
||||||
<finalName>FMCCore-${version}+${mc.version}.jar</finalName>
|
|
||||||
<descriptorRefs>
|
|
||||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
|
||||||
</descriptorRefs>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>single</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.spigotmc</groupId>
|
|
||||||
<artifactId>spigot-api</artifactId>
|
|
||||||
<version>1.20.6-R0.1-20240613.150924-57</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.imyeyu.inject</groupId>
|
|
||||||
<artifactId>timi-inject</artifactId>
|
|
||||||
<version>0.0.1</version>
|
|
||||||
</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>
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
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 org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
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<>();
|
|
||||||
|
|
||||||
public static <T extends FMCPlugin> void register(T fmcPlugin) {
|
|
||||||
FMC_PLUGIN_LIST.add(fmcPlugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
// 扫描插件
|
|
||||||
TimiInject.run(this);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
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 org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-10-19 16:07
|
|
||||||
*/
|
|
||||||
public abstract class FMCPlugin extends JavaPlugin {
|
|
||||||
|
|
||||||
protected FMCCommand fmcCommand;
|
|
||||||
|
|
||||||
public FMCPlugin() {
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final <T> T loadConfigAs(Class<T> clazz, FileConfiguration config) {
|
|
||||||
try {
|
|
||||||
T t = Ref.newInstance(clazz);
|
|
||||||
deserializeConfig(t, config);
|
|
||||||
return t;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TimiException(TimiCode.ERROR, "deserialize config error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void serializeConfig(Object obj, FileConfiguration config) throws Exception {
|
|
||||||
List<Field> fieldList = Ref.listFields(obj.getClass());
|
|
||||||
for (int i = 0; i < fieldList.size(); i++) {
|
|
||||||
Field field = fieldList.get(i);
|
|
||||||
ConfigPath configPath = field.getAnnotation(ConfigPath.class);
|
|
||||||
if (configPath == null) {
|
|
||||||
serializeConfig(Ref.getFieldValue(obj, field, Object.class), config);
|
|
||||||
} else {
|
|
||||||
if (Map.class.isAssignableFrom(field.getType())) {
|
|
||||||
Map<?, ?> map = Ref.getFieldValue(obj, field, Map.class);
|
|
||||||
map.forEach((key, value) -> config.set(configPath.value() + "." + key.toString(), value));
|
|
||||||
} else {
|
|
||||||
config.set(configPath.value(), Ref.getFieldValue(obj, field, Object.class));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deserializeConfig(Object obj, FileConfiguration config) throws Exception {
|
|
||||||
List<Field> fieldList = Ref.listFields(obj.getClass());
|
|
||||||
for (int i = 0; i < fieldList.size(); i++) {
|
|
||||||
Field field = fieldList.get(i);
|
|
||||||
ConfigPath configPath = field.getAnnotation(ConfigPath.class);
|
|
||||||
if (configPath == null) {
|
|
||||||
Ref.setFieldValue(obj, field, Ref.newInstance(field.getType()));
|
|
||||||
deserializeConfig(field.get(obj), config);
|
|
||||||
} else {
|
|
||||||
String configPathVal = configPath.value();
|
|
||||||
if (Map.class.isAssignableFrom(field.getType())) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
Set<String> keys = config.getKeys(true);
|
|
||||||
for (String key : keys) {
|
|
||||||
if (key.length() != configPathVal.length() && key.startsWith(configPathVal)) {
|
|
||||||
map.put(key.substring(configPathVal.length() + 1), config.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ref.setFieldValue(obj, field, map);
|
|
||||||
} else {
|
|
||||||
Ref.setFieldValue(obj, field, config.get(configPathVal));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.bean;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-01-19 21:57
|
|
||||||
*/
|
|
||||||
@Target(ElementType.FIELD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface ConfigPath {
|
|
||||||
|
|
||||||
String value();
|
|
||||||
}
|
|
||||||
@ -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,139 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.bean;
|
|
||||||
|
|
||||||
import cn.forevermc.spigot.core.FMCCore;
|
|
||||||
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;
|
|
||||||
import org.bukkit.entity.EntityType;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 命名化实体,用于绑定和持久化储存
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-29 16:50
|
|
||||||
*/
|
|
||||||
@StaticInject
|
|
||||||
public class NameEntity {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private static FMCCore fmcCore;
|
|
||||||
|
|
||||||
/** 实体 UUID */
|
|
||||||
protected String uuid;
|
|
||||||
|
|
||||||
/** 名称 */
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
protected String name;
|
|
||||||
|
|
||||||
/** 显示名称 */
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
protected String displayName;
|
|
||||||
|
|
||||||
/** 类型 */
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
protected EntityType type;
|
|
||||||
|
|
||||||
/** 位置 */
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
protected Location location;
|
|
||||||
|
|
||||||
/** true 为启用 */
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
protected boolean enable;
|
|
||||||
|
|
||||||
/** UUID */
|
|
||||||
protected transient UUID uuidObj;
|
|
||||||
|
|
||||||
/** 实体(禁用或未生成时可能不存在) */
|
|
||||||
@Getter
|
|
||||||
protected transient Entity entity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发光
|
|
||||||
*
|
|
||||||
* @param ttl 持续时间(TPS)
|
|
||||||
*/
|
|
||||||
public void glowing(int ttl) {
|
|
||||||
entity.setGlowing(true);
|
|
||||||
Bukkit.getScheduler().runTaskLater(fmcCore, () -> entity.setGlowing(false), ttl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 传送至新的位置
|
|
||||||
*
|
|
||||||
* @param location 位置
|
|
||||||
*/
|
|
||||||
public void teleportTo(Location location) {
|
|
||||||
this.location = location;
|
|
||||||
entity.teleport(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return true 为存活于世界中 */
|
|
||||||
public boolean isAlive() {
|
|
||||||
return get() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 生成实体 */
|
|
||||||
public Entity spawn() {
|
|
||||||
Entity entity = Objects.requireNonNull(location.getWorld()).spawnEntity(location, type);
|
|
||||||
entity.setCustomName(displayName);
|
|
||||||
entity.setCustomNameVisible(true);
|
|
||||||
entity.setInvulnerable(true);
|
|
||||||
this.uuidObj = entity.getUniqueId();
|
|
||||||
this.uuid = uuidObj.toString();
|
|
||||||
this.entity = entity;
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 重新生成 */
|
|
||||||
public Entity respawn() {
|
|
||||||
kill();
|
|
||||||
return spawn();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return 获取实体 */
|
|
||||||
public Entity get() {
|
|
||||||
return Bukkit.getEntity(getUID());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return 实体 UUID */
|
|
||||||
public UUID getUID() {
|
|
||||||
if (uuidObj == null) {
|
|
||||||
uuidObj = UUID.fromString(uuid);
|
|
||||||
}
|
|
||||||
return uuidObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 击杀 */
|
|
||||||
public void kill() {
|
|
||||||
get().remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置实体对象
|
|
||||||
*
|
|
||||||
* @param entity 实体
|
|
||||||
*/
|
|
||||||
public void setEntity(Entity entity) {
|
|
||||||
this.entity = entity;
|
|
||||||
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,192 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.bean;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.util.BoundingBox;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 区域(两点产生的区间,可能是线、面、长方体)
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-19 00:38
|
|
||||||
*/
|
|
||||||
public class Region implements Cloneable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 遍历区域回调
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-19 15:06
|
|
||||||
*/
|
|
||||||
public interface ForEachCallback {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行器
|
|
||||||
*
|
|
||||||
* @param world 世界
|
|
||||||
* @param x X 坐标
|
|
||||||
* @param y Y 坐标
|
|
||||||
* @param z Z 坐标
|
|
||||||
*/
|
|
||||||
void handler(World world, double x, double y, double z);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 区域顶点 */
|
|
||||||
private Location left, right;
|
|
||||||
|
|
||||||
/** 碰撞箱 */
|
|
||||||
private transient BoundingBox boundingBox;
|
|
||||||
|
|
||||||
/** 安全区域(必须已选两点且同一世界) */
|
|
||||||
private void assetSafeLocation() {
|
|
||||||
if (isFull() && !Objects.equals(left.getWorld(), right.getWorld())) {
|
|
||||||
throw new IllegalArgumentException("无法执行:选区不完整或世界不一致");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 遍历区域
|
|
||||||
*
|
|
||||||
* @param callback 遍历回调
|
|
||||||
*/
|
|
||||||
public void forEach(ForEachCallback callback) {
|
|
||||||
final World world = left.getWorld();
|
|
||||||
if (world == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assetSafeLocation();
|
|
||||||
|
|
||||||
final int x1 = left.getBlockX();
|
|
||||||
final int y1 = left.getBlockY();
|
|
||||||
final int z1 = left.getBlockZ();
|
|
||||||
final int x2 = right.getBlockX();
|
|
||||||
final int y2 = right.getBlockY();
|
|
||||||
final int z2 = right.getBlockZ();
|
|
||||||
|
|
||||||
for (int x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) {
|
|
||||||
for (int y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) {
|
|
||||||
for (int z = Math.min(z1, z2); z <= Math.max(z1, z2); z++) {
|
|
||||||
callback.handler(world, x, y, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 坐标是否在区域内
|
|
||||||
*
|
|
||||||
* @param location 位置
|
|
||||||
* @return true 为该坐标在区域内
|
|
||||||
*/
|
|
||||||
public boolean contain(Location location) {
|
|
||||||
return contain(location.getX(), location.getY(), location.getZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 坐标是否在区域内
|
|
||||||
*
|
|
||||||
* @param x X 坐标
|
|
||||||
* @param y Y 坐标
|
|
||||||
* @param z Z 坐标
|
|
||||||
* @return true 为该坐标在区域内
|
|
||||||
*/
|
|
||||||
public boolean contain(double x, double y, double z) {
|
|
||||||
if (!isFull()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
assetSafeLocation();
|
|
||||||
return getBoundingBox().contains(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return 获取区域碰撞箱 */
|
|
||||||
public BoundingBox getBoundingBox() {
|
|
||||||
assetSafeLocation();
|
|
||||||
if (boundingBox == null) {
|
|
||||||
final int x1 = left.getBlockX();
|
|
||||||
final int z1 = left.getBlockZ();
|
|
||||||
final int y1 = left.getBlockY();
|
|
||||||
final int x2 = right.getBlockX();
|
|
||||||
final int y2 = right.getBlockY();
|
|
||||||
final int z2 = right.getBlockZ();
|
|
||||||
|
|
||||||
final double minX = Math.min(x1, x2);
|
|
||||||
final double minY = Math.min(y1, y2);
|
|
||||||
final double minZ = Math.min(z1, z2);
|
|
||||||
final double maxX = Math.max(x1, x2) + .99;
|
|
||||||
final double maxY = Math.max(y1, y2) + .99;
|
|
||||||
final double maxZ = Math.max(z1, z2) + .99;
|
|
||||||
|
|
||||||
boundingBox = new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
|
|
||||||
}
|
|
||||||
return boundingBox;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return true 为没有选择区域 */
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return left == null && right == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return true 为仅选择一点 */
|
|
||||||
public boolean isHalf() {
|
|
||||||
return !isEmpty() && !isFull();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return true 为已选择两点区域 */
|
|
||||||
public boolean isFull() {
|
|
||||||
return left != null && right != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 清空顶点 */
|
|
||||||
public void clear() {
|
|
||||||
left = right = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return 获取顶点 1 */
|
|
||||||
public Location getP1() {
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return 获取顶点 2 */
|
|
||||||
public Location getP2() {
|
|
||||||
return right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return 中间位置 */
|
|
||||||
public Location getCenter() {
|
|
||||||
double centerX = (left.getX() + right.getX()) * .5;
|
|
||||||
double centerY = (left.getY() + right.getY()) * .5;
|
|
||||||
double centerZ = (left.getZ() + right.getZ()) * .5;
|
|
||||||
return new Location(left.getWorld(), centerX, centerY, centerZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return 克隆区域 */
|
|
||||||
@Override
|
|
||||||
public Region clone() {
|
|
||||||
try {
|
|
||||||
Region clone = (Region) super.clone();
|
|
||||||
clone.left = left.clone();
|
|
||||||
clone.right = right.clone();
|
|
||||||
return clone;
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
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,147 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.command;
|
|
||||||
|
|
||||||
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;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 抽象指令
|
|
||||||
*
|
|
||||||
* @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<>();
|
|
||||||
|
|
||||||
// ---------- 实时参数(每次触发更新) ----------
|
|
||||||
|
|
||||||
/** 发送玩家 */
|
|
||||||
protected Player senderPlayer;
|
|
||||||
|
|
||||||
/** 动作 */
|
|
||||||
protected List<String> actionList;
|
|
||||||
|
|
||||||
/** 发送者 */
|
|
||||||
protected CommandSender sender;
|
|
||||||
|
|
||||||
/** 触发指令,由 {@link FMCCommandExecutor} 调度 */
|
|
||||||
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 PlayerCommand && !Player.class.isAssignableFrom(sender.getClass())) {
|
|
||||||
error("不允许的执行对象");
|
|
||||||
} else {
|
|
||||||
senderPlayer = (Player) sender;
|
|
||||||
// 权限
|
|
||||||
if (this instanceof OPCommand && !senderPlayer.isOp()) {
|
|
||||||
error("没有权限操作");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this instanceof ConsoleCommand && !ConsoleCommandSender.class.isAssignableFrom(sender.getClass())) {
|
|
||||||
error("不允许的执行对象");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 触发
|
|
||||||
try {
|
|
||||||
run(args);
|
|
||||||
} catch (ArgsValueException e) {
|
|
||||||
error("参数错误:" + e.getMessage());
|
|
||||||
} catch (Exception e) {
|
|
||||||
error("执行错误:" + e.getMessage());
|
|
||||||
throw new RuntimeException("exec command error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行指令
|
|
||||||
*
|
|
||||||
* @param args 执行参数
|
|
||||||
*/
|
|
||||||
protected abstract void run(String[] args) throws ArgsValueException;
|
|
||||||
|
|
||||||
protected void appendArgsTabCompleter(String... tips) {
|
|
||||||
appendArgsTabCompleter(List.of(tips));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void appendArgsTabCompleter(Collection<String> list) {
|
|
||||||
argsTabCompleterMap.put(argsTabCompleterMap.size(), list);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putArgsTabCompleter(int index, Collection<String> list) {
|
|
||||||
argsTabCompleterMap.put(index, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void success(String msg) {
|
|
||||||
msg(Level.INFO, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void error(String msg) {
|
|
||||||
msg(Level.WARNING, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void msg(Level level, String msg) {
|
|
||||||
if (sender instanceof Player player) {
|
|
||||||
ChatColor color = level == Level.INFO ? ChatColor.GREEN : ChatColor.RED;
|
|
||||||
player.spawnParticle(Particle.SMOKE, new Location(player.getWorld(), 0, 0, 0), 10);
|
|
||||||
player.sendMessage(color + msg);
|
|
||||||
} else {
|
|
||||||
log.log(level, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractCommand getCommand(String command) {
|
|
||||||
return this.childrenCommandMap.get(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean hasChildren() {
|
|
||||||
return TimiJava.isNotEmpty(childrenCommandMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getTabCompleterList(CommandSender sender) {
|
|
||||||
List<String> result = new ArrayList<>();
|
|
||||||
if (sender instanceof Player player && !player.isOp()) {
|
|
||||||
for (Map.Entry<String, AbstractCommand> item : childrenCommandMap.entrySet()) {
|
|
||||||
if (!OPCommand.class.isAssignableFrom(item.getValue().getClass())) {
|
|
||||||
result.add(item.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.addAll(childrenCommandMap.keySet());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void appendChildren(String name, AbstractCommand command) {
|
|
||||||
childrenCommandMap.put(name, command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.command;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-10-10 14:48
|
|
||||||
*/
|
|
||||||
public abstract class ConsoleCommand extends AbstractCommand {
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.command;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-29 20:40
|
|
||||||
*/
|
|
||||||
public abstract class ConsolePlayerCommand extends AbstractCommand {
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
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() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String[] args) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
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() {
|
|
||||||
// 指令提示
|
|
||||||
Objects.requireNonNull(fmcCore.getCommand("fmc")).setTabCompleter((sender, command, label, args) -> {
|
|
||||||
AbstractCommand cmd = fmcCommand;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
List<String> result = new ArrayList<>();
|
|
||||||
while (TimiJava.isNotEmpty(cmd.childrenCommandMap)) {
|
|
||||||
final int j = i;
|
|
||||||
if (i == args.length - 1) {
|
|
||||||
result.addAll(cmd.getTabCompleterList(sender).stream().filter(item -> item.contains(args[j])).toList());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (cmd.getCommand(args[i]) == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cmd = cmd.getCommand(args[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
// 无子级指令
|
|
||||||
if (TimiJava.isNotEmpty(cmd.argsTabCompleterMap)) {
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
||||||
List<String> action = new ArrayList<>();
|
|
||||||
AbstractCommand cmd = fmcCommand;
|
|
||||||
if (TimiJava.isEmpty(args)) {
|
|
||||||
cmd.run0(sender, new String[0]);
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
|
||||||
if (cmd.hasChildren() && cmd.getCommand(args[i]) != null) {
|
|
||||||
action.add(args[i]);
|
|
||||||
|
|
||||||
cmd = cmd.getCommand(args[i]);
|
|
||||||
if (i == args.length - 1) {
|
|
||||||
String[] subArgs = new String[0];
|
|
||||||
cmd.actionList = action;
|
|
||||||
cmd.run0(sender, subArgs);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 全部视为参数
|
|
||||||
String[] newArgs = new String[args.length - i];
|
|
||||||
System.arraycopy(args, i, newArgs, 0, newArgs.length);
|
|
||||||
cmd.actionList = action;
|
|
||||||
cmd.run0(sender, newArgs);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.command;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-10-10 14:43
|
|
||||||
*/
|
|
||||||
public abstract class OPCommand extends PlayerCommand {
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.command;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-29 20:39
|
|
||||||
*/
|
|
||||||
public abstract class PlayerCommand extends AbstractCommand {
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-31 00:20
|
|
||||||
*/
|
|
||||||
public class ArgsValueException extends Exception {
|
|
||||||
|
|
||||||
public ArgsValueException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArgsValueException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.serializable;
|
|
||||||
|
|
||||||
import cn.forevermc.spigot.core.FMCCore;
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
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;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Location 对象序列化和反序列化
|
|
||||||
*
|
|
||||||
* @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()));
|
|
||||||
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());
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(Location src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
JsonObject obj = new JsonObject();
|
|
||||||
obj.addProperty("world", Objects.requireNonNull(src.getWorld()).getUID().toString());
|
|
||||||
obj.addProperty("x", src.getX());
|
|
||||||
obj.addProperty("y", src.getY());
|
|
||||||
obj.addProperty("z", src.getZ());
|
|
||||||
obj.addProperty("yaw", src.getYaw());
|
|
||||||
obj.addProperty("pitch", src.getPitch());
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
package cn.forevermc.spigot.core.serializable;
|
|
||||||
|
|
||||||
import cn.forevermc.spigot.core.bean.Region;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-29 10:05
|
|
||||||
*/
|
|
||||||
@StaticInject
|
|
||||||
public class RegionSerializer implements JsonSerializer<Region>, JsonDeserializer<Region> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private static Gson 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));
|
|
||||||
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()));
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,151 +0,0 @@
|
|||||||
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;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工具
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-08-19 15:05
|
|
||||||
*/
|
|
||||||
public class FMCUtil {
|
|
||||||
|
|
||||||
private static final Function EXPRESSION_ROUND = new Function("round") {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double apply(double... args) {
|
|
||||||
return BigDecimal.valueOf(args[0]).setScale(4, RoundingMode.HALF_UP).doubleValue();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 看向某个位置
|
|
||||||
*
|
|
||||||
* @param entity
|
|
||||||
* @param lookAt
|
|
||||||
*/
|
|
||||||
public static void lookAt(Entity entity, Location lookAt) {
|
|
||||||
Location loc = entity.getLocation();
|
|
||||||
loc.setDirection(lookAt.toVector().subtract(loc.toVector()).normalize());
|
|
||||||
entity.teleport(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 合并参数
|
|
||||||
*
|
|
||||||
* @param args
|
|
||||||
* @param from
|
|
||||||
* @param to
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String joinArgs(String[] args, int from, int to) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = from; i < to; i++) {
|
|
||||||
sb.append(args[i]).append(' ');
|
|
||||||
}
|
|
||||||
sb.deleteCharAt(sb.length() - 1);
|
|
||||||
if (sb.charAt(0) == '"') {
|
|
||||||
sb.deleteCharAt(0);
|
|
||||||
}
|
|
||||||
if (sb.charAt(sb.length() - 1) == '"') {
|
|
||||||
sb.deleteCharAt(sb.length() - 1);
|
|
||||||
}
|
|
||||||
if (sb.charAt(0) == '/') {
|
|
||||||
sb.deleteCharAt(0);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算表达式
|
|
||||||
*
|
|
||||||
* @param expression
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static double argExpression(String expression) {
|
|
||||||
return new ExpressionBuilder("round(%s)".formatted(expression)).function(EXPRESSION_ROUND).build().evaluate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 颜色消息
|
|
||||||
*
|
|
||||||
* @param msg
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String colorMsg(String msg) {
|
|
||||||
return ChatColor.translateAlternateColorCodes('&', msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取必要参数值
|
|
||||||
*
|
|
||||||
* @param args
|
|
||||||
* @param index
|
|
||||||
* @param name
|
|
||||||
* @return
|
|
||||||
* @throws ArgsValueException
|
|
||||||
*/
|
|
||||||
public static String argsValueRequired(String[] args, int index, String name) throws ArgsValueException {
|
|
||||||
if (args.length - 1 < index) {
|
|
||||||
throw new ArgsValueException("缺少 %s".formatted(name));
|
|
||||||
}
|
|
||||||
String value = args[index];
|
|
||||||
if (TimiJava.isEmpty(value)) {
|
|
||||||
throw new ArgsValueException("缺少 %s".formatted(name));
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取参数值
|
|
||||||
*
|
|
||||||
* @param args
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String argsValue(String[] args, int index) {
|
|
||||||
if (args.length - 1 < index) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String value = args[index];
|
|
||||||
if (TimiJava.isEmpty(value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取玩家看向的实体
|
|
||||||
*
|
|
||||||
* @param player 玩家
|
|
||||||
* @param range 直线范围
|
|
||||||
* @return 实体
|
|
||||||
*/
|
|
||||||
public static Entity getTargetEntity(Player player, double range) {
|
|
||||||
Vector direction = player.getEyeLocation().getDirection();
|
|
||||||
Vector start = player.getEyeLocation().toVector();
|
|
||||||
Vector end = start.add(direction.multiply(range));
|
|
||||||
|
|
||||||
for (Entity entity : player.getWorld().getNearbyEntities(player.getLocation(), range, range, range)) {
|
|
||||||
if (entity.getLocation().toVector().isInAABB(start, end)) {
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
name: fmc-core
|
|
||||||
version: '0.0.1'
|
|
||||||
main: cn.forevermc.spigot.core.FMCCore
|
|
||||||
api-version: '1.20'
|
|
||||||
|
|
||||||
commands:
|
|
||||||
fmc:
|
|
||||||
description: FMC Command
|
|
||||||
usage: "/<command>"
|
|
||||||
Reference in New Issue
Block a user