Waivio

Recommended Posts

RPGJS Tutorial - How to handle committee-account blocked accounts in game...

2 comments

nftea.gallery1.5 K2 months agoHive.Blog4 min read

https://images.hive.blog/DQmSz7NPUhG1xCrJaNvXiM565HL7C1jj2HNGAMkVDBtUHfY/image.png

As you may have been following, I've recently been blogging about my efforts working with the rpg-js framework, check out my profile if you've missed out on this content!

Today's tutorial covers several areas:

  • Retrieving the blocked account list from the committee-account
  • Map & game design

Let's first fetch the block list

I threw together the following nanoeffect!

import { nanoquery } from "@nanostores/query";
import Apis from "../../bts/ws/ApiInstances";
import { chains } from "../../config/chains";

import * as hash from "../../bts/ecc/hash.js";

import { $blockList } from "../../nanostores/blocklist";

async function getBlockedaccounts (chain: string) {
    return new Promise(async (resolve, reject) => {

        let _existingBlockList = $blockList.get();

        if (
          _existingBlockList.users.length > 0
          && (Date.now() - _existingBlockList.timestamp) < 1000 * 60 * 60 * 24
        ) {
            resolve(_existingBlockList.users);
            return;
        }

        let node = chains[chain].nodeList[0].url;

        let currentAPI;
        try {
          currentAPI = await Apis.instance(node, true, 4000, { enableDatabase: true }, (error: Error) =>
              console.log({ error })
            );
        } catch (error) {
          console.log({ error });
          reject(error);
          return;
        }

        let committeeAccount: any;
        try {
            committeeAccount = await currentAPI.db_api().exec("get_accounts", [["committee-blacklist-manager"]]);
        } catch (error) {
          console.log({ error });
          reject(error);
          return;
        }

        if (!committeeAccount || !committeeAccount.length) {
          reject(new Error("Unable to retrieve committee account"));
          return;
        }

        const blockedList = committeeAccount[0].blacklisted_accounts;

        let hashedBlockList = blockedList.map(account => hash.sha256(account).toString("hex"));
    
&nbsp;
        resolve(hashedBlockList);
    });
}

const [createBlockedAccountStore] = nanoquery({
    fetcher: async (...args: unknown[]) => {
        const chain = args[0] as string;

        let response;
        try {
            response = await getBlockedaccounts(chain);
        } catch (error) {
            console.log({ error });
            return;
        }
  
        if (!response) {
          console.log(`Failed to fetch banned accounts`);
          return;
        }
    
        return response;
    }
});

export {
    createBlockedAccountStore,
    getBlockedaccounts
};

.
This gave us the ability to create a blocked account store fetcher within our in-game Vue GUI component once it was mounted in view:

    onMounted(() => {
      const _blockList = $blockList.get();
      if (!_blockList.users.length) {
        console.log("Fetching block list..")
        const blockListStore = createBlockedAccountStore(["bitshares"]);

        const unsub = blockListStore.subscribe((result) => {
          if (result.error) {
            console.error(result.error);
          }

          if (!result.loading && result.data) {
            console.log({result: result.data})
            updateBlockList(result.data);
          }
        });

        return () => {
          unsub();
        };
      }
    });

.
With this list of blocked users now generally available let's store it in a nanostore to avoid repeated blockchain queries:

import { persistentMap } from "@nanostores/persistent";

type StoredBlocklist = {
    users: string[];
    timestamp: number;
};

const $blockList = persistentMap<StoredBlocklist>(
    "blocklist",
    {
        users: [],
        timestamp: Date.now(),
    },
    {
      encode(value) {
        return JSON.stringify(value);
      },
      decode(value) {
        try {
          return JSON.parse(value);
        } catch (e) {
          console.log(e);
          return value;
        }
      },
    }
);

function updateBlockList(users: string[]) {
    $blockList.set({
        users,
        timestamp: Date.now(),
    });
}

export { $blockList, updateBlockList };

.
Then, within the intro component (where the user picks their Bitshares account), we'll check if they're trying to use a blocked account id:

    async function checkBlocked(id) {
      const _id = hash.sha256(id).toString("hex");
      const _blockList = $blockList.get();
      if (_blockList.users.includes(_id)) {
        console.log("You're banned from using this app!");
        player.value.items = [];
        player.value.gold = 0;
        player.value.changeMap("jail");
      }
    }

.
Note that we are hashing the account id, this is so that we avoid storing names of blocked accounts in memory, we can scramble the data whilst retaining the ability to detect their attempted use of the app!

So, you might have spotted what we do in the checkBlocked function - we remove their items and gold, then we send them to a jail cell in the castle basement in which they're unable to proceed to do anything in game.

So let's check out what this new map looks like...

https://s12.gifyu.com/images/StFp4.gif

And here's how it looks if you try to use a blocked account!

https://s12.gifyu.com/images/StFgV.gif

Cool, so now we can rest assured that accounts deemed ban worthy are unable to proceed to play the rpgjs demo!

They're unable to go anywhere else in the game other than the castle basement jail cell, lol!


So, what do you think?

Comments and feedback welcome below! :)


These developments were brought to you by the NFTEA Gallery.

Consider collecting an NFTEA NFT to or donate to the following BTS or EOS blockchain accounts directly, to fund continued developments.

Don't have a Bitshares account? Make one today!

Comments

Sort byBest
AI
Waivio AI Assistant
How can I help you today?