import * as anchor from "@coral-xyz/anchor"; import { Program } from "@coral-xyz/anchor"; import { PublicKey } from "@solana/web3.js"; import { ComponentPosition } from "../target/types/component_position"; import { ComponentVelocity } from "../target/types/component_velocity"; import { BoltComponent } from "../target/types/bolt_component"; import { SystemSimpleMovement } from "../target/types/system_simple_movement"; import { SystemFly } from "../target/types/system_fly"; import { SystemApplyVelocity } from "../target/types/system_apply_velocity"; import { World } from "../target/types/world"; import { expect } from "chai"; import BN from "bn.js"; enum Direction { Left = "Left", Right = "Right", Up = "Up", Down = "Down", } function serializeArgs(args: any = {}) { const jsonString = JSON.stringify(args); const encoder = new TextEncoder(); const binaryData = encoder.encode(jsonString); return Buffer.from( binaryData.buffer, binaryData.byteOffset, binaryData.byteLength ); } describe("bolt", () => { const provider = anchor.AnchorProvider.env(); anchor.setProvider(provider); const worldProgram = anchor.workspace.World as Program; const boltComponentPositionProgram = anchor.workspace .ComponentPosition as Program; const boltComponentVelocityProgram = anchor.workspace .ComponentVelocity as Program; const boltComponentProgramOrigin = anchor.workspace .BoltComponent as Program; const systemSimpleMovement = ( anchor.workspace.SystemSimpleMovement as Program ).programId; const systemFly = (anchor.workspace.SystemFly as Program) .programId; const applyVelocity = ( anchor.workspace.SystemApplyVelocity as Program ).programId; let entity1: PublicKey; let entity2: PublicKey; let componentPositionEntity1: PublicKey; let componentPositionEntity2: PublicKey; let componentVelocityEntity1: PublicKey; it("InitializeWorldsRegistry", async () => { const registryPda = FindWorldRegistryPda(worldProgram); await worldProgram.methods .initializeRegistry() .accounts({ registry: registryPda, payer: provider.wallet.publicKey, }) .rpc(); }); it("InitializeNewWorld", async () => { const registryPda = FindWorldRegistryPda(worldProgram); const worldPda = FindWorldPda(worldProgram, new BN(0)); await worldProgram.methods .initializeNewWorld() .accounts({ world: worldPda, registry: registryPda, payer: provider.wallet.publicKey, }) .rpc(); }); it("Add entity 1", async () => { const worldPda = FindWorldPda(worldProgram, new BN(0)); entity1 = FindEntityPda(worldProgram, new BN(0), new BN(0)); await worldProgram.methods .addEntity() .accounts({ world: worldPda, entity: entity1, payer: provider.wallet.publicKey, }) .rpc(); }); it("Add entity 2", async () => { const worldPda = FindWorldPda(worldProgram, new BN(0)); entity2 = FindEntityPda(worldProgram, new BN(0), new BN(1)); await worldProgram.methods .addEntity() .accounts({ world: worldPda, entity: entity2, payer: provider.wallet.publicKey, }) .rpc(); }); it("Add entity 3", async () => { const worldPda = FindWorldPda(worldProgram, new BN(0)); const entityPda = FindEntityPda(worldProgram, new BN(0), new BN(2)); await worldProgram.methods .addEntity() .accounts({ world: worldPda, entity: entityPda, payer: provider.wallet.publicKey, }) .rpc(); }); it("Initialize Original Component on Entity 1, trough the world instance", async () => { let componentEntity1 = FindComponentPda( boltComponentProgramOrigin.programId, entity1, "origin-component" ); await worldProgram.methods .initializeComponent() .accounts({ payer: provider.wallet.publicKey, data: componentEntity1, componentProgram: boltComponentProgramOrigin.programId, entity: entity1, }) .rpc(); }); it("Initialize Original Component on Entity 2, trough the world instance", async () => { let componentEntity2 = FindComponentPda( boltComponentProgramOrigin.programId, entity2, "origin-component" ); await worldProgram.methods .initializeComponent() .accounts({ payer: provider.wallet.publicKey, data: componentEntity2, componentProgram: boltComponentProgramOrigin.programId, entity: entity2, }) .rpc(); }); it("Initialize Position Component on Entity 1", async () => { componentPositionEntity1 = FindComponentPda( boltComponentPositionProgram.programId, entity1, "component-position" ); console.log("Component Position E1: ", componentPositionEntity1.toBase58()); await worldProgram.methods .initializeComponent() .accounts({ payer: provider.wallet.publicKey, data: componentPositionEntity1, componentProgram: boltComponentPositionProgram.programId, entity: entity1, }) .rpc(); }); it("Initialize Velocity Component on Entity 1", async () => { componentVelocityEntity1 = FindComponentPda( boltComponentVelocityProgram.programId, entity1, "component-velocity" ); await worldProgram.methods .initializeComponent() .accounts({ payer: provider.wallet.publicKey, data: componentVelocityEntity1, componentProgram: boltComponentVelocityProgram.programId, entity: entity1, }) .rpc(); }); it("Initialize Position Component on Entity 2", async () => { componentPositionEntity2 = FindComponentPda( boltComponentPositionProgram.programId, entity2, "component-position" ); await worldProgram.methods .initializeComponent() .accounts({ payer: provider.wallet.publicKey, data: componentPositionEntity2, componentProgram: boltComponentPositionProgram.programId, entity: entity2, }) .rpc(); }); it("Check Position on Entity 1 is default", async () => { expect( ( await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ) ).x.toNumber() ).to.equal(0); expect( ( await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ) ).y.toNumber() ).to.equal(0); expect( ( await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ) ).z.toNumber() ).to.equal(0); }); it("Simple Movement System and Up direction on Entity 1", async () => { const args = { direction: Direction.Up, }; await worldProgram.methods .apply(serializeArgs(args)) // Move Up .accounts({ componentProgram: boltComponentPositionProgram.programId, boltSystem: systemSimpleMovement, boltComponent: componentPositionEntity1, }) .rpc({ skipPreflight: true }); expect( ( await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ) ).y.toNumber() ).to.equal(1); const componentData = await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ); const x = componentData.x.toNumber(); const y = componentData.y.toNumber(); const z = componentData.z.toNumber(); console.log("+-----------------------------+"); console.log("| Movement System: Entity 1 |"); console.log("+----------------+------------+"); console.log("| Coordinate | Value |"); console.log("+----------------+------------+"); console.log(`| X Position | ${String(x).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`); console.log("+----------------+------------+"); console.log("| |"); console.log("+-----------------------------+"); }); it("Simple Movement System and Right direction on Entity 1", async () => { const args = { direction: Direction.Right, }; await worldProgram.methods .apply(serializeArgs(args)) // Move Right .accounts({ componentProgram: boltComponentPositionProgram.programId, boltSystem: systemSimpleMovement, boltComponent: componentPositionEntity1, }) .rpc({ skipPreflight: true }); expect( ( await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ) ).y.toNumber() ).to.equal(1); expect( ( await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ) ).y.toNumber() ).to.equal(1); const componentData = await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ); const x = componentData.x.toNumber(); const y = componentData.y.toNumber(); const z = componentData.z.toNumber(); console.log("+-----------------------------+"); console.log("| Movement System: Entity 1 |"); console.log("+----------------+------------+"); console.log("| Coordinate | Value |"); console.log("+----------------+------------+"); console.log(`| X Position | ${String(x).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`); console.log("+----------------+------------+"); console.log("| |"); console.log("+-----------------------------+"); }); it("Fly System on Entity 1", async () => { await worldProgram.methods .apply(Buffer.alloc(0)) // Move Up .accounts({ componentProgram: boltComponentPositionProgram.programId, boltSystem: systemFly, boltComponent: componentPositionEntity1, }) .rpc(); expect( ( await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ) ).z.toNumber() ).to.equal(1); const componentData = await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ); const x = componentData.x.toNumber(); const y = componentData.y.toNumber(); const z = componentData.z.toNumber(); console.log("+-----------------------------+"); console.log("| Fly: Position Entity 1 |"); console.log("+----------------+------------+"); console.log("| Coordinate | Value |"); console.log("+----------------+------------+"); console.log(`| X Position | ${String(x).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`); console.log("+----------------+------------+"); console.log("| |"); console.log("+-----------------------------+"); }); it("Apply Velocity on Entity 1", async () => { await worldProgram.methods .apply2(Buffer.alloc(0)) .accounts({ componentProgram1: boltComponentVelocityProgram.programId, componentProgram2: boltComponentPositionProgram.programId, boltSystem: applyVelocity, boltComponent1: componentVelocityEntity1, boltComponent2: componentPositionEntity1, }) .remainingAccounts([ { pubkey: componentPositionEntity1, isWritable: false, isSigner: false, }, ]) .rpc(); console.log("Component Velocity: ", componentVelocityEntity1.toBase58()); let componentData = await boltComponentVelocityProgram.account.velocity.fetch( componentVelocityEntity1 ); let x = componentData.x.toNumber(); let y = componentData.y.toNumber(); let z = componentData.z.toNumber(); const tmp = componentData.lastApplied.toNumber(); console.log("+-----------------------------+"); console.log("| Apply Velocity: Velocity Entity 1 |"); console.log("+----------------+------------+"); console.log("| Coordinate | Value |"); console.log("+----------------+------------+"); console.log(`| X Position | ${String(x).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Timestamp | ${String(tmp).padEnd(10, " ")} |`); console.log("+----------------+------------+"); console.log("| |"); console.log("+-----------------------------+"); let positionData = await boltComponentPositionProgram.account.position.fetch( componentPositionEntity1 ); x = positionData.x.toNumber(); y = positionData.y.toNumber(); z = positionData.z.toNumber(); console.log("+-----------------------------+"); console.log("| Apply Velocity: Position Entity 1 |"); console.log("+----------------+------------+"); console.log("| Coordinate | Value |"); console.log("+----------------+------------+"); console.log(`| X Position | ${String(x).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`); console.log("| | |"); console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`); console.log("+----------------+------------+"); console.log("| |"); console.log("+-----------------------------+"); }); // Utils function FindWorldRegistryPda(program: Program) { return PublicKey.findProgramAddressSync( [Buffer.from("registry")], program.programId )[0]; } function FindWorldPda(program: Program, id: BN) { return PublicKey.findProgramAddressSync( [Buffer.from("world"), id.toBuffer("le", 8)], program.programId )[0]; } function FindEntityPda(program: Program, worldId: BN, entityId: BN) { return PublicKey.findProgramAddressSync( [ Buffer.from("entity"), worldId.toBuffer("be", 8), entityId.toBuffer("be", 8), ], program.programId )[0]; } function FindComponentPda( program: PublicKey, entity: PublicKey, seed: string = "component" ) { return PublicKey.findProgramAddressSync( [Buffer.from(seed), entity.toBytes()], program )[0]; } });