【尝试】半教程半制作半探索半学习的JAVA插件帖



  • 好的我又来发帖了
    这次是我第一次做一个如此大型的插件,
    为的是我即将开启的服务器
    (说实话,我也不知道什么时候开,估计不会超过2018年)

    计划是一个半科技半魔法的纯PVP类服务器
    因为只有我一个人(当然如果我的朋友学会了JAVA也会来帮我),而且制作工作十分巨大。
    所以这个插件将十分的难做,但是我会尽力的

    顺便发一下进度:
    0_1483709780896_捕获.PNG
    好吧我只做了一点微小的工作

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • 我们来研究一下下面一段代码:

    @Override
        public void onEnable(){
            new BukkitRunnable(){
                @Override
                public void run(){
                    for(Player p:Bukkit.getOnlinePlayers()){
                        ((CraftPlayer)p).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(IChatBaseComponent.ChatSerializer.a("{'text':'生命:"+nowHealth.get(p.getDisplayName())+"/"+maxHealth.get(p.getDisplayName()))+"\t"+"法力:"+nowMagic.get(p.getDisplayName()+"/"+maxMagic.get(p.getDisplayName()))));
                    }
                }
            }.runTaskTimer(this, 0L, 5L);
        }
    

    好吧这段代码我写了好久。


    @MoRan_Sky @Death_fish Player类能不能直接变CraftPlayer类?我查了源码发现它是Player的子类。但是源码是这样的:

    public static Collection< ? extends Player> getOnlinePlayers()
    //问一下这个泛型是不是CraftPlayer类型?
    

    好了我们继续:
    先不看这个有争议的(CraftPlayer)p,
    我们看一下这个“BukkitRunnable"
    这是在Spigot里实现多线程的方式


    在Spigot里不要直接使用Thread类或者Runnable接口!!!
    这是危险的,因为Spigot使用单线程运行。
    调用JAVA线程的方法是危险的。
    比如调用:

    Thread.sleep(time); //你认为是让插件停止time毫秒
    

    会使整个服务器停止运行time毫秒。


    所以,在插件编写中,常用的是Spigot实现的BukkitRunnable类
    此类实现Runnable接口,用以在Spigot中使用多线程
    不过这是个抽象类,所以我们有必要实现里面的run()方法(就像Runnable线程一样)
    在run方法里填写所需的过程


    BukkitRunnable类有以下几个实用的方法
    runTask(Plugin plugin) 运行任务
    runTaskAsynchronously(Plugin plugin) 异步运行
    runTaskLater(Plugin plugin, long delay) 在delay/20 秒后运行,对应setTimeOut
    runTaskLaterAsynchronously(Plugin plugin, long delay) 异步延时运行
    runTaskTimer(Plugin plugin, long delay, long period) 在delay/20 秒后开始运行,每period/20 秒运行一次,对应setInterval
    runTaskTimerAsynchronously(Plugin plugin, long delay, long period) 异步定时运行
    注意:
    异步运行不能调用BukkitAPI!

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • 补充:匿名内部类:
    仔细看这段代码:

     new BukkitRunnable(){
                @Override
                public void run(){
                    for(Player p:Bukkit.getOnlinePlayers()){
                       //code                
                    }
                }
            }.runTaskTimer(this, 0L, 5L);
    }
    

    对于初学者来说,这段代码难以理解也是正常的。
    这样,先简化一下:

    new BukkitRunnable().runTaskTimer(this,0L,5L);
    

    这个的本意是创建一个空的线程,每1/4秒运行一次
    但是这个无法通过编译,因为BukkitRunnable是抽象类,无法直接实例化
    所以我们要想办法OVERRIDE里面的run方法!
    于是就这样了:

     new BukkitRunnable(){
                @Override
                public void run(){
                    for(Player p:Bukkit.getOnlinePlayers()){
                       //code                
                    }
                }
            }.runTaskTimer(this, 0L, 5L);
    }
    

    当然,也相当于这样(用内部类):

    class MyBukkitRunnable extends BukkitRunnable {
                @Override
                public void run(){
                    for(Player p:Bukkit.getOnlinePlayers()){
                       //code                
                    }
                }
    }
    //...
    new MyBukkitRunnable().runTaskTimer(this, 0L, 5L);
    

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • 没有人看,含泪更新:
    做了一点微小的改动:

    //imports
    
    public class C {
        public static void sendOpMessage(Player p,String message){
            ((CraftPlayer)p).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(IChatBaseComponent.ChatSerializer.a("{'text':'"+message+"'}")));
        }
    }
    

    将一个常用的复杂方法“操作栏发送消息”封装到了C类里
    (至于为什么取C做名字,是取Convenience之意)
    这样以后调用都能方便些
    而且以后一些复杂的东西都会在里面封装。

    然后把主类改成了这样

    //imports
    
    public class BasicPluginForServer extends JavaPlugin{
        public HashMap<String,Long> maxHealth;
        public HashMap<String,Long> nowHealth;
        public HashMap<String,Long> maxMagic;
        public HashMap<String,Long> nowMagic;
        public HashMap<String,Short> level;
        public HashMap<String,Long> money;
        
        @Override
        public void onEnable(){
            new BukkitRunnable(){
                @Override
                public void run(){
                    for(Player p:Bukkit.getOnlinePlayers()){
                        String pName=p.getDisplayName();
                        String str=nowHealth.get(pName)+"/"+maxHealth.get(pName)+"\t"+"法力:"+nowMagic.get(pName)+"/"+maxMagic.get(pName);
                        C.sendOpMessage(p, str);
                    }
                }
            }.runTaskTimer(this, 0L, 5L);
        }
    

    (这里说一下,之前的代码里有一些错误,把前后括号的个数搞错了)

    还有就是新增了一个DBConeection类

    package basicpluginforserver;
    
    import java.sql.*;
    
    public class DBConnection {
        private static Connection conn;
        public static Connection getConnection(){
            return conn;
        }
        public static void connect(String DBURL,String DBUSER,String DBPASSWORD) throws SQLException{
            conn=DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD);
        }
        public static void init(String DBDRIVER) throws ClassNotFoundException{
            Class.forName(DBDRIVER);
        }
    }
    

    负责数据库的操作(不过还没写完

    没错,我就是不疯的疯牛,超越常理的存在

    1


  • P.P.S.S 本帖门槛:
    1.懂“一点”JAVA(至少懂一点”面向对象“)
    2.有电脑,有IDE,有手,有键盘,有鼠标,有网络,有”脑子“
    3.没了
    4.真的没了
    5.真的真的没了
    6.三四五都是假的
    7.知道BukkitAPI的网址!
    8.拥有一定的查API能力
    9.没了
    10.真的没了
    11.真的真的没了

    有问题随时欢迎提问

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • 明天期末考完,爆更!!!

    PS 不过我得先帮我同学搞一个破”创世战车“激活码的程序

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • 巨佬你好呢!~~~

    无势力死鱼Little_cat_998‮‮(´・ω・`)
    ﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉

    0

  • 超级萌新

    酷(不会告诉你这里是凑字数)



  • 停止运行??熊孩子又有玩的了呢



  • 开始更新啦!
    期末考试好了,向我妈讨了1个小时时间玩电脑。

    今天的任务主要是测试!(会上图):

    先写一个plugin.yml

    ## YAML Template.
    ---
    name: BasicPluginForServer
    version: test
    main: basicpluginforserver.BasicPluginForServer
    author: Crazy_Bull
    

    0_1484046820220_1.PNG

    构建ING。。。好了。
    0_1484046967809_2.PNG
    在这儿

    !!! !!! !!!
    注意,正在启动!正在启动!!!
    !!! !!! !!!

    好吧用了过时的JAR,不管了,只要等15秒
    0_1484047166644_3.PNG

    咦,插件失败了。
    0_1484047290693_4.PNG
    应该是程序有问题

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • 懂了,说到底还是发送到操作栏的问题。
    Spigot中的Player类怎么转换为CraftPlayer类?
    急!!!
    @MoRan_Sky @Death_fish @Kanzaki_Aria

    求两位大神帮忙!!!

    没错,我就是不疯的疯牛,超越常理的存在

    0

  • 超级萌新

    @Crazy_Bull 还是Player类转CraftPlayer类出现的错误?按道理应该不会错啊



  • @MoRan_Sky 可以直接用强制类型转换吗?

    没错,我就是不疯的疯牛,超越常理的存在

    0

  • 超级萌新

    @Crazy_Bull 应该是可以的,因为他是Player的子类啊



  • @MoRan_Sky 我也知道,不过父类转子类好像是有可能会出错的吧。

    没错,我就是不疯的疯牛,超越常理的存在

    0

  • 超级萌新

    @Crazy_Bull【尝试】半教程半制作半探索半学习的JAVA插件帖 中说:

    父类转子类

    父类转子类有可能,说不定这个Player就不是CraftPlayer(wodema),但这在JS里却是可以实现的



  • @MoRan_Sky 哎呀真烦,到时候测试一下toString吧,反正如果它是CraftPlayer的话会调CraftPlayer的toString方法

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • @MoRan_Sky 查明了不是这个原因,应为我把有关语句打成注释还是出错

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • @Crazy_Bull

    要不我给你java源码吧,用反射可以解决。



  • @terry_ma 好的,谢谢

    没错,我就是不疯的疯牛,超越常理的存在

    0


  • @Crazy_Bull player.getHandle()?
    推荐使用protocollib

    是咸鱼,总会翻身的
    #话说居然有人猜一条鱼是男是女…
    #鱼哪来的男女之分啊=_=||

    /*'<script>
    alert("-1s")</script>*/

    0

登录后回复