package com.example.pvptrust; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.player.AttackEntityCallback; import net.minecraft.command.argument.EntityArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.command.CommandManager; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffects; import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import static net.minecraft.server.command.CommandManager.literal; public class PvPTrustMod implements ModInitializer { public static final String MOD_ID = "pvptrust"; private static final Map> TRUST_MAP = new ConcurrentHashMap<>(); private static final Map> TEMP_TRUST_EXPIRATIONS = new ConcurrentHashMap<>(); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final Path DATA_FILE = Path.of("config", MOD_ID + "_data.json"); private static final Path CONFIG_FILE = Path.of("config", MOD_ID + ".json"); private int tickCounter = 0; private static Config config; public static class Config { public String attackMessage; public int trustBonusRadius; public int trustBonusDurationSeconds; public int trustBonusAmplifier; public Config() { this.attackMessage = "That player is trusted! You can't attack them until you /untrust them."; this.trustBonusRadius = 20; this.trustBonusDurationSeconds = 16; this.trustBonusAmplifier = 0; } } @Override public void onInitialize() { loadConfig(); loadTrustData(); CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { dispatcher.register(literal("trust") .then(CommandManager.argument("target", EntityArgumentType.player()) .executes(context -> { ServerPlayerEntity player = context.getSource().getPlayer(); ServerPlayerEntity target = EntityArgumentType.getPlayer(context, "target"); addTrust(player, target); return 1; }))); dispatcher.register(literal("untrust") .then(CommandManager.argument("target", EntityArgumentType.player()) .executes(context -> { ServerPlayerEntity player = context.getSource().getPlayer(); ServerPlayerEntity target = EntityArgumentType.getPlayer(context, "target"); removeTrust(player, target); return 1; }))); dispatcher.register(literal("trustlist") .executes(context -> { ServerPlayerEntity player = context.getSource().getPlayer(); Set trusted = TRUST_MAP.getOrDefault(player.getUuid(), Collections.emptySet()); if (trusted.isEmpty()) { player.sendMessage(Text.literal("You don't trust anyone."), false); } else { StringBuilder trustedNames = new StringBuilder("Trusted players: "); for (UUID uuid : trusted) { ServerPlayerEntity trustedPlayer = player.getServer().getPlayerManager().getPlayer(uuid); if (trustedPlayer != null) { trustedNames.append(trustedPlayer.getName().getString()).append(", "); } } if (trustedNames.length() > 18) { trustedNames.setLength(trustedNames.length() - 2); } player.sendMessage(Text.literal(trustedNames.toString()), false); } return 1; })); dispatcher.register(literal("trustfor") .then(CommandManager.argument("target", EntityArgumentType.player()) .then(CommandManager.argument("seconds", IntegerArgumentType.integer(1)) .executes(context -> { ServerPlayerEntity player = context.getSource().getPlayer(); ServerPlayerEntity target = EntityArgumentType.getPlayer(context, "target"); int seconds = IntegerArgumentType.getInteger(context, "seconds"); addTrust(player, target); long expiryTime = System.currentTimeMillis() + (seconds * 1000L); TEMP_TRUST_EXPIRATIONS .computeIfAbsent(player.getUuid(), k -> new HashMap<>()) .put(target.getUuid(), expiryTime); player.sendMessage(Text.literal("You temporarily trust " + target.getName().getString() + " for " + seconds + " seconds."), false); target.sendMessage(Text.literal(player.getName().getString() + " trusts you temporarily."), false); return 1; })))); }); AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { if (entity instanceof PlayerEntity target) { Set trusted = TRUST_MAP.getOrDefault(player.getUuid(), Collections.emptySet()); if (trusted.contains(target.getUuid())) { player.sendMessage(Text.literal(config.attackMessage), false); return ActionResult.FAIL; } } return ActionResult.PASS; }); ServerTickEvents.START_SERVER_TICK.register(server -> { long currentTime = System.currentTimeMillis(); for (UUID playerId : new HashSet<>(TEMP_TRUST_EXPIRATIONS.keySet())) { Map trustMap = TEMP_TRUST_EXPIRATIONS.get(playerId); if (trustMap == null) continue; for (UUID targetId : new HashSet<>(trustMap.keySet())) { if (trustMap.get(targetId) <= currentTime) { trustMap.remove(targetId); TRUST_MAP.getOrDefault(playerId, new HashSet<>()).remove(targetId); ServerPlayerEntity player = server.getPlayerManager().getPlayer(playerId); ServerPlayerEntity target = server.getPlayerManager().getPlayer(targetId); if (player != null) { player.sendMessage(Text.literal("Temporary trust for " + (target != null ? target.getName().getString() : targetId.toString()) + " has expired."), false); } if (target != null && player != null) { target.sendMessage(Text.literal(player.getName().getString() + "'s temporary trust has expired."), false); } } } if (trustMap.isEmpty()) { TEMP_TRUST_EXPIRATIONS.remove(playerId); } } }); ServerTickEvents.START_SERVER_TICK.register(server -> { tickCounter++; if (tickCounter < 20) return; tickCounter = 0; int radius = config.trustBonusRadius; int durationTicks = config.trustBonusDurationSeconds * 20; int amplifier = config.trustBonusAmplifier; for (ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) { Set trustedPlayers = TRUST_MAP.getOrDefault(player.getUuid(), Collections.emptySet()); for (UUID trustedUUID : trustedPlayers) { ServerPlayerEntity trustedPlayer = server.getPlayerManager().getPlayer(trustedUUID); if (trustedPlayer != null) { Set trustedOfTrusted = TRUST_MAP.getOrDefault(trustedUUID, Collections.emptySet()); if (trustedOfTrusted.contains(player.getUuid())) { double distanceSq = player.squaredDistanceTo(trustedPlayer); if (distanceSq <= radius * radius) { StatusEffectInstance resistance = new StatusEffectInstance(StatusEffects.RESISTANCE, durationTicks, amplifier, false, true, false); if (!player.hasStatusEffect(StatusEffects.RESISTANCE)) { player.addStatusEffect(resistance); } if (!trustedPlayer.hasStatusEffect(StatusEffects.RESISTANCE)) { trustedPlayer.addStatusEffect(resistance); } } } } } } }); } private void addTrust(ServerPlayerEntity player, ServerPlayerEntity target) { if (target == null) { player.sendMessage(Text.literal("Player not found."), false); return; } else if (player.getUuid().equals(target.getUuid())) { player.sendMessage(Text.literal("You can't trust yourself."), false); return; } TRUST_MAP.computeIfAbsent(player.getUuid(), k -> new HashSet<>()).add(target.getUuid()); target.sendMessage(Text.literal(player.getName().getString() + " now trusts you."), false); saveTrustData(); } private void removeTrust(ServerPlayerEntity player, ServerPlayerEntity target) { if (target == null) { player.sendMessage(Text.literal("Player not found."), false); return; } else if (player.getUuid().equals(target.getUuid())) { player.sendMessage(Text.literal("You can't untrust yourself."), false); return; } boolean removed = TRUST_MAP.computeIfPresent(player.getUuid(), (uuid, trustedSet) -> { trustedSet.remove(target.getUuid()); return trustedSet.isEmpty() ? null : trustedSet; }) != null; if (removed) { target.sendMessage(Text.literal(player.getName().getString() + " no longer trusts you."), false); saveTrustData(); } } private void loadTrustData() { try { if (Files.exists(DATA_FILE)) { try (Reader reader = Files.newBufferedReader(DATA_FILE)) { JsonObject json = JsonParser.parseReader(reader).getAsJsonObject(); for (String key : json.keySet()) { UUID playerId = UUID.fromString(key); Set trustedPlayers = new HashSet<>(); for (var element : json.getAsJsonArray(key)) { trustedPlayers.add(UUID.fromString(element.getAsString())); } TRUST_MAP.put(playerId, trustedPlayers); } } } } catch (IOException e) { System.err.println("Failed to load trust data: " + e.getMessage()); e.printStackTrace(); } } private void saveTrustData() { try { JsonObject json = new JsonObject(); for (Map.Entry> entry : TRUST_MAP.entrySet()) { json.add(entry.getKey().toString(), GSON.toJsonTree(entry.getValue())); } Files.createDirectories(DATA_FILE.getParent()); try (Writer writer = Files.newBufferedWriter(DATA_FILE)) { GSON.toJson(json, writer); } } catch (IOException e) { System.err.println("Failed to save trust data: " + e.getMessage()); e.printStackTrace(); } } private void loadConfig() { try { if (Files.exists(CONFIG_FILE)) { try (Reader reader = Files.newBufferedReader(CONFIG_FILE)) { config = GSON.fromJson(reader, Config.class); } } else { config = new Config(); // Default values are set in the constructor saveConfig(); } } catch (IOException e) { System.err.println("Failed to load config: " + e.getMessage()); e.printStackTrace(); config = new Config(); // Fallback to default config } } private void saveConfig() { try { Files.createDirectories(CONFIG_FILE.getParent()); try (Writer writer = Files.newBufferedWriter(CONFIG_FILE)) { GSON.toJson(config, writer); } } catch (IOException e) { System.err.println("Failed to save config: " + e.getMessage()); e.printStackTrace(); } } }