lib/attachments.ts
3.9 KB · sha256:25694e6181dd57a8e3e3ecab1aac6fb59310c72998c35e586f5cdf542aea50ea
import {
resolvePlayerPermissions,
resolvePrefix,
resolveSuffix,
findPlayerByUuid,
upsertPlayer,
} from "../models/Player";
import { onlineByUuid } from "./identity";
import { applyDisplay, clearDisplay } from "./chatbridge";
import { refreshPlayerSnapshot } from "../placeholders/papi";
const RUNE_PLUGIN_NAME = "Rune";
const attachments = new Map<string, any>();
let runePlugin: bukkit.plugin.Plugin | null = null;
function getRunePlugin(): bukkit.plugin.Plugin {
if (runePlugin) return runePlugin;
runePlugin = rune.bukkit.getPluginManager().getPlugin(RUNE_PLUGIN_NAME);
if (!runePlugin) {
throw new Error(
`ward: cannot find host plugin '${RUNE_PLUGIN_NAME}' for addAttachment`,
);
}
return runePlugin;
}
export async function applyToPlayer(player: Player): Promise<void> {
const uuid = String(player.getUniqueId());
await upsertPlayer(uuid, String(player.getName()));
await refreshPlayerSnapshot(uuid);
const perms = await resolvePlayerPermissions(uuid);
const [prefix, suffix] = await Promise.all([
resolvePrefix(uuid),
resolveSuffix(uuid),
]);
const prev = attachments.get(uuid);
if (prev) {
try {
player.removeAttachment(prev);
} catch {}
}
const attachment = player.addAttachment(getRunePlugin());
for (const [perm, grant] of perms.entries()) {
attachment.setPermission(perm, grant);
}
expandWildcards(attachment, perms);
attachments.set(uuid, attachment);
player.recalculatePermissions();
applyDisplay(player, prefix ?? "", suffix ?? "");
}
export async function refreshOne(uuid: string): Promise<void> {
const p = onlineByUuid(uuid);
if (p) await applyToPlayer(p);
}
export async function refreshAll(): Promise<void> {
for (const p of rune.bukkit.getOnlinePlayers() as any[]) {
try {
await applyToPlayer(p);
} catch (e) {
console.error(
`ward.attachments: failed to apply for ${p.getName()}:`,
(e as Error)?.stack ?? e,
);
}
}
}
/** Refresh every online player who is a member of the named group. */
export async function refreshGroupMembers(groupName: string): Promise<void> {
const lc = groupName.toLowerCase();
for (const p of rune.bukkit.getOnlinePlayers() as any[]) {
const uuid = String(p.getUniqueId());
const doc = await findPlayerByUuid(uuid);
if (!doc) continue;
const inGroup = doc.nodes.some(
(n) => n.type === "inheritance" && n.value && n.key === `group.${lc}`,
);
if (inGroup || doc.primaryGroup.toLowerCase() === lc) {
try {
await applyToPlayer(p);
} catch (e) {
console.error(
`ward.attachments: group-refresh for ${p.getName()} failed:`,
(e as Error)?.message,
);
}
}
}
}
export function dropPlayer(uuid: string): void {
attachments.delete(uuid);
clearDisplay(uuid);
}
// ---------------------------------------------------------------------------
// Wildcard expansion -- LuckPerms-style "foo.*" / "*" grants apply to every
// registered Bukkit perm with the matching prefix.
// ---------------------------------------------------------------------------
function expandWildcards(
attachment: any,
effective: Map<string, boolean>,
): void {
const wildcards: { prefix: string; grant: boolean }[] = [];
for (const [key, grant] of effective.entries()) {
if (key === "*") wildcards.push({ prefix: "", grant });
else if (key.endsWith(".*")) {
wildcards.push({ prefix: key.slice(0, -1), grant }); // keep trailing "."
}
}
if (wildcards.length === 0) return;
const pm = rune.bukkit.getPluginManager();
const registered = (pm.getPermissions() as any[]) ?? [];
for (const p of registered) {
const name = String(p.getName());
if (effective.has(name)) continue; // explicit entry wins
for (const w of wildcards) {
if (w.prefix === "" || name.startsWith(w.prefix)) {
attachment.setPermission(name, w.grant);
break;
}
}
}
}