Compare commits
20 commits
master
...
legacy/nms
Author | SHA1 | Date | |
---|---|---|---|
ef91b97d1f | |||
5f9cbe7425 | |||
bc055e0041 | |||
39dcfc8b31 | |||
|
874b7d227c | ||
|
4f187b92bb | ||
|
592c270e68 | ||
|
fa136c4955 | ||
|
230d7fc5b2 | ||
|
a3ba68434f | ||
|
e9b19fa2f1 | ||
|
db517ea09b | ||
|
8afc1fb202 | ||
|
3ac1042894 | ||
|
336d9626e1 | ||
|
24583880a2 | ||
|
b163e57563 | ||
|
6db8a11f5c | ||
|
6840d732ad | ||
|
fd225647f5 |
108 changed files with 8181 additions and 796 deletions
26
.github/workflows/maven.yml
vendored
26
.github/workflows/maven.yml
vendored
|
@ -1,26 +0,0 @@
|
||||||
name: Java CI
|
|
||||||
|
|
||||||
on: [push]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
|
|
||||||
- name: Set up JDK 11
|
|
||||||
uses: actions/setup-java@v1
|
|
||||||
with:
|
|
||||||
java-version: 11
|
|
||||||
|
|
||||||
- name: Build with Maven
|
|
||||||
run: mvn -B package --file pom.xml
|
|
||||||
|
|
||||||
- run: mkdir -p target
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@master
|
|
||||||
with:
|
|
||||||
name: MapReflectionAPI
|
|
||||||
path: target
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -86,6 +86,7 @@ buildNumber.properties
|
||||||
.mvn/timing.properties
|
.mvn/timing.properties
|
||||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||||
.mvn/wrapper/maven-wrapper.jar
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
.flattened-pom.xml
|
||||||
|
|
||||||
# Eclipse m2e generated files
|
# Eclipse m2e generated files
|
||||||
# Eclipse Core
|
# Eclipse Core
|
||||||
|
|
7
.idea/copyright/profiles_settings.xml
generated
Normal file
7
.idea/copyright/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<component name="CopyrightManager">
|
||||||
|
<settings default="SBDevelopment">
|
||||||
|
<module2copyright>
|
||||||
|
<element module="Project Files" copyright="SBDevelopment" />
|
||||||
|
</module2copyright>
|
||||||
|
</settings>
|
||||||
|
</component>
|
20
.idea/encodings.xml
generated
20
.idea/encodings.xml
generated
|
@ -1,6 +1,10 @@
|
||||||
<?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$/${project.basedir}/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/${project.basedir}/src/main/resources" charset="UTF-8" />
|
||||||
|
<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" />
|
||||||
|
@ -17,8 +21,20 @@
|
||||||
<file url="file://$PROJECT_DIR$/NMS-v1_17_R1/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/NMS-v1_17_R1/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/NMS-v1_18_R2/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/NMS-v1_18_R2/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/NMS-v1_18_R2/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/NMS-v1_18_R2/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/NMS-v1_19_R1/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/NMS-v1_19_R3/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/NMS-v1_19_R1/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/NMS-v1_19_R3/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R1/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R1/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R2/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R2/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R3/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R3/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R4/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_20_R4/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_21_R1/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_21_R1/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_21_R2/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/NMS-v1_21_R2/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||||
</component>
|
</component>
|
||||||
|
|
16
.idea/misc.xml
generated
16
.idea/misc.xml
generated
|
@ -1,8 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ComposerSettings">
|
|
||||||
<execution />
|
|
||||||
</component>
|
|
||||||
<component name="EntryPointsManager">
|
<component name="EntryPointsManager">
|
||||||
<list size="1">
|
<list size="1">
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
||||||
|
@ -17,20 +14,11 @@
|
||||||
</option>
|
</option>
|
||||||
<option name="ignoredFiles">
|
<option name="ignoredFiles">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$/API/pom.xml" />
|
<option value="$PROJECT_DIR$/NMS-v1_20_R1/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>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="temurin-11" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
12
.idea/ros.xml
generated
Normal file
12
.idea/ros.xml
generated
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ROSSettings">
|
||||||
|
<option name="rosPath" value="" />
|
||||||
|
<option name="workspacePath" value="" />
|
||||||
|
<option name="additionalSources" value="" />
|
||||||
|
<option name="excludedXmls" value="" />
|
||||||
|
<option name="licenseLinkType" value="Summary" />
|
||||||
|
<option name="knownKeys" value="" />
|
||||||
|
<option name="depSources" value="https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/base.yaml"https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/python.yaml"https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/ruby.yaml" />
|
||||||
|
</component>
|
||||||
|
</project>
|
2
.idea/vcs.xml
generated
2
.idea/vcs.xml
generated
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
178
API/pom.xml
Normal file
178
API/pom.xml
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.28</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.5.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>com.bergerkiller.bukkit.common</pattern>
|
||||||
|
<shadedPattern>tech.sbdevelopment.mapreflectionapi.libs.bkcommonlib</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.bstats</pattern>
|
||||||
|
<shadedPattern>tech.sbdevelopment.mapreflectionapi.libs.bstats</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
</relocations>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-maven-plugin</artifactId>
|
||||||
|
<version>1.18.20.0</version>
|
||||||
|
<configuration>
|
||||||
|
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
|
||||||
|
<outputDirectory>${maven.lombok.delombok-target}</outputDirectory>
|
||||||
|
<addOutputDirectory>false</addOutputDirectory>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>delombok</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>3.5.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
<sourcepath>${maven.lombok.delombok-target}</sourcepath>
|
||||||
|
<sourceFileExcludes>
|
||||||
|
<sourceFileExclude>**/com/bergerkiller/bukkit/common/io/*.java</sourceFileExclude>
|
||||||
|
<sourceFileExclude>**/com/bergerkiller/bukkit/common/map/*.java</sourceFileExclude>
|
||||||
|
<sourceFileExclude>**/com/bergerkiller/bukkit/common/map/color/*.java</sourceFileExclude>
|
||||||
|
<sourceFileExclude>**/tech/sbdevelopment/mapreflectionapi/*.java</sourceFileExclude>
|
||||||
|
<sourceFileExclude>**/tech/sbdevelopment/mapreflectionapi/cmd/*.java</sourceFileExclude>
|
||||||
|
<sourceFileExclude>**/tech/sbdevelopment/mapreflectionapi/managers/*.java</sourceFileExclude>
|
||||||
|
<sourceFileExclude>**/tech/sbdevelopment/mapreflectionapi/utils/*.java</sourceFileExclude>
|
||||||
|
<sourceFileExclude>**/tech/sbdevelopment/mapreflectionapi/listeners/*.java</sourceFileExclude>
|
||||||
|
</sourceFileExcludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
<includes>
|
||||||
|
<include>plugin.yml</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<excludes>
|
||||||
|
<exclude>plugin.yml</exclude>
|
||||||
|
</excludes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spigot-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.28</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bstats</groupId>
|
||||||
|
<artifactId>bstats-bukkit</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Libraries below are provided by Spigot -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains</groupId>
|
||||||
|
<artifactId>annotations-java5</artifactId>
|
||||||
|
<version>23.0.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-transport</artifactId>
|
||||||
|
<version>4.1.77.Final</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -38,6 +38,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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the plugin instance
|
* Get the plugin instance
|
||||||
|
@ -89,11 +90,26 @@ public class MapReflectionAPI extends JavaPlugin {
|
||||||
getLogger().info("Loading the commands...");
|
getLogger().info("Loading the commands...");
|
||||||
getCommand("mapmanager").setExecutor(new MapManagerCMD());
|
getCommand("mapmanager").setExecutor(new MapManagerCMD());
|
||||||
|
|
||||||
getLogger().info("Loading the map manager...");
|
try {
|
||||||
mapManager = new MapManager();
|
packetListener = PacketListener.construct(this);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
packetListener.init(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mapManager = new MapManager(this);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Configuration.getInstance().isAllowVanilla()) {
|
if (Configuration.getInstance().isAllowVanilla()) {
|
||||||
getLogger().info("Vanilla Maps are allowed. Discovering occupied Map IDs...");
|
getLogger().info("Vanilla Maps are allowed!");
|
||||||
|
getLogger().info("Discovering occupied Map IDs...");
|
||||||
int occupiedIDs = 0;
|
int occupiedIDs = 0;
|
||||||
for (int s = 0; s < Short.MAX_VALUE; s++) {
|
for (int s = 0; s < Short.MAX_VALUE; s++) {
|
||||||
try {
|
try {
|
||||||
|
@ -113,9 +129,8 @@ public class MapReflectionAPI extends JavaPlugin {
|
||||||
|
|
||||||
getLogger().info("Registering the listeners...");
|
getLogger().info("Registering the listeners...");
|
||||||
Bukkit.getPluginManager().registerEvents(new MapListener(), this);
|
Bukkit.getPluginManager().registerEvents(new MapListener(), this);
|
||||||
Bukkit.getPluginManager().registerEvents(new PacketListener(), this);
|
|
||||||
|
|
||||||
getLogger().info("Loading metrics...");
|
getLogger().info("Enabling metrics...");
|
||||||
Metrics metrics = new Metrics(this, 16033);
|
Metrics metrics = new Metrics(this, 16033);
|
||||||
metrics.addCustomChart(new SingleLineChart("managed_maps", () -> mapManager.getManagedMapsCount()));
|
metrics.addCustomChart(new SingleLineChart("managed_maps", () -> mapManager.getManagedMapsCount()));
|
||||||
|
|
||||||
|
@ -167,6 +182,9 @@ 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;
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,13 +18,17 @@
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.api;
|
package tech.sbdevelopment.mapreflectionapi.api;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
|
||||||
import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException;
|
import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException;
|
||||||
import tech.sbdevelopment.mapreflectionapi.managers.Configuration;
|
import tech.sbdevelopment.mapreflectionapi.managers.Configuration;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -36,6 +40,25 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
public class MapManager {
|
public class MapManager {
|
||||||
protected final Set<Integer> occupiedIds = new HashSet<>();
|
protected final Set<Integer> occupiedIds = new HashSet<>();
|
||||||
protected final List<MapWrapper> managedMaps = new CopyOnWriteArrayList<>();
|
protected final List<MapWrapper> managedMaps = new CopyOnWriteArrayList<>();
|
||||||
|
private final Class<?> wrapperClass;
|
||||||
|
|
||||||
|
public MapManager(JavaPlugin plugin) throws IllegalStateException {
|
||||||
|
String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||||
|
String version = packageName.substring(packageName.lastIndexOf('.') + 1);
|
||||||
|
|
||||||
|
plugin.getLogger().info("Enabling MapManager for " + version + "...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Class<?> clazz = Class.forName("tech.sbdevelopment.mapreflectionapi.nms.MapWrapper_" + version);
|
||||||
|
if (MapWrapper.class.isAssignableFrom(clazz)) {
|
||||||
|
wrapperClass = clazz;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Plugin corrupted! Detected invalid MapWrapper class.");
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new IllegalStateException("This Spigot version (" + version + ") is not supported! Contact the developer to get support.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the amount of maps managed by the plugin
|
* Get the amount of maps managed by the plugin
|
||||||
|
@ -124,9 +147,15 @@ public class MapManager {
|
||||||
* @return The wrapper
|
* @return The wrapper
|
||||||
*/
|
*/
|
||||||
private MapWrapper wrapNewImage(ArrayImage image) {
|
private MapWrapper wrapNewImage(ArrayImage image) {
|
||||||
MapWrapper wrapper = new MapWrapper(image);
|
try {
|
||||||
|
MapWrapper wrapper = (MapWrapper) wrapperClass.getDeclaredConstructor(ArrayImage.class).newInstance(image);
|
||||||
managedMaps.add(wrapper);
|
managedMaps.add(wrapper);
|
||||||
return wrapper;
|
return wrapper;
|
||||||
|
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
||||||
|
InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link MapWrapper} wraps one image.
|
||||||
|
*/
|
||||||
|
public abstract class MapWrapper extends AbstractMapWrapper {
|
||||||
|
protected ArrayImage content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@link MapWrapper}
|
||||||
|
*
|
||||||
|
* @param image The {@link ArrayImage} to wrap
|
||||||
|
*/
|
||||||
|
public MapWrapper(ArrayImage image) {
|
||||||
|
this.content = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayImage getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract MapController getController();
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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("Enabling PacketListener for " + 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,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
124
Dist/pom.xml
Normal file
124
Dist/pom.xml
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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_20_R4</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>tech.sbdevelopment</groupId>
|
||||||
|
<artifactId>MapReflectionAPI-NMS-v1_19_R3</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>
|
72
NMS-v1_12_R1/pom.xml
Normal file
72
NMS-v1_12_R1/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of MapReflectionAPI.
|
* This file is part of MapReflectionAPI.
|
||||||
* Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,25 +16,27 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package tech.sbdevelopment.mapreflectionapi.api;
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
import lombok.Data;
|
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.utils.ReflectionUtil;
|
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MapSender} sends the Map packets to players.
|
* The {@link MapSender_v1_12_R1} sends the Map packets to players.
|
||||||
*/
|
*/
|
||||||
public class MapSender {
|
public class MapSender_v1_12_R1 {
|
||||||
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;
|
||||||
|
|
||||||
private MapSender() {
|
private MapSender_v1_12_R1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,9 +84,6 @@ public class MapSender {
|
||||||
}, 0, 2);
|
}, 0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Class<?> packetPlayOutMapClass = ReflectionUtil.getNMSClass("network.protocol.game", "PacketPlayOutMap");
|
|
||||||
private static final Class<?> worldMapData = ReflectionUtil.supports(17) ? ReflectionUtil.getNMSClass("world.level.saveddata.maps", "WorldMap$b") : null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a map to a player
|
* Send a map to a player
|
||||||
*
|
*
|
||||||
|
@ -109,57 +108,59 @@ public class MapSender {
|
||||||
}
|
}
|
||||||
|
|
||||||
final int id = -id0;
|
final int id = -id0;
|
||||||
Object packet;
|
Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> {
|
||||||
if (ReflectionUtil.supports(17)) { //1.17+
|
try {
|
||||||
Object updateData = ReflectionUtil.callConstructor(worldMapData,
|
PacketPlayOutMap packet = new PacketPlayOutMap(
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
packet = ReflectionUtil.callConstructor(packetPlayOutMapClass,
|
|
||||||
id, //ID
|
id, //ID
|
||||||
(byte) 0, //Scale, 0 = 1 block per pixel
|
(byte) 0, //Scale
|
||||||
false, //Show icons
|
|
||||||
new ReflectionUtil.CollectionParam<>(), //Icons
|
|
||||||
updateData
|
|
||||||
);
|
|
||||||
} else if (ReflectionUtil.supports(14)) { //1.16-1.14
|
|
||||||
packet = ReflectionUtil.callConstructor(packetPlayOutMapClass,
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale, 0 = 1 block per pixel
|
|
||||||
false, //Tracking position
|
|
||||||
false, //Locked
|
|
||||||
new ReflectionUtil.CollectionParam<>(), //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(packetPlayOutMapClass,
|
|
||||||
id, //ID
|
|
||||||
(byte) 0, //Scale, 0 = 1 block per pixel
|
|
||||||
false, //???
|
false, //???
|
||||||
new ReflectionUtil.CollectionParam<>(), //Icons
|
new ArrayList<>(), //Icons
|
||||||
content.array, //Data
|
content.array, //Data
|
||||||
content.minX, //X pos
|
content.minX, //X pos
|
||||||
content.minY, //Y pos
|
content.minY, //Y pos
|
||||||
content.maxX, //X size (2nd X pos)
|
content.maxX, //X size (2nd X pos)
|
||||||
content.maxY //Y size (2nd Y pos)
|
content.maxY //Y size (2nd Y pos)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ReflectionUtil.sendPacket(player, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
static final class QueuedMap {
|
static final class QueuedMap {
|
||||||
private final int id;
|
private final int id;
|
||||||
private final ArrayImage image;
|
private final ArrayImage image;
|
||||||
private final Player player;
|
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;
|
||||||
|
QueuedMap 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 + ']';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,249 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import net.minecraft.server.v1_12_R1.*;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
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.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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
public class MapWrapper_v1_12_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_12_R1.this.content = duplicate.getContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapWrapper_v1_12_R1.this.content = content;
|
||||||
|
|
||||||
|
for (UUID id : viewers.keySet()) {
|
||||||
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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_12_R1.sendMap(id, MapWrapper_v1_12_R1.this.content, player);
|
||||||
|
} else {
|
||||||
|
MapSender_v1_12_R1.addToQueue(id, MapWrapper_v1_12_R1.this.content, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_12_R1.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.MAP, 1);
|
||||||
|
net.minecraft.server.v1_12_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.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.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.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_12_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_12_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack);
|
||||||
|
if (nmsStack.getTag() == null) nmsStack.setTag(new NBTTagCompound()); //No orCreate on 1.12.2!
|
||||||
|
nmsStack.getTag().setInt("map", mapId); //getTag putInt
|
||||||
|
|
||||||
|
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<DataWatcher.Item<?>> list = new ArrayList<>();
|
||||||
|
DataWatcherObject<net.minecraft.server.v1_12_R1.ItemStack> dataWatcherObject = (DataWatcherObject<net.minecraft.server.v1_12_R1.ItemStack>) getDeclaredField(EntityItemFrame.class, "c");
|
||||||
|
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
setDeclaredField(packet, "b", list);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public MapWrapper_v1_12_R1(ArrayImage image) {
|
||||||
|
super(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(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);
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_13_R2/pom.xml
Normal file
72
NMS-v1_13_R2/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_13_R2} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_13_R2 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_13_R2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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 + ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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 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 cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_13_R2.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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>) getDeclaredField(EntityItemFrame.class, "e");
|
||||||
|
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
setDeclaredField(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(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);
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_14_R1/pom.xml
Normal file
72
NMS-v1_14_R1/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_14_R1} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_14_R1 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_14_R1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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 + ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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 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 cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_14_R1.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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>) getDeclaredField(EntityItemFrame.class, "ITEM");
|
||||||
|
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
setDeclaredField(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(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);
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_15_R1/pom.xml
Normal file
72
NMS-v1_15_R1/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_15_R1} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_15_R1 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_15_R1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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 + ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,249 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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 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 cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_15_R1.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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>) getDeclaredField(EntityItemFrame.class, "ITEM");
|
||||||
|
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
setDeclaredField(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(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);
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_16_R3/pom.xml
Normal file
72
NMS-v1_16_R3/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_16_R3} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_16_R3 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_16_R3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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 + ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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 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 cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_16_R3.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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>) getDeclaredField(EntityItemFrame.class, "ITEM");
|
||||||
|
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
setDeclaredField(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(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);
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_17_R1/pom.xml
Normal file
72
NMS-v1_17_R1/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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>17</jdk.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_17_R1} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_17_R1 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_17_R1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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 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 cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_17_R1.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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>) getDeclaredField(EntityItemFrame.class, "ao");
|
||||||
|
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
setDeclaredField(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utils.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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(packetPlayInUseEntity, "a"); //entityId
|
||||||
|
Object action = getDeclaredField(packetPlayInUseEntity, "b"); //action
|
||||||
|
Enum<?> actionEnum = (Enum<?>) callDeclaredMethod(action, "a"); //action type
|
||||||
|
EnumHand hand = hasField(action, "a") ? (EnumHand) getDeclaredField(action, "a") : null; //hand
|
||||||
|
Vec3D pos = hasField(action, "b") ? (Vec3D) getDeclaredField(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
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_18_R2/pom.xml
Normal file
72
NMS-v1_18_R2/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_18_R2} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_18_R2 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_18_R2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.getDeclaredField;
|
||||||
|
import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.setDeclaredField;
|
||||||
|
|
||||||
|
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 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 cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_18_R2.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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>) getDeclaredField(EntityItemFrame.class, "ao");
|
||||||
|
DataWatcher.Item<?> dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
setDeclaredField(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utils.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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(packetPlayInUseEntity, "a"); //entityId
|
||||||
|
Object action = getDeclaredField(packetPlayInUseEntity, "b"); //action
|
||||||
|
Enum<?> actionEnum = (Enum<?>) callDeclaredMethod(action, "a"); //action type
|
||||||
|
EnumHand hand = hasField(action, "a") ? (EnumHand) getDeclaredField(action, "a") : null; //hand
|
||||||
|
Vec3D pos = hasField(action, "b") ? (Vec3D) getDeclaredField(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
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_19_R3/pom.xml
Normal file
72
NMS-v1_19_R3/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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_R3</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<NMSVersion>1.19.4-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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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_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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_19_R3} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_19_R3 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_19_R3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapWrapper_v1_19_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_19_R3.this.content = duplicate.getContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapWrapper_v1_19_R3.this.content = content;
|
||||||
|
|
||||||
|
for (UUID id : viewers.keySet()) {
|
||||||
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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_R3.sendMap(id, MapWrapper_v1_19_R3.this.content, player);
|
||||||
|
} else {
|
||||||
|
MapSender_v1_19_R3.addToQueue(id, MapWrapper_v1_19_R3.this.content, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_19_R3.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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().bO.j; //inventoryMenu containerId
|
||||||
|
int stateId = craftPlayer.getHandle().bO.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_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().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
|
||||||
|
|
||||||
|
List<DataWatcher.b<?>> list = new ArrayList<>();
|
||||||
|
DataWatcher.b<?> dataWatcherItem = DataWatcher.b.a(EntityItemFrame.g, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, list);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().b.a(packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public MapWrapper_v1_19_R3(ArrayImage image) {
|
||||||
|
super(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
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_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_19_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.utils.ReflectionUtil.*;
|
||||||
|
|
||||||
|
public class PacketListener_v1_19_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) {
|
||||||
|
int id = packetPlayOutMap.a(); //mapId
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(packetPlayInUseEntity, "a"); //entityId
|
||||||
|
Object action = getDeclaredField(packetPlayInUseEntity, "b"); //action
|
||||||
|
Enum<?> actionEnum = (Enum<?>) callDeclaredMethod(action, "a"); //action type
|
||||||
|
EnumHand hand = hasField(action, "a") ? (EnumHand) getDeclaredField(action, "a") : null; //hand
|
||||||
|
Vec3D pos = hasField(action, "b") ? (Vec3D) getDeclaredField(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.a();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().b, "h");
|
||||||
|
ChannelPipeline pipeline = networkManager.m.pipeline(); //connection channel
|
||||||
|
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePlayer(Player p) {
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().b, "h");
|
||||||
|
Channel channel = networkManager.m; //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
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_20_R2/pom.xml
Normal file
72
NMS-v1_20_R2/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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_20_R2</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<NMSVersion>1.20.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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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_20_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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_20_R2} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_20_R2 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_20_R2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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().c.a(packet); //connection send()
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record QueuedMap(int id, ArrayImage image, Player player) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapWrapper_v1_20_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_20_R2.this.content = duplicate.getContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapWrapper_v1_20_R2.this.content = content;
|
||||||
|
|
||||||
|
for (UUID id : viewers.keySet()) {
|
||||||
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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_20_R2.sendMap(id, MapWrapper_v1_20_R2.this.content, player);
|
||||||
|
} else {
|
||||||
|
MapSender_v1_20_R2.addToQueue(id, MapWrapper_v1_20_R2.this.content, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_20_R2.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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().bR.j; //inventoryMenu containerId
|
||||||
|
int stateId = craftPlayer.getHandle().bR.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().c.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_20_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.w().a("map", mapId); //getOrCreateTag putInt
|
||||||
|
|
||||||
|
List<DataWatcher.b<?>> list = new ArrayList<>();
|
||||||
|
DataWatcher.b<?> dataWatcherItem = DataWatcher.b.a(EntityItemFrame.g, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, list);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().c.a(packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public MapWrapper_v1_20_R2(ArrayImage image) {
|
||||||
|
super(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
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_20_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_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.utils.ReflectionUtil.*;
|
||||||
|
|
||||||
|
public class PacketListener_v1_20_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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(packetPlayInUseEntity, "a"); //entityId
|
||||||
|
Object action = getDeclaredField(packetPlayInUseEntity, "b"); //action
|
||||||
|
Enum<?> actionEnum = (Enum<?>) callDeclaredMethod(action, "a"); //action type
|
||||||
|
EnumHand hand = hasField(action, "a") ? (EnumHand) getDeclaredField(action, "a") : null; //hand
|
||||||
|
Vec3D pos = hasField(action, "b") ? (Vec3D) getDeclaredField(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.a();
|
||||||
|
ItemStack item = packetPlayInSetCreativeSlot.d();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
ChannelPipeline pipeline = networkManager.n.pipeline(); //connection channel
|
||||||
|
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePlayer(Player p) {
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
Channel channel = networkManager.n; //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
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_20_R3/pom.xml
Normal file
72
NMS-v1_20_R3/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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_20_R3</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<NMSVersion>1.20.4-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.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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_20_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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_20_R3} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_20_R3 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_20_R3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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().c.a(packet); //connection send()
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record QueuedMap(int id, ArrayImage image, Player player) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapWrapper_v1_20_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_20_R3.this.content = duplicate.getContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapWrapper_v1_20_R3.this.content = content;
|
||||||
|
|
||||||
|
for (UUID id : viewers.keySet()) {
|
||||||
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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_20_R3.sendMap(id, MapWrapper_v1_20_R3.this.content, player);
|
||||||
|
} else {
|
||||||
|
MapSender_v1_20_R3.addToQueue(id, MapWrapper_v1_20_R3.this.content, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_20_R3.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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().bR.j; //inventoryMenu containerId
|
||||||
|
int stateId = craftPlayer.getHandle().bR.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().c.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_20_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().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.w().a("map", mapId); //getOrCreateTag putInt
|
||||||
|
|
||||||
|
List<DataWatcher.b<?>> list = new ArrayList<>();
|
||||||
|
DataWatcher.b<?> dataWatcherItem = DataWatcher.b.a(EntityItemFrame.g, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, list);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().c.a(packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public MapWrapper_v1_20_R3(ArrayImage image) {
|
||||||
|
super(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
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_20_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_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.utils.ReflectionUtil.*;
|
||||||
|
|
||||||
|
public class PacketListener_v1_20_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) {
|
||||||
|
int id = (int) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(packetPlayInUseEntity, "a"); //entityId
|
||||||
|
Object action = getDeclaredField(packetPlayInUseEntity, "b"); //action
|
||||||
|
Enum<?> actionEnum = (Enum<?>) callDeclaredMethod(action, "a"); //action type
|
||||||
|
EnumHand hand = hasField(action, "a") ? (EnumHand) getDeclaredField(action, "a") : null; //hand
|
||||||
|
Vec3D pos = hasField(action, "b") ? (Vec3D) getDeclaredField(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.a();
|
||||||
|
ItemStack item = packetPlayInSetCreativeSlot.d();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
ChannelPipeline pipeline = networkManager.n.pipeline(); //connection channel
|
||||||
|
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePlayer(Player p) {
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
Channel channel = networkManager.n; //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
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_20_R4/pom.xml
Normal file
72
NMS-v1_20_R4/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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_20_R4</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<NMSVersion>1.20.6-R0.1-SNAPSHOT</NMSVersion>
|
||||||
|
<jdk.version>21</jdk.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.MapId;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.WorldMap;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R4.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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_20_R4} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_20_R4 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_20_R4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
MapId mapId = new MapId(id);
|
||||||
|
|
||||||
|
PacketPlayOutMap packet = new PacketPlayOutMap(
|
||||||
|
mapId, //ID
|
||||||
|
(byte) 0, //Scale
|
||||||
|
false, //Show icons
|
||||||
|
new ArrayList<>(), //Icons
|
||||||
|
updateData
|
||||||
|
);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().c.a(packet); //connection send()
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record QueuedMap(int id, ArrayImage image, Player player) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import net.minecraft.core.component.DataComponentType;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
|
||||||
|
import net.minecraft.network.syncher.DataWatcher;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.MapId;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R4.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R4.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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapWrapper_v1_20_R4 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_20_R4.this.content = duplicate.getContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapWrapper_v1_20_R4.this.content = content;
|
||||||
|
|
||||||
|
for (UUID id : viewers.keySet()) {
|
||||||
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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_20_R4.sendMap(id, MapWrapper_v1_20_R4.this.content, player);
|
||||||
|
} else {
|
||||||
|
MapSender_v1_20_R4.addToQueue(id, MapWrapper_v1_20_R4.this.content, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_20_R4.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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().cb.j; //inventoryMenu containerId
|
||||||
|
int stateId = craftPlayer.getHandle().cb.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().c.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_20_R4.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);
|
||||||
|
MapId mapId1 = new MapId(mapId);
|
||||||
|
nmsStack.b(DataComponents.B, mapId1); //set
|
||||||
|
|
||||||
|
List<DataWatcher.c<?>> list = new ArrayList<>();
|
||||||
|
DataWatcher.c<?> dataWatcherItem = DataWatcher.c.a(EntityItemFrame.g, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, list);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().c.a(packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public MapWrapper_v1_20_R4(ArrayImage image) {
|
||||||
|
super(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
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_20_R4.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R4.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.utils.ReflectionUtil.*;
|
||||||
|
|
||||||
|
public class PacketListener_v1_20_R4 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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(packetPlayInUseEntity, "a"); //entityId
|
||||||
|
Object action = getDeclaredField(packetPlayInUseEntity, "b"); //action
|
||||||
|
Enum<?> actionEnum = (Enum<?>) callDeclaredMethod(action, "a"); //action type
|
||||||
|
EnumHand hand = hasField(action, "a") ? (EnumHand) getDeclaredField(action, "a") : null; //hand
|
||||||
|
Vec3D pos = hasField(action, "b") ? (Vec3D) getDeclaredField(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 = (int) getDeclaredField(packetPlayInSetCreativeSlot, supports(20, 4) ? "b" : "a"); //slot, 1.20.5 = b, lower is a
|
||||||
|
ItemStack item = (ItemStack) getDeclaredField(packetPlayInSetCreativeSlot, supports(20, 4) ? "e" : "d"); //item, 1.20.5 = e, lower is d
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
ChannelPipeline pipeline = networkManager.n.pipeline(); //connection channel
|
||||||
|
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePlayer(Player p) {
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
Channel channel = networkManager.n; //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
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_21_R1/pom.xml
Normal file
72
NMS-v1_21_R1/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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_21_R1</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<NMSVersion>1.21-R0.1-SNAPSHOT</NMSVersion>
|
||||||
|
<jdk.version>21</jdk.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.MapId;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.WorldMap;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_21_R1} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_21_R1 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_21_R1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
MapId mapId = new MapId(id);
|
||||||
|
|
||||||
|
PacketPlayOutMap packet = new PacketPlayOutMap(
|
||||||
|
mapId, //ID
|
||||||
|
(byte) 0, //Scale
|
||||||
|
false, //Show icons
|
||||||
|
new ArrayList<>(), //Icons
|
||||||
|
updateData
|
||||||
|
);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().c.a(packet); //connection send()
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record QueuedMap(int id, ArrayImage image, Player player) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import net.minecraft.core.component.DataComponentType;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
|
||||||
|
import net.minecraft.network.syncher.DataWatcher;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.MapId;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapWrapper_v1_21_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_21_R1.this.content = duplicate.getContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapWrapper_v1_21_R1.this.content = content;
|
||||||
|
|
||||||
|
for (UUID id : viewers.keySet()) {
|
||||||
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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_21_R1.sendMap(id, MapWrapper_v1_21_R1.this.content, player);
|
||||||
|
} else {
|
||||||
|
MapSender_v1_21_R1.addToQueue(id, MapWrapper_v1_21_R1.this.content, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_21_R1.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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().cc.j; //inventoryMenu containerId
|
||||||
|
int stateId = craftPlayer.getHandle().cc.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().c.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_21_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);
|
||||||
|
MapId mapId1 = new MapId(mapId);
|
||||||
|
nmsStack.b(DataComponents.B, mapId1); //set
|
||||||
|
|
||||||
|
List<DataWatcher.c<?>> list = new ArrayList<>();
|
||||||
|
DataWatcher.c<?> dataWatcherItem = DataWatcher.c.a(EntityItemFrame.f, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, list);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().c.a(packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public MapWrapper_v1_21_R1(ArrayImage image) {
|
||||||
|
super(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
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_21_R1.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_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.utils.ReflectionUtil.*;
|
||||||
|
|
||||||
|
public class PacketListener_v1_21_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) getDeclaredField(packetPlayOutMap, "a");
|
||||||
|
|
||||||
|
if (id < 0) {
|
||||||
|
//It's one of our maps, invert ID and let through!
|
||||||
|
int newId = -id;
|
||||||
|
setDeclaredField(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) getDeclaredField(packetPlayInUseEntity, "a"); //entityId
|
||||||
|
Object action = getDeclaredField(packetPlayInUseEntity, "b"); //action
|
||||||
|
Enum<?> actionEnum = (Enum<?>) callDeclaredMethod(action, "a"); //action type
|
||||||
|
EnumHand hand = hasField(action, "a") ? (EnumHand) getDeclaredField(action, "a") : null; //hand
|
||||||
|
Vec3D pos = hasField(action, "b") ? (Vec3D) getDeclaredField(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 = (int) getDeclaredField(packetPlayInSetCreativeSlot, supports(20, 4) ? "b" : "a"); //slot, 1.20.5 = b, lower is a
|
||||||
|
ItemStack item = (ItemStack) getDeclaredField(packetPlayInSetCreativeSlot, supports(20, 4) ? "e" : "d"); //item, 1.20.5 = e, lower is d
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
ChannelPipeline pipeline = networkManager.n.pipeline(); //connection channel
|
||||||
|
pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePlayer(Player p) {
|
||||||
|
//The connection is private since 1.19.4 :|
|
||||||
|
NetworkManager networkManager = (NetworkManager) getField(((CraftPlayer) p).getHandle().c, "h");
|
||||||
|
Channel channel = networkManager.n; //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
|
||||||
|
}
|
||||||
|
}
|
72
NMS-v1_21_R2/pom.xml
Normal file
72
NMS-v1_21_R2/pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ This file is part of MapReflectionAPI.
|
||||||
|
~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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_21_R2</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<NMSVersion>1.21.3-R0.1-SNAPSHOT</NMSVersion>
|
||||||
|
<jdk.version>21</jdk.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>${jdk.version}</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>3.1.1</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>${revision}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutMap;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.MapId;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.WorldMap;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MapSender_v1_21_R2} sends the Map packets to players.
|
||||||
|
*/
|
||||||
|
public class MapSender_v1_21_R2 {
|
||||||
|
private static final List<QueuedMap> sendQueue = new ArrayList<>();
|
||||||
|
private static int senderID = -1;
|
||||||
|
|
||||||
|
private MapSender_v1_21_R2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a map to the send queue
|
||||||
|
*
|
||||||
|
* @param id The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a senderID in the sender queue
|
||||||
|
*
|
||||||
|
* @param s The senderID to cancel
|
||||||
|
*/
|
||||||
|
public static void cancelID(int s) {
|
||||||
|
sendQueue.removeIf(queuedMap -> queuedMap.id == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the sender task
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a map to a player
|
||||||
|
*
|
||||||
|
* @param id0 The ID of the map
|
||||||
|
* @param content The {@link ArrayImage} to view on the map
|
||||||
|
* @param player The {@link Player} to view for
|
||||||
|
*/
|
||||||
|
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.c updateData = new WorldMap.c(
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
MapId mapId = new MapId(id);
|
||||||
|
|
||||||
|
PacketPlayOutMap packet = new PacketPlayOutMap(
|
||||||
|
mapId, //ID
|
||||||
|
(byte) 0, //Scale
|
||||||
|
false, //Show icons
|
||||||
|
new ArrayList<>(), //Icons
|
||||||
|
updateData
|
||||||
|
);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().f.a(packet); //connection send()
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record QueuedMap(int id, ArrayImage image, Player player) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* This file is part of MapReflectionAPI.
|
||||||
|
* Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tech.sbdevelopment.mapreflectionapi.nms;
|
||||||
|
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
|
||||||
|
import net.minecraft.network.syncher.DataWatcher;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.decoration.EntityItemFrame;
|
||||||
|
import net.minecraft.world.level.saveddata.maps.MapId;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R2.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R2.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_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.api.exceptions.MapLimitExceededException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapWrapper_v1_21_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_21_R2.this.content = duplicate.getContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapWrapper_v1_21_R2.this.content = content;
|
||||||
|
|
||||||
|
for (UUID id : viewers.keySet()) {
|
||||||
|
sendContent(Bukkit.getPlayer(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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_21_R2.sendMap(id, MapWrapper_v1_21_R2.this.content, player);
|
||||||
|
} else {
|
||||||
|
MapSender_v1_21_R2.addToQueue(id, MapWrapper_v1_21_R2.this.content, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelSend() {
|
||||||
|
for (int s : viewers.values()) {
|
||||||
|
MapSender_v1_21_R2.cancelID(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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().cc.j; //inventoryMenu containerId
|
||||||
|
int stateId = craftPlayer.getHandle().cc.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().f.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_21_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);
|
||||||
|
MapId mapId1 = new MapId(mapId);
|
||||||
|
nmsStack.b(DataComponents.L, mapId1); //set
|
||||||
|
|
||||||
|
List<DataWatcher.c<?>> list = new ArrayList<>();
|
||||||
|
DataWatcher.c<?> dataWatcherItem = DataWatcher.c.a(EntityItemFrame.e, nmsStack);
|
||||||
|
list.add(dataWatcherItem);
|
||||||
|
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, list);
|
||||||
|
|
||||||
|
((CraftPlayer) player).getHandle().f.a(packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public MapWrapper_v1_21_R2(ArrayImage image) {
|
||||||
|
super(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue