update code

This commit is contained in:
HibiKier
2021-09-05 02:21:38 +08:00
parent 21a5feda43
commit 7afb099c12
84 changed files with 3377 additions and 1404 deletions
+19 -3
View File
@@ -9,9 +9,11 @@ from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.adapters.cqhttp.permission import GROUP
from utils.message_builder import image
from nonebot import on_command
from utils.utils import get_message_text
from utils.utils import get_message_text, scheduler
from pathlib import Path
from configs.path_config import DATA_PATH
from services.log import logger
from .utils import clear_sign_data_pic
try:
import ujson as json
@@ -52,16 +54,18 @@ total_sign_rank = on_command(
@sign.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
nickname = event.sender.card if event.sender.card else event.sender.nickname
await sign.send(
await group_user_check_in(event.user_id, event.group_id),
await group_user_check_in(nickname, event.user_id, event.group_id),
at_sender=True,
)
@my_sign.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
nickname = event.sender.card if event.sender.card else event.sender.nickname
await my_sign.send(
await group_user_check(event.user_id, event.group_id),
await group_user_check(nickname, event.user_id, event.group_id),
at_sender=True,
)
@@ -89,3 +93,15 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await total_sign_rank.send("设置成功,签到总榜将会显示您的头像名称以及好感度!", at_sender=True)
with open(_file, "w", encoding="utf8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
@scheduler.scheduled_job(
'interval',
hours=1,
)
async def _():
try:
clear_sign_data_pic()
logger.info('清理日常签到图片数据数据完成....')
except Exception as e:
logger.error(f'清理日常签到图片数据数据失败..{type(e)}: {e}')
+76
View File
@@ -0,0 +1,76 @@
from configs.path_config import IMAGE_PATH
from pathlib import Path
SIGN_RESOURCE_PATH = Path(IMAGE_PATH) / 'sign' / 'sign_res'
SIGN_TODAY_CARD_PATH = Path(IMAGE_PATH) / 'sign' / 'today_card'
SIGN_BORDER_PATH = Path(SIGN_RESOURCE_PATH) / 'border'
SIGN_BACKGROUND_PATH = Path(SIGN_RESOURCE_PATH) / 'background'
SIGN_TODAY_CARD_PATH.mkdir(exist_ok=True, parents=True)
SIGN_BORDER_PATH.mkdir(exist_ok=True, parents=True)
SIGN_BACKGROUND_PATH.mkdir(exist_ok=True, parents=True)
SIGN_CARD1_PROB = 0.2 # 好感度双倍加持卡Ⅰ
SIGN_CARD2_PROB = 0.09 # 好感度双倍加持卡Ⅱ
SIGN_CARD3_PROB = 0.05 # 好感度双倍加持卡Ⅲ
PROB_DATA = {
SIGN_CARD3_PROB: '好感度双倍加持卡Ⅲ',
SIGN_CARD2_PROB: '好感度双倍加持卡Ⅱ',
SIGN_CARD1_PROB: '好感度双倍加持卡Ⅰ'
}
lik2relation = {
'0': '路人',
'1': '陌生',
'2': '初识',
'3': '普通',
'4': '熟悉',
'5': '信赖',
'6': '相知',
'7': '厚谊',
'8': '亲密'
}
level2attitude = {
'0': '排斥',
'1': '警惕',
'2': '可以交流',
'3': '一般',
'4': '是个好人',
'5': '好朋友',
'6': '可以分享小秘密',
'7': '喜欢',
'8': '恋人'
}
weekdays = {
1: 'Mon',
2: 'Tue',
3: 'Wed',
4: 'Thu',
5: 'Fri',
6: 'Sat',
7: 'Sun'
}
lik2level = {
9999: '9',
400: '8',
270: '7',
200: '6',
140: '5',
90: '4',
50: '3',
25: '2',
10: '1',
0: '0'
}
+43 -55
View File
@@ -1,39 +1,47 @@
import random
from datetime import datetime, timedelta
from io import BytesIO
from services.log import logger
from services.db_context import db
from models.sigin_group_user import SignGroupUser
from models.sign_group_user import SignGroupUser
from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
from configs.config import MAX_SIGN_GOLD, NICKNAME
from utils.image_utils import CreateImg
import aiohttp
from configs.config import NICKNAME
from nonebot.adapters.cqhttp import MessageSegment
from asyncio.exceptions import TimeoutError
from utils.image_utils import CreateImg
from services.db_context import db
from .utils import get_card, SIGN_TODAY_CARD_PATH
from services.log import logger
from .random_event import random_event
from io import BytesIO
import random
import aiohttp
import math
import asyncio
import os
async def group_user_check_in(user_qq: int, group: int) -> str:
async def group_user_check_in(
nickname: str, user_qq: int, group: int
) -> MessageSegment:
"Returns string describing the result of checking in"
present = datetime.now()
async with db.transaction():
# 取得相应用户
user = await SignGroupUser.ensure(user_qq, group, for_update=True)
# 如果同一天签到过,特殊处理
if user.checkin_time_last.date() == present.date():
return _handle_already_checked_in(user)
return await _handle_check_in(user_qq, group, present) # ok
# if (
# user.checkin_time_last + timedelta(hours=8)
# ).date() >= present.date() or f"{user}_{group}_sign_{datetime.now().date()}" in os.listdir(
# SIGN_TODAY_CARD_PATH
# ):
# gold = await BagUser.get_gold(user_qq, group)
# return await get_card(user, nickname, -1, gold, "")
return await _handle_check_in(nickname, user_qq, group, present) # ok
def _handle_already_checked_in(user: SignGroupUser) -> str:
return f"已经签到过啦~ 好感度:{user.impression:.2f}"
async def _handle_check_in(user_qq: int, group: int, present: datetime) -> str:
async def _handle_check_in(
nickname: str, user_qq: int, group: int, present: datetime
) -> MessageSegment:
user = await SignGroupUser.ensure(user_qq, group, for_update=True)
impression_added = random.random()
present = present + timedelta(hours=8)
critx2 = random.random()
add_probability = user.add_probability
specify_probability = user.specify_probability
@@ -41,56 +49,36 @@ async def _handle_check_in(user_qq: int, group: int, present: datetime) -> str:
impression_added *= 2
elif critx2 < specify_probability:
impression_added *= 2
new_impression = user.impression + impression_added
message = random.choice(
(
"谢谢,你是个好人!",
"对了,来喝杯茶吗?",
)
)
await user.update(
checkin_count=user.checkin_count + 1,
checkin_time_last=present,
impression=new_impression,
add_probability=0,
specify_probability=0,
).apply()
# glod = await random_glod(user_qq, group, specify_probability)
if user.impression < 1:
impression = 1
else:
impression = user.impression
await SignGroupUser.sign(user, impression_added, present)
gold = random.randint(1, 100)
imgold = random.randint(1, int(impression))
if imgold > MAX_SIGN_GOLD:
imgold = MAX_SIGN_GOLD
await BagUser.add_gold(user_qq, group, gold + imgold)
gift, gift_type = random_event(user.impression)
if gift_type == "gold":
await BagUser.add_gold(user_qq, group, gold + gift)
gift = f"额外金币 + {gift}"
else:
await BagUser.add_props(user_qq, group, gift)
gift += ' + 1'
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
logger.info(
f"(USER {user.user_qq}, GROUP {user.belonging_group})"
f" CHECKED IN successfully. score: {new_impression:.2f} (+{impression_added * 2:.2f}).获取金币:{gold+imgold}"
f" CHECKED IN successfully. score: {user.impression:.2f} "
f"(+{impression_added * 2:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
)
return f"{message} 好感度:{new_impression:.2f} (+{impression_added/2:.2f}×2)!!!\n获取金币:{gold} \n好感度额外获得金币:{imgold}"
return await get_card(user, nickname, impression_added, gold, gift, True)
else:
logger.info(
f"(USER {user.user_qq}, GROUP {user.belonging_group})"
f" CHECKED IN successfully. score: {new_impression:.2f} (+{impression_added:.2f}).获取金币:{gold+imgold}"
f" CHECKED IN successfully. score: {user.impression:.2f} "
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
)
return f"{message} 好感度:{new_impression:.2f} (+{impression_added:.2f})\n获取金币:{gold} \n好感度额外获得金币:{imgold}"
return await get_card(user, nickname, impression_added, gold, gift)
async def group_user_check(user_qq: int, group: int) -> str:
async def group_user_check(nickname: str, user_qq: int, group: int) -> MessageSegment:
# heuristic: if users find they have never checked in they are probable to check in
user = await SignGroupUser.ensure(user_qq, group)
gold = await BagUser.get_gold(user_qq, group)
return "好感度:{:.2f}\n金币:{}\n历史签到数:{}\n上次签到日期:{}".format(
user.impression,
gold,
user.checkin_count,
user.checkin_time_last.date()
if user.checkin_time_last != datetime.min
else "从未",
)
return await get_card(user, nickname, None, gold, "", is_card_view=True)
async def group_impression_rank(group: int) -> str:
@@ -108,7 +96,7 @@ async def group_impression_rank(group: int) -> str:
user_name = (
await GroupInfoUser.get_member_info(user_qq, group)
).user_name
except Exception as e:
except AttributeError:
logger.info(f"USER {user_qq}, GROUP {group} 不在群内")
_count += 1
impression_list.remove(impression)
+24
View File
@@ -0,0 +1,24 @@
from configs.config import MAX_SIGN_GOLD
from typing import Union
from .config import PROB_DATA
import random
def random_event(impression: float) -> 'Union[str, int], str':
"""
签到随机事件
:param impression: 好感度
:return: 额外奖励 和 类型
"""
rand = random.random() - impression / 1000
for prob in PROB_DATA.keys():
if rand <= prob:
return PROB_DATA[prob], 'props'
gold = random.randint(1, random.randint(1, int(1 if impression < 1 else impression)))
gold = MAX_SIGN_GOLD if gold > MAX_SIGN_GOLD else gold
return gold, 'gold'
+330
View File
@@ -0,0 +1,330 @@
from .config import (
SIGN_RESOURCE_PATH,
SIGN_TODAY_CARD_PATH,
SIGN_BORDER_PATH,
SIGN_BACKGROUND_PATH,
lik2level,
lik2relation,
level2attitude,
weekdays,
)
from models.sign_group_user import SignGroupUser
from models.group_member_info import GroupInfoUser
from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg
from utils.message_builder import image
from configs.config import NICKNAME
from pathlib import Path
from datetime import datetime
from typing import Optional, List
from nonebot import Driver
from io import BytesIO
import asyncio
import nonebot
import aiohttp
import os
driver: Driver = nonebot.get_driver()
@driver.on_startup
async def init_image():
SIGN_RESOURCE_PATH.mkdir(parents=True, exist_ok=True)
await GroupInfoUser.add_member_info(114514, 114514, "", datetime.min)
generate_progress_bar_pic()
clear_sign_data_pic()
async def _get_pic(qq):
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=100"
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=5) as response:
return await response.read()
async def get_card(
user: "SignGroupUser",
nickname: str,
add_impression: Optional[float],
gold: Optional[int],
gift: str,
is_double: bool = False,
is_card_view: bool = False,
) -> MessageSegment:
user_id = user.user_qq
date = datetime.now().date()
_type = 'view' if is_card_view else 'sign'
card_file = Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.belonging_group}_{_type}_{date}.png"
if card_file.exists():
return image(f"{user_id}_{user.belonging_group}_{_type}_{date}.png", "sign/today_card")
else:
if add_impression == -1:
card_file = Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.belonging_group}_view_{date}.png"
if card_file.exists():
return image(f"{user_id}_{user.belonging_group}_view_{date}.png", "sign/today_card")
is_card_view = True
ava = BytesIO(await _get_pic(user_id))
uid = await GroupInfoUser.get_group_member_uid(
user.user_qq, user.belonging_group
)
impression_list = None
if is_card_view:
_, impression_list, _ = await SignGroupUser.get_all_impression(
user.belonging_group
)
return await asyncio.get_event_loop().run_in_executor(
None,
_generate_card,
user,
nickname,
user_id,
add_impression,
gold,
gift,
uid,
ava,
impression_list,
is_double,
is_card_view,
)
def _generate_card(
user: "SignGroupUser",
nickname: str,
user_id: int,
impression: Optional[float],
gold: Optional[int],
gift: str,
uid: str,
ava_bytes: BytesIO,
impression_list: List[float],
is_double: bool = False,
is_card_view: bool = False,
) -> MessageSegment:
ava_bk = CreateImg(140, 140, is_alpha=True)
ava_border = CreateImg(
140,
140,
background=SIGN_BORDER_PATH / 'ava_border_01.png',
)
ava = CreateImg(102, 102, background=ava_bytes)
ava.circle()
ava_bk.paste(ava, center_type="center")
ava_bk.paste(ava_border, alpha=True, center_type="center")
info_img = CreateImg(250, 150, color=(255, 255, 255, 0), font_size=15)
level, next_impression, previous_impression = get_level_and_next_impression(
user.impression
)
info_img.text((0, 0), f"· 好感度等级:{level} [{lik2relation[level]}]")
info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}")
info_img.text((0, 40), f"· 距离升级还差 {next_impression - user.impression:.2f} 好感度")
bar_bk = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
bar = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
bar_bk.paste(
bar,
(
-int(
220
* (
(next_impression - user.impression)
/ (next_impression - previous_impression)
)
),
0,
),
True,
)
font_size = 30
if '好感度双倍加持卡' in gift:
font_size = 20
gift_border = CreateImg(
270, 100, background=SIGN_BORDER_PATH / "gift_border_02.png", font_size=font_size
)
gift_border.text((0, 0), gift, center_type="center")
bk = CreateImg(
876, 424, background=SIGN_BACKGROUND_PATH / "background_01.jpg", font_size=25
)
A = CreateImg(876, 274, background=SIGN_RESOURCE_PATH / "white.png")
line = CreateImg(2, 180, color="black")
A.transparent(2)
A.paste(ava_bk, (25, 80), True)
A.paste(line, (200, 70))
nickname_img = CreateImg(
0,
0,
plain_text=nickname,
color=(255, 255, 255, 0),
font_size=50,
font_color=(255, 255, 255),
)
if uid:
uid = f"{uid}".rjust(12, "0")
uid = uid[:4] + " " + uid[4:8] + " " + uid[8:]
else:
uid = "XXXX XXXX XXXX"
uid_img = CreateImg(
0,
0,
plain_text=f"UID: {uid}",
color=(255, 255, 255, 0),
font_size=30,
font_color=(255, 255, 255),
)
sign_day_img = CreateImg(
0,
0,
plain_text=f"{user.checkin_count}",
color=(255, 255, 255, 0),
font_size=40,
font_color=(211, 64, 33),
)
lik_text1_img = CreateImg(
0, 0, plain_text="当前", color=(255, 255, 255, 0), font_size=20
)
lik_text2_img = CreateImg(
0,
0,
plain_text=f"好感度:{user.impression:.2f}",
color=(255, 255, 255, 0),
font_size=30,
)
watermark = CreateImg(
0,
0,
plain_text=f"{NICKNAME}@{datetime.now().year}",
color=(255, 255, 255, 0),
font_size=15,
font_color=(155, 155, 155),
)
today_data = CreateImg(300, 300, color=(255, 255, 255, 0), font_size=20)
if is_card_view:
today_sign_text_img = CreateImg(
0, 0, plain_text="", color=(255, 255, 255, 0), font_size=30
)
if impression_list:
impression_list.sort(reverse=True)
index = impression_list.index(user.impression)
rank_img = CreateImg(
0,
0,
plain_text=f"* 此群好感排名第 {index + 1} 位",
color=(255, 255, 255, 0),
font_size=30,
)
A.paste(rank_img, ((A.w - rank_img.w - 10), 20), True)
today_data.text(
(0, 0),
f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}",
)
today_data.text((0, 25), f"总金币:{gold}")
today_data.text((0, 50), f'色图概率:{(70 + user.impression if user.impression < 100 else 100):.2f}%')
today_data.text((0, 75), f'开箱次数:{(20 + int(user.impression / 3))}')
_type = "view"
else:
A.paste(gift_border, (570, 140), True)
today_sign_text_img = CreateImg(
0, 0, plain_text="今日签到", color=(255, 255, 255, 0), font_size=30
)
if is_double:
today_data.text((0, 0), f"好感度 + {impression / 2:.2f} × 2")
else:
today_data.text((0, 0), f"好感度 + {impression:.2f}")
today_data.text((0, 25), f"金币 + {gold}")
_type = "sign"
current_date = datetime.now()
week = current_date.isoweekday()
data = current_date.date()
hour = current_date.hour
minute = current_date.minute
second = current_date.second
data_img = CreateImg(
0,
0,
plain_text=f"时间:{data} {weekdays[week]} {hour}:{minute}:{second}",
color=(255, 255, 255, 0),
font_size=20,
)
bk.paste(nickname_img, (30, 15), True)
bk.paste(uid_img, (30, 85), True)
bk.paste(A, (0, 150), alpha=True)
bk.text((30, 167), "Accumulative check-in for")
_x = bk.getsize("Accumulative check-in for")[0] + sign_day_img.w + 45
bk.paste(sign_day_img, (346, 158), True)
bk.text((_x, 167), "days")
bk.paste(data_img, (220, 370), True)
bk.paste(lik_text1_img, (220, 240), True)
bk.paste(lik_text2_img, (262, 234), True)
bk.paste(bar_bk, (225, 275), True)
bk.paste(info_img, (220, 305), True)
bk.paste(today_sign_text_img, (550, 180), True)
bk.paste(today_data, (580, 220), True)
bk.paste(watermark, (15, 400), True)
bk.save(SIGN_TODAY_CARD_PATH / f"{user_id}_{user.belonging_group}_{_type}_{data}.png")
return image(f"{user_id}_{user.belonging_group}_{_type}_{data}.png", "sign/today_card")
def generate_progress_bar_pic():
bg_2 = (254, 1, 254)
bg_1 = (0, 245, 246)
bk = CreateImg(1000, 50, is_alpha=True)
img_x = CreateImg(50, 50, color=bg_2)
img_x.circle()
img_x.crop((25, 0, 50, 50))
img_y = CreateImg(50, 50, color=bg_1)
img_y.circle()
img_y.crop((0, 0, 25, 50))
A = CreateImg(950, 50)
width, height = A.size
step_r = (bg_2[0] - bg_1[0]) / width
step_g = (bg_2[1] - bg_1[1]) / width
step_b = (bg_2[2] - bg_1[2]) / width
for y in range(0, width):
bg_r = round(bg_1[0] + step_r * y)
bg_g = round(bg_1[1] + step_g * y)
bg_b = round(bg_1[2] + step_b * y)
for x in range(0, height):
A.point((y, x), fill=(bg_r, bg_g, bg_b))
bk.paste(img_y, (0, 0), True)
bk.paste(A, (25, 0))
bk.paste(img_x, (975, 0), True)
bk.save(SIGN_RESOURCE_PATH / "bar.png")
A = CreateImg(950, 50)
bk = CreateImg(1000, 50, is_alpha=True)
img_x = CreateImg(50, 50)
img_x.circle()
img_x.crop((25, 0, 50, 50))
img_y = CreateImg(50, 50)
img_y.circle()
img_y.crop((0, 0, 25, 50))
bk.paste(img_y, (0, 0), True)
bk.paste(A, (25, 0))
bk.paste(img_x, (975, 0), True)
bk.save(SIGN_RESOURCE_PATH / "bar_white.png")
def get_level_and_next_impression(impression: float):
if impression == 0:
return lik2level[10], 10, 0
keys = list(lik2level.keys())
for i in range(len(keys)):
if impression > keys[i]:
return lik2level[keys[i]], keys[i - 1], keys[i]
return lik2level[10], 10, 0
def clear_sign_data_pic():
date = datetime.now().date()
for file in os.listdir(SIGN_TODAY_CARD_PATH):
if str(date) not in file:
os.remove(SIGN_TODAY_CARD_PATH / file)