UNPKG

@brayjamin/codify

Version:

Wrapper for stdlib.data which simplifies linking data and Minecraft objects. (forked from @harrix432/codify on npm.)

414 lines (389 loc) 15.9 kB
import { type, server, root, simplify, plugin } from '@grakkit/stdlib-paper'; import { obiItemStack, obuVector, obLocation, obePlayer, obuBoundingBox, obbBlock, obeEntity, obpPersistentDataType, obOfflinePlayer } from '@grakkit/types-paper'; export type HasBoundingBox = obuBoundingBox | SerialBoundingBox | IsPhysical; export type HasItemStack = obiItemStack | SerialItemStack | IsPhysical; export type HasLocation = obLocation | SerialLocation | IsPhysical; export type HasVector = obuVector | SerialVector | HasLocation; export type IsContainer = obbBlock | IsEntity | obiItemStack | SerialEntity | SerialItemStack; export type IsEntity = obeEntity | obePlayer | obOfflinePlayer; export type IsPhysical = obbBlock | IsEntity | SerialEntity; export type SerialBoundingBox = { class: 'BoundingBox'; min: SerialVector; max: SerialVector; }; export type SerialEntity = { class: 'Entity'; location: SerialLocation; nbt: SerialNBTTagCompound; type: string; uuid: string; }; export type SerialItemStack = { amount: number; class: 'ItemStack'; nbt: SerialNBTTagCompound; type: string; }; export type SerialLocation = { class: 'Location'; pitch: number; world: string; x: number; y: number; yaw: number; z: number; }; export type SerialNBTTag = | { class: 'NBTTagByte'; value: number } | { class: 'NBTTagByteArray'; value: number[] } | { class: 'NBTTagCompound'; value: { [x: string]: SerialNBTTag } } | { class: 'NBTTagDouble'; value: number } | { class: 'NBTTagFloat'; value: number } | { class: 'NBTTagInt'; value: number } | { class: 'NBTTagIntArray'; value: number[] } | { class: 'NBTTagList'; value: SerialNBTTag[] } | { class: 'NBTTagLong'; value: number } | { class: 'NBTTagLongArray'; value: number[] } | { class: 'NBTTagShort'; value: number } | { class: 'NBTTagString'; value: string }; export type SerialNBTTagCompound = { class: 'NBTTagCompound'; value: { [x: string]: SerialNBTTag }; }; export type SerialVector = { class: 'Vector'; x: number; y: number; z: number }; export const session: { data: Map<string, any> } = { data: new Map() }; const ArrayList = type('java.util.ArrayList'); const Block = type('org.bukkit.block.Block'); const BlockStateMeta = type('org.bukkit.inventory.meta.BlockStateMeta'); const BoundingBox = type('org.bukkit.util.BoundingBox'); const Entity = type('org.bukkit.entity.Entity'); const EntityType = type('org.bukkit.entity.EntityType'); const ItemStack = type('org.bukkit.inventory.ItemStack'); const LivingEntity = type('org.bukkit.entity.LivingEntity'); const Location = type('org.bukkit.Location'); const Material = type('org.bukkit.Material'); const NamespacedKey = type('org.bukkit.NamespacedKey'); const OfflinePlayer = type('org.bukkit.OfflinePlayer'); const PersistentDataHolder = type('org.bukkit.persistence.PersistentDataHolder'); const PersistentDataType = type('org.bukkit.persistence.PersistentDataType'); const SpawnReason = type('org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason'); const UUID = type('java.util.UUID'); const Vector = type('org.bukkit.util.Vector'); // only used to define internal variable types type NBTTag = { new (...args: any[]): any; a(value: any): any }; const NMS: string = (() => { const item = new ItemStack(Material.STONE).ensureServerConversions(); const meta = item.getItemMeta(); meta.setDisplayName('sus'); item.setItemMeta(meta); //@ts-expect-error return item.handle.getTag().getClass().getCanonicalName().split('.').slice(0, -1).join('.'); })(); //@ts-expect-error const NBTTagByte: NBTTag = type(`${NMS}.NBTTagByte`); //@ts-expect-error const NBTTagByteArray: NBTTag = type(`${NMS}.NBTTagByteArray`); //@ts-expect-error const NBTTagCompound: NBTTag = type(`${NMS}.NBTTagCompound`); //@ts-expect-error const NBTTagDouble: NBTTag = type(`${NMS}.NBTTagDouble`); //@ts-expect-error const NBTTagFloat: NBTTag = type(`${NMS}.NBTTagFloat`); //@ts-expect-error const NBTTagInt: NBTTag = type(`${NMS}.NBTTagInt`); //@ts-expect-error const NBTTagIntArray: NBTTag = type(`${NMS}.NBTTagIntArray`); //@ts-expect-error const NBTTagList: NBTTag = type(`${NMS}.NBTTagList`); //@ts-expect-error const NBTTagLong: NBTTag = type(`${NMS}.NBTTagLong`); //@ts-expect-error const NBTTagLongArray: NBTTag = type(`${NMS}.NBTTagLongArray`); //@ts-expect-error const NBTTagShort: NBTTag = type(`${NMS}.NBTTagShort`); //@ts-expect-error const NBTTagString: NBTTag = type(`${NMS}.NBTTagString`); function auto (path) { session.data.has(path) || session.data.set(path, root.file('codify', `${path}.json`).json() || {}); return session.data.get(path); } export function boundingBox (arg1: HasBoundingBox) { const thing = parse(arg1); if (thing instanceof Block) { const bounds = thing.getBoundingBox(); if (bounds.getVolume() === 0) { // don't use default zero-volume bounding box return BoundingBox.of(thing.getLocation(), 0, 0, 0); } else { return bounds; } } else if (thing instanceof BoundingBox) { return thing; } else if (thing instanceof Entity) { return thing.getBoundingBox(); } } export const data: { (arg1: IsPhysical, arg2?: string): any; (arg1: obiItemStack, arg2?: string): { value: any }; } = (arg1: IsContainer, arg2 = 'default') => { const thing = parse(arg1); if (thing instanceof Block) { return auto( `block/${thing.getWorld().getUID().toString()}/${(thing.getX() + 3e7).toString(16)}-${(thing.getY() + 2048).toString(16)}-${(thing.getZ() + 3e7).toString(16)}/${arg2}` ); } else if (thing instanceof OfflinePlayer) { return auto(`player/${thing.getUniqueId().toString()}/${arg2}`); } else if (thing instanceof Entity) { return auto(`entity/${thing.getUniqueId().toString()}/${arg2}`); } else if (thing instanceof ItemStack) { const meta = thing.getItemMeta(); if (meta instanceof PersistentDataHolder) { const container = meta.getPersistentDataContainer(); const key = new NamespacedKey(plugin, `codify/${arg2}`); return { get value () { return container.has(key, string) ? JSON.parse(container.get(key, string)) : void 0; }, set value (value) { if (typeof value === 'undefined') { //@ts-expect-error container.has(key, string) && (container.remove(key), thing.setItemMeta(meta)); } else { const raw = JSON.stringify(simplify(value)); const match = container.has(key, string) && raw === container.get(key, string); //@ts-expect-error match || (container.set(key, string, raw), thing.setItemMeta(meta)); } } }; } else { return { get value () { return void 0; } }; } } }; export function itemStack (arg1: HasItemStack) { const stuff = parse(arg1); if (stuff instanceof Block) { const item = new ItemStack(stuff.getType()); const meta = item.getItemMeta(); meta instanceof BlockStateMeta && (meta.setBlockState(stuff.getState()), item.setItemMeta(meta)); return item; } else if (stuff instanceof Entity) { return stuff instanceof LivingEntity ? stuff.getEquipment().getItemInMainHand() : null; } else if (stuff instanceof ItemStack) { return stuff; } } export function location (arg1) { const stuff = parse(arg1); if (stuff instanceof Block || stuff instanceof Entity) { return stuff.getLocation(); } else if (stuff instanceof Location) { return stuff; } } export const parse: { (object: SerialBoundingBox): obuBoundingBox; (object: SerialEntity): obeEntity; (object: SerialItemStack): obiItemStack; (object: SerialLocation): obLocation; (object: SerialVector): obuVector; <X>(object: X): X; } = (object: SerialBoundingBox | SerialEntity | SerialItemStack | SerialLocation | SerialNBTTag | SerialVector) => { if (object && typeof object.class === 'string') { switch (object.class) { case 'BoundingBox': return BoundingBox.of(parse(object.min), parse(object.max)); case 'Entity': try { let entity = [ ...server.selectEntities(sender, '@e') ].filter( entity => object.uuid === entity.getUniqueId().toString() )[0]; if (!entity) { const location = parse(object.location); entity = location.getWorld().spawnEntity(location, EntityType[object.type], SpawnReason.CUSTOM); } //@ts-expect-error entity.getHandle().load(parse(object.nbt)); return entity; } catch (error) { console.error('CODIFY - ENTITY PARSING ERROR:'); console.error(error.stack || error.message || error); return null; } case 'ItemStack': const item_stack = new ItemStack(Material[object.type], object.amount).ensureServerConversions(); //@ts-expect-error item_stack.getHandle().setTag(parse(object.nbt)); return item_stack; case 'Location': return new Location( //@ts-expect-error server.getWorld(UUID.fromString(object.world)), object.x, object.y, object.z, object.yaw, object.pitch ); case 'NBTTagByte': return NBTTagByte.a(object.value); case 'NBTTagByteArray': const nbt_tag_byte_array = new NBTTagByteArray(new ArrayList()); for (const value of object.value) nbt_tag_byte_array.add(NBTTagByte.a(value)); return nbt_tag_byte_array; case 'NBTTagCompound': const nbt_tag_compound = new NBTTagCompound(); for (const key in object.value) nbt_tag_compound.set(key, parse(object.value[key])); return nbt_tag_compound; case 'NBTTagDouble': return NBTTagDouble.a(object.value); case 'NBTTagFloat': return NBTTagFloat.a(object.value); case 'NBTTagInt': return NBTTagInt.a(object.value); case 'NBTTagIntArray': const nbt_tag_int_array = new NBTTagIntArray(new ArrayList()); for (const value of object.value) nbt_tag_int_array.add(NBTTagInt.a(value)); return nbt_tag_int_array; case 'NBTTagList': const nbt_tag_list = new NBTTagList(); for (const value of object.value) nbt_tag_list.add(parse(value)); return nbt_tag_list; case 'NBTTagLong': return NBTTagLong.a(object.value); case 'NBTTagLongArray': const nbt_tag_long_array = new NBTTagLongArray(new ArrayList()); for (const value of object.value) nbt_tag_long_array.add(NBTTagLong.a(value)); return nbt_tag_long_array; case 'NBTTagShort': return NBTTagShort.a(object.value); case 'NBTTagString': return NBTTagString.a(object.value); case 'Vector': return new Vector(object.x, object.y, object.z); } } return object; }; export const serialize: { (object: obuBoundingBox): SerialBoundingBox; (object: IsEntity): SerialEntity; (object: obiItemStack): SerialItemStack; (object: obLocation): SerialLocation; (object: obuVector): SerialVector; <X>(object: X): X; } = (object: obuBoundingBox | IsEntity | obiItemStack | obLocation | obuVector) => { if (object instanceof BoundingBox) { return { class: 'BoundingBox', min: serialize(object.getMin()), max: serialize(object.getMax()) }; } else if (object instanceof Entity) { //@ts-expect-error const nbt: SerialNBTTagCompound = serialize(object.getHandle().save(new NBTTagCompound())); return { class: 'Entity', location: serialize(object.getLocation()), nbt, type: object.getType().name(), uuid: object.getUniqueId().toString() }; } else if (object instanceof ItemStack) { //@ts-expect-error const nbt: SerialNBTTagCompound = serialize(object.ensureServerConversions().getHandle().getTag()); return { amount: object.getAmount(), class: 'ItemStack', nbt, type: object.getType().name() }; } else if (object instanceof Location) { return { class: 'Location', pitch: object.getPitch(), world: object.getWorld().getUID().toString(), x: object.getX(), y: object.getY(), yaw: object.getYaw(), z: object.getZ() }; } else if (object instanceof Vector) { return { class: 'Vector', x: object.getX(), y: object.getY(), z: object.getZ() }; } else { // force VS code to shut the fuck up const nbt: any = object; if (nbt instanceof NBTTagByte) { return { class: 'NBTTagByte', value: nbt.asByte() }; } else if (nbt instanceof NBTTagByteArray) { return { class: 'NBTTagByteArray', value: [ ...nbt ].map(value => value.asByte()) }; } else if (nbt instanceof NBTTagCompound) { return { class: 'NBTTagCompound', value: Object.fromEntries([ ...nbt.getKeys() ].map(key => [ key, serialize(nbt.get(key)) ])) }; } else if (nbt instanceof NBTTagDouble) { return { class: 'NBTTagDouble', value: nbt.asDouble() }; } else if (nbt instanceof NBTTagFloat) { return { class: 'NBTTagFloat', value: nbt.asFloat() }; } else if (nbt instanceof NBTTagInt) { return { class: 'NBTTagInt', value: nbt.asInt() }; } else if (nbt instanceof NBTTagIntArray) { return { class: 'NBTTagIntArray', value: [ ...nbt ].map(value => value.asInt()) }; } else if (nbt instanceof NBTTagList) { return { class: 'NBTTagList', value: [ ...nbt ].map(serialize) }; } else if (nbt instanceof NBTTagLong) { return { class: 'NBTTagLong', value: nbt.asLong() }; } else if (nbt instanceof NBTTagLongArray) { return { class: 'NBTTagLongArray', value: [ ...nbt ].map(value => value.asLong()) }; } else if (nbt instanceof NBTTagShort) { return { class: 'NBTTagShort', value: nbt.asShort() }; } else if (nbt instanceof NBTTagString) { return { class: 'NBTTagString', value: nbt.asString() }; } else { return nbt; } } }; export function vector (arg1: HasVector) { const stuff = parse(arg1); if (stuff instanceof Block || stuff instanceof Entity) { return stuff.getLocation().toVector(); } else if (stuff instanceof Location) { return stuff.toVector(); } else if (stuff instanceof Vector) { return stuff; } } const sender = server.getConsoleSender(); //@ts-expect-error const string: obpPersistentDataType<string, string> = PersistentDataType.STRING; Core.hook(() => { for (const [ path, content ] of session.data) { const raw = JSON.stringify(simplify(content)); const target = root.file('codify', `${path}.json`); if (raw === '{}') { target.exists && target.remove(); } else { target.entry().write(raw); } } });