Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
# and run on both Linux, Windows, and Mac
os: [ubuntu-20.04, windows-latest]
os: [ubuntu-24.04, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: checkout repository
Expand Down
14 changes: 7 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://modmuss50.me/fabric.html
minecraft_version=1.21.5
yarn_mappings=1.21.5+build.1
loader_version=0.16.10
minecraft_version=1.21.6
yarn_mappings=1.21.6+build.1
loader_version=0.16.14
# Mod Properties
mod_version=1.1.16
mod_version=1.1.17
maven_group=us.potatoboy
archives_base_name=htm
# Dependencies
# check this on https://modmuss50.me/fabric.html
fabric_version=0.119.6+1.21.5
translation_version=2.5.0+1.21.5-rc1
permissions_api_version=0.3.3
fabric_version=0.127.1+1.21.6
translation_version=2.5.1+1.21.5
permissions_api_version=0.4.0-SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import com.github.fabricservertools.htm.api.Lock;
import com.github.fabricservertools.htm.api.LockType;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.Uuids;
Expand All @@ -28,14 +30,15 @@ public record HTMContainerLock(Lock type, UUID owner, Set<UUID> trusted, Map<Fla
);
private static final Codec<Map<FlagType, Boolean>> FLAGS_CODEC = setOf(FLAG_CODEC.listOf()).xmap(set -> Map.ofEntries(set.toArray(new Map.Entry[0])), Map::entrySet);

public static final Codec<HTMContainerLock> CODEC = RecordCodecBuilder.create(instance ->
public static final MapCodec<HTMContainerLock> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
LockType.CODEC.forGetter(HTMContainerLock::type),
Uuids.INT_STREAM_CODEC.fieldOf("Owner").forGetter(HTMContainerLock::owner),
setOf(Uuids.INT_STREAM_CODEC.listOf()).fieldOf("Trusted").forGetter(HTMContainerLock::trusted),
FLAGS_CODEC.fieldOf("Flags").forGetter(HTMContainerLock::flags)
).apply(instance, HTMContainerLock::new)
);
public static final Codec<HTMContainerLock> CODEC = MAP_CODEC.codec();

public HTMContainerLock(Lock type, ServerPlayerEntity owner) {
this(type, owner.getUuid(), Set.of(), defaultFlags());
Expand All @@ -59,7 +62,7 @@ public boolean canOpen(ServerPlayerEntity player) {
if (isOwner(player)) return true;

player.sendMessage(Text.translatable("text.htm.locked"), true);
player.playSound(SoundEvents.BLOCK_CHEST_LOCKED, 1.0F, 1.0F);
player.playSoundToPlayer(SoundEvents.BLOCK_CHEST_LOCKED, SoundCategory.BLOCKS, 1.0F, 1.0F);
return false;
}

Expand Down Expand Up @@ -98,7 +101,7 @@ public HTMContainerLock withFlag(FlagType flag, boolean value) {
public boolean isOwner(ServerPlayerEntity player) {
if (!owner.equals(player.getUuid())) {
if (Permissions.check(player, "htm.admin", 2)) {
String name = Utility.getNameFromUUID(owner, player.server);
String name = Utility.getNameFromUUID(owner, player.getServer());

Utility.sendMessage(player, Text.translatable("text.htm.override", name));
return true;
Expand Down
4 changes: 0 additions & 4 deletions src/main/java/com/github/fabricservertools/htm/api/Lock.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
public interface Lock {
boolean canOpen(ServerPlayerEntity player, HTMContainerLock lock);

default Lock withOwner(ServerPlayerEntity player) {
return this;
}

default void onInfo(ServerPlayerEntity player, HTMContainerLock lock) {}

Codec<? extends Lock> codec();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.github.fabricservertools.htm.api;

import com.github.fabricservertools.htm.HTMContainerLock;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public interface LockInteraction {

void execute(ServerPlayerEntity player, World world, BlockPos pos, LockableObject object, HTMContainerLock lock);
void execute(MinecraftServer server, ServerPlayerEntity player, BlockPos pos, LockableObject object, HTMContainerLock lock);

default boolean requiresLock() {
return true;
Expand Down
28 changes: 18 additions & 10 deletions src/main/java/com/github/fabricservertools/htm/api/LockType.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class LockType<T extends Lock> {
public final class LockType {
private static final BiMap<String, Codec<? extends Lock>> TYPES = HashBiMap.create();
private static final Map<String, Lock> INSTANCES = new HashMap<>();
private static final Map<String, Function<ServerPlayerEntity, Lock>> FACTORIES = new HashMap<>();

public static final MapCodec<Lock> CODEC = Codec.STRING.dispatchMap("Type",
LockType::id, type -> TYPES.get(type).fieldOf("TypeData"));
// A codec that dispatches a lock type (string) from the "Type" key, and then uses the lock type's codec to create a map codec that has a "TypeData" key as field
public static final MapCodec<Lock> CODEC = Codec.STRING.dispatchMap("Type", LockType::id, type -> TYPES.get(type).fieldOf("TypeData"));

private LockType() {}

public static String id(Lock lock) {
return TYPES.inverse().get(lock.codec());
Expand All @@ -29,21 +32,26 @@ public static Collection<String> types() {
}

public static Lock lock(String id, ServerPlayerEntity owner) {
Lock lock = INSTANCES.get(id);
Function<ServerPlayerEntity, Lock> lock = FACTORIES.get(id);
if (lock == null) {
return null;
}
return lock.withOwner(owner);
return lock.apply(owner);
}

private static void register(String id, Codec<? extends Lock> codec, Lock instance) {
TYPES.put(id, codec);
INSTANCES.put(id, instance);
FACTORIES.put(id, player -> instance);
}

private static void register(String id, Codec<? extends Lock> codec, Function<ServerPlayerEntity, Lock> factory) {
TYPES.put(id, codec);
FACTORIES.put(id, factory);
}

public static void init() {
register("private", PrivateLock.CODEC, new PrivateLock());
register("public", PublicLock.CODEC, new PublicLock());
register("key", KeyLock.CODEC, new KeyLock(null));
register("private", PrivateLock.CODEC, PrivateLock.INSTANCE);
register("public", PublicLock.CODEC, PublicLock.INSTANCE);
register("key", KeyLock.CODEC, KeyLock::fromMainHandItem);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
package com.github.fabricservertools.htm.api;

import com.github.fabricservertools.htm.HTM;
import com.github.fabricservertools.htm.HTMContainerLock;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;

import java.util.Optional;
import java.util.function.Consumer;

public interface LockableObject {

default void writeLock(WriteView view) {
getLock().ifPresent(lock -> view.put("container_lock", HTMContainerLock.CODEC, lock));
}

default void readLock(ReadView view, Consumer<HTMContainerLock> consumer) {
view.getOptionalString("Type").ifPresentOrElse(
legacy -> {
// Legacy, lock data was stored in the root NBT object before 1.21.5
// Even Mojang thinks this shouldn't be done anymore and marked the method as deprecated, will probably end up removing this functionality
// once this method is removed too
view.read(HTMContainerLock.MAP_CODEC).ifPresentOrElse(
consumer,
() -> {
HTM.LOGGER.warn("Failed to read legacy container lock data!"); // Can't really do much here
consumer.accept(null);
}
);
},
() -> view.read("container_lock", HTMContainerLock.CODEC).ifPresentOrElse(consumer, () -> consumer.accept(null))
);
}

default boolean canOpenUnchecked(ServerPlayerEntity player) {
return canOpen(player).orElse(true);
}

default Optional<Boolean> canOpen(ServerPlayerEntity player) {
return getLock().map(lock -> lock.canOpen(player));
}

Optional<HTMContainerLock> getLock();

void setLock(HTMContainerLock lock);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static net.minecraft.server.command.CommandManager.literal;

public class TrustCommand implements SubCommand {

@Override
public LiteralCommandNode<ServerCommandSource> build() {
return literal("trust")
Expand All @@ -39,12 +40,12 @@ public LiteralCommandNode<ServerCommandSource> build() {

@SuppressWarnings("SameReturnValue")
private int trustList(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
ServerPlayerEntity player = context.getSource().getPlayer();
GlobalTrustState globalTrustState = Utility.getGlobalTrustState(player.server);
ServerPlayerEntity player = context.getSource().getPlayerOrThrow();
GlobalTrustState globalTrustState = Utility.getGlobalTrustState(context.getSource().getServer());

String trustedList = globalTrustState.getTrusted().get(player.getUuid())
.stream()
.map(uuid -> Utility.getNameFromUUID(uuid, player.server))
.map(uuid -> Utility.getNameFromUUID(uuid, context.getSource().getServer()))
.collect(Collectors.joining(", "));

player.sendMessage(Text.translatable("text.htm.trusted.global", trustedList), false);
Expand All @@ -53,11 +54,11 @@ private int trustList(CommandContext<ServerCommandSource> context) throws Comman
}

private static int trust(ServerCommandSource source, Collection<GameProfile> gameProfiles, boolean global) throws CommandSyntaxException {
ServerPlayerEntity player = source.getPlayer();
ServerPlayerEntity player = source.getPlayerOrThrow();

if (global) {
for (GameProfile gameProfile : gameProfiles) {
GlobalTrustState globalTrustState = Utility.getGlobalTrustState(player.server);
GlobalTrustState globalTrustState = Utility.getGlobalTrustState(source.getServer());
if (player.getUuid().equals(gameProfile.getId())) {
player.sendMessage(Text.translatable("text.htm.error.trust_self"), false);
return -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static net.minecraft.server.command.CommandManager.literal;

public class UntrustCommand implements SubCommand {

@Override
public LiteralCommandNode<ServerCommandSource> build() {
return literal("untrust")
Expand All @@ -42,11 +43,11 @@ public LiteralCommandNode<ServerCommandSource> build() {

@SuppressWarnings("SameReturnValue")
private int untrust(ServerCommandSource source, Collection<GameProfile> gameProfiles, boolean global) throws CommandSyntaxException {
ServerPlayerEntity player = source.getPlayer();
ServerPlayerEntity player = source.getPlayerOrThrow();

if (global) {
for (GameProfile gameProfile : gameProfiles) {
GlobalTrustState globalTrustState = Utility.getGlobalTrustState(player.server);
GlobalTrustState globalTrustState = Utility.getGlobalTrustState(source.getServer());
if (globalTrustState.removeTrust(player.getUuid(), gameProfile.getId())) {
source.sendFeedback(() -> Text.translatable("text.htm.untrust", gameProfile.getName()).append(Text.translatable("text.htm.global")), false);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
import com.github.fabricservertools.htm.api.FlagType;
import com.github.fabricservertools.htm.api.LockInteraction;
import com.github.fabricservertools.htm.api.LockableObject;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Pair;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import java.util.Map;
import java.util.Optional;

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class FlagAction implements LockInteraction {

/**
* Optional flag type and value to set it to.
* If empty, get flag info instead
Expand All @@ -33,7 +34,7 @@ public FlagAction(Optional<Pair<FlagType, Boolean>> flagSet) {
}

@Override
public void execute(ServerPlayerEntity player, World world, BlockPos pos, LockableObject object, HTMContainerLock lock) {
public void execute(MinecraftServer server, ServerPlayerEntity player, BlockPos pos, LockableObject object, HTMContainerLock lock) {
if (!lock.isOwner(player)) {
player.sendMessage(Text.translatable("text.htm.error.not_owner"), false);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
import com.github.fabricservertools.htm.api.LockType;
import com.github.fabricservertools.htm.api.LockableObject;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import java.util.Optional;
import java.util.stream.Collectors;

public class InfoAction implements LockInteraction {

@Override
public void execute(ServerPlayerEntity player, World world, BlockPos pos, LockableObject object, HTMContainerLock lock) {
Optional<GameProfile> owner = player.server.getUserCache().getByUuid(lock.owner());
public void execute(MinecraftServer server, ServerPlayerEntity player, BlockPos pos, LockableObject object, HTMContainerLock lock) {
Optional<GameProfile> owner = Optional.ofNullable(server.getUserCache()).flatMap(cache -> cache.getByUuid(lock.owner()));

if (owner.isEmpty()) {
HTM.LOGGER.error("Can't find lock owner: {}", lock.owner());
Expand All @@ -32,7 +32,7 @@ public void execute(ServerPlayerEntity player, World world, BlockPos pos, Lockab
if (lock.isOwner(player)) {
String trustedList = lock.trusted()
.stream()
.map(uuid -> Utility.getNameFromUUID(uuid, player.server))
.map(uuid -> Utility.getNameFromUUID(uuid, server))
.collect(Collectors.joining(", "));

player.sendMessage(Text.translatable("text.htm.trusted", trustedList), false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
Expand Down Expand Up @@ -85,18 +86,18 @@ public LockableObject getFallback() {
}
};

public static void execute(ServerPlayerEntity player, World world, BlockPos pos) {
public static void execute(MinecraftServer server, ServerPlayerEntity player, BlockPos pos) {
LockInteraction action = pendingActions.get(player);

Optional<LockableObject> lockableObject = getLockable(player, pos);
lockableObject.ifPresentOrElse(object -> {
Optional<HTMContainerLock> containerLock = object.getLock();
if (action.requiresLock()) {
containerLock.ifPresentOrElse(
lock -> action.execute(player, world, pos, object, lock),
lock -> action.execute(server, player, pos, object, lock),
() -> player.sendMessage(Text.translatable("text.htm.error.no_lock"), false));
} else {
action.execute(player, world, pos, object, containerLock.orElse(null));
action.execute(server, player, pos, object, containerLock.orElse(null));
}
}, () -> player.sendMessage(Text.translatable("text.htm.error.unlockable"), false));

Expand All @@ -105,12 +106,16 @@ public static void execute(ServerPlayerEntity player, World world, BlockPos pos)
}
}

public static boolean canOpen(ServerPlayerEntity player, BlockPos pos) {
return getLock(player, pos).map(lock -> lock.canOpen(player)).orElse(true);
}

public static Optional<HTMContainerLock> getLock(ServerPlayerEntity player, BlockPos pos) {
return getLockable(player, pos).flatMap(LockableObject::getLock);
}

public static Optional<LockableObject> getLockable(ServerPlayerEntity player, BlockPos pos) {
return getLockable(player.getServerWorld(), pos);
return getLockable(player.getWorld(), pos);
}

public static Optional<HTMContainerLock> getLock(ServerWorld world, BlockPos pos) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import com.github.fabricservertools.htm.HTMContainerLock;
import com.github.fabricservertools.htm.api.LockInteraction;
import com.github.fabricservertools.htm.api.LockableObject;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class RemoveAction implements LockInteraction {
@Override
public void execute(ServerPlayerEntity player, World world, BlockPos pos, LockableObject object, HTMContainerLock lock) {
public void execute(MinecraftServer server, ServerPlayerEntity player, BlockPos pos, LockableObject object, HTMContainerLock lock) {
if (!lock.isOwner(player)) {
player.sendMessage(Text.translatable("text.htm.error.not_owner"), false);
return;
Expand Down
Loading