diff --git a/README.md b/README.md index 228a631..430a79f 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,8 @@ You can find config file in `./config/getoffmylawn.json`. To reload it, just typ "placeholderNoClaimOwners": "Nobody", "placeholderNoClaimTrusted": "Nobody", "placeholderClaimCanBuildInfo": "${owners} (${anchor})", - "placeholderClaimCantBuildInfo": "${owners} (${anchor})" + "placeholderClaimCantBuildInfo": "${owners} (${anchor})", + "claimColorSource": "location" // either "location" or "player" - "location" will chose the color based on the location of the claim (hash of coordinates), "player" will chose the color based on the owner of the claim (hash of UUID). } ``` diff --git a/src/main/java/draylar/goml/api/ClaimUtils.java b/src/main/java/draylar/goml/api/ClaimUtils.java index 9c2a6ae..ed7c4ea 100644 --- a/src/main/java/draylar/goml/api/ClaimUtils.java +++ b/src/main/java/draylar/goml/api/ClaimUtils.java @@ -13,6 +13,7 @@ import draylar.goml.other.StatusEnum; import draylar.goml.registry.GOMLBlocks; import me.lucko.fabric.api.permissions.v0.Permissions; +import net.minecraft.block.BlockState; import net.minecraft.entity.AreaEffectCloudEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.damage.DamageSource; @@ -21,6 +22,7 @@ import net.minecraft.entity.passive.TameableEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.registry.Registries; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; @@ -35,6 +37,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.stream.Collectors; public class ClaimUtils { @@ -121,6 +124,10 @@ public static Selection> getClaimsInOpenBox(WorldView wor return GetOffMyLawn.CLAIM.get(world).getClaims().entries(box -> box.intersectsOpen(checkBox)); } + public static Selection> getClaimsInDimension(WorldView world) { + return GetOffMyLawn.CLAIM.get(world).getClaims().entries(a -> true); + } + public static Box createBox(int x1, int y1, int z1, int x2, int y2, int z2) { return Box.create(Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2), Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2)); } @@ -465,4 +472,44 @@ public static boolean hasMatchingClaims(World world, BlockPos target, BlockPos o return claims.anyMatch(x -> x.getValue().hasPermission(trusted)); } + + private static int claimColorIndex(Claim claim) { + int hash = 0; + + if (GetOffMyLawn.CONFIG.usePlayerForColor()) { + // get lexicographically smallest UUID because set order is not stable + UUID min = null; + + for (UUID id : claim.getOwners()) { + if (min == null || id.compareTo(min) < 0) { + min = id; + } + } + + if (min != null) { + hash = min.hashCode(); + } + } else { + hash = claim.getOrigin().hashCode(); + } + + return hash & 0xF; + } + + // From https://lospec.com/palette-list/minecraft-concrete (matches block order so matches goggles). + private static final int[] CLAIM_COLORS_RGB = new int[]{0xcfd5d6, 0xe06101, 0xa9309f, 0x2489c7, 0xf1af15, 0x5ea918, 0xd5658f, 0x373a3e, 0x7d7d73, 0x157788, 0x64209c, 0x2d2f8f, 0x603c20, 0x495b24, 0x8e2121, 0x080a0f}; + + private static final BlockState[] CLAIM_COLORS_BLOCKS = Registries.BLOCK.stream().filter((b) -> { + var id = Registries.BLOCK.getId(b); + + return id.getNamespace().equals("minecraft") && id.getPath().endsWith("_concrete"); + }).map((b) -> b.getDefaultState()).collect(Collectors.toList()).toArray(new BlockState[0]); + + public static int dynmapClaimColor(Claim claim) { + return CLAIM_COLORS_RGB[claimColorIndex(claim)]; + } + + public static BlockState gogglesClaimColor(Claim claim) { + return CLAIM_COLORS_BLOCKS[claimColorIndex(claim)]; + } } diff --git a/src/main/java/draylar/goml/compat/DynmapCompat.java b/src/main/java/draylar/goml/compat/DynmapCompat.java index 1d6301b..5824abc 100644 --- a/src/main/java/draylar/goml/compat/DynmapCompat.java +++ b/src/main/java/draylar/goml/compat/DynmapCompat.java @@ -28,9 +28,6 @@ public class DynmapCompat { private static final String gomlMarkerSetId = "gomlMarkerSet"; - // From https://lospec.com/palette-list/minecraft-concrete (matches block order so matches goggles). - private static final int[] COLORS = new int[]{0xcfd5d6, 0xe06101, 0xa9309f, 0x2489c7, 0xf1af15, 0x5ea918, 0xd5658f, 0x373a3e, 0x7d7d73, 0x157788, 0x64209c, 0x2d2f8f, 0x603c20, 0x495b24, 0x8e2121, 0x080a0f}; - public static void init(final MinecraftServer server) { DynmapCommonAPIListener.register(new DynmapCommonAPIListener() { @Override @@ -60,7 +57,7 @@ private static void renderClaimArea(Claim claim, MinecraftServer server, MarkerA ClaimCorners corners = getClaimCorners(claim); AreaMarker marker = markerApi.getMarkerSet(gomlMarkerSetId).createAreaMarker(getClaimId(claim), getClaimLabel(claim, server), true, worldName, corners.x, corners.z, true); // marker.setRangeY(corners.y[0], corners.y[1]); - int color = COLORS[(claim.getOrigin().hashCode() & 0xFFFF) % COLORS.length]; + int color = ClaimUtils.dynmapClaimColor(claim); marker.setFillStyle(0.25, color); marker.setLineStyle(2, 1, color); } @@ -71,7 +68,8 @@ private static void resizeClaimArea(Claim claim, MinecraftServer server, MarkerA } private static void updateClaimArea(Claim claim, MinecraftServer server, MarkerAPI markerApi) { - handleClaimAreaUpdate(claim, server, markerApi, claimArea -> claimArea.setLabel(getClaimLabel(claim, server), true)); + deleteClaimArea(claim, markerApi); + renderClaimArea(claim, server, markerApi); } private static void deleteClaimArea(Claim claim, MarkerAPI markerApi) { diff --git a/src/main/java/draylar/goml/config/GOMLConfig.java b/src/main/java/draylar/goml/config/GOMLConfig.java index df63571..d0d9f95 100644 --- a/src/main/java/draylar/goml/config/GOMLConfig.java +++ b/src/main/java/draylar/goml/config/GOMLConfig.java @@ -60,6 +60,8 @@ public class GOMLConfig { public WrappedText placeholderClaimCanBuildInfo = WrappedText.of("${owners} (${anchor})"); public WrappedText placeholderClaimCantBuildInfo = WrappedText.of("${owners} (${anchor})"); + public String claimColorSource = "location"; + public boolean canInteract(Block block) { return this.allowedBlockInteraction.contains(block); } @@ -85,6 +87,14 @@ public boolean isBlacklisted(World world, Box claimBox) { return false; } + public boolean useLocationForColor() { + return !usePlayerForColor(); + } + + public boolean usePlayerForColor() { + return "player".equalsIgnoreCase(claimColorSource); + } + public MutableText prefix(Text text) { return Text.empty().append(messagePrefix.text()).append(Text.literal(" ")).append(text); } diff --git a/src/main/java/draylar/goml/item/GogglesItem.java b/src/main/java/draylar/goml/item/GogglesItem.java index dcb422b..1985c28 100644 --- a/src/main/java/draylar/goml/item/GogglesItem.java +++ b/src/main/java/draylar/goml/item/GogglesItem.java @@ -22,12 +22,6 @@ import java.util.stream.Collectors; public class GogglesItem extends ArmorItem implements PolymerItem { - private static final BlockState[] STATES = Registries.BLOCK.stream().filter((b) -> { - var id = Registries.BLOCK.getId(b); - - return id.getNamespace().equals("minecraft") && id.getPath().endsWith("_concrete"); - }).map((b) -> b.getDefaultState()).collect(Collectors.toList()).toArray(new BlockState[0]); - public GogglesItem() { super(ArmorMaterials.IRON, Type.HELMET, new Item.Settings().maxDamage(-1)); } @@ -47,9 +41,11 @@ public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, var minPos = new BlockPos(box.x1(), Math.max(box.y1(), world.getBottomY()), box.z1()); var maxPos = new BlockPos(box.x2() - 1, Math.min(box.y2() - 1, world.getTopY()), box.z2() - 1); + BlockState state = ClaimUtils.gogglesClaimColor(claim.getValue()); + WorldParticleUtils.render(player, minPos, maxPos, //new DustParticleEffect(new Vec3f(0.8f, 0.8f, 0.8f), 2) - new BlockStateParticleEffect(ParticleTypes.BLOCK_MARKER, STATES[(claim.getValue().getOrigin().hashCode() & 0xFFFF) % STATES.length]) + new BlockStateParticleEffect(ParticleTypes.BLOCK_MARKER, state) ); }); } diff --git a/src/main/java/draylar/goml/other/ClaimCommand.java b/src/main/java/draylar/goml/other/ClaimCommand.java index 5424c23..0d36c98 100644 --- a/src/main/java/draylar/goml/other/ClaimCommand.java +++ b/src/main/java/draylar/goml/other/ClaimCommand.java @@ -1,14 +1,18 @@ package draylar.goml.other; +import java.security.Permission; + import com.jamieswhiteshirt.rtree3i.RTreeMap; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import draylar.goml.GetOffMyLawn; import draylar.goml.api.Claim; import draylar.goml.api.ClaimBox; import draylar.goml.api.ClaimUtils; import draylar.goml.api.DataKey; +import draylar.goml.api.event.ClaimEvents; import draylar.goml.config.GOMLConfig; import draylar.goml.registry.GOMLEntities; import draylar.goml.ui.ClaimListGui; @@ -32,6 +36,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.Heightmap; + import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; @@ -143,6 +148,10 @@ public static void init() { }) ) ) + .then(literal("updateallclaims") + .requires(Permissions.require("goml.command.command.admin.updateallclaims", 4)) + .executes(ClaimCommand::updateAllClaims) + ) ) ); }); @@ -485,6 +494,15 @@ private static int reload(CommandContext context) { return 1; } + private static int updateAllClaims(CommandContext context) { + ServerWorld world = context.getSource().getWorld(); + ClaimUtils.getClaimsInDimension(world).forEach(claim -> { + ClaimEvents.CLAIM_UPDATED.invoker().onEvent(claim.getValue()); + }); + context.getSource().sendFeedback(() -> prefix(Text.literal("Updated all claims")), false); + return 1; + } + private static void bumpChat(ServerPlayerEntity player) { player.sendMessage(Text.literal(" "), false); }