mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 08:17:35 +00:00
Implement PlayerNegotiationEvent (#8599)
This commit is contained in:
1 parent
0f8c2fa454
commit
7fb5dfa3e6
5 files changed
+138
-1
No files matched your search
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.event.entity.player;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* This event is fired on the server when a connection has started the Forge handshake,
|
||||
* Forge will wait for all enqueued work to be completed before proceeding further with the login process.
|
||||
* <br>
|
||||
* This event can be used to delay the player login until any necessary work such as preloading user data has completed.
|
||||
* <br>
|
||||
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
|
||||
*/
|
||||
public class PlayerNegotiationEvent extends Event
|
||||
{
|
||||
|
||||
private final Connection connection;
|
||||
private final GameProfile profile;
|
||||
private final List<Future<Void>> futures;
|
||||
|
||||
public PlayerNegotiationEvent(Connection connection, GameProfile profile, List<Future<Void>> futures)
|
||||
{
|
||||
this.connection = connection;
|
||||
this.profile = profile;
|
||||
this.futures = futures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue work to be completed asynchronously before the login proceeds.
|
||||
*/
|
||||
public void enqueueWork(Runnable runnable)
|
||||
{
|
||||
enqueueWork(CompletableFuture.runAsync(runnable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue work to be completed asynchronously before the login proceeds.
|
||||
*/
|
||||
public void enqueueWork(Future<Void> future)
|
||||
{
|
||||
futures.add(future);
|
||||
}
|
||||
|
||||
public Connection getConnection()
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
|
||||
public GameProfile getProfile()
|
||||
{
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
package net.minecraftforge.network;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.handshake.ClientIntentionPacket;
|
||||
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
|
||||
@@ -13,7 +14,9 @@ import net.minecraft.network.protocol.login.ServerboundCustomQueryPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.LogMessageAdapter;
|
||||
import net.minecraftforge.event.entity.player.PlayerNegotiationEvent;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
@@ -25,7 +28,10 @@ import org.apache.logging.log4j.MarkerManager;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.IntSupplier;
|
||||
@@ -99,6 +105,8 @@ public class HandshakeHandler
|
||||
private Map<ResourceLocation, ForgeRegistry.Snapshot> registrySnapshots;
|
||||
private Set<ResourceLocation> registriesToReceive;
|
||||
private Map<ResourceLocation, String> registryHashes;
|
||||
private boolean negotiationStarted = false;
|
||||
private final List<Future<Void>> pendingFutures = new ArrayList<>();
|
||||
|
||||
private HandshakeHandler(Connection networkManager, NetworkDirection side)
|
||||
{
|
||||
@@ -281,6 +289,13 @@ public class HandshakeHandler
|
||||
*/
|
||||
public boolean tickServer()
|
||||
{
|
||||
if (!negotiationStarted) {
|
||||
GameProfile profile = ((ServerLoginPacketListenerImpl) manager.getPacketListener()).gameProfile;
|
||||
PlayerNegotiationEvent event = new PlayerNegotiationEvent(manager, profile, pendingFutures);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
negotiationStarted = true;
|
||||
}
|
||||
|
||||
if (packetPosition < messageList.size()) {
|
||||
NetworkRegistry.LoginPayload message = messageList.get(packetPosition);
|
||||
|
||||
@@ -290,8 +305,24 @@ public class HandshakeHandler
|
||||
packetPosition++;
|
||||
}
|
||||
|
||||
pendingFutures.removeIf(future -> {
|
||||
if (!future.isDone()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
future.get();
|
||||
} catch (ExecutionException ex) {
|
||||
LOGGER.error("Error during negotiation", ex.getCause());
|
||||
} catch (CancellationException | InterruptedException ex) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// we're done when sentMessages is empty
|
||||
if (sentMessages.isEmpty() && packetPosition >= messageList.size()-1) {
|
||||
if (sentMessages.isEmpty() && packetPosition >= messageList.size()-1 && pendingFutures.isEmpty()) {
|
||||
// clear ourselves - we're done!
|
||||
this.manager.channel().attr(NetworkConstants.FML_HANDSHAKE_HANDLER).set(null);
|
||||
LOGGER.debug(FMLHSMARKER, "Handshake complete!");
|
||||
|
||||
@@ -271,6 +271,7 @@ public net.minecraft.server.level.ServerLevel m_142646_()Lnet/minecraft/world/le
|
||||
public net.minecraft.server.level.ServerPlayer f_8940_ # containerCounter
|
||||
public net.minecraft.server.level.ServerPlayer m_143399_(Lnet/minecraft/world/inventory/AbstractContainerMenu;)V # initMenu
|
||||
public net.minecraft.server.level.ServerPlayer m_9217_()V # nextContainerCounter
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl f_10021_ # gameProfile
|
||||
public net.minecraft.server.packs.AbstractPackResources f_10203_ # file
|
||||
public net.minecraft.server.packs.resources.FallbackResourceManager f_10599_ # fallbacks
|
||||
public net.minecraft.tags.Tag$BuilderEntry <init>(Lnet/minecraft/tags/Tag$Entry;Ljava/lang/String;)V # constructor
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.debug.entity.player;
|
||||
|
||||
import net.minecraftforge.event.entity.player.PlayerNegotiationEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Tests {@link PlayerNegotiationEvent} by listening for and then enqueuing work to be done asynchronously,
|
||||
* details regarding the work execution is printed out and exceptions are thrown to ensure proper handling.
|
||||
*/
|
||||
@Mod("player_negotiation_event_test")
|
||||
@Mod.EventBusSubscriber()
|
||||
public class PlayerNegotiationEventTest
|
||||
{
|
||||
private static final boolean ENABLE = false;
|
||||
private static final Logger LOGGER = LogManager.getLogger(PlayerNegotiationEventTest.class);
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerNegotiation(PlayerNegotiationEvent event)
|
||||
{
|
||||
if (!ENABLE) return;
|
||||
LOGGER.info("{} ({})[{}] started negotiation", event.getProfile().getName(), event.getProfile().getId(), event.getConnection().getRemoteAddress());
|
||||
event.enqueueWork(() -> {
|
||||
// This log message should be printed on the fork-join-pool.
|
||||
LOGGER.info("Hello from {}", Thread.currentThread().getName());
|
||||
});
|
||||
event.enqueueWork(() -> {
|
||||
// This exception should be logged by Forge.
|
||||
throw new RuntimeException("Test Exception from PlayerNegotiationEventTest");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -218,5 +218,7 @@ license="LGPL v2.1"
|
||||
modId="server_world_creation_test"
|
||||
[[mods]]
|
||||
modId="valid_railshape_test"
|
||||
[[mods]]
|
||||
modId="player_negotiation_event_test"
|
||||
|
||||
# ADD ABOVE THIS LINE
|
||||
Reference in new issue
Block a user