# 添加商品和对应使用方法

在不修改shop插件代码的情况,添加商品和对应生效方法

# 导入方法1(不推荐)


# 该导入方式可能由于插件加载顺序先后问题导致出错!!

# use 提供了一个方法
# use.register_use(goods_name: str, **kwargs) : 注册插件使用方法

# shop提供了三个方法
#
# 注册商品
# register_goods(
#         name: str,                            # 商品名称
#         price: int,                           # 商品价格
#         des: str,                             # 商品简介
#         discount: Optional[float] = 1,        # 商品折扣
#         limit_time: Optional[int] = 0,        # 商品限时
#         daily_limit: Optional[int] = 0,       # 每日次数购买限制
#         is_passive: Optional[int] = 0,        # 是否为被动道具(无法主动使用)
#         icon: Optional[int] = 0,              # 图标,路径为 resources/shop_icon
#         **kwargs,
# )
# 删除商品
# delete_goods(name: str, id_: int)

# 更新商品
# update_goods(**kwargs)

# 导入添加商品的(使用require)
from nonebot.plugin import require

use = require("use")
shop = require("shop_handle")

from basic_plugins.shop.use.data_source import register_use, func_manager
from basic_plugins.shop.shop_handle.data_source import register_goods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 导入方法2(推荐)


from utils.decorator.shop import shop_register

1
2
3

# 参数说明


# 注册道具方法(以下均为默认值)
register_goods(
    name: str,                            # 商品名称
    price: int,                           # 商品价格
    des: str,                             # 商品简介
    discount: Optional[float] = 1,        # 商品折扣
    limit_time: Optional[int] = 0,        # 商品限时
    daily_limit: Optional[int] = 0,       # 每日次数购买限制
    load_status: bool = True,             # 每日次数购买限制
    is_passive: bool = False,             # 是否为被动道具(无法主动使用)
    icon: str = None,                     # 图标,路径为 resources/image/shop_icon
    **kwargs,
)

# kwargs中的特殊key(以下为默认值)
kwargs["max_num_limit"]: 1,        # 设置单次使用最大数量,默认为1
kwargs["send_success_msg"]: True   # 是否发送基础的使用道具提示,默认提示


# 例子
# 注册好感度加持卡
await register_goods(
    "好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)", **{"prob": 0.1}
)

# 道具使用前函数(非必要,仅在需要时注册)
shop_register.before_handle(
    name: Union[str, Tuple[str, ...]],                  # 道具名称
    load_status: bool = True    # 加载状态
)

# 道具使用后函数(非必要,仅在需要时注册)
shop_register.after_handle(
    name: Union[str, Tuple[str, ...]],                  # 道具名称
    load_status: bool = True    # 加载状态
)


# 道具生效方法,使用前方法,使用后方法,参数的获取方法三种函数均相同
# 更推荐第二种和第三种方式
# 第一种
async def sign_card(**kwargs):
    goods_name = kwargs.get('goods_name')     # 所有方法中都会含有goods_name
    user_id = kwargs.get('user_id')           # 所有方法中都会含有user_id
    group_id = kwargs.get('group_id')         # 所有方法中都会含有group_id
    bot = kwargs.get('_bot')                  # 所有方法中都会含有bot
    event = kwargs.get('event')               # 所有方法中都会含有event
    num = kwargs.get('num')                   # 所有方法中道具单次使用数量
    text = kwargs.get('text')                 # 所有方法中附带的纯文本信息
    message = kwargs.get('message')           # event.message(可以获取at,图片等) 
    prob = kwargs.get('prob')                 # prob为自己定义传递的值
    ...     # 处理逻辑

# 第二种
async def sign_card(goods_name: str, user_id: int, group_id: int, num: int, bot: Bot, event: Event, text: str, message: Message, prob: float): 
    print(f'{user_id}用了{num}{goods_name}')
    ...     # 处理逻辑

# 第三种
from utils.models import ShopParam

async def sign_card(shop_param: ShopParam):     
    goods_name = shop_param.goods_name
    user_id = shop_param.user_id
    group_id = shop_param.group_id
    bot = shop_param.bot
    event = shop_param.event
    num = shop_param.num
    text = shop_param.text
    message = shop_param.message
    prob = shop_param.prob      # prob为自己定义传递的值
    ...     # 处理逻辑

# 特别提醒!
# 道具使用前方法可以通过抛出异常来阻断使用并回复内容
from utils.decorator.shop import NotMeetUseConditionsException

async def before_handle(user_id: int): 
    print(f'{user_id}太笨了!不准使用道具!')
    raise NotMeetUseConditionsException("小真寻嫌弃你!")     # 消息内容 Union[str, MessageSegment, Message]
    ...     # 处理逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

# 注册商品和生效方法

可以直接注册商品和对应使用函数以及道具使用前,使用后函数


# 定义商品对应使用方法与方法一无异,含有三种形式,这里使用推荐的第二种形式

from utils.decorator.shop import shop_register

# 注册单个商品
@shop_register(
    name="好感度双倍加持卡Ⅰ",
    price=30,
    des="下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
    load_status=True,   # 加载状态,控制是否导入该道具,默认值为 True
    daily_limit=1,      # 每日购买次数限制,默认值为 1
    is_passive=False,   # 是否为被动道具,被动道具无法被主动使用,默认值为 False
    icon="favorability_card_1.png",     # 道具图标,路径在 resources/image/shop_icon 下,往该文件夹添加图片即可
    ** {"prob": 0.1},   # s
)
async def sign_card(user_id: int, group_id: int, prob: float): 
    print(f"{user_id}的好感度加持卡生效咯...")
    ...     # 处理逻辑

# 注册多个商品,即多个商品使用相同的处理函数
# 这时参数类型将由字符串转为元祖
# 每个商品拥有各自的数据
# 自定义参数需要使用 {f"{name}_xxx": value} 的形式
@shop_register(
    name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
    price=(30, 150, 250),
    des=(
        "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
        "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
        "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
    ),
    load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
    daily_limit=(10, 20, 30)    # 每日购买次数限制
    is_passive=(True, False, True)      # 第二个好感度卡为被动道具,无法主动使用
    icon=("favorability_card_1.png", "favorability_card_2.png", "favorability_card_3.png")
    ** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
)
async def sign_card(user_id: int, group_id: int, prob: float):
    user = await SignGroupUser.ensure(user_id, group_id)
    await user.update(add_probability=prob).apply()

# 注册多个商品,共用价格,简介,加载状态,是否被动,图标等等
# 其中 价格(price),简介(des),加载状态(load_status) 可不为元祖
@shop_register(
    name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
    price=30,       # 等同于 (30, 30, 30)
    des="下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
    load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
    is_passive=True,
    icon="favorability_card_1.png",
    ** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
)
async def sign_card(user_id: int, group_id: int, prob: float):
    user = await SignGroupUser.ensure(user_id, group_id)
    await user.update(add_probability=prob).apply()

# 道具使用前函数和使用后可以注册多个,会遍历执行,顺序为方法顺序,参数与生效方法参数一致可以通过参数名称获取

# 道具使用前函数
@shop_register.before_handle(name="测试道具A")
async def _(user_id: int, group_id: int, goods_name: str):
    print(f"有人要使用{goods_name}道具咯,让我检查一下道具是否安全")
    ...

from utils.decorator.shop import NotMeetUseConditionsException

# 道具使用前函数
@shop_register.before_handle(name="测试道具A")
async def _(user_id: int, goods_name: str):
    if goods_name == '炸弹':
        print(f"坏了!是炸弹!别让他使用!")
        raise NotMeetUseConditionsException("炸弹危险物品!不许用!")       # 该消息将反馈给道具使用者
    ...

# 道具使用后函数
@shop_register.after_handle(name="测试道具A")
async def _(goods_name: str):
    print(f'{goods_name}这个道具已经使用完成啦')

# 道具使用后函数
@shop_register.after_handle(name="测试道具A")
async def _(goods_name: str):
    print(f'{goods_name}这个道具已经使用完成啦(再一次!)')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

# 完整代码(方式一,看看参数就好了,不推荐啦)


######################################
## 示例:在Bot启动时导入商品和对应方法 ##
#####################################

from nonebot import Driver
from nonebot.plugin import require

driver: Driver = nonebot.get_driver()


use = require("use")
shop = require("shop_handle")

@driver.on_startup
async def _():
    # 生效方法 方式一
    async def sign_card(**kwargs):
        goods_name = kwargs['goods_name']
        user_id = kwargs['user_id']
        group_id = kwargs['group_id']
        prob = kwargs['prob']
        print(f"USER {user_id} GROUP {group_id} 这个道具:{goods_name}使用成功了:{prob}")
        # do something....
        # 使用 bot 进行发送消息
        # bot = kwargs.get('_bot')
        # await bot.send_group_msg(group_id=group_id, message="这个道具生效了!")
        return "这个道具生效了!"       # 返回值将作为提示内容输出,也可以返回None,在sign_card中使用bot发送消息

    # 生效方法 方式二
    async def sign_card(goods_name: str, user_id: int, group_id: int, prob: float):
        print(f"USER {user_id} GROUP {group_id} 这个道具:{goods_name}使用成功了:{prob}")
        # do something....
        return "这个道具生效了!"       # 返回值将作为提示内容输出,也可以返回None,在sign_card中使用bot发送消息

    # 生效方法 方式三
    from utils.models import ShopParam
    async def sign_card(shop_param: ShopParam):
        goods_name = shop_param.goods_name
        user_id = shop_param.user_id
        group_id = shop_param.group_id
        prob = shop_param.prob
        print(f"USER {user_id} GROUP {group_id} 这个道具:{goods_name}使用成功了:{prob}")
        # do something....
        return "这个道具生效了!"       # 返回值将作为提示内容输出,也可以返回None,在sign_card中使用bot发送消息
        

    # 在数据库中注册商品数据
    await shop.register_goods(
        "好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"
    )

    # 注册商品生效方法
    use.register_use("好感度双倍加持卡Ⅰ", sign_card, **{
        "max_num_limit": 10,       # 设置单次使用最大数量
        "send_success_msg": False   # 不发送基础的使用道具提示
        "prob": 0.1                 # 自己传递的值,在函数中需要使用到
    })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 完整代码(方式二,NICE推荐)

from nonebot import Driver
from utils.decorator.shop import shop_register, NotMeetUseConditionsException
driver: Driver = nonebot.get_driver()


@driver.on_startup
async def _():

    # 注册单个
    @shop_register(
        name="好感度双倍加持卡Ⅰ",
        price=30,
        des="下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
        load_status=True,
        daily_limit=100,
        icon="favorability_card_1.png",
        ** {"prob": 0.1},
    )
    async def sign_card(goods_name: str, user_id: int, group_id: int, prob: float):
        print(f"USER {user_id} GROUP {group_id} 这个道具:{goods_name}使用成功了:{prob}")
        # do something....
        return "这个道具生效了!"       # 返回值将作为提示内容输出,也可以返回None,在sign_card中使用bot发送消息

    # 道具使用前,使用后方法仅在需要时注册

    # 注册道具使用前函数
    @shop_register.before_handle(name="好感度双倍加持卡Ⅰ")
    async def _(user_id: int, group_id: int, goods_name: str):
        print("在使用之前,让我给你的道具检查一下发育健不健康")
        ...

    # 注册道具使用前函数
    @shop_register.before_handle(name="好感度双倍加持卡Ⅰ")
    async def _(user_id: int, group_id: int, goods_name: str):
        user = await SignGroupUser.ensure(user_id, group_id)
        if user.impression < 100:
            raise NotMeetUseConditionsException("你的好感度小于100,不准你使用好感度加持卡")
        await user.update(add_probability=prob).apply()

    @shop_register.after_handle(name="测试道具A")
    async def _():
        print("用完了,味道不错")
        ...


    # 注册多个
    @shop_register(
        name=("好人卡", "坏人卡"),
        price=(30, 10),
        des=("这是好人卡", "这是坏人卡"),
        load_status=(True, False),
        daily_limit=(10, 20),
        ** {"好人卡_prob": 0.1, "坏人卡_prob": 0.2},
    )
    async def sign_card(goods_name: str, user_id: int, group_id: int, prob: float):
        print(f"USER {user_id} GROUP {group_id} 这个道具:{goods_name}使用成功了:{prob}")
        # do something....
        return "这个道具生效了!"       # 返回值将作为提示内容输出,也可以返回None,在sign_card中使用bot发送消息
    
    # 一个道具使用前函数和使用后可以注册给多个商品
    # 注册道具使用前函数
    @shop_register.before_handle(name=("好人卡", "坏人卡"))
    async def _(user_id: int, group_id: int, goods_name: str):
        if goods_name == '好人卡':
            print('滴,检测到好人卡')
        if goods_name == '坏人卡':
            print('滴,检测到坏人卡')
        ...

    # 注册道具使用前函数
    @shop_register.before_handle(name=("好人卡", "坏人卡"))
    async def _(user_id: int, group_id: int, goods_name: str):
        if goods_name == '坏人卡':
            raise NotMeetUseConditionsException("你是坏人,抓起来")

    @shop_register.after_handle(name="测试道具A")
    async def _(goods_name: str):
        if goods_name == '好人卡':
            print('好人再见')
        ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81