Update Upstream

0036e06 Alter the CUI lifecycle to be more consistent and reliable (1633)
This commit is contained in:
NotMyFault
2021-06-05 11:27:27 +02:00
parent d1af6c38e7
commit 75fbe654ee
17 changed files with 326 additions and 118 deletions

View File

@ -42,11 +42,11 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import io.netty.buffer.Unpooled;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
@ -58,6 +58,7 @@ import net.minecraft.util.math.BlockPos;
import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.UUID;
@ -126,9 +127,11 @@ public class FabricPlayer extends AbstractPlayerActor {
if (params.length > 0) {
send = send + "|" + StringUtil.joinString(params, "|");
}
PacketByteBuf buffer = new PacketByteBuf(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET)));
CustomPayloadS2CPacket packet = new CustomPayloadS2CPacket(new Identifier(FabricWorldEdit.MOD_ID, FabricWorldEdit.CUI_PLUGIN_CHANNEL), buffer);
this.player.networkHandler.sendPacket(packet);
ServerPlayNetworking.send(
this.player,
WECUIPacketHandler.CUI_IDENTIFIER,
new PacketByteBuf(Unpooled.copiedBuffer(send, StandardCharsets.UTF_8))
);
}
@Override
@ -248,18 +251,18 @@ public class FabricPlayer extends AbstractPlayerActor {
@Override
public SessionKey getSessionKey() {
return new SessionKeyImpl(player.getUuid(), player.getName().getString());
return new SessionKeyImpl(player);
}
private static class SessionKeyImpl implements SessionKey {
static class SessionKeyImpl implements SessionKey {
// If not static, this will leak a reference
private final UUID uuid;
private final String name;
private SessionKeyImpl(UUID uuid, String name) {
this.uuid = uuid;
this.name = name;
SessionKeyImpl(ServerPlayerEntity player) {
this.uuid = player.getUuid();
this.name = player.getName().getString();
}
@Override

View File

@ -19,16 +19,17 @@
package com.sk89q.worldedit.fabric;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer;
import com.mojang.brigadier.CommandDispatcher;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.event.platform.SessionIdleEvent;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.fabric.net.handler.WECUIPacketHandler;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.block.BlockType;
@ -36,41 +37,50 @@ import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemCategory;
import com.sk89q.worldedit.world.item.ItemType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.fabricmc.fabric.api.event.server.ServerStartCallback;
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
import net.fabricmc.fabric.api.event.server.ServerTickCallback;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.tag.BlockTags;
import net.minecraft.tag.ItemTags;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer;
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
/**
* The Fabric implementation of WorldEdit.
*/
public class FabricWorldEdit implements ModInitializer {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Logger LOGGER = LogManager.getLogger();
public static final String MOD_ID = "worldedit";
public static final String CUI_PLUGIN_CHANNEL = "cui";
@ -91,11 +101,11 @@ public class FabricWorldEdit implements ModInitializer {
@Override
public void onInitialize() {
this.container = FabricLoader.getInstance().getModContainer("worldedit").orElseThrow(
() -> new IllegalStateException("WorldEdit mod missing in Fabric")
() -> new IllegalStateException("WorldEdit mod missing in Fabric")
);
// Setup working directory
workingDir = new File(FabricLoader.getInstance().getConfigDirectory(), "worldedit").toPath();
workingDir = FabricLoader.getInstance().getConfigDir().resolve("worldedit");
if (!Files.exists(workingDir)) {
try {
Files.createDirectory(workingDir);
@ -106,24 +116,55 @@ public class FabricWorldEdit implements ModInitializer {
WECUIPacketHandler.init();
ServerTickCallback.EVENT.register(ThreadSafeCache.getInstance());
ServerStartCallback.EVENT.register(this::onStartServer);
ServerStopCallback.EVENT.register(this::onStopServer);
ServerTickEvents.END_SERVER_TICK.register(ThreadSafeCache.getInstance());
CommandRegistrationCallback.EVENT.register(this::registerCommands);
ServerLifecycleEvents.SERVER_STARTING.register(this::onStartingServer);
ServerLifecycleEvents.SERVER_STARTED.register(this::onStartServer);
ServerLifecycleEvents.SERVER_STOPPING.register(this::onStopServer);
ServerPlayConnectionEvents.DISCONNECT.register(this::onPlayerDisconnect);
AttackBlockCallback.EVENT.register(this::onLeftClickBlock);
UseBlockCallback.EVENT.register(this::onRightClickBlock);
UseItemCallback.EVENT.register(this::onRightClickAir);
LOGGER.info("WorldEdit for Fabric (version " + getInternalVersion() + ") is loaded");
}
private void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher, boolean dedicated) {
PlatformManager manager = WorldEdit.getInstance().getPlatformManager();
if (manager.getPlatforms().isEmpty()) {
// We'll register as part of our platform initialization later.
return;
}
// This is a re-register (due to /reload), we must add our commands now
Platform commandsPlatform = manager.queryCapability(Capability.USER_COMMANDS);
if (commandsPlatform != platform || !platform.isHookingEvents()) {
// We're not in control of commands/events -- do not re-register.
return;
}
platform.setNativeDispatcher(dispatcher);
platform.registerCommands(manager.getPlatformCommandManager().getCommandManager());
}
private void setupPlatform(MinecraftServer server) {
this.platform = new FabricPlatform(this, server);
WorldEdit.getInstance().getPlatformManager().register(platform);
this.provider = new FabricPermissionsProvider.VanillaPermissionsProvider(platform);
this.provider = getInitialPermissionsProvider();
}
private void setupRegistries() {
private FabricPermissionsProvider getInitialPermissionsProvider() {
try {
Class.forName("me.lucko.fabric.api.permissions.v0.Permissions", false, getClass().getClassLoader());
return new FabricPermissionsProvider.LuckoFabricPermissionsProvider(platform);
} catch (ClassNotFoundException ignored) {
// fallback to vanilla
}
return new FabricPermissionsProvider.VanillaPermissionsProvider(platform);
}
private void setupRegistries(MinecraftServer server) {
// Blocks
for (Identifier name : Registry.BLOCK.getIds()) {
if (BlockType.REGISTRY.get(name.toString()) == null) {
@ -144,31 +185,42 @@ public class FabricWorldEdit implements ModInitializer {
}
}
// Biomes
for (Identifier name : Registry.BIOME.getIds()) {
for (Identifier name : server.getRegistryManager().get(Registry.BIOME_KEY).getIds()) {
if (BiomeType.REGISTRY.get(name.toString()) == null) {
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
}
}
// Tags
for (Identifier name : BlockTags.getContainer().getKeys()) {
for (Identifier name : BlockTags.getTagGroup().getTagIds()) {
if (BlockCategory.REGISTRY.get(name.toString()) == null) {
BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString()));
}
}
for (Identifier name : ItemTags.getContainer().getKeys()) {
for (Identifier name : ItemTags.getTagGroup().getTagIds()) {
if (ItemCategory.REGISTRY.get(name.toString()) == null) {
ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString()));
}
}
}
private void onStartingServer(MinecraftServer minecraftServer) {
final Path delChunks = workingDir.resolve(DELCHUNKS_FILE_NAME);
if (Files.exists(delChunks)) {
ChunkDeleter.runFromFile(delChunks, true);
}
}
private void onStartServer(MinecraftServer minecraftServer) {
FabricAdapter.setServer(minecraftServer);
setupPlatform(minecraftServer);
setupRegistries();
setupRegistries(minecraftServer);
config = new FabricConfiguration(this);
config.load();
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
minecraftServer.reloadResources(
minecraftServer.getDataPackManager().getEnabledNames()
);
}
private void onStopServer(MinecraftServer minecraftServer) {
@ -198,8 +250,9 @@ public class FabricWorldEdit implements ModInitializer {
blockPos.getY(),
blockPos.getZ()
);
com.sk89q.worldedit.util.Direction weDirection = FabricAdapter.adaptEnumFacing(direction);
if (we.handleBlockLeftClick(player, pos)) {
if (we.handleBlockLeftClick(player, pos, weDirection)) {
return ActionResult.SUCCESS;
}
@ -210,12 +263,6 @@ public class FabricWorldEdit implements ModInitializer {
return ActionResult.PASS;
}
public void onLeftClickAir(PlayerEntity playerEntity, World world, Hand hand) {
WorldEdit we = WorldEdit.getInstance();
FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity);
we.handleArmSwing(player);
}
private ActionResult onRightClickBlock(PlayerEntity playerEntity, World world, Hand hand, BlockHitResult blockHitResult) {
if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) {
return ActionResult.PASS;
@ -229,8 +276,9 @@ public class FabricWorldEdit implements ModInitializer {
blockHitResult.getBlockPos().getY(),
blockHitResult.getBlockPos().getZ()
);
com.sk89q.worldedit.util.Direction direction = FabricAdapter.adaptEnumFacing(blockHitResult.getSide());
if (we.handleBlockRightClick(player, pos)) {
if (we.handleBlockRightClick(player, pos, direction)) {
return ActionResult.SUCCESS;
}
@ -241,23 +289,29 @@ public class FabricWorldEdit implements ModInitializer {
return ActionResult.PASS;
}
private ActionResult onRightClickAir(PlayerEntity playerEntity, World world, Hand hand) {
private TypedActionResult<ItemStack> onRightClickAir(PlayerEntity playerEntity, World world, Hand hand) {
ItemStack stackInHand = playerEntity.getStackInHand(hand);
if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) {
return ActionResult.PASS;
return TypedActionResult.pass(stackInHand);
}
WorldEdit we = WorldEdit.getInstance();
FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity);
if (we.handleRightClick(player)) {
return ActionResult.SUCCESS;
return TypedActionResult.success(stackInHand);
}
return ActionResult.PASS;
return TypedActionResult.pass(stackInHand);
}
// TODO Pass empty left click to server
private void onPlayerDisconnect(ServerPlayNetworkHandler handler, MinecraftServer server) {
WorldEdit.getInstance().getEventBus()
.post(new SessionIdleEvent(new FabricPlayer.SessionKeyImpl(handler.player)));
}
/**
* Get the configuration.
*
@ -303,8 +357,8 @@ public class FabricWorldEdit implements ModInitializer {
*
* @return the working directory
*/
public File getWorkingDir() {
return this.workingDir.toFile();
public Path getWorkingDir() {
return this.workingDir;
}
/**

View File

@ -23,33 +23,23 @@ import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.fabric.FabricAdapter;
import com.sk89q.worldedit.fabric.FabricPlayer;
import com.sk89q.worldedit.fabric.FabricWorldEdit;
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.util.Identifier;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public final class WECUIPacketHandler {
private WECUIPacketHandler() {
}
public static final Charset UTF_8_CHARSET = StandardCharsets.UTF_8;
private static final Identifier CUI_IDENTIFIER = new Identifier(FabricWorldEdit.MOD_ID, FabricWorldEdit.CUI_PLUGIN_CHANNEL);
public static final Identifier CUI_IDENTIFIER = new Identifier(FabricWorldEdit.MOD_ID, FabricWorldEdit.CUI_PLUGIN_CHANNEL);
public static void init() {
ServerSidePacketRegistry.INSTANCE.register(CUI_IDENTIFIER, (packetContext, packetByteBuf) -> {
ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
ServerPlayNetworking.registerGlobalReceiver(CUI_IDENTIFIER, (server, player, handler, buf, responder) -> {
LocalSession session = FabricWorldEdit.inst.getSession(player);
if (session.hasCUISupport()) {
return;
}
String text = packetByteBuf.toString(UTF_8_CHARSET);
final FabricPlayer actor = FabricAdapter.adaptPlayer(player);
String text = buf.toString(StandardCharsets.UTF_8);
FabricPlayer actor = FabricAdapter.adaptPlayer(player);
session.handleCUIInitializationMessage(text, actor);
session.describeCUI(actor);
});
}
}

View File

@ -32,7 +32,7 @@
"fabric-api-base": "*",
"fabric-events-lifecycle-v0": "*",
"fabric-events-interaction-v0": "*",
"fabric-networking-v0": "*"
"fabric-networking-api-v1": "*"
},
"mixins": [
"worldedit.mixins.json"