增加签到预设切换 (#634)

This commit is contained in:
莲宝坏坏坏 2023-03-25 11:06:00 +08:00 committed by GitHub
parent d693f988bb
commit 587d3967ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 318 additions and 170 deletions

176
plugin/score/draw.go Normal file
View File

@ -0,0 +1,176 @@
// Package score 签到,答题得分
package score
import (
"bytes"
"fmt"
"image"
"image/color"
"strconv"
"time"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
"github.com/FloatTech/floatbox/file"
"github.com/FloatTech/gg"
"github.com/FloatTech/imgfactory"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/img/text"
"github.com/disintegration/imaging"
)
func drawScore16(a *scdata) (image.Image, error) {
// 绘图
getAvatar, err := initPic(a.picfile, a.uid)
if err != nil {
return nil, err
}
back, err := gg.LoadImage(a.picfile)
if err != nil {
return nil, err
}
// 避免图片过大,最大 1280*720
back = imgfactory.Limit(back, 1280, 720)
imgDX := back.Bounds().Dx()
imgDY := back.Bounds().Dy()
canvas := gg.NewContext(imgDX, imgDY)
// draw Aero Style
aeroStyle := gg.NewContext(imgDX-202, imgDY-202)
aeroStyle.DrawImage(imaging.Blur(back, 2.5), -100, -100)
// aero draw image.
aeroStyle.DrawRoundedRectangle(0, 0, float64(imgDX-200), float64(imgDY-200), 16)
// SideLine
aeroStyle.SetLineWidth(3)
aeroStyle.SetRGBA255(255, 255, 255, 100)
aeroStyle.StrokePreserve()
aeroStyle.SetRGBA255(255, 255, 255, 140)
// fill
aeroStyle.Fill()
// draw background
canvas.DrawImage(back, 0, 0)
// Aero style combine
canvas.DrawImage(aeroStyle.Image(), 100, 100)
canvas.Fill()
hourWord := getHourWord(time.Now())
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
if err != nil {
return nil, err
}
avatarf := imgfactory.Size(avatar, 200, 200)
canvas.DrawImage(avatarf.Circle(0).Image(), 120, 120)
// draw info(name,coin,etc)
canvas.SetRGB255(0, 0, 0)
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
if err != nil {
return nil, err
}
if err = canvas.ParseFontFace(data, 50); err != nil {
return nil, err
}
// draw head
canvas.DrawStringWrapped(a.nickname, 350, 180, 0.5, 0.5, 0.5, 0.5, gg.AlignLeft)
canvas.Fill()
// main draw
data, err = file.GetLazyData(text.FontFile, control.Md5File, true)
if err != nil {
return nil, err
}
if err = canvas.ParseFontFace(data, 30); err != nil {
return nil, err
}
canvas.DrawStringAnchored(hourWord, 350, 280, 0, 0)
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(a.inc), 350, 350, 0, 0)
canvas.DrawStringAnchored("当前ATRI币"+strconv.Itoa(a.score), 350, 400, 0, 0)
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(a.level)), 350, 450, 0, 0)
// draw Info(Time,etc.)
getTime := time.Now().Format("2006-01-02 15:04:05")
getTimeLengthWidth, getTimeLengthHight := canvas.MeasureString(getTime)
canvas.DrawStringAnchored(getTime, float64(imgDX)-100-20-getTimeLengthWidth/2, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
var nextrankScore int
if a.rank < 10 {
nextrankScore = rankArray[a.rank+1]
} else {
nextrankScore = SCOREMAX
}
nextLevelStyle := strconv.Itoa(a.level) + "/" + strconv.Itoa(nextrankScore)
getLevelLength, _ := canvas.MeasureString(nextLevelStyle)
canvas.DrawStringAnchored(nextLevelStyle, 100+getLevelLength, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
canvas.Fill()
canvas.SetRGB255(255, 255, 255)
if err = canvas.ParseFontFace(data, 20); err != nil {
return nil, err
}
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
canvas.SetRGB255(0, 0, 0)
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
canvas.SetRGB255(255, 255, 255)
// Gradient
grad := gg.NewLinearGradient(20, 320, 400, 20)
grad.AddColorStop(0, color.RGBA{G: 255, A: 255})
grad.AddColorStop(1, color.RGBA{B: 255, A: 255})
grad.AddColorStop(0.5, color.RGBA{R: 255, A: 255})
canvas.SetStrokeStyle(grad)
canvas.SetLineWidth(4)
// level array with rectangle work.
gradLineLength := float64(imgDX-120) - 120
renderLine := (float64(a.level) / float64(nextrankScore)) * gradLineLength
canvas.MoveTo(120, float64(imgDY)-102)
canvas.LineTo(120+renderLine, float64(imgDY)-102)
canvas.ClosePath()
canvas.Stroke()
return canvas.Image(), nil
}
func drawScore15(a *scdata) (image.Image, error) {
// 绘图
_, err := initPic(a.picfile, a.uid)
if err != nil {
return nil, err
}
back, err := gg.LoadImage(a.picfile)
if err != nil {
return nil, err
}
// 避免图片过大,最大 1280*720
back = imgfactory.Limit(back, 1280, 720)
canvas := gg.NewContext(back.Bounds().Size().X, int(float64(back.Bounds().Size().Y)*1.7))
canvas.SetRGB(1, 1, 1)
canvas.Clear()
canvas.DrawImage(back, 0, 0)
monthWord := time.Now().Format("01/02")
hourWord := getHourWord(time.Now())
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
if err != nil {
return nil, err
}
if err = canvas.LoadFontFace(text.BoldFontFile, float64(back.Bounds().Size().X)*0.1); err != nil {
return nil, err
}
canvas.SetRGB(0, 0, 0)
canvas.DrawString(hourWord, float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.2)
canvas.DrawString(monthWord, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*1.2)
_, err = file.GetLazyData(text.FontFile, control.Md5File, true)
if err != nil {
return nil, err
}
if err = canvas.LoadFontFace(text.FontFile, float64(back.Bounds().Size().X)*0.04); err != nil {
return nil, err
}
canvas.DrawString(a.nickname+fmt.Sprintf(" ATRI币+%d", a.inc), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.3)
canvas.DrawString("当前ATRI币:"+strconv.FormatInt(int64(a.score), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.4)
canvas.DrawString("LEVEL:"+strconv.FormatInt(int64(a.rank), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.5)
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*0.1)
canvas.SetRGB255(150, 150, 150)
canvas.Fill()
var nextrankScore int
if a.rank < 10 {
nextrankScore = rankArray[a.rank+1]
} else {
nextrankScore = SCOREMAX
}
canvas.SetRGB255(0, 0, 0)
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6*float64(a.level)/float64(nextrankScore), float64(back.Bounds().Size().Y)*0.1)
canvas.SetRGB255(102, 102, 102)
canvas.Fill()
canvas.DrawString(fmt.Sprintf("%d/%d", a.level, nextrankScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62)
return canvas.Image(), nil
}

View File

@ -122,3 +122,14 @@ func (sdb *scoredb) GetScoreRankByTopN(n int) (st []scoretable, err error) {
err = db.Model(&scoretable{}).Order("score desc").Limit(n).Find(&st).Error
return
}
type scdata struct {
drawedfile string
picfile string
uid int64
nickname string
inc int //增加币
score int //钱包
level int
rank int
}

View File

@ -2,25 +2,19 @@
package score
import (
"bytes"
"image"
"image/color"
"math"
"math/rand"
"os"
"strconv"
"time"
"github.com/disintegration/imaging"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
"github.com/FloatTech/AnimeAPI/bilibili"
"github.com/FloatTech/AnimeAPI/wallet"
fcext "github.com/FloatTech/floatbox/ctxext"
"github.com/FloatTech/floatbox/file"
"github.com/FloatTech/floatbox/process"
"github.com/FloatTech/floatbox/web"
"github.com/FloatTech/gg"
"github.com/FloatTech/imgfactory"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
@ -37,7 +31,8 @@ const (
referer = "https://weibo.com/"
signinMax = 1
// SCOREMAX 分数上限定为1200
SCOREMAX = 1200
SCOREMAX = 1200
defKeyID int64 = -6
)
var (
@ -48,6 +43,17 @@ var (
Help: "- 签到\n- 获得签到背景[@xxx] | 获得签到背景\n- 查看等级排名\n注:为跨群排名\n- 查看我的钱包\n- 查看钱包排名\n注:为本群排行,若群人数太多不建议使用该功能!!!",
PrivateDataFolder: "score",
})
initDef = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
var defkey string
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
_ = m.Manager.Response(defKeyID)
_ = m.Manager.GetExtra(defKeyID, &defkey)
if defkey == "" {
_ = m.Manager.SetExtra(defKeyID, "1")
return true
}
return true
})
)
func init() {
@ -60,185 +66,119 @@ func init() {
}
sdb = initialize(engine.DataFolder() + "score.db")
}()
engine.OnFullMatch("签到").Limit(ctxext.LimitByUser).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
uid := ctx.Event.UserID
now := time.Now()
today := now.Format("20060102")
// 签到图片
drawedFile := cachePath + strconv.FormatInt(uid, 10) + today + "signin.png"
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png"
// 获取签到时间
si := sdb.GetSignInByUID(uid)
siUpdateTimeStr := si.UpdatedAt.Format("20060102")
switch {
case si.Count >= signinMax && siUpdateTimeStr == today:
// 如果签到时间是今天
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!"))
if file.IsExist(drawedFile) {
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
}
return
case siUpdateTimeStr != today:
// 如果是跨天签到就清数据
err := sdb.InsertOrUpdateSignInCountByUID(uid, 0)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
engine.OnRegex(`^签到\s?(\d*)$`, initDef).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
//选择key
var key string
gid := ctx.Event.GroupID
if gid < 0 {
// 个人用户设为负数
gid = -ctx.Event.UserID
}
if ctx.State["regex_matched"].([]string)[1] != "" {
key = ctx.State["regex_matched"].([]string)[1]
} else {
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
_ = m.Manager.GetExtra(gid, &key)
if key == "" {
_ = m.Manager.GetExtra(defKeyID, &key)
}
// 更新签到次数
err := sdb.InsertOrUpdateSignInCountByUID(uid, si.Count+1)
}
uid := ctx.Event.UserID
today := time.Now().Format("20060102")
// 签到图片
drawedFile := cachePath + strconv.FormatInt(uid, 10) + today + "signin.png"
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png"
// 获取签到时间
si := sdb.GetSignInByUID(uid)
siUpdateTimeStr := si.UpdatedAt.Format("20060102")
switch {
case si.Count >= signinMax && siUpdateTimeStr == today:
// 如果签到时间是今天
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!"))
if file.IsExist(drawedFile) {
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
}
return
case siUpdateTimeStr != today:
// 如果是跨天签到就清数据
err := sdb.InsertOrUpdateSignInCountByUID(uid, 0)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 更新经验
level := sdb.GetScoreByUID(uid).Score + 1
if level > SCOREMAX {
level = SCOREMAX
ctx.SendChain(message.At(uid), message.Text("你的等级已经达到上限"))
}
err = sdb.InsertOrUpdateScoreByUID(uid, level)
}
// 更新签到次数
err := sdb.InsertOrUpdateSignInCountByUID(uid, si.Count+1)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 更新经验
level := sdb.GetScoreByUID(uid).Score + 1
if level > SCOREMAX {
level = SCOREMAX
ctx.SendChain(message.At(uid), message.Text("你的等级已经达到上限"))
}
err = sdb.InsertOrUpdateScoreByUID(uid, level)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 更新钱包
rank := getrank(level)
add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高
err = wallet.InsertWalletOf(uid, add)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
alldata := scdata{
drawedfile: drawedFile,
picfile: picFile,
uid: uid,
nickname: ctx.CardOrNickName(uid),
inc: add,
score: wallet.GetWalletOf(uid),
level: level,
rank: rank,
}
var drawimage image.Image
switch key {
case "1":
drawimage, err = drawScore16(&alldata)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 更新钱包
rank := getrank(level)
add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高
err = wallet.InsertWalletOf(uid, add)
case "2":
drawimage, err = drawScore15(&alldata)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
score := wallet.GetWalletOf(uid)
// 绘图
getAvatar, err := initPic(picFile, uid)
default:
ctx.SendChain(message.Text("未找到签到设定:", key))
return
}
// done.
f, err := os.Create(drawedFile)
if err != nil {
data, err := imgfactory.ToBytes(drawimage)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
back, err := gg.LoadImage(picFile)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 避免图片过大,最大 1280*720
back = imgfactory.Limit(back, 1280, 720)
imgDX := back.Bounds().Dx()
imgDY := back.Bounds().Dy()
canvas := gg.NewContext(imgDX, imgDY)
// draw Aero Style
aeroStyle := gg.NewContext(imgDX-202, imgDY-202)
aeroStyle.DrawImage(imaging.Blur(back, 2.5), -100, -100)
// aero draw image.
aeroStyle.DrawRoundedRectangle(0, 0, float64(imgDX-200), float64(imgDY-200), 16)
// SideLine
aeroStyle.SetLineWidth(3)
aeroStyle.SetRGBA255(255, 255, 255, 100)
aeroStyle.StrokePreserve()
aeroStyle.SetRGBA255(255, 255, 255, 140)
// fill
aeroStyle.Fill()
// draw background
canvas.DrawImage(back, 0, 0)
// Aero style combine
canvas.DrawImage(aeroStyle.Image(), 100, 100)
canvas.Fill()
hourWord := getHourWord(now)
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
avatarf := imgfactory.Size(avatar, 200, 200)
canvas.DrawImage(avatarf.Circle(0).Image(), 120, 120)
// draw info(name,coin,etc)
canvas.SetRGB255(0, 0, 0)
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if err = canvas.ParseFontFace(data, 50); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// draw head
nickName := ctx.CardOrNickName(uid)
canvas.DrawString(nickName, 350, 180)
canvas.Fill()
// main draw
data, err = file.GetLazyData(text.FontFile, control.Md5File, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if err = canvas.ParseFontFace(data, 30); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
canvas.DrawStringAnchored(hourWord, 350, 280, 0, 0)
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(add), 350, 350, 0, 0)
canvas.DrawStringAnchored("当前ATRI币"+strconv.Itoa(score), 350, 400, 0, 0)
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(level)), 350, 450, 0, 0)
// draw Info(Time,etc.)
getTime := time.Now().Format("2006-01-02 15:04:05")
getTimeLengthWidth, getTimeLengthHight := canvas.MeasureString(getTime)
canvas.DrawStringAnchored(getTime, float64(imgDX)-100-20-getTimeLengthWidth/2, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
var nextrankScore int
if rank < 10 {
nextrankScore = rankArray[rank+1]
} else {
nextrankScore = SCOREMAX
}
nextLevelStyle := strconv.Itoa(level) + "/" + strconv.Itoa(nextrankScore)
getLevelLength, _ := canvas.MeasureString(nextLevelStyle)
canvas.DrawStringAnchored(nextLevelStyle, 100+getLevelLength, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
canvas.Fill()
canvas.SetRGB255(255, 255, 255)
if err = canvas.ParseFontFace(data, 20); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
canvas.SetRGB255(0, 0, 0)
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
canvas.SetRGB255(255, 255, 255)
// Gradient
grad := gg.NewLinearGradient(20, 320, 400, 20)
grad.AddColorStop(0, color.RGBA{G: 255, A: 255})
grad.AddColorStop(1, color.RGBA{B: 255, A: 255})
grad.AddColorStop(0.5, color.RGBA{R: 255, A: 255})
canvas.SetStrokeStyle(grad)
canvas.SetLineWidth(4)
// level array with rectangle work.
gradLineLength := float64(imgDX-120) - 120
renderLine := (float64(level) / float64(nextrankScore)) * gradLineLength
canvas.MoveTo(120, float64(imgDY)-102)
canvas.LineTo(120+renderLine, float64(imgDY)-102)
canvas.ClosePath()
canvas.Stroke()
// done.
f, err := os.Create(drawedFile)
if err != nil {
data, err := imgfactory.ToBytes(canvas.Image())
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.ImageBytes(data))
return
}
_, err = imgfactory.WriteTo(canvas.Image(), f)
_ = f.Close()
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
})
ctx.SendChain(message.ImageBytes(data))
return
}
_, err = imgfactory.WriteTo(drawimage, f)
_ = f.Close()
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
})
engine.OnPrefix("获得签到背景", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
@ -328,6 +268,27 @@ func init() {
}
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
})
engine.OnRegex(`^设置(默认)?签到预设\s?(\d*)$`, zero.SuperUserPermission).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
if ctx.State["regex_matched"].([]string)[2] == "" {
ctx.SendChain(message.Text("设置失败,数据为空"))
} else {
s := ctx.State["regex_matched"].([]string)[1]
key := ctx.State["regex_matched"].([]string)[2]
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
if s != "" {
gid = defKeyID
}
err := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager.SetExtra(gid, key)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("设置成功,当前", s, "预设为:", key))
}
})
}
func getHourWord(t time.Time) string {