forked from HypixelDev/FabricModAPI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFabricModAPI.java
More file actions
183 lines (158 loc) · 8.17 KB
/
FabricModAPI.java
File metadata and controls
183 lines (158 loc) · 8.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package net.hypixel.modapi.fabric;
import com.mojang.logging.LogUtils;
import io.netty.buffer.ByteBuf;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.gametest.v1.GameTest;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.loader.api.FabricLoader;
import net.hypixel.modapi.HypixelModAPI;
import net.hypixel.modapi.HypixelModAPIImplementation;
import net.hypixel.modapi.fabric.event.HypixelModAPICallback;
import net.hypixel.modapi.fabric.event.HypixelModAPIErrorCallback;
import net.hypixel.modapi.fabric.payload.ClientboundHypixelPayload;
import net.hypixel.modapi.fabric.payload.ServerboundHypixelPayload;
import net.hypixel.modapi.packet.HypixelPacket;
import net.hypixel.modapi.packet.impl.clientbound.ClientboundHelloPacket;
import net.hypixel.modapi.packet.impl.clientbound.event.ClientboundLocationPacket;
import net.minecraft.client.Minecraft;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.Identifier;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
public class FabricModAPI implements ClientModInitializer, HypixelModAPIImplementation {
private static final Logger LOGGER = LogUtils.getLogger();
private static final boolean DEBUG_MODE = FabricLoader.getInstance().isDevelopmentEnvironment() || Boolean.getBoolean("net.hypixel.modapi.debug");
private boolean onHypixel = false;
@GameTest
@Override
public void onInitializeClient() {
HypixelModAPI.getInstance().setModImplementation(this);
}
@Override
public void onInit() {
HypixelModAPI.getInstance().createHandler(ClientboundHelloPacket.class, packet -> onHypixel = true);
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> onHypixel = false);
if (DEBUG_MODE) {
LOGGER.info("Debug mode is enabled!");
registerDebug();
}
reloadRegistrations();
}
@Override
public boolean sendPacket(HypixelPacket packet) {
if (!isConnectedToHypixel()) {
return false;
}
ServerboundHypixelPayload hypixelPayload = new ServerboundHypixelPayload(packet);
if (Minecraft.getInstance().getConnection() != null) {
ClientPlayNetworking.send(hypixelPayload);
return true;
}
try {
ClientConfigurationNetworking.send(hypixelPayload);
return true;
} catch (IllegalStateException ignored) {
LOGGER.warn("Failed to send a packet as the client is not connected to a server '{}'", packet);
return false;
}
}
@Override
public boolean isConnectedToHypixel() {
return onHypixel;
}
/**
* Reloads the identifiers that are registered in the Hypixel Mod API and makes sure that the packets are registered.
* <p>
* This method is available for internal use by Hypixel to add new packets externally, and is not intended for use by other developers.
*/
@ApiStatus.Internal
public static void reloadRegistrations() {
for (String identifier : HypixelModAPI.getInstance().getRegistry().getClientboundIdentifiers()) {
try {
registerClientbound(identifier);
LOGGER.info("Registered clientbound packet with identifier '{}'", identifier);
} catch (Exception e) {
LOGGER.error("Failed to register clientbound packet with identifier '{}'", identifier, e);
}
}
for (String identifier : HypixelModAPI.getInstance().getRegistry().getServerboundIdentifiers()) {
try {
registerServerbound(identifier);
LOGGER.info("Registered serverbound packet with identifier '{}'", identifier);
} catch (Exception e) {
LOGGER.error("Failed to register serverbound packet with identifier '{}'", identifier, e);
}
}
}
private static void registerClientbound(String identifier) {
try {
CustomPacketPayload.Type<ClientboundHypixelPayload> clientboundId = new CustomPacketPayload.Type<>(
Identifier.parse(identifier)
);
StreamCodec<ByteBuf, ClientboundHypixelPayload> codec = ClientboundHypixelPayload.buildCodec(clientboundId);
PayloadTypeRegistry.clientboundPlay().register(clientboundId, codec);
PayloadTypeRegistry.clientboundConfiguration().register(clientboundId, codec);
// Also register the global receiver for handling incoming packets during PLAY and CONFIGURATION
ClientPlayNetworking.registerGlobalReceiver(clientboundId, (payload, context) -> {
LOGGER.debug("Received packet with identifier '{}', during PLAY", identifier);
handleIncomingPayload(identifier, payload);
});
ClientConfigurationNetworking.registerGlobalReceiver(clientboundId, (payload, context) -> {
LOGGER.debug("Received packet with identifier '{}', during CONFIGURATION", identifier);
handleIncomingPayload(identifier, payload);
});
} catch (IllegalArgumentException ignored) {
// Ignored as this is fired when we reload the registrations and the packet is already registered
}
}
private static void handleIncomingPayload(String identifier, ClientboundHypixelPayload payload) {
if (!payload.isSuccess()) {
LOGGER.warn("Received an error response for packet {}: {}", identifier, payload.getErrorReason());
try {
HypixelModAPI.getInstance().handleError(identifier, payload.getErrorReason());
} catch (Exception e) {
LOGGER.error("An error occurred while handling error response for packet {}", identifier, e);
}
try {
HypixelModAPIErrorCallback.EVENT.invoker().onError(identifier, payload.getErrorReason());
} catch (Exception e) {
LOGGER.error("An error occurred while handling error response for packet {}", identifier, e);
}
return;
}
try {
HypixelModAPI.getInstance().handle(payload.getPacket());
} catch (Exception e) {
LOGGER.error("An error occurred while handling packet {}", identifier, e);
}
try {
HypixelModAPICallback.EVENT.invoker().onPacketReceived(payload.getPacket());
} catch (Exception e) {
LOGGER.error("An error occurred while handling packet {}", identifier, e);
}
}
private static void registerServerbound(String identifier) {
try {
CustomPacketPayload.Type<ServerboundHypixelPayload> serverboundId = new CustomPacketPayload.Type<>(
Identifier.parse(identifier)
);
StreamCodec<ByteBuf, ServerboundHypixelPayload> codec = ServerboundHypixelPayload.buildCodec();
PayloadTypeRegistry.serverboundPlay().register(serverboundId, codec);
PayloadTypeRegistry.serverboundConfiguration().register(serverboundId, codec);
} catch (IllegalArgumentException ignored) {
// Ignored as this is fired when we reload the registrations and the packet is already registered
}
}
private static void registerDebug() {
// Register events
HypixelModAPI.getInstance().subscribeToEventPacket(ClientboundLocationPacket.class);
HypixelModAPI.getInstance().createHandler(ClientboundLocationPacket.class, packet -> LOGGER.info("Received location packet {}", packet))
.onError(error -> LOGGER.error("Received error response for location packet: {}", error));
HypixelModAPICallback.EVENT.register(packet -> LOGGER.info("Received packet {}", packet));
HypixelModAPIErrorCallback.EVENT.register((identifier, error) -> LOGGER.error("Received error response for packet {}: {}", identifier, error));
}
}