Skip to content

Commit cb389fd

Browse files
committed
feat(chat): change chat type from server broadcast to client player
1 parent 308571b commit cb389fd

5 files changed

Lines changed: 118 additions & 34 deletions

File tree

src/main/java/tech/elicase/minecraftosc/MinecraftOscForgeConfig.java

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,40 @@ public final class MinecraftOscForgeConfig {
7070
.defineInRange("maxDispatchPerTick", 8, 1, 256);
7171

7272
public static final ForgeConfigSpec SPEC = BUILDER.build();
73+
private static final MinecraftOscSettings DEFAULT_SETTINGS = createSettings(
74+
9000,
75+
DEFAULT_OSC_ADDRESSES,
76+
false,
77+
DEFAULT_ALLOWED_SENDERS,
78+
"[VRChat] ",
79+
256,
80+
200,
81+
2,
82+
20,
83+
8,
84+
5,
85+
8
86+
);
7387

7488
private MinecraftOscForgeConfig() {
7589
}
7690

91+
/**
92+
* 读取配置加载前可用的默认快照
93+
*/
94+
public static MinecraftOscSettings defaults() {
95+
return DEFAULT_SETTINGS;
96+
}
97+
7798
/**
7899
* 构建核心层配置快照
79100
*/
80101
public static MinecraftOscSettings snapshot() {
81-
return new MinecraftOscSettings(
102+
return createSettings(
82103
LISTEN_PORT.get(),
83-
normalizeSet(ACCEPTED_OSC_ADDRESSES.get()),
104+
ACCEPTED_OSC_ADDRESSES.get(),
84105
ALLOW_ANY_SENDER.get(),
85-
normalizeSet(ALLOWED_SENDERS.get()),
106+
ALLOWED_SENDERS.get(),
86107
CHAT_PREFIX.get(),
87108
MAX_MESSAGE_LENGTH.get(),
88109
MAX_QUEUE_SIZE.get(),
@@ -101,6 +122,36 @@ public static void onConfigLoad(ModConfigEvent event) {
101122
}
102123
}
103124

125+
private static MinecraftOscSettings createSettings(
126+
int listenPort,
127+
List<? extends String> acceptedOscAddresses,
128+
boolean allowAnySender,
129+
List<? extends String> allowedSenders,
130+
String chatPrefix,
131+
int maxMessageLength,
132+
int maxQueueSize,
133+
int maxRetries,
134+
int retryDelayTicks,
135+
int rateLimitMessages,
136+
int rateLimitWindowSeconds,
137+
int maxDispatchPerTick
138+
) {
139+
return new MinecraftOscSettings(
140+
listenPort,
141+
normalizeSet(acceptedOscAddresses),
142+
allowAnySender,
143+
normalizeSet(allowedSenders),
144+
chatPrefix,
145+
maxMessageLength,
146+
maxQueueSize,
147+
maxRetries,
148+
retryDelayTicks,
149+
rateLimitMessages,
150+
rateLimitWindowSeconds,
151+
maxDispatchPerTick
152+
);
153+
}
154+
104155
private static boolean validateNonBlank(Object value) {
105156
return value instanceof String string && !string.trim().isEmpty();
106157
}

src/main/java/tech/elicase/minecraftosc/MinecraftOscMod.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import com.mojang.logging.LogUtils;
44
import net.minecraftforge.common.MinecraftForge;
5+
import net.minecraftforge.api.distmarker.Dist;
56
import net.minecraftforge.fml.event.config.ModConfigEvent;
67
import net.minecraftforge.fml.common.Mod;
78
import net.minecraftforge.fml.config.ModConfig;
89
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
10+
import net.minecraftforge.fml.loading.FMLEnvironment;
911
import org.slf4j.Logger;
1012
import tech.elicase.minecraftosc.core.config.ConfigManager;
11-
import tech.elicase.minecraftosc.platform.forge.ForgeAdapter;
13+
import tech.elicase.minecraftosc.platform.forge.ReloadableAdapter;
1214

1315
/**
1416
* MinecraftOSC 模组入口
@@ -20,14 +22,13 @@ public final class MinecraftOscMod {
2022
public static final Logger LOGGER = LogUtils.getLogger();
2123

2224
private final ConfigManager configManager;
23-
private final ForgeAdapter forgeAdapter;
25+
private final ReloadableAdapter platformAdapter;
2426

2527
public MinecraftOscMod(FMLJavaModLoadingContext context) {
26-
configManager = new ConfigManager(MinecraftOscForgeConfig.snapshot());
27-
forgeAdapter = new ForgeAdapter(configManager, LOGGER);
28+
configManager = new ConfigManager(MinecraftOscForgeConfig.defaults());
29+
platformAdapter = createPlatformAdapter(configManager);
2830
context.registerConfig(ModConfig.Type.COMMON, MinecraftOscForgeConfig.SPEC);
2931
context.getModEventBus().addListener(this::onConfigChanged);
30-
MinecraftForge.EVENT_BUS.register(forgeAdapter);
3132
LOGGER.info("MinecraftOSC 配置已注册");
3233
}
3334

@@ -36,6 +37,25 @@ private void onConfigChanged(ModConfigEvent event) {
3637
return;
3738
}
3839
configManager.update(MinecraftOscForgeConfig.snapshot());
39-
forgeAdapter.reload();
40+
if (platformAdapter != null) {
41+
platformAdapter.reload();
42+
}
43+
}
44+
45+
private ReloadableAdapter createPlatformAdapter(ConfigManager configManager) {
46+
if (FMLEnvironment.dist != Dist.CLIENT) {
47+
return null;
48+
}
49+
50+
try {
51+
Class<?> adapterClass = Class.forName("tech.elicase.minecraftosc.platform.forge.ForgeAdapter");
52+
ReloadableAdapter adapter = (ReloadableAdapter) adapterClass
53+
.getConstructor(ConfigManager.class, Logger.class)
54+
.newInstance(configManager, LOGGER);
55+
MinecraftForge.EVENT_BUS.register(adapter);
56+
return adapter;
57+
} catch (ReflectiveOperationException exception) {
58+
throw new IllegalStateException("客户端桥接适配器初始化失败", exception);
59+
}
4060
}
4161
}

src/main/java/tech/elicase/minecraftosc/platform/forge/ForgeAdapter.java

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package tech.elicase.minecraftosc.platform.forge;
22

3-
import net.minecraft.server.MinecraftServer;
3+
import net.minecraft.client.Minecraft;
4+
import net.minecraft.client.multiplayer.ClientPacketListener;
5+
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
46
import net.minecraftforge.event.TickEvent;
5-
import net.minecraftforge.event.server.ServerStartingEvent;
6-
import net.minecraftforge.event.server.ServerStoppingEvent;
77
import net.minecraftforge.eventbus.api.SubscribeEvent;
88
import org.slf4j.Logger;
99
import tech.elicase.minecraftosc.core.config.ConfigManager;
@@ -15,14 +15,13 @@
1515
/**
1616
* Forge 生命周期适配器
1717
*/
18-
public final class ForgeAdapter {
18+
public final class ForgeAdapter implements ReloadableAdapter {
1919

2020
private final ConfigManager configManager;
2121
private final Logger logger;
2222

2323
private MinecraftOscService oscService;
24-
private MinecraftServer server;
25-
private long serverTick;
24+
private long clientTick;
2625

2726
public ForgeAdapter(ConfigManager configManager, Logger logger) {
2827
this.configManager = configManager;
@@ -43,27 +42,31 @@ public void reload() {
4342
}
4443

4544
@SubscribeEvent
46-
public void onServerStarting(ServerStartingEvent event) {
47-
server = event.getServer();
45+
public void onClientLoggingIn(ClientPlayerNetworkEvent.LoggingIn event) {
4846
startService();
4947
}
5048

5149
@SubscribeEvent
52-
public void onServerStopping(ServerStoppingEvent event) {
50+
public void onClientLoggingOut(ClientPlayerNetworkEvent.LoggingOut event) {
5351
stopService();
54-
server = null;
5552
}
5653

5754
@SubscribeEvent
58-
public void onServerTick(TickEvent.ServerTickEvent event) {
59-
if (event.phase != TickEvent.Phase.END || oscService == null || server == null) {
55+
public void onClientTick(TickEvent.ClientTickEvent event) {
56+
if (event.phase != TickEvent.Phase.END || oscService == null) {
6057
return;
6158
}
6259

63-
serverTick++;
64-
oscService.releaseReadyRetries(serverTick);
60+
Minecraft minecraft = Minecraft.getInstance();
61+
ClientPacketListener connection = minecraft.getConnection();
62+
if (minecraft.player == null || connection == null) {
63+
return;
64+
}
65+
66+
clientTick++;
67+
oscService.releaseReadyRetries(clientTick);
6568

66-
ForgeChatBroadcaster broadcaster = new ForgeChatBroadcaster(server);
69+
ForgeChatBroadcaster broadcaster = new ForgeChatBroadcaster(connection);
6770
int dispatched = 0;
6871
while (dispatched < oscService.settings().maxDispatchPerTick()) {
6972
ChatEvent chatEvent = oscService.pollChatEvent();
@@ -73,17 +76,17 @@ public void onServerTick(TickEvent.ServerTickEvent event) {
7376

7477
try {
7578
broadcaster.broadcast(oscService.settings().chatPrefix() + chatEvent.content());
76-
logger.info("聊天消息已注入 Minecraft: id={}, source={}", chatEvent.id(), chatEvent.sourceAddress());
79+
logger.info("聊天消息已通过本地玩家发送: id={}, source={}", chatEvent.id(), chatEvent.sourceAddress());
7780
} catch (RuntimeException exception) {
78-
oscService.scheduleRetry(chatEvent, serverTick, exception);
81+
oscService.scheduleRetry(chatEvent, clientTick, exception);
7982
}
8083
dispatched++;
8184
}
8285
}
8386

8487
private void startService() {
8588
stopService();
86-
serverTick = 0L;
89+
clientTick = 0L;
8790
oscService = new MinecraftOscService(configManager, logger);
8891
try {
8992
oscService.start();
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
package tech.elicase.minecraftosc.platform.forge;
22

3-
import net.minecraft.network.chat.Component;
4-
import net.minecraft.server.MinecraftServer;
3+
import net.minecraft.client.multiplayer.ClientPacketListener;
54
import tech.elicase.minecraftosc.core.platform.ChatBroadcaster;
65

6+
import java.util.Objects;
7+
78
/**
8-
* Forge 聊天广播实现
9+
* Forge 客户端聊天发送实现
910
*/
1011
public final class ForgeChatBroadcaster implements ChatBroadcaster {
1112

12-
private final MinecraftServer server;
13+
private final ClientPacketListener connection;
1314

14-
public ForgeChatBroadcaster(MinecraftServer server) {
15-
this.server = server;
15+
public ForgeChatBroadcaster(ClientPacketListener connection) {
16+
this.connection = Objects.requireNonNull(connection, "connection");
1617
}
1718

1819
@Override
1920
public void broadcast(String message) {
20-
server.getPlayerList().broadcastSystemMessage(Component.literal(message), false);
21+
connection.sendChat(message);
2122
}
2223
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package tech.elicase.minecraftosc.platform.forge;
2+
3+
/**
4+
* 可响应配置重载的平台适配器
5+
*/
6+
public interface ReloadableAdapter {
7+
8+
void reload();
9+
}

0 commit comments

Comments
 (0)