Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
511
src/main/java/com/tiedup/remake/commands/SocialCommand.java
Normal file
511
src/main/java/com/tiedup/remake/commands/SocialCommand.java
Normal file
@@ -0,0 +1,511 @@
|
||||
package com.tiedup.remake.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.tiedup.remake.core.TiedUpMod;
|
||||
import com.tiedup.remake.state.SocialData;
|
||||
import com.tiedup.remake.util.MessageDispatcher;
|
||||
import java.util.*;
|
||||
import java.util.Optional;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
/**
|
||||
* Social and RP commands for Phase 18.
|
||||
*
|
||||
* Commands:
|
||||
* /blockplayer <player> - Block a player from interacting with you
|
||||
* /unblockplayer <player> - Unblock a player
|
||||
* /checkblocked <player> - Check if a player has blocked you
|
||||
* /norp - Announce non-consent to current RP (cooldown 45s)
|
||||
* /me <action> - Roleplay action message in local area
|
||||
* /pm <player> <message> - Private message to a player
|
||||
* /talkarea [distance] - Set local chat area distance
|
||||
*
|
||||
* These commands are usable while tied up.
|
||||
*
|
||||
* Data persistence: Block lists and talk area settings are stored in SocialData
|
||||
* (SavedData) and persist across server restarts.
|
||||
*/
|
||||
public class SocialCommand {
|
||||
|
||||
// Cooldowns for /norp (UUID -> last use timestamp)
|
||||
// Note: Cooldowns are intentionally NOT persisted - they reset on server restart
|
||||
private static final Map<UUID, Long> NORP_COOLDOWNS = new HashMap<>();
|
||||
private static final long NORP_COOLDOWN_MS = 45000; // 45 seconds
|
||||
|
||||
/** Remove player cooldown on disconnect to prevent memory leak. */
|
||||
public static void cleanupPlayer(UUID playerId) {
|
||||
NORP_COOLDOWNS.remove(playerId);
|
||||
}
|
||||
|
||||
public static void register(
|
||||
CommandDispatcher<CommandSourceStack> dispatcher
|
||||
) {
|
||||
dispatcher.register(createBlockPlayerCommand());
|
||||
dispatcher.register(createUnblockPlayerCommand());
|
||||
dispatcher.register(createCheckBlockedCommand());
|
||||
dispatcher.register(createNoRPCommand());
|
||||
dispatcher.register(createMeCommand());
|
||||
dispatcher.register(createPMCommand());
|
||||
dispatcher.register(createTalkAreaCommand());
|
||||
dispatcher.register(createTalkInfoCommand());
|
||||
}
|
||||
|
||||
// === Command Builders (for use as subcommands of /tiedup) ===
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createBlockPlayerCommand() {
|
||||
return Commands.literal("blockplayer").then(
|
||||
Commands.argument("player", EntityArgument.player()).executes(
|
||||
SocialCommand::blockPlayer
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createUnblockPlayerCommand() {
|
||||
return Commands.literal("unblockplayer").then(
|
||||
Commands.argument("player", EntityArgument.player()).executes(
|
||||
SocialCommand::unblockPlayer
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createCheckBlockedCommand() {
|
||||
return Commands.literal("checkblocked").then(
|
||||
Commands.argument("player", EntityArgument.player()).executes(
|
||||
SocialCommand::checkBlocked
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createNoRPCommand() {
|
||||
return Commands.literal("norp").executes(SocialCommand::noRP);
|
||||
}
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createMeCommand() {
|
||||
return Commands.literal("me").then(
|
||||
Commands.argument(
|
||||
"action",
|
||||
StringArgumentType.greedyString()
|
||||
).executes(SocialCommand::meAction)
|
||||
);
|
||||
}
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createPMCommand() {
|
||||
return Commands.literal("pm").then(
|
||||
Commands.argument("player", EntityArgument.player()).then(
|
||||
Commands.argument(
|
||||
"message",
|
||||
StringArgumentType.greedyString()
|
||||
).executes(SocialCommand::privateMessage)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createTalkAreaCommand() {
|
||||
return Commands.literal("talkarea")
|
||||
.executes(ctx -> setTalkArea(ctx, 0)) // Disable
|
||||
.then(
|
||||
Commands.argument(
|
||||
"distance",
|
||||
IntegerArgumentType.integer(1, 100)
|
||||
).executes(ctx ->
|
||||
setTalkArea(
|
||||
ctx,
|
||||
IntegerArgumentType.getInteger(ctx, "distance")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
||||
CommandSourceStack
|
||||
> createTalkInfoCommand() {
|
||||
return Commands.literal("talkinfo").executes(SocialCommand::talkInfo);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Block System
|
||||
// ========================================
|
||||
|
||||
private static int blockPlayer(CommandContext<CommandSourceStack> context)
|
||||
throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (playerOpt.isEmpty()) return 0;
|
||||
ServerPlayer player = playerOpt.get();
|
||||
|
||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
||||
|
||||
if (player.getUUID().equals(target.getUUID())) {
|
||||
source.sendFailure(Component.literal("You cannot block yourself"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SocialData data = SocialData.get(player.serverLevel());
|
||||
|
||||
if (data.isBlocked(player.getUUID(), target.getUUID())) {
|
||||
source.sendFailure(
|
||||
Component.literal(
|
||||
target.getName().getString() + " is already blocked"
|
||||
)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
data.addBlock(player.getUUID(), target.getUUID());
|
||||
source.sendSuccess(
|
||||
() ->
|
||||
Component.literal("§aBlocked " + target.getName().getString()),
|
||||
false
|
||||
);
|
||||
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[SOCIAL] {} blocked {}",
|
||||
player.getName().getString(),
|
||||
target.getName().getString()
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int unblockPlayer(CommandContext<CommandSourceStack> context)
|
||||
throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (playerOpt.isEmpty()) return 0;
|
||||
ServerPlayer player = playerOpt.get();
|
||||
|
||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
||||
|
||||
SocialData data = SocialData.get(player.serverLevel());
|
||||
|
||||
if (!data.isBlocked(player.getUUID(), target.getUUID())) {
|
||||
source.sendFailure(
|
||||
Component.literal(
|
||||
target.getName().getString() + " is not blocked"
|
||||
)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
data.removeBlock(player.getUUID(), target.getUUID());
|
||||
source.sendSuccess(
|
||||
() ->
|
||||
Component.literal(
|
||||
"§aUnblocked " + target.getName().getString()
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int checkBlocked(CommandContext<CommandSourceStack> context)
|
||||
throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (playerOpt.isEmpty()) return 0;
|
||||
ServerPlayer player = playerOpt.get();
|
||||
|
||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
||||
|
||||
SocialData data = SocialData.get(player.serverLevel());
|
||||
boolean blocked = data.isBlocked(target.getUUID(), player.getUUID());
|
||||
|
||||
if (blocked) {
|
||||
source.sendSuccess(
|
||||
() ->
|
||||
Component.literal(
|
||||
"§c" + target.getName().getString() + " has blocked you"
|
||||
),
|
||||
false
|
||||
);
|
||||
} else {
|
||||
source.sendSuccess(
|
||||
() ->
|
||||
Component.literal(
|
||||
"§a" +
|
||||
target.getName().getString() +
|
||||
" has not blocked you"
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player is blocked by another.
|
||||
* Can be used by other systems to check interaction permissions.
|
||||
*
|
||||
* @param level The server level to get SocialData from
|
||||
* @param blocker The player who may have blocked
|
||||
* @param blocked The player who may be blocked
|
||||
* @return true if blocker has blocked blocked
|
||||
*/
|
||||
public static boolean isBlocked(
|
||||
ServerLevel level,
|
||||
UUID blocker,
|
||||
UUID blocked
|
||||
) {
|
||||
return SocialData.get(level).isBlocked(blocker, blocked);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// RP Commands
|
||||
// ========================================
|
||||
|
||||
private static int noRP(CommandContext<CommandSourceStack> context)
|
||||
throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (playerOpt.isEmpty()) return 0;
|
||||
ServerPlayer player = playerOpt.get();
|
||||
|
||||
// Check cooldown
|
||||
long now = System.currentTimeMillis();
|
||||
Long lastUse = NORP_COOLDOWNS.get(player.getUUID());
|
||||
if (lastUse != null && now - lastUse < NORP_COOLDOWN_MS) {
|
||||
long remaining = (NORP_COOLDOWN_MS - (now - lastUse)) / 1000;
|
||||
source.sendFailure(
|
||||
Component.literal(
|
||||
"Please wait " +
|
||||
remaining +
|
||||
" seconds before using /norp again"
|
||||
)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set cooldown
|
||||
NORP_COOLDOWNS.put(player.getUUID(), now);
|
||||
|
||||
// Broadcast to all players
|
||||
Component message = Component.literal("")
|
||||
.append(
|
||||
Component.literal("[NoRP] ").withStyle(
|
||||
ChatFormatting.RED,
|
||||
ChatFormatting.BOLD
|
||||
)
|
||||
)
|
||||
.append(
|
||||
Component.literal(player.getName().getString()).withStyle(
|
||||
ChatFormatting.YELLOW
|
||||
)
|
||||
)
|
||||
.append(
|
||||
Component.literal(
|
||||
" has announced non-consent to current RP"
|
||||
).withStyle(ChatFormatting.RED)
|
||||
);
|
||||
|
||||
// Broadcast to all players (earplug-aware)
|
||||
for (ServerPlayer p : player.server.getPlayerList().getPlayers()) {
|
||||
MessageDispatcher.sendTo(p, message);
|
||||
}
|
||||
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[SOCIAL] {} used /norp",
|
||||
player.getName().getString()
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int meAction(CommandContext<CommandSourceStack> context)
|
||||
throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (playerOpt.isEmpty()) return 0;
|
||||
ServerPlayer player = playerOpt.get();
|
||||
|
||||
String action = StringArgumentType.getString(context, "action");
|
||||
|
||||
// Get talk area for local chat
|
||||
SocialData data = SocialData.get(player.serverLevel());
|
||||
int talkArea = data.getTalkArea(player.getUUID());
|
||||
|
||||
Component message = Component.literal("")
|
||||
.append(
|
||||
Component.literal("* ").withStyle(ChatFormatting.LIGHT_PURPLE)
|
||||
)
|
||||
.append(
|
||||
Component.literal(player.getName().getString()).withStyle(
|
||||
ChatFormatting.LIGHT_PURPLE
|
||||
)
|
||||
)
|
||||
.append(
|
||||
Component.literal(" " + action).withStyle(
|
||||
ChatFormatting.LIGHT_PURPLE
|
||||
)
|
||||
);
|
||||
|
||||
if (talkArea > 0) {
|
||||
// Local chat - send to nearby players (earplug-aware)
|
||||
AABB area = player.getBoundingBox().inflate(talkArea);
|
||||
List<ServerPlayer> nearby = player
|
||||
.serverLevel()
|
||||
.getEntitiesOfClass(ServerPlayer.class, area);
|
||||
for (ServerPlayer p : nearby) {
|
||||
MessageDispatcher.sendTo(p, message);
|
||||
}
|
||||
} else {
|
||||
// Global chat (earplug-aware)
|
||||
for (ServerPlayer p : player.server.getPlayerList().getPlayers()) {
|
||||
MessageDispatcher.sendTo(p, message);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int privateMessage(
|
||||
CommandContext<CommandSourceStack> context
|
||||
) throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> senderOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (senderOpt.isEmpty()) return 0;
|
||||
ServerPlayer sender = senderOpt.get();
|
||||
|
||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
||||
String message = StringArgumentType.getString(context, "message");
|
||||
|
||||
// Check if blocked
|
||||
SocialData data = SocialData.get(sender.serverLevel());
|
||||
if (data.isBlocked(target.getUUID(), sender.getUUID())) {
|
||||
source.sendFailure(
|
||||
Component.literal("This player has blocked you")
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send to target (earplug-aware)
|
||||
Component toTarget = Component.literal("")
|
||||
.append(
|
||||
Component.literal(
|
||||
"[PM from " + sender.getName().getString() + "] "
|
||||
).withStyle(ChatFormatting.LIGHT_PURPLE)
|
||||
)
|
||||
.append(Component.literal(message).withStyle(ChatFormatting.WHITE));
|
||||
MessageDispatcher.sendFrom(sender, target, toTarget);
|
||||
|
||||
// Confirm to sender (always show - they're the one sending)
|
||||
Component toSender = Component.literal("")
|
||||
.append(
|
||||
Component.literal(
|
||||
"[PM to " + target.getName().getString() + "] "
|
||||
).withStyle(ChatFormatting.GRAY)
|
||||
)
|
||||
.append(Component.literal(message).withStyle(ChatFormatting.WHITE));
|
||||
MessageDispatcher.sendSystemMessage(sender, toSender);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Talk Area
|
||||
// ========================================
|
||||
|
||||
private static int setTalkArea(
|
||||
CommandContext<CommandSourceStack> context,
|
||||
int distance
|
||||
) throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (playerOpt.isEmpty()) return 0;
|
||||
ServerPlayer player = playerOpt.get();
|
||||
|
||||
SocialData data = SocialData.get(player.serverLevel());
|
||||
data.setTalkArea(player.getUUID(), distance);
|
||||
|
||||
if (distance == 0) {
|
||||
source.sendSuccess(
|
||||
() -> Component.literal("§aTalk area disabled (global chat)"),
|
||||
false
|
||||
);
|
||||
} else {
|
||||
source.sendSuccess(
|
||||
() ->
|
||||
Component.literal(
|
||||
"§aTalk area set to " + distance + " blocks"
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int talkInfo(CommandContext<CommandSourceStack> context)
|
||||
throws CommandSyntaxException {
|
||||
CommandSourceStack source = context.getSource();
|
||||
|
||||
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
||||
source
|
||||
);
|
||||
if (playerOpt.isEmpty()) return 0;
|
||||
ServerPlayer player = playerOpt.get();
|
||||
|
||||
SocialData data = SocialData.get(player.serverLevel());
|
||||
int talkArea = data.getTalkArea(player.getUUID());
|
||||
|
||||
if (talkArea == 0) {
|
||||
source.sendSuccess(
|
||||
() ->
|
||||
Component.literal("Talk area: §edisabled §7(global chat)"),
|
||||
false
|
||||
);
|
||||
} else {
|
||||
source.sendSuccess(
|
||||
() -> Component.literal("Talk area: §e" + talkArea + " blocks"),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user