mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-04-22 06:02:07 +02:00
new skills
This commit is contained in:
parent
a6b1f4cb81
commit
54da4c9032
6 changed files with 375 additions and 55 deletions
26
act.js
26
act.js
|
@ -13,7 +13,7 @@ function buildSystemMessage(bot) {
|
|||
|
||||
|
||||
function buildExamples() {
|
||||
return[
|
||||
return [
|
||||
`mr_steve2: Will you help me collect wood?
|
||||
|
||||
!blocks
|
||||
|
@ -25,19 +25,19 @@ NEARBY_BLOCKS
|
|||
\`\`\`
|
||||
|
||||
Me: I'd be glad to help you collect wood.`,
|
||||
`I'm going to help mr_steve2 collect wood. The type of wood block nearby is 'oak_log'. I'll adjust my code to collect 10 'oak_log' for mr_steve2.
|
||||
`I'm going to help mr_steve2 collect wood. The type of wood block nearby is 'oak_log'. I'll adjust my code to collect an 'oak_log' for mr_steve2.
|
||||
\`\`\`
|
||||
await skills.CollectBlock(bot, 'oak_log', 10);
|
||||
await skills.GoToPlayer(bot, 'mr_steve2');
|
||||
await skills.DropItem(bot, 'oak_log', 10);
|
||||
await skills.collectBlock(bot, 'oak_log');
|
||||
await skills.giveToPlayer(bot, 'oak_log', 'mr_steve2');
|
||||
\`\`\``,
|
||||
`sally32: What are you doing?
|
||||
|
||||
!action
|
||||
\`\`\`
|
||||
await skills.ExploreToFind(bot, 'coal_ore');
|
||||
await skills.EquipItem(bot, 'wooden_pickaxe');
|
||||
await skills.CollectBlock(bot, 'coal_ore', 10);
|
||||
await skills.equipItem(bot, 'wooden_pickaxe');
|
||||
while (world.getInventory(bot).coal_ore < 10) {
|
||||
await skills.collectBlock(bot, 'coal_ore');
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
Me: I'm looking for coal. Have you seen any?
|
||||
|
@ -46,20 +46,22 @@ sally32: Yes, there's some in this cave, follow me.`,
|
|||
`I'm going to follow sally32 to the cave and collect coal. I'll adjust my code to follow sally32 until I find coal_ore and then I'll mine it.
|
||||
\`\`\`
|
||||
while (true) {
|
||||
await skills.GoToPlayer(bot, 'sally32');
|
||||
await skills.goToPlayer(bot, 'sally32');
|
||||
if (world.getNearbyBlocks(bot).includes('coal_ore')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
await skills.EquipItem(bot, 'wooden_pickaxe');
|
||||
await skills.CollectBlock(bot, 'coal_ore', 10);
|
||||
await skills.equipItem(bot, 'wooden_pickaxe');
|
||||
while (world.getInventory(bot).coal_ore < 10) {
|
||||
await skills.collectBlock(bot, 'coal_ore');
|
||||
}
|
||||
\`\`\``,
|
||||
`user42: come here
|
||||
|
||||
Me: Sure! I'm on my way.`,
|
||||
`I'm going to navigate to user42.
|
||||
\`\`\`
|
||||
await skills.GoToPlayer(bot, 'user42');
|
||||
await skills.goToPlayer(bot, 'user42');
|
||||
\`\`\``,
|
||||
]
|
||||
}
|
||||
|
|
2
chat.js
2
chat.js
|
@ -10,7 +10,7 @@ function buildSystemMessage() {
|
|||
message += ' Do not give instructions unless asked, and always be brief in your responses.';
|
||||
message += '\n\nYou can use the following commands followed by to query for information about the world.';
|
||||
message += ' The query response will be returned between sets of "\`\`\`":';
|
||||
message += '\n!stats - get player and world stats (e.g. current health and time of day)';
|
||||
message += '\n!stats - get player and world stats (current health, time of day, etc.)';
|
||||
message += '\n!inventory - get your current inventory';
|
||||
message += '\n!blocks - get a list of nearby blocks';
|
||||
message += '\n!craftable - get a list of craftable items with your current inventory';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { readFileSync } from 'fs';
|
||||
|
||||
import { getNearbyBlocks, getNearbyBlockTypes } from './world.js';
|
||||
import { getCraftingTable, getNearbyMobTypes, getNearbyPlayerNames, getNearbyBlockTypes, getInventoryCounts } from './world.js';
|
||||
import { getAllItems } from './mcdata.js';
|
||||
|
||||
|
||||
|
@ -20,22 +20,14 @@ export function getStats(bot) {
|
|||
|
||||
|
||||
export function getInventory(bot) {
|
||||
let inventory = getInventoryCounts(bot);
|
||||
let res = 'INVENTORY';
|
||||
let allItems = new Map();
|
||||
for (const item of bot.inventory.slots.values()) {
|
||||
if (item != null) {
|
||||
if (allItems.has(item.name)) {
|
||||
allItems.set(item.name, allItems.get(item.name) + item.count);
|
||||
} else {
|
||||
allItems.set(item.name, item.count);
|
||||
}
|
||||
}
|
||||
for (const item in inventory) {
|
||||
if (inventory[item] > 0)
|
||||
res += `\n- ${item}: ${inventory[item]}`;
|
||||
}
|
||||
for (const [item, count] of allItems.entries()) {
|
||||
res += `\n- ${item}: ${count}`;
|
||||
}
|
||||
if (allItems.size == 0) {
|
||||
res += ': empty';
|
||||
if (res == 'INVENTORY') {
|
||||
res += ': none';
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -56,14 +48,11 @@ export function getBlocks(bot) {
|
|||
|
||||
export function getNearbyEntities(bot) {
|
||||
let res = 'NEARBY_ENTITIES';
|
||||
for (const entity of Object.values(bot.entities)) {
|
||||
const distance = entity.position.distanceTo(bot.entity.position);
|
||||
if (distance > 50) continue;
|
||||
if (entity.type == 'mob') {
|
||||
res += `\n- mob: ${entity.mobType}`;
|
||||
} else if (entity.type == 'player' && entity.username != bot.username) {
|
||||
res += `\n- player: ${entity.username}`;
|
||||
}
|
||||
for (const entity of getNearbyPlayerNames(bot)) {
|
||||
res += `\n- player: ${entity}`;
|
||||
}
|
||||
for (const entity of getNearbyMobTypes(bot)) {
|
||||
res += `\n- mob: ${entity}`;
|
||||
}
|
||||
if (res == 'NEARBY_ENTITIES') {
|
||||
res += ': none';
|
||||
|
@ -73,14 +62,7 @@ export function getNearbyEntities(bot) {
|
|||
|
||||
|
||||
export function getCraftable(bot) {
|
||||
const blocks = getNearbyBlocks(bot, 50);
|
||||
let table = null;
|
||||
for (const block of blocks) {
|
||||
if (block.name == 'crafting_table') {
|
||||
table = block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const table = getCraftingTable(bot);
|
||||
let res = 'CRAFTABLE_ITEMS';
|
||||
for (const item of getAllItems()) {
|
||||
let recipes = bot.recipesFor(item.id, null, 1, table);
|
||||
|
|
|
@ -26,7 +26,7 @@ Sure, do you want oak or birch?`},
|
|||
\`\`\`
|
||||
while (true) {
|
||||
await skills.CollectBlock(bot, 'oak_log', 1);
|
||||
await skills.GoToPlayer(bot, 'username');
|
||||
await skills.goToPlayer(bot, 'username');
|
||||
await skills.DropItem(bot, 'oak_log', 1);
|
||||
}
|
||||
\`\`\``}
|
||||
|
|
194
utils/skills.js
194
utils/skills.js
|
@ -1,4 +1,5 @@
|
|||
import { getItemId } from "./mcdata.js";
|
||||
import { getCraftingTable, getInventoryCounts, getInventoryStacks, getNearbyMobs, getNearbyBlocks } from "./world.js";
|
||||
import pf from 'mineflayer-pathfinder';
|
||||
|
||||
|
||||
|
@ -8,24 +9,207 @@ import pf from 'mineflayer-pathfinder';
|
|||
* @param {string} item_name, the item name to craft.
|
||||
* @returns {Promise<boolean>} true if the item was crafted, false otherwise.
|
||||
* @example
|
||||
* await skills.CraftItem(bot, "wooden_pickaxe");
|
||||
* await skills.craftItem(bot, "wooden_pickaxe");
|
||||
**/
|
||||
export async function CraftItem(bot, itemName) {
|
||||
let recipes = bot.recipesFor(getItemId(itemName), null, 1, null); // TODO add crafting table as final arg
|
||||
export async function craftItem(bot, itemName) {
|
||||
const table = getCraftingTable(bot);
|
||||
let recipes = bot.recipesFor(getItemId(itemName), null, 1, table);
|
||||
await bot.craft(recipes[0], 1, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attack mob of the given type.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {string} mobType, the type of mob to attack.
|
||||
* @returns {Promise<boolean>} true if the mob was attacked, false if the mob type was not found.
|
||||
* @example
|
||||
* await skills.attackMob(bot, "zombie");
|
||||
**/
|
||||
export async function attackMob(bot, mobType) {
|
||||
const mobs = getNearbyMobs(bot);
|
||||
for (let i = 0; i < mobs.length; i++) {
|
||||
if (mobs[i].mobType == mobType) {
|
||||
bot.attack(mobs[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collect one of the given block type.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {string} blockType, the type of block to collect.
|
||||
* @returns {Promise<boolean>} true if the block was collected, false if the block type was not found.
|
||||
* @example
|
||||
* await skills.collectBlock(bot, "oak_log");
|
||||
**/
|
||||
export async function collectBlock(bot, blockType) {
|
||||
const blocks = getNearbyBlocks(bot);
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i].name == blockType) {
|
||||
await bot.collectBlock.collect(blocks[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Break the block at the given position. Will use the bot's equipped item.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {number} x, the x coordinate of the block to break.
|
||||
* @param {number} y, the y coordinate of the block to break.
|
||||
* @param {number} z, the z coordinate of the block to break.
|
||||
* @returns {Promise<boolean>} true if the block was broken, false otherwise.
|
||||
* @example
|
||||
* let position = getPosition(bot);
|
||||
* await skills.breakBlockAt(bot, position.x, position.y - 1, position.x);
|
||||
**/
|
||||
export async function breakBlockAt(bot, x, y, z) {
|
||||
let current = bot.blockAt({ x: x, y: y, z: z });
|
||||
if (current.name != 'air')
|
||||
await bot.dig(current, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Place the given block type at the given position.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {string} blockType, the type of block to place.
|
||||
* @param {number} x, the x coordinate to place the block at.
|
||||
* @param {number} y, the y coordinate to place the block at.
|
||||
* @param {number} z, the z coordinate to place the block at.
|
||||
* @returns {Promise<boolean>} true if the block was placed, false otherwise.
|
||||
* @example
|
||||
* let position = getPosition(bot);
|
||||
* await skills.placeBlock(bot, "oak_log", position.x + 1, position.y, position.x);
|
||||
**/
|
||||
export async function placeBlock(bot, blockType, x, y, z) {
|
||||
|
||||
let referenceBlock = null;
|
||||
let refVec = null;
|
||||
if (bot.blockAt({ x: x + 1, y: y, z: z }).name != "air") {
|
||||
referenceBlock = bot.blockAt({ x: x + 1, y: y, z: z });
|
||||
refVec = { x: x - 1, y: y, z: z };
|
||||
} else if (bot.blockAt({ x: x - 1, y: y, z: z }).name != "air") {
|
||||
referenceBlock = bot.blockAt({ x: x - 1, y: y, z: z });
|
||||
refVec = { x: x + 1, y: y, z: z };
|
||||
} else if (bot.blockAt({ x: x, y: y + 1, z: z }).name != "air") {
|
||||
referenceBlock = bot.blockAt({ x: x, y: y + 1, z: z });
|
||||
refVec = { x: x, y: y - 1, z: z };
|
||||
} else if (bot.blockAt({ x: x, y: y - 1, z: z }).name != "air") {
|
||||
referenceBlock = bot.blockAt({ x: x, y: y - 1, z: z });
|
||||
refVec = { x: x, y: y + 1, z: z };
|
||||
} else if (bot.blockAt({ x: x, y: y, z: z + 1 }).name != "air") {
|
||||
referenceBlock = bot.blockAt({ x: x, y: y, z: z + 1 });
|
||||
refVec = { x: x, y: y, z: z - 1 };
|
||||
} else if (bot.blockAt({ x: x, y: y, z: z - 1 }).name != "air") {
|
||||
referenceBlock = bot.blockAt({ x: x, y: y, z: z - 1 });
|
||||
refVec = { x: x, y: y, z: z + 1 };
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
let block = null;
|
||||
for (let stack of getInventoryStacks(bot)) {
|
||||
if (stack.name == blockType) {
|
||||
block = stack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (block == null)
|
||||
return false;
|
||||
|
||||
breakBlockAt(bot, x, y, z);
|
||||
await bot.equip(block, 'hand');
|
||||
await bot.placeBlock(referenceBlock, refVec);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Equip the given item or block.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {string} itemName, the item or block name to equip.
|
||||
* @returns {Promise<boolean>} true if the item was equipped, false otherwise.
|
||||
* @example
|
||||
* await skills.equipItem(bot, "wooden_pickaxe");
|
||||
**/
|
||||
export async function equipItem(bot, itemName) {
|
||||
let item = null;
|
||||
for (let stack of getInventoryStacks(bot)) {
|
||||
if (stack.name == itemName) {
|
||||
item = stack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (item == null)
|
||||
return false;
|
||||
await bot.equip(item, 'hand');
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Navigate to the given position.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {number} x, the x coordinate to navigate to. If null, the bot's current x coordinate will be used.
|
||||
* @param {number} y, the y coordinate to navigate to. If null, the bot's current y coordinate will be used.
|
||||
* @param {number} z, the z coordinate to navigate to. If null, the bot's current z coordinate will be used.
|
||||
* @returns {Promise<boolean>} true if the position was reached, false otherwise.
|
||||
* @example
|
||||
* let position = getPosition(bot);
|
||||
* await skills.goToPosition(bot, position.x, position.y, position.x + 20);
|
||||
**/
|
||||
export async function goToPosition(bot, x, y, z) {
|
||||
if (x == null) x = bot.entity.position.x;
|
||||
if (y == null) y = bot.entity.position.y;
|
||||
if (z == null) z = bot.entity.position.z;
|
||||
bot.pathfinder.setMovements(new pf.Movements(bot));
|
||||
let pos = { x: x, y: y, z: z };
|
||||
bot.pathfinder.setGoal(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Give one of the specified item to the specified player
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {string} itemType, the name of the item to give.
|
||||
* @param {string} username, the username of the player to give the item to.
|
||||
* @returns {Promise<boolean>} true if the item was given, false otherwise.
|
||||
* @example
|
||||
* await skills.giveToPlayer(bot, "oak_log", "player1");
|
||||
**/
|
||||
export async function giveToPlayer(bot, itemType, username) {
|
||||
let player = bot.players[username].entity
|
||||
if (!player)
|
||||
return false;
|
||||
if (getInventoryCounts(bot)[itemType] == 0)
|
||||
return false;
|
||||
goToPlayer(bot, username);
|
||||
let pos = player.position;
|
||||
await bot.lookAt(pos);
|
||||
await bot.toss(getItemId(itemType), null, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Navigate to the given player.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {string} username, the username of the player to navigate to.
|
||||
* @returns {Promise<boolean>} true if the player was found, false otherwise.
|
||||
* @example
|
||||
* await skills.GoToPlayer(bot, "player");
|
||||
* await skills.goToPlayer(bot, "player");
|
||||
**/
|
||||
export async function GoToPlayer(bot, username) {
|
||||
export async function goToPlayer(bot, username) {
|
||||
let player = bot.players[username].entity
|
||||
if (!player)
|
||||
return false;
|
||||
|
|
162
utils/world.js
162
utils/world.js
|
@ -1,12 +1,164 @@
|
|||
import { getAllBlockIds } from './mcdata.js';
|
||||
import { getAllBlockIds, getAllBlocks, getAllItems } from './mcdata.js';
|
||||
|
||||
|
||||
export function getNearbyBlocks(bot, distance) {
|
||||
let positions = bot.findBlocks({matching: getAllBlockIds(['air']), maxDistance: distance, count: 10000});
|
||||
let found = [];
|
||||
export function getCraftingTable(bot) {
|
||||
const blocks = getNearbyBlocks(bot, 50);
|
||||
let table = null;
|
||||
for (const block of blocks) {
|
||||
if (block.name == 'crafting_table') {
|
||||
table = block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
export function getNearbyBlocks(bot, maxDistance) {
|
||||
if (maxDistance == null) maxDistance = 16;
|
||||
let positions = bot.findBlocks({matching: getAllBlockIds(['air']), maxDistance: maxDistance, count: 10000});
|
||||
let blocks = [];
|
||||
for (let i = 0; i < positions.length; i++) {
|
||||
let block = bot.blockAt(positions[i]);
|
||||
found.push(block);
|
||||
let distance = positions[i].distanceTo(bot.entity.position);
|
||||
blocks.push({ block: block, distance: distance });
|
||||
}
|
||||
blocks.sort((a, b) => a.distance - b.distance);
|
||||
let res = [];
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
res.push(blocks[i].block);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
export function getNearbyMobs(bot, maxDistance) {
|
||||
if (maxDistance == null) maxDistance = 16;
|
||||
let entities = [];
|
||||
for (const entity of Object.values(bot.entities)) {
|
||||
const distance = entity.position.distanceTo(bot.entity.position);
|
||||
if (distance > maxDistance) continue;
|
||||
if (entity.type == 'mob') {
|
||||
entities.push({ entity: entity, distance: distance });
|
||||
}
|
||||
}
|
||||
entities.sort((a, b) => a.distance - b.distance);
|
||||
let res = [];
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
res.push(entities[i].entity);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
export function getNearbyPlayers(bot, maxDistance) {
|
||||
if (maxDistance == null) maxDistance = 16;
|
||||
let players = [];
|
||||
for (const entity of Object.values(bot.entities)) {
|
||||
const distance = entity.position.distanceTo(bot.entity.position);
|
||||
if (distance > maxDistance) continue;
|
||||
if (entity.type == 'player' && entity.username != bot.username) {
|
||||
players.push({ entity: entity, distance: distance });
|
||||
}
|
||||
}
|
||||
players.sort((a, b) => a.distance - b.distance);
|
||||
let res = [];
|
||||
for (let i = 0; i < players.length; i++) {
|
||||
res.push(players[i].entity);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
export function getInventoryStacks(bot) {
|
||||
let inventory = [];
|
||||
for (const item of bot.inventory.slots.values()) {
|
||||
if (item != null) {
|
||||
inventory.push(item);
|
||||
}
|
||||
}
|
||||
return inventory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an object representing the bot's inventory.
|
||||
* @param {Bot} bot - The bot to get the inventory for.
|
||||
* @returns {object} - An object with item names as keys and counts as values.
|
||||
* @example
|
||||
* let inventory = world.getInventoryCounts(bot);
|
||||
* let oakLogCount = inventory['oak_log'];
|
||||
* let hasWoodenPickaxe = inventory['wooden_pickaxe'] > 0;
|
||||
**/
|
||||
export function getInventoryCounts(bot) {
|
||||
let inventory = {};
|
||||
for (const item of getInventoryStacks(bot)) {
|
||||
if (inventory.hasOwnProperty(item.name)) {
|
||||
inventory[item.name] = inventory[item.name] + item.count;
|
||||
} else {
|
||||
inventory[item.name] = item.count;
|
||||
}
|
||||
}
|
||||
for (const item of getAllItems()) {
|
||||
if (!inventory.hasOwnProperty(item.name)) {
|
||||
inventory[item.name] = 0;
|
||||
}
|
||||
}
|
||||
for (const item of getAllBlocks()) {
|
||||
if (!inventory.hasOwnProperty(item.name)) {
|
||||
inventory[item.name] = 0;
|
||||
}
|
||||
}
|
||||
return inventory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get your position in the world (Note that y is vertical).
|
||||
* @param {Bot} bot - The bot to get the position for.
|
||||
* @returns {Vec3} - An object with x, y, and x attributes representing the position of the bot.
|
||||
* @example
|
||||
* let position = world.getPosition(bot);
|
||||
* let x = position.x;
|
||||
**/
|
||||
export function getPosition(bot) {
|
||||
return bot.entity.position;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of all nearby mob types.
|
||||
* @param {Bot} bot - The bot to get nearby mobs for.
|
||||
* @returns {string[]} - A list of all nearby mobs.
|
||||
* @example
|
||||
* let mobs = world.getNearbyMobTypes(bot);
|
||||
**/
|
||||
export function getNearbyMobTypes(bot) {
|
||||
let mobs = getNearbyMobs(bot, 16);
|
||||
let found = [];
|
||||
for (let i = 0; i < mobs.length; i++) {
|
||||
if (!found.includes(mobs[i].mobType)) {
|
||||
found.push(mobs[i].mobType);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of all nearby player names.
|
||||
* @param {Bot} bot - The bot to get nearby players for.
|
||||
* @returns {string[]} - A list of all nearby players.
|
||||
* @example
|
||||
* let players = world.getNearbyPlayerNames(bot);
|
||||
**/
|
||||
export function getNearbyPlayerNames(bot) {
|
||||
let players = getNearbyPlayers(bot, 16);
|
||||
let found = [];
|
||||
for (let i = 0; i < players.length; i++) {
|
||||
if (!found.includes(players[i].username) && players[i].username != bot.username) {
|
||||
found.push(players[i].username);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue