bolt.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. import * as anchor from "@coral-xyz/anchor";
  2. import { Program } from "@coral-xyz/anchor";
  3. import { PublicKey } from "@solana/web3.js";
  4. import { ComponentPosition } from "../target/types/component_position";
  5. import { ComponentVelocity } from "../target/types/component_velocity";
  6. import { BoltComponent } from "../target/types/bolt_component";
  7. import { SystemSimpleMovement } from "../target/types/system_simple_movement";
  8. import { SystemFly } from "../target/types/system_fly";
  9. import { SystemApplyVelocity } from "../target/types/system_apply_velocity";
  10. import { World } from "../target/types/world";
  11. import { expect } from "chai";
  12. import BN from "bn.js";
  13. enum Direction {
  14. Left = "Left",
  15. Right = "Right",
  16. Up = "Up",
  17. Down = "Down",
  18. }
  19. function serializeArgs(args: any = {}) {
  20. const jsonString = JSON.stringify(args);
  21. const encoder = new TextEncoder();
  22. const binaryData = encoder.encode(jsonString);
  23. return Buffer.from(
  24. binaryData.buffer,
  25. binaryData.byteOffset,
  26. binaryData.byteLength
  27. );
  28. }
  29. describe("bolt", () => {
  30. const provider = anchor.AnchorProvider.env();
  31. anchor.setProvider(provider);
  32. const worldProgram = anchor.workspace.World as Program<World>;
  33. const boltComponentPositionProgram = anchor.workspace
  34. .ComponentPosition as Program<ComponentPosition>;
  35. const boltComponentVelocityProgram = anchor.workspace
  36. .ComponentVelocity as Program<ComponentVelocity>;
  37. const boltComponentProgramOrigin = anchor.workspace
  38. .BoltComponent as Program<BoltComponent>;
  39. const systemSimpleMovement = (
  40. anchor.workspace.SystemSimpleMovement as Program<SystemSimpleMovement>
  41. ).programId;
  42. const systemFly = (anchor.workspace.SystemFly as Program<SystemFly>)
  43. .programId;
  44. const applyVelocity = (
  45. anchor.workspace.SystemApplyVelocity as Program<SystemApplyVelocity>
  46. ).programId;
  47. let entity1: PublicKey;
  48. let entity2: PublicKey;
  49. let componentPositionEntity1: PublicKey;
  50. let componentPositionEntity2: PublicKey;
  51. let componentVelocityEntity1: PublicKey;
  52. it("InitializeWorldsRegistry", async () => {
  53. const registryPda = FindWorldRegistryPda(worldProgram);
  54. await worldProgram.methods
  55. .initializeRegistry()
  56. .accounts({
  57. registry: registryPda,
  58. payer: provider.wallet.publicKey,
  59. })
  60. .rpc();
  61. });
  62. it("InitializeNewWorld", async () => {
  63. const registryPda = FindWorldRegistryPda(worldProgram);
  64. const worldPda = FindWorldPda(worldProgram, new BN(0));
  65. await worldProgram.methods
  66. .initializeNewWorld()
  67. .accounts({
  68. world: worldPda,
  69. registry: registryPda,
  70. payer: provider.wallet.publicKey,
  71. })
  72. .rpc();
  73. });
  74. it("InitializeNewWorld 2", async () => {
  75. const registryPda = FindWorldRegistryPda(worldProgram);
  76. const worldPda = FindWorldPda(worldProgram, new BN(1));
  77. await worldProgram.methods
  78. .initializeNewWorld()
  79. .accounts({
  80. world: worldPda,
  81. registry: registryPda,
  82. payer: provider.wallet.publicKey,
  83. })
  84. .rpc();
  85. });
  86. it("Add entity 1", async () => {
  87. const worldPda = FindWorldPda(worldProgram, new BN(0));
  88. entity1 = FindEntityPda(worldProgram, new BN(0), new BN(0));
  89. await worldProgram.methods
  90. .addEntity(null)
  91. .accounts({
  92. world: worldPda,
  93. entity: entity1,
  94. payer: provider.wallet.publicKey,
  95. })
  96. .rpc();
  97. });
  98. it("Add entity 2", async () => {
  99. const worldPda = FindWorldPda(worldProgram, new BN(0));
  100. entity2 = FindEntityPda(worldProgram, new BN(0), new BN(1));
  101. await worldProgram.methods
  102. .addEntity(null)
  103. .accounts({
  104. world: worldPda,
  105. entity: entity2,
  106. payer: provider.wallet.publicKey,
  107. })
  108. .rpc();
  109. });
  110. it("Add entity 3", async () => {
  111. const worldPda = FindWorldPda(worldProgram, new BN(0));
  112. const entityPda = FindEntityPda(worldProgram, new BN(0), new BN(2));
  113. await worldProgram.methods
  114. .addEntity(null)
  115. .accounts({
  116. world: worldPda,
  117. entity: entityPda,
  118. payer: provider.wallet.publicKey,
  119. })
  120. .rpc();
  121. });
  122. it("Add entity 4 with extra seeds", async () => {
  123. const worldPda = FindWorldPda(worldProgram, new BN(0));
  124. const seed = "extra-seed";
  125. let entity3 = FindEntityPda(worldProgram, new BN(0), new BN(3), seed);
  126. await worldProgram.methods
  127. .addEntity(seed)
  128. .accounts({
  129. world: worldPda,
  130. entity: entity3,
  131. payer: provider.wallet.publicKey,
  132. })
  133. .rpc();
  134. });
  135. it("Initialize Original Component on Entity 1, trough the world instance", async () => {
  136. let componentEntity1 = FindComponentPda(
  137. boltComponentProgramOrigin.programId,
  138. entity1,
  139. "origin-component"
  140. );
  141. await worldProgram.methods
  142. .initializeComponent()
  143. .accounts({
  144. payer: provider.wallet.publicKey,
  145. data: componentEntity1,
  146. componentProgram: boltComponentProgramOrigin.programId,
  147. entity: entity1,
  148. })
  149. .rpc();
  150. });
  151. it("Initialize Original Component on Entity 2, trough the world instance", async () => {
  152. let componentEntity2 = FindComponentPda(
  153. boltComponentProgramOrigin.programId,
  154. entity2,
  155. "origin-component"
  156. );
  157. await worldProgram.methods
  158. .initializeComponent()
  159. .accounts({
  160. payer: provider.wallet.publicKey,
  161. data: componentEntity2,
  162. componentProgram: boltComponentProgramOrigin.programId,
  163. entity: entity2,
  164. })
  165. .rpc();
  166. });
  167. it("Initialize Position Component on Entity 1", async () => {
  168. componentPositionEntity1 = FindComponentPda(
  169. boltComponentPositionProgram.programId,
  170. entity1,
  171. "component-position"
  172. );
  173. console.log("Component Position E1: ", componentPositionEntity1.toBase58());
  174. await worldProgram.methods
  175. .initializeComponent()
  176. .accounts({
  177. payer: provider.wallet.publicKey,
  178. data: componentPositionEntity1,
  179. componentProgram: boltComponentPositionProgram.programId,
  180. entity: entity1,
  181. })
  182. .rpc();
  183. });
  184. it("Initialize Velocity Component on Entity 1", async () => {
  185. componentVelocityEntity1 = FindComponentPda(
  186. boltComponentVelocityProgram.programId,
  187. entity1,
  188. "component-velocity"
  189. );
  190. await worldProgram.methods
  191. .initializeComponent()
  192. .accounts({
  193. payer: provider.wallet.publicKey,
  194. data: componentVelocityEntity1,
  195. componentProgram: boltComponentVelocityProgram.programId,
  196. entity: entity1,
  197. })
  198. .rpc();
  199. });
  200. it("Initialize Position Component on Entity 2", async () => {
  201. componentPositionEntity2 = FindComponentPda(
  202. boltComponentPositionProgram.programId,
  203. entity2,
  204. "component-position"
  205. );
  206. await worldProgram.methods
  207. .initializeComponent()
  208. .accounts({
  209. payer: provider.wallet.publicKey,
  210. data: componentPositionEntity2,
  211. componentProgram: boltComponentPositionProgram.programId,
  212. entity: entity2,
  213. })
  214. .rpc();
  215. });
  216. it("Check Position on Entity 1 is default", async () => {
  217. expect(
  218. (
  219. await boltComponentPositionProgram.account.position.fetch(
  220. componentPositionEntity1
  221. )
  222. ).x.toNumber()
  223. ).to.equal(0);
  224. expect(
  225. (
  226. await boltComponentPositionProgram.account.position.fetch(
  227. componentPositionEntity1
  228. )
  229. ).y.toNumber()
  230. ).to.equal(0);
  231. expect(
  232. (
  233. await boltComponentPositionProgram.account.position.fetch(
  234. componentPositionEntity1
  235. )
  236. ).z.toNumber()
  237. ).to.equal(0);
  238. });
  239. it("Simple Movement System and Up direction on Entity 1", async () => {
  240. const args = {
  241. direction: Direction.Up,
  242. };
  243. await worldProgram.methods
  244. .apply(serializeArgs(args)) // Move Up
  245. .accounts({
  246. componentProgram: boltComponentPositionProgram.programId,
  247. boltSystem: systemSimpleMovement,
  248. boltComponent: componentPositionEntity1,
  249. })
  250. .rpc({ skipPreflight: true });
  251. expect(
  252. (
  253. await boltComponentPositionProgram.account.position.fetch(
  254. componentPositionEntity1
  255. )
  256. ).y.toNumber()
  257. ).to.equal(1);
  258. const componentData =
  259. await boltComponentPositionProgram.account.position.fetch(
  260. componentPositionEntity1
  261. );
  262. const x = componentData.x.toNumber();
  263. const y = componentData.y.toNumber();
  264. const z = componentData.z.toNumber();
  265. console.log("+-----------------------------+");
  266. console.log("| Movement System: Entity 1 |");
  267. console.log("+----------------+------------+");
  268. console.log("| Coordinate | Value |");
  269. console.log("+----------------+------------+");
  270. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  271. console.log("| | |");
  272. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  273. console.log("| | |");
  274. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  275. console.log("+----------------+------------+");
  276. console.log("| |");
  277. console.log("+-----------------------------+");
  278. });
  279. it("Simple Movement System and Right direction on Entity 1", async () => {
  280. const args = {
  281. direction: Direction.Right,
  282. };
  283. await worldProgram.methods
  284. .apply(serializeArgs(args)) // Move Right
  285. .accounts({
  286. componentProgram: boltComponentPositionProgram.programId,
  287. boltSystem: systemSimpleMovement,
  288. boltComponent: componentPositionEntity1,
  289. })
  290. .rpc({ skipPreflight: true });
  291. expect(
  292. (
  293. await boltComponentPositionProgram.account.position.fetch(
  294. componentPositionEntity1
  295. )
  296. ).y.toNumber()
  297. ).to.equal(1);
  298. expect(
  299. (
  300. await boltComponentPositionProgram.account.position.fetch(
  301. componentPositionEntity1
  302. )
  303. ).y.toNumber()
  304. ).to.equal(1);
  305. const componentData =
  306. await boltComponentPositionProgram.account.position.fetch(
  307. componentPositionEntity1
  308. );
  309. const x = componentData.x.toNumber();
  310. const y = componentData.y.toNumber();
  311. const z = componentData.z.toNumber();
  312. console.log("+-----------------------------+");
  313. console.log("| Movement System: Entity 1 |");
  314. console.log("+----------------+------------+");
  315. console.log("| Coordinate | Value |");
  316. console.log("+----------------+------------+");
  317. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  318. console.log("| | |");
  319. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  320. console.log("| | |");
  321. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  322. console.log("+----------------+------------+");
  323. console.log("| |");
  324. console.log("+-----------------------------+");
  325. });
  326. it("Fly System on Entity 1", async () => {
  327. await worldProgram.methods
  328. .apply(Buffer.alloc(0)) // Move Up
  329. .accounts({
  330. componentProgram: boltComponentPositionProgram.programId,
  331. boltSystem: systemFly,
  332. boltComponent: componentPositionEntity1,
  333. })
  334. .rpc();
  335. expect(
  336. (
  337. await boltComponentPositionProgram.account.position.fetch(
  338. componentPositionEntity1
  339. )
  340. ).z.toNumber()
  341. ).to.equal(1);
  342. const componentData =
  343. await boltComponentPositionProgram.account.position.fetch(
  344. componentPositionEntity1
  345. );
  346. const x = componentData.x.toNumber();
  347. const y = componentData.y.toNumber();
  348. const z = componentData.z.toNumber();
  349. console.log("+-----------------------------+");
  350. console.log("| Fly: Position Entity 1 |");
  351. console.log("+----------------+------------+");
  352. console.log("| Coordinate | Value |");
  353. console.log("+----------------+------------+");
  354. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  355. console.log("| | |");
  356. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  357. console.log("| | |");
  358. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  359. console.log("+----------------+------------+");
  360. console.log("| |");
  361. console.log("+-----------------------------+");
  362. });
  363. it("Apply Velocity on Entity 1", async () => {
  364. await worldProgram.methods
  365. .apply2(Buffer.alloc(0))
  366. .accounts({
  367. componentProgram1: boltComponentVelocityProgram.programId,
  368. componentProgram2: boltComponentPositionProgram.programId,
  369. boltSystem: applyVelocity,
  370. boltComponent1: componentVelocityEntity1,
  371. boltComponent2: componentPositionEntity1,
  372. })
  373. .remainingAccounts([
  374. {
  375. pubkey: componentPositionEntity1,
  376. isWritable: false,
  377. isSigner: false,
  378. },
  379. ])
  380. .rpc();
  381. console.log("Component Velocity: ", componentVelocityEntity1.toBase58());
  382. let componentData =
  383. await boltComponentVelocityProgram.account.velocity.fetch(
  384. componentVelocityEntity1
  385. );
  386. let x = componentData.x.toNumber();
  387. let y = componentData.y.toNumber();
  388. let z = componentData.z.toNumber();
  389. const tmp = componentData.lastApplied.toNumber();
  390. console.log("+-----------------------------+");
  391. console.log("| Apply Velocity: Velocity Entity 1 |");
  392. console.log("+----------------+------------+");
  393. console.log("| Coordinate | Value |");
  394. console.log("+----------------+------------+");
  395. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  396. console.log("| | |");
  397. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  398. console.log("| | |");
  399. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  400. console.log("| | |");
  401. console.log(`| Timestamp | ${String(tmp).padEnd(10, " ")} |`);
  402. console.log("+----------------+------------+");
  403. console.log("| |");
  404. console.log("+-----------------------------+");
  405. let positionData =
  406. await boltComponentPositionProgram.account.position.fetch(
  407. componentPositionEntity1
  408. );
  409. x = positionData.x.toNumber();
  410. y = positionData.y.toNumber();
  411. z = positionData.z.toNumber();
  412. console.log("+-----------------------------+");
  413. console.log("| Apply Velocity: Position Entity 1 |");
  414. console.log("+----------------+------------+");
  415. console.log("| Coordinate | Value |");
  416. console.log("+----------------+------------+");
  417. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  418. console.log("| | |");
  419. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  420. console.log("| | |");
  421. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  422. console.log("+----------------+------------+");
  423. console.log("| |");
  424. console.log("+-----------------------------+");
  425. });
  426. // Utils
  427. function FindWorldRegistryPda(program: Program<World>) {
  428. return PublicKey.findProgramAddressSync(
  429. [Buffer.from("registry")],
  430. program.programId
  431. )[0];
  432. }
  433. function FindWorldPda(program: Program<World>, id: BN) {
  434. return PublicKey.findProgramAddressSync(
  435. [Buffer.from("world"), id.toBuffer("be", 8)],
  436. program.programId
  437. )[0];
  438. }
  439. function FindEntityPda(
  440. program: Program<World>,
  441. worldId: BN,
  442. entityId: BN,
  443. extraSeed?: string
  444. ) {
  445. let seeds = [Buffer.from("entity"), worldId.toBuffer("be", 8)];
  446. if (extraSeed) {
  447. seeds.push(Buffer.from(new Uint8Array(8)));
  448. seeds.push(Buffer.from(extraSeed));
  449. } else {
  450. seeds.push(entityId.toBuffer("be", 8));
  451. }
  452. return PublicKey.findProgramAddressSync(seeds, program.programId)[0];
  453. }
  454. function FindComponentPda(
  455. program: PublicKey,
  456. entity: PublicKey,
  457. seed: string = "component"
  458. ) {
  459. return PublicKey.findProgramAddressSync(
  460. [Buffer.from(seed), entity.toBytes()],
  461. program
  462. )[0];
  463. }
  464. });