init
This commit is contained in:
commit
834f535304
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
13
.idea/McLiveAPI.iml
Normal file
13
.idea/McLiveAPI.iml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="minecraft" name="Minecraft">
|
||||||
|
<configuration>
|
||||||
|
<autoDetectTypes>
|
||||||
|
<platformType>SPIGOT</platformType>
|
||||||
|
<platformType>BUNGEECORD</platformType>
|
||||||
|
</autoDetectTypes>
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
</module>
|
12
.idea/artifacts/McLiveAPI.xml
Normal file
12
.idea/artifacts/McLiveAPI.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<component name="ArtifactManager">
|
||||||
|
<artifact type="jar" name="McLiveAPI">
|
||||||
|
<output-path>$PROJECT_DIR$/out/artifacts/McLiveAPI</output-path>
|
||||||
|
<root id="archive" name="McLiveAPI.jar">
|
||||||
|
<element id="module-output" name="McLiveAPI" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/fastjson-2.0.43.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/hutool-all-5.8.23.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/Java-WebSocket-1.5.5.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/protobuf-java-3.25.1.jar" path-in-jar="/" />
|
||||||
|
</root>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
13
.idea/compiler.xml
Normal file
13
.idea/compiler.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<annotationProcessing>
|
||||||
|
<profile name="Maven default annotation processors profile" enabled="true">
|
||||||
|
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||||
|
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||||
|
<outputRelativeToContentRoot value="true" />
|
||||||
|
<module name="McLiveAPI" />
|
||||||
|
</profile>
|
||||||
|
</annotationProcessing>
|
||||||
|
</component>
|
||||||
|
</project>
|
20
.idea/jarRepositories.xml
Normal file
20
.idea/jarRepositories.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RemoteRepositoriesConfiguration">
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="central" />
|
||||||
|
<option name="name" value="Central Repository" />
|
||||||
|
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="central" />
|
||||||
|
<option name="name" value="Maven Central repository" />
|
||||||
|
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="jboss.community" />
|
||||||
|
<option name="name" value="JBoss Community repository" />
|
||||||
|
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||||
|
</remote-repository>
|
||||||
|
</component>
|
||||||
|
</project>
|
20
.idea/misc.xml
Normal file
20
.idea/misc.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EntryPointsManager">
|
||||||
|
<list size="2">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="net.md_5.bungee.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_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?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>
|
12
McLiveAPI.iml
Normal file
12
McLiveAPI.iml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="minecraft" name="Minecraft">
|
||||||
|
<configuration>
|
||||||
|
<autoDetectTypes>
|
||||||
|
<platformType>SPIGOT</platformType>
|
||||||
|
</autoDetectTypes>
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
</module>
|
BIN
lib/BungeeCord.jar
Normal file
BIN
lib/BungeeCord.jar
Normal file
Binary file not shown.
BIN
lib/CDTimeAPI.jar
Normal file
BIN
lib/CDTimeAPI.jar
Normal file
Binary file not shown.
BIN
lib/Java-WebSocket-1.5.5.jar
Normal file
BIN
lib/Java-WebSocket-1.5.5.jar
Normal file
Binary file not shown.
BIN
lib/NBTAPI.jar
Normal file
BIN
lib/NBTAPI.jar
Normal file
Binary file not shown.
BIN
lib/fastjson-2.0.43.jar
Normal file
BIN
lib/fastjson-2.0.43.jar
Normal file
Binary file not shown.
BIN
lib/hutool-all-5.8.23.jar
Normal file
BIN
lib/hutool-all-5.8.23.jar
Normal file
Binary file not shown.
BIN
lib/protobuf-java-3.25.1.jar
Normal file
BIN
lib/protobuf-java-3.25.1.jar
Normal file
Binary file not shown.
BIN
lib/spigot-api-1.18.2.jar
Normal file
BIN
lib/spigot-api-1.18.2.jar
Normal file
Binary file not shown.
BIN
out/artifacts/McLiveAPI/McLiveAPI.jar
Normal file
BIN
out/artifacts/McLiveAPI/McLiveAPI.jar
Normal file
Binary file not shown.
52
pom.xml
Normal file
52
pom.xml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml c="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>org.example</groupId>
|
||||||
|
<artifactId>McLiveAPI</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>16</source>
|
||||||
|
<target>16</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.io.yutian.livemutually.liveroom;
|
||||||
|
|
||||||
|
public interface Chat {
|
||||||
|
|
||||||
|
String content();
|
||||||
|
|
||||||
|
User user();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.io.yutian.livemutually.liveroom;
|
||||||
|
|
||||||
|
public interface Follow {
|
||||||
|
|
||||||
|
User user();
|
||||||
|
|
||||||
|
}
|
11
src/main/java/com/io/yutian/livemutually/liveroom/Gift.java
Normal file
11
src/main/java/com/io/yutian/livemutually/liveroom/Gift.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package com.io.yutian.livemutually.liveroom;
|
||||||
|
|
||||||
|
public interface Gift {
|
||||||
|
|
||||||
|
User user();
|
||||||
|
|
||||||
|
String name();
|
||||||
|
|
||||||
|
long count();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.io.yutian.livemutually.liveroom;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.wss.KSWebSocketClient;
|
||||||
|
import com.io.yutian.mclive.Main;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class KSLiveRoomClient {
|
||||||
|
|
||||||
|
private static final String URL = "ws://localhost:8765";
|
||||||
|
private String roomId;
|
||||||
|
private Map<String, String> headMap = new HashMap<>();
|
||||||
|
private KSWebSocketClient socketClient;
|
||||||
|
private ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
|
public KSLiveRoomClient(String roomId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
headMap.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1");
|
||||||
|
headMap.put("Content-Type", "text/plain;charset=UTF-8");
|
||||||
|
headMap.put("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
|
||||||
|
headMap.put("cookie", "__ac_nonce=0638733a400869171be51");
|
||||||
|
}
|
||||||
|
|
||||||
|
public KSWebSocketClient getSocketClient() {
|
||||||
|
return socketClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openRoom(Player player) throws Exception {
|
||||||
|
URI uri = new URI(URL);
|
||||||
|
KSWebSocketClient ksWebSocketClient = new KSWebSocketClient(player, uri, headMap);
|
||||||
|
socketClient = ksWebSocketClient;
|
||||||
|
Main.LiveRoomClientList.add(ksWebSocketClient);
|
||||||
|
executor.submit(() -> socketClient.run());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
if (socketClient == null || socketClient.isClosed() || socketClient.isClosing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
socketClient.setForcedClose(true);
|
||||||
|
socketClient.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoomId() {
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.io.yutian.livemutually.liveroom;
|
||||||
|
|
||||||
|
public interface Like {
|
||||||
|
|
||||||
|
User user();
|
||||||
|
|
||||||
|
long count();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.io.yutian.livemutually.liveroom;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class LiveRoomWatcher {
|
||||||
|
|
||||||
|
protected Consumer<Chat> chatHandler;
|
||||||
|
protected Consumer<User> userHandler;
|
||||||
|
protected Consumer<Like> likeHandler;
|
||||||
|
protected Consumer<Follow> followHandler;
|
||||||
|
protected Consumer<Gift> giftHandler;
|
||||||
|
|
||||||
|
public final LiveRoomWatcher onChat(Consumer<Chat> handler) {
|
||||||
|
Objects.requireNonNull(handler);
|
||||||
|
this.chatHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final LiveRoomWatcher onUser(Consumer<User> handler) {
|
||||||
|
Objects.requireNonNull(handler);
|
||||||
|
this.userHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final LiveRoomWatcher onLike(Consumer<Like> handler) {
|
||||||
|
Objects.requireNonNull(handler);
|
||||||
|
this.likeHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final LiveRoomWatcher onFollow(Consumer<Follow> handler) {
|
||||||
|
Objects.requireNonNull(handler);
|
||||||
|
this.followHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final LiveRoomWatcher onGift(Consumer<Gift> handler) {
|
||||||
|
Objects.requireNonNull(handler);
|
||||||
|
this.giftHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callChat(Chat chat) {
|
||||||
|
if (chatHandler != null) {
|
||||||
|
chatHandler.accept(chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callUser(User user) {
|
||||||
|
if (userHandler != null) {
|
||||||
|
userHandler.accept(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callLike(Like like) {
|
||||||
|
if (likeHandler != null) {
|
||||||
|
likeHandler.accept(like);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callFollow(Follow follow) {
|
||||||
|
if (followHandler != null) {
|
||||||
|
followHandler.accept(follow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callGift(Gift gift) {
|
||||||
|
if (giftHandler != null) {
|
||||||
|
giftHandler.accept(gift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.io.yutian.livemutually.liveroom;
|
||||||
|
|
||||||
|
public interface User {
|
||||||
|
|
||||||
|
String nickName();
|
||||||
|
|
||||||
|
String avatar();
|
||||||
|
|
||||||
|
}
|
157
src/main/java/com/io/yutian/livemutually/liveroom/新建文本文档.txt
Normal file
157
src/main/java/com/io/yutian/livemutually/liveroom/新建文本文档.txt
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
package com.io.yutian.livemutually.wss;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.KSLiveRoomClient;
|
||||||
|
import com.io.yutian.livemutually.liveroom.LiveRoomWatcher;
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
import com.io.yutian.mclive.Main;
|
||||||
|
import json.JSONObject;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
import org.java_websocket.drafts.Draft_6455;
|
||||||
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class KSWebSocketClient extends WebSocketClient {
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
private LiveRoomWatcher liveRoomWatcher;
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KSWebSocketClient(Player player, URI uri, Map<String, String> httpHeaders) {
|
||||||
|
super(uri, new Draft_6455(), httpHeaders);
|
||||||
|
this.player = player;
|
||||||
|
this.liveRoomWatcher = new KSAPILiveRoomWatcher(player);
|
||||||
|
Bukkit.getConsoleSender().sendMessage("#WebSocketClient 已创建.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(ServerHandshake serverHandshake) {
|
||||||
|
this.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String,String> hashMap = new HashMap<>();
|
||||||
|
@Override
|
||||||
|
public void onMessage(String s) {
|
||||||
|
//if(s.isEmpty()){return;}
|
||||||
|
Bukkit.getConsoleSender().sendMessage("TEST = "+s);
|
||||||
|
Bukkit.getConsoleSender().sendMessage("TEST = "+new JSONObject(s));
|
||||||
|
JSONObject jsonObject = new JSONObject(s);
|
||||||
|
/*String type = jsonObject.getString("type");
|
||||||
|
if (!type.equalsIgnoreCase("liudui")) {
|
||||||
|
if (type.equalsIgnoreCase("礼物")) {
|
||||||
|
String username = jsonObject.getString("昵称");
|
||||||
|
String userpng = jsonObject.getString("头像");
|
||||||
|
if(hashMap.get(userpng) != null){
|
||||||
|
username = hashMap.get(userpng);
|
||||||
|
}
|
||||||
|
String giftname = jsonObject.getString("礼物名称");
|
||||||
|
int amount = jsonObject.getInt("礼物增量");
|
||||||
|
if (amount >= 1){
|
||||||
|
liveRoomWatcher.callGift(new KuaiShouGift(username, giftname, amount));
|
||||||
|
}
|
||||||
|
}else if (type.equalsIgnoreCase("muyu")) {
|
||||||
|
String user = jsonObject.getString("user");
|
||||||
|
int zan = jsonObject.getInt("zan");
|
||||||
|
liveRoomWatcher.callLike(new KuaiShouLike(user, zan));
|
||||||
|
} else if (type.equalsIgnoreCase("点赞")) {
|
||||||
|
String user = jsonObject.getString("昵称");
|
||||||
|
int zan = jsonObject.getInt("点赞次数");
|
||||||
|
liveRoomWatcher.callLike(new KuaiShouLike(user, zan));
|
||||||
|
} else if (type.equalsIgnoreCase("fayan")) {
|
||||||
|
String nickname = jsonObject.getString("nickname");
|
||||||
|
String headurl = jsonObject.getString("headurl");
|
||||||
|
String nr = jsonObject.getString("nr");
|
||||||
|
liveRoomWatcher.callChat(new KuaiShouChat(nickname, nr));
|
||||||
|
} else if (type.equalsIgnoreCase("gift")) {
|
||||||
|
String username = jsonObject.getString("giftusername");
|
||||||
|
String giftpic = jsonObject.getString("giftpic");
|
||||||
|
hashMap.put(giftpic,username);
|
||||||
|
int amount = jsonObject.getInt("liwushuliang");
|
||||||
|
String giftPic2 = jsonObject.getString("liwutupian");
|
||||||
|
String nr = jsonObject.getString("giftnr");
|
||||||
|
String giftname = nr.split("个")[1];
|
||||||
|
} else if (type.equalsIgnoreCase("others")) {
|
||||||
|
String qian = jsonObject.getString("qian");
|
||||||
|
if(qian.contains("欢迎")){
|
||||||
|
String nr = jsonObject.getString("othernr");
|
||||||
|
String userName = nr.split(" 进入")[0];
|
||||||
|
liveRoomWatcher.callUser(new KuaiShouUser(userName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose(int i, String s, boolean b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendVerify() {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("type", "register");
|
||||||
|
KSWebSocketClient.this.send(jsonObject.toString().getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send() {
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!KSWebSocketClient.this.isOpen()) {
|
||||||
|
// Bukkit.getConsoleSender().sendMessage("[直播互动] 心跳检测失败,已自动重连.");
|
||||||
|
// restartReconnectionTimer();
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("type", "heartbeat");
|
||||||
|
KSWebSocketClient.this.send(jsonObject.toString().getBytes());
|
||||||
|
}
|
||||||
|
}.runTaskTimerAsynchronously(Main.plugin, 0L, 10 * 20L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean forcedClose = false;
|
||||||
|
private volatile boolean isReconnecting = false;
|
||||||
|
|
||||||
|
public void setForcedClose(boolean forcedClose) {
|
||||||
|
this.forcedClose = forcedClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restartReconnectionTimer() {
|
||||||
|
new BukkitRunnable() {
|
||||||
|
private int i = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (reconnectBlocking()) {
|
||||||
|
cancel();
|
||||||
|
isReconnecting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (i >= 100) {
|
||||||
|
if (player != null) {
|
||||||
|
player.sendMessage("§c[系统]§a直播间自动重连失败...");
|
||||||
|
}
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimerAsynchronously(Main.plugin, 0L, 5L);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.io.yutian.livemutually.manager;
|
||||||
|
|
||||||
|
import cn.hamster3.cdapi.CDTimeAPI;
|
||||||
|
import com.io.yutian.livemutually.liveroom.KSLiveRoomClient;
|
||||||
|
import com.io.yutian.mclive.*;
|
||||||
|
import com.io.yutian.verify.AESUtil;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class KSLiveRoomManager {
|
||||||
|
|
||||||
|
public static Map<Player, KSLiveRoomClient> liveRoomClientMap = new HashMap<>();
|
||||||
|
|
||||||
|
public static void connect(Player player, String id) {
|
||||||
|
if (isConnected(player)) {
|
||||||
|
disconnect(player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!Pattern.matches("[a-zA-Z0-9_]+", id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String pluginName = Main.configYml.getGameMode();
|
||||||
|
if (AESUtil.isVerifyCheck(player,pluginName,id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CDTimeAPI.setPlayerCD(player.getUniqueId(),"link_live_Cd",1000 * 6);
|
||||||
|
KSLiveRoomClient liveRoomClient = new KSLiveRoomClient(id);
|
||||||
|
try {
|
||||||
|
liveRoomClient.openRoom(player);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
liveRoomClientMap.put(player, liveRoomClient);
|
||||||
|
if (player != null) {
|
||||||
|
player.sendMessage("§c[系统]§a您的直播间: §e" + id + " §a已连接...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KSLiveRoomClient getLiveRoomClient(Player player) {
|
||||||
|
return liveRoomClientMap.get(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isConnected(Player player) {
|
||||||
|
KSLiveRoomClient liveRoomClient = getLiveRoomClient(player);
|
||||||
|
return liveRoomClient != null && liveRoomClient.getSocketClient() != null && liveRoomClient.getSocketClient().isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void disconnect(Player player) {
|
||||||
|
if (!isConnected(player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KSLiveRoomClient liveRoomClient = getLiveRoomClient(player);
|
||||||
|
liveRoomClient.close();
|
||||||
|
if (player != null) {
|
||||||
|
player.sendMessage("§c[系统]§b已断开直播间连接...");
|
||||||
|
}
|
||||||
|
liveRoomClientMap.remove(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.io.yutian.livemutually.wss;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.LiveRoomWatcher;
|
||||||
|
import com.io.yutian.mclive.Main;
|
||||||
|
import com.io.yutian.mclive.event.LiveChatEvents;
|
||||||
|
import com.io.yutian.mclive.event.LiveEnterEvents;
|
||||||
|
import com.io.yutian.mclive.event.LiveGiftEvents;
|
||||||
|
import com.io.yutian.mclive.event.LiveLikeEvents;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class KSAPILiveRoomWatcher extends LiveRoomWatcher {
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
public KSAPILiveRoomWatcher(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
onChat(chat -> {
|
||||||
|
Bukkit.getScheduler().runTask(Main.plugin, ()-> {
|
||||||
|
LiveChatEvents event = new LiveChatEvents(player, chat.user(), chat.content());
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
onUser(user -> {
|
||||||
|
Bukkit.getScheduler().runTask(Main.plugin, ()-> {
|
||||||
|
LiveEnterEvents event = new LiveEnterEvents(player, user);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
onLike(like -> {
|
||||||
|
Bukkit.getScheduler().runTask(Main.plugin, ()-> {
|
||||||
|
LiveLikeEvents event = new LiveLikeEvents(player, like.user(), like.count());
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
onGift(gift -> {
|
||||||
|
String giftName = gift.name();
|
||||||
|
long count = gift.count();
|
||||||
|
String count_color = "§a";
|
||||||
|
if (count >= 1314) {
|
||||||
|
count_color = "§c";
|
||||||
|
} else if (count >= 520) {
|
||||||
|
count_color = "§d";
|
||||||
|
} else if (count >= 188) {
|
||||||
|
count_color = "§e";
|
||||||
|
} else if (count >= 66) {
|
||||||
|
count_color = "§b";
|
||||||
|
}
|
||||||
|
String message = "§6[日志 - 礼物触发] §f"+player.getName()+ " >>> " + gift.user().nickName() + " = §a" + giftName + " 数量: "+count_color + count;
|
||||||
|
Bukkit.getConsoleSender().sendMessage(message);
|
||||||
|
Bukkit.getScheduler().runTask(Main.plugin, () -> {
|
||||||
|
LiveGiftEvents event = new LiveGiftEvents(player, gift.user(), gift.name(), gift.count());
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
package com.io.yutian.livemutually.wss;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.KSLiveRoomClient;
|
||||||
|
import com.io.yutian.livemutually.liveroom.LiveRoomWatcher;
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
import com.io.yutian.mclive.Main;
|
||||||
|
import json.JSONObject;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
import org.java_websocket.drafts.Draft_6455;
|
||||||
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class KSWebSocketClient extends WebSocketClient {
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
private LiveRoomWatcher liveRoomWatcher;
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KSWebSocketClient(Player player, URI uri, Map<String, String> httpHeaders) {
|
||||||
|
super(uri, new Draft_6455(), httpHeaders);
|
||||||
|
this.player = player;
|
||||||
|
this.liveRoomWatcher = new KSAPILiveRoomWatcher(player);
|
||||||
|
Bukkit.getConsoleSender().sendMessage("#WebSocketClient 已创建.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(ServerHandshake serverHandshake) {
|
||||||
|
this.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String,String> hashMap = new HashMap<>();
|
||||||
|
@Override
|
||||||
|
public void onMessage(String s) {
|
||||||
|
//if(s.isEmpty()){return;}
|
||||||
|
Bukkit.getConsoleSender().sendMessage("TEST = "+s);
|
||||||
|
Bukkit.getConsoleSender().sendMessage("TEST = "+new JSONObject(s));
|
||||||
|
JSONObject jsonObject = new JSONObject(s);
|
||||||
|
/*String type = jsonObject.getString("type");
|
||||||
|
if (!type.equalsIgnoreCase("liudui")) {
|
||||||
|
if (type.equalsIgnoreCase("礼物")) {
|
||||||
|
String username = jsonObject.getString("昵称");
|
||||||
|
String userpng = jsonObject.getString("头像");
|
||||||
|
if(hashMap.get(userpng) != null){
|
||||||
|
username = hashMap.get(userpng);
|
||||||
|
}
|
||||||
|
String giftname = jsonObject.getString("礼物名称");
|
||||||
|
int amount = jsonObject.getInt("礼物增量");
|
||||||
|
if (amount >= 1){
|
||||||
|
liveRoomWatcher.callGift(new KuaiShouGift(username, giftname, amount));
|
||||||
|
}
|
||||||
|
}else if (type.equalsIgnoreCase("muyu")) {
|
||||||
|
String user = jsonObject.getString("user");
|
||||||
|
int zan = jsonObject.getInt("zan");
|
||||||
|
liveRoomWatcher.callLike(new KuaiShouLike(user, zan));
|
||||||
|
} else if (type.equalsIgnoreCase("点赞")) {
|
||||||
|
String user = jsonObject.getString("昵称");
|
||||||
|
int zan = jsonObject.getInt("点赞次数");
|
||||||
|
liveRoomWatcher.callLike(new KuaiShouLike(user, zan));
|
||||||
|
} else if (type.equalsIgnoreCase("fayan")) {
|
||||||
|
String nickname = jsonObject.getString("nickname");
|
||||||
|
String headurl = jsonObject.getString("headurl");
|
||||||
|
String nr = jsonObject.getString("nr");
|
||||||
|
liveRoomWatcher.callChat(new KuaiShouChat(nickname, nr));
|
||||||
|
} else if (type.equalsIgnoreCase("gift")) {
|
||||||
|
String username = jsonObject.getString("giftusername");
|
||||||
|
String giftpic = jsonObject.getString("giftpic");
|
||||||
|
hashMap.put(giftpic,username);
|
||||||
|
int amount = jsonObject.getInt("liwushuliang");
|
||||||
|
String giftPic2 = jsonObject.getString("liwutupian");
|
||||||
|
String nr = jsonObject.getString("giftnr");
|
||||||
|
String giftname = nr.split("个")[1];
|
||||||
|
} else if (type.equalsIgnoreCase("others")) {
|
||||||
|
String qian = jsonObject.getString("qian");
|
||||||
|
if(qian.contains("欢迎")){
|
||||||
|
String nr = jsonObject.getString("othernr");
|
||||||
|
String userName = nr.split(" 进入")[0];
|
||||||
|
liveRoomWatcher.callUser(new KuaiShouUser(userName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose(int i, String s, boolean b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendVerify() {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("type", "register");
|
||||||
|
KSWebSocketClient.this.send(jsonObject.toString().getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send() {
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!KSWebSocketClient.this.isOpen()) {
|
||||||
|
// Bukkit.getConsoleSender().sendMessage("[直播互动] 心跳检测失败,已自动重连.");
|
||||||
|
// restartReconnectionTimer();
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("type", "heartbeat");
|
||||||
|
KSWebSocketClient.this.send(jsonObject.toString().getBytes());
|
||||||
|
}
|
||||||
|
}.runTaskTimerAsynchronously(Main.plugin, 0L, 10 * 20L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean forcedClose = false;
|
||||||
|
private volatile boolean isReconnecting = false;
|
||||||
|
|
||||||
|
public void setForcedClose(boolean forcedClose) {
|
||||||
|
this.forcedClose = forcedClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restartReconnectionTimer() {
|
||||||
|
new BukkitRunnable() {
|
||||||
|
private int i = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (reconnectBlocking()) {
|
||||||
|
cancel();
|
||||||
|
isReconnecting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (i >= 100) {
|
||||||
|
if (player != null) {
|
||||||
|
player.sendMessage("§c[系统]§a直播间自动重连失败...");
|
||||||
|
}
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimerAsynchronously(Main.plugin, 0L, 5L);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.io.yutian.livemutually.wss;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.Chat;
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
|
||||||
|
public class KuaiShouChat implements Chat {
|
||||||
|
|
||||||
|
private String userName;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public KuaiShouChat(String userName, String content) {
|
||||||
|
this.userName = userName;
|
||||||
|
this.content = content;
|
||||||
|
this.user = new KuaiShouUser(userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String content() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User user() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.io.yutian.livemutually.wss;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.Gift;
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
|
||||||
|
public class KuaiShouGift implements Gift {
|
||||||
|
|
||||||
|
private String userName;
|
||||||
|
private String giftName;
|
||||||
|
private int amount;
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public KuaiShouGift(String userName, String giftName, int amount) {
|
||||||
|
this.userName = userName;
|
||||||
|
this.giftName = giftName;
|
||||||
|
this.amount = amount;
|
||||||
|
this.user = new KuaiShouUser(userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User user() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return giftName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long count() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.io.yutian.livemutually.wss;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.Like;
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
|
||||||
|
public class KuaiShouLike implements Like {
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
public KuaiShouLike(String nickName, int count) {
|
||||||
|
this.user = new KuaiShouUser(nickName);
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User user() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long count() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.io.yutian.livemutually.wss;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
|
||||||
|
public class KuaiShouUser implements User {
|
||||||
|
|
||||||
|
private String nickName;
|
||||||
|
|
||||||
|
public KuaiShouUser(String nickName) {
|
||||||
|
this.nickName = nickName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String nickName() {
|
||||||
|
return nickName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String avatar() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
76
src/main/java/com/io/yutian/mclive/ConfigYml.java
Normal file
76
src/main/java/com/io/yutian/mclive/ConfigYml.java
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package com.io.yutian.mclive;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class ConfigYml {
|
||||||
|
|
||||||
|
private String GameMode;
|
||||||
|
private boolean MainDebug;
|
||||||
|
private HashMap<String, String> RoomId_Map = new HashMap<>();
|
||||||
|
|
||||||
|
public ConfigYml(FileConfiguration yml) {
|
||||||
|
this.MainDebug = yml.getBoolean("MainDebug");
|
||||||
|
this.GameMode = yml.getString("GameMode");
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§b[整蛊MC直播] §7对接游戏: §e"+ this.GameMode);
|
||||||
|
if (yml.getConfigurationSection("LiveId") != null) {
|
||||||
|
HashMap<String, String> hashMap = new HashMap<>();
|
||||||
|
for (String playName : yml.getConfigurationSection("LiveId").getKeys(false)) {
|
||||||
|
String live_id = yml.getString("LiveId." + playName);
|
||||||
|
hashMap.put(playName, live_id);
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§b[整蛊MC直播] §7主播: §e"+ playName + " - " + live_id);
|
||||||
|
}
|
||||||
|
this.RoomId_Map = hashMap;
|
||||||
|
}
|
||||||
|
int room_size = this.RoomId_Map.size();
|
||||||
|
if (room_size >= 1) {
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§b[整蛊MC直播] §7当前模式: §a单人直播");
|
||||||
|
} else {
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§b[整蛊MC直播] §7当前模式: §c尚未设置ID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReloadConfig() {
|
||||||
|
Main.plugin.reloadConfig();
|
||||||
|
Main.plugin.saveConfig();
|
||||||
|
Main.configYml = new ConfigYml(Main.plugin.getConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveConfigYml() {
|
||||||
|
FileConfiguration yml = Main.plugin.getConfig();
|
||||||
|
yml.set("LiveId", null);
|
||||||
|
for (String playName : getRoomId_Map().keySet()) {
|
||||||
|
yml.set("LiveId." + playName, getRoomId(playName));
|
||||||
|
}
|
||||||
|
Main.plugin.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMainDebug() {return MainDebug;}
|
||||||
|
public void setMainDebug(boolean butt) {
|
||||||
|
FileConfiguration yml = Main.plugin.getConfig();
|
||||||
|
yml.set("MainDebug",butt);
|
||||||
|
Main.plugin.saveConfig();
|
||||||
|
MainDebug = butt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGameMode() {
|
||||||
|
return this.GameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoomId(String a) {
|
||||||
|
if (this.RoomId_Map.get(a) != null) {
|
||||||
|
return getRoomId_Map().get(a);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, String> getRoomId_Map() {
|
||||||
|
return this.RoomId_Map;
|
||||||
|
}
|
||||||
|
public void setRoomId(String playName, String roomId) {
|
||||||
|
this.RoomId_Map.put(playName,roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
src/main/java/com/io/yutian/mclive/LinkRoom.java
Normal file
41
src/main/java/com/io/yutian/mclive/LinkRoom.java
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package com.io.yutian.mclive;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerKickEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
|
||||||
|
|
||||||
|
public class LinkRoom implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onSwap(PlayerSwapHandItemsEvent e) {
|
||||||
|
Player p = e.getPlayer();
|
||||||
|
if (!Main.check_plugin) {
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[系统提示] 当前房间未检测到游戏插件,请检查配置文件.");
|
||||||
|
p.sendMessage("§c[系统]§a游戏设置错误,未检测到游戏插件.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.setCancelled(true);
|
||||||
|
if (p.isSneaking()) {
|
||||||
|
LiveAdminGui.OpenGui(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onQuit(PlayerQuitEvent e){
|
||||||
|
Player player = e.getPlayer();
|
||||||
|
String playName = player.getName();
|
||||||
|
Main.configYml.SaveConfigYml();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onKick(PlayerKickEvent e){
|
||||||
|
Player player = e.getPlayer();
|
||||||
|
String playName = player.getName();
|
||||||
|
Main.configYml.SaveConfigYml();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
231
src/main/java/com/io/yutian/mclive/LiveAdminGui.java
Normal file
231
src/main/java/com/io/yutian/mclive/LiveAdminGui.java
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
package com.io.yutian.mclive;
|
||||||
|
|
||||||
|
import cn.hamster3.cdapi.CDTimeAPI;
|
||||||
|
import com.io.yutian.livemutually.manager.KSLiveRoomManager;
|
||||||
|
import com.io.yutian.livemutually.wss.KSWebSocketClient;
|
||||||
|
import com.io.yutian.mclive.event.ZhuboAPI;
|
||||||
|
import com.io.yutian.verify.AESUtil;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LiveAdminGui implements Listener {
|
||||||
|
|
||||||
|
public static String invTitle = "我的世界整蛊玩法操作界面";
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onclick(InventoryClickEvent e){
|
||||||
|
int rawSlot = e.getRawSlot();
|
||||||
|
Player player = (Player) e.getWhoClicked();
|
||||||
|
String playName = player.getName();
|
||||||
|
Inventory inv = e.getInventory();
|
||||||
|
if(e.getView().getTitle().equalsIgnoreCase(invTitle)){
|
||||||
|
e.setCancelled(true);
|
||||||
|
ItemStack item = e.getCurrentItem();
|
||||||
|
if(item != null && item.getType() == Material.AIR){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(rawSlot == 1){
|
||||||
|
player.closeInventory();
|
||||||
|
if(Main.configYml.getRoomId(playName) == null) {
|
||||||
|
player.sendMessage("§c[系统]§a请输入命令设置直播间ID: §e/mclive 授权号");
|
||||||
|
player.playSound(player.getLocation(), Sound.ENTITY_BLAZE_DEATH,1,1);
|
||||||
|
}else {
|
||||||
|
if (ZhuboAPI.isRoomisConnected(player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(Main.LiveRoomClientList.size() >= 1) {
|
||||||
|
for (KSWebSocketClient socketClient : Main.LiveRoomClientList) {
|
||||||
|
if (socketClient.getPlayer().equals(player)) {
|
||||||
|
if (socketClient.isOpen()) {
|
||||||
|
socketClient.setForcedClose(true);
|
||||||
|
}
|
||||||
|
socketClient.close();
|
||||||
|
KSLiveRoomManager.liveRoomClientMap.remove(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String roomId = Main.configYml.getRoomId(playName);
|
||||||
|
KSLiveRoomManager.connect(player,roomId);
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
loc.getWorld().playEffect(loc, Effect.MOBSPAWNER_FLAMES, 20);
|
||||||
|
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS,1,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(rawSlot == 3){
|
||||||
|
player.closeInventory();
|
||||||
|
player.performCommand("livegift gui");
|
||||||
|
player.sendMessage("§c[系统]§a手持任意物品按住 §eSHIFT+Q §a打开界面");
|
||||||
|
player.playSound(player.getLocation(), Sound.BLOCK_COMPARATOR_CLICK,1,1);
|
||||||
|
}
|
||||||
|
if(rawSlot == 5){
|
||||||
|
player.closeInventory();
|
||||||
|
player.performCommand("gameedit");
|
||||||
|
player.playSound(player.getLocation(), Sound.BLOCK_COMPARATOR_CLICK,1,1);
|
||||||
|
}
|
||||||
|
if(rawSlot == 8){
|
||||||
|
player.closeInventory();
|
||||||
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),"stop");
|
||||||
|
}
|
||||||
|
if(rawSlot == 18){
|
||||||
|
player.closeInventory();
|
||||||
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),"mclive stop");
|
||||||
|
}
|
||||||
|
if(rawSlot == 20){
|
||||||
|
player.closeInventory();
|
||||||
|
if(Main.configYml.getRoomId(playName) == null) {
|
||||||
|
player.sendMessage("§c[系统]§a请输入命令设置直播间ID: §e/mclive 授权号");
|
||||||
|
player.playSound(player.getLocation(), Sound.ENTITY_BLAZE_DEATH,1,1);
|
||||||
|
}else {
|
||||||
|
String roomId = Main.configYml.getRoomId(playName);
|
||||||
|
if (AESUtil.isVerifyCheck(player,Main.configYml.getGameMode(),roomId)) {
|
||||||
|
player.playSound(player.getLocation(), Sound.ENTITY_BLAZE_DEATH,1,1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.sendMessage("§c[系统]§a直播间授权通过,感谢您选择我们的产品.");
|
||||||
|
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP,1,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HashMap<Player,Integer> offline_zhubo = new HashMap<>();
|
||||||
|
|
||||||
|
public static void OpenGui(Player p){
|
||||||
|
Inventory inv = Bukkit.createInventory(null,27,invTitle);
|
||||||
|
inv.setItem(8,Stop_Server());
|
||||||
|
inv.setItem(1,Link_Room(p));
|
||||||
|
inv.setItem(3,Gift_BuChang());
|
||||||
|
inv.setItem(5,Games_Edit());
|
||||||
|
inv.setItem(18,Stop_LiveLink());
|
||||||
|
inv.setItem(20,test_Verify(p));
|
||||||
|
p.openInventory(inv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack Stop_LiveLink(){
|
||||||
|
ItemStack item = new ItemStack(Material.FLINT);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.setDisplayName("§d★ §e断开主播连接");
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
lore.add("§c当出现一个礼物多个效果时点击");
|
||||||
|
lore.add("§b断开后需重新连接直播间");
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7断开连接");
|
||||||
|
meta.setLore(lore);
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
|
||||||
|
meta.setCustomModelData(55);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack Stop_Server(){
|
||||||
|
ItemStack item = new ItemStack(Material.PAPER);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.setDisplayName("§d★ §e重启服务器");
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
lore.add("§c下播后请重启服务器");
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7开始重启");
|
||||||
|
meta.setLore(lore);
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
|
||||||
|
meta.setCustomModelData(55);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ItemStack Gift_BuChang(){
|
||||||
|
ItemStack item = new ItemStack(Material.PAPER);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.setDisplayName("§d★ §e礼物漏刷管理");
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
lore.add("§c手动执行礼物效果");
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7打开界面");
|
||||||
|
meta.setLore(lore);
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
|
||||||
|
meta.setCustomModelData(11);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ItemStack Games_Edit(){
|
||||||
|
ItemStack item = new ItemStack(Material.STONECUTTER);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.setDisplayName("§d★ §e整蛊游戏设置");
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
lore.add("§c设置部分游戏参数");
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7打开界面");
|
||||||
|
meta.setLore(lore);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
public static ItemStack Link_Room(Player p){
|
||||||
|
ItemStack item = new ItemStack(Material.GOLDEN_SWORD);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.setDisplayName("§d★ §a§l连接直播间");
|
||||||
|
if (ZhuboAPI.isRoomisConnected(p)) {
|
||||||
|
meta.setDisplayName("§d★ §c§l断开直播间");
|
||||||
|
}
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
if (ZhuboAPI.isRoomisConnected(p)) {
|
||||||
|
String roomId = Main.configYml.getRoomId(p.getName());
|
||||||
|
lore.add("§d★ §c§l断开直播间");
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§7您的直播间号: §a" + roomId);
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§c★ §6鼠标点击 §7断开直播连接");
|
||||||
|
}else {
|
||||||
|
if (Main.configYml.getRoomId(p.getName()) == null) {
|
||||||
|
lore.add("§c建议开播前通过下方三项");
|
||||||
|
lore.add("§c测试后再开播并连接直播间");
|
||||||
|
lore.add("§7您的直播间号: §9尚未设置");
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7设置直播间");
|
||||||
|
} else {
|
||||||
|
lore.add("§c建议开播前通过下方三项");
|
||||||
|
lore.add("§c测试后再开播并连接直播间");
|
||||||
|
String roomId = Main.configYml.getRoomId(p.getName());
|
||||||
|
lore.add("§7您的直播间号: §a" + roomId);
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7开始连接");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
meta.setLore(lore);
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack test_Verify(Player p){
|
||||||
|
ItemStack item = new ItemStack(Material.IRON_INGOT);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.setDisplayName("§d★ §e直播间授权验证");
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
if(Main.configYml.getRoomId(p.getName()) == null) {
|
||||||
|
lore.add("§7您的直播间号: §9尚未设置");
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7设置直播间");
|
||||||
|
}else{
|
||||||
|
String roomId = Main.configYml.getRoomId(p.getName());
|
||||||
|
lore.add("§7您的直播间号: §a"+roomId);
|
||||||
|
lore.add(" ");
|
||||||
|
lore.add("§b★ §6鼠标点击 §7开始测试");
|
||||||
|
}
|
||||||
|
meta.setLore(lore);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
63
src/main/java/com/io/yutian/mclive/LiveEvent.java
Normal file
63
src/main/java/com/io/yutian/mclive/LiveEvent.java
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package com.io.yutian.mclive;
|
||||||
|
|
||||||
|
import com.io.yutian.mclive.event.*;
|
||||||
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
public class LiveEvent implements Listener {
|
||||||
|
|
||||||
|
private ConfigYml configYml;
|
||||||
|
|
||||||
|
public LiveEvent(ConfigYml configYml){this.configYml = configYml;}
|
||||||
|
@EventHandler
|
||||||
|
public void onGift(LiveGiftEvents e){
|
||||||
|
if (Main.check_plugin) {
|
||||||
|
LiveAdminGui.offline_zhubo.put(e.getPlayer(), 1);
|
||||||
|
String type = "礼物";
|
||||||
|
String audience = e.getUser().nickName();
|
||||||
|
String gift_name = e.getName();
|
||||||
|
long gift_amount = e.getAmount();
|
||||||
|
// Bukkit.getConsoleSender().sendMessage("[直播互动 " + e.getPlayer().getName() + "] 类型: " + type + " 用户: " + audience + " 礼物: " + gift_name + "x" + gift_amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler//关注
|
||||||
|
public void onMcLive(LiveFollowEvents e) {
|
||||||
|
LiveAdminGui.offline_zhubo.put(e.getPlayer(),1);
|
||||||
|
String type = "关注";
|
||||||
|
String audience = e.getUser().nickName();
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[直播互动 "+e.getPlayer().getName()+"] 类型: " + type + " 用户: " + audience);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler//信息
|
||||||
|
public void onMcLive(LiveChatEvents e) {
|
||||||
|
LiveAdminGui.offline_zhubo.put(e.getPlayer(),1);
|
||||||
|
String type = "信息";
|
||||||
|
String audience = e.getUser().nickName();
|
||||||
|
String message = e.getContent();
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[直播互动 "+e.getPlayer().getName()+"] 类型: " + type + " 用户: " + audience + " 信息: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler//点赞
|
||||||
|
public void onGuanzhu(LiveLikeEvents e) {
|
||||||
|
LiveAdminGui.offline_zhubo.put(e.getPlayer(),1);
|
||||||
|
String type = "点赞";
|
||||||
|
String audience = e.getUser().nickName();
|
||||||
|
long gift_amount = e.getCount();
|
||||||
|
// Bukkit.getConsoleSender().sendMessage("[直播互动 "+e.getPlayer().getName()+"] 类型: " + type + " 用户: " + audience + " 次数: " + gift_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler//进入
|
||||||
|
public void onMcLive(LiveEnterEvents e) {
|
||||||
|
Player player = e.getPlayer();
|
||||||
|
LiveAdminGui.offline_zhubo.put(e.getPlayer(),1);
|
||||||
|
String type = "进入";
|
||||||
|
String audience = e.getUser().nickName();
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[直播互动 "+e.getPlayer().getName()+"] 类型: " + type + " 用户: " + audience);
|
||||||
|
player.spigot().sendMessage(ChatMessageType.ACTION_BAR,new TextComponent("§6" + Main.HideName(audience) + "来了"));
|
||||||
|
}
|
||||||
|
}
|
165
src/main/java/com/io/yutian/mclive/Main.java
Normal file
165
src/main/java/com/io/yutian/mclive/Main.java
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
package com.io.yutian.mclive;
|
||||||
|
|
||||||
|
import cn.hamster3.cdapi.CDTimeAPI;
|
||||||
|
import com.io.yutian.livemutually.manager.KSLiveRoomManager;
|
||||||
|
import com.io.yutian.livemutually.wss.KSWebSocketClient;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.*;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class Main extends JavaPlugin {
|
||||||
|
|
||||||
|
public static Main plugin;
|
||||||
|
public static boolean check_plugin = false;
|
||||||
|
public static ConfigYml configYml;
|
||||||
|
public static List<KSWebSocketClient> LiveRoomClientList = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
plugin = this;
|
||||||
|
SendPluginsAuthorMessage(Bukkit.getConsoleSender());
|
||||||
|
saveDefaultConfig();
|
||||||
|
configYml = new ConfigYml(getConfig());
|
||||||
|
getServer().getPluginManager().registerEvents(new LiveAdminGui(),this);
|
||||||
|
getServer().getPluginManager().registerEvents(new LinkRoom(),this);
|
||||||
|
getServer().getPluginManager().registerEvents(new LiveEvent(configYml),this);
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§b[整蛊MC直播] §7当前版本: §ev"+plugin.getDescription().getVersion());
|
||||||
|
Plugin plugin = getServer().getPluginManager().getPlugin(configYml.getGameMode());
|
||||||
|
if (plugin != null) {
|
||||||
|
check_plugin = true;
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§b[整蛊MC直播] §a已激活游戏模式");
|
||||||
|
} else {
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§b[整蛊MC直播] §c未检测到§a<"+configYml.getGameMode()+">§c游戏插件.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String Command, String[] args) {
|
||||||
|
if (Command.equalsIgnoreCase("mclive")) {
|
||||||
|
if (args.length == 0) {
|
||||||
|
sender.sendMessage("");
|
||||||
|
sender.sendMessage("§e------ ====== §6直播弹幕互动 §e====== ------");
|
||||||
|
if (sender instanceof Player) {
|
||||||
|
sender.sendMessage("§2/mclive §e[直播间ID] §f- §2设置直播间");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("§2/mclive §e[主播名] §2<直播间ID> §f- §2设置直播间");
|
||||||
|
}
|
||||||
|
sender.sendMessage("§2/mclive debug §f- §2开启调试模式");
|
||||||
|
sender.sendMessage("§2/mclive reload §f- §2重新载入配置文件");
|
||||||
|
sender.sendMessage("§e------ ====== §6直播弹幕互动 §e====== ------");
|
||||||
|
sender.sendMessage("");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("reload")) {
|
||||||
|
Main.configYml.ReloadConfig();
|
||||||
|
sender.sendMessage("§c[系统]§a配置文件已重载");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("stop")) {
|
||||||
|
KSLiveRoomManager.liveRoomClientMap.clear();
|
||||||
|
for (KSWebSocketClient socketClient : LiveRoomClientList) {
|
||||||
|
if (socketClient.isOpen()) {
|
||||||
|
socketClient.setForcedClose(true);
|
||||||
|
}
|
||||||
|
socketClient.close();
|
||||||
|
}
|
||||||
|
Bukkit.broadcastMessage("§c[系统]§a已断开所有主播的连接.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("debug")) {
|
||||||
|
if (configYml.isMainDebug()) {
|
||||||
|
configYml.setMainDebug(false);
|
||||||
|
sender.sendMessage("§c[系统]§a调试模式: §b已关闭");
|
||||||
|
} else {
|
||||||
|
configYml.setMainDebug(true);
|
||||||
|
sender.sendMessage("§c[系统]§a调试模式: §a已启动");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length == 1 && sender instanceof Player player) {
|
||||||
|
String playName = player.getName();
|
||||||
|
String room_id = args[0];
|
||||||
|
if (!Pattern.matches("[a-zA-Z0-9_]+", room_id)) {
|
||||||
|
sender.sendMessage("§c[系统]§a您的抖音账号参数设置错误,正确示例: §e/mclive 123654789");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Main.configYml.setRoomId(playName, room_id);
|
||||||
|
Main.configYml.SaveConfigYml();
|
||||||
|
sender.sendMessage("§c[系统]§a直播间已设置 §e" + playName + " §a--> §e" + room_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("save")) {
|
||||||
|
Main.configYml.SaveConfigYml();
|
||||||
|
sender.sendMessage("§c[系统]§a配置文件已保存.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length == 2) {
|
||||||
|
String playName = args[0];
|
||||||
|
String room_id = args[1];
|
||||||
|
Main.configYml.setRoomId(playName, room_id);
|
||||||
|
Main.configYml.SaveConfigYml();
|
||||||
|
sender.sendMessage("§c[系统]§a直播间已设置 §e" + playName + " §a--> §e" + room_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendPluginsAuthorMessage(CommandSender sender) {
|
||||||
|
sender.sendMessage(" ");
|
||||||
|
sender.sendMessage("§b ██ ████");
|
||||||
|
sender.sendMessage("§b ██");
|
||||||
|
sender.sendMessage("§b██░███▒ ████ ███ ███ ░████▒ ██");
|
||||||
|
sender.sendMessage("§b███████▒ ████ ██▒▒██ ░██████▒ ██");
|
||||||
|
sender.sendMessage("§b███ ███ ██ ▒████▒ ██▒ ▒██ ██");
|
||||||
|
sender.sendMessage("§b██░ ░██ ██ ████ ████████ ██");
|
||||||
|
sender.sendMessage("§b██ ██ ██ ▒██▒ ████████ ██");
|
||||||
|
sender.sendMessage("§b██░ ░██ ██ ████ ██ ██");
|
||||||
|
sender.sendMessage("§b███ ███ ██ ▒████▒ ███░ ▒█ ██▒");
|
||||||
|
sender.sendMessage("§b███████▒ ████████ ██▒▒██ ░███████ █████");
|
||||||
|
sender.sendMessage("§b██░███▒ ████████ ███ ███ ░█████▒ ░████");
|
||||||
|
sender.sendMessage("§b██");
|
||||||
|
sender.sendMessage("§b█ 弹幕互动引擎 由极光像素工作室提供技术支持!!");
|
||||||
|
sender.sendMessage("§b█ 如有使用问题可联系售后: §d"+getAuthorFile().getString("author"));
|
||||||
|
sender.sendMessage(""+getAuthorFile().getString("linemessage"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FileConfiguration getAuthorFile(){
|
||||||
|
File ShopMenufile = new File("plugins/PluginMetrics", "config.yml");
|
||||||
|
return YamlConfiguration.loadConfiguration(ShopMenufile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String HideName(String audience){
|
||||||
|
if(audience.length() <= 2){
|
||||||
|
return "**";
|
||||||
|
}
|
||||||
|
// 获取第一个和第二个字符
|
||||||
|
char firstChar = audience.charAt(0);
|
||||||
|
char lastChar = audience.charAt(audience.length() - 1);
|
||||||
|
// 构建屏蔽后的字符串
|
||||||
|
StringBuilder maskedString = new StringBuilder();
|
||||||
|
for (int i = 1; i < audience.length() - 1; i++) {
|
||||||
|
maskedString.append('*');
|
||||||
|
}
|
||||||
|
return String.valueOf(firstChar) + maskedString + lastChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTime(String format){
|
||||||
|
Date date = Calendar.getInstance().getTime();
|
||||||
|
SimpleDateFormat datatime = new SimpleDateFormat(format);
|
||||||
|
return datatime.format(date);
|
||||||
|
}
|
||||||
|
}
|
44
src/main/java/com/io/yutian/mclive/event/LiveChatEvents.java
Normal file
44
src/main/java/com/io/yutian/mclive/event/LiveChatEvents.java
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package com.io.yutian.mclive.event;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class LiveChatEvents extends Event {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public LiveChatEvents(Player player, User user, String content) {
|
||||||
|
this.player = player;
|
||||||
|
this.user = user;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.io.yutian.mclive.event;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class LiveEnterEvents extends Event {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public LiveEnterEvents(Player player, User user) {
|
||||||
|
this.player = player;
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.io.yutian.mclive.event;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class LiveFollowEvents extends Event {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public LiveFollowEvents(Player player, User user) {
|
||||||
|
this.player = player;
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/main/java/com/io/yutian/mclive/event/LiveGiftEvents.java
Normal file
50
src/main/java/com/io/yutian/mclive/event/LiveGiftEvents.java
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package com.io.yutian.mclive.event;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class LiveGiftEvents extends Event {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
private String name;
|
||||||
|
private long amount;
|
||||||
|
|
||||||
|
public LiveGiftEvents(Player player, User user, String name, long amount) {
|
||||||
|
this.player = player;
|
||||||
|
this.user = user;
|
||||||
|
this.name = name;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
43
src/main/java/com/io/yutian/mclive/event/LiveLikeEvents.java
Normal file
43
src/main/java/com/io/yutian/mclive/event/LiveLikeEvents.java
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package com.io.yutian.mclive.event;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.liveroom.User;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class LiveLikeEvents extends Event {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
private User user;
|
||||||
|
private long count;
|
||||||
|
|
||||||
|
public LiveLikeEvents(Player player, User user, long count) {
|
||||||
|
this.player = player;
|
||||||
|
this.user = user;
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
src/main/java/com/io/yutian/mclive/event/ZhuboAPI.java
Normal file
12
src/main/java/com/io/yutian/mclive/event/ZhuboAPI.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package com.io.yutian.mclive.event;
|
||||||
|
|
||||||
|
import com.io.yutian.livemutually.manager.KSLiveRoomManager;
|
||||||
|
import com.io.yutian.mclive.Main;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public abstract class ZhuboAPI {
|
||||||
|
// 获取主播的连接状态
|
||||||
|
public static boolean isRoomisConnected(Player zhubo){
|
||||||
|
return KSLiveRoomManager.isConnected(zhubo);
|
||||||
|
}
|
||||||
|
}
|
95
src/main/java/com/io/yutian/verify/AESUtil.java
Normal file
95
src/main/java/com/io/yutian/verify/AESUtil.java
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package com.io.yutian.verify;
|
||||||
|
|
||||||
|
import com.io.yutian.mclive.Main;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class AESUtil {
|
||||||
|
|
||||||
|
private static final String KEY_ALGORITHM = "AES";
|
||||||
|
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
|
||||||
|
|
||||||
|
public static boolean isVerifyCheck(Player p, String pluginName, String roomId){
|
||||||
|
if(!Main.check_plugin){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PluginVerifyResult verifyResult = VerifyHandler.verify("127.0.0.1",pluginName,roomId);
|
||||||
|
if (!verifyResult.equals(PluginVerifyResult.VERIFY_SUCCESS)) {
|
||||||
|
if(verifyResult == PluginVerifyResult.USER_STATE_DISABLE){
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[验证日志 - 拦截] "+p.getName()+" 的直播间授权已到期.");
|
||||||
|
p.sendMessage("§c[系统]§a验证尚未通过,您的直播间授权已到期.");
|
||||||
|
} else
|
||||||
|
if(verifyResult == PluginVerifyResult.FAIL_CODE){
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[验证日志 - 拦截] "+p.getName()+" 的直播间尚未进行授权. "+roomId);
|
||||||
|
p.sendMessage("§c[系统]§a验证尚未通过,直播间§e<"+roomId+">§a尚未进行授权.");
|
||||||
|
} else
|
||||||
|
if(verifyResult == PluginVerifyResult.FAIL_TIMEOUT){
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[验证日志 - 拦截] "+p.getName()+" 的本地网络有问题,无法连接验证服务器.");
|
||||||
|
p.sendMessage("§c[系统]§a验证尚未通过,您当前的网络环境有问题.");
|
||||||
|
} else {
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[验证日志 - 拦截] "+p.getName()+" 的无法通过验证. "+verifyResult);
|
||||||
|
p.sendMessage("§c[系统]§a验证尚未通过,无法连接直播间,请联系管理员。§c§l#" + verifyResult);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAESRandomKey() {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
long randomKey = random.nextLong();
|
||||||
|
return String.valueOf(randomKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encrypt(String content, String key) {
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
|
||||||
|
byte[] byteContent = content.getBytes("utf-8");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));
|
||||||
|
byte[] result = cipher.doFinal(byteContent);
|
||||||
|
return byte2Base64(result);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String decrypt(String content, String key) {
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
|
||||||
|
byte[] result = cipher.doFinal(base642Byte(content));
|
||||||
|
return new String(result, "utf-8");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKeySpec getSecretKey(final String key) {
|
||||||
|
try {
|
||||||
|
KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
|
||||||
|
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
random.setSeed(key.getBytes());
|
||||||
|
kg.init(128, random);
|
||||||
|
SecretKey secretKey = kg.generateKey();
|
||||||
|
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
|
||||||
|
} catch (NoSuchAlgorithmException ex) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String byte2Base64(byte[] bytes) {
|
||||||
|
return Base64.getEncoder().encodeToString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] base642Byte(String base64Key) {
|
||||||
|
return Base64.getDecoder().decode(base64Key);
|
||||||
|
}
|
||||||
|
}
|
16
src/main/java/com/io/yutian/verify/PluginVerifyResult.java
Normal file
16
src/main/java/com/io/yutian/verify/PluginVerifyResult.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package com.io.yutian.verify;
|
||||||
|
|
||||||
|
public enum PluginVerifyResult {
|
||||||
|
|
||||||
|
INVALID_DATA_MISS_PARAMETER,
|
||||||
|
VERIFY_SUCCESS,
|
||||||
|
FAIL_TIMEOUT,
|
||||||
|
FAIL_IP,
|
||||||
|
FAIL_CODE,
|
||||||
|
INVALID_DATA_PLUGIN,
|
||||||
|
PLUGIN_DISABLE,
|
||||||
|
USER_STATE_DISABLE,
|
||||||
|
UNABLE_CONNECT_SERVER,
|
||||||
|
UNKNOWN
|
||||||
|
|
||||||
|
}
|
75
src/main/java/com/io/yutian/verify/VerifyHandler.java
Normal file
75
src/main/java/com/io/yutian/verify/VerifyHandler.java
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package com.io.yutian.verify;
|
||||||
|
|
||||||
|
import json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public class VerifyHandler {
|
||||||
|
|
||||||
|
public static PluginVerifyResult verify(String ip, String pluginName, String sequenceCode) {
|
||||||
|
try {
|
||||||
|
if (ip == null) {
|
||||||
|
return PluginVerifyResult.UNKNOWN;
|
||||||
|
}
|
||||||
|
if (sequenceCode == null || sequenceCode.trim().isEmpty()) {
|
||||||
|
return PluginVerifyResult.FAIL_CODE;
|
||||||
|
}
|
||||||
|
String result = get(pluginName, sequenceCode);
|
||||||
|
PluginVerifyResult pluginVerifyResult = PluginVerifyResult.UNKNOWN;
|
||||||
|
JSONObject jsonObject1 = new JSONObject(result);
|
||||||
|
int code = jsonObject1.getInt("code");
|
||||||
|
if (code == 100) {
|
||||||
|
pluginVerifyResult = PluginVerifyResult.VERIFY_SUCCESS;
|
||||||
|
// APIVerifyHandler.handlerAPI();
|
||||||
|
} else if (code == -1) {
|
||||||
|
pluginVerifyResult = PluginVerifyResult.INVALID_DATA_PLUGIN;
|
||||||
|
} else if (code == -2) {
|
||||||
|
pluginVerifyResult = PluginVerifyResult.FAIL_CODE;
|
||||||
|
} else if (code == -100) {
|
||||||
|
pluginVerifyResult = PluginVerifyResult.USER_STATE_DISABLE;
|
||||||
|
}
|
||||||
|
return pluginVerifyResult;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof SocketTimeoutException) {
|
||||||
|
return PluginVerifyResult.VERIFY_SUCCESS;
|
||||||
|
}
|
||||||
|
return PluginVerifyResult.UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static String getServerIp(){
|
||||||
|
String a = "47.";
|
||||||
|
String b = "111.";
|
||||||
|
String c = "169.";
|
||||||
|
String d = "142";
|
||||||
|
String e = "82";
|
||||||
|
String f = "81";
|
||||||
|
return a+b+c+d+":"+e+f;
|
||||||
|
}
|
||||||
|
private static String get(String plugin, String code) throws Exception {
|
||||||
|
String url = "/verify?plugin="+plugin+"&code="+code;
|
||||||
|
URL realUrl = new URL("http://"+getServerIp()+url);
|
||||||
|
URLConnection connection = realUrl.openConnection();
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setReadTimeout(15000);
|
||||||
|
connection.setRequestProperty("accept", "*/*");
|
||||||
|
connection.setRequestProperty("connection", "Keep-Alive");
|
||||||
|
connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
||||||
|
connection.connect();
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = in.readLine()) != null) {
|
||||||
|
stringBuilder.append(line);
|
||||||
|
}
|
||||||
|
if (in != null) {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1517
src/main/java/json/JSONArray.java
Normal file
1517
src/main/java/json/JSONArray.java
Normal file
File diff suppressed because it is too large
Load Diff
45
src/main/java/json/JSONException.java
Normal file
45
src/main/java/json/JSONException.java
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JSONException is thrown by the JSON.org classes when things are amiss.
|
||||||
|
*
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2015-12-09
|
||||||
|
*/
|
||||||
|
public class JSONException extends RuntimeException {
|
||||||
|
/** Serialization ID */
|
||||||
|
private static final long serialVersionUID = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a JSONException with an explanatory message.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* Detail about the reason for the exception.
|
||||||
|
*/
|
||||||
|
public JSONException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a JSONException with an explanatory message and cause.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* Detail about the reason for the exception.
|
||||||
|
* @param cause
|
||||||
|
* The cause.
|
||||||
|
*/
|
||||||
|
public JSONException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new JSONException with the specified cause.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* The cause.
|
||||||
|
*/
|
||||||
|
public JSONException(final Throwable cause) {
|
||||||
|
super(cause.getMessage(), cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
2647
src/main/java/json/JSONObject.java
Normal file
2647
src/main/java/json/JSONObject.java
Normal file
File diff suppressed because it is too large
Load Diff
293
src/main/java/json/JSONPointer.java
Normal file
293
src/main/java/json/JSONPointer.java
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2002 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JSON Pointer is a simple query language defined for JSON documents by
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
|
||||||
|
*
|
||||||
|
* In a nutshell, JSONPointer allows the user to navigate into a JSON document
|
||||||
|
* using strings, and retrieve targeted objects, like a simple form of XPATH.
|
||||||
|
* Path segments are separated by the '/' char, which signifies the root of
|
||||||
|
* the document when it appears as the first char of the string. Array
|
||||||
|
* elements are navigated using ordinals, counting from 0. JSONPointer strings
|
||||||
|
* may be extended to any arbitrary number of segments. If the navigation
|
||||||
|
* is successful, the matched item is returned. A matched item may be a
|
||||||
|
* JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building
|
||||||
|
* fails, an appropriate exception is thrown. If the navigation fails to find
|
||||||
|
* a match, a JSONPointerException is thrown.
|
||||||
|
*
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2016-05-14
|
||||||
|
*/
|
||||||
|
public class JSONPointer {
|
||||||
|
|
||||||
|
// used for URL encoding and decoding
|
||||||
|
private static final String ENCODING = "utf-8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class allows the user to build a JSONPointer in steps, using
|
||||||
|
* exactly one segment in each step.
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
// Segments for the eventual JSONPointer string
|
||||||
|
private final List<String> refTokens = new ArrayList<String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@code JSONPointer} instance using the tokens previously set using the
|
||||||
|
* {@link #append(String)} method calls.
|
||||||
|
*/
|
||||||
|
public JSONPointer build() {
|
||||||
|
return new JSONPointer(this.refTokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an arbitrary token to the list of reference tokens. It can be any non-null value.
|
||||||
|
*
|
||||||
|
* Unlike in the case of JSON string or URI fragment representation of JSON pointers, the
|
||||||
|
* argument of this method MUST NOT be escaped. If you want to query the property called
|
||||||
|
* {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no
|
||||||
|
* need to escape it as {@code "a~0b"}.
|
||||||
|
*
|
||||||
|
* @param token the new token to be appended to the list
|
||||||
|
* @return {@code this}
|
||||||
|
* @throws NullPointerException if {@code token} is null
|
||||||
|
*/
|
||||||
|
public Builder append(String token) {
|
||||||
|
if (token == null) {
|
||||||
|
throw new NullPointerException("token cannot be null");
|
||||||
|
}
|
||||||
|
this.refTokens.add(token);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an integer to the reference token list. Although not necessarily, mostly this token will
|
||||||
|
* denote an array index.
|
||||||
|
*
|
||||||
|
* @param arrayIndex the array index to be added to the token list
|
||||||
|
* @return {@code this}
|
||||||
|
*/
|
||||||
|
public Builder append(int arrayIndex) {
|
||||||
|
this.refTokens.add(String.valueOf(arrayIndex));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static factory method for {@link Builder}. Example usage:
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* JSONPointer pointer = JSONPointer.builder()
|
||||||
|
* .append("obj")
|
||||||
|
* .append("other~key").append("another/key")
|
||||||
|
* .append("\"")
|
||||||
|
* .append(0)
|
||||||
|
* .build();
|
||||||
|
* </code></pre>
|
||||||
|
*
|
||||||
|
* @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained
|
||||||
|
* {@link Builder#append(String)} calls.
|
||||||
|
*/
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Segments for the JSONPointer string
|
||||||
|
private final List<String> refTokens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-parses and initializes a new {@code JSONPointer} instance. If you want to
|
||||||
|
* evaluate the same JSON Pointer on different JSON documents then it is recommended
|
||||||
|
* to keep the {@code JSONPointer} instances due to performance considerations.
|
||||||
|
*
|
||||||
|
* @param pointer the JSON String or URI Fragment representation of the JSON pointer.
|
||||||
|
* @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer
|
||||||
|
*/
|
||||||
|
public JSONPointer(final String pointer) {
|
||||||
|
if (pointer == null) {
|
||||||
|
throw new NullPointerException("pointer cannot be null");
|
||||||
|
}
|
||||||
|
if (pointer.isEmpty() || pointer.equals("#")) {
|
||||||
|
this.refTokens = Collections.emptyList();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String refs;
|
||||||
|
if (pointer.startsWith("#/")) {
|
||||||
|
refs = pointer.substring(2);
|
||||||
|
try {
|
||||||
|
refs = URLDecoder.decode(refs, ENCODING);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else if (pointer.startsWith("/")) {
|
||||||
|
refs = pointer.substring(1);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'");
|
||||||
|
}
|
||||||
|
this.refTokens = new ArrayList<String>();
|
||||||
|
int slashIdx = -1;
|
||||||
|
int prevSlashIdx = 0;
|
||||||
|
do {
|
||||||
|
prevSlashIdx = slashIdx + 1;
|
||||||
|
slashIdx = refs.indexOf('/', prevSlashIdx);
|
||||||
|
if(prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) {
|
||||||
|
// found 2 slashes in a row ( obj//next )
|
||||||
|
// or single slash at the end of a string ( obj/test/ )
|
||||||
|
this.refTokens.add("");
|
||||||
|
} else if (slashIdx >= 0) {
|
||||||
|
final String token = refs.substring(prevSlashIdx, slashIdx);
|
||||||
|
this.refTokens.add(unescape(token));
|
||||||
|
} else {
|
||||||
|
// last item after separator, or no separator at all.
|
||||||
|
final String token = refs.substring(prevSlashIdx);
|
||||||
|
this.refTokens.add(unescape(token));
|
||||||
|
}
|
||||||
|
} while (slashIdx >= 0);
|
||||||
|
// using split does not take into account consecutive separators or "ending nulls"
|
||||||
|
//for (String token : refs.split("/")) {
|
||||||
|
// this.refTokens.add(unescape(token));
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONPointer(List<String> refTokens) {
|
||||||
|
this.refTokens = new ArrayList<String>(refTokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String unescape(String token) {
|
||||||
|
return token.replace("~1", "/").replace("~0", "~")
|
||||||
|
.replace("\\\"", "\"")
|
||||||
|
.replace("\\\\", "\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates this JSON Pointer on the given {@code document}. The {@code document}
|
||||||
|
* is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty
|
||||||
|
* JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the
|
||||||
|
* returned value will be {@code document} itself.
|
||||||
|
*
|
||||||
|
* @param document the JSON document which should be the subject of querying.
|
||||||
|
* @return the result of the evaluation
|
||||||
|
* @throws JSONPointerException if an error occurs during evaluation
|
||||||
|
*/
|
||||||
|
public Object queryFrom(Object document) throws JSONPointerException {
|
||||||
|
if (this.refTokens.isEmpty()) {
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
Object current = document;
|
||||||
|
for (String token : this.refTokens) {
|
||||||
|
if (current instanceof JSONObject) {
|
||||||
|
current = ((JSONObject) current).opt(unescape(token));
|
||||||
|
} else if (current instanceof JSONArray) {
|
||||||
|
current = readByIndexToken(current, token);
|
||||||
|
} else {
|
||||||
|
throw new JSONPointerException(format(
|
||||||
|
"value [%s] is not an array or object therefore its key %s cannot be resolved", current,
|
||||||
|
token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a JSONArray element by ordinal position
|
||||||
|
* @param current the JSONArray to be evaluated
|
||||||
|
* @param indexToken the array index in string form
|
||||||
|
* @return the matched object. If no matching item is found a
|
||||||
|
* @throws JSONPointerException is thrown if the index is out of bounds
|
||||||
|
*/
|
||||||
|
private static Object readByIndexToken(Object current, String indexToken) throws JSONPointerException {
|
||||||
|
try {
|
||||||
|
int index = Integer.parseInt(indexToken);
|
||||||
|
JSONArray currentArr = (JSONArray) current;
|
||||||
|
if (index >= currentArr.length()) {
|
||||||
|
throw new JSONPointerException(format("index %s is out of bounds - the array has %d elements", indexToken,
|
||||||
|
Integer.valueOf(currentArr.length())));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return currentArr.get(index);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
throw new JSONPointerException("Error reading value at index position " + index, e);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new JSONPointerException(format("%s is not an array index", indexToken), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representing the JSONPointer path value using string
|
||||||
|
* representation
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder rval = new StringBuilder("");
|
||||||
|
for (String token: this.refTokens) {
|
||||||
|
rval.append('/').append(escape(token));
|
||||||
|
}
|
||||||
|
return rval.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes path segment values to an unambiguous form.
|
||||||
|
* The escape char to be inserted is '~'. The chars to be escaped
|
||||||
|
* are ~, which maps to ~0, and /, which maps to ~1. Backslashes
|
||||||
|
* and double quote chars are also escaped.
|
||||||
|
* @param token the JSONPointer segment value to be escaped
|
||||||
|
* @return the escaped value for the token
|
||||||
|
*/
|
||||||
|
private static String escape(String token) {
|
||||||
|
return token.replace("~", "~0")
|
||||||
|
.replace("/", "~1")
|
||||||
|
.replace("\\", "\\\\")
|
||||||
|
.replace("\"", "\\\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representing the JSONPointer path value using URI
|
||||||
|
* fragment identifier representation
|
||||||
|
*/
|
||||||
|
public String toURIFragment() {
|
||||||
|
try {
|
||||||
|
StringBuilder rval = new StringBuilder("#");
|
||||||
|
for (String token : this.refTokens) {
|
||||||
|
rval.append('/').append(URLEncoder.encode(token, ENCODING));
|
||||||
|
}
|
||||||
|
return rval.toString();
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
src/main/java/json/JSONPointerException.java
Normal file
45
src/main/java/json/JSONPointerException.java
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2002 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JSONPointerException is thrown by {@link JSONPointer} if an error occurs
|
||||||
|
* during evaluating a pointer.
|
||||||
|
*
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2016-05-13
|
||||||
|
*/
|
||||||
|
public class JSONPointerException extends JSONException {
|
||||||
|
private static final long serialVersionUID = 8872944667561856751L;
|
||||||
|
|
||||||
|
public JSONPointerException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONPointerException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
43
src/main/java/json/JSONPropertyIgnore.java
Normal file
43
src/main/java/json/JSONPropertyIgnore.java
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2018 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Target({METHOD})
|
||||||
|
/**
|
||||||
|
* Use this annotation on a getter method to override the Bean name
|
||||||
|
* parser for Bean -> JSONObject mapping. If this annotation is
|
||||||
|
* present at any level in the class hierarchy, then the method will
|
||||||
|
* not be serialized from the bean into the JSONObject.
|
||||||
|
*/
|
||||||
|
public @interface JSONPropertyIgnore { }
|
47
src/main/java/json/JSONPropertyName.java
Normal file
47
src/main/java/json/JSONPropertyName.java
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2018 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Target({METHOD})
|
||||||
|
/**
|
||||||
|
* Use this annotation on a getter method to override the Bean name
|
||||||
|
* parser for Bean -> JSONObject mapping. A value set to empty string <code>""</code>
|
||||||
|
* will have the Bean parser fall back to the default field name processing.
|
||||||
|
*/
|
||||||
|
public @interface JSONPropertyName {
|
||||||
|
/**
|
||||||
|
* @return The name of the property as to be used in the JSON Object.
|
||||||
|
*/
|
||||||
|
String value();
|
||||||
|
}
|
18
src/main/java/json/JSONString.java
Normal file
18
src/main/java/json/JSONString.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package json;
|
||||||
|
/**
|
||||||
|
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
|
||||||
|
* method so that a class can change the behavior of
|
||||||
|
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
|
||||||
|
* and <code>JSONWriter.value(</code>Object<code>)</code>. The
|
||||||
|
* <code>toJSONString</code> method will be used instead of the default behavior
|
||||||
|
* of using the Object's <code>toString()</code> method and quoting the result.
|
||||||
|
*/
|
||||||
|
public interface JSONString {
|
||||||
|
/**
|
||||||
|
* The <code>toJSONString</code> method allows a class to produce its own JSON
|
||||||
|
* serialization.
|
||||||
|
*
|
||||||
|
* @return A strictly syntactically correct JSON text.
|
||||||
|
*/
|
||||||
|
public String toJSONString();
|
||||||
|
}
|
79
src/main/java/json/JSONStringer.java
Normal file
79
src/main/java/json/JSONStringer.java
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2006 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSONStringer provides a quick and convenient way of producing JSON text.
|
||||||
|
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||||
|
* added, so the results are ready for transmission or storage. Each instance of
|
||||||
|
* JSONStringer can produce one JSON text.
|
||||||
|
* <p>
|
||||||
|
* A JSONStringer instance provides a <code>value</code> method for appending
|
||||||
|
* values to the
|
||||||
|
* text, and a <code>key</code>
|
||||||
|
* method for adding keys before values in objects. There are <code>array</code>
|
||||||
|
* and <code>endArray</code> methods that make and bound array values, and
|
||||||
|
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||||
|
* object values. All of these methods return the JSONWriter instance,
|
||||||
|
* permitting cascade style. For example, <pre>
|
||||||
|
* myString = new JSONStringer()
|
||||||
|
* .object()
|
||||||
|
* .key("JSON")
|
||||||
|
* .value("Hello, World!")
|
||||||
|
* .endObject()
|
||||||
|
* .toString();</pre> which produces the string <pre>
|
||||||
|
* {"JSON":"Hello, World!"}</pre>
|
||||||
|
* <p>
|
||||||
|
* The first method called must be <code>array</code> or <code>object</code>.
|
||||||
|
* There are no methods for adding commas or colons. JSONStringer adds them for
|
||||||
|
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||||
|
* <p>
|
||||||
|
* This can sometimes be easier than using a JSONObject to build a string.
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2015-12-09
|
||||||
|
*/
|
||||||
|
public class JSONStringer extends JSONWriter {
|
||||||
|
/**
|
||||||
|
* Make a fresh JSONStringer. It can be used to build one JSON text.
|
||||||
|
*/
|
||||||
|
public JSONStringer() {
|
||||||
|
super(new StringWriter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the JSON text. This method is used to obtain the product of the
|
||||||
|
* JSONStringer instance. It will return <code>null</code> if there was a
|
||||||
|
* problem in the construction of the JSON text (such as the calls to
|
||||||
|
* <code>array</code> were not properly balanced with calls to
|
||||||
|
* <code>endArray</code>).
|
||||||
|
* @return The JSON text.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.mode == 'd' ? this.writer.toString() : null;
|
||||||
|
}
|
||||||
|
}
|
526
src/main/java/json/JSONTokener.java
Normal file
526
src/main/java/json/JSONTokener.java
Normal file
|
@ -0,0 +1,526 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2002 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JSONTokener takes a source string and extracts characters and tokens from
|
||||||
|
* it. It is used by the JSONObject and JSONArray constructors to parse
|
||||||
|
* JSON source strings.
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2014-05-03
|
||||||
|
*/
|
||||||
|
public class JSONTokener {
|
||||||
|
/** current read character position on the current line. */
|
||||||
|
private long character;
|
||||||
|
/** flag to indicate if the end of the input has been found. */
|
||||||
|
private boolean eof;
|
||||||
|
/** current read index of the input. */
|
||||||
|
private long index;
|
||||||
|
/** current line of the input. */
|
||||||
|
private long line;
|
||||||
|
/** previous character read from the input. */
|
||||||
|
private char previous;
|
||||||
|
/** Reader for the input. */
|
||||||
|
private final Reader reader;
|
||||||
|
/** flag to indicate that a previous character was requested. */
|
||||||
|
private boolean usePrevious;
|
||||||
|
/** the number of characters read in the previous line. */
|
||||||
|
private long characterPreviousLine;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a JSONTokener from a Reader. The caller must close the Reader.
|
||||||
|
*
|
||||||
|
* @param reader A reader.
|
||||||
|
*/
|
||||||
|
public JSONTokener(Reader reader) {
|
||||||
|
this.reader = reader.markSupported()
|
||||||
|
? reader
|
||||||
|
: new BufferedReader(reader);
|
||||||
|
this.eof = false;
|
||||||
|
this.usePrevious = false;
|
||||||
|
this.previous = 0;
|
||||||
|
this.index = 0;
|
||||||
|
this.character = 1;
|
||||||
|
this.characterPreviousLine = 0;
|
||||||
|
this.line = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a JSONTokener from an InputStream. The caller must close the input stream.
|
||||||
|
* @param inputStream The source.
|
||||||
|
*/
|
||||||
|
public JSONTokener(InputStream inputStream) {
|
||||||
|
this(new InputStreamReader(inputStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a JSONTokener from a string.
|
||||||
|
*
|
||||||
|
* @param s A source string.
|
||||||
|
*/
|
||||||
|
public JSONTokener(String s) {
|
||||||
|
this(new StringReader(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Back up one character. This provides a sort of lookahead capability,
|
||||||
|
* so that you can test for a digit or letter before attempting to parse
|
||||||
|
* the next number or identifier.
|
||||||
|
* @throws JSONException Thrown if trying to step back more than 1 step
|
||||||
|
* or if already at the start of the string
|
||||||
|
*/
|
||||||
|
public void back() throws JSONException {
|
||||||
|
if (this.usePrevious || this.index <= 0) {
|
||||||
|
throw new JSONException("Stepping back two steps is not supported");
|
||||||
|
}
|
||||||
|
this.decrementIndexes();
|
||||||
|
this.usePrevious = true;
|
||||||
|
this.eof = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the indexes for the {@link #back()} method based on the previous character read.
|
||||||
|
*/
|
||||||
|
private void decrementIndexes() {
|
||||||
|
this.index--;
|
||||||
|
if(this.previous=='\r' || this.previous == '\n') {
|
||||||
|
this.line--;
|
||||||
|
this.character=this.characterPreviousLine ;
|
||||||
|
} else if(this.character > 0){
|
||||||
|
this.character--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hex value of a character (base16).
|
||||||
|
* @param c A character between '0' and '9' or between 'A' and 'F' or
|
||||||
|
* between 'a' and 'f'.
|
||||||
|
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||||
|
*/
|
||||||
|
public static int dehexchar(char c) {
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
return c - '0';
|
||||||
|
}
|
||||||
|
if (c >= 'A' && c <= 'F') {
|
||||||
|
return c - ('A' - 10);
|
||||||
|
}
|
||||||
|
if (c >= 'a' && c <= 'f') {
|
||||||
|
return c - ('a' - 10);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the end of the input has been reached.
|
||||||
|
*
|
||||||
|
* @return true if at the end of the file and we didn't step back
|
||||||
|
*/
|
||||||
|
public boolean end() {
|
||||||
|
return this.eof && !this.usePrevious;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the source string still contains characters that next()
|
||||||
|
* can consume.
|
||||||
|
* @return true if not yet at the end of the source.
|
||||||
|
* @throws JSONException thrown if there is an error stepping forward
|
||||||
|
* or backward while checking for more data.
|
||||||
|
*/
|
||||||
|
public boolean more() throws JSONException {
|
||||||
|
if(this.usePrevious) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.reader.mark(1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JSONException("Unable to preserve stream position", e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// -1 is EOF, but next() can not consume the null character '\0'
|
||||||
|
if(this.reader.read() <= 0) {
|
||||||
|
this.eof = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.reader.reset();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JSONException("Unable to read the next character from the stream", e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next character in the source string.
|
||||||
|
*
|
||||||
|
* @return The next character, or 0 if past the end of the source string.
|
||||||
|
* @throws JSONException Thrown if there is an error reading the source string.
|
||||||
|
*/
|
||||||
|
public char next() throws JSONException {
|
||||||
|
int c;
|
||||||
|
if (this.usePrevious) {
|
||||||
|
this.usePrevious = false;
|
||||||
|
c = this.previous;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
c = this.reader.read();
|
||||||
|
} catch (IOException exception) {
|
||||||
|
throw new JSONException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c <= 0) { // End of stream
|
||||||
|
this.eof = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
this.incrementIndexes(c);
|
||||||
|
this.previous = (char) c;
|
||||||
|
return this.previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the internal indexes according to the previous character
|
||||||
|
* read and the character passed as the current character.
|
||||||
|
* @param c the current character read.
|
||||||
|
*/
|
||||||
|
private void incrementIndexes(int c) {
|
||||||
|
if(c > 0) {
|
||||||
|
this.index++;
|
||||||
|
if(c=='\r') {
|
||||||
|
this.line++;
|
||||||
|
this.characterPreviousLine = this.character;
|
||||||
|
this.character=0;
|
||||||
|
}else if (c=='\n') {
|
||||||
|
if(this.previous != '\r') {
|
||||||
|
this.line++;
|
||||||
|
this.characterPreviousLine = this.character;
|
||||||
|
}
|
||||||
|
this.character=0;
|
||||||
|
} else {
|
||||||
|
this.character++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume the next character, and check that it matches a specified
|
||||||
|
* character.
|
||||||
|
* @param c The character to match.
|
||||||
|
* @return The character.
|
||||||
|
* @throws JSONException if the character does not match.
|
||||||
|
*/
|
||||||
|
public char next(char c) throws JSONException {
|
||||||
|
char n = this.next();
|
||||||
|
if (n != c) {
|
||||||
|
if(n > 0) {
|
||||||
|
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
|
||||||
|
n + "'");
|
||||||
|
}
|
||||||
|
throw this.syntaxError("Expected '" + c + "' and instead saw ''");
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next n characters.
|
||||||
|
*
|
||||||
|
* @param n The number of characters to take.
|
||||||
|
* @return A string of n characters.
|
||||||
|
* @throws JSONException
|
||||||
|
* Substring bounds error if there are not
|
||||||
|
* n characters remaining in the source string.
|
||||||
|
*/
|
||||||
|
public String next(int n) throws JSONException {
|
||||||
|
if (n == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] chars = new char[n];
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < n) {
|
||||||
|
chars[pos] = this.next();
|
||||||
|
if (this.end()) {
|
||||||
|
throw this.syntaxError("Substring bounds error");
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
return new String(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next char in the string, skipping whitespace.
|
||||||
|
* @throws JSONException Thrown if there is an error reading the source string.
|
||||||
|
* @return A character, or 0 if there are no more characters.
|
||||||
|
*/
|
||||||
|
public char nextClean() throws JSONException {
|
||||||
|
for (;;) {
|
||||||
|
char c = this.next();
|
||||||
|
if (c == 0 || c > ' ') {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the characters up to the next close quote character.
|
||||||
|
* Backslash processing is done. The formal JSON format does not
|
||||||
|
* allow strings in single quotes, but an implementation is allowed to
|
||||||
|
* accept them.
|
||||||
|
* @param quote The quoting character, either
|
||||||
|
* <code>"</code> <small>(double quote)</small> or
|
||||||
|
* <code>'</code> <small>(single quote)</small>.
|
||||||
|
* @return A String.
|
||||||
|
* @throws JSONException Unterminated string.
|
||||||
|
*/
|
||||||
|
public String nextString(char quote) throws JSONException {
|
||||||
|
char c;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (;;) {
|
||||||
|
c = this.next();
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
throw this.syntaxError("Unterminated string");
|
||||||
|
case '\\':
|
||||||
|
c = this.next();
|
||||||
|
switch (c) {
|
||||||
|
case 'b':
|
||||||
|
sb.append('\b');
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
sb.append('\t');
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
sb.append('\n');
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
sb.append('\f');
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
sb.append('\r');
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
try {
|
||||||
|
sb.append((char)Integer.parseInt(this.next(4), 16));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw this.syntaxError("Illegal escape.", e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
sb.append(c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw this.syntaxError("Illegal escape.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c == quote) {
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text up but not including the specified character or the
|
||||||
|
* end of line, whichever comes first.
|
||||||
|
* @param delimiter A delimiter character.
|
||||||
|
* @return A string.
|
||||||
|
* @throws JSONException Thrown if there is an error while searching
|
||||||
|
* for the delimiter
|
||||||
|
*/
|
||||||
|
public String nextTo(char delimiter) throws JSONException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (;;) {
|
||||||
|
char c = this.next();
|
||||||
|
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
|
||||||
|
if (c != 0) {
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text up but not including one of the specified delimiter
|
||||||
|
* characters or the end of line, whichever comes first.
|
||||||
|
* @param delimiters A set of delimiter characters.
|
||||||
|
* @return A string, trimmed.
|
||||||
|
* @throws JSONException Thrown if there is an error while searching
|
||||||
|
* for the delimiter
|
||||||
|
*/
|
||||||
|
public String nextTo(String delimiters) throws JSONException {
|
||||||
|
char c;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (;;) {
|
||||||
|
c = this.next();
|
||||||
|
if (delimiters.indexOf(c) >= 0 || c == 0 ||
|
||||||
|
c == '\n' || c == '\r') {
|
||||||
|
if (c != 0) {
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next value. The value can be a Boolean, Double, Integer,
|
||||||
|
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||||
|
* @throws JSONException If syntax error.
|
||||||
|
*
|
||||||
|
* @return An object.
|
||||||
|
*/
|
||||||
|
public Object nextValue() throws JSONException {
|
||||||
|
char c = this.nextClean();
|
||||||
|
String string;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
return this.nextString(c);
|
||||||
|
case '{':
|
||||||
|
this.back();
|
||||||
|
return new JSONObject(this);
|
||||||
|
case '[':
|
||||||
|
this.back();
|
||||||
|
return new JSONArray(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle unquoted text. This could be the values true, false, or
|
||||||
|
* null, or it can be a number. An implementation (such as this one)
|
||||||
|
* is allowed to also accept non-standard forms.
|
||||||
|
*
|
||||||
|
* Accumulate characters until we reach the end of the text or a
|
||||||
|
* formatting character.
|
||||||
|
*/
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
||||||
|
sb.append(c);
|
||||||
|
c = this.next();
|
||||||
|
}
|
||||||
|
if (!this.eof) {
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
string = sb.toString().trim();
|
||||||
|
if ("".equals(string)) {
|
||||||
|
throw this.syntaxError("Missing value");
|
||||||
|
}
|
||||||
|
return JSONObject.stringToValue(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip characters until the next character is the requested character.
|
||||||
|
* If the requested character is not found, no characters are skipped.
|
||||||
|
* @param to A character to skip to.
|
||||||
|
* @return The requested character, or zero if the requested character
|
||||||
|
* is not found.
|
||||||
|
* @throws JSONException Thrown if there is an error while searching
|
||||||
|
* for the to character
|
||||||
|
*/
|
||||||
|
public char skipTo(char to) throws JSONException {
|
||||||
|
char c;
|
||||||
|
try {
|
||||||
|
long startIndex = this.index;
|
||||||
|
long startCharacter = this.character;
|
||||||
|
long startLine = this.line;
|
||||||
|
this.reader.mark(1000000);
|
||||||
|
do {
|
||||||
|
c = this.next();
|
||||||
|
if (c == 0) {
|
||||||
|
// in some readers, reset() may throw an exception if
|
||||||
|
// the remaining portion of the input is greater than
|
||||||
|
// the mark size (1,000,000 above).
|
||||||
|
this.reader.reset();
|
||||||
|
this.index = startIndex;
|
||||||
|
this.character = startCharacter;
|
||||||
|
this.line = startLine;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} while (c != to);
|
||||||
|
this.reader.mark(1);
|
||||||
|
} catch (IOException exception) {
|
||||||
|
throw new JSONException(exception);
|
||||||
|
}
|
||||||
|
this.back();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a JSONException to signal a syntax error.
|
||||||
|
*
|
||||||
|
* @param message The error message.
|
||||||
|
* @return A JSONException object, suitable for throwing
|
||||||
|
*/
|
||||||
|
public JSONException syntaxError(String message) {
|
||||||
|
return new JSONException(message + this.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a JSONException to signal a syntax error.
|
||||||
|
*
|
||||||
|
* @param message The error message.
|
||||||
|
* @param causedBy The throwable that caused the error.
|
||||||
|
* @return A JSONException object, suitable for throwing
|
||||||
|
*/
|
||||||
|
public JSONException syntaxError(String message, Throwable causedBy) {
|
||||||
|
return new JSONException(message + this.toString(), causedBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a printable string of this JSONTokener.
|
||||||
|
*
|
||||||
|
* @return " at {index} [character {character} line {line}]"
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return " at " + this.index + " [character " + this.character + " line " +
|
||||||
|
this.line + "]";
|
||||||
|
}
|
||||||
|
}
|
413
src/main/java/json/JSONWriter.java
Normal file
413
src/main/java/json/JSONWriter.java
Normal file
|
@ -0,0 +1,413 @@
|
||||||
|
package json;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2006 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSONWriter provides a quick and convenient way of producing JSON text.
|
||||||
|
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||||
|
* added, so the results are ready for transmission or storage. Each instance of
|
||||||
|
* JSONWriter can produce one JSON text.
|
||||||
|
* <p>
|
||||||
|
* A JSONWriter instance provides a <code>value</code> method for appending
|
||||||
|
* values to the
|
||||||
|
* text, and a <code>key</code>
|
||||||
|
* method for adding keys before values in objects. There are <code>array</code>
|
||||||
|
* and <code>endArray</code> methods that make and bound array values, and
|
||||||
|
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||||
|
* object values. All of these methods return the JSONWriter instance,
|
||||||
|
* permitting a cascade style. For example, <pre>
|
||||||
|
* new JSONWriter(myWriter)
|
||||||
|
* .object()
|
||||||
|
* .key("JSON")
|
||||||
|
* .value("Hello, World!")
|
||||||
|
* .endObject();</pre> which writes <pre>
|
||||||
|
* {"JSON":"Hello, World!"}</pre>
|
||||||
|
* <p>
|
||||||
|
* The first method called must be <code>array</code> or <code>object</code>.
|
||||||
|
* There are no methods for adding commas or colons. JSONWriter adds them for
|
||||||
|
* you. Objects and arrays can be nested up to 200 levels deep.
|
||||||
|
* <p>
|
||||||
|
* This can sometimes be easier than using a JSONObject to build a string.
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2016-08-08
|
||||||
|
*/
|
||||||
|
public class JSONWriter {
|
||||||
|
private static final int maxdepth = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The comma flag determines if a comma should be output before the next
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
private boolean comma;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current mode. Values:
|
||||||
|
* 'a' (array),
|
||||||
|
* 'd' (done),
|
||||||
|
* 'i' (initial),
|
||||||
|
* 'k' (key),
|
||||||
|
* 'o' (object).
|
||||||
|
*/
|
||||||
|
protected char mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object/array stack.
|
||||||
|
*/
|
||||||
|
private final JSONObject stack[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stack top index. A value of 0 indicates that the stack is empty.
|
||||||
|
*/
|
||||||
|
private int top;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The writer that will receive the output.
|
||||||
|
*/
|
||||||
|
protected Appendable writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a fresh JSONWriter. It can be used to build one JSON text.
|
||||||
|
*/
|
||||||
|
public JSONWriter(Appendable w) {
|
||||||
|
this.comma = false;
|
||||||
|
this.mode = 'i';
|
||||||
|
this.stack = new JSONObject[maxdepth];
|
||||||
|
this.top = 0;
|
||||||
|
this.writer = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a value.
|
||||||
|
* @param string A string value.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the value is out of sequence.
|
||||||
|
*/
|
||||||
|
private JSONWriter append(String string) throws JSONException {
|
||||||
|
if (string == null) {
|
||||||
|
throw new JSONException("Null pointer");
|
||||||
|
}
|
||||||
|
if (this.mode == 'o' || this.mode == 'a') {
|
||||||
|
try {
|
||||||
|
if (this.comma && this.mode == 'a') {
|
||||||
|
this.writer.append(',');
|
||||||
|
}
|
||||||
|
this.writer.append(string);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Android as of API 25 does not support this exception constructor
|
||||||
|
// however we won't worry about it. If an exception is happening here
|
||||||
|
// it will just throw a "Method not found" exception instead.
|
||||||
|
throw new JSONException(e);
|
||||||
|
}
|
||||||
|
if (this.mode == 'o') {
|
||||||
|
this.mode = 'k';
|
||||||
|
}
|
||||||
|
this.comma = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new JSONException("Value out of sequence.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin appending a new array. All values until the balancing
|
||||||
|
* <code>endArray</code> will be appended to this array. The
|
||||||
|
* <code>endArray</code> method must be called to mark the array's end.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the nesting is too deep, or if the object is
|
||||||
|
* started in the wrong place (for example as a key or after the end of the
|
||||||
|
* outermost array or object).
|
||||||
|
*/
|
||||||
|
public JSONWriter array() throws JSONException {
|
||||||
|
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
|
||||||
|
this.push(null);
|
||||||
|
this.append("[");
|
||||||
|
this.comma = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new JSONException("Misplaced array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End something.
|
||||||
|
* @param m Mode
|
||||||
|
* @param c Closing character
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If unbalanced.
|
||||||
|
*/
|
||||||
|
private JSONWriter end(char m, char c) throws JSONException {
|
||||||
|
if (this.mode != m) {
|
||||||
|
throw new JSONException(m == 'a'
|
||||||
|
? "Misplaced endArray."
|
||||||
|
: "Misplaced endObject.");
|
||||||
|
}
|
||||||
|
this.pop(m);
|
||||||
|
try {
|
||||||
|
this.writer.append(c);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Android as of API 25 does not support this exception constructor
|
||||||
|
// however we won't worry about it. If an exception is happening here
|
||||||
|
// it will just throw a "Method not found" exception instead.
|
||||||
|
throw new JSONException(e);
|
||||||
|
}
|
||||||
|
this.comma = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End an array. This method most be called to balance calls to
|
||||||
|
* <code>array</code>.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If incorrectly nested.
|
||||||
|
*/
|
||||||
|
public JSONWriter endArray() throws JSONException {
|
||||||
|
return this.end('a', ']');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End an object. This method most be called to balance calls to
|
||||||
|
* <code>object</code>.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If incorrectly nested.
|
||||||
|
*/
|
||||||
|
public JSONWriter endObject() throws JSONException {
|
||||||
|
return this.end('k', '}');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a key. The key will be associated with the next value. In an
|
||||||
|
* object, every value must be preceded by a key.
|
||||||
|
* @param string A key string.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the key is out of place. For example, keys
|
||||||
|
* do not belong in arrays or if the key is null.
|
||||||
|
*/
|
||||||
|
public JSONWriter key(String string) throws JSONException {
|
||||||
|
if (string == null) {
|
||||||
|
throw new JSONException("Null key.");
|
||||||
|
}
|
||||||
|
if (this.mode == 'k') {
|
||||||
|
try {
|
||||||
|
JSONObject topObject = this.stack[this.top - 1];
|
||||||
|
// don't use the built in putOnce method to maintain Android support
|
||||||
|
if(topObject.has(string)) {
|
||||||
|
throw new JSONException("Duplicate key \"" + string + "\"");
|
||||||
|
}
|
||||||
|
topObject.put(string, true);
|
||||||
|
if (this.comma) {
|
||||||
|
this.writer.append(',');
|
||||||
|
}
|
||||||
|
this.writer.append(JSONObject.quote(string));
|
||||||
|
this.writer.append(':');
|
||||||
|
this.comma = false;
|
||||||
|
this.mode = 'o';
|
||||||
|
return this;
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Android as of API 25 does not support this exception constructor
|
||||||
|
// however we won't worry about it. If an exception is happening here
|
||||||
|
// it will just throw a "Method not found" exception instead.
|
||||||
|
throw new JSONException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new JSONException("Misplaced key.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin appending a new object. All keys and values until the balancing
|
||||||
|
* <code>endObject</code> will be appended to this object. The
|
||||||
|
* <code>endObject</code> method must be called to mark the object's end.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the nesting is too deep, or if the object is
|
||||||
|
* started in the wrong place (for example as a key or after the end of the
|
||||||
|
* outermost array or object).
|
||||||
|
*/
|
||||||
|
public JSONWriter object() throws JSONException {
|
||||||
|
if (this.mode == 'i') {
|
||||||
|
this.mode = 'o';
|
||||||
|
}
|
||||||
|
if (this.mode == 'o' || this.mode == 'a') {
|
||||||
|
this.append("{");
|
||||||
|
this.push(new JSONObject());
|
||||||
|
this.comma = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new JSONException("Misplaced object.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop an array or object scope.
|
||||||
|
* @param c The scope to close.
|
||||||
|
* @throws JSONException If nesting is wrong.
|
||||||
|
*/
|
||||||
|
private void pop(char c) throws JSONException {
|
||||||
|
if (this.top <= 0) {
|
||||||
|
throw new JSONException("Nesting error.");
|
||||||
|
}
|
||||||
|
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||||
|
if (m != c) {
|
||||||
|
throw new JSONException("Nesting error.");
|
||||||
|
}
|
||||||
|
this.top -= 1;
|
||||||
|
this.mode = this.top == 0
|
||||||
|
? 'd'
|
||||||
|
: this.stack[this.top - 1] == null
|
||||||
|
? 'a'
|
||||||
|
: 'k';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push an array or object scope.
|
||||||
|
* @param jo The scope to open.
|
||||||
|
* @throws JSONException If nesting is too deep.
|
||||||
|
*/
|
||||||
|
private void push(JSONObject jo) throws JSONException {
|
||||||
|
if (this.top >= maxdepth) {
|
||||||
|
throw new JSONException("Nesting too deep.");
|
||||||
|
}
|
||||||
|
this.stack[this.top] = jo;
|
||||||
|
this.mode = jo == null ? 'a' : 'k';
|
||||||
|
this.top += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a JSON text of an Object value. If the object has an
|
||||||
|
* value.toJSONString() method, then that method will be used to produce the
|
||||||
|
* JSON text. The method is required to produce a strictly conforming text.
|
||||||
|
* If the object does not contain a toJSONString method (which is the most
|
||||||
|
* common case), then a text will be produced by other means. If the value
|
||||||
|
* is an array or Collection, then a JSONArray will be made from it and its
|
||||||
|
* toJSONString method will be called. If the value is a MAP, then a
|
||||||
|
* JSONObject will be made from it and its toJSONString method will be
|
||||||
|
* called. Otherwise, the value's toString method will be called, and the
|
||||||
|
* result will be quoted.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Warning: This method assumes that the data structure is acyclical.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The value to be serialized.
|
||||||
|
* @return a printable, displayable, transmittable representation of the
|
||||||
|
* object, beginning with <code>{</code> <small>(left
|
||||||
|
* brace)</small> and ending with <code>}</code> <small>(right
|
||||||
|
* brace)</small>.
|
||||||
|
* @throws JSONException
|
||||||
|
* If the value is or contains an invalid number.
|
||||||
|
*/
|
||||||
|
public static String valueToString(Object value) throws JSONException {
|
||||||
|
if (value == null || value.equals(null)) {
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
if (value instanceof JSONString) {
|
||||||
|
String object;
|
||||||
|
try {
|
||||||
|
object = ((JSONString) value).toJSONString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new JSONException(e);
|
||||||
|
}
|
||||||
|
if (object != null) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
throw new JSONException("Bad value from toJSONString: " + object);
|
||||||
|
}
|
||||||
|
if (value instanceof Number) {
|
||||||
|
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
|
||||||
|
final String numberAsString = JSONObject.numberToString((Number) value);
|
||||||
|
if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) {
|
||||||
|
// Close enough to a JSON number that we will return it unquoted
|
||||||
|
return numberAsString;
|
||||||
|
}
|
||||||
|
// The Number value is not a valid JSON number.
|
||||||
|
// Instead we will quote it as a string
|
||||||
|
return JSONObject.quote(numberAsString);
|
||||||
|
}
|
||||||
|
if (value instanceof Boolean || value instanceof JSONObject
|
||||||
|
|| value instanceof JSONArray) {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
if (value instanceof Map) {
|
||||||
|
Map<?, ?> map = (Map<?, ?>) value;
|
||||||
|
return new JSONObject(map).toString();
|
||||||
|
}
|
||||||
|
if (value instanceof Collection) {
|
||||||
|
Collection<?> coll = (Collection<?>) value;
|
||||||
|
return new JSONArray(coll).toString();
|
||||||
|
}
|
||||||
|
if (value.getClass().isArray()) {
|
||||||
|
return new JSONArray(value).toString();
|
||||||
|
}
|
||||||
|
if(value instanceof Enum<?>){
|
||||||
|
return JSONObject.quote(((Enum<?>)value).name());
|
||||||
|
}
|
||||||
|
return JSONObject.quote(value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append either the value <code>true</code> or the value
|
||||||
|
* <code>false</code>.
|
||||||
|
* @param b A boolean.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException
|
||||||
|
*/
|
||||||
|
public JSONWriter value(boolean b) throws JSONException {
|
||||||
|
return this.append(b ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a double value.
|
||||||
|
* @param d A double.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the number is not finite.
|
||||||
|
*/
|
||||||
|
public JSONWriter value(double d) throws JSONException {
|
||||||
|
return this.value(Double.valueOf(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a long value.
|
||||||
|
* @param l A long.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException
|
||||||
|
*/
|
||||||
|
public JSONWriter value(long l) throws JSONException {
|
||||||
|
return this.append(Long.toString(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append an object value.
|
||||||
|
* @param object The object to append. It can be null, or a Boolean, Number,
|
||||||
|
* String, JSONObject, or JSONArray, or an object that implements JSONString.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the value is out of sequence.
|
||||||
|
*/
|
||||||
|
public JSONWriter value(Object object) throws JSONException {
|
||||||
|
return this.append(valueToString(object));
|
||||||
|
}
|
||||||
|
}
|
24
src/main/resources/config.yml
Normal file
24
src/main/resources/config.yml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# 当前服务端玩法
|
||||||
|
GameMode: BlockWars
|
||||||
|
# 调试模式
|
||||||
|
MainDebug: false
|
||||||
|
# 请勿调动此参数
|
||||||
|
GiftDelay: 6000
|
||||||
|
# 直播平台
|
||||||
|
LivePlatform: DouYin
|
||||||
|
# 后台输出信息
|
||||||
|
Settings:
|
||||||
|
# 礼物
|
||||||
|
debug_gifts: false
|
||||||
|
# 点赞
|
||||||
|
debug_dianzan: false
|
||||||
|
# 关注
|
||||||
|
debug_guanzhu: false
|
||||||
|
# 进入
|
||||||
|
debug_join: true
|
||||||
|
# 聊天消息
|
||||||
|
debug_message: true
|
||||||
|
# 进入提示信息
|
||||||
|
join_show: true
|
||||||
|
AutoLink: false
|
||||||
|
LiveId: {}
|
22
src/main/resources/keyconfig.yml
Normal file
22
src/main/resources/keyconfig.yml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# 1 = 左Shift 16 = 右Shift
|
||||||
|
# 2 = 左Ctrl 32 = 右Ctrl
|
||||||
|
# 8 = 左Alt 128 = 右Alt
|
||||||
|
32+21: 加油鸭 #右Ctrl+Y
|
||||||
|
32+22: 小心心 #右Ctrl+U
|
||||||
|
32+23: 玫瑰 #右Ctrl+I
|
||||||
|
32+24: 你最好看 #右Ctrl+O
|
||||||
|
32+25: 抖音 #右Ctrl+P
|
||||||
|
32+26: 爱你哟 #右Ctrl+{
|
||||||
|
32+27: 为你闪耀 #右Ctrl+}
|
||||||
|
32+43: 送你花花 #右Ctrl+|
|
||||||
|
32+34: 亲吻 #右Ctrl+G
|
||||||
|
32+35: 真的爱你 #右Ctrl+H
|
||||||
|
32+36: 闪耀星辰 #右Ctrl+J
|
||||||
|
32+37: 爱的纸鹤 #右Ctrl+K
|
||||||
|
32+38: 比心兔兔 #右Ctrl+L
|
||||||
|
32+39: 私人飞机 #右Ctrl+:
|
||||||
|
32+40: 直升机 #右Ctrl+"
|
||||||
|
32+47: 大啤酒 #右Ctrl+V
|
||||||
|
32+48: 人气票 #右Ctrl+B
|
||||||
|
32+49: 荧光棒 #右Ctrl+N
|
||||||
|
32+50: Thuglife #右Ctrl+M
|
8
src/main/resources/plugin.yml
Normal file
8
src/main/resources/plugin.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
name: McLiveAPI
|
||||||
|
version: 1.3
|
||||||
|
main: com.io.yutian.mclive.Main
|
||||||
|
api-version: 1.18
|
||||||
|
author: yutian
|
||||||
|
|
||||||
|
commands:
|
||||||
|
mclive:
|
BIN
target/classes/com/io/yutian/livemutually/liveroom/Chat.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/liveroom/Chat.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/liveroom/Follow.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/liveroom/Follow.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/liveroom/Gift.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/liveroom/Gift.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/liveroom/Like.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/liveroom/Like.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/liveroom/User.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/liveroom/User.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouChat.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouChat.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouGift.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouGift.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouLike.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouLike.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouUser.class
Normal file
BIN
target/classes/com/io/yutian/livemutually/wss/KuaiShouUser.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/ConfigYml.class
Normal file
BIN
target/classes/com/io/yutian/mclive/ConfigYml.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/LinkRoom.class
Normal file
BIN
target/classes/com/io/yutian/mclive/LinkRoom.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/LiveAdminGui.class
Normal file
BIN
target/classes/com/io/yutian/mclive/LiveAdminGui.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/LiveEvent.class
Normal file
BIN
target/classes/com/io/yutian/mclive/LiveEvent.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/Main.class
Normal file
BIN
target/classes/com/io/yutian/mclive/Main.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/event/LiveChatEvents.class
Normal file
BIN
target/classes/com/io/yutian/mclive/event/LiveChatEvents.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/event/LiveEnterEvents.class
Normal file
BIN
target/classes/com/io/yutian/mclive/event/LiveEnterEvents.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/event/LiveFollowEvents.class
Normal file
BIN
target/classes/com/io/yutian/mclive/event/LiveFollowEvents.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/event/LiveGiftEvents.class
Normal file
BIN
target/classes/com/io/yutian/mclive/event/LiveGiftEvents.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/event/LiveLikeEvents.class
Normal file
BIN
target/classes/com/io/yutian/mclive/event/LiveLikeEvents.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/mclive/event/ZhuboAPI.class
Normal file
BIN
target/classes/com/io/yutian/mclive/event/ZhuboAPI.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/verify/AESUtil.class
Normal file
BIN
target/classes/com/io/yutian/verify/AESUtil.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/verify/PluginVerifyResult.class
Normal file
BIN
target/classes/com/io/yutian/verify/PluginVerifyResult.class
Normal file
Binary file not shown.
BIN
target/classes/com/io/yutian/verify/VerifyHandler.class
Normal file
BIN
target/classes/com/io/yutian/verify/VerifyHandler.class
Normal file
Binary file not shown.
24
target/classes/config.yml
Normal file
24
target/classes/config.yml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# 当前服务端玩法
|
||||||
|
GameMode: BlockWars
|
||||||
|
# 调试模式
|
||||||
|
MainDebug: false
|
||||||
|
# 请勿调动此参数
|
||||||
|
GiftDelay: 6000
|
||||||
|
# 直播平台
|
||||||
|
LivePlatform: DouYin
|
||||||
|
# 后台输出信息
|
||||||
|
Settings:
|
||||||
|
# 礼物
|
||||||
|
debug_gifts: false
|
||||||
|
# 点赞
|
||||||
|
debug_dianzan: false
|
||||||
|
# 关注
|
||||||
|
debug_guanzhu: false
|
||||||
|
# 进入
|
||||||
|
debug_join: true
|
||||||
|
# 聊天消息
|
||||||
|
debug_message: true
|
||||||
|
# 进入提示信息
|
||||||
|
join_show: true
|
||||||
|
AutoLink: false
|
||||||
|
LiveId: {}
|
BIN
target/classes/json/JSONArray.class
Normal file
BIN
target/classes/json/JSONArray.class
Normal file
Binary file not shown.
BIN
target/classes/json/JSONException.class
Normal file
BIN
target/classes/json/JSONException.class
Normal file
Binary file not shown.
BIN
target/classes/json/JSONObject$Null.class
Normal file
BIN
target/classes/json/JSONObject$Null.class
Normal file
Binary file not shown.
BIN
target/classes/json/JSONObject.class
Normal file
BIN
target/classes/json/JSONObject.class
Normal file
Binary file not shown.
BIN
target/classes/json/JSONPointer$Builder.class
Normal file
BIN
target/classes/json/JSONPointer$Builder.class
Normal file
Binary file not shown.
BIN
target/classes/json/JSONPointer.class
Normal file
BIN
target/classes/json/JSONPointer.class
Normal file
Binary file not shown.
BIN
target/classes/json/JSONPointerException.class
Normal file
BIN
target/classes/json/JSONPointerException.class
Normal file
Binary file not shown.
BIN
target/classes/json/JSONPropertyIgnore.class
Normal file
BIN
target/classes/json/JSONPropertyIgnore.class
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user