import { World } from './world'; import { PlayerEntity } from './entity'; import { Identifier, Hand, Pos, ActionResult, Direction, SimpleRegistry, JavaObjectWrapper, SimpleBuiltinRegistry } from './core'; import { CompoundTag } from './tag'; import { useBridge, addBridge } from 'scriptcraft-core'; import { Inventory } from './inventory'; import { Registry } from './registry'; /** * Block Material */ export class Material extends JavaObjectWrapper { /** * Create Material Wrapper From Java Object * @param javaObject Java Object */ constructor(javaObject: JavaObject | JavaObjectWrapper) { super(javaObject); this.assertValidJavaObject('Material'); } /** * Get Associated Material Color * @returns Material Color */ getColor(): MaterialColor { const obj = useBridge('Material.getColor', this.getJavaObject()) as JavaObject; if (obj !== null) { return new MaterialColor(obj); } else { return null; } } } /** * Block Material Color */ export class MaterialColor extends JavaObjectWrapper { /** * Create Material Color Wrapper From Java Object * @param javaObject Java Object */ constructor(javaObject: JavaObject | JavaObjectWrapper) { super(javaObject); this.assertValidJavaObject('MaterialColor'); } } /** * Settings for {@link CustomBlock} */ export class BlockSettings { #material: Material; #materialColor: MaterialColor; #resistance: number; #hardness: number; /** * Create Block Settings * @param material Material * @param materialColor Material Color */ constructor(material: Material); constructor(material: Material, materialColor: MaterialColor); constructor(material: Material, materialColor?: MaterialColor) { this.#material = material; this.#materialColor = materialColor !== null ? materialColor : material.getColor(); this.#resistance = 0; this.#hardness = 0; } /** * Set Block Strength * @param hardness Hardness Value * @param resistance Blast Resistance Value */ strength(hardness: number, resistance: number): BlockSettings { this.#hardness = hardness; this.#resistance = resistance; return this; } /** * Set Hardness * @param hardness Hardness Value */ hardness(hardness: number): BlockSettings { this.#hardness = hardness; return this; } /** * Set Blast Resistance * @param resistance Blast Resistance Value */ resistance(resistance: number): BlockSettings { this.#resistance = resistance; return this; } /** * Get Material * @returns Material */ getMaterial(): Material { return this.#material; } /** * Set Material * @param material Material */ material(material: Material): BlockSettings { this.#material = material; return this; } /** * Set Material Color * @param materialColor Material Color */ materialColor(materialColor: MaterialColor): BlockSettings { this.#materialColor = materialColor; return this; } /** * Get Material Color * @returns Material Color */ getMaterialColor(): MaterialColor { return this.#materialColor; } /** * Get Blast Resistance * @returns Blast Resistance */ getResistance(): number { return this.#resistance; } /** * Get Hardness * @returns Hardness */ getHardness(): number { return this.#hardness; } /** * Create Java Object * @returns Java Object */ createJavaObject(): JavaObject { return useBridge('BlockSettings.create', this.getMaterial().getJavaObject(), this.getMaterialColor().getJavaObject(), this.getHardness(), this.getResistance()) as JavaObject; } } /** * Custom Block */ export class CustomBlock { readonly #settings: Readonly; readonly #propertyBuilder: BlockStatePropertyBuilder; /** * Create Custom Block * @param settings Block Settings */ constructor(settings: BlockSettings) { this.#settings = Object.freeze(settings); this.#propertyBuilder = BlockStatePropertyBuilder.create(); this.appendProperties(this.getPropertyBuilder()); } /** * Get Block Settings * @returns Block Settings */ getSettings(): Readonly { return this.#settings; } /** * Get Block State Property Builder * @returns Block State Property Builder */ getPropertyBuilder(): BlockStatePropertyBuilder { return this.#propertyBuilder; } /** * 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 */ onUse(world: World, blockState: BlockState, pos: Pos, side: Direction, player: PlayerEntity, hand: Hand): ActionResult { return ActionResult.PASS; } /** * Add Block State Properties * @param builder Block State Property Builder */ appendProperties(builder: BlockStatePropertyBuilder): void { } } /** * Custom Block Entity */ export 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): void { this.world = world; this.pos = pos; } /** * Save Data To Tag * @param tag Tag * @returns Tag */ toTag(tag: CompoundTag): CompoundTag { return tag; } /** * Load Data From Tag * @param tag Tag */ fromTag(tag: CompoundTag): void {} /** * Runs Every Tick */ tick(): void {} /** * Get World * @returns World */ getWorld(): World { return this.world; } /** * Get Position * @returns Position */ getPos(): Pos { return this.pos; } /** * Mark Dirty */ markDirty(): void { if (this.getWorld() !== null) { const entity = this.getWorld().getBlockEntity(this.getPos()); if (entity !== null) { entity.markDirty(); } } } /** * Get Custom Block Entity by ID * @param id ID * @returns Custom Block Entity */ static getByID(id: number): CustomBlockEntity { return BlockRegistry.INSTANCE.getCustomBlockEntityByID(id); } } /** * Block */ export class Block extends JavaObjectWrapper { /** * Create Block Wrapper From Java Object * @param javaObject Java Object */ constructor(javaObject: JavaObject | JavaObjectWrapper) { super(javaObject); this.assertValidJavaObject('Block'); } /** * Get Block Material */ getMaterial(): Material { const obj = useBridge('Block.getMaterial', this.getJavaObject()) as JavaObject; if (obj !== null) { return new Material(obj); } else { return null; } } /** * Get Block Material Color */ getMaterialColor(): MaterialColor { const obj = useBridge('Block.getMaterialColor', this.getJavaObject()) as JavaObject; if (obj !== null) { return new MaterialColor(obj); } else { return null; } } /** * Get Block ID * @returns ID */ getID(): Identifier { const obj = useBridge('Block.getID', this.getJavaObject()) as string; if (obj !== null) { return new Identifier(obj); } else { return null; } } /** * Get Default Block State * @returns Default Block State */ getDefaultState(): BlockState { const obj = useBridge('Block.getDefaultState', this.getJavaObject()) as JavaObject; if (obj !== null) { return new BlockState(obj); } else { return null; } } } /** * Custom Block State Property Builder */ export class BlockStatePropertyBuilder extends JavaObjectWrapper { /** * Create Block State Property Builder Wrapper From Java Object * @param javaObject Java Object */ constructor(javaObject: JavaObject | JavaObjectWrapper) { super(javaObject); this.assertValidJavaObject('BlockStatePropertyBuilder'); } /** * Create Block State Property Builder * @returns New Block State Property Builder */ static create(): BlockStatePropertyBuilder { const obj = useBridge('BlockStatePropertyBuilder.create') as JavaObject; if (obj) { return new BlockStatePropertyBuilder(obj); } else { return null; } } /** * Add Integer Property * @param name Property Name * @param min Minimum Value * @param max Maximum Value * @param defaultValue Default Value */ intProperty(name: string, min: number, max: number, defaultValue: number): BlockStatePropertyBuilder { useBridge('BlockStatePropertyBuilder.intProperty', this.getJavaObject(), name, min, max, defaultValue); return this; } /** * Add Boolean Property * @param name Property Name * @param defaultValue Default Value */ booleanProperty(name: string, defaultValue: boolean): BlockStatePropertyBuilder { useBridge('BlockStatePropertyBuilder.booleanProperty', this.getJavaObject(), name, defaultValue); return this; } } type BlockStatePropertyType = string | number | boolean; /** * Block State */ export class BlockState extends JavaObjectWrapper { /** * Create Block State Wrapper From Java Object * @param javaObject Java Object */ constructor(javaObject: JavaObject | JavaObjectWrapper) { super(javaObject); this.assertValidJavaObject('BlockState'); } /** * Get Block ID * @returns Block ID */ getBlock(): Block { const obj = useBridge('BlockState.getBlock', this.getJavaObject()) as JavaObject; if (obj !== null) { return new Block(obj); } else { return null; } } /** * Get Custom Block * @returns Custom Block */ getCustomBlock(): CustomBlock { const id = this.getBlock(); return BlockRegistry.INSTANCE.get(id.getID()); } /** * Get Block State Property * @param property Property Name * @returns Value */ get(property: string): BlockStatePropertyType { return useBridge('BlockState.get', this.getJavaObject(), property) as BlockStatePropertyType; } /** * Get New Block State With Property Set To Value * @param property Property Name * @param value Value * @returns New Block State */ with(property: string, value: BlockStatePropertyType): BlockState { const obj = useBridge('BlockState.with', this.getJavaObject(), property, value) as JavaObject; if (obj !== null) { return new BlockState(obj); } else { return null; } } /** * Get All Block State Properties * @returns All Block State Properties */ properties(): string[] { return useBridge('BlockState.properties', this.getJavaObject()) as string[]; } /** * Convert To String * @returns String */ toString(): string { const start = this.getBlock().getID().toString(); const properties = this.properties(); const parts: string[] = []; for (const property of properties) { parts.push(property + ' = ' + this.get(property).toString()); } return start + '[' + parts.join(', ') + ']'; } } /** * Block Entity */ export class BlockEntity extends JavaObjectWrapper { /** * Create Block Entity Wrapper From Java Object * @param javaObject Java Object */ constructor(javaObject: JavaObject | JavaObjectWrapper) { super(javaObject); this.assertValidJavaObject('BlockEntity'); } /** * Get Block Entity ID * @returns ID */ getID(): Identifier { const obj = useBridge('BlockEntity.getID', this.getJavaObject()) as string; if (obj !== null) { return new Identifier(obj); } else { return null; } } /** * Get Block Entity Inventory * @returns Inventory If Block Entity Has One, Otherwise NULL */ getInventory(): Inventory { const obj = useBridge('BlockEntity.getInventory', this.getJavaObject()) as JavaObject; if (obj !== null) { return new Inventory(obj); } else { return null; } } /** * Mark Dirty */ markDirty(): void { useBridge('BlockEntity.markDirty', this.getJavaObject()); } } /** * {@link CustomBlock} With {@link CustomBlockEntity} */ export class CustomBlockWithEntity extends CustomBlock { /** * Create Custom Block Entity * @returns Custom Block Entity */ createBlockEntity(): CustomBlockEntity { throw new Error('CustomBlockWithEntity.createBlockEntity is not implemented'); } } class BlockRegistry implements SimpleRegistry { static INSTANCE = new BlockRegistry(); readonly #blocks: Map; readonly #blockEntities: CustomBlockEntity[]; private constructor() { this.#blocks = new Map(); this.#blockEntities = []; } register(id: Identifier, obj: CustomBlock): void { this.#blocks.set(id.toString(), obj); useBridge(obj instanceof CustomBlockWithEntity ? 'Registry.registerBlockWithEntity' : 'Registry.registerBlock', id.toString(), obj.getSettings().createJavaObject(), obj.getPropertyBuilder().getJavaObject()); } 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; } getCustomBlockEntityByID(id: number): CustomBlockEntity { return this.#blockEntities[id]; } createCustomBlockEntity(id: Identifier, i: number): void { const block = this.get(id) as CustomBlockWithEntity; this.#blockEntities[i] = block.createBlockEntity(); } freeCustomBlockEntity(i: number): void { delete this.#blockEntities[i]; } } Registry.BLOCK = BlockRegistry.INSTANCE; addBridge('CustomBlockEntity.create', (id: string, i: number) => { BlockRegistry.INSTANCE.createCustomBlockEntity(new Identifier(id), i); }); addBridge('CustomBlockEntity.fromTag', (i: number, tag: JavaObject) => { BlockRegistry.INSTANCE.getCustomBlockEntityByID(i).fromTag(new CompoundTag(tag)); }); addBridge('CustomBlockEntity.toTag', (i: number, tag: JavaObject): JavaObject => { return BlockRegistry.INSTANCE.getCustomBlockEntityByID(i).toTag(new CompoundTag(tag)).getJavaObject(); }); addBridge('CustomBlockEntity.tick', (i: number) => { BlockRegistry.INSTANCE.getCustomBlockEntityByID(i).tick(); }); addBridge('CustomBlockEntity.setLocation', (i: number, world: JavaObject, x: number, y: number, z: number) => { BlockRegistry.INSTANCE.getCustomBlockEntityByID(i).setLocation(new World(world), new Pos(x, y, z)); }); addBridge('CustomBlockEntity.free', (i: number) => { BlockRegistry.INSTANCE.freeCustomBlockEntity(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]); }); /** * @internal */ export class BlockBuiltinRegistry implements SimpleBuiltinRegistry { static readonly INSTANCE = new BlockBuiltinRegistry(); private constructor() { } get(id: Identifier): Block { const obj = useBridge('BuiltinRegistry.getBlock', id.toString()) as JavaObject; if (obj !== null) { return new Block(obj); } else { return null; } } }