import { World } from './world'; import { PlayerEntity } from './entity'; import { useBridge, addBridge, Identifier, Hand, Pos, ActionResult, Direction, SimpleRegistry } from './core'; import { CompoundTag } from './tag'; /** * Settings for {@link CustomBlock} */ export class BlockSettings { readonly #material: string; readonly #materialColor: string; #resistance: number; #hardness: number; /** * Create Block Settings * @param material Material * @param materialColor Material Color */ constructor(material: string); constructor(material: string, materialColor: string); constructor(material: string, materialColor?: string) { this.#material = material; this.#materialColor = materialColor; this.#resistance = 0; this.#hardness = 0; } /** * Set Block Strength * @param hardness Hardness Value * @param resistance Blast Resistance Value */ setStrength(hardness: number, resistance: number): BlockSettings { this.#hardness = hardness; this.#resistance = resistance; return this; } /** * Set Hardness * @param hardness Hardness Value */ setHardness(hardness: number): BlockSettings { this.#hardness = hardness; return this; } /** * Set Blast Resistance * @param resistance Blast Resistance Value */ setResistance(resistance: number): BlockSettings { this.#resistance = resistance; return this; } /** * @internal */ createJavaObject(): JavaObject { return useBridge('BlockSettings.create', this.#material, this.#materialColor, this.#hardness, this.#resistance) as JavaObject; } } /** * Custom Block */ export abstract class CustomBlock { /** * @internal */ settings: BlockSettings; constructor(settings: BlockSettings) { this.settings = settings; } /** * Called When The Block Is Used * @param world World * @param blockState Block State * @param pos Block Position * @param side Side Of The Block Used * @param player Player * @param hand Hand * @returns Action Result */ abstract onUse(world: World, blockState: BlockState, pos: Pos, side: Direction, player: PlayerEntity, hand: Hand): ActionResult; } /** * Block State */ export class BlockState { /** * @internal */ readonly javaObject: JavaObject; constructor(javaObject: JavaObject) { this.javaObject = javaObject; } /** * Get Default Block State for Block * @param block Block ID * @returns Default Block State */ static getDefaultState(block: Identifier): BlockState { const obj = useBridge('BlockState.getDefaultState', block.toString()) as JavaObject; if (obj) { return new BlockState(obj); } else { return null; } } /** * Get Block ID * @returns Block ID */ getBlock(): Identifier { const obj = useBridge('BlockState.getBlock', this.javaObject) as string; if (obj) { return new Identifier(obj); } else { return null; } } /** * Get Custom Block * @returns Custom Block */ getCustomBlock(): CustomBlock { const id = this.getBlock(); return BlockRegistry.INSTANCE.get(id); } } /** * Custom Block Entity */ export abstract class CustomBlockEntity { /** * World */ protected world: World; /** * Position */ protected pos: Pos; /** * Set Location * @param world New World * @param pos New Position */ setLocation(world: World, pos: Pos) { this.world = world; this.pos = pos; } /** * Save Data To Tag * @param tag Tag * @returns Tag */ abstract toTag(tag: CompoundTag): CompoundTag; /** * Load Data From Tag * @param tag Tag */ abstract fromTag(tag: CompoundTag): void; /** * Runs Every Tick */ abstract tick(): void; /** * Get World * @returns World */ getWorld(): World { return this.world; } /** * Get Position * @returns Position */ getPos(): Pos { return this.pos; } /** * Mark Dirty */ markDirty() { if (this.getWorld() != null) { useBridge('World.markBlockEntityDirty', this.getWorld().javaObject, this.getPos().getX(), this.getPos().getY(), this.getPos().getZ()); } } } /** * {@link CustomBlock} With {@link CustomBlockEntity} */ export abstract class CustomBlockWithEntity extends CustomBlock { /** * Create Custom Block Entity * @returns Custom Block Entity */ abstract createBlockEntity(): CustomBlockEntity; } /** * @internal */ export class BlockRegistry implements SimpleRegistry { static INSTANCE = new BlockRegistry(); #blocks: Map; #blockEntities: Map; private constructor() { this.#blocks = new Map(); this.#blockEntities = new Map(); } register(id: Identifier, obj: CustomBlock) { this.#blocks.set(id.toString(), obj); if (obj instanceof CustomBlockWithEntity) { useBridge('Registry.registerBlockWithEntity', id.toString(), obj.settings.createJavaObject()); } else { useBridge('Registry.registerBlock', id.toString(), obj.settings.createJavaObject()); } } get(id: Identifier): CustomBlock { return this.#blocks.get(id.toString()); } getID(obj: CustomBlock): Identifier { for (const block of this.#blocks) { if (block[1] === obj) { return new Identifier(block[0]); } } return null; } getCustomBlockEntity(id: Identifier, i: number): CustomBlockEntity { return this.#blockEntities.get(id.toString())[i]; } getCustomBlockEntities(): CustomBlockEntity[] { let out: CustomBlockEntity[] = []; for (const key of this.#blockEntities.keys()) { const list = this.#blockEntities.get(key); out = out.concat(list); } return out; } createCustomBlockEntity(id: Identifier, i: number) { const block = this.get(id) as CustomBlockWithEntity; if (!this.#blockEntities.get(id.toString())) { this.#blockEntities.set(id.toString(), []); } this.#blockEntities.get(id.toString()).push(block.createBlockEntity()); } freeCustomBlockEntity(id: Identifier, i: number) { delete this.#blockEntities.get(id.toString())[i]; } } addBridge('CustomBlockEntity.create', (id: string, i: number) => { BlockRegistry.INSTANCE.createCustomBlockEntity(new Identifier(id), i); }); addBridge('CustomBlockEntity.fromTag', (id: string, i: number, tag: JavaObject) => { BlockRegistry.INSTANCE.getCustomBlockEntity(new Identifier(id), i).fromTag(new CompoundTag(tag)); }); addBridge('CustomBlockEntity.toTag', (id: string, i: number, tag: JavaObject): JavaObject => { return BlockRegistry.INSTANCE.getCustomBlockEntity(new Identifier(id), i).toTag(new CompoundTag(tag)).javaObject; }); addBridge('CustomBlockEntity.tick', (id: string, i: number) => { BlockRegistry.INSTANCE.getCustomBlockEntity(new Identifier(id), i).tick(); }); addBridge('CustomBlockEntity.setLocation', (id: string, i: number, world: JavaObject, x: number, y: number, z: number) => { BlockRegistry.INSTANCE.getCustomBlockEntity(new Identifier(id), i).setLocation(new World(world), new Pos(x, y, z)); }); addBridge('CustomBlockEntity.free', (id: string, i: number) => { BlockRegistry.INSTANCE.freeCustomBlockEntity(new Identifier(id), i); }); addBridge('CustomBlock.onUse', (id: string, world: JavaObject, state: JavaObject, x: number, y: number, z: number, side: keyof typeof Direction, player: JavaObject, hand: keyof typeof Hand): string => { return BlockRegistry.INSTANCE.get(new Identifier(id)).onUse(new World(world), new BlockState(state), new Pos(x, y, z), Direction[side], new PlayerEntity(player), Hand[hand]); });