` 形式.
-##### 复杂的消息建造 (比如图片什么的) 用 MessageBuilder 类:
+### 复杂的消息建造 (比如图片什么的) 用 MessageBuilder 类:
注意: `.add(Object)` 方法对于所有类型的对象都有效, 只要能 `toString()` 就行
@@ -481,7 +525,7 @@ new MessageBuilder()
-#### 4. 指令
+### 4. 指令
每一个指令需要单独创建一个类, 实现一个指令接口
如果这个指令在所有消息环境内都能执行的话, 实现 `EverywhereCommand` 类
@@ -508,7 +552,7 @@ public class CommandVersion implements EverywhereCommand // 实现EverywhereComm
{
// 处理, 返回值会自动回复回去
// 这里因为这个指令是用来查版本的, 所以直接返回字符串了
- return "TestBot - PicqBotX v4.10.1.928";
+ return "TestBot - PicqBotX v4.11.0.971";
}
}
```
@@ -524,7 +568,7 @@ bot.getCommandManager().registerCommands(new 指令1(), new 指令2(), ...);
常见问题:
--------
-#### Q: 为什么刚加的群不能回复消息?
+### Q: 为什么刚加的群不能回复消息?
因为用户信息在账号管理器里缓存了啦...
不会自动刷新的...
diff --git a/docs/._index.html b/docs/._index.html
new file mode 100644
index 00000000..951d37b2
Binary files /dev/null and b/docs/._index.html differ
diff --git a/docs/cc/moecraft/icq/PicqBotX.html b/docs/cc/moecraft/icq/PicqBotX.html
index 7ad1d24a..542caa31 100644
--- a/docs/cc/moecraft/icq/PicqBotX.html
+++ b/docs/cc/moecraft/icq/PicqBotX.html
@@ -18,7 +18,7 @@
catch(err) {
}
//-->
-var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10};
+var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10};
var tabs = {65535:["t0","所有方法"],2:["t2","实例方法"],8:["t4","具体方法"]};
var altColor = "altColor";
var rowColor = "rowColor";
@@ -169,7 +169,7 @@ 方法概要
方法和说明 |
-void |
+boolean |
addAccount(java.lang.String name,
java.lang.String postUrl,
int postPort)
@@ -177,31 +177,46 @@ 方法概要
|
+boolean |
+addAccount(java.lang.String name,
+ java.lang.String postUrl,
+ int postPort,
+ java.util.function.Consumer<cn.hutool.http.HttpException> errorHandler)
+添加机器人账号
+ |
+
+
void |
enableCommandManager(java.lang.String... prefixes)
初始化指令管理器
|
-
+
+java.lang.String |
+printDebugSupportInfo()
+获取Debug信息w
+ |
+
+
void |
setUniversalHyExpSupport(boolean value)
设置是否替换HyExp表达式
|
-
+
void |
setUniversalHyExpSupport(boolean value,
boolean safeMode)
设置是否替换HyExp表达式
|
-
+
void |
startBot()
启动机器人
|
-
+
boolean |
verifyHttpPluginVersion()
验证HTTP插件版本
@@ -287,15 +302,39 @@ 方法详细资料
-
addAccount
-public void addAccount(java.lang.String name,
- java.lang.String postUrl,
- int postPort)
+public boolean addAccount(java.lang.String name,
+ java.lang.String postUrl,
+ int postPort)
添加机器人账号
- 参数:
name - 名字
postUrl - 发送URL (Eg. 127.0.0.1)
postPort - 发送端口 (Eg. 31091)
+- 返回:
+- 是否成功添加
+
+
+
+
+
+
+
+-
+
addAccount
+public boolean addAccount(java.lang.String name,
+ java.lang.String postUrl,
+ int postPort,
+ java.util.function.Consumer<cn.hutool.http.HttpException> errorHandler)
+添加机器人账号
+
+- 参数:
+name - 名字
+postUrl - 发送URL(Eg. 127.0.0.1)
+postPort - 发送端口(Eg. 31091)
+errorHandler - 错误处理(HttpException)
+- 返回:
+- 是否成功添加
@@ -354,7 +393,7 @@ setUniversalHyExpSupport
-
diff --git a/docs/cc/moecraft/icq/event/events/request/EventFriendRequest.html b/docs/cc/moecraft/icq/event/events/request/EventFriendRequest.html
index 731ddd3b..a6afee8b 100644
--- a/docs/cc/moecraft/icq/event/events/request/EventFriendRequest.html
+++ b/docs/cc/moecraft/icq/event/events/request/EventFriendRequest.html
@@ -18,7 +18,7 @@
catch(err) {
}
//-->
-var methods = {"i0":10,"i1":10};
+var methods = {"i0":10,"i1":10,"i2":10};
var tabs = {65535:["t0","所有方法"],2:["t2","实例方法"],8:["t4","具体方法"]};
var altColor = "altColor";
var rowColor = "rowColor";
@@ -194,6 +194,10 @@ 方法概要
|
void |
+reject() |
+
+
+void |
reject(java.lang.String reason)
拒绝申请
|
@@ -259,6 +263,15 @@ accept
+
+
+
+
+-
+
reject
+public void reject()
+
+
diff --git a/docs/cc/moecraft/icq/sender/IcqHttpApi.html b/docs/cc/moecraft/icq/sender/IcqHttpApi.html
index 7e60fa8d..1639b149 100644
--- a/docs/cc/moecraft/icq/sender/IcqHttpApi.html
+++ b/docs/cc/moecraft/icq/sender/IcqHttpApi.html
@@ -18,7 +18,7 @@
catch(err) {
}
//-->
-var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":10,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":10,"i50":10,"i51":10,"i52":10,"i53":10,"i54":10,"i55":10,"i56":10,"i57":10,"i58":10,"i59":10,"i60":10,"i61":10,"i62":10,"i63":10,"i64":10};
+var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":10,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":10,"i50":10,"i51":10,"i52":10,"i53":10,"i54":10,"i55":10,"i56":10,"i57":10,"i58":10,"i59":10,"i60":10,"i61":10,"i62":10,"i63":10,"i64":10,"i65":10};
var tabs = {65535:["t0","所有方法"],2:["t2","实例方法"],8:["t4","具体方法"]};
var altColor = "altColor";
var rowColor = "rowColor";
@@ -228,43 +228,49 @@ 方法概要
+ReturnData<RCookies> |
+getCookies(java.lang.String domain)
+抢走酷Q的曲奇饼w
+ |
+
+
ReturnData<RCredentials> |
getCredentials()
抢走酷Q的曲奇饼并获取CSRF Token
|
-
+
ReturnData<RCsrfToken> |
getCsrfToken()
获取CSRF Token
|
-
+
ReturnListData<RFriendList> |
getFriendList()
获取好友列表
|
-
+
ReturnData<RGroupDetail> |
getGroupInfo(long groupId)
获取群信息
|
-
+
ReturnListData<RGroup> |
getGroupList()
获取群列表
|
-
+
ReturnData<RGroupMemberInfo> |
getGroupMemberInfo(long groupId,
long qq)
获取群成员信息, 默认不使用缓存
|
-
+
ReturnData<RGroupMemberInfo> |
getGroupMemberInfo(long groupId,
long qq,
@@ -272,37 +278,37 @@ 方法概要
获取群成员信息
|
-
+
ReturnListData<RGroupMemberInfo> |
getGroupMemberList(long groupId)
获取群成员列表
|
-
+
ReturnListData<RGroupNotice> |
getGroupNotices(long groupId)
获取一个群的所有公告
|
-
+
ReturnData<RFile> |
getImage(java.lang.String file)
获取图片文件完整路径
|
-
+
java.io.File |
getImageFile(java.lang.String file)
获取图片文件 (封装)
|
-
+
ReturnData<RLoginInfo> |
getLoginInfo()
获取登录号信息
|
-
+
ReturnData<RFile> |
getRecord(java.lang.String file,
java.lang.String format,
@@ -310,44 +316,44 @@ 方法概要
获取语音文件
|
-
+
ReturnData<RStatus> |
getStatus()
获取插件运行状态
|
-
+
ReturnData<RStrangerInfo> |
getStrangerInfo(long qq)
获取陌生人信息, 默认不使用缓存
|
-
+
ReturnData<RStrangerInfo> |
getStrangerInfo(long qq,
boolean noCache)
获取陌生人信息
|
-
+
ReturnData<RVersionInfo> |
getVersionInfo()
获取酷 Q 及 HTTP API 插件的版本信息
|
-
+
ReturnData<RVipInfo> |
getVIPInfo(long qq)
获取用户VIP信息
|
-
+
java.lang.String |
makeUrl(HttpApiNode api)
生成URL
|
-
+
RawReturnData |
rejectGroupRequest(java.lang.String flag,
java.lang.String type,
@@ -355,7 +361,7 @@ 方法概要
拒绝加群请求/邀请
|
-
+
<T extends ReturnPojoBase> ReturnData<T> |
send(java.lang.Class<T> type,
HttpApiNode api,
@@ -363,21 +369,21 @@ 方法概要
发送请求 封装
|
-
+
com.google.gson.JsonElement |
send(HttpApiNode api,
java.util.Map<java.lang.String,java.lang.Object> params)
发送请求
|
-
+
com.google.gson.JsonElement |
send(HttpApiNode api,
java.lang.Object... params)
发送请求 封装
|
-
+
<T extends ReturnPojoBase> ReturnData<T> |
send(java.lang.reflect.Type type,
HttpApiNode api,
@@ -385,14 +391,14 @@ 方法概要
发送请求 封装
|
-
+
ReturnData<RMessageReturnData> |
sendDiscussMsg(long groupId,
java.lang.String message)
发送讨论组消息
|
-
+
ReturnData<RMessageReturnData> |
sendDiscussMsg(long groupId,
java.lang.String message,
@@ -400,14 +406,14 @@ 方法概要
发送讨论组消息
|
-
+
ReturnData<RMessageReturnData> |
sendGroupMsg(long groupId,
java.lang.String message)
发送群聊消息
|
-
+
ReturnData<RMessageReturnData> |
sendGroupMsg(long groupId,
java.lang.String message,
@@ -415,7 +421,7 @@ 方法概要
发送群聊消息
|
-
+
RawReturnData |
sendGroupNotice(long groupId,
java.lang.String title,
@@ -423,21 +429,21 @@ 方法概要
发布群公告
|
-
+
RawReturnData |
sendLike(long qq,
long times)
发送好友赞
|
-
+
ReturnData<RMessageReturnData> |
sendPrivateMsg(long qq,
java.lang.String message)
发送私聊消息
|
-
+
ReturnData<RMessageReturnData> |
sendPrivateMsg(long qq,
java.lang.String message,
@@ -445,7 +451,7 @@ 方法概要
发送私聊消息
|
-
+
<T extends ReturnPojoBase> ReturnListData<T> |
sendReturnList(java.lang.Class<T> type,
HttpApiNode api,
@@ -453,7 +459,7 @@ 方法概要
发送请求 封装
|
-
+
<T extends ReturnPojoBase> ReturnListData<T> |
sendReturnList(java.lang.reflect.Type type,
HttpApiNode api,
@@ -461,34 +467,34 @@ 方法概要
发送请求 封装
|
-
+
RawReturnData |
sendReturnRaw(HttpApiNode api,
java.util.Map<java.lang.String,java.lang.Object> params)
发送请求 封装
|
-
+
RawReturnData |
sendReturnRaw(HttpApiNode api,
java.lang.Object... params)
发送请求 封装
|
-
+
RawReturnData |
setDiscussLeave(long discussId)
退出讨论组
|
-
+
RawReturnData |
setFriendAndRequest(java.lang.String flag,
boolean approve)
处理加好友请求
|
-
+
RawReturnData |
setFriendAndRequest(java.lang.String flag,
boolean approve,
@@ -496,7 +502,7 @@ 方法概要
处理加好友请求
|
-
+
RawReturnData |
setGroupAdmin(long groupId,
long qq,
@@ -504,7 +510,7 @@ 方法概要
群组设置管理员
|
-
+
RawReturnData |
setGroupAndRequest(java.lang.String flag,
java.lang.String type,
@@ -513,14 +519,14 @@ 方法概要
处理加群请求/邀请
|
-
+
RawReturnData |
setGroupAnonymous(long groupId,
boolean enable)
群组设置匿名
|
-
+
RawReturnData |
setGroupAnonymousBan(EventGroupMessage.Anonymous anonymous,
long groupId,
@@ -528,7 +534,7 @@ 方法概要
群组匿名用户禁言
|
-
+
RawReturnData |
setGroupAnonymousBan(java.lang.String flag,
long groupId,
@@ -536,7 +542,7 @@ 方法概要
群组匿名用户禁言
|
-
+
RawReturnData |
setGroupBan(long groupId,
long qq,
@@ -544,7 +550,7 @@ 方法概要
群组单人禁言
|
-
+
RawReturnData |
setGroupCard(long groupId,
long qq,
@@ -552,14 +558,14 @@ 方法概要
设置群名片 (群备注)
|
-
+
RawReturnData |
setGroupKick(long groupId,
long qq)
群组踢人
|
-
+
RawReturnData |
setGroupKick(long groupId,
long qq,
@@ -567,20 +573,20 @@ 方法概要
群组踢人
|
-
+
RawReturnData |
setGroupLeave(long groupId)
退出群组
|
-
+
RawReturnData |
setGroupLeave(long groupId,
boolean dismiss)
退出群组
|
-
+
RawReturnData |
setGroupSpecialTitle(long groupId,
long qq,
@@ -588,7 +594,7 @@ 方法概要
设置群组专属头衔
|
-
+
RawReturnData |
setGroupSpecialTitle(long groupId,
long qq,
@@ -597,32 +603,32 @@ 方法概要
设置群组专属头衔
|
-
+
RawReturnData |
setGroupWholeBan(long groupId,
boolean enable)
群组全员禁言
|
-
+
RawReturnData |
setRestartPlugin()
重启 HTTP API 插件
|
-
+
RawReturnData |
setRestartPlugin(int delay)
重启 HTTP API 插件
|
-
+
RawReturnData |
setRestartUnsafe()
重启酷Q, 并以当前登录号自动登陆 (需要勾选快速登录)
|
-
+
RawReturnData |
setRestartUnsafe(boolean cleanLog,
boolean cleanCache,
@@ -1804,6 +1810,22 @@ getCookies
+
+
+
+
diff --git a/docs/cc/moecraft/icq/utils/MiscUtils.html b/docs/cc/moecraft/icq/utils/MiscUtils.html
index 53b36b21..7422fb6d 100644
--- a/docs/cc/moecraft/icq/utils/MiscUtils.html
+++ b/docs/cc/moecraft/icq/utils/MiscUtils.html
@@ -74,13 +74,13 @@
@@ -125,6 +125,25 @@ 类 MiscUtils
-
+
+
+-
+
+
+
字段概要
+
+字段
+
+限定符和类型 |
+字段和说明 |
+
+
+static boolean |
+disabled |
+
+
+
+
|
VERSION |
-"4.10.1.928" |
+"4.11.0.971" |
diff --git a/docs/index-files/index-1.html b/docs/index-files/index-1.html
index ada3076b..17ca9f7f 100644
--- a/docs/index-files/index-1.html
+++ b/docs/index-files/index-1.html
@@ -111,6 +111,10 @@ A
添加机器人账号
+addAccount(String, String, int, Consumer<HttpException>) - 类 中的方法cc.moecraft.icq.PicqBotX
+
+添加机器人账号
+
Admin() - 类 的构造器cc.moecraft.icq.sender.returndata.returnpojo.get.RGroupDetail.Admin
alias - 类 中的变量cc.moecraft.icq.command.CommandProperties
diff --git a/docs/index-files/index-15.html b/docs/index-files/index-15.html
index c32bbaa8..e4cbadb4 100644
--- a/docs/index-files/index-15.html
+++ b/docs/index-files/index-15.html
@@ -121,6 +121,10 @@ P
postType - 类 中的变量cc.moecraft.icq.event.Event
+printDebugSupportInfo() - 类 中的方法cc.moecraft.icq.PicqBotX
+
+获取Debug信息w
+
printStackTrace() - 异常错误 中的方法cc.moecraft.icq.exceptions.HttpServerException
PrivateCommand - cc.moecraft.icq.command.interfaces中的接口
diff --git a/docs/index-files/index-16.html b/docs/index-files/index-16.html
index 37ddf5f3..058540c0 100644
--- a/docs/index-files/index-16.html
+++ b/docs/index-files/index-16.html
@@ -156,6 +156,8 @@ R
注册很多个事件监听器
+reject() - 类 中的方法cc.moecraft.icq.event.events.request.EventFriendRequest
+
reject(String) - 类 中的方法cc.moecraft.icq.event.events.request.EventFriendRequest
reject(String) - 类 中的方法cc.moecraft.icq.event.events.request.EventGroupAddRequest
diff --git a/docs/index-files/index-4.html b/docs/index-files/index-4.html
index f6520b6e..5d9eb1dd 100644
--- a/docs/index-files/index-4.html
+++ b/docs/index-files/index-4.html
@@ -87,6 +87,8 @@ D
撤回消息
+disabled - 类 中的静态变量cc.moecraft.icq.utils.MiscUtils
+
DiscussCommand - cc.moecraft.icq.command.interfaces中的接口
讨论组指令
diff --git a/docs/index-files/index-7.html b/docs/index-files/index-7.html
index 28a8e6fa..21c7f59d 100644
--- a/docs/index-files/index-7.html
+++ b/docs/index-files/index-7.html
@@ -101,6 +101,10 @@ G
抢走酷Q的曲奇饼w
+getCookies(String) - 类 中的方法cc.moecraft.icq.sender.IcqHttpApi
+
+抢走酷Q的曲奇饼w
+
getCredentials() - 类 中的方法cc.moecraft.icq.sender.IcqHttpApi
抢走酷Q的曲奇饼并获取CSRF Token
diff --git a/docs/overview-tree.html b/docs/overview-tree.html
index 84938846..56eba889 100644
--- a/docs/overview-tree.html
+++ b/docs/overview-tree.html
@@ -305,9 +305,9 @@ 枚举分层结构
- java.lang.Enum<E> (implements java.lang.Comparable<T>, java.io.Serializable)
diff --git a/pom.xml b/pom.xml
index 8c9db356..280837d5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
cc.moecraft
PicqBotX
- 4.10.1.928
+ 4.11.0.971
1.8
@@ -68,4 +68,4 @@
test
-
\ No newline at end of file
+
diff --git a/src/main/java/cc/moecraft/icq/PicqBotX.java b/src/main/java/cc/moecraft/icq/PicqBotX.java
index 1f9422cd..43aa6a38 100644
--- a/src/main/java/cc/moecraft/icq/PicqBotX.java
+++ b/src/main/java/cc/moecraft/icq/PicqBotX.java
@@ -9,10 +9,12 @@
import cc.moecraft.icq.exceptions.VerifyFailedException;
import cc.moecraft.icq.listeners.HyExpressionListener;
import cc.moecraft.icq.receiver.PicqHttpServer;
+import cc.moecraft.icq.sender.message.MessageBuilder;
import cc.moecraft.icq.sender.returndata.returnpojo.get.RVersionInfo;
import cc.moecraft.icq.user.GroupManager;
import cc.moecraft.icq.user.GroupUserManager;
import cc.moecraft.icq.user.UserManager;
+import cc.moecraft.icq.utils.MiscUtils;
import cc.moecraft.logger.HyLogger;
import cc.moecraft.logger.LoggerInstanceManager;
import cc.moecraft.logger.environments.ConsoleColoredEnv;
@@ -20,6 +22,8 @@
import cc.moecraft.logger.format.AnsiColor;
import cc.moecraft.utils.HyExpressionResolver;
import cn.hutool.http.HttpException;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import lombok.Getter;
import java.util.function.Consumer;
@@ -139,6 +143,9 @@ public PicqBotX(int socketPort)
*/
private void init()
{
+ // 设置是否输出 Init 消息
+ MiscUtils.disabled = !config.isLogInit();
+
// 日志管理器
loggerInstanceManager = new LoggerInstanceManager();
loggerInstanceManager.addEnvironment(new ConsoleColoredEnv(config.getColorSupportLevel()));
@@ -150,43 +157,31 @@ private void init()
// 日志对象
logger = loggerInstanceManager.getLoggerInstance("PicqBotX", config.isDebug());
logger.timing.init();
- if(config.isLogInit()){
- logResource(logger, config.getColorSupportLevel() == null ? "splash" : "splash-precolored", "version", VERSION);
- logInitDone(logger, "日志管理器 ", 0, 6);
- }
+ logResource(logger, config.getColorSupportLevel() == null ? "splash" : "splash-precolored", "version", VERSION);
+ logInitDone(logger, "日志管理器 ", 0, 6);
// 用户和群缓存管理器
userManager = new UserManager(this);
groupUserManager = new GroupUserManager(this);
groupManager = new GroupManager(this);
- if(config.isLogInit()){
- logInitDone(logger, "缓存管理器 ", 1, 5);
- }
+ logInitDone(logger, "缓存管理器 ", 1, 5);
// Debug设置没啦w
- if(config.isLogInit()){
- logInitDone(logger, "DEBUG设置 ", 2, 4);
- }
+ logInitDone(logger, "DEBUG设置 ", 2, 4);
// 事件管理器
eventManager = new EventManager(this);
eventManager.registerListener(new HyExpressionListener());
- if(config.isLogInit()){
- logInitDone(logger, "事件管理器 ", 3, 3);
- }
+ logInitDone(logger, "事件管理器 ", 3, 3);
// 账号管理器
accountManager = new AccountManager();
eventManager.registerListener(new AccountManagerListener(accountManager));
- if(config.isLogInit()){
- logInitDone(logger, "账号管理器 ", 4, 2);
- }
+ logInitDone(logger, "账号管理器 ", 4, 2);
// HTTP监听服务器
httpServer = new PicqHttpServer(config.getSocketPort(), this);
- if(config.isLogInit()){
- logInitDone(logger, "HTTP监听服务器 ", 5, 1);
- }
+ logInitDone(logger, "HTTP监听服务器 ", 5, 1);
logger.timing.clear();
}
@@ -201,29 +196,34 @@ private void init()
*/
public boolean addAccount(String name, String postUrl, int postPort)
{
- return addAccount(name, postUrl, postPort, (ex)->{
- logger.error("HTTP发送错误: " + ex.getLocalizedMessage());
- logger.error("- 检查一下是不是忘记开酷Q了, 或者写错地址了");
+ return addAccount(name, postUrl, postPort, (ex)->
+ {
+ logger.error("HTTP发送错误: " + ex.getLocalizedMessage());
+ logger.error("- 检查一下是不是忘记开酷Q了, 或者写错地址了");
});
}
- /**
- * 添加机器人账号
- *
- * @param name 名字
- * @param postUrl 发送URL(Eg. 127.0.0.1)
- * @param postPort 发送端口(Eg. 31091)
- * @param errorHandler 错误处理(HttpException)
- * @return 是否成功添加
- */
- public boolean addAccount(String name, String postUrl, int postPort, Consumer errorHandler) {
- try {
- this.accountManager.addAccount(new BotAccount(name, this, postUrl, postPort));
- return true;
- } catch (HttpException ex) {
- errorHandler.accept(ex);
- return false;
- }
+ /**
+ * 添加机器人账号
+ *
+ * @param name 名字
+ * @param postUrl 发送URL(Eg. 127.0.0.1)
+ * @param postPort 发送端口(Eg. 31091)
+ * @param errorHandler 错误处理(HttpException)
+ * @return 是否成功添加
+ */
+ public boolean addAccount(String name, String postUrl, int postPort, Consumer errorHandler)
+ {
+ try
+ {
+ this.accountManager.addAccount(new BotAccount(name, this, postUrl, postPort));
+ return true;
+ }
+ catch (HttpException ex)
+ {
+ errorHandler.accept(ex);
+ return false;
+ }
}
/**
@@ -252,9 +252,7 @@ public void enableCommandManager(String... prefixes)
commandManager = new CommandManager(this, prefixes);
eventManager.registerListener(new CommandListener(commandManager));
- if(config.isLogInit()){
- logInitDone(logger, "指令管理器 ", 6, 0);
- }
+ logInitDone(logger, "指令管理器 ", 6, 0);
logger.timing.clear();
}
@@ -291,7 +289,7 @@ public boolean verifyHttpPluginVersion()
if (!versionInfo.getCoolqEdition().equalsIgnoreCase("pro"))
{
if(config.isLogInit()){
- logger.warning(prefix + "版本正确, 不过用酷Q Pro的话效果更好哦!");
+ logger.warning(prefix + "版本正确, 不过用酷Q Pro的话效果更好哦!");
}
}
}
@@ -313,8 +311,9 @@ public boolean verifyHttpPluginVersion()
return false;
}
- if(config.isLogInit()){
- logger.log(AnsiColor.YELLOW + prefix + AnsiColor.GREEN + " 版本验证完成!");
+ if(config.isLogInit())
+ {
+ logger.log(AnsiColor.YELLOW + prefix + AnsiColor.GREEN + " 版本验证完成!");
}
}
return true;
@@ -340,4 +339,22 @@ public void setUniversalHyExpSupport(boolean value, boolean safeMode)
{
hyExpressionResolver = value ? new HyExpressionResolver(safeMode) : null;
}
+
+ /**
+ * 获取Debug信息w
+ *
+ * @return Debug 信息
+ */
+ public String printDebugSupportInfo()
+ {
+ Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+ MessageBuilder builder = new MessageBuilder()
+ .add("===== 配置 =====").newLine()
+ .add(gson.toJson(config)).newLine()
+ .add("===== 账号 =====").newLine()
+ .add(gson.toJson(accountManager.getAccounts()));
+
+ return builder.toString();
+ }
}
diff --git a/src/main/java/cc/moecraft/icq/PicqConfig.java b/src/main/java/cc/moecraft/icq/PicqConfig.java
index 78ddbfa5..50fdfba8 100644
--- a/src/main/java/cc/moecraft/icq/PicqConfig.java
+++ b/src/main/java/cc/moecraft/icq/PicqConfig.java
@@ -28,7 +28,7 @@
public class PicqConfig
{
/** 接收端口 */
- private final int socketPort;
+ private final transient int socketPort;
/** 是否输出Debug消息 */
private boolean debug = false;
@@ -58,10 +58,10 @@ public class PicqConfig
private boolean httpPaused = false;
/** X-Signature SHA1 验证秘钥 (设置为空就是不用秘钥w) */
- private String secret = "";
+ private transient String secret = "";
/** Access Token 访问令牌 (设置为空就是不用令牌) */
- private String accessToken = "";
+ private transient String accessToken = "";
/** 是否启用限速调用API (需要enable_rate_limited_actions=true) */
private boolean apiRateLimited = false;
@@ -84,7 +84,7 @@ public class PicqConfig
/** Logger日志文件名 */
private String logFileName = "PicqBotX-Log";
- // Taskeren 配置项
+ /** 是否输出 Init 日志 */
private boolean logInit = true;
// 方法 | Methods
diff --git a/src/main/java/cc/moecraft/icq/PicqConstants.java b/src/main/java/cc/moecraft/icq/PicqConstants.java
index a2e0370a..a6f1fa60 100644
--- a/src/main/java/cc/moecraft/icq/PicqConstants.java
+++ b/src/main/java/cc/moecraft/icq/PicqConstants.java
@@ -18,7 +18,7 @@ public class PicqConstants
// 版本常量 | Version constant
/** 当前版本 */
- public static final String VERSION = "4.10.1.928";
+ public static final String VERSION = "4.11.0.971";
/** 兼容版本检测Regex */
public static String HTTP_API_VERSION_DETECTION = ".*4.10.*";
diff --git a/src/main/java/cc/moecraft/icq/command/CommandManager.java b/src/main/java/cc/moecraft/icq/command/CommandManager.java
index 45996ed6..a215ff4b 100644
--- a/src/main/java/cc/moecraft/icq/command/CommandManager.java
+++ b/src/main/java/cc/moecraft/icq/command/CommandManager.java
@@ -152,7 +152,10 @@ else if (isPM && runner instanceof PrivateCommand)
public ArrayList getCommandList()
{
ArrayList result = new ArrayList<>();
- commands.forEach((k, v) -> result.add(v));
+ commands.forEach((k, v) ->
+ {
+ if (!result.contains(v)) result.add(v);
+ });
return result;
}
@@ -163,8 +166,6 @@ public ArrayList getCommandList()
*/
public ArrayList getCommandNameList()
{
- ArrayList result = new ArrayList<>();
- getCommandList().forEach(command -> result.add(command.properties().getName()));
- return result;
+ return new ArrayList<>(commands.keySet());
}
}
diff --git a/src/main/java/cc/moecraft/icq/sender/IcqHttpApi.java b/src/main/java/cc/moecraft/icq/sender/IcqHttpApi.java
index 5409c478..cb506d8c 100644
--- a/src/main/java/cc/moecraft/icq/sender/IcqHttpApi.java
+++ b/src/main/java/cc/moecraft/icq/sender/IcqHttpApi.java
@@ -865,6 +865,17 @@ public ReturnData getCookies()
return send(RCookies.class, GET_COOKIES);
}
+ /**
+ * 抢走酷Q的曲奇饼w
+ *
+ * @param domain 需要抢走曲奇的域名w
+ * @return Cookies
+ */
+ public ReturnData getCookies(String domain)
+ {
+ return send(RCookies.class, GET_COOKIES, "domain", domain);
+ }
+
/**
* 获取CSRF Token
*
diff --git a/src/main/java/cc/moecraft/icq/utils/MiscUtils.java b/src/main/java/cc/moecraft/icq/utils/MiscUtils.java
index 0be89a34..d32b51e2 100644
--- a/src/main/java/cc/moecraft/icq/utils/MiscUtils.java
+++ b/src/main/java/cc/moecraft/icq/utils/MiscUtils.java
@@ -5,6 +5,7 @@
import static cc.moecraft.logger.format.AnsiColor.*;
import static cc.moecraft.logger.format.AnsiFormat.replaceAllFormatWithANSI;
+import static cc.moecraft.utils.StringUtils.repeat;
/**
* The class {@code MiscUtils} is an utilities class for random things.
@@ -18,6 +19,8 @@
*/
public class MiscUtils
{
+ public static boolean disabled = false;
+
/**
* 输出一行"初始化完成"的日志
*
@@ -28,21 +31,14 @@ public class MiscUtils
*/
public static void logInitDone(HyLogger logger, String name, int greens, int reds)
{
- StringBuilder greenStars = new StringBuilder();
- StringBuilder redStars = new StringBuilder();
-
- for (int i = 0; i < greens; i++)
- {
- greenStars.append("*");
- }
- for (int i = 0; i < reds; i++)
- {
- redStars.append("*");
- }
+ if (disabled) return;
+
+ String green = repeat("*", greens);
+ String red = repeat("*", reds);
logger.log(String.format("%s%s%s初始化完成%s [%s%s%s%s%s] ...(%s ms)",
YELLOW, name, GREEN, YELLOW,
- GREEN, greenStars.toString(), RED, redStars.toString(), YELLOW,
+ GREEN, green, RED, red, YELLOW,
Math.round(logger.timing.getMilliseconds() * 100d) / 100d));
logger.timing.reset();
@@ -57,6 +53,8 @@ public static void logInitDone(HyLogger logger, String name, int greens, int red
*/
public static void logResource(HyLogger logger, String name, Object... vars)
{
+ if (disabled) return;
+
ResourceUtils.printResource(MiscUtils.class.getClassLoader(),
s -> logger.log(replaceAllFormatWithANSI(s)), name, vars);
}
diff --git a/src/main/java/taskeren/extrabot/components/Component.java b/src/main/java/taskeren/extrabot/components/Component.java
new file mode 100644
index 00000000..9b74bb4d
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/Component.java
@@ -0,0 +1,172 @@
+package taskeren.extrabot.components;
+
+import lombok.ToString;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 消息组件根,用于处理消息组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+public class Component {
+
+ private static final String REGEX_CQ_CODE = "(\\[CQ:.*?,.*?])";
+ private static final Pattern CQC = Pattern.compile(REGEX_CQ_CODE);
+
+ /**
+ * 返回解析后的组件,任何错误的数据将使用默认值,基础数据为{@code -1},其他为{@code null}。
+ *
+ * @param message 消息原文
+ * @return 解析后的组件
+ */
+ public static Component parseComponent(String message) {
+ String s0 = message.substring(1, message.length() - 1); // 去掉头尾的"[]"
+ String[] s1 = s0.split(","); // 处理成数据对,像这样:["CQ:at", "qq=123456"]
+ HashMap map = genDataMap(s1); // 处理成Map
+ ParserMap data = new ParserMap(map);
+ String type = data.get("CQ"); // 获取CQ码类型
+ try {
+ switch (type) {
+
+ case "face":
+ return new ComponentFace(data.getInteger("id"));
+
+ case "bface":
+ return new ComponentBFace(data.getInteger("p"), data.get("id"));
+
+ case "image":
+ return new ComponentImage(data.get("file"), data.get("url"));
+
+ case "record":
+ return new ComponentRecord(data.get("file"), data.getBoolean("magic"));
+
+ case "at":
+ return new ComponentAt(data.getLong("qq"));
+
+ case "rps":
+ return new ComponentRPS(ComponentRPS.RPS.parse(data.getInteger("type")));
+
+ case "dice":
+ return new ComponentDice(data.getInteger("type"));
+
+ case "shake":
+ return new ComponentShake();
+
+ case "sign":
+ return new ComponentSign(data.get("location"), data.get("title"), data.get("image"));
+
+ case "rich":
+ return new ComponentRich(data.get("title"), data.get("text"), data.get("content"));
+
+ case "location":
+ return new ComponentLocation(data.get("lat"), data.get("lon"), data.get("title"), data.get("content"),
+ data.getInteger("style"));
+
+ case "contact":
+ return new ComponentContact(data.getLong("id"), ComponentContact.ContactTo.parse(data.get("type")));
+
+ default:
+ return new ComponentString(message);
+ }
+ } catch (Exception e) {
+ return new ComponentString(message);
+ }
+ }
+
+ /**
+ * 返回解析后的组件列表。解析方法:{@link #parseComponent(String)}。
+ *
+ * @param s 消息
+ * @return 解析后组件列表
+ */
+ public static ArrayList parseComponents(String s) {
+ ArrayList components = new ArrayList<>();
+ int count = 0;
+
+ Matcher matcher = CQC.matcher(s);
+ int end = 0;
+ while (matcher.find()) {
+ // string before cq code
+ if (matcher.start() > end) {
+ String strBefore = s.substring(end, matcher.start());
+ components.add(new ComponentString(strBefore));
+ }
+ String content = matcher.group();
+ Component component = parseComponent(content);
+ components.add(component);
+ end = matcher.end();
+ count++;
+ }
+ // string after last cq code
+ if (end < s.length()) {
+ String strAfter = s.substring(end);
+ components.add(new ComponentString(strAfter));
+ count++;
+ }
+ if (count == 0) {
+ components.add(new ComponentString(s));
+ }
+ return components;
+ }
+
+ /**
+ * 返回解析后的组件列表。解析方法:{@link #parseComponent(String)}。
+ *
+ * @param args 消息列表
+ * @return 解析后组件列表
+ */
+ public static ArrayList parseComponents(ArrayList args) {
+ ArrayList components = new ArrayList<>();
+
+ for (String arg : args) {
+ components.addAll(parseComponents(arg));
+ }
+
+ return components;
+ }
+
+ private static HashMap genDataMap(String[] array) {
+ HashMap map = new HashMap<>();
+
+ for (String s : array) {
+ String[] s0 = s.split("[:=]", 2);
+ if (s0.length < 2) continue;
+ map.put(s0[0], s0[1]);
+ }
+
+ return map;
+ }
+
+ public static class ParserMap {
+
+ final Map data;
+
+ public ParserMap(Map data) {
+ this.data = data;
+ }
+
+ public String get(String key){
+ return data.getOrDefault(key, "");
+ }
+
+ public int getInteger(String key){
+ return Integer.parseInt(data.getOrDefault(key, "-1"));
+ }
+
+ public long getLong(String key){
+ return Long.parseLong(data.getOrDefault(key, "-1"));
+ }
+
+ public boolean getBoolean(String key){
+ return Boolean.parseBoolean(data.get(key));
+ }
+
+ }
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentAt.java b/src/main/java/taskeren/extrabot/components/ComponentAt.java
new file mode 100644
index 00000000..a9823405
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentAt.java
@@ -0,0 +1,22 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 群内AT组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentAt extends Component {
+
+ /**
+ * 被AT的QQ号
+ */
+ protected final long at;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentBFace.java b/src/main/java/taskeren/extrabot/components/ComponentBFace.java
new file mode 100644
index 00000000..ae718658
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentBFace.java
@@ -0,0 +1,20 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 原创表情组件,其中的参数尚未明白。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentBFace extends Component {
+
+ final int p;
+ final String id;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentContact.java b/src/main/java/taskeren/extrabot/components/ComponentContact.java
new file mode 100644
index 00000000..92a04022
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentContact.java
@@ -0,0 +1,41 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 名片组件,包括QQ用户名片和群名片。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentContact extends Component {
+
+ public enum ContactTo {
+ USER, GROUP;
+
+ public static ContactTo parse(String str){
+ switch(str) {
+ case "qq": return USER;
+ case "group": return GROUP;
+ default: return null;
+ }
+ }
+ }
+
+ /**
+ * 名片指向的QQ号或群号
+ */
+ final long id;
+
+ /**
+ * 名片类型(QQ用户或QQ群)
+ *
+ * @see ContactTo
+ */
+ final ContactTo to;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentDice.java b/src/main/java/taskeren/extrabot/components/ComponentDice.java
new file mode 100644
index 00000000..5ebad459
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentDice.java
@@ -0,0 +1,22 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 骰子组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentDice extends Component {
+
+ /**
+ * 投到的点数
+ */
+ final int type;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentFace.java b/src/main/java/taskeren/extrabot/components/ComponentFace.java
new file mode 100644
index 00000000..27792c91
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentFace.java
@@ -0,0 +1,22 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 自带表情组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentFace extends Component {
+
+ /**
+ * 表情ID
+ */
+ final int id;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentImage.java b/src/main/java/taskeren/extrabot/components/ComponentImage.java
new file mode 100644
index 00000000..2c828397
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentImage.java
@@ -0,0 +1,27 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 图片组件(包括自定义表情)。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentImage extends Component {
+
+ /**
+ * 图片暂存于腾讯服务器上的地址
+ */
+ final String url;
+
+ /**
+ * 图片下载到本地的地址
+ */
+ final String file;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentLocation.java b/src/main/java/taskeren/extrabot/components/ComponentLocation.java
new file mode 100644
index 00000000..e300c021
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentLocation.java
@@ -0,0 +1,42 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 位置组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentLocation extends Component {
+
+ /**
+ * 经度
+ */
+ final String lat;
+
+ /**
+ * 纬度
+ */
+ final String lon;
+
+ /**
+ * 粗略地名
+ */
+ final String title;
+
+ /**
+ * 详细地址
+ */
+ final String content;
+
+ /**
+ * 样式代码(未知)
+ */
+ final int style;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentRPS.java b/src/main/java/taskeren/extrabot/components/ComponentRPS.java
new file mode 100644
index 00000000..f6a111f5
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentRPS.java
@@ -0,0 +1,37 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 石头剪刀布组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentRPS extends Component {
+
+ public enum RPS {
+ ROCK, // 石头
+ PAPER, // 布
+ SCISSORS; // 剪刀
+
+ public static RPS parse(int type){
+ switch (type) {
+ case 1: return ROCK;
+ case 2: return SCISSORS;
+ case 3: return PAPER;
+ default: return null;
+ }
+ }
+ }
+
+ /**
+ * 石头剪刀布
+ */
+ final RPS type;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentRecord.java b/src/main/java/taskeren/extrabot/components/ComponentRecord.java
new file mode 100644
index 00000000..6def018f
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentRecord.java
@@ -0,0 +1,27 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 语音组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentRecord extends Component {
+
+ /**
+ * 语音储存在本地的位置
+ */
+ final String file;
+
+ /**
+ * 是否使用变声器
+ */
+ final boolean magic;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentRich.java b/src/main/java/taskeren/extrabot/components/ComponentRich.java
new file mode 100644
index 00000000..2cdc3940
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentRich.java
@@ -0,0 +1,23 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 这是一个神奇的组件,富文本组件。
+ * 他包含了很多功能,包括网易云音乐、QQ音乐、Bilibili的分享,
+ * 还有其他群投票等群功能,都使用的是富文本组件,请自行选用。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentRich extends Component {
+
+ final String title;
+ final String text;
+ final String content;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentShake.java b/src/main/java/taskeren/extrabot/components/ComponentShake.java
new file mode 100644
index 00000000..4b41e3a7
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentShake.java
@@ -0,0 +1,16 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 戳一戳组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentShake extends Component {
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentSign.java b/src/main/java/taskeren/extrabot/components/ComponentSign.java
new file mode 100644
index 00000000..c5540ff4
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentSign.java
@@ -0,0 +1,32 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 签到组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentSign extends Component {
+
+ /**
+ * 签到地点
+ */
+ final String location;
+
+ /**
+ * 签到内容
+ */
+ final String title;
+
+ /**
+ * 签到图片
+ */
+ final String image;
+
+}
diff --git a/src/main/java/taskeren/extrabot/components/ComponentString.java b/src/main/java/taskeren/extrabot/components/ComponentString.java
new file mode 100644
index 00000000..46d92dae
--- /dev/null
+++ b/src/main/java/taskeren/extrabot/components/ComponentString.java
@@ -0,0 +1,19 @@
+package taskeren.extrabot.components;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+
+/**
+ * 文本消息,不是组件。
+ *
+ * @author Taskeren
+ */
+@ToString
+@AllArgsConstructor
+@Getter
+public class ComponentString extends Component {
+
+ final String message;
+
+}
diff --git a/src/test/java/cc/moecraft/test/general/HttpApiTest.java b/src/test/java/cc/moecraft/test/general/HttpApiTest.java
index cadb3468..9cbd6e3b 100644
--- a/src/test/java/cc/moecraft/test/general/HttpApiTest.java
+++ b/src/test/java/cc/moecraft/test/general/HttpApiTest.java
@@ -29,6 +29,7 @@
* @author Vanilla (https://github.com/VergeDX)
* @since 2019-03-21 21:05
*/
+@Ignore
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class HttpApiTest
{
diff --git a/src/test/java/cc/moecraft/test/icq/features/minigames/guess/CommandGuess.java b/src/test/java/cc/moecraft/test/icq/features/minigames/guess/CommandGuess.java
new file mode 100644
index 00000000..0480ee36
--- /dev/null
+++ b/src/test/java/cc/moecraft/test/icq/features/minigames/guess/CommandGuess.java
@@ -0,0 +1,52 @@
+package cc.moecraft.test.icq.features.minigames.guess;
+
+import cc.moecraft.icq.command.CommandProperties;
+import cc.moecraft.icq.command.interfaces.EverywhereCommand;
+import cc.moecraft.icq.event.events.message.EventMessage;
+import cc.moecraft.icq.user.User;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * 猜数字游戏指令w
+ *
+ * Class created by the HyDEV Team on 2019-05-11!
+ *
+ * @author HyDEV Team (https://github.com/HyDevelop)
+ * @author Hykilpikonna (https://github.com/hykilpikonna)
+ * @author Vanilla (https://github.com/VergeDX)
+ * @since 2019-05-11 14:38
+ */
+public class CommandGuess implements EverywhereCommand
+{
+ @Getter
+ private Map sessions = new HashMap<>(); // 会话列表w
+
+ @Override
+ public String run(EventMessage event, User sender, String command, ArrayList args)
+ {
+ if (args.size() != 0)
+ {
+ return "猜数字直接输数字就可以了哦w";
+ }
+
+ // 创建会话
+ event.respond("[猜数字] 正在生成答案...");
+
+ // 放进会话列表里
+ sessions.put(sender.getId(), new GuessSession(sender.getId(), new Random().nextInt(100)));
+
+ // 游戏提示
+ return "请猜一个数字w (范围: [0,100])";
+ }
+
+ @Override
+ public CommandProperties properties()
+ {
+ return new CommandProperties("guess", "猜数字");
+ }
+}
diff --git a/src/test/java/cc/moecraft/test/icq/features/minigames/guess/GuessListener.java b/src/test/java/cc/moecraft/test/icq/features/minigames/guess/GuessListener.java
new file mode 100644
index 00000000..f540b75a
--- /dev/null
+++ b/src/test/java/cc/moecraft/test/icq/features/minigames/guess/GuessListener.java
@@ -0,0 +1,70 @@
+package cc.moecraft.test.icq.features.minigames.guess;
+
+import cc.moecraft.icq.event.EventHandler;
+import cc.moecraft.icq.event.IcqListener;
+import cc.moecraft.icq.event.events.message.EventMessage;
+import cc.moecraft.utils.StringUtils;
+import lombok.AllArgsConstructor;
+
+/**
+ * TODO: No description yet...
+ *
+ * Class created by the HyDEV Team on 2019-05-11!
+ *
+ * @author HyDEV Team (https://github.com/HyDevelop)
+ * @author Hykilpikonna (https://github.com/hykilpikonna)
+ * @author Vanilla (https://github.com/VergeDX)
+ * @since 2019-05-11 15:00
+ */
+@AllArgsConstructor
+public class GuessListener extends IcqListener
+{
+ private final CommandGuess guess;
+
+ @EventHandler
+ public void onMessage(EventMessage event)
+ {
+ // TODO: 忽略指令
+
+ // 忽略不是数字的输入
+ if (!StringUtils.isNumeric(event.getMessage()))
+ {
+ return;
+ }
+
+ // 忽略没有会话的情况
+ if (!guess.getSessions().containsKey(event.getSenderId()))
+ {
+ return;
+ }
+
+ // 用户会话已经在列表里面了
+ GuessSession session = guess.getSessions().get(event.getSenderId());
+
+ // 如果不在有效时间内, 移除会话
+ if (!session.isValid())
+ {
+ guess.getSessions().remove(event.getSenderId());
+ return;
+ }
+
+ // 游戏逻辑
+ int num = Integer.parseInt(event.getMessage());
+
+ if (num > session.getGuessTarget())
+ {
+ event.respond("[猜数字] 太大了x 继续猜w");
+ }
+ else if (num < session.getGuessTarget())
+ {
+ event.respond("[猜数字] 太小了x 继续猜w");
+ }
+ else
+ {
+ event.respond("[猜数字] 正确w! 次数: " + session.getGuessCount());
+ guess.getSessions().remove(session.getId());
+ }
+
+ session.updateCount();
+ }
+}
diff --git a/src/test/java/cc/moecraft/test/icq/features/minigames/guess/GuessSession.java b/src/test/java/cc/moecraft/test/icq/features/minigames/guess/GuessSession.java
new file mode 100644
index 00000000..621183b9
--- /dev/null
+++ b/src/test/java/cc/moecraft/test/icq/features/minigames/guess/GuessSession.java
@@ -0,0 +1,45 @@
+package cc.moecraft.test.icq.features.minigames.guess;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * 猜数字游戏会话w
+ *
+ * Class created by the HyDEV Team on 2019-05-11!
+ *
+ * @author HyDEV Team (https://github.com/HyDevelop)
+ * @author Hykilpikonna (https://github.com/hykilpikonna)
+ * @author Vanilla (https://github.com/VergeDX)
+ * @since 2019-05-11 14:38
+ */
+@Data @AllArgsConstructor
+@RequiredArgsConstructor
+public class GuessSession
+{
+ private final long id; // 用户QQ号
+ private long timestamp = System.currentTimeMillis(); // 时间戳 (ms)
+
+ private final long guessTarget; // 猜数字的答案
+ private long guessCount; // 猜数字的尝试数
+
+ /**
+ * 判断是否在有效时间内
+ *
+ * @return 是否有效
+ */
+ public boolean isValid()
+ {
+ return System.currentTimeMillis() - timestamp < 5 * 60 * 1000;
+ }
+
+ /**
+ * +1 次猜测
+ */
+ public void updateCount()
+ {
+ timestamp = System.currentTimeMillis();
+ guessCount ++;
+ }
+}