package io.gitlab.jfronny.betterwhitelist.server; import io.gitlab.jfronny.betterwhitelist.BetterWhitelist; import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.Script; import io.gitlab.jfronny.muscript.data.dynamic.DNull; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal; import io.gitlab.jfronny.muscript.error.LocationalException; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.minecraft.network.PacketByteBuf; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class ServerScope { public static Dynamic run(Script script, Challenge challenge) { try { return script.run(fork(challenge)); } catch (LocationalException le) { for (Throwable t = le; t != null; t = t.getCause()) { if (t instanceof ServerScope.AssertFail af) throw af; } throw le; } } private static Scope fork(Challenge challenge) { return BetterWhitelist.SCOPE.fork().set("assert", args -> { if (args.size() != 1 && args.size() != 2) throw new IllegalArgumentException("Invalid number of arguments for assert: expected 1 or 2 but got " + args.size()); if (!args.get(0).asBool().getValue()) throw new AssertFail(args.size() > 1 ? args.get(1).asString().getValue() : "Failed Whitelist Check"); return new DNull(); }).set("challenge", args -> { if (args.size() == 0) throw new IllegalArgumentException("Invalid number of arguments for challenge: expected 1 or more but got 0"); PacketByteBuf buf = PacketByteBufs.create(); String challengeString = Dynamic.serialize(args.get(0).asCallable()); BetterWhitelist.LOG.info("Sending challenge to " + challenge.profile.getName() + ": " + challengeString); buf.writeString(challengeString); List> params = args.getValue().subList(1, args.size()); buf.writeInt(params.size()); params.forEach(p -> buf.writeString(Dynamic.serialize(p))); challenge.response.reset(); challenge.sender.sendPacket(BetterWhitelist.CHALLENGE_CHANNEL, buf); try { return challenge.response.get(1, TimeUnit.SECONDS); } catch (TimeoutException e) { throw new AssertFail("Took too long to respond"); } }).set("user", Map.of( "id", challenge.profile.getId() == null ? new DNull() : DFinal.of(challenge.profile.getId().toString()), "name", DFinal.of(challenge.profile.getName()) )); } public static class AssertFail extends RuntimeException { public AssertFail(String message) { super(message); } } }