UI cleanup, trade implementation via hotkey and via /trade player|yes|no
This commit is contained in:
@@ -18,6 +18,13 @@ public final class TradeClientState {
|
|||||||
return minecraft;
|
return minecraft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void showOrUpdate(TradeView view) {
|
||||||
|
if (minecraft == null) {
|
||||||
|
minecraft = Minecraft.getInstance();
|
||||||
|
}
|
||||||
|
showOrUpdate(minecraft, view);
|
||||||
|
}
|
||||||
|
|
||||||
public static void showOrUpdate(Minecraft minecraftInstance, TradeView view) {
|
public static void showOrUpdate(Minecraft minecraftInstance, TradeView view) {
|
||||||
minecraft = minecraftInstance;
|
minecraft = minecraftInstance;
|
||||||
if (minecraft.screen instanceof TradeScreen screen && screen.sessionId().equals(view.sessionId())) {
|
if (minecraft.screen instanceof TradeScreen screen && screen.sessionId().equals(view.sessionId())) {
|
||||||
@@ -32,6 +39,13 @@ public final class TradeClientState {
|
|||||||
minecraft.setScreen(new TradeScreen(new TradeScreen.TradeMenu(0, minecraft.player.getInventory(), view), minecraft.player.getInventory(), Component.literal("Trade")));
|
minecraft.setScreen(new TradeScreen(new TradeScreen.TradeMenu(0, minecraft.player.getInventory(), view), minecraft.player.getInventory(), Component.literal("Trade")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void closeTrade(UUID sessionId, Component reason) {
|
||||||
|
if (minecraft == null) {
|
||||||
|
minecraft = Minecraft.getInstance();
|
||||||
|
}
|
||||||
|
closeTrade(minecraft, sessionId, reason);
|
||||||
|
}
|
||||||
|
|
||||||
public static void closeTrade(Minecraft minecraftInstance, UUID sessionId, Component reason) {
|
public static void closeTrade(Minecraft minecraftInstance, UUID sessionId, Component reason) {
|
||||||
minecraft = minecraftInstance;
|
minecraft = minecraftInstance;
|
||||||
if (minecraft.screen instanceof TradeScreen screen && screen.sessionId().equals(sessionId)) {
|
if (minecraft.screen instanceof TradeScreen screen && screen.sessionId().equals(sessionId)) {
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ public final class TradeCommand {
|
|||||||
.then(Commands.literal("accept").executes(context -> acceptDebug(context.getSource())))
|
.then(Commands.literal("accept").executes(context -> acceptDebug(context.getSource())))
|
||||||
.then(Commands.literal("cancel").executes(context -> cancelDebug(context.getSource())))
|
.then(Commands.literal("cancel").executes(context -> cancelDebug(context.getSource())))
|
||||||
.then(Commands.literal("close").executes(context -> closeDebug(context.getSource()))))
|
.then(Commands.literal("close").executes(context -> closeDebug(context.getSource()))))
|
||||||
|
.then(Commands.literal("yes").executes(context -> respondTrade(context.getSource(), true)))
|
||||||
|
.then(Commands.literal("no").executes(context -> respondTrade(context.getSource(), false)))
|
||||||
.then(Commands.argument("player", StringArgumentType.word())
|
.then(Commands.argument("player", StringArgumentType.word())
|
||||||
.suggests((context, builder) -> suggestPlayers(context.getSource(), builder))
|
.suggests((context, builder) -> suggestPlayers(context.getSource(), builder))
|
||||||
.executes(context -> startTrade(context.getSource(), StringArgumentType.getString(context, "player")))));
|
.executes(context -> requestTrade(context.getSource(), StringArgumentType.getString(context, "player")))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CompletableFuture<com.mojang.brigadier.suggestion.Suggestions> suggestPlayers(CommandSourceStack source, SuggestionsBuilder builder) {
|
private static CompletableFuture<com.mojang.brigadier.suggestion.Suggestions> suggestPlayers(CommandSourceStack source, SuggestionsBuilder builder) {
|
||||||
@@ -45,7 +47,7 @@ public final class TradeCommand {
|
|||||||
return builder.buildFuture();
|
return builder.buildFuture();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int startTrade(CommandSourceStack source, String targetName) {
|
private static int requestTrade(CommandSourceStack source, String targetName) {
|
||||||
if (!(source.getEntity() instanceof ServerPlayer player)) {
|
if (!(source.getEntity() instanceof ServerPlayer player)) {
|
||||||
source.sendFailure(Component.literal("Only players can start trades."));
|
source.sendFailure(Component.literal("Only players can start trades."));
|
||||||
return 0;
|
return 0;
|
||||||
@@ -62,15 +64,25 @@ public final class TradeCommand {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TradeManager.get(source.getServer()).startTrade(player, target)) {
|
if (!TradeManager.get(source.getServer()).requestTrade(player, target)) {
|
||||||
source.sendFailure(Component.literal("Trade could not be started. One of you is already trading."));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
source.sendSuccess(() -> Component.literal("Trade opened with " + target.getGameProfile().getName() + "."), false);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int respondTrade(CommandSourceStack source, boolean accept) {
|
||||||
|
if (!(source.getEntity() instanceof ServerPlayer player)) {
|
||||||
|
source.sendFailure(Component.literal("Only players can answer trade requests."));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean result = accept
|
||||||
|
? TradeManager.get(source.getServer()).acceptPendingTrade(player)
|
||||||
|
: TradeManager.get(source.getServer()).declinePendingTrade(player);
|
||||||
|
return result ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
private static int initDebug(CommandSourceStack source) {
|
private static int initDebug(CommandSourceStack source) {
|
||||||
if (!(source.getEntity() instanceof ServerPlayer player)) {
|
if (!(source.getEntity() instanceof ServerPlayer player)) {
|
||||||
source.sendFailure(Component.literal("Only players can start debug trades."));
|
source.sendFailure(Component.literal("Only players can start debug trades."));
|
||||||
|
|||||||
@@ -1,18 +1,52 @@
|
|||||||
package com.trunksbomb.trade.mod;
|
package com.trunksbomb.trade.mod;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
import com.trunksbomb.trade.mod.client.TradeClientState;
|
import com.trunksbomb.trade.mod.client.TradeClientState;
|
||||||
|
import com.trunksbomb.trade.mod.network.TradeRequestPayload;
|
||||||
|
import net.minecraft.client.KeyMapping;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.neoforged.api.distmarker.Dist;
|
import net.neoforged.api.distmarker.Dist;
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
import net.neoforged.bus.api.IEventBus;
|
||||||
import net.neoforged.fml.common.EventBusSubscriber;
|
|
||||||
import net.neoforged.fml.common.Mod;
|
import net.neoforged.fml.common.Mod;
|
||||||
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
|
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
|
||||||
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
@Mod(value = TradeMod.MODID, dist = Dist.CLIENT)
|
@Mod(value = TradeMod.MODID, dist = Dist.CLIENT)
|
||||||
@EventBusSubscriber(modid = TradeMod.MODID, value = Dist.CLIENT)
|
|
||||||
public class TradeClientMod {
|
public class TradeClientMod {
|
||||||
@SubscribeEvent
|
private static final KeyMapping REQUEST_TRADE = new KeyMapping(
|
||||||
static void onClientSetup(FMLClientSetupEvent event) {
|
"key.trade.request_trade",
|
||||||
event.enqueueWork(() -> TradeClientState.init(Minecraft.getInstance()));
|
InputConstants.Type.KEYSYM,
|
||||||
|
GLFW.GLFW_KEY_G,
|
||||||
|
"key.categories.gameplay");
|
||||||
|
|
||||||
|
public TradeClientMod(IEventBus modEventBus) {
|
||||||
|
modEventBus.addListener(this::registerKeyMappings);
|
||||||
|
NeoForge.EVENT_BUS.addListener(this::onClientTick);
|
||||||
|
TradeClientState.init(Minecraft.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerKeyMappings(RegisterKeyMappingsEvent event) {
|
||||||
|
event.register(REQUEST_TRADE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClientTick(ClientTickEvent.Post event) {
|
||||||
|
Minecraft minecraft = Minecraft.getInstance();
|
||||||
|
while (REQUEST_TRADE.consumeClick()) {
|
||||||
|
if (minecraft.player == null || minecraft.screen != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(minecraft.crosshairPickEntity instanceof Player target) || target == minecraft.player) {
|
||||||
|
minecraft.player.displayClientMessage(Component.literal("Look at a player to send a trade request."), true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketDistributor.sendToServer(new TradeRequestPayload(target.getId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/main/java/com/trunksbomb/trade/mod/TradeConfig.java
Normal file
24
src/main/java/com/trunksbomb/trade/mod/TradeConfig.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package com.trunksbomb.trade.mod;
|
||||||
|
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
|
||||||
|
public final class TradeConfig {
|
||||||
|
public static final ModConfigSpec SPEC;
|
||||||
|
private static final ModConfigSpec.IntValue TRADE_COMMAND_PROXIMITY;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
|
||||||
|
builder.push("trade");
|
||||||
|
TRADE_COMMAND_PROXIMITY = builder
|
||||||
|
.comment("Maximum distance in blocks to initiate or accept a trade request. 0 disables the distance check.")
|
||||||
|
.defineInRange("tradeCommandProximity", 0, 0, 1024);
|
||||||
|
builder.pop();
|
||||||
|
SPEC = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TradeConfig() {}
|
||||||
|
|
||||||
|
public static int tradeCommandProximity() {
|
||||||
|
return TRADE_COMMAND_PROXIMITY.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import com.trunksbomb.trade.mod.command.TradeCommand;
|
|||||||
import com.trunksbomb.trade.mod.network.TradeNetworking;
|
import com.trunksbomb.trade.mod.network.TradeNetworking;
|
||||||
import com.trunksbomb.trade.mod.trade.TradeManager;
|
import com.trunksbomb.trade.mod.trade.TradeManager;
|
||||||
import net.neoforged.bus.api.IEventBus;
|
import net.neoforged.bus.api.IEventBus;
|
||||||
|
import net.neoforged.fml.ModContainer;
|
||||||
import net.neoforged.fml.common.Mod;
|
import net.neoforged.fml.common.Mod;
|
||||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
import net.neoforged.neoforge.common.NeoForge;
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
@@ -18,9 +19,10 @@ public class TradeMod {
|
|||||||
public static final String MODID = "trade";
|
public static final String MODID = "trade";
|
||||||
public static final Logger LOGGER = LogUtils.getLogger();
|
public static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
public TradeMod(IEventBus modEventBus) {
|
public TradeMod(IEventBus modEventBus, ModContainer modContainer) {
|
||||||
modEventBus.addListener(this::commonSetup);
|
modEventBus.addListener(this::commonSetup);
|
||||||
modEventBus.addListener(this::registerPayloads);
|
modEventBus.addListener(this::registerPayloads);
|
||||||
|
modContainer.registerConfig(net.neoforged.fml.config.ModConfig.Type.SERVER, TradeConfig.SPEC);
|
||||||
NeoForge.EVENT_BUS.addListener(this::registerCommands);
|
NeoForge.EVENT_BUS.addListener(this::registerCommands);
|
||||||
NeoForge.EVENT_BUS.addListener(this::onPlayerLogout);
|
NeoForge.EVENT_BUS.addListener(this::onPlayerLogout);
|
||||||
NeoForge.EVENT_BUS.addListener(this::onItemPickup);
|
NeoForge.EVENT_BUS.addListener(this::onItemPickup);
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.trunksbomb.trade.mod.network;
|
package com.trunksbomb.trade.mod.network;
|
||||||
|
|
||||||
import com.trunksbomb.trade.mod.client.TradeScreen;
|
|
||||||
import com.trunksbomb.trade.mod.trade.TradeManager;
|
import com.trunksbomb.trade.mod.trade.TradeManager;
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.neoforged.neoforge.network.handling.DirectionalPayloadHandler;
|
import net.neoforged.neoforge.network.handling.DirectionalPayloadHandler;
|
||||||
@@ -25,6 +23,10 @@ public final class TradeNetworking {
|
|||||||
TradeActionPayload.TYPE,
|
TradeActionPayload.TYPE,
|
||||||
TradeActionPayload.STREAM_CODEC,
|
TradeActionPayload.STREAM_CODEC,
|
||||||
TradeNetworking::handleTradeActionServer);
|
TradeNetworking::handleTradeActionServer);
|
||||||
|
registrar.playToServer(
|
||||||
|
TradeRequestPayload.TYPE,
|
||||||
|
TradeRequestPayload.STREAM_CODEC,
|
||||||
|
TradeNetworking::handleTradeRequestServer);
|
||||||
registrar.playToServer(
|
registrar.playToServer(
|
||||||
DebugTradeControlPayload.TYPE,
|
DebugTradeControlPayload.TYPE,
|
||||||
DebugTradeControlPayload.STREAM_CODEC,
|
DebugTradeControlPayload.STREAM_CODEC,
|
||||||
@@ -32,31 +34,11 @@ public final class TradeNetworking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void handleTradeStateClient(TradeStatePayload payload, IPayloadContext context) {
|
private static void handleTradeStateClient(TradeStatePayload payload, IPayloadContext context) {
|
||||||
Minecraft minecraft = Minecraft.getInstance();
|
invokeClientState("showOrUpdate", new Class<?>[] {payload.view().getClass()}, payload.view());
|
||||||
if (minecraft.player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minecraft.screen instanceof TradeScreen screen && screen.sessionId().equals(payload.view().sessionId())) {
|
|
||||||
screen.updateView(payload.view());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
minecraft.setScreen(new TradeScreen(
|
|
||||||
new TradeScreen.TradeMenu(0, minecraft.player.getInventory(), payload.view()),
|
|
||||||
minecraft.player.getInventory(),
|
|
||||||
Component.literal("Trade")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleTradeCloseClient(TradeClosePayload payload, IPayloadContext context) {
|
private static void handleTradeCloseClient(TradeClosePayload payload, IPayloadContext context) {
|
||||||
Minecraft minecraft = Minecraft.getInstance();
|
invokeClientState("closeTrade", new Class<?>[] {java.util.UUID.class, Component.class}, payload.sessionId(), payload.reason());
|
||||||
if (minecraft.screen instanceof TradeScreen screen && screen.sessionId().equals(payload.sessionId())) {
|
|
||||||
minecraft.setScreen(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minecraft.player != null) {
|
|
||||||
minecraft.player.displayClientMessage(payload.reason(), false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleTradeActionServer(TradeActionPayload payload, IPayloadContext context) {
|
private static void handleTradeActionServer(TradeActionPayload payload, IPayloadContext context) {
|
||||||
@@ -65,6 +47,19 @@ public final class TradeNetworking {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void handleTradeRequestServer(TradeRequestPayload payload, IPayloadContext context) {
|
||||||
|
if (!(context.player() instanceof ServerPlayer player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player.serverLevel().getEntity(payload.targetEntityId()) instanceof ServerPlayer target)) {
|
||||||
|
player.sendSystemMessage(Component.literal("You must be looking at a player to trade."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TradeManager.get(player.server).requestTrade(player, target);
|
||||||
|
}
|
||||||
|
|
||||||
private static void handleDebugTradeControlServer(DebugTradeControlPayload payload, IPayloadContext context) {
|
private static void handleDebugTradeControlServer(DebugTradeControlPayload payload, IPayloadContext context) {
|
||||||
if (context.player() instanceof ServerPlayer player) {
|
if (context.player() instanceof ServerPlayer player) {
|
||||||
TradeManager.get(player.server).handleDebugControl(player, payload.sessionId(), payload.action(), payload.spec());
|
TradeManager.get(player.server).handleDebugControl(player, payload.sessionId(), payload.action(), payload.spec());
|
||||||
@@ -74,4 +69,13 @@ public final class TradeNetworking {
|
|||||||
private static void ignoreTradeStateServer(TradeStatePayload payload, IPayloadContext context) {}
|
private static void ignoreTradeStateServer(TradeStatePayload payload, IPayloadContext context) {}
|
||||||
|
|
||||||
private static void ignoreTradeCloseServer(TradeClosePayload payload, IPayloadContext context) {}
|
private static void ignoreTradeCloseServer(TradeClosePayload payload, IPayloadContext context) {}
|
||||||
|
|
||||||
|
private static void invokeClientState(String methodName, Class<?>[] parameterTypes, Object... arguments) {
|
||||||
|
try {
|
||||||
|
Class<?> clientState = Class.forName("com.trunksbomb.trade.mod.client.TradeClientState");
|
||||||
|
clientState.getMethod(methodName, parameterTypes).invoke(null, arguments);
|
||||||
|
} catch (ReflectiveOperationException exception) {
|
||||||
|
throw new RuntimeException("Failed to invoke TradeClientState#" + methodName, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.trunksbomb.trade.mod.network;
|
||||||
|
|
||||||
|
import com.trunksbomb.trade.mod.TradeMod;
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public record TradeRequestPayload(int targetEntityId) implements CustomPacketPayload {
|
||||||
|
public static final Type<TradeRequestPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(TradeMod.MODID, "trade_request"));
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, TradeRequestPayload> STREAM_CODEC = new StreamCodec<>() {
|
||||||
|
@Override
|
||||||
|
public void encode(RegistryFriendlyByteBuf buf, TradeRequestPayload value) {
|
||||||
|
buf.writeVarInt(value.targetEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TradeRequestPayload decode(RegistryFriendlyByteBuf buf) {
|
||||||
|
return new TradeRequestPayload(buf.readVarInt());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<? extends CustomPacketPayload> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package com.trunksbomb.trade.mod.trade;
|
package com.trunksbomb.trade.mod.trade;
|
||||||
|
|
||||||
|
import com.trunksbomb.trade.mod.TradeConfig;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.ClickEvent;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@@ -17,6 +20,7 @@ public class TradeManager {
|
|||||||
private final Map<UUID, UUID> sessionByPlayer = new HashMap<>();
|
private final Map<UUID, UUID> sessionByPlayer = new HashMap<>();
|
||||||
private final Map<UUID, DebugTradeSession> debugSessionsById = new HashMap<>();
|
private final Map<UUID, DebugTradeSession> debugSessionsById = new HashMap<>();
|
||||||
private final Map<UUID, UUID> debugSessionByPlayer = new HashMap<>();
|
private final Map<UUID, UUID> debugSessionByPlayer = new HashMap<>();
|
||||||
|
private final Map<UUID, TradeRequest> pendingRequestsByTarget = new HashMap<>();
|
||||||
|
|
||||||
public static TradeManager get(MinecraftServer server) {
|
public static TradeManager get(MinecraftServer server) {
|
||||||
return INSTANCES.computeIfAbsent(server, ignored -> new TradeManager());
|
return INSTANCES.computeIfAbsent(server, ignored -> new TradeManager());
|
||||||
@@ -37,6 +41,82 @@ public class TradeManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean requestTrade(ServerPlayer requester, ServerPlayer target) {
|
||||||
|
if (requester == target) {
|
||||||
|
requester.sendSystemMessage(Component.literal("You cannot trade with yourself."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTrading(requester) || isTrading(target)) {
|
||||||
|
requester.sendSystemMessage(Component.literal("Trade could not be started. One of you is already trading."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!withinTradeRange(requester, target)) {
|
||||||
|
requester.sendSystemMessage(Component.literal("That player is too far away to trade."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TradeRequest existing = pendingRequestsByTarget.get(target.getUUID());
|
||||||
|
if (existing != null && existing.requester().equals(requester.getUUID())) {
|
||||||
|
requester.sendSystemMessage(Component.literal("Trade request already sent to " + target.getGameProfile().getName() + "."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingRequestsByTarget.put(target.getUUID(), new TradeRequest(requester.getUUID(), target.getUUID()));
|
||||||
|
requester.sendSystemMessage(Component.literal("Trade request sent to " + target.getGameProfile().getName() + "."));
|
||||||
|
target.sendSystemMessage(Component.literal(requester.getGameProfile().getName() + " would like to trade with you: ")
|
||||||
|
.append(Component.literal("click to accept")
|
||||||
|
.withStyle(Style.EMPTY
|
||||||
|
.withColor(0x55FF55)
|
||||||
|
.withUnderlined(true)
|
||||||
|
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/trade yes")))));
|
||||||
|
target.sendSystemMessage(Component.literal("You can also use /trade yes or /trade no."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean acceptPendingTrade(ServerPlayer target) {
|
||||||
|
TradeRequest request = pendingRequestsByTarget.remove(target.getUUID());
|
||||||
|
if (request == null) {
|
||||||
|
target.sendSystemMessage(Component.literal("You have no pending trade request."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerPlayer requester = target.server.getPlayerList().getPlayer(request.requester());
|
||||||
|
if (requester == null) {
|
||||||
|
target.sendSystemMessage(Component.literal("That trade request is no longer valid."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!withinTradeRange(requester, target)) {
|
||||||
|
requester.sendSystemMessage(Component.literal(target.getGameProfile().getName() + " is too far away to trade."));
|
||||||
|
target.sendSystemMessage(Component.literal(requester.getGameProfile().getName() + " is too far away to trade."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!startTrade(requester, target)) {
|
||||||
|
target.sendSystemMessage(Component.literal("Trade could not be started. One of you is already trading."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean declinePendingTrade(ServerPlayer target) {
|
||||||
|
TradeRequest request = pendingRequestsByTarget.remove(target.getUUID());
|
||||||
|
if (request == null) {
|
||||||
|
target.sendSystemMessage(Component.literal("You have no pending trade request."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerPlayer requester = target.server.getPlayerList().getPlayer(request.requester());
|
||||||
|
if (requester != null) {
|
||||||
|
requester.sendSystemMessage(Component.literal(target.getGameProfile().getName() + " declined your trade request."));
|
||||||
|
}
|
||||||
|
target.sendSystemMessage(Component.literal("Trade request declined."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void handleAction(ServerPlayer player, UUID sessionId, TradeAction action, int slot, int amount) {
|
public void handleAction(ServerPlayer player, UUID sessionId, TradeAction action, int slot, int amount) {
|
||||||
TradeSession session = sessionsById.get(sessionId);
|
TradeSession session = sessionsById.get(sessionId);
|
||||||
if (session != null && session.involves(player)) {
|
if (session != null && session.involves(player)) {
|
||||||
@@ -124,6 +204,8 @@ public class TradeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void handleDisconnect(ServerPlayer player) {
|
public void handleDisconnect(ServerPlayer player) {
|
||||||
|
clearPendingRequests(player);
|
||||||
|
|
||||||
TradeSession session = getSession(player);
|
TradeSession session = getSession(player);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
cancel(session, Component.literal(player.getGameProfile().getName() + " left the game."));
|
cancel(session, Component.literal(player.getGameProfile().getName() + " left the game."));
|
||||||
@@ -306,4 +388,39 @@ public class TradeManager {
|
|||||||
debugSessionsById.remove(session.id());
|
debugSessionsById.remove(session.id());
|
||||||
debugSessionByPlayer.remove(session.player().getUUID());
|
debugSessionByPlayer.remove(session.player().getUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean withinTradeRange(ServerPlayer first, ServerPlayer second) {
|
||||||
|
int maxDistance = TradeConfig.tradeCommandProximity();
|
||||||
|
if (maxDistance <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (first.level() != second.level()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double maxDistanceSquared = maxDistance * maxDistance;
|
||||||
|
return first.distanceToSqr(second) <= maxDistanceSquared;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearPendingRequests(ServerPlayer player) {
|
||||||
|
TradeRequest direct = pendingRequestsByTarget.remove(player.getUUID());
|
||||||
|
if (direct != null) {
|
||||||
|
ServerPlayer requester = player.server.getPlayerList().getPlayer(direct.requester());
|
||||||
|
if (requester != null) {
|
||||||
|
requester.sendSystemMessage(Component.literal("Your trade request to " + player.getGameProfile().getName() + " expired."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingRequestsByTarget.entrySet().removeIf(entry -> {
|
||||||
|
if (!entry.getValue().requester().equals(player.getUUID())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ServerPlayer target = player.server.getPlayerList().getPlayer(entry.getValue().target());
|
||||||
|
if (target != null) {
|
||||||
|
target.sendSystemMessage(Component.literal("The trade request from " + player.getGameProfile().getName() + " expired."));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private record TradeRequest(UUID requester, UUID target) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"key.trade.request_trade": "Request Trade",
|
||||||
"trade.trade.title": "Trading Screen",
|
"trade.trade.title": "Trading Screen",
|
||||||
"trade.trade.offer": "Offer screen",
|
"trade.trade.offer": "Offer screen",
|
||||||
"trade.trade.confirm": "Confirmation screen"
|
"trade.trade.confirm": "Confirmation screen"
|
||||||
|
|||||||
Reference in New Issue
Block a user