我先放张效果图:
这张图中主要实现的功能就是消息同步,后来我又加了执行命令的功能,有兴趣的可以自己改改玩233
上图插件的介绍地址:http://mcbbs.net/thread-682777-1-1.html
项目开源地址:http://git.oschina.net/chenxuuu/Minecraft-QQGroupPlubin
gitosc的readme中我写了双方通讯的socket格式了,如下:
协议食用指南:
插件通过socket通讯,使用2333端口
客户端:minecraft插件实现
服务端:cq插件实现
===========================
通讯协议举例:
客户端与服务端每秒发送/接收一次数据
客户端→服务端(minecraft插件→cq插件)发送字符串举例:xxxxxxxx]][[ccccc]][[dawdasdasdasdasd]][[asadsdasdasd
分割符号为“]][[”(如果这一秒内有多条消息的话会这样)
服务端→客户端(cq插件→minecraft插件)发送字符串举例:|||||xxxxxxxx|||||command>ccccc|||||<player>dawdasdasdasdasd
分割符号为“|||||”(如果这一秒内有多条消息的话会这样),当分割开后,字符串中包含“<”符号的,将直接在服务器全局发送;字符串中包含“command>”符号且不包含“<”符号的,将作为命令发送到控制台,其他数据将舍弃(如xxxxxxxx那一个字符串)。
我就稍微再贴一下两边的核心代码吧。
java端:
java这个语言我是没接触过的,所以代码基本都是请教的Balrogs_xt大佬(博客地址:http://www.acgxt.com/),还有万能的百度
java端实现的功能是socket的客户端、并且作为minecraft插件输出和执行各种数据,代码不长,我就全部贴在这里了:
package com.sweetcreeper.qqplugin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
public class Qqplugin extends JavaPlugin implements Listener
{
public String player="none233";
public String msg="none233";
@Override//重写父类的方法
public void onEnable()
{
getLogger().info("QQGroupMessagePlugin is started successfully!");
//注册监听
Bukkit.getPluginManager().registerEvents(this,this);
new BukkitRunnable(){
int s = 0;//设置定10秒后执行某段代码
@Override
public void run(){
if(s>=60)
{
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "tm abc 发钱啦!");
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "eco give * 1");
s=0;
}
else
{
s++;
}
//s--;//迭代递减,我看官方的教程是没这个的,我没试过,你也可以删除试试
//if(s==0){
//这个写10秒后执行的代码(假如定义的定时器每次是1秒)
// cancel();//cancel用来取消定时器
//}else{
//这里可以写每次触发定时器执行的代码
try
{
//1.创建客户端Socket,指定服务器地址和端口
Socket socket=new Socket("localhost", 2333);
//2.获取输出流,向服务器端发送信息
OutputStream os=socket.getOutputStream();//字节输出流
PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流
if(player!="none233")
{
pw.write(msg);
player="none233";
}
else
{
pw.write("getmsg");
}
pw.flush();
socket.shutdownOutput();//关闭输出流
//3.获取输入流,并读取服务器端的响应信息
InputStream is=socket.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String info=null;
info=br.readLine();
String[] sourceStrArray=info.split("\\|\\|\\|\\|\\|");
for(int i=0;i<sourceStrArray.length;i++)
{
if(sourceStrArray[i].indexOf("<")!=-1)
{
Bukkit.broadcastMessage(sourceStrArray[i]);
}
else if(sourceStrArray[i].indexOf("command>")!=-1)
{
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), sourceStrArray[i].replace("command>", ""));
if(player!="none233")
{
msg+="]][[<提示>"+sourceStrArray[i].replace("command>", "")+"已执行";
}
else
{
player="ok";
msg="<提示>"+sourceStrArray[i].replace("command>", "")+"已执行";
}
}
}
//Bukkit.broadcastMessage("debug:"+info);
//4.关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
//e.printStackTrace();
} catch (IOException e) {
//e.printStackTrace();
}
//}
}
}.runTaskTimer(this, 0L, 20L);//参数是,主类、延迟、多少秒运行一次,比如5秒那就是5*20L
}
@Override
public void onDisable()
{
getLogger().info("QQGroupMessagePlugin is stoped successfully!");
}
@EventHandler
public void onPlayerSay(AsyncPlayerChatEvent event)
{
if(player!="none233")
{
msg+="]][[<"+event.getPlayer().getName()+">"+event.getMessage();
//player="ok";
}
else
{
player="ok";
msg="<"+event.getPlayer().getName()+">"+event.getMessage();
}
//Bukkit.broadcastMessage("player:"+event.getPlayer().getName()+",msg:"+event.getMessage());
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event)
{
if(player!="none233")
{
msg+="]][[<消息>"+event.getPlayer().getName()+"上线了";
}
else
{
player="ok";
msg="<消息>"+event.getPlayer().getName()+"上线了";
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event)
{
if(player!="none233")
{
msg+="]][[<消息>"+event.getPlayer().getName()+"掉线了";
}
else
{
player="ok";
msg="<消息>"+event.getPlayer().getName()+"掉线了";
}
}
}
基本的思路就是前面写的那个格式:“xxxxxxxx]][[ccccc]][[dawdasdasdasdasd]][[asadsdasdasd”
C#端:
c#端作为酷q插件,在socket通讯中作为服务端
我把网上找来的socket代码稍作修改:
/// <summary>
/// 监听客户端连接
/// </summary>
private static void ListenClientConnect()
{
while (true)
{
Socket clientSocket = serverSocket.Accept();
//clientSocket.Send(Encoding.ASCII.GetBytes("Server Say Hello\r\n"));
Socket myClientSocket = (Socket)clientSocket;
int receiveNumber;
receiveNumber = myClientSocket.Receive(result);
//Console.WriteLine("接收客户端 {0} 消息{1}", myClientSocket.RemoteEndPoint.ToString(), Encoding.UTF8.GetString(result, 0, receiveNumber));
string replay = Encoding.UTF8.GetString(result, 0, receiveNumber);
if (replay.IndexOf("<") != -1)
{
if (replay.IndexOf("]][[") != -1)
{
try
{
string[] str2;
str2 = replay.Split(new string[] { "]][[" }, StringSplitOptions.None);
foreach (string i in str2)
{
CQ.SendGroupMessage(GroupSet, i);
}
}
catch { }
}
else
{
CQ.SendGroupMessage(GroupSet, replay);
}
}
clientSocket.Send(Encoding.UTF8.GetBytes("ok233"));
clientSocket.Send(Encoding.UTF8.GetBytes(mcmsg));
mcmsg = "";
myClientSocket.Shutdown(SocketShutdown.Both);
myClientSocket.Close();
}
}
上面那段作为多线程部分后台死循环运行。
然后定义几个全局变量:
private static byte[] result = new byte[4096]; private static int myProt = 2333; // 端口 static Socket serverSocket;
在插件初始化时,打开该线程:
IPAddress ip = IPAddress.Parse("127.0.0.1");
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(ip, myProt)); // 绑定 IP 地址:端口
serverSocket.Listen(10); // 设定最多 10 个排队连接请求
// 通过 Clientsoket 发送数据
Thread myThread = new Thread(ListenClientConnect);
myThread.Start();
最后只是消息处理问题了,只要让结果消息+="|||||"和别的东西就可以了。
注意的地方:
如果普通消息中你没有强制插入"<"符号,可能后导致命令输入漏洞,所以我从c#到java输出的普通聊天记录的格式是[群消息]<玩家id>消息内容
其他:没东西啦















因为没有自动换行右边的侧边栏把代码挡住了2333
老文章,反正也是垃圾代码,没人看的吧