mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
style: clang mass formatting
This commit is contained in:
@@ -18,15 +18,15 @@ enum class SkillUsage // 技能用法
|
||||
{
|
||||
NotUse = 0, // 不自动使用
|
||||
Possibly = 1, // 有就用,例如干员 棘刺 3 技能
|
||||
Times = 2, // 用 X 次,例如干员 山 2 技能用 1 次、重岳 3 技能用 5 次,由 "skill_times" 字段控制
|
||||
InTime = 3, // 自动判断使用时机,画饼.jpg
|
||||
TimesUsed // 已经使用了 X 次
|
||||
Times = 2, // 用 X 次,例如干员 山 2 技能用 1 次、重岳 3 技能用 5 次,由 "skill_times" 字段控制
|
||||
InTime = 3, // 自动判断使用时机,画饼.jpg
|
||||
TimesUsed // 已经使用了 X 次
|
||||
};
|
||||
|
||||
struct OperUsage // 干员用法
|
||||
{
|
||||
std::string name;
|
||||
int skill = 0; // 技能序号,取值范围 [0, 3],0时使用默认技能 或 上次编队时使用的技能
|
||||
int skill = 0; // 技能序号,取值范围 [0, 3],0时使用默认技能 或 上次编队时使用的技能
|
||||
SkillUsage skill_usage = SkillUsage::NotUse;
|
||||
int skill_times = 1; // 使用技能的次数,默认为 1,兼容曾经的作业
|
||||
};
|
||||
|
||||
@@ -41,9 +41,9 @@ struct Skill
|
||||
std::string desc;
|
||||
std::unordered_map<std::string, double> efficient; // 技能效率,key:产品名(赤金、经验书等), value: 效率数值
|
||||
std::unordered_map<std::string, std::string>
|
||||
efficient_regex; // 技能效率正则,key:产品名(赤金、经验书等), value: 效率正则。
|
||||
// 如不为空,会先对正则进行计算,再加上efficient里面的值
|
||||
int max_num = INT_MAX; // 最多选几个该技能
|
||||
efficient_regex; // 技能效率正则,key:产品名(赤金、经验书等), value: 效率正则。
|
||||
// 如不为空,会先对正则进行计算,再加上efficient里面的值
|
||||
int max_num = INT_MAX; // 最多选几个该技能
|
||||
|
||||
bool operator==(const Skill& skill) const noexcept { return id == skill.id; }
|
||||
};
|
||||
@@ -108,9 +108,9 @@ struct SkillsGroup
|
||||
{
|
||||
std::string desc; // 文字介绍,实际不起作用
|
||||
std::unordered_map<std::string, int> conditions; // 技能组合可用条件,例如:key 发电站数量,value 3
|
||||
std::vector<SkillsComb> necessary; // 必选技能。这里面的缺少任一,则该技能组合不可用
|
||||
std::vector<SkillsComb> optional; // 可选技能。
|
||||
bool allow_external = false; // 当干员数没满3个的时候,是否允许补充外部干员
|
||||
std::vector<SkillsComb> necessary; // 必选技能。这里面的缺少任一,则该技能组合不可用
|
||||
std::vector<SkillsComb> optional; // 可选技能。
|
||||
bool allow_external = false; // 当干员数没满3个的时候,是否允许补充外部干员
|
||||
};
|
||||
|
||||
struct CustomRoomConfig
|
||||
|
||||
@@ -462,11 +462,11 @@ struct TaskPipelineInfo
|
||||
constexpr TaskPipelineInfo(TaskPipelineInfo&&) noexcept = default;
|
||||
constexpr TaskPipelineInfo& operator=(const TaskPipelineInfo&) = default;
|
||||
constexpr TaskPipelineInfo& operator=(TaskPipelineInfo&&) noexcept = default;
|
||||
std::string name; // 任务名
|
||||
TaskList next; // 下一个可能的任务(列表)
|
||||
TaskList sub; // 子任务(列表)
|
||||
TaskList on_error_next; // 任务出错之后要去执行什么
|
||||
TaskList exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
|
||||
std::string name; // 任务名
|
||||
TaskList next; // 下一个可能的任务(列表)
|
||||
TaskList sub; // 子任务(列表)
|
||||
TaskList on_error_next; // 任务出错之后要去执行什么
|
||||
TaskList exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
|
||||
TaskList reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,
|
||||
// 则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1
|
||||
};
|
||||
@@ -502,17 +502,17 @@ struct TaskInfo : public TaskPipelineInfo
|
||||
constexpr TaskInfo& operator=(TaskInfo&&) noexcept = default;
|
||||
AlgorithmType algorithm = AlgorithmType::Invalid; // 图像算法类型
|
||||
ProcessTaskAction action = ProcessTaskAction::Invalid; // 要进行的操作
|
||||
bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务
|
||||
int max_times = INT_MAX; // 任务最多执行多少次
|
||||
Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域
|
||||
int pre_delay = 0; // 执行该任务前的延时
|
||||
int post_delay = 0; // 执行该任务后的延时
|
||||
int retry_times = INT_MAX; // 未找到图像时的重试次数
|
||||
Rect roi; // 要识别的区域,若为0则全图识别
|
||||
Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。
|
||||
// 即识别到了res,点击res + result_move的位置
|
||||
bool cache = false; // 是否使用缓存区域
|
||||
std::vector<int> special_params; // 某些任务会用到的特殊参数
|
||||
bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务
|
||||
int max_times = INT_MAX; // 任务最多执行多少次
|
||||
Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域
|
||||
int pre_delay = 0; // 执行该任务前的延时
|
||||
int post_delay = 0; // 执行该任务后的延时
|
||||
int retry_times = INT_MAX; // 未找到图像时的重试次数
|
||||
Rect roi; // 要识别的区域,若为0则全图识别
|
||||
Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。
|
||||
// 即识别到了res,点击res + result_move的位置
|
||||
bool cache = false; // 是否使用缓存区域
|
||||
std::vector<int> special_params; // 某些任务会用到的特殊参数
|
||||
std::string input_text; // 输入任务的文字,目前希望仅针对 Input 任务有效, algorithm 为 JustReturn
|
||||
};
|
||||
|
||||
@@ -532,9 +532,9 @@ struct OcrTaskInfo : public TaskInfo
|
||||
bool full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
|
||||
bool is_ascii = false; // 是否启用字符数字模型
|
||||
bool without_det = false; // 是否不使用检测模型
|
||||
bool replace_full = false; // 匹配之后,是否将整个字符串replace(false是只替换match的部分)
|
||||
bool replace_full = false; // 匹配之后,是否将整个字符串replace(false是只替换match的部分)
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配
|
||||
replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配
|
||||
};
|
||||
|
||||
using OcrTaskPtr = std::shared_ptr<OcrTaskInfo>;
|
||||
@@ -556,9 +556,9 @@ struct MatchTaskInfo : public TaskInfo
|
||||
std::vector<std::string> templ_names; // 匹配模板图片文件名
|
||||
std::vector<double> templ_thresholds; // 模板匹配阈值
|
||||
std::vector<MatchMethod> methods; // 匹配方法
|
||||
Ranges mask_ranges; // 匹配掩码范围,TaskData 仅允许 array<int, 2>,但保留彩色掩码支持
|
||||
Ranges color_scales; // 数色掩码范围
|
||||
bool color_close = true; // 数色时是否使用闭运算处理
|
||||
Ranges mask_ranges; // 匹配掩码范围,TaskData 仅允许 array<int, 2>,但保留彩色掩码支持
|
||||
Ranges color_scales; // 数色掩码范围
|
||||
bool color_close = true; // 数色时是否使用闭运算处理
|
||||
};
|
||||
|
||||
using MatchTaskPtr = std::shared_ptr<MatchTaskInfo>;
|
||||
|
||||
@@ -194,7 +194,7 @@ bool asst::RoguelikeRecruitConfig::parse(const json::value& json)
|
||||
}
|
||||
for (auto& offset : oper_info.recruit_priority_offsets) { // 干员的所有 offset 策略组
|
||||
for (auto& group : offset.groups) { // 策略组内的每个干员组
|
||||
offset.opers.insert( // 向当前策略组计入这个干员组的无重复干员
|
||||
offset.opers.insert( // 向当前策略组计入这个干员组的无重复干员
|
||||
get_group_info(theme, group).opers.begin(),
|
||||
get_group_info(theme, group).opers.end());
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@ struct RecruitPriorityOffset
|
||||
{
|
||||
std::vector<std::string> groups; // 造成优先级改变的所有干员组
|
||||
std::unordered_set<std::string> opers; // 所有干员组的所有无重复干员
|
||||
int threshold = 0; // 已拥有组内干员数量阈值,达到此阈值时应用优先级改变
|
||||
bool is_less = false; // 高于阈值时改变还是低于阈值时改变
|
||||
int offset = 0; // 优先级改变的大小
|
||||
int threshold = 0; // 已拥有组内干员数量阈值,达到此阈值时应用优先级改变
|
||||
bool is_less = false; // 高于阈值时改变还是低于阈值时改变
|
||||
int offset = 0; // 优先级改变的大小
|
||||
};
|
||||
|
||||
// 收藏品 priority 影响因子
|
||||
@@ -31,13 +31,13 @@ struct CollectionPriorityOffset
|
||||
// 干员信息,战斗相关
|
||||
struct RoguelikeOperInfo
|
||||
{
|
||||
std::string name; // 干员名
|
||||
std::vector<int> group_id = {}; // 干员组 id,允许一个干员存在于多个干员组
|
||||
std::unordered_map<int, int> order_in_group; // 干员在干员组内的顺序 干员组 id:干员组内顺序
|
||||
int recruit_priority = 0; // 招募优先级 (0-1000)
|
||||
int promote_priority = 0; // 晋升优先级 (0-1000)
|
||||
int recruit_priority_when_team_full = 0; // 队伍满时的招募优先级 (0-1000)
|
||||
int promote_priority_when_team_full = 0; // 队伍满时的晋升优先级 (0-1000)
|
||||
std::string name; // 干员名
|
||||
std::vector<int> group_id = {}; // 干员组 id,允许一个干员存在于多个干员组
|
||||
std::unordered_map<int, int> order_in_group; // 干员在干员组内的顺序 干员组 id:干员组内顺序
|
||||
int recruit_priority = 0; // 招募优先级 (0-1000)
|
||||
int promote_priority = 0; // 晋升优先级 (0-1000)
|
||||
int recruit_priority_when_team_full = 0; // 队伍满时的招募优先级 (0-1000)
|
||||
int promote_priority_when_team_full = 0; // 队伍满时的晋升优先级 (0-1000)
|
||||
std::vector<std::pair<int, int>> recruit_priority_offset; // [deprecated]
|
||||
bool offset_melee = false; // [deprecated]
|
||||
bool is_key = false; // 是否为核心干员
|
||||
@@ -46,7 +46,7 @@ struct RoguelikeOperInfo
|
||||
std::vector<CollectionPriorityOffset> collection_priority_offsets; // 收藏品 priority 影响因子
|
||||
bool is_alternate = false; // 是否后备干员 (允许重复招募、划到后备干员时不再往右划动)
|
||||
int skill = 0; // 使用几技能
|
||||
int alternate_skill = 0; // 当没有指定技能时使用的备选技能,一般是6星干员未精二且精二后使用3技能时才需要指定
|
||||
int alternate_skill = 0; // 当没有指定技能时使用的备选技能,一般是6星干员未精二且精二后使用3技能时才需要指定
|
||||
battle::SkillUsage skill_usage = battle::SkillUsage::Possibly; // 技能使用模式
|
||||
int skill_times = 1; // 技能使用次数
|
||||
battle::SkillUsage alternate_skill_usage = battle::SkillUsage::Possibly; // 备选技能使用模式
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
const noexcept; // 获取该肉鸽内用到的干员组[干员组1,干员组2, ...], renamed from "get_group_info"
|
||||
int get_group_id_from_name(
|
||||
const std::string& theme,
|
||||
const std::string& group_name) noexcept; // 用干员组名获取干员组 id
|
||||
const std::string& group_name) noexcept; // 用干员组名获取干员组 id
|
||||
const std::string
|
||||
get_group_name_from_id(const std::string& theme, const int group_id) const noexcept; // 用干员组 id 获取干员组名
|
||||
|
||||
|
||||
@@ -205,14 +205,10 @@ bool asst::BattleHelper::update_deployment_(
|
||||
re_matcher.set_task_info("BattleAvatarReMatch");
|
||||
re_matcher.set_templ(oper.avatar);
|
||||
if (re_matcher.analyze()) {
|
||||
if (const auto& results = re_matcher.get_result();
|
||||
!results.empty()) {
|
||||
if (const auto& results = re_matcher.get_result(); !results.empty()) {
|
||||
// 遍历结果,找到 y 最小的(之前选中的) rect
|
||||
auto min_rect_iter =
|
||||
ranges::min_element(
|
||||
results, [](const auto& a, const auto& b) {
|
||||
return a.rect.y < b.rect.y;
|
||||
});
|
||||
ranges::min_element(results, [](const auto& a, const auto& b) { return a.rect.y < b.rect.y; });
|
||||
|
||||
oper_rect = min_rect_iter->rect;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ protected:
|
||||
|
||||
private:
|
||||
bool inited = false; // 是否成功初始化为1次,初始化后后续不再检测 (实现调整次数后移除此变量
|
||||
int m_series = 1; // 连续战斗次数
|
||||
int m_series = 1; // 连续战斗次数
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ private:
|
||||
int m_medicine = 0;
|
||||
int m_expiring_medicine = 0;
|
||||
int m_stone = 0;
|
||||
int m_cur_medicine; // 已使用的理智药数量,不计算临期药品。在每次任务开始前,通过clear()清空
|
||||
int m_cur_medicine; // 已使用的理智药数量,不计算临期药品。在每次任务开始前,通过clear()清空
|
||||
int m_cur_stone; // 已碎石数量。在每次任务开始前,通过clear()清空
|
||||
bool m_sanity_not_enough = false; // 理智不够,需要吃药 / 碎石
|
||||
std::unordered_map<std::string, int> m_drop_stats;
|
||||
|
||||
@@ -83,11 +83,11 @@ bool asst::CopilotTask::set_params(const json::value& params)
|
||||
is_raid = params.get("is_adverse", false);
|
||||
}
|
||||
}
|
||||
bool use_sanity_potion = params.get("use_sanity_potion", false); // 是否吃理智药
|
||||
bool with_formation = params.get("formation", false); // 是否使用自动编队
|
||||
int select_formation = params.get("select_formation", 0); // 选择第几个编队,0为不选择
|
||||
bool add_trust = params.get("add_trust", false); // 是否自动补信赖
|
||||
bool add_user_additional = params.contains("user_additional"); // 是否自动补用户自定义干员
|
||||
bool use_sanity_potion = params.get("use_sanity_potion", false); // 是否吃理智药
|
||||
bool with_formation = params.get("formation", false); // 是否使用自动编队
|
||||
int select_formation = params.get("select_formation", 0); // 选择第几个编队,0为不选择
|
||||
bool add_trust = params.get("add_trust", false); // 是否自动补信赖
|
||||
bool add_user_additional = params.contains("user_additional"); // 是否自动补用户自定义干员
|
||||
auto support_unit_usage = static_cast<SupportUnitUsage>(
|
||||
params.get("support_unit_usage", static_cast<int>(SupportUnitUsage::None))); // 助战干员使用模式
|
||||
std::string support_unit_name = params.get("support_unit_name", std::string());
|
||||
|
||||
@@ -59,9 +59,9 @@ public:
|
||||
enum class SupportUnitUsage // 助战干员使用策略
|
||||
{
|
||||
None = 0, // 不使用助战干员
|
||||
WhenNeeded = 1, // 如果有且仅有一名缺失干员则尝试寻找助战干员补齐编队, 如果无缺失干员则不使用助战干员
|
||||
Specific = 2, // 如果有且仅有一名缺失干员则尝试寻找助战干员补齐编队,如果无缺失干员则使用指定助战干员
|
||||
Random = 3 // 如果有且仅有一名缺失干员则尝试寻找助战干员补齐编队,如果无缺失干员则使用随机助战干员
|
||||
WhenNeeded = 1, // 如果有且仅有一名缺失干员则尝试寻找助战干员补齐编队, 如果无缺失干员则不使用助战干员
|
||||
Specific = 2, // 如果有且仅有一名缺失干员则尝试寻找助战干员补齐编队,如果无缺失干员则使用指定助战干员
|
||||
Random = 3 // 如果有且仅有一名缺失干员则尝试寻找助战干员补齐编队,如果无缺失干员则使用随机助战干员
|
||||
};
|
||||
|
||||
void set_support_unit_usage(const SupportUnitUsage& value) { m_support_unit_usage = value; }
|
||||
|
||||
@@ -27,9 +27,9 @@ public:
|
||||
protected:
|
||||
virtual bool _run() override;
|
||||
bool m_force_shopping_if_credit_full = false; // 设置是否防止信用值溢出
|
||||
bool m_only_buy_discount = false; // 设置只购买折扣信用商品(未打折的白名单物品仍会购买)
|
||||
bool m_reserve_max_credit = false; // 设置消耗信用点至300以下时停止购买商品(仍然会购买白名单物品)
|
||||
bool m_info_credit_full = false; // 设置是否在不购买黑名单物品阶段通知信用点溢出
|
||||
bool m_only_buy_discount = false; // 设置只购买折扣信用商品(未打折的白名单物品仍会购买)
|
||||
bool m_reserve_max_credit = false; // 设置消耗信用点至300以下时停止购买商品(仍然会购买白名单物品)
|
||||
bool m_info_credit_full = false; // 设置是否在不购买黑名单物品阶段通知信用点溢出
|
||||
int credit_ocr();
|
||||
|
||||
// 用于在信用商店界面识别商品信息左上角的折扣信息
|
||||
|
||||
@@ -21,10 +21,10 @@ public:
|
||||
enum class RoguelikeMode
|
||||
{
|
||||
// ------------------ 通用模式 ------------------
|
||||
Exp = 0, // 0 - 刷经验,尽可能稳定地打更多层数,不期而遇采用激进策略
|
||||
Investment = 1, // 1 - 刷源石锭,第一层投资完就退出,不期而遇采用保守策略
|
||||
// 2 - 【已移除】两者兼顾,投资过后再退出,没有投资就继续往后打
|
||||
Ending = 3, // 3 - 尝试通关,激进策略(TODO)
|
||||
Exp = 0, // 0 - 刷经验,尽可能稳定地打更多层数,不期而遇采用激进策略
|
||||
Investment = 1, // 1 - 刷源石锭,第一层投资完就退出,不期而遇采用保守策略
|
||||
// 2 - 【已移除】两者兼顾,投资过后再退出,没有投资就继续往后打
|
||||
Ending = 3, // 3 - 尝试通关,激进策略(TODO)
|
||||
Collectible = 4, // 4 - 刷开局,以获得热水壶或者演讲稿开局或只凹直升,不期而遇采用保守策略
|
||||
Squad = 6, // 6 - 月度小队,尽可能稳定地打更多层数,不期而遇采用激进策略
|
||||
Exploration = 7, // 7 - 深入调查,尽可能稳定地打更多层数,不期而遇采用激进策略
|
||||
|
||||
@@ -72,9 +72,9 @@ bool asst::RoguelikeCustomStartTaskPlugin::load_params(const json::value& params
|
||||
m_collectible_mode_squad = params.get("collectible_mode_squad", m_squad);
|
||||
}
|
||||
|
||||
set_custom(RoguelikeCustomType::Roles, params.get("roles", "")); // 开局职业组
|
||||
set_custom(RoguelikeCustomType::CoreChar, params.get("core_char", "")); // 开局干员名
|
||||
m_config->set_use_support(params.get("use_support", false)); // 开局干员是否为助战干员
|
||||
set_custom(RoguelikeCustomType::Roles, params.get("roles", "")); // 开局职业组
|
||||
set_custom(RoguelikeCustomType::CoreChar, params.get("core_char", "")); // 开局干员名
|
||||
m_config->set_use_support(params.get("use_support", false)); // 开局干员是否为助战干员
|
||||
m_config->set_use_nonfriend_support(params.get("use_nonfriend_support", false)); // 是否可以是非好友助战干员
|
||||
|
||||
if (auto select_list = params.find<json::object>("collectible_mode_start_list"); select_list) {
|
||||
|
||||
@@ -55,8 +55,8 @@ private:
|
||||
const RecruitPriorityOffset& condition,
|
||||
const std::unordered_map<std::string, RoguelikeOper>& chars_map);
|
||||
|
||||
int m_recruit_count = 0; // 第几次招募
|
||||
int m_recruit_count = 0; // 第几次招募
|
||||
bool m_starts_complete = false; // 开局干员是否已经招募,阵容中必须有开局干员,没有前仅招募start干员或预备干员
|
||||
bool m_team_complete = false; // 阵容是否完备,阵容完备前,仅招募key干员或预备干员
|
||||
bool m_team_complete = false; // 阵容是否完备,阵容完备前,仅招募key干员或预备干员
|
||||
};
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ void asst::RoguelikeCollapsalParadigmTaskPlugin::check_panel()
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
toggle_panel(); // 坍缩范式状态栏检查完毕,关闭状态栏,以下为处理识别到的结果
|
||||
toggle_panel(); // 坍缩范式状态栏检查完毕,关闭状态栏,以下为处理识别到的结果
|
||||
|
||||
if (prev_clp_pds == cur_clp_pds) { // 如果坍缩范式没有变动
|
||||
return;
|
||||
|
||||
@@ -51,9 +51,9 @@ private:
|
||||
std::unordered_set<std::string> m_expected_clp_pds; // 希望刷到的坍缩范式
|
||||
|
||||
// ———————— 插件配置信息,从 tasks.json 中读取 ——————————————————————————————
|
||||
std::string m_deepen_text; // 坍缩范式变动通知中"坍缩范式加深"的文字
|
||||
std::string m_deepen_text; // 坍缩范式变动通知中"坍缩范式加深"的文字
|
||||
|
||||
std::unordered_set<std::string> m_banner_triggers_start; // 通过 SubTaskStart 触发 banner check 的任务
|
||||
std::unordered_set<std::string> m_banner_triggers_start; // 通过 SubTaskStart 触发 banner check 的任务
|
||||
std::unordered_set<std::string> m_banner_triggers_completed; // 通过 SubTaskCompleted 触发 banner check 的任务
|
||||
std::unordered_set<std::string> m_panel_triggers; // 通过 SubTaskStart 触发 panel check 的任务
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ std::vector<Matcher::RawResult> Matcher::preproc_and_match(const cv::Mat& image,
|
||||
fp.convertTo(fp, CV_32S);
|
||||
cv::Mat count_result;
|
||||
cv::divide(2 * tp, tp + fp + tp_fn, count_result, 1, CV_32F); // 数色结果为 f1_score
|
||||
cv::multiply(matched, count_result, matched); // 最终结果是数色和模板匹配的点积
|
||||
cv::multiply(matched, count_result, matched); // 最终结果是数色和模板匹配的点积
|
||||
}
|
||||
results.emplace_back(RawResult { .matched = matched, .templ = templ, .templ_name = templ_name });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user