Skip to content

Commit

Permalink
feat: + MinecraftConnect
Browse files Browse the repository at this point in the history
  • Loading branch information
dragon-fish committed Jan 16, 2024
1 parent c934ce2 commit 72ae919
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 13 deletions.
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ import * as PluginSwitch from 'koishi-plugin-switch'

import { HTMLService } from '$utils/RenderHTML'

import { AdapterMinecraft } from './plugins/adapter-minecraft'
import { MinecraftConnect } from './modules/MinecraftConnect'
import { MinecraftBot } from './plugins/adapter-minecraft'

const PROD = process.env.NODE_ENV === 'production'

Expand Down Expand Up @@ -171,7 +172,7 @@ app.plugin(function PluginCollectionAdapters(ctx) {

// Minecraft
if (env.MINECRAFT_TOKEN) {
ctx.plugin(AdapterMinecraft, {
ctx.plugin(MinecraftBot, {
host: env.MINECRAFT_HOST,
port: Number(env.MINECRAFT_PORT),
protocol: env.MINECRAFT_PROTOCOL as 'ws' | 'wss',
Expand Down Expand Up @@ -367,6 +368,7 @@ app.plugin(function PluginCollectionInternal(ctx) {
ctx.plugin(PluginReboot)
ctx.plugin(PluginSensitiveFilter)
ctx.plugin(PluginSpawn, { shell: 'pwsh' })
ctx.plugin(MinecraftConnect)
})

/** 启动应用程序 */
Expand Down
35 changes: 35 additions & 0 deletions src/modules/MinecraftConnect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Context } from 'koishi'

import { MinecraftBot } from '@/plugins/adapter-minecraft'

import BasePlugin from '~/_boilerplate'

export class MinecraftConnect extends BasePlugin {
constructor(
public ctx: Context,
options
) {
super(ctx, options, 'mc-connect')

const QQ_GROUP = process.env.CHANNEL_QQ_NGNL_MINECRAFT

const qqBot = ctx.bots.find((bot) =>
['onebot', 'red'].includes(bot.platform)
)
const qqCtx = ctx.channel(QQ_GROUP, process.env.CHANNEL_QQ_SANDBOX)
const mcBot = ctx.bots.find(
(bot) => bot.platform === 'minecraft'
) as MinecraftBot<Context>
const mcCtx = ctx.platform('minecraft')

mcCtx.on('message', (session) => {
qqBot.sendMessage(
QQ_GROUP,
`[MC] ${session.username}:\n${session.content}`
)
})
qqCtx.on('message', (session) => {
mcBot.sendMessageAs(session.username, session.content)
})
}
}
91 changes: 84 additions & 7 deletions src/plugins/adapter-minecraft.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Adapter, Bot, Context, Logger, Session } from 'koishi'
import { Adapter, Bot, Context, Fragment, Logger, h } from 'koishi'

import { SendOptions } from '@satorijs/protocol'

export interface Config extends Adapter.WsClientConfig {
host: string
Expand All @@ -16,6 +18,7 @@ export class MinecraftBot<C extends Context> extends Bot<C, Config> {
protocol: 'ws',
token: '',
}
public ws?: ReturnType<C['http']['ws']>

constructor(
public ctx: C,
Expand All @@ -24,6 +27,7 @@ export class MinecraftBot<C extends Context> extends Bot<C, Config> {
config = { ...MinecraftBot.defaultConfig, ...config }
super(ctx, config)
this.platform = 'minecraft'
this.ctx.root.plugin(AdapterMinecraft, this)
}

get serverURL() {
Expand All @@ -33,26 +37,99 @@ export class MinecraftBot<C extends Context> extends Bot<C, Config> {
url.protocol = this.config.protocol
return url
}

async sendMessage(
channelId: string,
content: Fragment,
guildId?: string,
options?: SendOptions & {
sendAs?: string
}
): Promise<string[]> {
this.ws.send(
JSON.stringify({
Name: options.sendAs || this.ctx.root.config.name || 'koishi',
Content: this.stringifyContent(content),
})
)
return []
}

async sendMessageAs(username: string, content: Fragment) {
return this.sendMessage('0', content, undefined, {
sendAs: username,
})
}

stringifyContent(content: Fragment) {
const elements = h.parse(content.toString())
console.log('[[stringifyContent]] income:', content, elements)
return elements
.map((el) => {
console.log('[[stringifyContent]] map:', el)
if (el.type === 'text') return el
switch (el.type) {
default:
return el
case 'at':
return h.text(`@${el.attrs.name || el.attrs.id}`)
case 'img':
case 'image':
return h.text('[图片]')
case 'video':
return h.text('[视频]')
case 'audio':
return h.text('[音频]')
case 'file':
return h.text('[文件]')
case 'face':
return h.text('[表情]')
}
})
.join('')
}
}

export class AdapterMinecraft extends Adapter.WsClient<
Context,
MinecraftBot<Context>
> {
protected async prepare() {
return this.ctx.http.ws(this.bot.serverURL.href, {
const ws = this.ctx.http.ws(this.bot.serverURL.href, {
headers: {
authorization: `Bot ${this.bot.config.token}`,
},
})
this.bot.ws = ws
return ws
}
protected accept(): void {
this.bot.online()
this.socket.addEventListener('message', (raw: any) => {
const data = JSON.parse(raw.toString())
logger.info('[recieved]', raw, data)

// if (!this.bot.) return
// this.bot.sendMessage('0', 'SILI is online')
this.socket.addEventListener('message', (msg: any) => {
const data: {
Name: string
Content: string
} = typeof msg.data === 'string' ? JSON.parse(msg.data) : msg.data
logger.info('[message]', data)
const user = {
id: 'MC:' + data.Name,
name: data.Name,
}
const channel = {
id: '0',
type: 0,
}
const session = this.bot.session({
type: 'message',
user,
channel,
message: {
user,
},
})
session.content = data.Content
this.bot.dispatch(session)
})
}
}
4 changes: 2 additions & 2 deletions src/plugins/sticker/蔚蓝档案/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
<title>Document</title>
<link
rel="stylesheet"
href="https://gcore.jsdelivr.net/gh/CeriseBouquet/static@master/fonts/GlowSans/font.css"
href="https://fastly.jsdelivr.net/gh/CeriseBouquet/static@master/fonts/GlowSans/font.css"
/>
<link
rel="stylesheet"
href="https://gcore.jsdelivr.net/gh/CeriseBouquet/static@master/fonts/RoGSans_sliced/font.css"
href="https://fastly.jsdelivr.net/gh/CeriseBouquet/static@master/fonts/RoGSans_sliced/font.css"
/>
</head>
<body>
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/sticker/蔚蓝档案/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ export default class 蔚蓝档案 extends BaseSticker {
url.searchParams.set('rightText', rightText)
await page.goto(url.toString(), {
waitUntil: 'load',
timeout: 8 * 1000,
timeout: 15 * 1000,
})
await page.waitForNetworkIdle({ timeout: 5 * 1000 })
await page.waitForNetworkIdle({ timeout: 10 * 1000 })
const logo = await page.$('#logo')
const buffer = await logo?.screenshot({ type: 'jpeg' })
return h.image(buffer, 'image/jpeg')
Expand Down

0 comments on commit 72ae919

Please sign in to comment.