Skip to content

Commit

Permalink
huge rework
Browse files Browse the repository at this point in the history
  • Loading branch information
hmbanan666 committed Apr 16, 2024
1 parent 3cf1cf7 commit 6accaa3
Show file tree
Hide file tree
Showing 104 changed files with 4,417 additions and 1,029 deletions.
25 changes: 25 additions & 0 deletions EVENTS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
## 2024-04-14

- Появилась возможность создавать разные комнаты-сцены
- Базовая анимация персонажа при передвижении

## 2024-04-13

- Определились с новой концепцией игры - волны, строительство, главный игрок
- Ротация ресурсов в руке (вместо отдельного интерфейса)

## 2024-04-12

- Новый титул: Зритель. Можно покупать баллы за активность на Twitch
- Научились "шатать" объекты (появились базовая анимация)
- Звуки вернулись

## 2024-04-11

- Статус компаньона: открылись возможности копить и тратить баллы при просмотре стрима
- Сократилось кол-во сообщений между клиентом и сервером (в 8 раз)

## 2024-04-09

- Первый рейд от Duckate с 22 зрителями!

## 2024-04-07

- Первый донат от sava5621!
Expand Down
54 changes: 46 additions & 8 deletions apps/api/src/bot/bot.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RefreshingAuthProvider } from "@twurple/auth";
import { Bot } from "@twurple/easy-bot";
import { PubSubClient } from "@twurple/pubsub";
import type { Game } from "../game/game";
import { BotService } from "./bot.service";

Expand Down Expand Up @@ -29,36 +30,73 @@ export class BotController {
await Bun.write(tokenFile, data);
});

await authProvider.addUserForToken(tokenData, ["chat"]);
await authProvider.addUserForToken(tokenData, ["chat", "channel"]);

return authProvider;
}

prepareBotCommands() {
return [
this.service.commandStartGroupBuild(),
this.service.commandJoinGroup(),
this.service.commandDisbandGroup(),
this.service.commandChop(),
this.service.commandMine(),
this.service.commandGift(),
this.service.commandSell(),
this.service.commandBuy(),
// this.service.commandGift(),
// this.service.commandSell(),
// this.service.commandBuy(),
this.service.commandHelp(),
this.service.commandHelpEn(),
//this.service.commandHelpEn(),
this.service.commandDonate(),
this.service.commandDonateEn(),
//this.service.commandDonateEn(),
];
}

public async serve() {
const authProvider = await this.prepareAuthProvider();

const pubSubClient = new PubSubClient({ authProvider });

pubSubClient.onRedemption(this.userId, ({ userId, userName, rewardId }) => {
this.service.reactOnChannelRewardRedemption({
userId,
userName,
rewardId,
});
});

const bot = new Bot({
authProvider: await this.prepareAuthProvider(),
authProvider,
channels: [this.channel],
commands: this.prepareBotCommands(),
chatClientOptions: {
requestMembershipEvents: true,
},
});

bot.onRaid(({ broadcasterName, userName, userId, viewerCount }) => {
void bot.say(broadcasterName, `@${userName} устроил рейд!`);
void bot.say(broadcasterName, `@${userName} устроил(а) рейд! Готовимся!`);
void this.service.reactOnRaid({ userName, userId, viewerCount });
});
bot.onRaidCancel((event) => {
console.log("raid canceled!", event);
});

bot.onMessage(({ userId, isAction, text }) => {
console.log("message", userId, isAction, text);
});

bot.onAction(({ userId, userName, isAction, text }) => {
console.log("action!", userId, userName, isAction, text);
});

bot.onJoin(({ userName }) => {
console.log(new Date().toLocaleTimeString(), "joined!", userName);
});
bot.onLeave(({ userName }) => {
console.log("left!", userName);
});

bot.onSub(({ broadcasterName, userName }) => {
void bot.say(
broadcasterName,
Expand Down
194 changes: 132 additions & 62 deletions apps/api/src/bot/bot.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createBotCommand } from "@twurple/easy-bot";
import { DISCORD_SERVER_INVITE_URL, DONATE_URL } from "../config";
import { TWITCH_CHANNEL_REWARDS } from "../config";
import {
addStoneToVillage,
addWoodToVillage,
Expand All @@ -14,43 +14,79 @@ export class BotService {
this.game = game;
}

public commandChop() {
public commandStartGroupBuild() {
return createBotCommand(
"рубить",
"собрать",
async (params, { userId, userName, reply }) => {
console.log("рубить", userId, userName, params);

const player = await this.game.findOrCreatePlayer(userId, userName);
if (player.state === "CHOPPING") {
void reply(`${userName}, ты пока занят(а).`);
return;
const result = await this.game.handleChatCommand({
action: "START_GROUP_BUILD",
userId,
userName,
params,
});
if (result.message) {
void reply(result.message);
}
},
);
}

const sent = this.game.sendPlayerToChopATree(player);
if (!sent) {
void reply(`${userName}, нет доступного дерева.`);
return;
public commandJoinGroup() {
return createBotCommand("го", async (_, { userId, userName, reply }) => {
const result = await this.game.handleChatCommand({
action: "JOIN_GROUP",
userId,
userName,
});
if (result.message) {
void reply(result.message);
}
});
}

public commandDisbandGroup() {
return createBotCommand(
"расформировать",
async (_, { userId, userName, reply }) => {
const result = await this.game.handleChatCommand({
action: "DISBAND_GROUP",
userId,
userName,
});
if (result.message) {
void reply(result.message);
}
},
);
}

public commandMine() {
public commandChop() {
return createBotCommand(
"добывать",
async (params, { userId, userName, reply }) => {
console.log("добывать", userId, userName, params);

const player = await this.game.findOrCreatePlayer(userId, userName);
if (player.state === "MINING") {
void reply(`${userName}, ты пока занят(а).`);
return;
"рубить",
async (_, { userId, userName, reply }) => {
const result = await this.game.handleChatCommand({
action: "CHOP",
userId,
userName,
});
if (result.message) {
void reply(result.message);
}
},
);
}

const sent = this.game.sendPlayerToMineStone(player);
if (!sent) {
void reply(`${userName}, нет доступного камня.`);
return;
public commandMine() {
return createBotCommand(
"добыть",
async (_, { userId, userName, reply }) => {
const result = await this.game.handleChatCommand({
action: "MINE",
userId,
userName,
});
if (result.message) {
void reply(result.message);
}
},
);
Expand All @@ -62,7 +98,10 @@ export class BotService {
async (params, { userId, userName, reply }) => {
console.log("подарить", userId, userName, params);

const player = await this.game.findOrCreatePlayer(userId, userName);
const player = await this.game.repository.findOrCreatePlayer(
userId,
userName,
);
const items = player.inventory?.items ?? [];

if (params[0] === "древесину" || params[0] === "древесина") {
Expand Down Expand Up @@ -123,7 +162,10 @@ export class BotService {
async (params, { userId, userName, reply }) => {
console.log("продать", userId, userName, params);

const player = await this.game.findOrCreatePlayer(userId, userName);
const player = await this.game.repository.findOrCreatePlayer(
userId,
userName,
);
const items = player.inventory?.items ?? [];

if (params[0] === "древесину" || params[0] === "древесина") {
Expand Down Expand Up @@ -178,7 +220,10 @@ export class BotService {
async (params, { userId, userName, reply }) => {
console.log("купить", userId, userName, params);

const player = await this.game.findOrCreatePlayer(userId, userName);
const player = await this.game.repository.findOrCreatePlayer(
userId,
userName,
);
const items = player.inventory?.items ?? [];

if (params[0] === "топор") {
Expand Down Expand Up @@ -235,55 +280,80 @@ export class BotService {
return createBotCommand(
"помощь",
async (_, { userId, userName, reply }) => {
await this.game.findOrCreatePlayer(userId, userName);

void reply(
`${userName}, это интерактивная игра-чат, в которой может участвовать любой зритель! Пиши команды (примеры на экране) для управления своим героем. Вступай в наше комьюнити: ${DISCORD_SERVER_INVITE_URL}`,
);
return;
const result = await this.game.handleChatCommand({
action: "HELP",
userId,
userName,
});
if (result.message) {
void reply(result.message);
}
},
);
}

public commandHelpEn() {
return createBotCommand("help", async (_, { userId, userName, reply }) => {
await this.game.findOrCreatePlayer(userId, userName);

void reply(
`${userName}, this is an interactive chat game that any viewer can participate in! Write commands (examples on the screen) to control your hero. Join our community: ${DISCORD_SERVER_INVITE_URL}`,
);
return;
});
}
// public commandHelpEn() {
// return createBotCommand("help", async (_, { userId, userName, reply }) => {
// await this.game.repository.findOrCreatePlayer(userId, userName);
//
// void reply(
// `${userName}, this is an interactive chat game that any viewer can participate in! Write commands (examples on the screen) to control your hero. Join our community: ${DISCORD_SERVER_INVITE_URL}`,
// );
// return;
// });
// }

public commandDonate() {
return createBotCommand("донат", async (_, { userId, userName, reply }) => {
await this.game.findOrCreatePlayer(userId, userName);

void reply(`${userName}, поддержи игру: ${DONATE_URL}`);
return;
const result = await this.game.handleChatCommand({
action: "DONATE",
userId,
userName,
});
if (result.message) {
void reply(result.message);
}
});
}

public commandDonateEn() {
return createBotCommand(
"donate",
async (_, { userId, userName, reply }) => {
await this.game.findOrCreatePlayer(userId, userName);

void reply(`${userName}, support the game: ${DONATE_URL}`);
return;
},
);
}
// public commandDonateEn() {
// return createBotCommand(
// "donate",
// async (_, { userId, userName, reply }) => {
// await this.game.repository.findOrCreatePlayer(userId, userName);
//
// void reply(`${userName}, support the game: ${DONATE_URL}`);
// return;
// },
// );
// }

public async reactOnRaid({
userName,
userId,
viewerCount,
}: { userName: string; userId: string; viewerCount: number }) {
console.log("raid!", userName, userId, viewerCount);
return this.game.handleChatCommand({
action: "START_RAID",
userId,
userName,
viewerCount,
});
}

await this.game.findOrCreatePlayer(userId, userName);
public async reactOnChannelRewardRedemption({
userId,
userName,
rewardId,
}: { userId: string; userName: string; rewardId: string }) {
console.log("reactOnChannelRewardRedemption", userId, userName, rewardId);
const player = await this.game.repository.findOrCreatePlayer(
userId,
userName,
);
if (rewardId === TWITCH_CHANNEL_REWARDS["150viewerPoints"].id) {
await this.game.repository.addPlayerViewerPoints(player.id, 150);
return;
}
}
}
Loading

0 comments on commit 6accaa3

Please sign in to comment.