Skip to content

Commit

Permalink
feat: kotori-plugin-adapter-minecraft
Browse files Browse the repository at this point in the history
  • Loading branch information
BIYUEHU committed May 2, 2024
1 parent b6b55cb commit 56e9eae
Show file tree
Hide file tree
Showing 14 changed files with 296 additions and 6 deletions.
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- [ ] @kotori-bot/kotori-plugin-adapter-mail
- [ ] @kotori-bot/kotori-plugin-adapter-telegram
- [ ] @kotori-bot/kotori-plugin-adapter-discord
- [ ] kotori-plugin-adapter-minecraft
- [x] kotori-plugin-adapter-minecraft
- [x] kotori-plugin-requester
- [x] kotori-plugin-grouper
- [x] kotori-plugin-manger
Expand Down
19 changes: 19 additions & 0 deletions modules/adapter-minecraft/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# @kotori-bot/kotori-plugin-adapter-minecraft

Base on `mcwss` package for Minecraft Bedrock Edition,support `private` and `group` scope.

## Config

```typescript
interface CmdConfig extends Adapter {
'command-prefix': string; // no "/"
port: number; // server port,
address: string; // server address,
nickname?: string; // name of bot
template: null | string; // bot message formation, example: <§b§l%nickname%§f> §a%msg%§f
}
```

## Reference

- [Kotori Docs](https://kotori.js.org/)
32 changes: 32 additions & 0 deletions modules/adapter-minecraft/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "kotori-plugin-adapter-minecraft",
"version": "1.0.0",
"description": "Adapter For Minecraft Bedrock Edition",
"main": "lib/index.js",
"scripts": {
"build": "tsc --build"
},
"keywords": [
"kotori",
"chatbot",
"kotori-plugin",
"minecraft",
"websocket",
"minecraft bedrock",
"mojang"
],
"license": "GPL-3.0",
"files": [
"lib",
"locales",
"LICENSE",
"README.md"
],
"author": "Hotaru <biyuehuya@gmail.com>",
"peerDependencies": {
"kotori-bot": "workspace:^"
},
"dependencies": {
"mcwss": "^2.1.1"
}
}
115 changes: 115 additions & 0 deletions modules/adapter-minecraft/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* @Author: Hotaru biyuehuya@gmail.com
* @Blog: https://hotaru.icu
* @Date: 2023-09-29 14:31:09
* @LastEditors: Hotaru biyuehuya@gmail.com
* @LastEditTime: 2024-05-02 18:12:01
*/
import { Adapter, AdapterConfig, Context, MessageScope, Tsu, stringTemp } from 'kotori-bot';
import Mcwss from 'mcwss';
import McApi from './api';
import McElements from './elements';

export const config = Tsu.Object({
port: Tsu.Number().int().range(1, 65535),
address: Tsu.String()
.regexp(/^ws(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/)
.default('ws://127.0.0.1'),
nickname: Tsu.String().default('Romi'),
template: Tsu.Union([Tsu.Null(), Tsu.String()]).default('<%nickname%> %msg%')
});

type McConfig = Tsu.infer<typeof config> & AdapterConfig;

type MessageData =
Parameters<Mcwss['on']> extends [unknown, infer F]
? F extends (data: infer D) => void
? D extends { header: { eventName: 'PlayerMessage' } }
? D
: never
: never
: never;

export class McAdapter extends Adapter<McApi> {
private app?: Mcwss;

private clients: Record<string, MessageData['client']> = {};

private messageId = 1;

public readonly config: McConfig;

public constructor(ctx: Context, config: McConfig, identity: string) {
super(ctx, config, identity, McApi, new McElements());
this.config = config;
}

public handle(data: MessageData) {
this.session('on_message', {
type: data.body.type === 'chat' ? MessageScope.GROUP : MessageScope.PRIVATE,
messageId: this.messageId,
message: data.body.message,
userId: `${data.client.sessionId}@${data.body.sender}`,
sender: {
nickname: data.body.sender,
sex: 'unknown',
age: 0
},
groupId: data.body.type === 'chat' ? data.client.sessionId : undefined
});
this.messageId += 1;
}

public start() {
this.connect();
this.ctx.emit('connect', {
type: 'connect',
adapter: this,
normal: true,
mode: 'ws-reverse',
address: `${this.config.address}:${this.config.port}`
});
}

public stop() {
this.app?.stop();
this.ctx.emit('connect', {
type: 'disconnect',
adapter: this,
normal: true,
mode: 'other',
address: `${this.config.address}:${this.config.port}`
});
this.offline();
}

public send(action: string, params: { msg: string }) {
const [sessionId, playerName] = action.split('@');
const { msg } = params;
if (!(sessionId in this.clients)) return;
if (playerName) {
this.clients[sessionId].run(['msg', `@a[name="${playerName}"]`, msg]);
} else if (this.config.template) {
this.clients[sessionId].chatf(stringTemp(this.config.template, { nickname: this.config.nickname, msg }));
} else {
this.clients[sessionId].chat(msg);
}
this.ctx.emit('send', {
api: this.api,
messageId: this.messageId
});
}

private connect() {
this.app = new Mcwss({ port: this.config.port, autoRegister: true, autoClearEvents: true });
this.app.on('error', (err) => this.ctx.logger.error(err));
this.app.on('connection', (data) => {
if (Object.keys(this.clients).length === 0) this.online();
this.clients[data.client.sessionId] = data.client;
});
this.app.on('player_message', (data) => this.handle(data));
this.app.start();
}
}

export default McAdapter;
20 changes: 20 additions & 0 deletions modules/adapter-minecraft/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* @Author: Hotaru biyuehuya@gmail.com
* @Blog: https://hotaru.icu
* @Date: 2023-09-29 14:31:13
* @LastEditors: Hotaru biyuehuya@gmail.com
* @LastEditTime: 2024-05-02 17:22:10
*/
import { Api, EventDataTargetId, MessageRaw } from 'kotori-bot';

export class CmdApi extends Api {
public sendPrivateMsg(message: MessageRaw, userId: EventDataTargetId) {
this.adapter.send(String(userId), { msg: message });
}

public sendGroupMsg(message: MessageRaw, groupId: EventDataTargetId) {
this.adapter.send(String(groupId), { msg: message });
}
}

export default CmdApi;
35 changes: 35 additions & 0 deletions modules/adapter-minecraft/src/elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Elements, EventDataTargetId, none } from 'kotori-bot';

export class McElements extends Elements {
public at(target: EventDataTargetId) {
none(this);
return `@${String(target).split('@')[1]} `;
}

public image(url: string) {
none(this);
return `[image,${url}]`;
}

public voice(url: string) {
none(this);
return `[voice,${url}]`;
}

public video(url: string) {
none(this);
return `[video,${url}]`;
}

public face(id: string) {
none(this);
return `[face,${id}]`;
}

public file(data: string) {
none(data, this);
return `[file]`;
}
}

export default McElements;
4 changes: 4 additions & 0 deletions modules/adapter-minecraft/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { McAdapter } from './adapter';

export { config } from './adapter';
export default McAdapter;
12 changes: 12 additions & 0 deletions modules/adapter-minecraft/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.node.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib"
},
"references": [
{
"path": "../../packages/kotori"
}
]
}
2 changes: 1 addition & 1 deletion packages/core/src/utils/factory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Context } from '../context';

export function disposeFactory(ctx: Context, dispose: Function) {
export function disposeFactory(ctx: Context, dispose: () => void) {
ctx.once('dispose_module', (data) => {
if ((typeof data.instance === 'object' ? data.instance.name : data.instance) !== ctx.identity) {
disposeFactory(ctx, dispose);
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions packages/loader/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* @Blog: https://hotaru.icu
* @Date: 2023-10-29 16:20:51
* @LastEditors: Hotaru biyuehuya@gmail.com
* @LastEditTime: 2024-02-20 20:20:54
* @LastEditTime: 2024-05-02 10:44:55
*/

export * from './loader';
export * from './consts';
export * from './constants';
export * from '@kotori-bot/logger';
2 changes: 1 addition & 1 deletion packages/loader/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import fs from 'fs';
import Logger from '@kotori-bot/logger';
import Runner, { localeTypeSchema } from './runner';
import loadInfo from './log';
import { BUILD_CONFIG_NAME, DEV_CONFIG_NAME, SUPPORTS_HALF_VERSION, SUPPORTS_VERSION } from './consts';
import { BUILD_CONFIG_NAME, DEV_CONFIG_NAME, SUPPORTS_HALF_VERSION, SUPPORTS_VERSION } from './constants';
import Server from './service/server';
import type Database from './service/database';
import File from './service/file';
Expand Down
2 changes: 1 addition & 1 deletion packages/loader/src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
stringRightSplit
} from '@kotori-bot/core';
import { ConsoleTransport, FileTransport, LoggerLevel } from '@kotori-bot/logger';
import { BUILD_FILE, DEV_CODE_DIRS, DEV_FILE, DEV_IMPORT } from './consts';
import { BUILD_FILE, DEV_CODE_DIRS, DEV_FILE, DEV_IMPORT } from './constants';
import KotoriLogger from './utils/logger';

interface BaseDir {
Expand Down
53 changes: 53 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 56e9eae

Please sign in to comment.