Moved to reflection #1
53 changed files with 879 additions and 4667 deletions
2
.idea/encodings.xml
generated
2
.idea/encodings.xml
generated
|
@ -1,8 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="Encoding">
|
<component name="Encoding">
|
||||||
<file url="file://$PROJECT_DIR$/API/src/main/java" charset="UTF-8" />
|
|
||||||
<file url="file://$PROJECT_DIR$/API/src/main/resources" charset="UTF-8" />
|
|
||||||
<file url="file://$PROJECT_DIR$/Dist/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Dist/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/Dist/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Dist/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/NMS-v1_12_R1/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/NMS-v1_12_R1/src/main/java" charset="UTF-8" />
|
||||||
|
|
16
.idea/misc.xml
generated
16
.idea/misc.xml
generated
|
@ -15,8 +15,22 @@
|
||||||
<option value="$PROJECT_DIR$/pom.xml" />
|
<option value="$PROJECT_DIR$/pom.xml" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="ignoredFiles">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$/API/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/Dist/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_12_R1/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_13_R2/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_14_R1/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_15_R1/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_16_R3/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_17_R1/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_18_R2/pom.xml" />
|
||||||
|
<option value="$PROJECT_DIR$/NMS-v1_19_R1/pom.xml" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
75
API/pom.xml
75
API/pom.xml
|
@ -1,75 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ This file is part of MapReflectionAPI.
|
|
||||||
~ Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
~
|
|
||||||
~ 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 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<jdk.version>11</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<directory>src/main/resources</directory>
|
|
||||||
<filtering>true</filtering>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>MG-Dev Jenkins CI Maven Repository</id>
|
|
||||||
<url>https://ci.mg-dev.eu/plugin/repository/everything</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.bergerkiller.bukkit</groupId>
|
|
||||||
<artifactId>BKCommonLib</artifactId>
|
|
||||||
<version>1.19-v1</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.api;
|
|
||||||
|
|
||||||
public abstract class MapWrapper {
|
|
||||||
protected ArrayImage content;
|
|
||||||
|
|
||||||
public MapWrapper(ArrayImage image) {
|
|
||||||
this.content = image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract MapController getController();
|
|
||||||
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.listeners;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
public abstract class PacketListener implements Listener {
|
|
||||||
protected JavaPlugin plugin;
|
|
||||||
|
|
||||||
public static PacketListener construct(JavaPlugin plugin) throws IllegalStateException {
|
|
||||||
String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
|
||||||
String version = packageName.substring(packageName.lastIndexOf('.') + 1);
|
|
||||||
|
|
||||||
plugin.getLogger().info("Initializing the packet handler for Minecraft version " + version + "...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
final Class<?> clazz = Class.forName("tech.sbdevelopment.mapreflectionapi.nms.PacketListener_" + version);
|
|
||||||
if (PacketListener.class.isAssignableFrom(clazz)) {
|
|
||||||
return (PacketListener) clazz.getDeclaredConstructor().newInstance();
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Plugin corrupted! Detected invalid PacketListener class.");
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new IllegalStateException("This Minecraft version (" + version + ") is not supported! Contact the developer to get support.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(JavaPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onJoin(PlayerJoinEvent e) {
|
|
||||||
injectPlayer(e.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onQuit(PlayerQuitEvent e) {
|
|
||||||
removePlayer(e.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void injectPlayer(Player p);
|
|
||||||
|
|
||||||
public abstract void removePlayer(Player p);
|
|
||||||
|
|
||||||
protected abstract Vector vec3DToVector(Object vec3d);
|
|
||||||
|
|
||||||
protected boolean hasField(Object packet, String field) {
|
|
||||||
try {
|
|
||||||
packet.getClass().getDeclaredField(field);
|
|
||||||
return true;
|
|
||||||
} catch (NoSuchFieldException ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.util;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
public class ReflectionUtil {
|
|
||||||
public static Object getField(Object packet, String field) throws NoSuchFieldException, IllegalAccessException {
|
|
||||||
Field f = packet.getClass().getDeclaredField(field);
|
|
||||||
f.setAccessible(true);
|
|
||||||
return f.get(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object getField(Class<?> clazz, String field) throws NoSuchFieldException, IllegalAccessException {
|
|
||||||
Field f = clazz.getDeclaredField(field);
|
|
||||||
f.setAccessible(true);
|
|
||||||
return f.get(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setField(Object packet, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
|
|
||||||
Field f = packet.getClass().getDeclaredField(field);
|
|
||||||
f.setAccessible(true);
|
|
||||||
f.set(packet, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object getValue(Object packet, String method) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
|
||||||
Method m = packet.getClass().getDeclaredMethod(method, null);
|
|
||||||
m.setAccessible(true);
|
|
||||||
return m.invoke(packet, null);
|
|
||||||
}
|
|
||||||
}
|
|
101
Dist/pom.xml
101
Dist/pom.xml
|
@ -1,101 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-Dist</artifactId>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<directory>../target</directory>
|
|
||||||
<finalName>${project.parent.name}-${project.version}</finalName>
|
|
||||||
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.3.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
|
||||||
|
|
||||||
<!-- Include all the dependencies required by the plugin -->
|
|
||||||
<artifactSet>
|
|
||||||
<includes>
|
|
||||||
<include>tech.sbdevelopment:MapReflectionAPI*</include>
|
|
||||||
</includes>
|
|
||||||
</artifactSet>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_19_R1</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_18_R2</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_16_R3</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_17_R1</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_15_R1</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_14_R1</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_13_R2</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_12_R1</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_12_R1</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.12.2-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>11</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.server.v1_12_R1.*;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class PacketListener_v1_12_R1 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap) {
|
|
||||||
PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet;
|
|
||||||
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity) {
|
|
||||||
PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet;
|
|
||||||
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.a(); //action
|
|
||||||
EnumHand hand = packetPlayInUseEntity.b(); //hand
|
|
||||||
Vec3D pos = packetPlayInUseEntity.c(); //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, action.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet;
|
|
||||||
|
|
||||||
int slot = packetPlayInSetCreativeSlot.a();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.getItemStack();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline();
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel;
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0);
|
|
||||||
|
|
||||||
Vec3D vec3dObj = (Vec3D) vec3d;
|
|
||||||
return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_13_R2</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.13.2-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>11</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,139 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_13_R2.PacketPlayOutMap;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class MapSender_v1_13_R2 {
|
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
|
||||||
private static int senderID = -1;
|
|
||||||
|
|
||||||
public static void addToQueue(final int id, final ArrayImage content, final Player player) {
|
|
||||||
QueuedMap toSend = new QueuedMap(id, content, player);
|
|
||||||
if (sendQueue.contains(toSend)) return;
|
|
||||||
sendQueue.add(toSend);
|
|
||||||
|
|
||||||
runSender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runSender() {
|
|
||||||
if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
if (sendQueue.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) {
|
|
||||||
QueuedMap current = sendQueue.get(0);
|
|
||||||
if (current == null) return;
|
|
||||||
|
|
||||||
sendMap(current.id, current.image, current.player);
|
|
||||||
|
|
||||||
if (!sendQueue.isEmpty()) sendQueue.remove(0);
|
|
||||||
}
|
|
||||||
}, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMap(final int id0, final ArrayImage content, final Player player) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
|
||||||
List<QueuedMap> toRemove = new ArrayList<>();
|
|
||||||
for (QueuedMap qMap : sendQueue) {
|
|
||||||
if (qMap == null) continue;
|
|
||||||
|
|
||||||
if (qMap.player == null || !qMap.player.isOnline()) {
|
|
||||||
toRemove.add(qMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().cancelTask(senderID);
|
|
||||||
sendQueue.removeAll(toRemove);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int id = -id0;
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
try {
|
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale
|
|
||||||
false, //???
|
|
||||||
new ArrayList<>(), //Icons
|
|
||||||
content.array, //Data
|
|
||||||
content.minX, //X pos
|
|
||||||
content.minY, //Y pos
|
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY //Y size (2nd Y pos)
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class QueuedMap {
|
|
||||||
private final int id;
|
|
||||||
private final ArrayImage image;
|
|
||||||
private final Player player;
|
|
||||||
|
|
||||||
QueuedMap(int id, ArrayImage image, Player player) {
|
|
||||||
this.id = id;
|
|
||||||
this.image = image;
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == this) return true;
|
|
||||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
|
||||||
var that = (QueuedMap) obj;
|
|
||||||
return this.id == that.id &&
|
|
||||||
Objects.equals(this.image, that.image) &&
|
|
||||||
Objects.equals(this.player, that.player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id, image, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "QueuedMap[" +
|
|
||||||
"id=" + id + ", " +
|
|
||||||
"image=" + image + ", " +
|
|
||||||
"player=" + player + ']';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,251 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_13_R2.*;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_13_R2.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class MapWrapper_v1_13_R2 extends MapWrapper {
|
|
||||||
protected MapController controller = new MapController() {
|
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewer(Player player) throws MapLimitExceededException {
|
|
||||||
if (!isViewing(player)) {
|
|
||||||
viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeViewer(OfflinePlayer player) {
|
|
||||||
viewers.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearViewers() {
|
|
||||||
for (UUID uuid : viewers.keySet()) {
|
|
||||||
viewers.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewing(OfflinePlayer player) {
|
|
||||||
if (player == null) return false;
|
|
||||||
return viewers.containsKey(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMapId(OfflinePlayer player) {
|
|
||||||
if (isViewing(player)) {
|
|
||||||
return viewers.get(player.getUniqueId());
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(ArrayImage content) {
|
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
|
||||||
if (duplicate != null) {
|
|
||||||
MapWrapper_v1_13_R2.this.content = duplicate.getContent();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper_v1_13_R2.this.content = content;
|
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
|
||||||
sendContent(Bukkit.getPlayer(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return MapWrapper_v1_13_R2.this.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player) {
|
|
||||||
sendContent(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player, boolean withoutQueue) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
int id = getMapId(player);
|
|
||||||
if (withoutQueue) {
|
|
||||||
MapSender_v1_13_R2.sendMap(id, MapWrapper_v1_13_R2.this.content, player);
|
|
||||||
} else {
|
|
||||||
MapSender_v1_13_R2.addToQueue(id, MapWrapper_v1_13_R2.this.content, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot, boolean force) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
if (player.getGameMode() == GameMode.CREATIVE && !force) return;
|
|
||||||
|
|
||||||
if (slot < 9) {
|
|
||||||
slot += 36;
|
|
||||||
} else if (slot > 35 && slot != 45) {
|
|
||||||
slot = 8 - (slot - 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
|
||||||
int windowId = craftPlayer.getHandle().defaultContainer.windowId;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
net.minecraft.server.v1_13_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack);
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot) {
|
|
||||||
showInInventory(player, slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player, boolean force) {
|
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player) {
|
|
||||||
showInHand(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame) {
|
|
||||||
showInFrame(player, frame, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
|
||||||
if (frame.getItem().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInFrame(player, frame.getEntityId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId) {
|
|
||||||
showInFrame(player, entityId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
if (debugInfo != null) {
|
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
|
||||||
itemMeta.setDisplayName(debugInfo);
|
|
||||||
stack.setItemMeta(itemMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
|
||||||
if (frame != null) {
|
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_13_R2.this));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, int entityId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, ItemFrame frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().getEntity(entityId);
|
|
||||||
if (entity == null) return null;
|
|
||||||
|
|
||||||
org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity();
|
|
||||||
if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
|
||||||
net.minecraft.server.v1_13_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
|
||||||
DataWatcherObject<net.minecraft.server.v1_13_R2.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.server.v1_13_R2.ItemStack>) getField(EntityItemFrame.class, "e");
|
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public MapWrapper_v1_13_R2(ArrayImage image) {
|
|
||||||
super(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.server.v1_13_R2.*;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class PacketListener_v1_13_R2 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap) {
|
|
||||||
PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet;
|
|
||||||
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity) {
|
|
||||||
PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet;
|
|
||||||
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action
|
|
||||||
EnumHand hand = packetPlayInUseEntity.c(); //hand
|
|
||||||
Vec3D pos = packetPlayInUseEntity.d(); //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, action.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet;
|
|
||||||
|
|
||||||
int slot = packetPlayInSetCreativeSlot.b();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.getItemStack();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline();
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel;
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0);
|
|
||||||
|
|
||||||
Vec3D vec3dObj = (Vec3D) vec3d;
|
|
||||||
return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_14_R1</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.14.4-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>11</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_14_R1.PacketPlayOutMap;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class MapSender_v1_14_R1 {
|
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
|
||||||
private static int senderID = -1;
|
|
||||||
|
|
||||||
public static void addToQueue(final int id, final ArrayImage content, final Player player) {
|
|
||||||
QueuedMap toSend = new QueuedMap(id, content, player);
|
|
||||||
if (sendQueue.contains(toSend)) return;
|
|
||||||
sendQueue.add(toSend);
|
|
||||||
|
|
||||||
runSender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runSender() {
|
|
||||||
if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
if (sendQueue.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) {
|
|
||||||
QueuedMap current = sendQueue.get(0);
|
|
||||||
if (current == null) return;
|
|
||||||
|
|
||||||
sendMap(current.id, current.image, current.player);
|
|
||||||
|
|
||||||
if (!sendQueue.isEmpty()) sendQueue.remove(0);
|
|
||||||
}
|
|
||||||
}, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMap(final int id0, final ArrayImage content, final Player player) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
|
||||||
List<QueuedMap> toRemove = new ArrayList<>();
|
|
||||||
for (QueuedMap qMap : sendQueue) {
|
|
||||||
if (qMap == null) continue;
|
|
||||||
|
|
||||||
if (qMap.player == null || !qMap.player.isOnline()) {
|
|
||||||
toRemove.add(qMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().cancelTask(senderID);
|
|
||||||
sendQueue.removeAll(toRemove);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int id = -id0;
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
try {
|
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale
|
|
||||||
false, //Tracking position
|
|
||||||
false, //Locked
|
|
||||||
new ArrayList<>(), //Icons
|
|
||||||
content.array, //Data
|
|
||||||
content.minX, //X pos
|
|
||||||
content.minY, //Y pos
|
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY //Y size (2nd Y pos)
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class QueuedMap {
|
|
||||||
private final int id;
|
|
||||||
private final ArrayImage image;
|
|
||||||
private final Player player;
|
|
||||||
|
|
||||||
QueuedMap(int id, ArrayImage image, Player player) {
|
|
||||||
this.id = id;
|
|
||||||
this.image = image;
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == this) return true;
|
|
||||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
|
||||||
var that = (QueuedMap) obj;
|
|
||||||
return this.id == that.id &&
|
|
||||||
Objects.equals(this.image, that.image) &&
|
|
||||||
Objects.equals(this.player, that.player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id, image, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "QueuedMap[" +
|
|
||||||
"id=" + id + ", " +
|
|
||||||
"image=" + image + ", " +
|
|
||||||
"player=" + player + ']';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,251 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_14_R1.*;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class MapWrapper_v1_14_R1 extends MapWrapper {
|
|
||||||
protected MapController controller = new MapController() {
|
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewer(Player player) throws MapLimitExceededException {
|
|
||||||
if (!isViewing(player)) {
|
|
||||||
viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeViewer(OfflinePlayer player) {
|
|
||||||
viewers.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearViewers() {
|
|
||||||
for (UUID uuid : viewers.keySet()) {
|
|
||||||
viewers.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewing(OfflinePlayer player) {
|
|
||||||
if (player == null) return false;
|
|
||||||
return viewers.containsKey(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMapId(OfflinePlayer player) {
|
|
||||||
if (isViewing(player)) {
|
|
||||||
return viewers.get(player.getUniqueId());
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(ArrayImage content) {
|
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
|
||||||
if (duplicate != null) {
|
|
||||||
MapWrapper_v1_14_R1.this.content = duplicate.getContent();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper_v1_14_R1.this.content = content;
|
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
|
||||||
sendContent(Bukkit.getPlayer(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return MapWrapper_v1_14_R1.this.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player) {
|
|
||||||
sendContent(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player, boolean withoutQueue) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
int id = getMapId(player);
|
|
||||||
if (withoutQueue) {
|
|
||||||
MapSender_v1_14_R1.sendMap(id, MapWrapper_v1_14_R1.this.content, player);
|
|
||||||
} else {
|
|
||||||
MapSender_v1_14_R1.addToQueue(id, MapWrapper_v1_14_R1.this.content, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot, boolean force) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
if (player.getGameMode() == GameMode.CREATIVE && !force) return;
|
|
||||||
|
|
||||||
if (slot < 9) {
|
|
||||||
slot += 36;
|
|
||||||
} else if (slot > 35 && slot != 45) {
|
|
||||||
slot = 8 - (slot - 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
|
||||||
int windowId = craftPlayer.getHandle().defaultContainer.windowId;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
net.minecraft.server.v1_14_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack);
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot) {
|
|
||||||
showInInventory(player, slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player, boolean force) {
|
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player) {
|
|
||||||
showInHand(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame) {
|
|
||||||
showInFrame(player, frame, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
|
||||||
if (frame.getItem().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInFrame(player, frame.getEntityId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId) {
|
|
||||||
showInFrame(player, entityId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
if (debugInfo != null) {
|
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
|
||||||
itemMeta.setDisplayName(debugInfo);
|
|
||||||
stack.setItemMeta(itemMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
|
||||||
if (frame != null) {
|
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_14_R1.this));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, int entityId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, ItemFrame frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().getEntity(entityId);
|
|
||||||
if (entity == null) return null;
|
|
||||||
|
|
||||||
org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity();
|
|
||||||
if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
|
||||||
net.minecraft.server.v1_14_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
|
||||||
DataWatcherObject<net.minecraft.server.v1_14_R1.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.server.v1_14_R1.ItemStack>) getField(EntityItemFrame.class, "ITEM");
|
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public MapWrapper_v1_14_R1(ArrayImage image) {
|
|
||||||
super(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.server.v1_14_R1.*;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class PacketListener_v1_14_R1 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap) {
|
|
||||||
PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet;
|
|
||||||
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity) {
|
|
||||||
PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet;
|
|
||||||
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action
|
|
||||||
EnumHand hand = packetPlayInUseEntity.c(); //hand
|
|
||||||
Vec3D pos = packetPlayInUseEntity.d(); //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, action.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet;
|
|
||||||
|
|
||||||
int slot = packetPlayInSetCreativeSlot.b();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.getItemStack();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline();
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel;
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0);
|
|
||||||
|
|
||||||
Vec3D vec3dObj = (Vec3D) vec3d;
|
|
||||||
return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_15_R1</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.15.2-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>11</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_15_R1.PacketPlayOutMap;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class MapSender_v1_15_R1 {
|
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
|
||||||
private static int senderID = -1;
|
|
||||||
|
|
||||||
public static void addToQueue(final int id, final ArrayImage content, final Player player) {
|
|
||||||
QueuedMap toSend = new QueuedMap(id, content, player);
|
|
||||||
if (sendQueue.contains(toSend)) return;
|
|
||||||
sendQueue.add(toSend);
|
|
||||||
|
|
||||||
runSender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runSender() {
|
|
||||||
if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
if (sendQueue.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) {
|
|
||||||
QueuedMap current = sendQueue.get(0);
|
|
||||||
if (current == null) return;
|
|
||||||
|
|
||||||
sendMap(current.id, current.image, current.player);
|
|
||||||
|
|
||||||
if (!sendQueue.isEmpty()) sendQueue.remove(0);
|
|
||||||
}
|
|
||||||
}, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMap(final int id0, final ArrayImage content, final Player player) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
|
||||||
List<QueuedMap> toRemove = new ArrayList<>();
|
|
||||||
for (QueuedMap qMap : sendQueue) {
|
|
||||||
if (qMap == null) continue;
|
|
||||||
|
|
||||||
if (qMap.player == null || !qMap.player.isOnline()) {
|
|
||||||
toRemove.add(qMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().cancelTask(senderID);
|
|
||||||
sendQueue.removeAll(toRemove);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int id = -id0;
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
try {
|
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale
|
|
||||||
false, //Tracking position
|
|
||||||
false, //Locked
|
|
||||||
new ArrayList<>(), //Icons
|
|
||||||
content.array, //Data
|
|
||||||
content.minX, //X pos
|
|
||||||
content.minY, //Y pos
|
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY //Y size (2nd Y pos)
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class QueuedMap {
|
|
||||||
private final int id;
|
|
||||||
private final ArrayImage image;
|
|
||||||
private final Player player;
|
|
||||||
|
|
||||||
QueuedMap(int id, ArrayImage image, Player player) {
|
|
||||||
this.id = id;
|
|
||||||
this.image = image;
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == this) return true;
|
|
||||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
|
||||||
var that = (QueuedMap) obj;
|
|
||||||
return this.id == that.id &&
|
|
||||||
Objects.equals(this.image, that.image) &&
|
|
||||||
Objects.equals(this.player, that.player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id, image, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "QueuedMap[" +
|
|
||||||
"id=" + id + ", " +
|
|
||||||
"image=" + image + ", " +
|
|
||||||
"player=" + player + ']';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,252 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_15_R1.*;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class MapWrapper_v1_15_R1 extends MapWrapper {
|
|
||||||
|
|
||||||
protected MapController controller = new MapController() {
|
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewer(Player player) throws MapLimitExceededException {
|
|
||||||
if (!isViewing(player)) {
|
|
||||||
viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeViewer(OfflinePlayer player) {
|
|
||||||
viewers.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearViewers() {
|
|
||||||
for (UUID uuid : viewers.keySet()) {
|
|
||||||
viewers.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewing(OfflinePlayer player) {
|
|
||||||
if (player == null) return false;
|
|
||||||
return viewers.containsKey(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMapId(OfflinePlayer player) {
|
|
||||||
if (isViewing(player)) {
|
|
||||||
return viewers.get(player.getUniqueId());
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(ArrayImage content) {
|
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
|
||||||
if (duplicate != null) {
|
|
||||||
MapWrapper_v1_15_R1.this.content = duplicate.getContent();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper_v1_15_R1.this.content = content;
|
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
|
||||||
sendContent(Bukkit.getPlayer(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return MapWrapper_v1_15_R1.this.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player) {
|
|
||||||
sendContent(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player, boolean withoutQueue) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
int id = getMapId(player);
|
|
||||||
if (withoutQueue) {
|
|
||||||
MapSender_v1_15_R1.sendMap(id, MapWrapper_v1_15_R1.this.content, player);
|
|
||||||
} else {
|
|
||||||
MapSender_v1_15_R1.addToQueue(id, MapWrapper_v1_15_R1.this.content, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot, boolean force) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
if (player.getGameMode() == GameMode.CREATIVE && !force) return;
|
|
||||||
|
|
||||||
if (slot < 9) {
|
|
||||||
slot += 36;
|
|
||||||
} else if (slot > 35 && slot != 45) {
|
|
||||||
slot = 8 - (slot - 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
|
||||||
int windowId = craftPlayer.getHandle().defaultContainer.windowId;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
net.minecraft.server.v1_15_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack);
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot) {
|
|
||||||
showInInventory(player, slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player, boolean force) {
|
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player) {
|
|
||||||
showInHand(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame) {
|
|
||||||
showInFrame(player, frame, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
|
||||||
if (frame.getItem().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInFrame(player, frame.getEntityId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId) {
|
|
||||||
showInFrame(player, entityId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
if (debugInfo != null) {
|
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
|
||||||
itemMeta.setDisplayName(debugInfo);
|
|
||||||
stack.setItemMeta(itemMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
|
||||||
if (frame != null) {
|
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_15_R1.this));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, int entityId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, ItemFrame frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().getEntity(entityId);
|
|
||||||
if (entity == null) return null;
|
|
||||||
|
|
||||||
org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity();
|
|
||||||
if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
|
||||||
net.minecraft.server.v1_15_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
|
||||||
DataWatcherObject<net.minecraft.server.v1_15_R1.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.server.v1_15_R1.ItemStack>) getField(EntityItemFrame.class, "ITEM");
|
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public MapWrapper_v1_15_R1(ArrayImage image) {
|
|
||||||
super(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.server.v1_15_R1.*;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class PacketListener_v1_15_R1 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap) {
|
|
||||||
PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet;
|
|
||||||
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity) {
|
|
||||||
PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet;
|
|
||||||
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action
|
|
||||||
EnumHand hand = packetPlayInUseEntity.c(); //hand
|
|
||||||
Vec3D pos = packetPlayInUseEntity.d(); //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, action.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet;
|
|
||||||
|
|
||||||
int slot = packetPlayInSetCreativeSlot.b();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.getItemStack();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline();
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel;
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0);
|
|
||||||
|
|
||||||
Vec3D vec3dObj = (Vec3D) vec3d;
|
|
||||||
return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_16_R3</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.16.4-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>11</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_16_R3.PacketPlayOutMap;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class MapSender_v1_16_R3 {
|
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
|
||||||
private static int senderID = -1;
|
|
||||||
|
|
||||||
public static void addToQueue(final int id, final ArrayImage content, final Player player) {
|
|
||||||
QueuedMap toSend = new QueuedMap(id, content, player);
|
|
||||||
if (sendQueue.contains(toSend)) return;
|
|
||||||
sendQueue.add(toSend);
|
|
||||||
|
|
||||||
runSender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runSender() {
|
|
||||||
if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
if (sendQueue.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) {
|
|
||||||
QueuedMap current = sendQueue.get(0);
|
|
||||||
if (current == null) return;
|
|
||||||
|
|
||||||
sendMap(current.id, current.image, current.player);
|
|
||||||
|
|
||||||
if (!sendQueue.isEmpty()) sendQueue.remove(0);
|
|
||||||
}
|
|
||||||
}, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMap(final int id0, final ArrayImage content, final Player player) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
|
||||||
List<QueuedMap> toRemove = new ArrayList<>();
|
|
||||||
for (QueuedMap qMap : sendQueue) {
|
|
||||||
if (qMap == null) continue;
|
|
||||||
|
|
||||||
if (qMap.player == null || !qMap.player.isOnline()) {
|
|
||||||
toRemove.add(qMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().cancelTask(senderID);
|
|
||||||
sendQueue.removeAll(toRemove);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int id = -id0;
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
try {
|
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale
|
|
||||||
false, //Tracking position
|
|
||||||
false, //Locked
|
|
||||||
new ArrayList<>(), //Icons
|
|
||||||
content.array, //Data
|
|
||||||
content.minX, //X pos
|
|
||||||
content.minY, //Y pos
|
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY //Y size (2nd Y pos)
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class QueuedMap {
|
|
||||||
private final int id;
|
|
||||||
private final ArrayImage image;
|
|
||||||
private final Player player;
|
|
||||||
|
|
||||||
QueuedMap(int id, ArrayImage image, Player player) {
|
|
||||||
this.id = id;
|
|
||||||
this.image = image;
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == this) return true;
|
|
||||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
|
||||||
var that = (QueuedMap) obj;
|
|
||||||
return this.id == that.id &&
|
|
||||||
Objects.equals(this.image, that.image) &&
|
|
||||||
Objects.equals(this.player, that.player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id, image, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "QueuedMap[" +
|
|
||||||
"id=" + id + ", " +
|
|
||||||
"image=" + image + ", " +
|
|
||||||
"player=" + player + ']';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,251 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_16_R3.*;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class MapWrapper_v1_16_R3 extends MapWrapper {
|
|
||||||
protected MapController controller = new MapController() {
|
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewer(Player player) throws MapLimitExceededException {
|
|
||||||
if (!isViewing(player)) {
|
|
||||||
viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeViewer(OfflinePlayer player) {
|
|
||||||
viewers.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearViewers() {
|
|
||||||
for (UUID uuid : viewers.keySet()) {
|
|
||||||
viewers.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewing(OfflinePlayer player) {
|
|
||||||
if (player == null) return false;
|
|
||||||
return viewers.containsKey(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMapId(OfflinePlayer player) {
|
|
||||||
if (isViewing(player)) {
|
|
||||||
return viewers.get(player.getUniqueId());
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(ArrayImage content) {
|
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
|
||||||
if (duplicate != null) {
|
|
||||||
MapWrapper_v1_16_R3.this.content = duplicate.getContent();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper_v1_16_R3.this.content = content;
|
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
|
||||||
sendContent(Bukkit.getPlayer(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return MapWrapper_v1_16_R3.this.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player) {
|
|
||||||
sendContent(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player, boolean withoutQueue) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
int id = getMapId(player);
|
|
||||||
if (withoutQueue) {
|
|
||||||
MapSender_v1_16_R3.sendMap(id, MapWrapper_v1_16_R3.this.content, player);
|
|
||||||
} else {
|
|
||||||
MapSender_v1_16_R3.addToQueue(id, MapWrapper_v1_16_R3.this.content, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot, boolean force) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
if (player.getGameMode() == GameMode.CREATIVE && !force) return;
|
|
||||||
|
|
||||||
if (slot < 9) {
|
|
||||||
slot += 36;
|
|
||||||
} else if (slot > 35 && slot != 45) {
|
|
||||||
slot = 8 - (slot - 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
|
||||||
int windowId = craftPlayer.getHandle().defaultContainer.windowId;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
net.minecraft.server.v1_16_R3.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack);
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot) {
|
|
||||||
showInInventory(player, slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player, boolean force) {
|
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player) {
|
|
||||||
showInHand(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame) {
|
|
||||||
showInFrame(player, frame, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
|
||||||
if (frame.getItem().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInFrame(player, frame.getEntityId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId) {
|
|
||||||
showInFrame(player, entityId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
if (debugInfo != null) {
|
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
|
||||||
itemMeta.setDisplayName(debugInfo);
|
|
||||||
stack.setItemMeta(itemMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
|
||||||
if (frame != null) {
|
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_16_R3.this));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, int entityId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, ItemFrame frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().getEntity(entityId);
|
|
||||||
if (entity == null) return null;
|
|
||||||
|
|
||||||
org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity();
|
|
||||||
if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
|
||||||
net.minecraft.server.v1_16_R3.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
|
||||||
DataWatcherObject<net.minecraft.server.v1_16_R3.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.server.v1_16_R3.ItemStack>) getField(EntityItemFrame.class, "ITEM");
|
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public MapWrapper_v1_16_R3(ArrayImage image) {
|
|
||||||
super(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.server.v1_16_R3.*;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class PacketListener_v1_16_R3 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap) {
|
|
||||||
PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet;
|
|
||||||
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity) {
|
|
||||||
PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet;
|
|
||||||
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action
|
|
||||||
EnumHand hand = packetPlayInUseEntity.c(); //hand
|
|
||||||
Vec3D pos = packetPlayInUseEntity.d(); //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, action.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet;
|
|
||||||
|
|
||||||
int slot = packetPlayInSetCreativeSlot.b();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.getItemStack();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline();
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel;
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0);
|
|
||||||
|
|
||||||
Vec3D vec3dObj = (Vec3D) vec3d;
|
|
||||||
return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ This file is part of MapReflectionAPI.
|
|
||||||
~ Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
~
|
|
||||||
~ 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 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_17_R1</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.17.1-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>16</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
|
||||||
import net.minecraft.world.level.saveddata.maps.WorldMap;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MapSender_v1_17_R1 {
|
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
|
||||||
private static int senderID = -1;
|
|
||||||
|
|
||||||
public static void addToQueue(final int id, final ArrayImage content, final Player player) {
|
|
||||||
QueuedMap toSend = new QueuedMap(id, content, player);
|
|
||||||
if (sendQueue.contains(toSend)) return;
|
|
||||||
sendQueue.add(toSend);
|
|
||||||
|
|
||||||
runSender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runSender() {
|
|
||||||
if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
if (sendQueue.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) {
|
|
||||||
QueuedMap current = sendQueue.get(0);
|
|
||||||
if (current == null) return;
|
|
||||||
|
|
||||||
sendMap(current.id, current.image, current.player);
|
|
||||||
|
|
||||||
if (!sendQueue.isEmpty()) sendQueue.remove(0);
|
|
||||||
}
|
|
||||||
}, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMap(final int id0, final ArrayImage content, final Player player) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
|
||||||
List<QueuedMap> toRemove = new ArrayList<>();
|
|
||||||
for (QueuedMap qMap : sendQueue) {
|
|
||||||
if (qMap == null) continue;
|
|
||||||
|
|
||||||
if (qMap.player == null || !qMap.player.isOnline()) {
|
|
||||||
toRemove.add(qMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().cancelTask(senderID);
|
|
||||||
sendQueue.removeAll(toRemove);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int id = -id0;
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
try {
|
|
||||||
WorldMap.b updateData = new WorldMap.b(
|
|
||||||
content.minX, //X pos
|
|
||||||
content.minY, //Y pos
|
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY, //Y size (2nd Y pos)
|
|
||||||
content.array //Data
|
|
||||||
);
|
|
||||||
|
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale
|
|
||||||
false, //Show icons
|
|
||||||
new ArrayList<>(), //Icons
|
|
||||||
updateData
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().b.sendPacket(packet); //connection send()
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
record QueuedMap(int id, ArrayImage image, Player player) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,254 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
|
|
||||||
import net.minecraft.network.syncher.DataWatcher;
|
|
||||||
import net.minecraft.network.syncher.DataWatcherObject;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class MapWrapper_v1_17_R1 extends MapWrapper {
|
|
||||||
protected MapController controller = new MapController() {
|
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewer(Player player) throws MapLimitExceededException {
|
|
||||||
if (!isViewing(player)) {
|
|
||||||
viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeViewer(OfflinePlayer player) {
|
|
||||||
viewers.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearViewers() {
|
|
||||||
for (UUID uuid : viewers.keySet()) {
|
|
||||||
viewers.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewing(OfflinePlayer player) {
|
|
||||||
if (player == null) return false;
|
|
||||||
return viewers.containsKey(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMapId(OfflinePlayer player) {
|
|
||||||
if (isViewing(player)) {
|
|
||||||
return viewers.get(player.getUniqueId());
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(ArrayImage content) {
|
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
|
||||||
if (duplicate != null) {
|
|
||||||
MapWrapper_v1_17_R1.this.content = duplicate.getContent();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper_v1_17_R1.this.content = content;
|
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
|
||||||
sendContent(Bukkit.getPlayer(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return MapWrapper_v1_17_R1.this.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player) {
|
|
||||||
sendContent(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player, boolean withoutQueue) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
int id = getMapId(player);
|
|
||||||
if (withoutQueue) {
|
|
||||||
MapSender_v1_17_R1.sendMap(id, MapWrapper_v1_17_R1.this.content, player);
|
|
||||||
} else {
|
|
||||||
MapSender_v1_17_R1.addToQueue(id, MapWrapper_v1_17_R1.this.content, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot, boolean force) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
if (player.getGameMode() == GameMode.CREATIVE && !force) return;
|
|
||||||
|
|
||||||
if (slot < 9) {
|
|
||||||
slot += 36;
|
|
||||||
} else if (slot > 35 && slot != 45) {
|
|
||||||
slot = 8 - (slot - 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
|
||||||
int windowId = craftPlayer.getHandle().bU.j; //inventoryMenu containerId
|
|
||||||
int stateId = craftPlayer.getHandle().bU.getStateId(); //inventoryMenu getStateId()
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, stateId, slot, nmsStack);
|
|
||||||
((CraftPlayer) player).getHandle().b.sendPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot) {
|
|
||||||
showInInventory(player, slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player, boolean force) {
|
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player) {
|
|
||||||
showInHand(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame) {
|
|
||||||
showInFrame(player, frame, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
|
||||||
if (frame.getItem().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInFrame(player, frame.getEntityId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId) {
|
|
||||||
showInFrame(player, entityId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
if (debugInfo != null) {
|
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
|
||||||
itemMeta.setDisplayName(debugInfo);
|
|
||||||
stack.setItemMeta(itemMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
|
||||||
if (frame != null) {
|
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_17_R1.this));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, int entityId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, ItemFrame frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().getEntity(entityId);
|
|
||||||
if (entity == null) return null;
|
|
||||||
|
|
||||||
if (entity instanceof ItemFrame) return (ItemFrame) entity;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
|
||||||
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
|
||||||
DataWatcherObject<net.minecraft.world.item.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.world.item.ItemStack>) getField(EntityItemFrame.class, "ao");
|
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().b.sendPacket(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public MapWrapper_v1_17_R1(ArrayImage image) {
|
|
||||||
super(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInUseEntity;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
|
||||||
import net.minecraft.world.EnumHand;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.phys.Vec3D;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.*;
|
|
||||||
|
|
||||||
public class PacketListener_v1_17_R1 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap packetPlayOutMap) {
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity packetPlayInUseEntity) {
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
Object action = getField(packetPlayInUseEntity, "b"); //action
|
|
||||||
Enum<?> actionEnum = (Enum<?>) getValue(action, "a"); //action type
|
|
||||||
EnumHand hand = hasField(action, "a") ? (EnumHand) getField(action, "a") : null; //hand
|
|
||||||
Vec3D pos = hasField(action, "b") ? (Vec3D) getField(action, "b") : null; //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, actionEnum.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot) {
|
|
||||||
int slot = packetPlayInSetCreativeSlot.b();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.getItemStack();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().b.a.k.pipeline(); //connection connection channel
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().b.a.k; //connection connection channel
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D vec3dObj)) return new Vector(0, 0, 0);
|
|
||||||
return new Vector(vec3dObj.b, vec3dObj.c, vec3dObj.d); //x, y, z
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ This file is part of MapReflectionAPI.
|
|
||||||
~ Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
~
|
|
||||||
~ 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 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_18_R2</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.18.2-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>17</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
|
||||||
import net.minecraft.world.level.saveddata.maps.WorldMap;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MapSender_v1_18_R2 {
|
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
|
||||||
private static int senderID = -1;
|
|
||||||
|
|
||||||
public static void addToQueue(final int id, final ArrayImage content, final Player player) {
|
|
||||||
QueuedMap toSend = new QueuedMap(id, content, player);
|
|
||||||
if (sendQueue.contains(toSend)) return;
|
|
||||||
sendQueue.add(toSend);
|
|
||||||
|
|
||||||
runSender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runSender() {
|
|
||||||
if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
if (sendQueue.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) {
|
|
||||||
QueuedMap current = sendQueue.get(0);
|
|
||||||
if (current == null) return;
|
|
||||||
|
|
||||||
sendMap(current.id, current.image, current.player);
|
|
||||||
|
|
||||||
if (!sendQueue.isEmpty()) sendQueue.remove(0);
|
|
||||||
}
|
|
||||||
}, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMap(final int id0, final ArrayImage content, final Player player) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
|
||||||
List<QueuedMap> toRemove = new ArrayList<>();
|
|
||||||
for (QueuedMap qMap : sendQueue) {
|
|
||||||
if (qMap == null) continue;
|
|
||||||
|
|
||||||
if (qMap.player == null || !qMap.player.isOnline()) {
|
|
||||||
toRemove.add(qMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().cancelTask(senderID);
|
|
||||||
sendQueue.removeAll(toRemove);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int id = -id0;
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
try {
|
|
||||||
WorldMap.b updateData = new WorldMap.b(
|
|
||||||
content.minX, //X pos
|
|
||||||
content.minY, //Y pos
|
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY, //Y size (2nd Y pos)
|
|
||||||
content.array //Data
|
|
||||||
);
|
|
||||||
|
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale
|
|
||||||
false, //Show icons
|
|
||||||
new ArrayList<>(), //Icons
|
|
||||||
updateData
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().b.a(packet); //connection send()
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
record QueuedMap(int id, ArrayImage image, Player player) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,254 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
|
|
||||||
import net.minecraft.network.syncher.DataWatcher;
|
|
||||||
import net.minecraft.network.syncher.DataWatcherObject;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class MapWrapper_v1_18_R2 extends MapWrapper {
|
|
||||||
protected MapController controller = new MapController() {
|
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewer(Player player) throws MapLimitExceededException {
|
|
||||||
if (!isViewing(player)) {
|
|
||||||
viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeViewer(OfflinePlayer player) {
|
|
||||||
viewers.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearViewers() {
|
|
||||||
for (UUID uuid : viewers.keySet()) {
|
|
||||||
viewers.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewing(OfflinePlayer player) {
|
|
||||||
if (player == null) return false;
|
|
||||||
return viewers.containsKey(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMapId(OfflinePlayer player) {
|
|
||||||
if (isViewing(player)) {
|
|
||||||
return viewers.get(player.getUniqueId());
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(ArrayImage content) {
|
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
|
||||||
if (duplicate != null) {
|
|
||||||
MapWrapper_v1_18_R2.this.content = duplicate.getContent();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper_v1_18_R2.this.content = content;
|
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
|
||||||
sendContent(Bukkit.getPlayer(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return MapWrapper_v1_18_R2.this.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player) {
|
|
||||||
sendContent(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player, boolean withoutQueue) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
int id = getMapId(player);
|
|
||||||
if (withoutQueue) {
|
|
||||||
MapSender_v1_18_R2.sendMap(id, MapWrapper_v1_18_R2.this.content, player);
|
|
||||||
} else {
|
|
||||||
MapSender_v1_18_R2.addToQueue(id, MapWrapper_v1_18_R2.this.content, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot, boolean force) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
if (player.getGameMode() == GameMode.CREATIVE && !force) return;
|
|
||||||
|
|
||||||
if (slot < 9) {
|
|
||||||
slot += 36;
|
|
||||||
} else if (slot > 35 && slot != 45) {
|
|
||||||
slot = 8 - (slot - 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
|
||||||
int windowId = craftPlayer.getHandle().bU.j; //inventoryMenu containerId
|
|
||||||
int stateId = craftPlayer.getHandle().bU.j(); //inventoryMenu getStateId()
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, stateId, slot, nmsStack);
|
|
||||||
((CraftPlayer) player).getHandle().b.a(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot) {
|
|
||||||
showInInventory(player, slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player, boolean force) {
|
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player) {
|
|
||||||
showInHand(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame) {
|
|
||||||
showInFrame(player, frame, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
|
||||||
if (frame.getItem().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInFrame(player, frame.getEntityId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId) {
|
|
||||||
showInFrame(player, entityId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
if (debugInfo != null) {
|
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
|
||||||
itemMeta.setDisplayName(debugInfo);
|
|
||||||
stack.setItemMeta(itemMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
|
||||||
if (frame != null) {
|
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_18_R2.this));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, int entityId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, ItemFrame frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().a(entityId);
|
|
||||||
if (entity == null) return null;
|
|
||||||
|
|
||||||
if (entity instanceof ItemFrame) return (ItemFrame) entity;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
|
||||||
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
nmsStack.u().a("map", mapId); //getOrCreateTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
|
||||||
DataWatcherObject<net.minecraft.world.item.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.world.item.ItemStack>) getField(EntityItemFrame.class, "ao");
|
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().b.a(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public MapWrapper_v1_18_R2(ArrayImage image) {
|
|
||||||
super(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInUseEntity;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
|
||||||
import net.minecraft.world.EnumHand;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.phys.Vec3D;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.*;
|
|
||||||
|
|
||||||
public class PacketListener_v1_18_R2 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap packetPlayOutMap) {
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity packetPlayInUseEntity) {
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
Object action = getField(packetPlayInUseEntity, "b"); //action
|
|
||||||
Enum<?> actionEnum = (Enum<?>) getValue(action, "a"); //action type
|
|
||||||
EnumHand hand = hasField(action, "a") ? (EnumHand) getField(action, "a") : null; //hand
|
|
||||||
Vec3D pos = hasField(action, "b") ? (Vec3D) getField(action, "b") : null; //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, actionEnum.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot) {
|
|
||||||
int slot = packetPlayInSetCreativeSlot.b();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.c();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().b.a.m.pipeline(); //connection connection channel
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().b.a.m; //connection connection channel
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D vec3dObj)) return new Vector(0, 0, 0);
|
|
||||||
return new Vector(vec3dObj.b, vec3dObj.c, vec3dObj.d); //x, y, z
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ This file is part of MapReflectionAPI.
|
|
||||||
~ Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
~
|
|
||||||
~ 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 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>MapReflectionAPI-NMS-v1_19_R1</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<NMSVersion>1.19-R0.1-SNAPSHOT</NMSVersion>
|
|
||||||
<jdk.version>17</jdk.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.9.0-SNAPSHOT</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>craftbukkit</artifactId>
|
|
||||||
<version>${NMSVersion}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
|
||||||
<artifactId>MapReflectionAPI-API</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
|
||||||
import net.minecraft.world.level.saveddata.maps.WorldMap;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MapSender_v1_19_R1 {
|
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
|
||||||
private static int senderID = -1;
|
|
||||||
|
|
||||||
public static void addToQueue(final int id, final ArrayImage content, final Player player) {
|
|
||||||
QueuedMap toSend = new QueuedMap(id, content, player);
|
|
||||||
if (sendQueue.contains(toSend)) return;
|
|
||||||
sendQueue.add(toSend);
|
|
||||||
|
|
||||||
runSender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runSender() {
|
|
||||||
if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
if (sendQueue.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) {
|
|
||||||
QueuedMap current = sendQueue.get(0);
|
|
||||||
if (current == null) return;
|
|
||||||
|
|
||||||
sendMap(current.id, current.image, current.player);
|
|
||||||
|
|
||||||
if (!sendQueue.isEmpty()) sendQueue.remove(0);
|
|
||||||
}
|
|
||||||
}, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMap(final int id0, final ArrayImage content, final Player player) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
|
||||||
List<QueuedMap> toRemove = new ArrayList<>();
|
|
||||||
for (QueuedMap qMap : sendQueue) {
|
|
||||||
if (qMap == null) continue;
|
|
||||||
|
|
||||||
if (qMap.player == null || !qMap.player.isOnline()) {
|
|
||||||
toRemove.add(qMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().cancelTask(senderID);
|
|
||||||
sendQueue.removeAll(toRemove);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int id = -id0;
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
try {
|
|
||||||
WorldMap.b updateData = new WorldMap.b(
|
|
||||||
content.minX, //X pos
|
|
||||||
content.minY, //Y pos
|
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY, //Y size (2nd Y pos)
|
|
||||||
content.array //Data
|
|
||||||
);
|
|
||||||
|
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale
|
|
||||||
false, //Show icons
|
|
||||||
new ArrayList<>(), //Icons
|
|
||||||
updateData
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().b.a(packet); //connection send()
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
record QueuedMap(int id, ArrayImage image, Player player) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,254 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
|
|
||||||
import net.minecraft.network.syncher.DataWatcher;
|
|
||||||
import net.minecraft.network.syncher.DataWatcherObject;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
|
||||||
|
|
||||||
public class MapWrapper_v1_19_R1 extends MapWrapper {
|
|
||||||
protected MapController controller = new MapController() {
|
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewer(Player player) throws MapLimitExceededException {
|
|
||||||
if (!isViewing(player)) {
|
|
||||||
viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeViewer(OfflinePlayer player) {
|
|
||||||
viewers.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearViewers() {
|
|
||||||
for (UUID uuid : viewers.keySet()) {
|
|
||||||
viewers.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewing(OfflinePlayer player) {
|
|
||||||
if (player == null) return false;
|
|
||||||
return viewers.containsKey(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMapId(OfflinePlayer player) {
|
|
||||||
if (isViewing(player)) {
|
|
||||||
return viewers.get(player.getUniqueId());
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(ArrayImage content) {
|
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
|
||||||
if (duplicate != null) {
|
|
||||||
MapWrapper_v1_19_R1.this.content = duplicate.getContent();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper_v1_19_R1.this.content = content;
|
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
|
||||||
sendContent(Bukkit.getPlayer(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayImage getContent() {
|
|
||||||
return MapWrapper_v1_19_R1.this.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player) {
|
|
||||||
sendContent(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContent(Player player, boolean withoutQueue) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
int id = getMapId(player);
|
|
||||||
if (withoutQueue) {
|
|
||||||
MapSender_v1_19_R1.sendMap(id, MapWrapper_v1_19_R1.this.content, player);
|
|
||||||
} else {
|
|
||||||
MapSender_v1_19_R1.addToQueue(id, MapWrapper_v1_19_R1.this.content, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot, boolean force) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
if (player.getGameMode() == GameMode.CREATIVE && !force) return;
|
|
||||||
|
|
||||||
if (slot < 9) {
|
|
||||||
slot += 36;
|
|
||||||
} else if (slot > 35 && slot != 45) {
|
|
||||||
slot = 8 - (slot - 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
|
||||||
int windowId = craftPlayer.getHandle().bT.j; //inventoryMenu containerId
|
|
||||||
int stateId = craftPlayer.getHandle().bT.j(); //inventoryMenu getStateId()
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, stateId, slot, nmsStack);
|
|
||||||
((CraftPlayer) player).getHandle().b.a(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInInventory(Player player, int slot) {
|
|
||||||
showInInventory(player, slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player, boolean force) {
|
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInHand(Player player) {
|
|
||||||
showInHand(player, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame) {
|
|
||||||
showInFrame(player, frame, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
|
||||||
if (frame.getItem().getType() != Material.FILLED_MAP && !force) return;
|
|
||||||
showInFrame(player, frame.getEntityId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId) {
|
|
||||||
showInFrame(player, entityId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
|
||||||
if (!isViewing(player)) return;
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.FILLED_MAP, 1);
|
|
||||||
if (debugInfo != null) {
|
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
|
||||||
itemMeta.setDisplayName(debugInfo);
|
|
||||||
stack.setItemMeta(itemMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> {
|
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
|
||||||
if (frame != null) {
|
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_19_R1.this));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, int entityId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearFrame(Player player, ItemFrame frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().a(entityId);
|
|
||||||
if (entity == null) return null;
|
|
||||||
|
|
||||||
if (entity instanceof ItemFrame) return (ItemFrame) entity;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
|
||||||
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
nmsStack.v().a("map", mapId); //getOrCreateTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
|
||||||
DataWatcherObject<net.minecraft.world.item.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.world.item.ItemStack>) getField(EntityItemFrame.class, "ao");
|
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().b.a(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public MapWrapper_v1_19_R1(ArrayImage image) {
|
|
||||||
super(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of MapReflectionAPI.
|
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
|
||||||
*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
|
||||||
|
|
||||||
import io.netty.channel.*;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInUseEntity;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
|
||||||
import net.minecraft.world.EnumHand;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.phys.Vec3D;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.*;
|
|
||||||
|
|
||||||
public class PacketListener_v1_19_R1 extends PacketListener {
|
|
||||||
@Override
|
|
||||||
protected void injectPlayer(Player p) {
|
|
||||||
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
|
|
||||||
@Override
|
|
||||||
//On send packet
|
|
||||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayOutMap packetPlayOutMap) {
|
|
||||||
int id = (int) getField(packetPlayOutMap, "a");
|
|
||||||
|
|
||||||
if (id < 0) {
|
|
||||||
//It's one of our maps, invert ID and let through!
|
|
||||||
int newId = -id;
|
|
||||||
setField(packetPlayOutMap, "a", newId); //mapId
|
|
||||||
} else {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapCancelEvent event = new MapCancelEvent(p, id, async);
|
|
||||||
if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true);
|
|
||||||
if (event.getHandlers().getRegisteredListeners().length > 0)
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.write(ctx, packet, promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
//On receive packet
|
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
|
||||||
if (packet instanceof PacketPlayInUseEntity packetPlayInUseEntity) {
|
|
||||||
int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId
|
|
||||||
Object action = getField(packetPlayInUseEntity, "b"); //action
|
|
||||||
Enum<?> actionEnum = (Enum<?>) getValue(action, "a"); //action type
|
|
||||||
EnumHand hand = hasField(action, "a") ? (EnumHand) getField(action, "a") : null; //hand
|
|
||||||
Vec3D pos = hasField(action, "b") ? (Vec3D) getField(action, "b") : null; //pos
|
|
||||||
|
|
||||||
if (Bukkit.getScheduler().callSyncMethod(plugin, () -> {
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
MapInteractEvent event = new MapInteractEvent(p, entityId, actionEnum.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
|
|
||||||
if (event.getFrame() != null && event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).get(1, TimeUnit.SECONDS)) return;
|
|
||||||
} else if (packet instanceof PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot) {
|
|
||||||
int slot = packetPlayInSetCreativeSlot.b();
|
|
||||||
ItemStack item = packetPlayInSetCreativeSlot.c();
|
|
||||||
|
|
||||||
boolean async = !plugin.getServer().isPrimaryThread();
|
|
||||||
CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async);
|
|
||||||
if (event.getMapWrapper() != null) {
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
if (event.isCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.channelRead(ctx, packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().b.b.m.pipeline(); //connection connection channel
|
|
||||||
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
Channel channel = ((CraftPlayer) p).getHandle().b.b.m; //connection connection channel
|
|
||||||
channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vector vec3DToVector(Object vec3d) {
|
|
||||||
if (!(vec3d instanceof Vec3D vec3dObj)) return new Vector(0, 0, 0);
|
|
||||||
return new Vector(vec3dObj.c, vec3dObj.d, vec3dObj.e); //x, y, z
|
|
||||||
}
|
|
||||||
}
|
|
116
pom.xml
116
pom.xml
|
@ -1,4 +1,27 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ 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 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.
|
||||||
|
-->
|
||||||
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
@ -6,69 +29,50 @@
|
||||||
|
|
||||||
<groupId>tech.sbdevelopment</groupId>
|
<groupId>tech.sbdevelopment</groupId>
|
||||||
<artifactId>MapReflectionAPI</artifactId>
|
<artifactId>MapReflectionAPI</artifactId>
|
||||||
<packaging>pom</packaging>
|
<version>1.1</version>
|
||||||
<version>${revision}</version>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>MapReflectionAPI</name>
|
||||||
|
<description>This API helps developer with viewing images on maps.</description>
|
||||||
|
<url>https://sbdplugins.nl</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<revision>1.0-SNAPSHOT</revision>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<jdk.version>11</jdk.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<modules>
|
|
||||||
<module>API</module>
|
|
||||||
<module>Dist</module>
|
|
||||||
<module>NMS-v1_19_R1</module>
|
|
||||||
<module>NMS-v1_18_R2</module>
|
|
||||||
<module>NMS-v1_17_R1</module>
|
|
||||||
<module>NMS-v1_16_R3</module>
|
|
||||||
<module>NMS-v1_15_R1</module>
|
|
||||||
<module>NMS-v1_14_R1</module>
|
|
||||||
<module>NMS-v1_13_R2</module>
|
|
||||||
<module>NMS-v1_12_R1</module>
|
|
||||||
</modules>
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<defaultGoal>clean package</defaultGoal>
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-toolchains-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.1.0</version>
|
<version>3.9.0-SNAPSHOT</version>
|
||||||
|
<configuration>
|
||||||
|
<release>11</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.3.1-SNAPSHOT</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>toolchain</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
|
||||||
<toolchains>
|
|
||||||
<jdk>
|
|
||||||
<version>${jdk.version}</version>
|
|
||||||
</jdk>
|
|
||||||
</toolchains>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.10.1</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${jdk.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>3.0.0-M2</version>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
@ -76,6 +80,14 @@
|
||||||
<id>spigot-repo</id>
|
<id>spigot-repo</id>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>MG-Dev Jenkins CI Maven Repository</id>
|
||||||
|
<url>https://ci.mg-dev.eu/plugin/repository/everything</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>dmulloy2-repo</id>
|
||||||
|
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -84,5 +96,17 @@
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.19-R0.1-SNAPSHOT</version>
|
<version>1.19-R0.1-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.bergerkiller.bukkit</groupId>
|
||||||
|
<artifactId>BKCommonLib</artifactId>
|
||||||
|
<version>1.19-v1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.comphenix.protocol</groupId>
|
||||||
|
<artifactId>ProtocolLib</artifactId>
|
||||||
|
<version>4.8.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi;
|
package tech.sbdevelopment.mapreflectionapi;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.ProtocolManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.map.MapView;
|
import org.bukkit.map.MapView;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
@ -35,7 +37,7 @@ import java.util.logging.Level;
|
||||||
public class MapReflectionAPI extends JavaPlugin {
|
public class MapReflectionAPI extends JavaPlugin {
|
||||||
private static MapReflectionAPI instance;
|
private static MapReflectionAPI instance;
|
||||||
private static MapManager mapManager;
|
private static MapManager mapManager;
|
||||||
private static PacketListener packetListener;
|
private ProtocolManager protocolManager;
|
||||||
|
|
||||||
public static MapReflectionAPI getInstance() {
|
public static MapReflectionAPI getInstance() {
|
||||||
if (instance == null) throw new IllegalStateException("The plugin is not enabled yet!");
|
if (instance == null) throw new IllegalStateException("The plugin is not enabled yet!");
|
||||||
|
@ -61,14 +63,8 @@ public class MapReflectionAPI extends JavaPlugin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
protocolManager = ProtocolLibrary.getProtocolManager();
|
||||||
packetListener = PacketListener.construct(this);
|
protocolManager.addPacketListener(new PacketListener(this));
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
getLogger().log(Level.SEVERE, e.getMessage(), e);
|
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
packetListener.init(this);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mapManager = new MapManager(this);
|
mapManager = new MapManager(this);
|
||||||
|
@ -99,9 +95,6 @@ public class MapReflectionAPI extends JavaPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
getLogger().info("Disabling the packet handler...");
|
|
||||||
if (packetListener != null) Bukkit.getOnlinePlayers().forEach(p -> packetListener.removePlayer(p));
|
|
||||||
|
|
||||||
getLogger().info("MapReflectionAPI is disabled!");
|
getLogger().info("MapReflectionAPI is disabled!");
|
||||||
|
|
||||||
instance = null;
|
instance = null;
|
|
@ -71,6 +71,16 @@ public class ArrayImage {
|
||||||
this.array = result;
|
this.array = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferedImage toBuffered() {
|
||||||
|
BufferedImage img = new BufferedImage(width, height, this.imageType);
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
img.setRGB(x, y, MapColorPalette.getRealColor(array[y * width + x]).getRGB());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
|
@ -21,20 +21,19 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
package tech.sbdevelopment.mapreflectionapi.api;
|
||||||
|
|
||||||
import net.minecraft.server.v1_12_R1.PacketPlayOutMap;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class MapSender_v1_12_R1 {
|
public class MapSender {
|
||||||
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
private static int senderID = -1;
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
@ -80,28 +79,55 @@ public class MapSender_v1_12_R1 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Class<?> packetClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutMap");
|
||||||
final int id = -id0;
|
final int id = -id0;
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
Object packet;
|
||||||
try {
|
if (ReflectionUtils.supports(17)) { //1.17+
|
||||||
PacketPlayOutMap packet = new PacketPlayOutMap(
|
Class<?> worldMapClass = ReflectionUtils.getNMSClass("world.level.saveddata.maps", "WorldMap");
|
||||||
id, //ID
|
Object updateData = ReflectionUtil.callConstructor(worldMapClass,
|
||||||
(byte) 0, //Scale
|
content.minX, //X pos
|
||||||
false, //???
|
content.minY, //Y pos
|
||||||
new ArrayList<>(), //Icons
|
content.maxX, //X size (2nd X pos)
|
||||||
content.array, //Data
|
content.maxY, //Y size (2nd Y pos)
|
||||||
content.minX, //X pos
|
content.array //Data
|
||||||
content.minY, //Y pos
|
);
|
||||||
content.maxX, //X size (2nd X pos)
|
|
||||||
content.maxY //Y size (2nd Y pos)
|
|
||||||
);
|
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
packet = ReflectionUtil.callConstructor(packetClass,
|
||||||
} catch (Exception e) {
|
id, //ID
|
||||||
e.printStackTrace();
|
(byte) 0, //Scale
|
||||||
}
|
false, //Show icons
|
||||||
});
|
new ArrayList<>(), //Icons
|
||||||
|
updateData
|
||||||
|
);
|
||||||
|
} else if (ReflectionUtils.supports(14)) { //1.16-1.14
|
||||||
|
packet = ReflectionUtil.callConstructor(packetClass,
|
||||||
|
id, //ID
|
||||||
|
(byte) 0, //Scale
|
||||||
|
false, //Tracking position
|
||||||
|
false, //Locked
|
||||||
|
new ArrayList<>(), //Icons
|
||||||
|
content.array, //Data
|
||||||
|
content.minX, //X pos
|
||||||
|
content.minY, //Y pos
|
||||||
|
content.maxX, //X size (2nd X pos)
|
||||||
|
content.maxY //Y size (2nd Y pos)
|
||||||
|
);
|
||||||
|
} else { //1.13-
|
||||||
|
packet = ReflectionUtil.callConstructor(packetClass,
|
||||||
|
id, //ID
|
||||||
|
(byte) 0, //Scale
|
||||||
|
false, //???
|
||||||
|
new ArrayList<>(), //Icons
|
||||||
|
content.array, //Data
|
||||||
|
content.minX, //X pos
|
||||||
|
content.minY, //Y pos
|
||||||
|
content.maxX, //X size (2nd X pos)
|
||||||
|
content.maxY //Y size (2nd Y pos)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReflectionUtils.sendPacket(player, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class QueuedMap {
|
static final class QueuedMap {
|
||||||
private final int id;
|
private final int id;
|
||||||
private final ArrayImage image;
|
private final ArrayImage image;
|
|
@ -21,32 +21,28 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.nms;
|
package tech.sbdevelopment.mapreflectionapi.api;
|
||||||
|
|
||||||
import net.minecraft.server.v1_12_R1.*;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.ItemFrame;
|
import org.bukkit.entity.ItemFrame;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
import org.bukkit.metadata.FixedMetadataValue;
|
||||||
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapController;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
|
|
||||||
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField;
|
public class MapWrapper {
|
||||||
import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField;
|
protected ArrayImage content;
|
||||||
|
|
||||||
|
public MapWrapper(ArrayImage image) {
|
||||||
|
this.content = image;
|
||||||
|
}
|
||||||
|
|
||||||
public class MapWrapper_v1_12_R1 extends MapWrapper {
|
|
||||||
protected MapController controller = new MapController() {
|
protected MapController controller = new MapController() {
|
||||||
private final Map<UUID, Integer> viewers = new HashMap<>();
|
private final Map<UUID, Integer> viewers = new HashMap<>();
|
||||||
|
|
||||||
|
@ -87,11 +83,11 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
public void update(ArrayImage content) {
|
public void update(ArrayImage content) {
|
||||||
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content);
|
||||||
if (duplicate != null) {
|
if (duplicate != null) {
|
||||||
MapWrapper_v1_12_R1.this.content = duplicate.getContent();
|
MapWrapper.this.content = duplicate.getContent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapWrapper_v1_12_R1.this.content = content;
|
MapWrapper.this.content = content;
|
||||||
|
|
||||||
for (UUID id : viewers.keySet()) {
|
for (UUID id : viewers.keySet()) {
|
||||||
sendContent(Bukkit.getPlayer(id));
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
@ -100,7 +96,7 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayImage getContent() {
|
public ArrayImage getContent() {
|
||||||
return MapWrapper_v1_12_R1.this.getContent();
|
return MapWrapper.this.getContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,9 +110,9 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
|
|
||||||
int id = getMapId(player);
|
int id = getMapId(player);
|
||||||
if (withoutQueue) {
|
if (withoutQueue) {
|
||||||
MapSender_v1_12_R1.sendMap(id, MapWrapper_v1_12_R1.this.content, player);
|
MapSender.sendMap(id, MapWrapper.this.content, player);
|
||||||
} else {
|
} else {
|
||||||
MapSender_v1_12_R1.addToQueue(id, MapWrapper_v1_12_R1.this.content, player);
|
MapSender.addToQueue(id, MapWrapper.this.content, player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,14 +128,35 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
slot = 8 - (slot - 36);
|
slot = 8 - (slot - 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
CraftPlayer craftPlayer = (CraftPlayer) player;
|
Object playerHandle = ReflectionUtils.getHandle(player);
|
||||||
int windowId = craftPlayer.getHandle().defaultContainer.windowId;
|
Object inventoryMenu = ReflectionUtil.getField(playerHandle, ReflectionUtils.supports(19) ? "bT" : ReflectionUtils.supports(17) ? "bU" : "defaultContainer");
|
||||||
|
int windowId = (int) ReflectionUtil.getField(inventoryMenu, ReflectionUtils.supports(17) ? "j" : "windowId");
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.MAP, 1);
|
ItemStack stack = new ItemStack(ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP, 1);
|
||||||
net.minecraft.server.v1_12_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
|
||||||
|
|
||||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack);
|
Class<?> craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack");
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack);
|
||||||
|
|
||||||
|
Class<?> setSlotPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutSetSlot");
|
||||||
|
Object packet;
|
||||||
|
if (ReflectionUtils.supports(17)) { //1.17+
|
||||||
|
int stateId = (int) ReflectionUtil.callMethod(inventoryMenu, ReflectionUtils.supports(18) ? "j" : "getStateId");
|
||||||
|
|
||||||
|
packet = ReflectionUtil.callConstructor(setSlotPacketClass,
|
||||||
|
windowId,
|
||||||
|
stateId,
|
||||||
|
slot,
|
||||||
|
nmsStack
|
||||||
|
);
|
||||||
|
} else { //1.16-
|
||||||
|
packet = ReflectionUtil.callConstructor(setSlotPacketClass,
|
||||||
|
windowId,
|
||||||
|
slot,
|
||||||
|
nmsStack
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReflectionUtils.sendPacket(player, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -149,7 +166,8 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showInHand(Player player, boolean force) {
|
public void showInHand(Player player, boolean force) {
|
||||||
if (player.getInventory().getItemInMainHand().getType() != Material.MAP && !force) return;
|
if (player.getInventory().getItemInMainHand().getType() != (ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force)
|
||||||
|
return;
|
||||||
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
showInInventory(player, player.getInventory().getHeldItemSlot(), force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +183,8 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
public void showInFrame(Player player, ItemFrame frame, boolean force) {
|
||||||
if (frame.getItem().getType() != Material.MAP && !force) return;
|
if (frame.getItem().getType() != (ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force)
|
||||||
|
return;
|
||||||
showInFrame(player, frame.getEntityId());
|
showInFrame(player, frame.getEntityId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +197,7 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
public void showInFrame(Player player, int entityId, String debugInfo) {
|
public void showInFrame(Player player, int entityId, String debugInfo) {
|
||||||
if (!isViewing(player)) return;
|
if (!isViewing(player)) return;
|
||||||
|
|
||||||
ItemStack stack = new ItemStack(Material.MAP, 1);
|
ItemStack stack = new ItemStack(ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP, 1);
|
||||||
if (debugInfo != null) {
|
if (debugInfo != null) {
|
||||||
ItemMeta itemMeta = stack.getItemMeta();
|
ItemMeta itemMeta = stack.getItemMeta();
|
||||||
itemMeta.setDisplayName(debugInfo);
|
itemMeta.setDisplayName(debugInfo);
|
||||||
|
@ -189,7 +208,7 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
ItemFrame frame = getItemFrameById(player.getWorld(), entityId);
|
||||||
if (frame != null) {
|
if (frame != null) {
|
||||||
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance());
|
||||||
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_12_R1.this));
|
frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper.this));
|
||||||
}
|
}
|
||||||
|
|
||||||
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
sendItemFramePacket(player, entityId, stack, getMapId(player));
|
||||||
|
@ -208,45 +227,64 @@ public class MapWrapper_v1_12_R1 extends MapWrapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemFrame getItemFrameById(World world, int entityId) {
|
public ItemFrame getItemFrameById(World world, int entityId) {
|
||||||
CraftWorld craftWorld = (CraftWorld) world;
|
Object worldHandle = ReflectionUtils.getHandle(world);
|
||||||
|
Object nmsEntity = ReflectionUtil.callMethod(worldHandle, ReflectionUtils.supports(18) ? "a" : "getEntity");
|
||||||
|
if (nmsEntity == null) return null;
|
||||||
|
|
||||||
Entity entity = craftWorld.getHandle().getEntity(entityId);
|
if (!ReflectionUtils.supports(17)) {
|
||||||
if (entity == null) return null;
|
nmsEntity = ReflectionUtil.callMethod(nmsEntity, "getBukkitEntity");
|
||||||
|
}
|
||||||
org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity();
|
|
||||||
if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity;
|
|
||||||
|
|
||||||
|
if (nmsEntity instanceof ItemFrame) return (ItemFrame) nmsEntity;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) {
|
||||||
net.minecraft.server.v1_12_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
Class<?> craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack");
|
||||||
if (nmsStack.getTag() == null) nmsStack.setTag(new NBTTagCompound()); //No orCreate on 1.12.2!
|
Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack);
|
||||||
nmsStack.getTag().setInt("map", mapId); //getTag putInt
|
|
||||||
|
|
||||||
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
Object nbtObject = ReflectionUtil.callMethod(nmsStack, ReflectionUtils.supports(19) ? "v" : ReflectionUtils.supports(18) ? "u" : ReflectionUtils.supports(13) ? "getOrCreateTag" : "getTag");
|
||||||
|
|
||||||
try {
|
if (!ReflectionUtils.supports(13) && nbtObject == null) { //1.12 has no getOrCreate, call create if null!
|
||||||
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
Class<?> tagCompoundClass = ReflectionUtils.getCraftClass("NBTTagCompound");
|
||||||
DataWatcherObject<net.minecraft.server.v1_12_R1.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.server.v1_12_R1.ItemStack>) getField(EntityItemFrame.class, "c");
|
Object tagCompound = ReflectionUtil.callConstructor(tagCompoundClass);
|
||||||
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
|
||||||
list.add(dataWatcherItem);
|
ReflectionUtil.callMethod(nbtObject, "setTag", tagCompound);
|
||||||
setField(packet, "b", list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
ReflectionUtil.callMethod(nbtObject, ReflectionUtils.supports(18) ? "a" : "setInt", "map", mapId);
|
||||||
|
|
||||||
|
Class<?> entityClass = ReflectionUtils.getNMSClass("world.entity", "Entity");
|
||||||
|
|
||||||
|
Class<?> dataWatcherClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher");
|
||||||
|
Object dataWatcher = ReflectionUtil.callConstructor(dataWatcherClass, entityClass.cast(null));
|
||||||
|
|
||||||
|
Class<?> entityMetadataPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata");
|
||||||
|
Object packet = ReflectionUtil.callConstructor(entityMetadataPacketClass,
|
||||||
|
entityId,
|
||||||
|
dataWatcher, //dummy watcher!
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Object> list = new ArrayList<>();
|
||||||
|
Class<?> entityItemFrameClass = ReflectionUtils.getNMSClass("world.entity.decoration", "EntityItemFrame");
|
||||||
|
Object dataWatcherObject = ReflectionUtil.getDeclaredField(entityItemFrameClass, ReflectionUtils.supports(17) ? "ao" : ReflectionUtils.supports(14) ? "ITEM" : ReflectionUtils.supports(13) ? "e" : "c");
|
||||||
|
Class<?> dataWatcherItemClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher$Item");
|
||||||
|
Object dataWatcherItem = ReflectionUtil.callConstructor(dataWatcherItemClass, dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
ReflectionUtil.setDeclaredField(packet, "b", list);
|
||||||
|
|
||||||
|
ReflectionUtils.sendPacket(player, packet);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public MapWrapper_v1_12_R1(ArrayImage image) {
|
public ArrayImage getContent() {
|
||||||
super(image);
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapController getController() {
|
public MapController getController() {
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* 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 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.listeners;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.events.ListenerPriority;
|
||||||
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
|
||||||
|
|
||||||
|
public class PacketListener extends PacketAdapter {
|
||||||
|
public PacketListener(Plugin plugin) {
|
||||||
|
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP, PacketType.Play.Client.USE_ENTITY, PacketType.Play.Client.SET_CREATIVE_SLOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(PacketEvent event) {
|
||||||
|
if (event.getPacketType() != PacketType.Play.Server.MAP) return; //Make sure it's the right packet!
|
||||||
|
|
||||||
|
int id = event.getPacket().getIntegers().read(0); //Read first int (a); that's the MAP id
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
event.getPacket().getIntegers().write(0, newId); //set the MAP id to the reverse
|
||||||
|
} else {
|
||||||
|
boolean async = !plugin.getServer().isPrimaryThread();
|
||||||
|
MapCancelEvent cancelEvent = new MapCancelEvent(event.getPlayer(), id, async);
|
||||||
|
if (MapReflectionAPI.getMapManager().isIdUsedBy(event.getPlayer(), id)) cancelEvent.setCancelled(true);
|
||||||
|
if (cancelEvent.getHandlers().getRegisteredListeners().length > 0)
|
||||||
|
Bukkit.getPluginManager().callEvent(cancelEvent);
|
||||||
|
|
||||||
|
if (cancelEvent.isCancelled()) event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPacketReceiving(PacketEvent event) {
|
||||||
|
if (event.getPacketType() == PacketType.Play.Client.USE_ENTITY) {
|
||||||
|
int entityId = event.getPacket().getIntegers().read(0); //entityId
|
||||||
|
WrappedEnumEntityUseAction action = event.getPacket().getEnumEntityUseActions().read(0);
|
||||||
|
EnumWrappers.EntityUseAction actionEnum = action.getAction();
|
||||||
|
EnumWrappers.Hand hand = action.getHand();
|
||||||
|
Vector pos = action.getPosition();
|
||||||
|
|
||||||
|
boolean async = !plugin.getServer().isPrimaryThread();
|
||||||
|
MapInteractEvent interactEvent = new MapInteractEvent(event.getPlayer(), entityId, actionEnum.ordinal(), pos, hand.ordinal(), async);
|
||||||
|
if (interactEvent.getFrame() != null && interactEvent.getMapWrapper() != null) {
|
||||||
|
Bukkit.getPluginManager().callEvent(interactEvent);
|
||||||
|
if (interactEvent.isCancelled()) event.setCancelled(true);
|
||||||
|
}
|
||||||
|
} else if (event.getPacketType() == PacketType.Play.Client.SET_CREATIVE_SLOT) {
|
||||||
|
int slot = event.getPacket().getIntegers().read(0);
|
||||||
|
ItemStack item = event.getPacket().getItemModifier().read(0);
|
||||||
|
|
||||||
|
boolean async = !plugin.getServer().isPrimaryThread();
|
||||||
|
CreateInventoryMapUpdateEvent updateEvent = new CreateInventoryMapUpdateEvent(event.getPlayer(), slot, item, async);
|
||||||
|
if (updateEvent.getMapWrapper() != null) {
|
||||||
|
Bukkit.getPluginManager().callEvent(updateEvent);
|
||||||
|
if (updateEvent.isCancelled()) event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* 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 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.util;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>ReflectionUtil</b> - Reflection handler for NMS and CraftBukkit.<br>
|
||||||
|
* Caches the packet related methods and is asynchronous.
|
||||||
|
* <p>
|
||||||
|
* This class does not handle null checks as most of the requests are from the
|
||||||
|
* other utility classes that already handle null checks.
|
||||||
|
* <p>
|
||||||
|
* <a href="https://wiki.vg/Protocol">Clientbound Packets</a> are considered fake
|
||||||
|
* updates to the client without changing the actual data. Since all the data is handled
|
||||||
|
* by the server.
|
||||||
|
*
|
||||||
|
* @author Crypto Morin, Stijn Bannink
|
||||||
|
* @version 2.1
|
||||||
|
*/
|
||||||
|
public class ReflectionUtil {
|
||||||
|
private ReflectionUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class<?> wrapperToPrimitive(Class<?> clazz) {
|
||||||
|
if (clazz == Boolean.class) return boolean.class;
|
||||||
|
if (clazz == Integer.class) return int.class;
|
||||||
|
if (clazz == Double.class) return double.class;
|
||||||
|
if (clazz == Float.class) return float.class;
|
||||||
|
if (clazz == Long.class) return long.class;
|
||||||
|
if (clazz == Short.class) return short.class;
|
||||||
|
if (clazz == Byte.class) return byte.class;
|
||||||
|
if (clazz == Void.class) return void.class;
|
||||||
|
if (clazz == Character.class) return char.class;
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class<?>[] toParamTypes(Object... params) {
|
||||||
|
return Arrays.stream(params)
|
||||||
|
.map(obj -> wrapperToPrimitive(obj.getClass()))
|
||||||
|
.toArray(Class<?>[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Class<?> getClass(@NotNull String name) {
|
||||||
|
try {
|
||||||
|
return Class.forName(name);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object callConstructor(Class<?> clazz, Object... params) {
|
||||||
|
try {
|
||||||
|
Constructor<?> con = clazz.getConstructor(toParamTypes(params));
|
||||||
|
con.setAccessible(true);
|
||||||
|
return con.newInstance(params);
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
|
||||||
|
InvocationTargetException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object callDeclaredConstructor(Class<?> clazz, Object... params) {
|
||||||
|
try {
|
||||||
|
Constructor<?> con = clazz.getDeclaredConstructor(toParamTypes(params));
|
||||||
|
con.setAccessible(true);
|
||||||
|
return con.newInstance(params);
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
|
||||||
|
InvocationTargetException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object callMethod(Object obj, String method, Object... params) {
|
||||||
|
try {
|
||||||
|
Method m = obj.getClass().getMethod(method, toParamTypes(params));
|
||||||
|
m.setAccessible(true);
|
||||||
|
return m.invoke(obj, params);
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object callDeclaredMethod(Object obj, String method, Object... params) {
|
||||||
|
try {
|
||||||
|
Method m = obj.getClass().getDeclaredMethod(method, toParamTypes(params));
|
||||||
|
m.setAccessible(true);
|
||||||
|
return m.invoke(obj, params);
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object getField(Object object, String field) {
|
||||||
|
try {
|
||||||
|
Field f = object.getClass().getField(field);
|
||||||
|
f.setAccessible(true);
|
||||||
|
return f.get(object);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object getDeclaredField(Object object, String field) {
|
||||||
|
try {
|
||||||
|
Field f = object.getClass().getDeclaredField(field);
|
||||||
|
f.setAccessible(true);
|
||||||
|
return f.get(object);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDeclaredField(Object object, String field, Object value) {
|
||||||
|
try {
|
||||||
|
Field f = object.getClass().getDeclaredField(field);
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.set(object, toParamTypes(value));
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,381 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* 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 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.
|
||||||
|
*/
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.util;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>ReflectionUtils</b> - Reflection handler for NMS and CraftBukkit.<br>
|
||||||
|
* Caches the packet related methods and is asynchronous.
|
||||||
|
* <p>
|
||||||
|
* This class does not handle null checks as most of the requests are from the
|
||||||
|
* other utility classes that already handle null checks.
|
||||||
|
* <p>
|
||||||
|
* <a href="https://wiki.vg/Protocol">Clientbound Packets</a> are considered fake
|
||||||
|
* updates to the client without changing the actual data. Since all the data is handled
|
||||||
|
* by the server.
|
||||||
|
* <p>
|
||||||
|
* A useful resource used to compare mappings is <a href="https://minidigger.github.io/MiniMappingViewer/#/spigot">Mini's Mapping Viewer</a>
|
||||||
|
*
|
||||||
|
* @author Crypto Morin
|
||||||
|
* @version 6.0.1
|
||||||
|
*/
|
||||||
|
public final class ReflectionUtils {
|
||||||
|
/**
|
||||||
|
* We use reflection mainly to avoid writing a new class for version barrier.
|
||||||
|
* The version barrier is for NMS that uses the Minecraft version as the main package name.
|
||||||
|
* <p>
|
||||||
|
* E.g. EntityPlayer in 1.15 is in the class {@code net.minecraft.server.v1_15_R1}
|
||||||
|
* but in 1.14 it's in {@code net.minecraft.server.v1_14_R1}
|
||||||
|
* In order to maintain cross-version compatibility we cannot import these classes.
|
||||||
|
* <p>
|
||||||
|
* Performance is not a concern for these specific statically initialized values.
|
||||||
|
*/
|
||||||
|
public static final String VERSION;
|
||||||
|
/**
|
||||||
|
* The raw minor version number.
|
||||||
|
* E.g. {@code v1_17_R1} to {@code 17}
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public static final int VER = Integer.parseInt(VERSION.substring(1).split("_")[1]);
|
||||||
|
/**
|
||||||
|
* Mojang remapped their NMS in 1.17 https://www.spigotmc.org/threads/spigot-bungeecord-1-17.510208/#post-4184317
|
||||||
|
*/
|
||||||
|
public static final String
|
||||||
|
CRAFTBUKKIT = "org.bukkit.craftbukkit." + VERSION + '.',
|
||||||
|
NMS = v(17, "net.minecraft.").orElse("net.minecraft.server." + VERSION + '.');
|
||||||
|
/**
|
||||||
|
* A nullable public accessible field only available in {@code EntityPlayer}.
|
||||||
|
* This can be null if the player is offline.
|
||||||
|
*/
|
||||||
|
private static final MethodHandle PLAYER_CONNECTION;
|
||||||
|
/**
|
||||||
|
* Responsible for getting the NMS handler {@code EntityPlayer} object for the player.
|
||||||
|
* {@code CraftPlayer} is simply a wrapper for {@code EntityPlayer}.
|
||||||
|
* Used mainly for handling packet related operations.
|
||||||
|
* <p>
|
||||||
|
* This is also where the famous player {@code ping} field comes from!
|
||||||
|
*/
|
||||||
|
private static final MethodHandle GET_HANDLE;
|
||||||
|
private static final MethodHandle GET_HANDLE_WORLD;
|
||||||
|
/**
|
||||||
|
* Sends a packet to the player's client through a {@code NetworkManager} which
|
||||||
|
* is where {@code ProtocolLib} controls packets by injecting channels!
|
||||||
|
*/
|
||||||
|
private static final MethodHandle SEND_PACKET;
|
||||||
|
|
||||||
|
static { // This needs to be right below VERSION because of initialization order.
|
||||||
|
// This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion()
|
||||||
|
// which allows easier testing as well.
|
||||||
|
String found = null;
|
||||||
|
for (Package pack : Package.getPackages()) {
|
||||||
|
String name = pack.getName();
|
||||||
|
|
||||||
|
// .v because there are other packages.
|
||||||
|
if (name.startsWith("org.bukkit.craftbukkit.v")) {
|
||||||
|
found = pack.getName().split("\\.")[3];
|
||||||
|
|
||||||
|
// Just a final guard to make sure it finds this important class.
|
||||||
|
// As a protection for forge+bukkit implementation that tend to mix versions.
|
||||||
|
// The real CraftPlayer should exist in the package.
|
||||||
|
// Note: Doesn't seem to function properly. Will need to separate the version
|
||||||
|
// handler for NMS and CraftBukkit for softwares like catmc.
|
||||||
|
try {
|
||||||
|
Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer");
|
||||||
|
break;
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
found = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found == null)
|
||||||
|
throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'");
|
||||||
|
VERSION = found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
Class<?> entityPlayer = getNMSClass("server.level", "EntityPlayer");
|
||||||
|
Class<?> worldServer = getNMSClass("server.level", "WorldServer");
|
||||||
|
Class<?> craftPlayer = getCraftClass("entity.CraftPlayer");
|
||||||
|
Class<?> craftWorld = getCraftClass("CraftWorld");
|
||||||
|
Class<?> playerConnection = getNMSClass("server.network", "PlayerConnection");
|
||||||
|
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
MethodHandle sendPacket = null, getHandle = null, getHandleWorld = null, connection = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
connection = lookup.findGetter(entityPlayer,
|
||||||
|
v(17, "b").orElse("playerConnection"), playerConnection);
|
||||||
|
getHandle = lookup.findVirtual(craftPlayer, "getHandle", MethodType.methodType(entityPlayer));
|
||||||
|
getHandleWorld = lookup.findVirtual(craftWorld, "getHandle", MethodType.methodType(worldServer));
|
||||||
|
sendPacket = lookup.findVirtual(playerConnection,
|
||||||
|
v(18, "a").orElse("sendPacket"),
|
||||||
|
MethodType.methodType(void.class, getNMSClass("network.protocol", "Packet")));
|
||||||
|
} catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
PLAYER_CONNECTION = connection;
|
||||||
|
SEND_PACKET = sendPacket;
|
||||||
|
GET_HANDLE = getHandle;
|
||||||
|
GET_HANDLE_WORLD = getHandleWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectionUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is purely for readability.
|
||||||
|
* No performance is gained.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public static <T> VersionHandler<T> v(int version, T handle) {
|
||||||
|
return new VersionHandler<>(version, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CallableVersionHandler<T> v(int version, Callable<T> handle) {
|
||||||
|
return new CallableVersionHandler<>(version, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the server version is equal or greater than the given version.
|
||||||
|
*
|
||||||
|
* @param version the version to compare the server version with.
|
||||||
|
* @return true if the version is equal or newer, otherwise false.
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public static boolean supports(int version) {
|
||||||
|
return VER >= version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a NMS (net.minecraft.server) class which accepts a package for 1.17 compatibility.
|
||||||
|
*
|
||||||
|
* @param newPackage the 1.17 package name.
|
||||||
|
* @param name the name of the class.
|
||||||
|
* @return the NMS class or null if not found.
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Class<?> getNMSClass(@Nonnull String newPackage, @Nonnull String name) {
|
||||||
|
if (supports(17)) name = newPackage + '.' + name;
|
||||||
|
return getNMSClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a NMS (net.minecraft.server) class.
|
||||||
|
*
|
||||||
|
* @param name the name of the class.
|
||||||
|
* @return the NMS class or null if not found.
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Class<?> getNMSClass(@Nonnull String name) {
|
||||||
|
try {
|
||||||
|
return Class.forName(NMS + name);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to the player asynchronously if they're online.
|
||||||
|
* Packets are thread-safe.
|
||||||
|
*
|
||||||
|
* @param player the player to send the packet to.
|
||||||
|
* @param packets the packets to send.
|
||||||
|
* @return the async thread handling the packet.
|
||||||
|
* @see #sendPacketSync(Player, Object...)
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public static CompletableFuture<Void> sendPacket(@Nonnull Player player, @Nonnull Object... packets) {
|
||||||
|
return CompletableFuture.runAsync(() -> sendPacketSync(player, packets))
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to the player synchronously if they're online.
|
||||||
|
*
|
||||||
|
* @param player the player to send the packet to.
|
||||||
|
* @param packets the packets to send.
|
||||||
|
* @see #sendPacket(Player, Object...)
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public static void sendPacketSync(@Nonnull Player player, @Nonnull Object... packets) {
|
||||||
|
try {
|
||||||
|
Object handle = GET_HANDLE.invoke(player);
|
||||||
|
Object connection = PLAYER_CONNECTION.invoke(handle);
|
||||||
|
|
||||||
|
// Checking if the connection is not null is enough. There is no need to check if the player is online.
|
||||||
|
if (connection != null) {
|
||||||
|
for (Object packet : packets) SEND_PACKET.invoke(connection, packet);
|
||||||
|
}
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object getHandle(@Nonnull Player player) {
|
||||||
|
Objects.requireNonNull(player, "Cannot get handle of null player");
|
||||||
|
try {
|
||||||
|
return GET_HANDLE.invoke(player);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object getHandle(@Nonnull World world) {
|
||||||
|
Objects.requireNonNull(world, "Cannot get handle of null world");
|
||||||
|
try {
|
||||||
|
return GET_HANDLE_WORLD.invoke(world);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object getConnection(@Nonnull Player player) {
|
||||||
|
Objects.requireNonNull(player, "Cannot get connection of null player");
|
||||||
|
try {
|
||||||
|
Object handle = GET_HANDLE.invoke(player);
|
||||||
|
return PLAYER_CONNECTION.invoke(handle);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a CraftBukkit (org.bukkit.craftbukkit) class.
|
||||||
|
*
|
||||||
|
* @param name the name of the class to load.
|
||||||
|
* @return the CraftBukkit class or null if not found.
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Class<?> getCraftClass(@Nonnull String name) {
|
||||||
|
try {
|
||||||
|
return Class.forName(CRAFTBUKKIT + name);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<?> getArrayClass(String clazz, boolean nms) {
|
||||||
|
clazz = "[L" + (nms ? NMS : CRAFTBUKKIT) + clazz + ';';
|
||||||
|
try {
|
||||||
|
return Class.forName(clazz);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<?> toArrayClass(Class<?> clazz) {
|
||||||
|
try {
|
||||||
|
return Class.forName("[L" + clazz.getName() + ';');
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class VersionHandler<T> {
|
||||||
|
private int version;
|
||||||
|
private T handle;
|
||||||
|
|
||||||
|
private VersionHandler(int version, T handle) {
|
||||||
|
if (supports(version)) {
|
||||||
|
this.version = version;
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public VersionHandler<T> v(int version, T handle) {
|
||||||
|
if (version == this.version)
|
||||||
|
throw new IllegalArgumentException("Cannot have duplicate version handles for version: " + version);
|
||||||
|
if (version > this.version && supports(version)) {
|
||||||
|
this.version = version;
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T orElse(T handle) {
|
||||||
|
return this.version == 0 ? handle : this.handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CallableVersionHandler<T> {
|
||||||
|
private int version;
|
||||||
|
private Callable<T> handle;
|
||||||
|
|
||||||
|
private CallableVersionHandler(int version, Callable<T> handle) {
|
||||||
|
if (supports(version)) {
|
||||||
|
this.version = version;
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallableVersionHandler<T> v(int version, Callable<T> handle) {
|
||||||
|
if (version == this.version)
|
||||||
|
throw new IllegalArgumentException("Cannot have duplicate version handles for version: " + version);
|
||||||
|
if (version > this.version && supports(version)) {
|
||||||
|
this.version = version;
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T orElse(Callable<T> handle) {
|
||||||
|
try {
|
||||||
|
return (this.version == 0 ? handle : this.handle).call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue