diff --git a/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java b/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java index 35ceb67..7b1bd2c 100644 --- a/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java +++ b/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java @@ -34,6 +34,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -143,6 +144,12 @@ public class Claim implements IPermissionContainer { return this.owner; } + public Optional getOwnerPlayer() { + if (this.getOwner() != null) + return Optional.ofNullable(this.world.getServer().getPlayerManager().getPlayer(this.getOwner())); + return Optional.empty(); + } + public ServerWorld getWorld() { return this.world; } diff --git a/common/src/main/java/io/github/flemmli97/flan/claim/ClaimStorage.java b/common/src/main/java/io/github/flemmli97/flan/claim/ClaimStorage.java index 4d66125..969d9a5 100644 --- a/common/src/main/java/io/github/flemmli97/flan/claim/ClaimStorage.java +++ b/common/src/main/java/io/github/flemmli97/flan/claim/ClaimStorage.java @@ -89,6 +89,7 @@ public class ClaimStorage { Flan.log("Creating new claim {}", claim); this.addClaim(claim); data.addDisplayClaim(claim, EnumDisplayType.MAIN, player.getBlockPos().getY()); + data.updateScoreboard(); player.sendMessage(PermHelper.simpleColoredText(ConfigHandler.lang.claimCreateSuccess, Formatting.GOLD), false); player.sendMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.lang.claimBlocksFormat, data.getClaimBlocks(), data.getAdditionalClaims(), data.usedClaimBlocks()), Formatting.GOLD), false); @@ -123,8 +124,6 @@ public class ClaimStorage { return false; } Flan.log("Try deleting claim {}", claim); - if (updateClaim) - claim.remove(); int[] pos = getChunkPos(claim); for (int x = pos[0]; x <= pos[1]; x++) for (int z = pos[2]; z <= pos[3]; z++) { @@ -137,13 +136,21 @@ public class ClaimStorage { } this.playerClaimMap.getOrDefault(claim.getOwner(), new HashSet<>()).remove(claim); this.dirty.add(claim.getOwner()); + if (updateClaim) { + claim.remove(); + claim.getOwnerPlayer().ifPresent(o -> PlayerClaimData.get(o).updateScoreboard()); + } return this.claimUUIDMap.remove(claim.getClaimID()) != null; } public void toggleAdminClaim(ServerPlayerEntity player, Claim claim, boolean toggle) { Flan.log("Set claim {} to an admin claim", claim); this.deleteClaim(claim, false, EnumEditMode.DEFAULT, player.getServerWorld()); + if (toggle) + claim.getOwnerPlayer().ifPresent(o -> PlayerClaimData.get(o).updateScoreboard()); claim.toggleAdminClaim(player, toggle); + if (!toggle) + PlayerClaimData.get(player).updateScoreboard(); this.addClaim(claim); } @@ -163,22 +170,20 @@ public class ClaimStorage { } int diff = newClaim.getPlane() - claim.getPlane(); PlayerClaimData data = PlayerClaimData.get(player); - IPlayerData newData = null; - boolean enoughBlocks = false; - if (player.getUuid().equals(claim.getOwner()) || claim.isAdminClaim()) { - enoughBlocks = claim.isAdminClaim() || data.canUseClaimBlocks(diff); - newData = data; - } else { - ServerPlayerEntity other = player.getServer().getPlayerManager().getPlayer(claim.getOwner()); - newData = other != null ? PlayerClaimData.get(other) : new OfflinePlayerData(player.getServer(), claim.getOwner()); - enoughBlocks = newData.canUseClaimBlocks(diff); - } + IPlayerData newData = claim.getOwnerPlayer().map(o -> { + if (o == player || claim.isAdminClaim()) + return data; + return (IPlayerData) PlayerClaimData.get(o); + }).orElse(new OfflinePlayerData(player.getServer(), claim.getOwner())); + boolean enoughBlocks = claim.isAdminClaim() || newData.canUseClaimBlocks(diff); if (enoughBlocks) { Flan.log("Resizing claim {}", claim); this.deleteClaim(claim, false, EnumEditMode.DEFAULT, player.getServerWorld()); claim.copySizes(newClaim); this.addClaim(claim); data.addDisplayClaim(claim, EnumDisplayType.MAIN, player.getBlockPos().getY()); + if (newData instanceof PlayerClaimData) + ((PlayerClaimData) newData).updateScoreboard(); player.sendMessage(PermHelper.simpleColoredText(ConfigHandler.lang.resizeSuccess, Formatting.GOLD), false); player.sendMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.lang.claimBlocksFormat, newData.getClaimBlocks(), newData.getAdditionalClaims(), newData.usedClaimBlocks()), Formatting.GOLD), false); @@ -233,6 +238,7 @@ public class ClaimStorage { return old; }); this.dirty.add(claim.getOwner()); + claim.getOwnerPlayer().ifPresent(o -> PlayerClaimData.get(o).updateScoreboard()); claim.transferOwner(newOwner); this.playerClaimMap.merge(claim.getOwner(), Sets.newHashSet(claim), (old, val) -> { old.add(claim); diff --git a/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java b/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java index dde1bf7..6f4dc97 100644 --- a/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java +++ b/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java @@ -12,8 +12,10 @@ import io.github.flemmli97.flan.claim.ParticleIndicators; import io.github.flemmli97.flan.claim.PermHelper; import io.github.flemmli97.flan.config.ConfigHandler; import io.github.flemmli97.flan.event.EntityInteractEvents; +import io.github.flemmli97.flan.scoreboard.ClaimCriterias; import net.minecraft.block.BlockState; import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; +import net.minecraft.scoreboard.ScoreboardCriterion; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; @@ -44,6 +46,8 @@ import java.util.function.Consumer; public class PlayerClaimData implements IPlayerData { private int claimBlocks, additionalClaimBlocks, confirmTick, actionCooldown; + //Scoreboard tracking + private int usedBlocks; private int lastBlockTick, trappedTick = -1, deathPickupTick; private Vec3d trappedPos; @@ -81,14 +85,15 @@ public class PlayerClaimData implements IPlayerData { public void setClaimBlocks(int amount) { this.claimBlocks = amount; + updateScoreFor(this.player, ClaimCriterias.AMOUNT, this.claimBlocks + this.additionalClaimBlocks); + updateScoreFor(this.player, ClaimCriterias.FREE, this.claimBlocks + this.additionalClaimBlocks - this.usedBlocks); this.dirty = true; } public boolean addClaimBlocks(int amount) { if (this.claimBlocks + amount > ConfigHandler.config.maxClaimBlocks) return false; - this.claimBlocks += amount; - this.dirty = true; + this.setClaimBlocks(this.claimBlocks + amount); return true; } @@ -99,6 +104,8 @@ public class PlayerClaimData implements IPlayerData { public void setAdditionalClaims(int amount) { this.additionalClaimBlocks = Math.max(0, amount); + updateScoreFor(this.player, ClaimCriterias.AMOUNT, this.claimBlocks + this.additionalClaimBlocks); + updateScoreFor(this.player, ClaimCriterias.FREE, this.claimBlocks + this.additionalClaimBlocks - this.usedBlocks); this.dirty = true; } @@ -321,6 +328,38 @@ public class PlayerClaimData implements IPlayerData { this.player.sendMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.lang.unlockDropsCmd, "/flan unlockDrops"), Formatting.GOLD), false); } + public void updateScoreboard() { + int claims = this.updateClaimScores(); + updateScoreFor(this.player, ClaimCriterias.USED, this.usedBlocks); + updateScoreFor(this.player, ClaimCriterias.FREE, this.claimBlocks + this.additionalClaimBlocks - this.usedBlocks); + updateScoreFor(this.player, ClaimCriterias.CLAIMS, claims); + } + + private int updateClaimScores() { + int usedClaimsBlocks = 0; + int claimsAmount = 0; + for (ServerWorld world : this.player.getServer().getWorlds()) { + Collection claims = ClaimStorage.get(world).allClaimsFromPlayer(this.player.getUuid()); + if (claims != null) { + usedClaimsBlocks += claims.stream().filter(claim -> !claim.isAdminClaim()).mapToInt(Claim::getPlane).sum(); + claimsAmount += claims.size(); + } + } + this.usedBlocks = usedClaimsBlocks; + return claimsAmount; + } + + private int calculateUsedClaimBlocks() { + int usedClaimsBlocks = 0; + for (ServerWorld world : this.player.getServer().getWorlds()) { + Collection claims = ClaimStorage.get(world).allClaimsFromPlayer(this.player.getUuid()); + if (claims != null) { + usedClaimsBlocks += claims.stream().filter(claim -> !claim.isAdminClaim()).mapToInt(Claim::getPlane).sum(); + } + } + return usedClaimsBlocks; + } + public void save(MinecraftServer server) { Flan.log("Saving player data for player {} with uuid {}", this.player.getName(), this.player.getUuid()); File dir = new File(server.getSavePath(WorldSavePath.PLAYERDATA).toFile(), "/claimData/"); @@ -364,6 +403,7 @@ public class PlayerClaimData implements IPlayerData { } FileReader reader = new FileReader(file); JsonObject obj = ConfigHandler.GSON.fromJson(reader, JsonObject.class); + reader.close(); Flan.debug("Read following json data {} from file {}", obj, file.getName()); this.claimBlocks = obj.get("ClaimBlocks").getAsInt(); this.additionalClaimBlocks = obj.get("AdditionalBlocks").getAsInt(); @@ -379,12 +419,19 @@ public class PlayerClaimData implements IPlayerData { }); } }); - reader.close(); + updateScoreFor(this.player, ClaimCriterias.AMOUNT, this.claimBlocks + this.additionalClaimBlocks); + this.updateClaimScores(); } catch (IOException e) { e.printStackTrace(); } } + public static void updateScoreFor(ServerPlayerEntity player, ScoreboardCriterion criterion, int val) { + player.getScoreboard().forEachScore(criterion, player.getEntityName(), (scoreboardPlayerScore) -> { + scoreboardPlayerScore.setScore(val); + }); + } + public static void editForOfflinePlayer(MinecraftServer server, UUID uuid, int additionalClaimBlocks) { Flan.log("Adding {} addional claimblocks for offline player with uuid {}", additionalClaimBlocks, uuid); File dir = new File(server.getSavePath(WorldSavePath.PLAYERDATA).toFile(), "/claimData/"); @@ -410,17 +457,6 @@ public class PlayerClaimData implements IPlayerData { } } - - private int calculateUsedClaimBlocks() { - int usedClaimsBlocks = 0; - for (ServerWorld world : this.player.getServer().getWorlds()) { - Collection claims = ClaimStorage.get(world).allClaimsFromPlayer(this.player.getUuid()); - if (claims != null) - usedClaimsBlocks += claims.stream().filter(claim -> !claim.isAdminClaim()).mapToInt(Claim::getPlane).sum(); - } - return usedClaimsBlocks; - } - public static boolean readGriefPreventionPlayerData(MinecraftServer server, ServerCommandSource src) { Flan.log("Reading grief prevention data"); File griefPrevention = server.getSavePath(WorldSavePath.ROOT).resolve("plugins/GriefPreventionData/PlayerData").toFile(); diff --git a/common/src/main/java/io/github/flemmli97/flan/scoreboard/ClaimCriterias.java b/common/src/main/java/io/github/flemmli97/flan/scoreboard/ClaimCriterias.java new file mode 100644 index 0000000..f792f08 --- /dev/null +++ b/common/src/main/java/io/github/flemmli97/flan/scoreboard/ClaimCriterias.java @@ -0,0 +1,28 @@ +package io.github.flemmli97.flan.scoreboard; + +import net.minecraft.scoreboard.ScoreboardCriterion; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +public class ClaimCriterias { + + public static ScoreboardCriterion AMOUNT = create("flan:total_claimblocks", true, ScoreboardCriterion.RenderType.INTEGER); + public static ScoreboardCriterion USED = create("flan:used_claimblocks", true, ScoreboardCriterion.RenderType.INTEGER); + public static ScoreboardCriterion FREE = create("flan:free_claimblocks", true, ScoreboardCriterion.RenderType.INTEGER); + public static ScoreboardCriterion CLAIMS = create("flan:claim_number", true, ScoreboardCriterion.RenderType.INTEGER); + + /** + * Just reflection cause its only called once during init + */ + private static ScoreboardCriterion create(String name, boolean readOnly, ScoreboardCriterion.RenderType renderType) { + try { + Constructor cons = ScoreboardCriterion.class.getDeclaredConstructor(String.class, boolean.class, ScoreboardCriterion.RenderType.class); + cons.setAccessible(true); + return cons.newInstance(name, readOnly, renderType); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/fabric/src/main/java/io/github/flemmli97/flan/FlanFabric.java b/fabric/src/main/java/io/github/flemmli97/flan/FlanFabric.java index b7a8ab5..3e62949 100644 --- a/fabric/src/main/java/io/github/flemmli97/flan/FlanFabric.java +++ b/fabric/src/main/java/io/github/flemmli97/flan/FlanFabric.java @@ -16,6 +16,7 @@ import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; import net.fabricmc.fabric.api.event.player.UseEntityCallback; import net.fabricmc.fabric.api.event.player.UseItemCallback; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.server.MinecraftServer; public class FlanFabric implements ModInitializer { @@ -26,9 +27,7 @@ public class FlanFabric implements ModInitializer { UseEntityCallback.EVENT.register(EntityInteractEvents::useAtEntity); AttackEntityCallback.EVENT.register(EntityInteractEvents::attackEntity); UseItemCallback.EVENT.register(ItemInteractEvents::useItem); - ServerLifecycleEvents.SERVER_STARTING.register(ConfigHandler::serverLoad); - ServerLifecycleEvents.SERVER_STARTING.register(ObjectToPermissionMap::reload); - ServerLifecycleEvents.SERVER_STARTING.register(Flan::lockRegistry); + ServerLifecycleEvents.SERVER_STARTING.register(FlanFabric::serverLoad); CommandRegistrationCallback.EVENT.register(CommandClaim::register); @@ -38,4 +37,10 @@ public class FlanFabric implements ModInitializer { if (Flan.playerAbilityLib) PlayerAbilityEvents.register(); } + + public static void serverLoad(MinecraftServer server) { + ConfigHandler.serverLoad(server); + ObjectToPermissionMap.reload(server); + Flan.lockRegistry(server); + } }