-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTestConnectionImpl.java
More file actions
130 lines (108 loc) · 4.89 KB
/
TestConnectionImpl.java
File metadata and controls
130 lines (108 loc) · 4.89 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
package net.minestom.testing;
import net.kyori.adventure.translation.GlobalTranslator;
import net.minestom.server.ServerProcess;
import net.minestom.server.adventure.MinestomAdventure;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
final class TestConnectionImpl implements TestConnection {
private final ServerProcess process;
private final GameProfile gameProfile;
private final PlayerConnectionImpl playerConnection = new PlayerConnectionImpl();
private final AtomicBoolean connected = new AtomicBoolean(false);
private final List<IncomingCollector<ServerPacket>> incomingTrackers = new CopyOnWriteArrayList<>();
TestConnectionImpl(Env env, GameProfile gameProfile) {
this.process = env.process();
this.gameProfile = gameProfile;
}
@Override
public Player connect(Instance instance, Pos pos) {
if (!connected.compareAndSet(false, true)) {
throw new IllegalStateException("Already connected");
}
var player = process.connection().createPlayer(playerConnection, gameProfile);
player.eventNode().addListener(AsyncPlayerConfigurationEvent.class, event -> {
event.setSpawningInstance(instance);
event.getPlayer().setRespawnPoint(pos);
});
// Force the player through the entirety of the login process manually
CompletableFuture<Player> future = new CompletableFuture<>();
Thread.startVirtualThread(() -> {
// `isFirstConfig` is set to false in order to not block the thread
// waiting for known packs.
// The consequence is that registry packets cannot be listened to.
process.connection().doConfiguration(player, false);
process.connection().transitionConfigToPlay(player);
future.complete(player);
});
future.join();
playerConnection.setClientState(ConnectionState.PLAY);
playerConnection.setServerState(ConnectionState.PLAY);
process.connection().updateWaitingPlayers();
return player;
}
@Override
public <T extends ServerPacket> Collector<T> trackIncoming(Class<T> type) {
var tracker = new IncomingCollector<>(type);
this.incomingTrackers.add(IncomingCollector.class.cast(tracker));
return tracker;
}
final class PlayerConnectionImpl extends PlayerConnection {
private boolean online = true;
@Override
public void sendPacket(SendablePacket packet) {
final var serverPacket = this.extractPacket(packet);
for (var tracker : incomingTrackers) {
if (tracker.type.isAssignableFrom(serverPacket.getClass())) tracker.packets.add(serverPacket);
}
}
private ServerPacket extractPacket(final SendablePacket packet) {
if (!(packet instanceof ServerPacket serverPacket))
return SendablePacket.extractServerPacket(getServerState(), packet);
final Player player = getPlayer();
if (player == null) return serverPacket;
if (MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION && serverPacket instanceof ServerPacket.ComponentHolding) {
serverPacket = ((ServerPacket.ComponentHolding) serverPacket).copyWithOperator(component ->
GlobalTranslator.render(component, Objects.requireNonNullElseGet(player.getLocale(), MinestomAdventure::getDefaultLocale)));
}
return serverPacket;
}
@Override
public SocketAddress getRemoteAddress() {
return new InetSocketAddress("localhost", 25565);
}
@Override
public boolean isOnline() {
return online;
}
@Override
public void disconnect() {
online = false;
}
}
final class IncomingCollector<T extends ServerPacket> implements Collector<T> {
private final Class<T> type;
private final List<T> packets = new CopyOnWriteArrayList<>();
public IncomingCollector(Class<T> type) {
this.type = type;
}
@Override
public List<T> collect() {
incomingTrackers.remove(this);
return List.copyOf(packets);
}
}
}