From c486a210e40d764a76001ec878022824fa403639 Mon Sep 17 00:00:00 2001 From: fumiama Date: Mon, 14 Feb 2022 14:46:33 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E5=A2=9E=E5=8A=A0=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=20=E6=BC=82=E6=B5=81=E7=93=B6=20#2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data | 2 +- main.go | 1 + plugin_drift_bottle/data.go | 52 +++++++++++++++ plugin_drift_bottle/db.go | 23 +++++++ plugin_drift_bottle/main.go | 125 ++++++++++++++++++++++++++++++++++++ 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 plugin_drift_bottle/data.go create mode 100644 plugin_drift_bottle/db.go create mode 100644 plugin_drift_bottle/main.go diff --git a/data b/data index 3a7d07ec99..431911b875 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 3a7d07ec9955fa7162d4600f1d4fb1ebefa0dc23 +Subproject commit 431911b8755799e61f096c7853a05731743f3761 diff --git a/main.go b/main.go index 5598fdcf9f..9f1bdf3d36 100644 --- a/main.go +++ b/main.go @@ -64,6 +64,7 @@ import ( _ "github.com/FloatTech/ZeroBot-Plugin/plugin_cpstory" // cp短打 _ "github.com/FloatTech/ZeroBot-Plugin/plugin_danbooru" // DeepDanbooru二次元图标签识别 _ "github.com/FloatTech/ZeroBot-Plugin/plugin_diana" // 嘉心糖发病 + _ "github.com/FloatTech/ZeroBot-Plugin/plugin_drift_bottle" // 漂流瓶 _ "github.com/FloatTech/ZeroBot-Plugin/plugin_emojimix" // 合成emoji _ "github.com/FloatTech/ZeroBot-Plugin/plugin_fortune" // 运势 _ "github.com/FloatTech/ZeroBot-Plugin/plugin_funny" // 笑话 diff --git a/plugin_drift_bottle/data.go b/plugin_drift_bottle/data.go new file mode 100644 index 0000000000..6313bd47b4 --- /dev/null +++ b/plugin_drift_bottle/data.go @@ -0,0 +1,52 @@ +package driftbottle + +import ( + "fmt" + "hash/crc64" + "strconv" + "sync" + + sql "github.com/FloatTech/sqlite" + "github.com/FloatTech/zbputils/binary" +) + +type bottle struct { + ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64 + QQ int64 `db:"qq"` // QQ 发送者 qq + Grp int64 `db:"grp"` // Grp 限制抽出的群 / 人(负数) + Name string `db:"name"` // Name 发送者 昵称 + Msg string `db:"msg"` // Msg 消息,纯文本 +} + +var seamu sync.RWMutex + +func newBottle(qq, grp int64, name, msg string) *bottle { + id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s", qq, grp, name, msg)), crc64.MakeTable(crc64.ISO))) + return &bottle{ID: id, QQ: qq, Grp: grp, Name: name, Msg: msg} +} + +func (b *bottle) throw(db *sql.Sqlite, channel string) error { + seamu.Lock() + defer seamu.Unlock() + return db.Insert(channel, b) +} + +func (b *bottle) destroy(db *sql.Sqlite, channel string) error { + seamu.Lock() + defer seamu.Unlock() + return db.Del(channel, "WHERE id="+strconv.FormatInt(b.ID, 10)) +} + +// fetchBottle grp != 0 +func fetchBottle(db *sql.Sqlite, channel string, grp int64) (*bottle, error) { + seamu.RLock() + defer seamu.RUnlock() + b := new(bottle) + return b, db.Find(channel, b, "WHERE grp=0 or grp="+strconv.FormatInt(grp, 10)+" ORDER BY RANDOM() limit 1") +} + +func createChannel(db *sql.Sqlite, channel string) error { + seamu.Lock() + defer seamu.Unlock() + return db.Create(channel, &bottle{}) +} diff --git a/plugin_drift_bottle/db.go b/plugin_drift_bottle/db.go new file mode 100644 index 0000000000..568c96513d --- /dev/null +++ b/plugin_drift_bottle/db.go @@ -0,0 +1,23 @@ +package driftbottle + +import ( + "os" + + sql "github.com/FloatTech/sqlite" +) + +const ( + dbpath = "data/driftbottle/" + dbfile = dbpath + "sea.db" +) + +var sea = &sql.Sqlite{DBPath: dbfile} + +func init() { + _ = os.MkdirAll(dbpath, 0755) + err := sea.Open() + if err != nil { + panic(err) + } + _ = createChannel(sea, "global") +} diff --git a/plugin_drift_bottle/main.go b/plugin_drift_bottle/main.go new file mode 100644 index 0000000000..bf48c6648a --- /dev/null +++ b/plugin_drift_bottle/main.go @@ -0,0 +1,125 @@ +package driftbottle + +import ( + "strconv" + "strings" + "sync" + + "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/control/order" + "github.com/FloatTech/zbputils/ctxext" + "github.com/sirupsen/logrus" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +func init() { + en := control.Register("driftbottle", order.AcquirePrio(), &control.Options{ + DisableOnDefault: false, + Help: "漂流瓶\n- (在群xxx)丢漂流瓶(到频道xxx) [消息]\n- (从频道xxx)捡漂流瓶\n- 创建频道 xxx\n- 跳入(频道)海中\n- 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global", + }) + en.OnRegex(`^(在群\d+)?丢漂流瓶(到频道\w+)?\s+(.*)$`).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + msgs := ctx.State["regex_matched"].([]string) + grp := ctx.Event.GroupID + channel := "global" + msg := msgs[3] + var err error + if msgs[1] != "" { + grp, err = strconv.ParseInt(msgs[1][6:], 10, 64) + if err != nil { + ctx.SendChain(message.Text("群号非法!")) + return + } + } + if msgs[2] != "" { + channel = msgs[2][9:] + } + if msg == "" { + ctx.SendChain(message.Text("消息为空!")) + return + } + logrus.Debugln("[driftbottle]", grp, channel, msg) + err = newBottle( + ctx.Event.UserID, + grp, + ctxext.CardOrNickName(ctx, ctx.Event.UserID), + msg, + ).throw(sea, channel) + if err != nil { + ctx.SendChain(message.Text("ERROR:", err)) + return + } + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你将它扔进大海,希望有人捞到吧~"))) + }) + en.OnRegex(`^(从频道\w+)?捡漂流瓶$`).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + msgs := ctx.State["regex_matched"].([]string) + grp := ctx.Event.GroupID + if grp == 0 { + grp = -ctx.Event.UserID + } + if grp == 0 { + ctx.SendChain(message.Text("找不到对象!")) + return + } + channel := "global" + if msgs[1] != "" { + channel = msgs[1][9:] + } + logrus.Debugln("[driftbottle]", grp, channel) + b, err := fetchBottle(sea, channel, grp) + if err != nil { + ctx.SendChain(message.Text("ERROR:", err)) + return + } + var wg sync.WaitGroup + wg.Add(1) + go func() { + err = b.destroy(sea, channel) + wg.Done() + }() + ctx.Send( + message.ReplyWithMessage( + ctx.Event.MessageID, + message.Text("你在海边捡到了一个来自 ", b.Name, " 的漂流瓶,打开瓶子,里面有一张纸条,写着:"), + message.Text(b.Msg), + ), + ) + wg.Wait() + if err != nil { + ctx.SendChain(message.Text("ERROR:", err)) + return + } + }) + en.OnPrefix("创建频道", zero.SuperUserPermission, zero.OnlyToMe).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + channel := strings.TrimRight(ctx.State["args"].(string), " ") + if channel == "" { + ctx.SendChain(message.Text("频道名为空!")) + return + } + err := createChannel(sea, channel) + if err != nil { + ctx.SendChain(message.Text("ERROR:", err)) + return + } + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("成功~"))) + }) + en.OnRegex(`^跳入(\w+)?海中$`).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + msgs := ctx.State["regex_matched"].([]string) + channel := "global" + if msgs[1] != "" { + channel = msgs[1] + } + seamu.RLock() + c, err := sea.Count(channel) + seamu.RUnlock() + if err != nil { + ctx.SendChain(message.Text("ERROR:", err)) + return + } + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你缓缓走入大海,感受着海浪轻柔地拍打着你的小腿,膝盖……\n波浪卷着你的腰腹,你感觉有些把握不住平衡了……\n……\n你沉入海中,", c, " 个物体与你一同沉浮。\n不知何处涌来一股暗流,你失去了意识。"))) + }) +}