:>1.0.0 Add new EaglerXBukkitAPI plugin files

Use IEaglerXBukkitAPI.getAPI(player) to access the new official API for communication between your Bukkit plugins and an EaglerXBungee/EaglerXVelocity server
This commit is contained in:
lax1dude 2024-08-09 20:28:45 -07:00
parent d8ef6423c5
commit 64a1396b97
39 changed files with 2876 additions and 0 deletions

View File

@ -0,0 +1,10 @@
lib/*
.idea/*
*.iml
out/*
/.gradle/
/.settings/
.classpath
.project
/build/
/bin/

View File

@ -0,0 +1,40 @@
plugins {
id 'java'
id 'eclipse'
}
group = 'net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper'
version = ''
repositories {
mavenCentral()
maven {
url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/'
}
maven {
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
sourceSets {
main {
java {
srcDirs 'src/main/java'
srcDirs '../backend-rpc-protocol/src/backend-rpc-protocol/java'
}
}
}
dependencies {
compileOnly 'org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
jar {
compileJava.options.encoding = 'UTF-8'
javadoc.options.encoding = 'UTF-8'
}

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Thu Jun 20 10:14:47 CDT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

234
gateway/EaglercraftXBukkitAPI/gradlew vendored Normal file
View File

@ -0,0 +1,234 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,2 @@
rootProject.name = 'EaglercraftXBukkitAPI'

View File

@ -0,0 +1,58 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.messaging.PluginMessageListener;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl.PlayerDataObj;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerXBukkitAPIListener implements Listener, PluginMessageListener {
@EventHandler
public void onLoginEvent(PlayerLoginEvent evt) {
PlayerDataObj.setupPlayer(evt.getPlayer());
}
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] data) {
if(EaglerBackendRPCProtocol.CHANNEL_NAME.equals(channel)) {
PlayerDataObj dataObj = PlayerDataObj.getForPlayer(player);
if(dataObj != null) {
dataObj.firePluginMsgRecievedInternal(data);
}
}else if(EaglerBackendRPCProtocol.CHANNEL_NAME_READY.equals(channel)) {
PlayerDataObj dataObj = PlayerDataObj.getForPlayer(player);
if(dataObj != null) {
dataObj.firePluginReadyMsgRecieved();
}
}
}
@EventHandler
public void onQuitEvent(PlayerQuitEvent evt) {
PlayerDataObj dataObj = PlayerDataObj.getForPlayer(evt.getPlayer());
if(dataObj != null) {
dataObj.firePlayerQuitEventInternal();
}
}
}

View File

@ -0,0 +1,86 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper;
import java.util.Collection;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl.PlayerDataObj;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerXBukkitAPIPlugin extends JavaPlugin {
private static EaglerXBukkitAPIPlugin instance = null;
private Timer timeoutHandler;
public EaglerXBukkitAPIPlugin() {
instance = this;
}
@Override
public void onLoad() {
}
@Override
public void onEnable() {
EaglerXBukkitAPIListener ls = new EaglerXBukkitAPIListener();
getServer().getPluginManager().registerEvents(ls, this);
getServer().getMessenger().registerOutgoingPluginChannel(this, EaglerBackendRPCProtocol.CHANNEL_NAME);
getServer().getMessenger().registerIncomingPluginChannel(this, EaglerBackendRPCProtocol.CHANNEL_NAME, ls);
getServer().getMessenger().registerIncomingPluginChannel(this, EaglerBackendRPCProtocol.CHANNEL_NAME_READY, ls);
if(timeoutHandler == null) {
timeoutHandler = new Timer("EaglerXBukkitAPI: Timeout cleanup thread");
timeoutHandler.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Collection<? extends Player> pp = EaglerXBukkitAPIPlugin.this.getServer().getOnlinePlayers();
if(!pp.isEmpty()) {
long now = System.nanoTime() / 1000000l;
for(Player p : pp) {
PlayerDataObj.getForPlayer(p).fireCheckRequestTimeoutsInternal(now);
}
}
}
}, 0l, 5000l);
}
}
@Override
public void onDisable() {
getServer().getMessenger().unregisterOutgoingPluginChannel(this);
getServer().getMessenger().unregisterIncomingPluginChannel(this);
if(timeoutHandler != null) {
timeoutHandler.cancel();
timeoutHandler = null;
}
}
public static EaglerXBukkitAPIPlugin getEagler() {
return instance;
}
public static Logger logger() {
return instance.getLogger();
}
}

View File

@ -0,0 +1,37 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ClientBrandUUIDs {
public static final UUID BRAND_NULL_UUID = new UUID(0l, 0l);
public static final UUID BRAND_VANILLA_UUID = new UUID(0x1DCE015CD384374El, 0x85030A4DE95E5736l);
public static final UUID BRAND_EAGLERCRAFTX_V4_UUID = makeClientBrandUUID("EaglercraftX");
public static final UUID BRAND_EAGLERCRAFTX_LEGACY_UUID = makeClientBrandUUIDLegacy("EaglercraftX");
public static UUID makeClientBrandUUID(String name) {
return UUID.nameUUIDFromBytes(("EaglercraftXClient:" + name).getBytes(StandardCharsets.UTF_8));
}
public static UUID makeClientBrandUUIDLegacy(String name) {
return UUID.nameUUIDFromBytes(("EaglercraftXClientOld:" + name).getBytes(StandardCharsets.UTF_8));
}
}

View File

@ -0,0 +1,35 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerRPCException extends RuntimeException {
public EaglerRPCException() {
}
public EaglerRPCException(String message, Throwable cause) {
super(message, cause);
}
public EaglerRPCException(String message) {
super(message);
}
public EaglerRPCException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,45 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerRPCInitException extends EaglerRPCException {
private int code;
public EaglerRPCInitException(int code) {
this.code = code;
}
public EaglerRPCInitException(int code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
public EaglerRPCInitException(int code, String message) {
super(message);
this.code = code;
}
public EaglerRPCInitException(int code, Throwable cause) {
super(cause);
this.code = code;
}
public int getFailureCodeEagler() {
return code;
}
}

View File

@ -0,0 +1,39 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCSubscribeEvents;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public enum EnumSubscribeEvents {
/** @see net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.EventWebViewOpenClose */
EVENT_WEBVIEW_OPEN_CLOSE(CPacketRPCSubscribeEvents.SUBSCRIBE_EVENT_WEBVIEW_OPEN_CLOSE),
/** @see net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.EventWebViewMessage */
EVENT_WEBVIEW_MESSAGE(CPacketRPCSubscribeEvents.SUBSCRIBE_EVENT_WEBVIEW_MESSAGE),
/** @see net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.EventToggledVoice */
EVENT_TOGGLE_VOICE(CPacketRPCSubscribeEvents.SUBSCRIBE_EVENT_TOGGLE_VOICE);
protected static final EnumSubscribeEvents[] _VALUES = values();
public final int bit;
private EnumSubscribeEvents(int bit) {
this.bit = bit;
}
}

View File

@ -0,0 +1,22 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface IEaglerRPCCloseHandler {
void handleEvent(IEaglerXBukkitAPI api);
}

View File

@ -0,0 +1,24 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.IEaglerRPCEvent;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface IEaglerRPCEventHandler<T extends IEaglerRPCEvent> {
void handleEvent(IEaglerXBukkitAPI api, EnumSubscribeEvents event, T data);
}

View File

@ -0,0 +1,48 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
import java.util.concurrent.Executor;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface IEaglerRPCFuture<V> extends ListenableFuture<V> {
public static final Executor SAME_THREAD_EXECUTOR = MoreExecutors.sameThreadExecutor();
/**
* Warning: Futures.addCallback is recommended!
*/
default void addListener(Runnable runnable) {
addListener(runnable, SAME_THREAD_EXECUTOR);
}
default void addCallback(FutureCallback<V> runnable, Executor executor) {
Futures.addCallback(this, runnable, executor);
}
default void addCallback(FutureCallback<V> runnable) {
Futures.addCallback(this, runnable, SAME_THREAD_EXECUTOR);
}
void setExpiresMSFromNow(int millis);
boolean hasExpired();
}

View File

@ -0,0 +1,243 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.bukkit.entity.Player;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCNotifBadgeShow;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCSetPauseMenuCustom;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.NotificationBadgeBuilder;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.SkinPacketHelper;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.IEaglerRPCEvent;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseBytes;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseCookie;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseString;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseUUID;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseVoiceStatus;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseWebViewStatus;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl.EaglerXBukkitImpl;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface IEaglerXBukkitAPI {
public static IEaglerRPCFuture<IEaglerXBukkitAPI> getAPI(Player player) {
IEaglerRPCFuture<IEaglerXBukkitAPI> futureRet = EaglerXBukkitImpl.getAPI(player);
futureRet.setExpiresMSFromNow(EaglerXBukkitImpl.DEFAULT_TIMEOUT);
return futureRet;
}
public static IEaglerRPCFuture<IEaglerXBukkitAPI> getAPI(Player player, int timeoutMS) {
IEaglerRPCFuture<IEaglerXBukkitAPI> futureRet = EaglerXBukkitImpl.getAPI(player);
futureRet.setExpiresMSFromNow(timeoutMS);
return futureRet;
}
EaglerBackendRPCProtocol getRPCProtocolVersion();
int getEaglerProtocolVersion();
boolean isOpen();
void closeAPI();
Player getPlayer();
void sendRPCPacket(EaglerBackendRPCPacket packet);
default void subscribeEvents(EnumSubscribeEvents...events) {
int bits = 0;
for(int i = 0; i < events.length; ++i) {
bits |= events[i].bit;
}
subscribeEvents(bits);
}
void subscribeEvents(int events);
default void unsubscribeEvents(EnumSubscribeEvents...events) {
int bits = 0;
for(int i = 0; i < events.length; ++i) {
bits |= events[i].bit;
}
unsubscribeEvents(bits);
}
void unsubscribeEvents(int events);
void unsubscribeAllEvents();
int getSubscribedEventsBits();
default Set<EnumSubscribeEvents> getSubscribedEvents() {
Set<EnumSubscribeEvents> ret = new HashSet<>(4);
int bits = getSubscribedEventsBits();
EnumSubscribeEvents[] enums = EnumSubscribeEvents._VALUES;
for(int i = 0; i < enums.length; ++i) {
if((bits & enums[i].bit) != 0) {
ret.add(enums[i]);
}
}
return ret;
}
void addEventListener(EnumSubscribeEvents eventType, IEaglerRPCEventHandler<? extends IEaglerRPCEvent> handler);
void removeEventListener(EnumSubscribeEvents eventType, IEaglerRPCEventHandler<? extends IEaglerRPCEvent> handler);
void removeEventListeners(EnumSubscribeEvents eventType);
void addCloseListener(IEaglerRPCCloseHandler handler);
void removeCloseListener(IEaglerRPCCloseHandler handler);
void removeCloseListeners();
boolean redirectPlayerSupported();
void redirectPlayerToWebSocket(String webSocketURI);
void setBaseRequestTimeout(int seconds);
IEaglerRPCFuture<ResponseUUID> requestPlayerProfileUUID();
IEaglerRPCFuture<ResponseString> requestPlayerRealIP();
IEaglerRPCFuture<ResponseString> requestPlayerOrigin();
IEaglerRPCFuture<ResponseString> requestPlayerUserAgent();
IEaglerRPCFuture<ResponseBytes> requestPlayerSkinData();
IEaglerRPCFuture<ResponseBytes> requestPlayerCapeData();
IEaglerRPCFuture<ResponseCookie> requestPlayerCookieData();
IEaglerRPCFuture<ResponseString> requestPlayerClientBrandStr();
IEaglerRPCFuture<ResponseString> requestPlayerClientVersionStr();
IEaglerRPCFuture<ResponseString> requestPlayerClientBrandAndVersionStr();
IEaglerRPCFuture<ResponseUUID> requestPlayerClientBrandUUID();
IEaglerRPCFuture<ResponseVoiceStatus> requestPlayerVoiceStatus();
IEaglerRPCFuture<ResponseWebViewStatus> requestPlayerWebViewStatus();
void sendRawCustomPayloadPacket(String channel, byte[] data);
default void sendRawEaglerPacketV4(byte[] data) {
sendRawCustomPayloadPacket("EAG|1.8", data);
}
boolean pauseMenuCustomizationSupported();
void setPauseMenuCustomizationState(CPacketRPCSetPauseMenuCustom packet);
void sendWebViewMessageString(String channelName, String data);
void sendWebViewMessageBytes(String channelName, byte[] data);
void forcePlayerSkin(byte[] skinData, boolean notifyOthers);
default void forcePlayerSkinPreset(int presetID, boolean notifyOthers) {
forcePlayerSkin(SkinPacketHelper.writePresetSkinPacket(presetID), notifyOthers);
}
default void forcePlayerSkinCustom(int modelId, byte[] texture64x64, boolean notifyOthers) {
forcePlayerSkin(SkinPacketHelper.writeCustomSkinPacket(modelId, texture64x64), notifyOthers);
}
void forcePlayerCape(byte[] capeData, boolean notifyOthers);
default void forcePlayerCapePreset(int presetID, boolean notifyOthers) {
forcePlayerCape(SkinPacketHelper.writePresetCapePacket(presetID), notifyOthers);
}
default void forcePlayerCapeCustom(byte[] texture32x32, boolean notifyOthers) {
forcePlayerCape(SkinPacketHelper.writeCustomCapePacket(texture32x32), notifyOthers);
}
void setCookieData(byte[] cookieData, int expiresAfterSec, boolean revokeQuerySupported, boolean saveToDisk);
default void setCookieData(byte[] cookieData, int expiresAfter, TimeUnit expiresTimeUnit, boolean revokeQuerySupported, boolean saveToDisk) {
setCookieData(cookieData, (int)expiresTimeUnit.toSeconds(expiresAfter), revokeQuerySupported, saveToDisk);
}
default void setCookieData(byte[] cookieData, int expiresAfterSec, boolean revokeQuerySupported) {
setCookieData(cookieData, expiresAfterSec, revokeQuerySupported, true);
}
default void setCookieData(byte[] cookieData, int expiresAfter, TimeUnit expiresTimeUnit, boolean revokeQuerySupported) {
setCookieData(cookieData, (int)expiresTimeUnit.toSeconds(expiresAfter), revokeQuerySupported, true);
}
default void setCookieData(byte[] cookieData, int expiresAfterSec) {
setCookieData(cookieData, expiresAfterSec, false, true);
}
default void setCookieData(byte[] cookieData, int expiresAfter, TimeUnit expiresTimeUnit) {
setCookieData(cookieData, (int)expiresTimeUnit.toSeconds(expiresAfter), false, true);
}
default void clearCookieData() {
setCookieData(null, 0, false, false);
}
void setFNAWSkinsEnabled(boolean enabled, boolean force);
void setFNAWSkinsEnabled(boolean enabled);
void resetForcedMulti(boolean resetSkin, boolean resetCape, boolean resetFNAWForce, boolean notifyOtherPlayers);
void resetForcedSkin(boolean notifyOtherPlayers);
void resetForcedCape(boolean notifyOtherPlayers);
void resetForcedFNAW();
boolean notifSupported();
void notifIconRegister(Map<UUID, PacketImageData> iconsToRegister);
void notifIconRegister(UUID iconUUID, PacketImageData imageData);
void notifIconRelease(Collection<UUID> iconsToRelease);
void notifIconRelease(UUID iconUUID);
void notifBadgeShow(CPacketRPCNotifBadgeShow packet);
default void notifBadgeShow(NotificationBadgeBuilder packet) {
notifBadgeShow(packet.buildPacket());
}
void notifBadgeHide(UUID badgeUUID);
<T> void setMeta(String key, T value);
<T> T getMeta(String key);
}

View File

@ -0,0 +1,96 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.SkinPacketHelper;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ImageDataLoader {
public static PacketImageData loadPacketImageData(File img) throws IOException {
return loadPacketImageData(ImageIO.read(img), 255, 255);
}
public static PacketImageData loadPacketImageData(File img, int maxWidth, int maxHeight) throws IOException {
return loadPacketImageData(ImageIO.read(img), maxWidth, maxHeight);
}
public static PacketImageData loadPacketImageData(BufferedImage img) {
return loadPacketImageData(img, 255, 255);
}
public static PacketImageData loadPacketImageData(BufferedImage img, int maxWidth, int maxHeight) {
int w = img.getWidth();
int h = img.getHeight();
if(w > maxWidth || h > maxHeight) {
float aspectRatio = (float)w / (float)h;
int nw, nh;
if(aspectRatio >= 1.0f) {
nw = (int)(maxWidth / aspectRatio);
nh = maxHeight;
}else {
nw = maxWidth;
nh = (int)(maxHeight * aspectRatio);
}
BufferedImage resized = new BufferedImage(nw, nh, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) resized.getGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setBackground(new Color(0, true));
g.clearRect(0, 0, nw, nh);
g.drawImage(img, 0, 0, nw, nh, 0, 0, w, h, null);
g.dispose();
img = resized;
}
int[] pixels = new int[w * h];
img.getRGB(0, 0, w, h, pixels, 0, w);
return new PacketImageData(w, h, pixels);
}
public static byte[] loadCustomSkin(File texture64x64) throws IOException {
return SkinPacketHelper.loadCustomSkin(texture64x64);
}
public static byte[] loadCustomSkin(InputStream texture64x64) throws IOException {
return SkinPacketHelper.loadCustomSkin(texture64x64);
}
public static byte[] loadCustomSkin(BufferedImage texture64x64) {
return SkinPacketHelper.loadCustomSkin(texture64x64);
}
public static byte[] loadCustomCape(File textureNx64) throws IOException {
return SkinPacketHelper.loadCustomCape(textureNx64);
}
public static byte[] loadCustomCape(InputStream textureNx64) throws IOException {
return SkinPacketHelper.loadCustomCape(textureNx64);
}
public static byte[] loadCustomCape(BufferedImage textureNx64) {
return SkinPacketHelper.loadCustomCape(textureNx64);
}
}

View File

@ -0,0 +1,39 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EventToggledVoice implements IEaglerRPCEvent {
public static enum VoiceState {
SERVER_DISABLE, DISABLED, ENABLED;
}
public final VoiceState oldVoiceState;
public final VoiceState newVoiceState;
public EventToggledVoice(VoiceState oldVoiceState, VoiceState newVoiceState) {
this.oldVoiceState = oldVoiceState;
this.newVoiceState = newVoiceState;
}
@Override
public EnumSubscribeEvents getType() {
return EnumSubscribeEvents.EVENT_TOGGLE_VOICE;
}
}

View File

@ -0,0 +1,59 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event;
import java.nio.charset.StandardCharsets;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EventWebViewMessage implements IEaglerRPCEvent {
public static enum MessageType {
STRING, BINARY;
}
public final String channelName;
public final MessageType messageType;
protected final byte[] messageContent;
protected String asString = null;
public EventWebViewMessage(String channelName, MessageType messageType, byte[] messageContent) {
this.channelName = channelName;
this.messageType = messageType;
this.messageContent = messageContent;
}
public String getContentStr() {
if(messageType == MessageType.STRING) {
if(asString == null) {
asString = new String(messageContent, StandardCharsets.UTF_8);
}
return asString;
}else {
return null;
}
}
public byte[] getContentBytes() {
return messageType == MessageType.BINARY ? messageContent : null;
}
@Override
public EnumSubscribeEvents getType() {
return EnumSubscribeEvents.EVENT_WEBVIEW_MESSAGE;
}
}

View File

@ -0,0 +1,35 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EventWebViewOpenClose implements IEaglerRPCEvent {
public final String channelName;
public final boolean opened;
public EventWebViewOpenClose(String channelName, boolean opened) {
this.channelName = channelName;
this.opened = opened;
}
@Override
public EnumSubscribeEvents getType() {
return EnumSubscribeEvents.EVENT_WEBVIEW_OPEN_CLOSE;
}
}

View File

@ -0,0 +1,24 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface IEaglerRPCEvent {
EnumSubscribeEvents getType();
}

View File

@ -0,0 +1,37 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerRPCResponseException extends EaglerRPCException {
public EaglerRPCResponseException() {
}
public EaglerRPCResponseException(String message, Throwable cause) {
super(message, cause);
}
public EaglerRPCResponseException(String message) {
super(message);
}
public EaglerRPCResponseException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,29 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerRPCTimeoutException extends EaglerRPCException {
public EaglerRPCTimeoutException() {
}
public EaglerRPCTimeoutException(String message) {
super(message);
}
}

View File

@ -0,0 +1,26 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface IEaglerRPCResponse {
IEaglerXBukkitAPI getSource();
int getRequestID();
}

View File

@ -0,0 +1,42 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ResponseBytes implements IEaglerRPCResponse {
protected final IEaglerXBukkitAPI source;
protected final int requestID;
public final byte[] bytes;
public ResponseBytes(IEaglerXBukkitAPI source, int requestID, byte[] bytes) {
this.source = source;
this.requestID = requestID;
this.bytes = bytes;
}
@Override
public IEaglerXBukkitAPI getSource() {
return source;
}
@Override
public int getRequestID() {
return requestID;
}
}

View File

@ -0,0 +1,44 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ResponseCookie implements IEaglerRPCResponse {
protected final IEaglerXBukkitAPI source;
protected final int requestID;
public final boolean cookieEnabled;
public final byte[] cookieBytes;
public ResponseCookie(IEaglerXBukkitAPI source, int requestID, boolean cookieEnabled, byte[] cookieBytes) {
this.source = source;
this.requestID = requestID;
this.cookieEnabled = cookieEnabled;
this.cookieBytes = cookieBytes;
}
@Override
public IEaglerXBukkitAPI getSource() {
return source;
}
@Override
public int getRequestID() {
return requestID;
}
}

View File

@ -0,0 +1,42 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ResponseString implements IEaglerRPCResponse {
protected final IEaglerXBukkitAPI source;
protected final int requestID;
public final String string;
public ResponseString(IEaglerXBukkitAPI source, int requestID, String string) {
this.source = source;
this.requestID = requestID;
this.string = string;
}
@Override
public IEaglerXBukkitAPI getSource() {
return source;
}
@Override
public int getRequestID() {
return requestID;
}
}

View File

@ -0,0 +1,44 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import java.util.UUID;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ResponseUUID implements IEaglerRPCResponse {
protected final IEaglerXBukkitAPI source;
protected final int requestID;
public final UUID uuid;
public ResponseUUID(IEaglerXBukkitAPI source, int requestID, UUID uuid) {
this.source = source;
this.requestID = requestID;
this.uuid = uuid;
}
@Override
public IEaglerXBukkitAPI getSource() {
return source;
}
@Override
public int getRequestID() {
return requestID;
}
}

View File

@ -0,0 +1,46 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ResponseVoiceStatus implements IEaglerRPCResponse {
public static enum VoiceState {
SERVER_DISABLE, DISABLED, ENABLED;
}
protected final IEaglerXBukkitAPI source;
protected final int requestID;
public final VoiceState voiceState;
public ResponseVoiceStatus(IEaglerXBukkitAPI source, int requestID, VoiceState voiceState) {
this.source = source;
this.requestID = requestID;
this.voiceState = voiceState;
}
@Override
public IEaglerXBukkitAPI getSource() {
return source;
}
@Override
public int getRequestID() {
return requestID;
}
}

View File

@ -0,0 +1,48 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ResponseWebViewStatus implements IEaglerRPCResponse {
public static enum WebViewState {
NOT_SUPPORTED, SERVER_DISABLE, CHANNEL_CLOSED, CHANNEL_OPEN;
}
protected final IEaglerXBukkitAPI source;
protected final int requestID;
public final WebViewState webviewState;
public final String channelName;
public ResponseWebViewStatus(IEaglerXBukkitAPI source, int requestID, WebViewState webviewState, String channelName) {
this.source = source;
this.requestID = requestID;
this.webviewState = webviewState;
this.channelName = channelName;
}
@Override
public IEaglerXBukkitAPI getSource() {
return source;
}
@Override
public int getRequestID() {
return requestID;
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl;
import com.google.common.util.concurrent.AbstractFuture;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCFuture;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerRPCFutureImpl<V> extends AbstractFuture<V> implements IEaglerRPCFuture<V> {
private volatile long timeStart = -1l;
private volatile int timeoutAfter = -1;
@Override
public void setExpiresMSFromNow(int millis) {
if(millis > 0) {
timeStart = System.nanoTime() / 1000000l;
timeoutAfter = millis;
}else {
timeStart = -1l;
timeoutAfter = -1;
}
}
@Override
public boolean hasExpired() {
return (timeStart > 0l && timeoutAfter > 0) ? ((System.nanoTime() / 1000000l) - timeStart) > timeoutAfter : false;
}
public boolean hasExpiredBetter(long now) {
return (timeStart > 0l && timeoutAfter > 0) ? (now - timeStart) > timeoutAfter : false;
}
public void fireCompleteInternal(V value) {
this.set(value);
}
public void fireExceptionInternal(Throwable value) {
this.setException(value);
}
}

View File

@ -0,0 +1,788 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder.ListMultimapBuilder;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.*;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.*;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.EaglerXBukkitAPIPlugin;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCCloseHandler;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCEventHandler;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCFuture;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.*;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.*;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerXBukkitImpl implements IEaglerXBukkitAPI {
public static final int DEFAULT_TIMEOUT = 10000;
public static EaglerRPCFutureImpl<IEaglerXBukkitAPI> getAPI(Player player) {
if(player == null) {
throw new NullPointerException("Player cannot be null!");
}
PlayerDataObj data = PlayerDataObj.getForPlayer(player);
if(data == null) {
throw new IllegalStateException("Player object is not ready yet for EaglerXBukkitAPI.createAPI()! (Try hooking PlayerJoinEvent instead of PlayerLoginEvent you hooker)");
}
boolean sendHello;
synchronized(data) {
if(data.openFuture != null) {
return data.openFuture;
}
if(data.currentAPI != null) {
EaglerRPCFutureImpl<IEaglerXBukkitAPI> completeImmedately = new EaglerRPCFutureImpl();
completeImmedately.fireCompleteInternal(data.currentAPI);
return completeImmedately;
}
data.openFuture = new EaglerRPCFutureImpl();
sendHello = data.hasRecievedReady;
}
if(sendHello) {
sendHelloPacket(player);
}
return data.openFuture;
}
protected static void sendHelloPacket(Player player) {
player.sendPluginMessage(EaglerXBukkitAPIPlugin.getEagler(), EaglerBackendRPCProtocol.CHANNEL_NAME, HelloPacketFactory.BASE_HELLO_PACKET);
}
protected static EaglerXBukkitImpl createFromHandshakeInternal(PlayerDataObj playerDataObj, SPacketRPCEnabledSuccess pkt) {
return new EaglerXBukkitImpl(playerDataObj, EaglerBackendRPCProtocol.getByID(pkt.selectedRPCProtocol), pkt.playerClientProtocol);
}
protected final PlayerDataObj playerDataObj;
protected final Player playerObj;
protected final EaglerBackendRPCProtocol protocol;
protected final int gameProtocol;
protected boolean open;
protected final Map<String,Object> metadata = new ConcurrentHashMap<>(4);
protected final EaglerXBukkitAPIHandler packetHandler;
protected int subscribedEvents = 0;
protected final ListMultimap<EnumSubscribeEvents, IEaglerRPCEventHandler<? extends IEaglerRPCEvent>> eventHandlers = ListMultimapBuilder
.hashKeys().arrayListValues().build();
protected final List<IEaglerRPCCloseHandler> closeHandlers = new ArrayList<>(4);
protected final Map<Integer,EaglerRPCFutureImpl<? extends IEaglerRPCResponse>> waitingRequests = new ConcurrentHashMap<>();
protected int baseTimeout = DEFAULT_TIMEOUT;
protected final AtomicInteger requestIDGenerator = new AtomicInteger();
private final ReentrantLock inputStreamLock = new ReentrantLock();
private final ReentrantLock outputStreamLock = new ReentrantLock();
private final ReusableByteArrayInputStream reusableInputStream = new ReusableByteArrayInputStream();
private final ReusableByteArrayOutputStream reusableOutputStream = new ReusableByteArrayOutputStream();
private final DataInputStream dataInputStream = new DataInputStream(reusableInputStream);
private final DataOutputStream dataOutputStream = new DataOutputStream(reusableOutputStream);
protected EaglerXBukkitImpl(PlayerDataObj playerDataObj, EaglerBackendRPCProtocol protocol, int gameProtocol) {
this.playerDataObj = playerDataObj;
this.playerObj = playerDataObj.player;
this.protocol = protocol;
this.gameProtocol = gameProtocol;
this.open = true;
this.packetHandler = new EaglerXBukkitAPIHandler();
}
@Override
public EaglerBackendRPCProtocol getRPCProtocolVersion() {
return protocol;
}
@Override
public int getEaglerProtocolVersion() {
return gameProtocol;
}
@Override
public boolean isOpen() {
return open;
}
@Override
public void closeAPI() {
if(open) {
try {
sendRPCPacket(new CPacketRPCDisabled());
}finally {
fireAPIClosedEventInternal();
}
}
}
protected void fireAPIClosedEventInternal() {
if(!open) return;
open = false;
synchronized(closeHandlers) {
for(int i = 0, l = closeHandlers.size(); i < l; ++i) {
IEaglerRPCCloseHandler hd = closeHandlers.get(i);
try {
hd.handleEvent(this);
}catch(Throwable t) {
EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE,
"[" + playerObj.getName() + "] caught exception while firing close handler " + hd, t);
}
}
}
}
protected void fireAPIPacketRecievedInternal(EaglerBackendRPCPacket ret) {
ret.handlePacket(packetHandler);
}
protected <T extends IEaglerRPCEvent> void fireEventHandlers(T eventObj) {
EnumSubscribeEvents type = eventObj.getType();
List<IEaglerRPCEventHandler<? extends IEaglerRPCEvent>> lst;
synchronized(eventHandlers) {
lst = eventHandlers.get(type);
}
for(int i = 0, l = lst.size(); i < l; ++i) {
IEaglerRPCEventHandler<T> handler = (IEaglerRPCEventHandler<T>) lst.get(i);
try {
handler.handleEvent(this, type, eventObj);
}catch(Throwable t) {
EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE,
"[" + playerObj.getName() + "] caught exception while processing event type "
+ type + " using handler " + handler, t);
}
}
}
protected class EaglerXBukkitAPIHandler implements EaglerBackendRPCHandler {
public void handleServer(SPacketRPCResponseTypeNull packet) {
EaglerRPCFutureImpl<? extends IEaglerRPCResponse> future = waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireCompleteInternal(null);
}
}
public void handleServer(SPacketRPCResponseTypeBytes packet) {
EaglerRPCFutureImpl<ResponseBytes> future = (EaglerRPCFutureImpl<ResponseBytes>)waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireCompleteInternal(new ResponseBytes(EaglerXBukkitImpl.this, packet.requestID, packet.response));
}
}
public void handleServer(SPacketRPCResponseTypeString packet) {
EaglerRPCFutureImpl<ResponseString> future = (EaglerRPCFutureImpl<ResponseString>)waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireCompleteInternal(new ResponseString(EaglerXBukkitImpl.this, packet.requestID, packet.response));
}
}
public void handleServer(SPacketRPCResponseTypeUUID packet) {
EaglerRPCFutureImpl<ResponseUUID> future = (EaglerRPCFutureImpl<ResponseUUID>)waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireCompleteInternal(new ResponseUUID(EaglerXBukkitImpl.this, packet.requestID, packet.uuid));
}
}
public void handleServer(SPacketRPCResponseTypeCookie packet) {
EaglerRPCFutureImpl<ResponseCookie> future = (EaglerRPCFutureImpl<ResponseCookie>)waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireCompleteInternal(new ResponseCookie(EaglerXBukkitImpl.this, packet.requestID, packet.cookiesEnabled, packet.cookieData));
}
}
public void handleServer(SPacketRPCResponseTypeVoiceStatus packet) {
EaglerRPCFutureImpl<ResponseVoiceStatus> future = (EaglerRPCFutureImpl<ResponseVoiceStatus>)waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireCompleteInternal(new ResponseVoiceStatus(EaglerXBukkitImpl.this, packet.requestID, translateVoiceState2(packet.voiceState)));
}
}
public void handleServer(SPacketRPCResponseTypeWebViewStatus packet) {
EaglerRPCFutureImpl<ResponseWebViewStatus> future = (EaglerRPCFutureImpl<ResponseWebViewStatus>)waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireCompleteInternal(new ResponseWebViewStatus(EaglerXBukkitImpl.this, packet.requestID, translateWebViewState(packet.webviewState), packet.channelName));
}
}
public void handleServer(SPacketRPCResponseTypeError packet) {
EaglerRPCFutureImpl<ResponseWebViewStatus> future = (EaglerRPCFutureImpl<ResponseWebViewStatus>)waitingRequests.remove(packet.requestID);
if(future != null) {
future.fireExceptionInternal(new EaglerRPCResponseException(packet.errorMessage));
}
}
public void handleServer(SPacketRPCEventWebViewOpenClose packet) {
if((subscribedEvents & EnumSubscribeEvents.EVENT_WEBVIEW_OPEN_CLOSE.bit) != 0) {
fireEventHandlers(new EventWebViewOpenClose(packet.channelName, packet.channelOpen));
}
}
public void handleServer(SPacketRPCEventWebViewMessage packet) {
if((subscribedEvents & EnumSubscribeEvents.EVENT_WEBVIEW_MESSAGE.bit) != 0) {
EventWebViewMessage.MessageType mt;
switch(packet.messageType) {
case SPacketRPCEventWebViewMessage.MESSAGE_TYPE_STRING:
mt = EventWebViewMessage.MessageType.STRING;
break;
case SPacketRPCEventWebViewMessage.MESSAGE_TYPE_BINARY:
mt = EventWebViewMessage.MessageType.BINARY;
break;
default:
return;
}
fireEventHandlers(new EventWebViewMessage(packet.channelName, mt, packet.messageContent));
}
}
public void handleServer(SPacketRPCEventToggledVoice packet) {
if((subscribedEvents & EnumSubscribeEvents.EVENT_TOGGLE_VOICE.bit) != 0) {
EventToggledVoice.VoiceState vsOld = translateVoiceState(packet.oldVoiceState);
EventToggledVoice.VoiceState vsNew = translateVoiceState(packet.newVoiceState);
if(vsOld == null || vsNew == null) {
return;
}
fireEventHandlers(new EventToggledVoice(vsOld, vsNew));
}
}
}
private static EventToggledVoice.VoiceState translateVoiceState(int vs) {
switch(vs) {
case SPacketRPCResponseTypeVoiceStatus.VOICE_STATE_SERVER_DISABLE:
return EventToggledVoice.VoiceState.SERVER_DISABLE;
case SPacketRPCResponseTypeVoiceStatus.VOICE_STATE_DISABLED:
return EventToggledVoice.VoiceState.DISABLED;
case SPacketRPCResponseTypeVoiceStatus.VOICE_STATE_ENABLED:
return EventToggledVoice.VoiceState.ENABLED;
default:
return null;
}
}
private static ResponseVoiceStatus.VoiceState translateVoiceState2(int vs) {
switch(vs) {
case SPacketRPCEventToggledVoice.VOICE_STATE_SERVER_DISABLE:
default:
return ResponseVoiceStatus.VoiceState.SERVER_DISABLE;
case SPacketRPCEventToggledVoice.VOICE_STATE_DISABLED:
return ResponseVoiceStatus.VoiceState.DISABLED;
case SPacketRPCEventToggledVoice.VOICE_STATE_ENABLED:
return ResponseVoiceStatus.VoiceState.ENABLED;
}
}
private static ResponseWebViewStatus.WebViewState translateWebViewState(int vs) {
switch(vs) {
case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_NOT_SUPPORTED:
default:
return ResponseWebViewStatus.WebViewState.NOT_SUPPORTED;
case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_SERVER_DISABLE:
return ResponseWebViewStatus.WebViewState.SERVER_DISABLE;
case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_CHANNEL_CLOSED:
return ResponseWebViewStatus.WebViewState.CHANNEL_CLOSED;
case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_CHANNEL_OPEN:
return ResponseWebViewStatus.WebViewState.CHANNEL_OPEN;
}
}
@Override
public Player getPlayer() {
return playerObj;
}
@Override
public void sendRPCPacket(EaglerBackendRPCPacket packet) {
if(!open) {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + "] Sent " + packet.getClass().getSimpleName() + " on a dead connection!");
return;
}
if(packet == null) {
throw new NullPointerException("Packet cannot be null!");
}
byte[] ret;
int len = packet.length() + 1;
if(outputStreamLock.tryLock()) {
try {
reusableOutputStream.feedBuffer(new byte[len > 0 ? len : 64]);
try {
protocol.writePacket(dataOutputStream, EaglerBackendRPCProtocol.CLIENT_TO_SERVER, packet);
}catch(IOException ex) {
throw new EaglerRPCException("Failed to serialize packet: " + packet.getClass().getSimpleName(), ex);
}
ret = reusableOutputStream.returnBuffer();
}finally {
outputStreamLock.unlock();
}
}else {
ReusableByteArrayOutputStream bao = new ReusableByteArrayOutputStream();
bao.feedBuffer(new byte[len > 0 ? len : 64]);
try {
protocol.writePacket(new DataOutputStream(bao), EaglerBackendRPCProtocol.CLIENT_TO_SERVER, packet);
}catch(IOException ex) {
throw new EaglerRPCException("Failed to serialize packet: " + packet.getClass().getSimpleName(), ex);
}
ret = bao.returnBuffer();
}
if(len > 0 && len != ret.length) {
EaglerXBukkitAPIPlugin.logger()
.warning("[" + playerObj.getName() + "] Packet type " + packet.getClass().getSimpleName()
+ " was the wrong length after serialization: " + ret.length + " != " + len);
}
playerObj.sendPluginMessage(EaglerXBukkitAPIPlugin.getEagler(), EaglerBackendRPCProtocol.CHANNEL_NAME, ret);
}
protected EaglerBackendRPCPacket decodePacket(byte[] data) throws IOException {
EaglerBackendRPCPacket ret;
if(inputStreamLock.tryLock()) {
try {
reusableInputStream.feedBuffer(data);
ret = protocol.readPacket(dataInputStream, EaglerBackendRPCProtocol.SERVER_TO_CLIENT);
}finally {
inputStreamLock.unlock();
}
}else {
ReusableByteArrayInputStream bai = new ReusableByteArrayInputStream();
bai.feedBuffer(data);
ret = protocol.readPacket(new DataInputStream(bai), EaglerBackendRPCProtocol.SERVER_TO_CLIENT);
}
return ret;
}
@Override
public void subscribeEvents(int events) {
int newEvents = subscribedEvents | events;
if(newEvents != subscribedEvents) {
sendRPCPacket(new CPacketRPCSubscribeEvents(newEvents));
subscribedEvents = events;
}
}
@Override
public void unsubscribeEvents(int events) {
int newEvents = subscribedEvents & ~events;
if(newEvents != subscribedEvents) {
sendRPCPacket(new CPacketRPCSubscribeEvents(newEvents));
subscribedEvents = events;
}
}
@Override
public void unsubscribeAllEvents() {
if(subscribedEvents != 0) {
sendRPCPacket(new CPacketRPCSubscribeEvents(0));
subscribedEvents = 0;
}
}
@Override
public int getSubscribedEventsBits() {
return subscribedEvents;
}
@Override
public void addEventListener(EnumSubscribeEvents eventType,
IEaglerRPCEventHandler<? extends IEaglerRPCEvent> handler) {
synchronized(eventHandlers) {
eventHandlers.put(eventType, handler);
}
}
@Override
public void removeEventListener(EnumSubscribeEvents eventType,
IEaglerRPCEventHandler<? extends IEaglerRPCEvent> handler) {
synchronized(eventHandlers) {
eventHandlers.remove(eventType, handler);
}
}
@Override
public void removeEventListeners(EnumSubscribeEvents eventType) {
synchronized(eventHandlers) {
eventHandlers.removeAll(eventType);
}
}
@Override
public void addCloseListener(IEaglerRPCCloseHandler handler) {
synchronized(closeHandlers) {
closeHandlers.add(handler);
}
}
@Override
public void removeCloseListener(IEaglerRPCCloseHandler handler) {
synchronized(closeHandlers) {
closeHandlers.remove(handler);
}
}
@Override
public void removeCloseListeners() {
synchronized(closeHandlers) {
closeHandlers.clear();
}
}
@Override
public boolean redirectPlayerSupported() {
return gameProtocol >= 4;
}
@Override
public void redirectPlayerToWebSocket(String webSocketURI) {
if(gameProtocol >= 4) {
if(webSocketURI == null) {
throw new NullPointerException("URI cannot be null!");
}
sendRPCPacket(new CPacketRPCRedirectPlayer(webSocketURI));
}else {
EaglerXBukkitAPIPlugin.logger()
.warning("[" + playerObj.getName() + "] some plugin tried to redirect player to \"" + webSocketURI
+ "\" but that player's client does not support websocket redirects!");
}
}
@Override
public void setBaseRequestTimeout(int seconds) {
baseTimeout = seconds * 1000;
}
protected <T extends IEaglerRPCResponse> IEaglerRPCFuture<T> requestSendHelper(int type) {
EaglerRPCFutureImpl<T> ret = new EaglerRPCFutureImpl();
ret.setExpiresMSFromNow(baseTimeout);
int rqid = requestIDGenerator.incrementAndGet();
sendRPCPacket(new CPacketRPCRequestPlayerInfo(rqid, type));
waitingRequests.put(rqid, ret);
return ret;
}
@Override
public IEaglerRPCFuture<ResponseUUID> requestPlayerProfileUUID() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_REAL_UUID);
}
@Override
public IEaglerRPCFuture<ResponseString> requestPlayerRealIP() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_REAL_IP);
}
@Override
public IEaglerRPCFuture<ResponseString> requestPlayerOrigin() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_ORIGIN);
}
@Override
public IEaglerRPCFuture<ResponseString> requestPlayerUserAgent() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_USER_AGENT);
}
@Override
public IEaglerRPCFuture<ResponseBytes> requestPlayerSkinData() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_SKIN_DATA);
}
@Override
public IEaglerRPCFuture<ResponseBytes> requestPlayerCapeData() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CAPE_DATA);
}
@Override
public IEaglerRPCFuture<ResponseCookie> requestPlayerCookieData() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_COOKIE);
}
@Override
public IEaglerRPCFuture<ResponseString> requestPlayerClientBrandStr() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_BRAND_STR);
}
@Override
public IEaglerRPCFuture<ResponseString> requestPlayerClientVersionStr() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_VERSION_STR);
}
@Override
public IEaglerRPCFuture<ResponseString> requestPlayerClientBrandAndVersionStr() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_BRAND_VERSION_STR);
}
@Override
public IEaglerRPCFuture<ResponseUUID> requestPlayerClientBrandUUID() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_BRAND_UUID);
}
@Override
public IEaglerRPCFuture<ResponseVoiceStatus> requestPlayerVoiceStatus() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_VOICE_STATUS);
}
@Override
public IEaglerRPCFuture<ResponseWebViewStatus> requestPlayerWebViewStatus() {
return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_WEBVIEW_STATUS);
}
protected void cleanupTimedOutRequests(long now) {
if(!waitingRequests.isEmpty()) {
List<EaglerRPCFutureImpl<? extends IEaglerRPCResponse>> expired = null;
Iterator<EaglerRPCFutureImpl<? extends IEaglerRPCResponse>> itr = waitingRequests.values().iterator();
while(itr.hasNext()) {
EaglerRPCFutureImpl<? extends IEaglerRPCResponse> itm = itr.next();
if(itm.hasExpiredBetter(now)) {
if(expired == null) {
expired = new ArrayList<>(4);
}
expired.add(itm);
try {
itr.remove();
}catch(Throwable t) {
}
}
}
if(expired != null) {
for(int i = 0, l = expired.size(); i < l; ++i) {
try {
EaglerRPCFutureImpl<? extends IEaglerRPCResponse> itm = expired.get(i);
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + "] An RPC request timed out before it could be completed!");
itm.fireExceptionInternal(new EaglerRPCTimeoutException("The request was not completed in time!"));
}catch(Throwable t) {
EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + playerObj.getName() + "] An unhandled exception was thrown while firing request timeout signal!", t);
}
}
}
}
}
@Override
public void sendRawCustomPayloadPacket(String channel, byte[] data) {
sendRPCPacket(new CPacketRPCSendRawMessage(channel, data));
}
@Override
public boolean pauseMenuCustomizationSupported() {
return gameProtocol >= 4;
}
@Override
public void setPauseMenuCustomizationState(CPacketRPCSetPauseMenuCustom packet) {
if(gameProtocol >= 4) {
sendRPCPacket(packet);
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to configure pause menu customization, but the player's client does not support that feature!");
}
}
@Override
public void sendWebViewMessageString(String channelName, String data) {
if(gameProtocol >= 4) {
if(channelName == null) {
throw new NullPointerException("Channel cannot be null!");
}
if(data == null) {
throw new NullPointerException("Data cannot be null!");
}
sendRPCPacket(new CPacketRPCSendWebViewMessage(channelName,
CPacketRPCSendWebViewMessage.MESSAGE_TYPE_STRING, data.getBytes(StandardCharsets.UTF_8)));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to send a webview channel message, but the player's client does not support that feature!");
}
}
@Override
public void sendWebViewMessageBytes(String channelName, byte[] data) {
if(gameProtocol >= 4) {
if(channelName == null) {
throw new NullPointerException("Channel cannot be null!");
}
if(data == null) {
throw new NullPointerException("Data cannot be null!");
}
sendRPCPacket(new CPacketRPCSendWebViewMessage(channelName, CPacketRPCSendWebViewMessage.MESSAGE_TYPE_BINARY, data));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to send a webview channel message, but the player's client does not support that feature!");
}
}
@Override
public void forcePlayerSkin(byte[] skinData, boolean notifyOthers) {
if(skinData == null) {
throw new NullPointerException("Skin data cannot be null!");
}
if(skinData.length > 32720) {
throw new IllegalArgumentException("Skin data cannot be more than 32720 bytes!");
}
sendRPCPacket(new CPacketRPCSetPlayerSkin(notifyOthers, skinData));
}
@Override
public void forcePlayerCape(byte[] capeData, boolean notifyOthers) {
if(capeData == null) {
throw new NullPointerException("Cape data cannot be null!");
}
if(capeData.length > 32720) {
throw new IllegalArgumentException("Cape data cannot be more than 32720 bytes!");
}
sendRPCPacket(new CPacketRPCSetPlayerCape(notifyOthers, capeData));
}
@Override
public void setCookieData(byte[] cookieData, int expiresAfterSec, boolean revokeQuerySupported,
boolean saveToDisk) {
if(gameProtocol >= 4) {
sendRPCPacket(new CPacketRPCSetPlayerCookie(revokeQuerySupported, saveToDisk, expiresAfterSec, cookieData));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to set a cookie, but the player's client does not support that feature!");
}
}
@Override
public void setFNAWSkinsEnabled(boolean enabled, boolean force) {
sendRPCPacket(new CPacketRPCSetPlayerFNAWEn(enabled, force));
}
@Override
public void setFNAWSkinsEnabled(boolean enabled) {
sendRPCPacket(new CPacketRPCSetPlayerFNAWEn(enabled, false));
}
@Override
public void resetForcedMulti(boolean resetSkin, boolean resetCape, boolean resetFNAWForce, boolean notifyOtherPlayers) {
sendRPCPacket(new CPacketRPCResetPlayerMulti(resetSkin, resetCape, resetFNAWForce, notifyOtherPlayers));
}
@Override
public void resetForcedSkin(boolean notifyOtherPlayers) {
sendRPCPacket(new CPacketRPCResetPlayerMulti(true, false, false, notifyOtherPlayers));
}
@Override
public void resetForcedCape(boolean notifyOtherPlayers) {
sendRPCPacket(new CPacketRPCResetPlayerMulti(false, true, false, notifyOtherPlayers));
}
@Override
public void resetForcedFNAW() {
sendRPCPacket(new CPacketRPCResetPlayerMulti(false, false, true, false));
}
@Override
public boolean notifSupported() {
return gameProtocol >= 4;
}
@Override
public void notifIconRegister(Map<UUID, PacketImageData> iconsToRegister) {
if(gameProtocol >= 4) {
sendRPCPacket(new CPacketRPCNotifIconRegister(iconsToRegister));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to register notification icons, but the player's client does not support that feature!");
}
}
@Override
public void notifIconRegister(UUID iconUUID, PacketImageData imageData) {
if(gameProtocol >= 4) {
Map<UUID, PacketImageData> toReg = new HashMap<>(1);
toReg.put(iconUUID, imageData);
sendRPCPacket(new CPacketRPCNotifIconRegister(toReg));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to register notification icons, but the player's client does not support that feature!");
}
}
@Override
public void notifIconRelease(Collection<UUID> iconsToRelease) {
if(gameProtocol >= 4) {
sendRPCPacket(new CPacketRPCNotifIconRelease(iconsToRelease));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to release notification icons, but the player's client does not support that feature!");
}
}
@Override
public void notifIconRelease(UUID iconUUID) {
if(gameProtocol >= 4) {
sendRPCPacket(new CPacketRPCNotifIconRelease(Arrays.asList(iconUUID)));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to release notification icons, but the player's client does not support that feature!");
}
}
@Override
public void notifBadgeShow(CPacketRPCNotifBadgeShow packet) {
if(gameProtocol >= 4) {
sendRPCPacket(packet);
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to show notification badge, but the player's client does not support that feature!");
}
}
@Override
public void notifBadgeHide(UUID badgeUUID) {
if(gameProtocol >= 4) {
sendRPCPacket(new CPacketRPCNotifBadgeHide(badgeUUID));
}else {
EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName()
+ "] some plugin tried to hide notification badge, but the player's client does not support that feature!");
}
}
@Override
public <T> void setMeta(String key, T value) {
if(key == null) {
throw new NullPointerException("Key cannot be null!");
}
metadata.put(key, value);
}
@Override
public <T> T getMeta(String key) {
if(key == null) {
throw new NullPointerException("Key cannot be null!");
}
return (T)metadata.get(key);
}
}

View File

@ -0,0 +1,41 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCEnabled;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class HelloPacketFactory {
public static final byte[] BASE_HELLO_PACKET;
static {
try {
ByteArrayOutputStream bao = new ByteArrayOutputStream();
DataOutputStream dao = new DataOutputStream(bao);
CPacketRPCEnabled pkt = new CPacketRPCEnabled(new int[] { EaglerBackendRPCProtocol.V1.vers });
EaglerBackendRPCProtocol.INIT.writePacket(dao, EaglerBackendRPCProtocol.CLIENT_TO_SERVER, pkt);
BASE_HELLO_PACKET = bao.toByteArray();
}catch(IOException ex) {
throw new RuntimeException(ex);
}
}
}

View File

@ -0,0 +1,196 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import org.bukkit.metadata.LazyMetadataValue;
import org.bukkit.metadata.MetadataValue;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.SPacketRPCEnabledFailure;
import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.SPacketRPCEnabledSuccess;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.EaglerXBukkitAPIPlugin;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCInitException;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI;
import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.EaglerRPCTimeoutException;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class PlayerDataObj {
public static final String METADATA_BASE = "EXRPC_PDataObj";
public final Player player;
public volatile boolean hasRecievedReady = false;
public volatile boolean isSupported = true;
public volatile EaglerXBukkitImpl currentAPI = null;
public volatile EaglerRPCFutureImpl<IEaglerXBukkitAPI> openFuture = null;
public static PlayerDataObj getForPlayer(Player player) {
List<MetadataValue> vigg = player.getMetadata(METADATA_BASE);
return !vigg.isEmpty() ? (PlayerDataObj)vigg.get(0).value() : null;
}
public static void setupPlayer(Player player) {
player.setMetadata(METADATA_BASE, new LazyMetadataValue(EaglerXBukkitAPIPlugin.getEagler(), () -> new PlayerDataObj(player)));
}
protected PlayerDataObj(Player player) {
this.player = player;
}
public void firePluginReadyMsgRecieved() {
synchronized(this) {
if(!hasRecievedReady) {
hasRecievedReady = true;
if(openFuture != null) {
EaglerXBukkitImpl.sendHelloPacket(player);
}
}
}
}
public void firePluginMsgRecievedInternal(byte[] data) {
EaglerXBukkitImpl apiObj = null;
synchronized(this) {
if(openFuture != null) {
try {
handleOpenResult(openFuture, data);
}finally {
openFuture = null;
}
}else if(currentAPI != null) {
apiObj = currentAPI;
}
}
if(apiObj != null) {
handleAPIMessage(apiObj, data);
}
}
public void firePlayerQuitEventInternal() {
synchronized(this) {
if(openFuture != null) {
try {
openFuture.fireExceptionInternal(new EaglerRPCException("Player quit before the connection could be established!"));
}finally {
openFuture = null;
}
}else if(currentAPI != null) {
currentAPI.fireAPIClosedEventInternal();
}
}
}
private void handleOpenResult(EaglerRPCFutureImpl<IEaglerXBukkitAPI> apiFuture, byte[] data) {
EaglerBackendRPCPacket ret;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
ret = EaglerBackendRPCProtocol.INIT.readPacket(new DataInputStream(bis), EaglerBackendRPCProtocol.SERVER_TO_CLIENT);
if(bis.available() > 0) {
throw new IOException("There were " + bis.available() + " bytes available after reading packet \"" + ret.getClass().getSimpleName() + "\"!");
}
}catch(IOException ex) {
EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + player.getName() + "] Could not parse incoming RPC packet from bungee/velocity server! (protocol: INIT)", ex);
apiFuture.fireExceptionInternal(ex);
return;
}
if(ret instanceof SPacketRPCEnabledSuccess) {
SPacketRPCEnabledSuccess pkt = (SPacketRPCEnabledSuccess)ret;
if(pkt.selectedRPCProtocol != EaglerBackendRPCProtocol.V1.vers) {
try {
// send raw CPacketRPCDisabled
player.sendPluginMessage(EaglerXBukkitAPIPlugin.getEagler(), EaglerBackendRPCProtocol.CHANNEL_NAME, new byte[] { 0x03 });
}finally {
apiFuture.fireExceptionInternal(new EaglerRPCException("Server tried to select an unsupported protocol: " + pkt.selectedRPCProtocol));
}
}else {
currentAPI = EaglerXBukkitImpl.createFromHandshakeInternal(this, pkt);
apiFuture.fireCompleteInternal(currentAPI);
}
}else if(ret instanceof SPacketRPCEnabledFailure) {
SPacketRPCEnabledFailure pkt = (SPacketRPCEnabledFailure)ret;
String msg = "Server responded with failure code: ";
switch(pkt.failureCode) {
case SPacketRPCEnabledFailure.FAILURE_CODE_NOT_ENABLED:
msg += "FAILURE_CODE_NOT_ENABLED";
break;
case SPacketRPCEnabledFailure.FAILURE_CODE_NOT_EAGLER_PLAYER:
msg += "FAILURE_CODE_NOT_EAGLER_PLAYER";
break;
case SPacketRPCEnabledFailure.FAILURE_CODE_OUTDATED_SERVER:
msg += "FAILURE_CODE_OUTDATED_SERVER";
break;
case SPacketRPCEnabledFailure.FAILURE_CODE_OUTDATED_CLIENT:
msg += "FAILURE_CODE_OUTDATED_CLIENT";
break;
case SPacketRPCEnabledFailure.FAILURE_CODE_INTERNAL_ERROR:
msg += "FAILURE_CODE_INTERNAL_ERROR";
break;
default:
msg += pkt.failureCode;
break;
}
apiFuture.fireExceptionInternal(new EaglerRPCInitException(pkt.failureCode, msg));
}else {
EaglerXBukkitAPIPlugin.logger().severe("[" + player.getName() + "] Unknown response type from bungee/velocity to API open request: " + ret.getClass().getSimpleName());
}
}
private void handleAPIMessage(EaglerXBukkitImpl apiObj, byte[] data) {
EaglerBackendRPCPacket ret;
try {
ret = apiObj.decodePacket(data);
}catch(IOException ex) {
EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + player.getName() + "] Could not parse incoming RPC packet from bungee/velocity server! (protocol: " + apiObj.getRPCProtocolVersion() + ")", ex);
return;
}
apiObj.fireAPIPacketRecievedInternal(ret);
}
public void fireCheckRequestTimeoutsInternal(long now) {
EaglerXBukkitImpl apiObj;
synchronized(this) {
if(openFuture != null) {
if(openFuture.hasExpiredBetter(now)) {
try {
EaglerXBukkitAPIPlugin.logger().warning("[" + player.getName() + "] An RPC open request timed out before it could be completed!");
openFuture.fireExceptionInternal(new EaglerRPCTimeoutException("The request was not completed in time!"));
}catch(Throwable t) {
EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + player.getName() + "] An unhandled exception was thrown while firing request timeout signal!", t);
}finally {
openFuture = null;
}
}
return;
}else {
apiObj = currentAPI;
}
}
if(apiObj != null) {
apiObj.cleanupTimedOutRequests(now);
}
}
}

View File

@ -0,0 +1,80 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl;
import java.io.IOException;
import java.io.InputStream;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ReusableByteArrayInputStream extends InputStream {
private volatile byte[] currentBuffer = null;
private int idx = 0;
private int markIDX = 0;
public void feedBuffer(byte[] b) {
currentBuffer = b;
idx = 0;
markIDX = 0;
}
@Override
public int read() throws IOException {
if(currentBuffer.length <= idx) throw new IOException("ReusableByteArrayInputStream buffer underflow, no bytes remaining");
return (int)currentBuffer[idx++] & 0xFF;
}
@Override
public int read(byte b[], int off, int len) throws IOException {
if(idx + len > currentBuffer.length) {
throw new IOException(
"ReusableByteArrayInputStream buffer underflow, tried to read " + len + " when there are only "
+ (currentBuffer.length - idx) + " bytes remaining",
new ArrayIndexOutOfBoundsException(idx + len - 1));
}
if(off + len > b.length) {
throw new ArrayIndexOutOfBoundsException(off + len - 1);
}
System.arraycopy(currentBuffer, idx, b, off, len);
idx += len;
return len;
}
public void mark() {
markIDX = idx;
}
public void reset() {
idx = markIDX;
}
public int getReaderIndex() {
return idx;
}
public int available() {
return Math.max(currentBuffer.length - idx, 0);
}
public void setReaderIndex(int i) {
idx = i;
markIDX = idx;
}
public boolean markSupported() {
return true;
}
}

View File

@ -0,0 +1,81 @@
package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class ReusableByteArrayOutputStream extends OutputStream {
private volatile byte[] currentBuffer = null;
private int idx = 0;
private int originalSize = 0;
public void feedBuffer(byte[] buf) {
currentBuffer = buf;
idx = 0;
originalSize = buf == null ? 0 : buf.length;
}
public boolean hasGrown() {
return currentBuffer.length != originalSize;
}
public byte[] returnBuffer() {
return currentBuffer.length == idx ? currentBuffer : Arrays.copyOf(currentBuffer, idx);
}
private void growBuffer(int i) {
int ii = currentBuffer.length;
int iii = i - ii;
if(iii > 0) {
int j = ii + (ii >> 1);
while(j < i) {
j += (j >> 1);
}
byte[] n = new byte[j];
System.arraycopy(currentBuffer, 0, n, 0, ii);
currentBuffer = n;
}
}
public int getWriterIndex() {
return idx;
}
public void setWriterIndex(int i) {
idx = i;
}
@Override
public void write(int b) throws IOException {
if(idx >= currentBuffer.length) {
growBuffer(idx + 1);
}
currentBuffer[idx++] = (byte) b;
}
@Override
public void write(byte b[], int off, int len) throws IOException {
if(idx + len > currentBuffer.length) {
growBuffer(idx + len);
}
System.arraycopy(b, off, currentBuffer, idx, len);
idx += len;
}
}

View File

@ -0,0 +1,6 @@
name: EaglercraftXBukkitAPI
version: 1.0.0
main: net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.EaglerXBukkitAPIPlugin
description: Official EaglercraftX API for Bukkit servers
author: lax1dude
api-version: 1.8