4 Commits
1.4.5 ... 1.5.0

Author SHA1 Message Date
9ac54fa915 feat: 新增 Velocity 支持
All checks were successful
Publish Project / build (push) Successful in 2m31s
2025-08-06 01:45:27 +08:00
7582653d54 feat: 新增 Velocity 支持 2025-08-06 01:42:35 +08:00
c496aaeb98 docs: 更改描述 2024-03-19 15:45:59 +08:00
204d0ab47f docs: 更改插件描述 2024-03-19 15:34:46 +08:00
19 changed files with 939 additions and 21 deletions

View File

@@ -0,0 +1,28 @@
name: Publish Project
on:
push:
tags:
- "*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: 21
distribution: temurin
cache: gradle
cache-dependency-path: gradle/wrapper/gradle-wrapper.properties
- name: Build Project
env:
ORG_GRADLE_PROJECT_MAVEN_AIRGAME_TOKEN: ${{ secrets.MAVEN_AIRGAME_TOKEN }}
run: chmod +x gradlew && ./gradlew build
- name: Publish to Release
uses: softprops/action-gh-release@v2
with:
files: build/*.jar

View File

@@ -5,12 +5,11 @@ plugins {
}
group = "cn.hamster3.mc.plugin"
version = "1.4.5"
version = "1.5.0"
description = "将 HamsterBall 转换成 HamsterService 兼容的 API"
repositories {
maven {
url = uri("https://maven.airgame.net/maven-public/")
}
maven("https://maven.airgame.net/maven-public/")
}
dependencies {
@@ -19,13 +18,31 @@ dependencies {
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("net.md-5:bungeecord-api:1.20-R0.1-SNAPSHOT")
compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
compileOnly("cn.hamster3.mc.plugin:core-bukkit:+")
compileOnly("cn.hamster3.mc.plugin:ball-bukkit:+")
compileOnly("me.clip:placeholderapi:2.11.2")
compileOnly("me.clip:placeholderapi:2.11.6")
}
sourceSets.create("templates") {
java {
srcDir("src/main/templates")
}
}
val templateSource = file("src/main/templates")
val templateDest = layout.buildDirectory.dir("generated/sources/templates")
val generateTemplates = tasks.register<Copy>("generateTemplates") {
from(templateSource)
into(templateDest)
expand(project.properties)
}
sourceSets.main.get().java.srcDir(generateTemplates.map { it.outputs })
tasks {
withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
@@ -35,8 +52,6 @@ tasks {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
}
jar {
@@ -44,9 +59,9 @@ tasks {
destinationDirectory = rootProject.layout.buildDirectory
}
processResources {
filesMatching("plugin.yml") {
filesMatching(listOf("plugin.yml", "bungee.yml", "update.yml")) {
expand(project.properties)
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
}

View File

@@ -1,6 +1,6 @@
#Mon Mar 11 19:25:59 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -250,7 +250,9 @@ public abstract class ServiceMessageAPI {
}
public static void kickPlayer(UUID uuid, String reason) {
kickPlayer(uuid, new JsonPrimitive(reason));
JsonObject object = new JsonObject();
object.addProperty("text", reason);
kickPlayer(uuid, object);
}
public static void kickPlayer(UUID uuid, JsonElement reason) {

View File

@@ -124,7 +124,9 @@ public abstract class ServiceMessageAPI {
* @param message 消息
*/
public static void sendPlayerMessage(UUID uuid, String message) {
sendPlayerMessage(uuid, new JsonPrimitive(message));
JsonObject object = new JsonObject();
object.addProperty("text", message);
sendPlayerMessage(uuid, object);
}
/**
@@ -223,7 +225,9 @@ public abstract class ServiceMessageAPI {
}
public static void kickPlayer(UUID uuid, String reason) {
kickPlayer(uuid, new JsonPrimitive(reason));
JsonObject object = new JsonObject();
object.addProperty("text", reason);
kickPlayer(uuid, object);
}
public static void kickPlayer(UUID uuid, JsonElement reason) {

View File

@@ -1,6 +1,5 @@
package cn.hamster3.service.bungee.event;
import net.md_5.bungee.api.plugin.Event;
/**
@@ -22,7 +21,6 @@ public class ServiceConnectEvent extends Event {
this.cause = cause;
}
/**
* 是否成功连接到服务中心
*

View File

@@ -0,0 +1,50 @@
package cn.hamster3.service.velocity;
import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
import cn.hamster3.service.common.util.ServiceLogUtils;
import cn.hamster3.service.velocity.listener.BridgeListener;
import cn.hamster3.service.velocity.listener.ServiceMainListener;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Dependency;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import java.util.logging.Logger;
@Plugin(
id = "hamster-service",
name = "HamsterService",
version = BuildConstants.VERSION,
description = BuildConstants.DESCRIPTION,
authors = {"MiniDay"},
dependencies = @Dependency(id = "hamster-ball")
)
public class BallBridgePlugin {
private static BallBridgePlugin instance;
private final ProxyServer proxyServer;
@Inject
public BallBridgePlugin(ProxyServer proxyServer) {
this.proxyServer = proxyServer;
instance = this;
ServiceLogUtils.setLogger(Logger.getLogger("HamsterService"));
}
public static BallBridgePlugin getInstance() {
return instance;
}
public ProxyServer getProxyServer() {
return proxyServer;
}
@Subscribe(priority = 0)
public void onProxyInitialization(ProxyInitializeEvent event) {
BallAPI.getInstance().subscribeRaw("HamsterService");
BallAPI.getInstance().getEventBus().register(BridgeListener.INSTANCE);
proxyServer.getEventManager().register(this, ServiceMainListener.INSTANCE);
}
}

View File

@@ -0,0 +1,141 @@
package cn.hamster3.service.velocity.api;
import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo;
import cn.hamster3.mc.plugin.ball.common.entity.BallServerInfo;
import cn.hamster3.mc.plugin.ball.common.entity.BallServerType;
import cn.hamster3.service.common.data.ServicePlayerInfo;
import cn.hamster3.service.common.entity.ServiceSenderInfo;
import cn.hamster3.service.common.entity.ServiceSenderType;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.UUID;
import java.util.stream.Collectors;
@SuppressWarnings("unused")
public class ServiceInfoAPI {
/**
* 获取玩家信息,当玩家不在线时返回 null
*
* @param uuid 玩家的UUID
* @return 玩家信息
*/
public static ServicePlayerInfo getPlayerInfo(@NotNull UUID uuid) {
return transfer(BallAPI.getInstance().getPlayerInfo(uuid));
}
/**
* 获取玩家信息,当玩家不在线时返回 null
*
* @param playerName 玩家ID
* @return 玩家信息
*/
public static ServicePlayerInfo getPlayerInfo(@NotNull String playerName) {
return transfer(BallAPI.getInstance().getPlayerInfo(playerName));
}
/**
* 获取全部在线玩家的信息
*
* @return 玩家们的信息
*/
public static HashSet<ServicePlayerInfo> getOnlinePlayers() {
return BallAPI.getInstance().getAllPlayerInfo().values()
.stream()
.filter(BallPlayerInfo::isOnline)
.map(ServiceInfoAPI::transfer)
.collect(Collectors.toCollection(HashSet::new));
}
/**
* 获取全部在线玩家的信息
*
* @return 玩家们的信息
*/
public static HashSet<ServicePlayerInfo> getAllPlayerInfo() {
return BallAPI.getInstance().getAllPlayerInfo().values()
.stream()
.map(ServiceInfoAPI::transfer)
.collect(Collectors.toCollection(HashSet::new));
}
/**
* 获取服务端信息
*
* @param senderName 服务端id
* @return 服务端信息
*/
public static ServiceSenderInfo getSenderInfo(String senderName) {
return transfer(BallAPI.getInstance().getServerInfo(senderName));
}
/**
* 获取所有连接至服务中心的信息
*
* @return 服务器信息
*/
public static HashSet<ServiceSenderInfo> getAllSenderInfo() {
return BallAPI.getInstance().getAllServerInfo().values()
.stream()
.map(ServiceInfoAPI::transfer)
.collect(Collectors.toCollection(HashSet::new));
}
/**
* 获取当前服务器的名称
*
* @return 服务器id
*/
public static String getLocalServerName() {
return BallAPI.getInstance().getLocalServerId();
}
/**
* 获取当前服务器的别名
*
* @return 服务器别名
*/
public static String getLocalServerNickName() {
return BallAPI.getInstance().getLocalServerInfo().getName();
}
/**
* 获取当前服务器的SenderInfo对象
*
* @return 当前服务器的发送者信息
*/
public static ServiceSenderInfo getLocalSenderInfo() {
return new ServiceSenderInfo(
ServiceSenderType.PROXY,
BallAPI.getInstance().getLocalServerInfo().getId(),
BallAPI.getInstance().getLocalServerInfo().getName()
);
}
public static ServiceSenderInfo transfer(BallServerInfo info) {
if (info == null) {
return null;
}
return new ServiceSenderInfo(
info.getType() == BallServerType.PROXY ? ServiceSenderType.PROXY : ServiceSenderType.BUKKIT,
info.getId(),
info.getName()
);
}
public static ServicePlayerInfo transfer(BallPlayerInfo info) {
if (info == null) {
return null;
}
return new ServicePlayerInfo(
info.getUuid(),
info.getName(),
info.getGameServer(),
info.getProxyServer(),
info.isOnline()
);
}
}

View File

@@ -0,0 +1,333 @@
package cn.hamster3.service.velocity.api;
import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
import cn.hamster3.mc.plugin.ball.common.data.BallMessage;
import cn.hamster3.service.common.data.ServiceLocation;
import cn.hamster3.service.common.data.ServicePlayerInfo;
import cn.hamster3.service.common.entity.ServiceMessageInfo;
import cn.hamster3.service.velocity.BallBridgePlugin;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import java.util.UUID;
@SuppressWarnings("unused")
public abstract class ServiceMessageAPI {
/**
* 订阅某个标签的消息
*
* @param tag 标签
*/
public static void subscribeTag(String tag) {
sendServiceMessage("HamsterService", "subscribeTag", tag);
}
/**
* 取消订阅某个标签的消息
*
* @param tag 标签
*/
public static void unsubscribeTag(String tag) {
sendServiceMessage("HamsterService", "unsubscribeTag", tag);
}
/**
* 发送一条服务消息
*
* @param tag 消息标签
* @param action 执行动作
*/
public static void sendServiceMessage(String tag, String action) {
BallAPI.getInstance().sendRawBallMessage(tag, action);
}
/**
* 发送一条有附加参数的服务消息
*
* @param tag 消息标签
* @param action 执行动作
* @param content 附加参数
*/
public static void sendServiceMessage(String tag, String action, String content) {
BallAPI.getInstance().sendRawBallMessage(tag, action, content);
}
/**
* 发送一条有附加参数的服务消息,使用 String.format() 替换附加参数
*
* @param tag 消息标签
* @param action 执行动作
* @param content 附加参数
* @param args 替换参数
* @see String#format(String, Object...)
*/
public static void sendServiceMessage(String tag, String action, String content, Object... args) {
BallAPI.getInstance().sendRawBallMessage(tag, action, new JsonPrimitive(String.format(content, args)));
}
/**
* 发送一条有附加参数的消息
*
* @param tag 消息标签
* @param action 执行动作
* @param content 附加参数
*/
public static void sendServiceMessage(String tag, String action, JsonElement content) {
BallAPI.getInstance().sendBallMessage(tag, new BallMessage(action, content), false, false);
}
/**
* 自定义服务消息信息并发送
*
* @param info 消息内容
* @param block 是否阻塞(即必须等待消息发送完成,该方法才会返回)
*/
public static void sendServiceMessage(ServiceMessageInfo info, boolean block) {
BallMessage message = new BallMessage(
info.getSenderInfo().getName(),
info.getToServer(),
null,
info.getAction(),
info.getContent()
);
BallAPI.getInstance().sendBallMessage(info.getTag(), message, false, block);
}
/**
* 强制玩家执行一个 bukkit 命令
*
* @param uuid 玩家的uuid
* @param command 命令内容
*/
public static void dispatchBukkitCommand(UUID uuid, String command) {
sendServiceMessage("HamsterService", "dispatchBukkitCommand", command);
}
/**
* 强制玩家执行一个代理端指BungeeCord等命令
*
* @param uuid 玩家的uuid
* @param command 命令内容
*/
public static void dispatchProxyCommand(UUID uuid, String command) {
sendServiceMessage("HamsterService", "dispatchProxyCommand", command);
}
/**
* 给玩家发送一条消息
*
* @param uuid 玩家
* @param message 消息
*/
public static void sendPlayerMessage(UUID uuid, String message) {
JsonObject object = new JsonObject();
object.addProperty("text", message);
sendPlayerMessage(uuid, object);
}
/**
* 给玩家发送一条消息
*
* @param uuid 玩家
* @param message 消息
*/
public static void sendPlayerMessage(UUID uuid, JsonElement message) {
Player player = BallBridgePlugin.getInstance().getProxyServer().getPlayer(uuid).orElse(null);
if (player != null) {
player.sendMessage(GsonComponentSerializer.gson().deserializeFromTree(message));
return;
}
JsonObject object = new JsonObject();
object.addProperty("uuid", uuid.toString());
object.add("message", message);
sendServiceMessage("HamsterService", "sendPlayerMessage", object);
}
/**
* 给服务器的在线玩家广播一条消息
*
* @param message 消息
* @since 2.1.0
*/
public static void broadcastMessage(String message) {
JsonObject object = new JsonObject();
object.addProperty("text", message);
broadcastMessage(object);
}
/**
* 给服务器的在线玩家广播一条消息
*
* @param message 消息
* @since 2.1.0
*/
public static void broadcastMessage(JsonElement message) {
sendServiceMessage("HamsterService", "broadcastMessage", message);
}
/**
* 把玩家传送到另一个玩家身边
* <p>
* 支持跨服传送
*
* @param sendPlayer 被传送的玩家
* @param toPlayer 传送的目标玩家
* @since 2.1.0
*/
public static void sendPlayerToPlayer(UUID sendPlayer, UUID toPlayer) {
ServicePlayerInfo sendPlayerInfo = ServiceInfoAPI.getPlayerInfo(sendPlayer);
// 如果被传送玩家不在线
if (sendPlayerInfo == null || !sendPlayerInfo.isOnline()) {
return;
}
ServicePlayerInfo toPlayerInfo = ServiceInfoAPI.getPlayerInfo(toPlayer);
// 如果目标玩家不在线
if (toPlayerInfo == null || !toPlayerInfo.isOnline()) {
return;
}
JsonObject object = new JsonObject();
object.addProperty("sendPlayer", sendPlayer.toString());
object.addProperty("toPlayer", toPlayer.toString());
sendServiceMessage("HamsterService", "sendPlayerToPlayer", object);
}
/**
* 把玩家传送到一个位置
* <p>
* 支持跨服传送
*
* @param uuid 玩家的uuid
* @param location 坐标
* @since 2.1.0
*/
public static void sendPlayerToLocation(UUID uuid, ServiceLocation location) {
ServicePlayerInfo playerInfo = ServiceInfoAPI.getPlayerInfo(uuid);
// 如果玩家不在线
if (playerInfo == null || !playerInfo.isOnline()) {
return;
}
// 如果目标服务器不在线
if (ServiceInfoAPI.getSenderInfo(location.getServerName()) == null) {
return;
}
JsonObject object = new JsonObject();
object.addProperty("uuid", uuid.toString());
object.add("location", location.saveToJson());
sendServiceMessage("HamsterService", "sendPlayerToLocation", object);
}
public static void kickPlayer(UUID uuid, String reason) {
JsonObject object = new JsonObject();
object.addProperty("text", reason);
kickPlayer(uuid, object);
}
public static void kickPlayer(UUID uuid, JsonElement reason) {
Player player = BallBridgePlugin.getInstance().getProxyServer().getPlayer(uuid).orElse(null);
if (player != null) {
player.disconnect(GsonComponentSerializer.gson().deserializeFromTree(reason));
return;
}
JsonObject object = new JsonObject();
object.addProperty("uuid", uuid.toString());
object.add("reason", reason);
sendServiceMessage("HamsterService", "kickPlayer", object);
}
/**
* 开启/关闭 安全模式
* <p>
* 在安全模式开启时玩家将无法连接至服务器
* <p>
* 且根据 config 的配置不同,有可能会踢出全部在线玩家
*
* @param enable 是否启用
*/
public static void setSafeMode(boolean enable) {
sendServiceMessage("HamsterService", "setSafeMode", new JsonPrimitive(enable));
}
/**
* 发送一条服务消息
*
* @param tag 消息标签
* @param action 执行动作
* @deprecated 你应该使用 sendServiceMessage
* <p>
* 因为这个方法名有歧义
*/
@Deprecated
public static void sendMessage(String tag, String action) {
sendServiceMessage(tag, action);
}
/**
* 发送一条有附加参数的服务消息
*
* @param tag 消息标签
* @param action 执行动作
* @param content 附加参数
* @deprecated 你应该使用 sendServiceMessage
* <p>
* 因为这个方法名有歧义
*/
@Deprecated
public static void sendMessage(String tag, String action, String content) {
sendServiceMessage(tag, action, content);
}
/**
* 发送一条有附加参数的服务消息,使用 String.format() 替换附加参数
*
* @param tag 消息标签
* @param action 执行动作
* @param content 附加参数
* @param args 替换参数
* @see String#format(String, Object...)
* @deprecated 你应该使用 sendServiceMessage
* <p>
* 因为这个方法名有歧义
*/
@Deprecated
public static void sendMessage(String tag, String action, String content, Object... args) {
sendServiceMessage(tag, action, content, args);
}
/**
* 发送一条有附加参数的服务消息
*
* @param tag 消息标签
* @param action 执行动作
* @param content 附加参数
* @deprecated 你应该使用 sendServiceMessage
* <p>
* 因为这个方法名有歧义
*/
@Deprecated
public static void sendMessage(String tag, String action, JsonElement content) {
sendServiceMessage(tag, action, content);
}
/**
* 自定义服务消息信息并发送
*
* @param info 消息内容
* @param block 是否阻塞(即必须等待消息发送完成,该方法才会返回)
* @deprecated 你应该使用 sendServiceMessage
* <p>
* 因为这个方法名有歧义
*/
@Deprecated
public static void sendMessage(ServiceMessageInfo info, boolean block) {
sendServiceMessage(info, block);
}
}

View File

@@ -0,0 +1,20 @@
package cn.hamster3.service.velocity.event;
import cn.hamster3.service.common.entity.ServiceMessageInfo;
/**
* 服务消息事件的基类
*/
@SuppressWarnings("unused")
public class MessageEvent {
private final ServiceMessageInfo messageInfo;
public MessageEvent(ServiceMessageInfo messageInfo) {
this.messageInfo = messageInfo;
}
public ServiceMessageInfo getMessageInfo() {
return messageInfo;
}
}

View File

@@ -0,0 +1,14 @@
package cn.hamster3.service.velocity.event;
import cn.hamster3.service.common.entity.ServiceMessageInfo;
/**
* 从服务中心收到消息时产生的事件
*/
@SuppressWarnings("unused")
public class MessageReceivedEvent extends MessageEvent {
public MessageReceivedEvent(ServiceMessageInfo info) {
super(info);
}
}

View File

@@ -0,0 +1,44 @@
package cn.hamster3.service.velocity.event;
import cn.hamster3.service.common.entity.ServiceMessageInfo;
/**
* 消息发送出去之后产生的事件
*/
@SuppressWarnings("unused")
public class MessageSentEvent extends MessageEvent {
private final boolean success;
private final Throwable cause;
public MessageSentEvent(ServiceMessageInfo info) {
super(info);
success = true;
cause = null;
}
public MessageSentEvent(ServiceMessageInfo messageInfo, Throwable cause) {
super(messageInfo);
success = false;
this.cause = cause;
}
/**
* 消息是否成功发送出去了
*
* @return true代表成功发送
*/
public boolean isSuccess() {
return success;
}
/**
* 若消息发送失败,则失败原因为何
* 若发送成功则返回null
*
* @return 失败原因
*/
public Throwable getCause() {
return cause;
}
}

View File

@@ -0,0 +1,41 @@
package cn.hamster3.service.velocity.event;
/**
* 服务连接事件
*/
@SuppressWarnings("unused")
public class ServiceConnectEvent {
private final boolean success;
private final Throwable cause;
public ServiceConnectEvent() {
success = true;
cause = null;
}
public ServiceConnectEvent(Throwable cause) {
success = false;
this.cause = cause;
}
/**
* 是否成功连接到服务中心
*
* @return true代表成功
*/
public boolean isSuccess() {
return success;
}
/**
* 如果连接失败了,则返回失败原因
* <p>
* 如果连接成功了则返回null
*
* @return 失败原因
*/
public Throwable getCause() {
return cause;
}
}

View File

@@ -0,0 +1,45 @@
package cn.hamster3.service.velocity.listener;
import cn.hamster3.service.common.entity.ServiceMessageInfo;
import cn.hamster3.service.velocity.BallBridgePlugin;
import cn.hamster3.service.velocity.api.ServiceInfoAPI;
import cn.hamster3.service.velocity.event.MessageReceivedEvent;
import cn.hamster3.service.velocity.event.MessageSentEvent;
import com.google.common.eventbus.Subscribe;
public class BridgeListener {
public static final BridgeListener INSTANCE = new BridgeListener();
private BridgeListener() {
}
@Subscribe
public void onMessageSent(cn.hamster3.mc.plugin.ball.common.event.message.MessageSentEvent event) {
BallBridgePlugin.getInstance().getProxyServer().getEventManager().fireAndForget(
new MessageSentEvent(
new ServiceMessageInfo(
ServiceInfoAPI.getSenderInfo(event.getSenderID()),
event.getReceiverID(),
event.getChannel(),
event.getAction(),
event.getContent()
)
)
);
}
@Subscribe
public void onMessageReceived(cn.hamster3.mc.plugin.ball.common.event.message.MessageReceivedEvent event) {
BallBridgePlugin.getInstance().getProxyServer().getEventManager().fireAndForget(
new MessageReceivedEvent(
new ServiceMessageInfo(
ServiceInfoAPI.getSenderInfo(event.getSenderID()),
event.getReceiverID(),
event.getChannel(),
event.getAction(),
event.getContent()
)
)
);
}
}

View File

@@ -0,0 +1,163 @@
package cn.hamster3.service.velocity.listener;
import cn.hamster3.service.common.data.ServiceLocation;
import cn.hamster3.service.common.data.ServicePlayerInfo;
import cn.hamster3.service.common.entity.ServiceMessageInfo;
import cn.hamster3.service.common.entity.ServiceSenderInfo;
import cn.hamster3.service.common.util.ServiceLogUtils;
import cn.hamster3.service.velocity.BallBridgePlugin;
import cn.hamster3.service.velocity.api.ServiceInfoAPI;
import cn.hamster3.service.velocity.api.ServiceMessageAPI;
import cn.hamster3.service.velocity.event.MessageReceivedEvent;
import cn.hamster3.service.velocity.event.ServiceConnectEvent;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import java.util.UUID;
public class ServiceMainListener {
public static final ServiceMainListener INSTANCE = new ServiceMainListener();
private ServiceMainListener() {
}
@Subscribe
public void onServiceConnect(ServiceConnectEvent event) {
if (!event.isSuccess()) {
return;
}
ServiceLogUtils.info("连接至服务中心成功...");
JsonArray playerInfoArray = new JsonArray();
for (Player player : BallBridgePlugin.getInstance().getProxyServer().getAllPlayers()) {
ServicePlayerInfo playerInfo = new ServicePlayerInfo(
player.getUniqueId(),
player.getUsername(),
player.getCurrentServer().map(o -> o.getServerInfo().getName()).orElse(""),
ServiceInfoAPI.getLocalServerName()
);
playerInfoArray.add(playerInfo.saveToJson());
}
ServiceMessageAPI.sendServiceMessage("HamsterService", "updatePlayerInfoArray", playerInfoArray);
}
@Subscribe
public void onMessageReceived(MessageReceivedEvent event) {
ServiceMessageInfo info = event.getMessageInfo();
if (!"HamsterService".equals(info.getTag())) {
return;
}
ProxyServer proxyServer = BallBridgePlugin.getInstance().getProxyServer();
switch (info.getAction()) {
case "sendPlayerMessage": {
JsonObject object = info.getContentAsJsonObject();
UUID uuid = UUID.fromString(object.get("uuid").getAsString());
Player player = proxyServer.getPlayer(uuid).orElse(null);
if (player == null) {
return;
}
JsonElement message = object.get("message");
player.sendMessage(GsonComponentSerializer.gson().deserializeFromTree(message));
break;
}
case "broadcastMessage": {
Component component = GsonComponentSerializer.gson().deserializeFromTree(info.getContentAsJsonObject());
proxyServer.getConsoleCommandSource().sendMessage(component);
break;
}
case "proxyConsoleCommand": {
proxyServer.getCommandManager().executeAsync(proxyServer.getConsoleCommandSource(), info.getContentAsString());
break;
}
case "dispatchProxyCommand": {
JsonObject object = info.getContentAsJsonObject();
UUID uuid = UUID.fromString(object.get("uuid").getAsString());
Player player = proxyServer.getPlayer(uuid).orElse(null);
if (player == null) {
return;
}
String command = object.get("command").getAsString();
proxyServer.getCommandManager().executeAsync(player, command);
break;
}
case "sendPlayerToLocation": {
JsonObject object = info.getContent().getAsJsonObject();
UUID uuid = UUID.fromString(object.get("uuid").getAsString());
Player player = proxyServer.getPlayer(uuid).orElse(null);
if (player == null) {
return;
}
ServiceLocation location = new ServiceLocation(object.getAsJsonObject("location"));
String serverName = player.getCurrentServer().map(o -> o.getServerInfo().getName()).orElse("");
if (location.getServerName().equals(serverName)) {
return;
}
ServiceSenderInfo senderInfo = ServiceInfoAPI.getSenderInfo(location.getServerName());
if (senderInfo == null) {
return;
}
RegisteredServer server = proxyServer.getServer(location.getServerName()).orElse(null);
player.createConnectionRequest(server).connectWithIndication();
break;
}
case "kickPlayer": {
JsonObject object = info.getContentAsJsonObject();
UUID uuid = UUID.fromString(object.get("uuid").getAsString());
Player player = proxyServer.getPlayer(uuid).orElse(null);
if (player != null) {
player.disconnect(GsonComponentSerializer.gson().deserializeFromTree(object.get("reason")));
return;
}
break;
}
}
}
@Subscribe
public void onServerConnected(ServerConnectedEvent event) {
Player player = event.getPlayer();
ServicePlayerInfo playerInfo = new ServicePlayerInfo(
player.getUniqueId(),
player.getUsername(),
event.getServer().getServerInfo().getName(),
ServiceInfoAPI.getLocalServerName()
);
ServiceMessageAPI.sendServiceMessage("HamsterService", "updatePlayerInfo", playerInfo.saveToJson());
}
@Subscribe(priority = 100)
public void onPostLogin(PostLoginEvent event) {
Player player = event.getPlayer();
ServicePlayerInfo playerInfo = new ServicePlayerInfo(
player.getUniqueId(),
player.getUsername(),
null,
ServiceInfoAPI.getLocalServerName(),
true
);
ServiceMessageAPI.sendServiceMessage("HamsterService", "playerPostLogin", playerInfo.saveToJson());
}
@Subscribe
public void onPlayerDisconnect(DisconnectEvent event) {
Player player = event.getPlayer();
ServicePlayerInfo playerInfo = new ServicePlayerInfo(
player.getUniqueId(),
player.getUsername(),
null,
ServiceInfoAPI.getLocalServerName(),
false
);
ServiceMessageAPI.sendServiceMessage("HamsterService", "playerDisconnect", playerInfo.saveToJson());
}
}

View File

@@ -3,6 +3,14 @@ main: cn.hamster3.service.bungee.BallBridgePlugin
version: ${version}
author: MiniDay
description: ${description}
website: https://git.airgame.net/MiniDay/hamster-ball-bridge/
UPDATE_CHECKER:
VERSION: ${version}
CHECK_TYPE: GITEA_RELEASES
GIT_BASE_URL: https://git.airgame.net
GIT_REPO: MiniDay/hamster-ball-bridge
depends:
- HamsterBall

View File

@@ -4,8 +4,14 @@ version: ${version}
api-version: 1.13
author: MiniDay
website: https://github.com/MiniDay/hamster-little-plugins
description: 将 HamsterBall 转换成 HamsterService 兼容的 API
description: ${description}
website: https://git.airgame.net/MiniDay/hamster-ball-bridge/
UPDATE_CHECKER:
VERSION: ${version}
CHECK_TYPE: GITEA_RELEASES
GIT_BASE_URL: https://git.airgame.net
GIT_REPO: MiniDay/hamster-ball-bridge
depend:
- HamsterCore

View File

@@ -1,6 +1,4 @@
version: ${version}
VERSION: ${version}
CHECK_TYPE: GITEA_RELEASES
GIT_BASE_URL: https://git.airgame.net
GIT_REPO: MiniDay/hamster-ball-bridge
GIT_TOKEN: a44a69a4d1b8601bf6091403247759cd28764d5e
DOWNLOAD_URL: https://jenkins.airgame.net/job/opensource/job/hamster-ball-bridge/
GIT_REPO: MiniDay/hamster-ball-bridge

View File

@@ -0,0 +1,8 @@
package cn.hamster3.service.velocity;
// The constants are replaced before compilation
@SuppressWarnings("unused")
public class BuildConstants {
public static final String VERSION = "${version}";
public static final String DESCRIPTION = "${description}";
}