LV. 4
GP 0

【教學 || Normal】如何自製插件 (圖影文) 暫休 1-8節

樓主 老葉 class70636
GP107 BP-
    最近礙於上班,又加上電腦壞了,可能要一段時間才會繼續寫

    這要追溯到我之前遊玩EK永恆國度的時候,看到了台灣獨一無二的插件。然後我做了件非常蠢的事,我就去向製作插件的『doublehell、mm2015』兩位大大要了插件,不用說當然踢鐵板。但是mm2015大大鼓勵我說好好學Java,所以開啟了一連串的做插件興趣,沒研究很久所以沒說特別厲害,但是小有收穫,板上也有類似文章,但是好像沒再更新,所以決定發一篇算是心得吧 !

前置預備工具  (請先按下右上角的開啟圖片吧)

˙Java SE Development Kit (簡稱 JDK) - 下載連結
1 進入後請往下找到這個,並按下上方的 " Accept License Agreement  " 才可以開始下載,下載時選擇自己的電腦作業系統。

2  下載完後開啟檔案,用莽夫安裝法安裝,一直按下一步 ( next ) 安裝就可以了。
-------------------------------------------------------------------------------------------------------------------------------˙Eclipse IDE for Java Developers( 開發軟體  中文化教學) - 下載連結
1  進入後會看到旁邊有 " Download Links " ,選擇自己的電腦類別及位元。

2  再來就會看到這個,點擊紅色框框會跳到別的頁面就會開始自動下載了。

3 下載下來應該是一個壓縮檔,將檔案解壓縮到你想要的地方就可以了。
-------------------------------------------------------------------------------------------------------------------------------˙CraftBukkit -  下載連結
1 進入後只要選擇你要開發的版本按下Download就可以開始下載了。


正題 - 開發插件  

因為板上已有大大類似的文章,那篇文章正是基礎的基礎,建議先學會那位大大學的之後再來做這邊的。 傳送門

如果有先學過C++的就會發現很輕鬆 !

* 以下的教學我使用 英文 版的,如是使用中文的朋友們,只是英文變成中文而已,位置應該不會跑掉,按照位置點就好了。

第一節   自定義物品   ( 以後會教用自己寫函式的方法,會快很多又不容易出錯 )

顧名思義,如圖 。可自訂物品名稱還有敘述
算是有點徒法煉鋼但是其實很簡單的。
1  首先先在  public class 專案名稱 extends JavaPlugin 裡輸入以下:
public class CustomItem extends JavaPlugin{
    protected static ItemStack item01;

    static {
    item01 = new ItemStack(Material.DIAMOND_SWORD,(short) 1);
    }
}
說明:藍色 的部分可自行更改,但要藍色的地方都要一樣
           紅色 的部分為自訂義物品的樣式,此處為以鑽石劍舉例。如要查詢物品名稱,請點我
請將 Material.XXX 後方的XXX改為你要自訂義的物品名稱。
       - short 後方的數字代表 數量


2 接著在 public void onEnable()函式裡輸入:
public void onEnable(){
    ItemMeta test = item01.getItemMeta();
    test.setDisplayName(ChatColor.GOLD + "破邪之劍");
    test.setLore(Arrays.asList(new String[] {
       (ChatColor.WHITE + "擁有強大力量的劍") ,
       (ChatColor.RED + "非常危險!")
    }));
    item01.setItemMeta(test);

}
說明:藍色 可自行更改,但是還是老話一句,藍色的地方都要一樣
            * 橘色 這次不可以再亂更改了,在第 1步驟裡的藍色,要跟這裡的橘色 一樣。

* test.setDisplayName();
  - 此為物品的名稱,也就是圖片上的 "破邪之劍" 那一行。
    - 注意一定要打在 " " 裡頭。文字顏色請參考 這裡Official Name 此欄位。

*  test.setLore(Arrays.asList(new String[] {
       (ChatColor.WHITE + "擁有強大力量的劍") ,
       (ChatColor.RED + "非常危險!")
    }));
- 此為物品的敘述,也是圖片"擁有強大力量的劍" 及 "非常危險!" 兩行。
  - 一樣要打在" "裡頭。如敘述需要多行,請用 , 隔開,假如我現在要三行敘述就要寫成以   下:
  (""),(""),("")

3 既然做好了一個物品,那要怎麼取得呢 ?  就必須用到onCommand()這個函式了:
public boolean onCommand(CommandSender sender , Command cmd , String lable , String[] args) {
    Player p = (Player) sender;
    if(lable.equalsIgnoreCase("get")) {
        if(args.length == 0) {
            p.sendMessage(ChatColor.RED + "請輸入物品編號!");
        }
        else if(args.length == 1) {
            String a = args[0];
            switch(a){
            case "001":
                p.getInventory().addItem(item01);
                p.updateInventory();
                break;
            default:
                p.sendMessage(ChatColor.RED + "無此物品編號!")
            }
        }
    }
    return false;
}
說明:藍色 的部分為指令可以自由更改。
           紅色 的部分為你剛剛寫的新物品,也就是第 1 步驟中的藍色文字。
此處較複雜的為 switch 為一個 條件判斷陳述式,也就是你丟甚麼進去,他會回丟給你某個東西......

* 如果要新增第二樣、第三樣、第四樣...等多樣自訂義物品,
1 就要多新增以下:
protected static ItemStack item01;
protected static ItemStack item02;
protected static ItemStack item03;
... 以此類推

2 就要多新增以下:
將此整段複製下來
ItemMeta test = item01.getItemMeta();
    test.setDisplayname(ChatColor.GOLD + "破邪之劍");
    test.setLore(Arrays.asList(new String[] {
       (ChatColor.WHITE + "擁有強大力量的劍") ,
       (ChatColor.RED + "非常危險!")
    }));
    item01.setItemMeta(test);
然後貼在此段下方,並將 test 改為別的名稱,item01 改為 item02
...以此類推如下
ItemMeta test = item01.getItemMeta();
    test.setDisplayname(ChatColor.GOLD + "破邪之劍");
    test.setLore(Arrays.asList(new String[] {
       (ChatColor.WHITE + "擁有強大力量的劍") ,
       (ChatColor.RED + "非常危險!")
    }));
    item01.setItemMeta(test);

ItemMeta test02 = item02.getItemMeta();
    test02.setDisplayname(ChatColor.GOLD + "第二樣物品名稱");
    test02.setLore(Arrays.asList(new String[] {
       (ChatColor.WHITE + "第二樣物品敘述") ,
       (ChatColor.RED + "第二樣物品敘述")
    }));
    item02.setItemMeta(test02);

3 較簡單,只要將本來的
switch(a){
            case "001":
                p.getInventory().addItem(item01);
                p.updateInventory();
                break;
            default:
                p.sendMessage(ChatColor.RED + "無此物品編號!")
            }
case下方多新增後面的 002 、003...等等。並將p.getInventory.addItem(item01)改為 p.getInventory.addItem(item02)...以此類推。
switch(a){
            case "001":
                p.getInventory().addItem(item01);
                p.updateInventory();
                break;
                           case "002":
                                    p.getInventory().addItem(item02);
                p.updateInventory();
                break;
            default:
                p.sendMessage(ChatColor.RED + "無此物品編號!")
            }
* 請注意:default不用動,只要動case 就可以了,但是將 case 的頭排成一直線,我也不知道沒排成一直線會怎樣。

進入遊戲後只要打指令 /get 001 或 / get 002 就可以拿到對應的自訂義物品了 !

那麼,做出來可以幹嘛 ? 又不會有能力效果,砍怪也不會比較痛啊
華生,你突破盲點了,做出來用途可多的,傷害的話要在後面幾節才會學到,目前可以搭配其他插件做使用。例如:

1 Shopkeepers ( 自訂商人兌換插件 ) - 原文網址
   可以搭配此插件使用,將取得過後的自訂義物品放到商人裡面,讓你的玩家可以兌換獨一無二的物品。

2 TreasureChest ( 藏寶箱插件 ) - 原文網址
   也可以放到藏寶箱裡面,讓玩家在找到藏寶箱後打開裡面不是普通的金粒、鐵裝,或一些普通的方塊,而是你自製的物品喔 。

詳細使用方法在板上都找得到喔,也可以自己找找看有甚麼插件可以搭配使用 ~

此連結 為此插件所有程式碼。

◎ 以上會用到的資源:
1 minecraft物品及方塊ID、名稱查詢 - Here
2 minecraft色碼表 - Here


第二節   自定義合成表   ( 請沿用上一節的專案,不要另外新增專案 ! )
相信我這絕對比你想像的還簡單。

1 首先在public void onEnable() 以及 public void onDisable() 函式裡加入以下:
public void onEnable(){
    ShapedRecipe test = new ShapedRecipe(new ItemStack(Material.GOLD_ORE))
.shape("   ","!/!","   ")
.setIngredient('!',Material.BEDROCK).
setIngredient('/',Material.GOLD_BLOCK);

getServer().addRecipe(test);
}

public void onDisable(){
    getServer().clearRecipes();
}
說明:紅色代表此合成表名稱。可自行更改
           綠色代表要被合成出來的物品。可自行更改
           藍色代表合成表,解釋如下:
("123"),("456"),("789")  對照為合成表為  
1 2 3
4 5 6
7 8 9

所以上方藍色也可以自行更改,例如:("!@!"),("@#@"),("$!@")
比照為合成就為
! @ !
@ # @
$ ! @

* 若為空白一定要按空白鍵,例如("  !"),(" @ "),("#  ")如下:
!
@
#
每個("   ")裡頭一定滿3個字元,空白也算!!!

- setIngredient('!',Material.BEDROCK)
不用我多說了就是'!'代表的是 BEDROCK ,有幾個字元就在後面多加.setIngredient

進階 ( 如果能夠舉一反三的話就會發現其實可以搭配自訂義物品 )
例如:

只要新增一個物品 item01 ,然後將紅色的部分
ShapedRecipe test = new ShapedRecipe(new ItemStack(Material.GOLD_ORE)).shape("   ","!/!","   ")
.setIngredient('!',Material.BEDROCK).
setIngredient('/',Material.GOLD_BLOCK);
改成以下
ShapedRecipe test = new ShapedRecipe(item01).shape("   ","!/!","   ")
.setIngredient('!',Material.BEDROCK).
setIngredient('/',Material.GOLD_BLOCK);
就大功告成啦 !

那如果我要兩個、三個合成表呢 ?
非常簡單,在原有的 ShapedRecipe test = new Shaped ~
下方在新增一個 ShapedRecipe test02 = new Shaped ~
合成表就要自己新增了,以此類推...要第三個就
ShapedRecipe test03 = new Shaped ~

!!忘了提醒,假如新增完了一個test02合成表,一定要在原本
gerServer().addRecipe(test);的下方在新增一個
getServer().addRecipe(test02);才會有作用喔!


此插件不用輸入任何指令,是不是很簡單呢 ?

此連結 為此插件所有程式碼。( 影片日後補上)



第三節   事件(EVENT)  javadoc
    在minecraft當中,事件 是一個很重要的東西。那麼,事件 是甚麼呢 ? 也就是玩家在遊戲中做的所有動作像:放置方塊、破壞方塊、移動、睡覺、打字、丟東西、撿東西、釣魚...等,太多太多。此外 事件 也不僅包括玩家而已,連怪物、動物也算在其中;而當觸發這些事情,就會觸發一些我們自己寫的東西。 我這邊只能列出幾個我目前學到可以用得到的,其他還要有請比較厲害的大大補充了。 ( 以下都是以我自己的翻譯來做解釋,若有錯誤懇請告知以加以修改 )

* 先到 Javadoc 中,然後依序點擊:Classes → Class List → org → bukkit → event

      :主目錄;       :子目錄;╙:次級子目錄 ( 若上面有提到,則以下就不會再提,因為幾乎都大同小異 );╘:中級子目錄

block (方塊) 凡對方塊做任何事都會觸發此項
       Action (動作) :對方塊做的動作
               LEFT_CLICK_AIR 玩家 空氣 左鍵
               LEFT_CLICK_BLOCK 玩家 方塊 左鍵
                RIGHT_CLICK_AIR 玩家 空氣 右鍵
                RIGHT_CLICK_CLOCK 方塊 右鍵
       BlockBreakEvent :當有某方塊被破壞
               getPlayer :取得破壞方塊的玩家
               setCancelled:設置將該事件 取消。 (感謝 冰霜o奶茶 大大補充)
       BlockBurnEvent :當有某方塊著火時
       BlockDamageEvent :方塊受到傷害時 ( !? )
               getItemInHand:取得觸發此事件的人手上的物品
       BlockExpEvent :方塊經驗值 ( 應該是指玩家破壞方塊時,不知道被炸掉算不算 )
               getExpToDrop取得方塊掉落時的經驗值
               setExpToDrop設置方塊掉落時的經驗值
       BlockGrowEvent :這地方應該是指 樹苗、種子 等方塊成長的時候
               getNewState:取得新的階段
       BlockIgniteEvent:方塊點燃。跟上面的Burn不同,此處是指各種會讓方塊起火原因
               IgniteCause:起火原因
                          ╘ ENDER_CRYSTAL   終界水晶 ( 在打終界龍會幫終界龍補血的那個 )
                          ╘ EXPLOSION   爆炸 ( TNT 、 苦力怕 等等)
                          ╘ FIREBALL   火球 ( 地獄幽靈 射出來的那個吧 )
                          ╘ FLINT_AND_STEEL  打火石
                          ╘ LAVA  岩漿
                          ╘ LIGHTING  閃電
                          ╘ SPREAD  火勢蔓延
               getCause:取得起火原因
               getIgnitingBlock:取得正在起火的方塊
               getIgnitingEntity:取得正在起火的實體
       BlockPistonEvent活塞事件
               getDirection:取得活塞的方向
               isSticky:是否黏性
       BlockPistonExtendEvent活塞伸出事件
               getBlocks:取得活塞這個方塊
               getLength:取得延長的長度
       BlockPistonRetractEvent活塞縮回事件
               getRetractLocation:取得縮回後的座標
       BlockPlaceEvent方塊放置事件。 ( 跟上方的 Break相呼應 )
       BlockRedstoneEvent紅石事件
               getNewCurrent:取得新的電流
               getOldCurrent:取得舊的電流
               SetNewCurrent:設置新的電流
       SignChangeEvent告示牌改變事件
               getLine:取得行上的文字
               setLine:設置行上的文字

enchantment (附魔) 附魔就會觸發此項
       EnchantItemEvent:物品附魔事件
               getEnchantBlock:取得附魔用的方塊
               getEnchanter:取得附魔的人
               getEnchantsToAdd:取得要附進去的附魔、等級
               getExpLevelCost:取得附魔要消耗的經驗值、等級
               setExpLevelCost:設置附魔要消耗的經驗值、等級

entity (實體) 實體包含人、怪物、動物,我稱為 生物
       CreatureSpawnEvent:生物重生、出生的事件
               SpawnReason:重生、生出的原因
                          ╘ BED   床
                          ╘ BREEDING   動物交配
                          ╘ BUILD_IRONGOLEM   建造鐵巨人
                          ╘ BUILD_SNOWMAN   建造雪人
                          ╘ BUILD_WITHER   建造凋零怪
                          ╘ CUSTOM   自訂
                          ╘ DEFAULT   minecraft預設
                          ╘ EGG    ( 是指一般雞蛋 )
                          ╘ NATURIAL   自然生出
                          ╘ BREEDING   動物交配
                          ╘ SLIME_SPLIT   史萊姆分裂
                          ╘ SPAWNER_EGG   重生蛋
                          ╘ VILLAGE_DEFENSE   村莊防禦 !?
                          ╘ VILLAGE_INVASION   村莊入侵 !?
               getEntity:取得生物
               getLocation:取得座標
               getSpawnReason:取得重生、生出原因
       EntityBreakDoorEvent:生物破壞門的事件
       EntityDamageByBlockEvent:生物被方塊傷害 ( 沙子、礫石壓到 )
               getDamager:取得受到傷害的生物
       EntityDamageByEntityEvent:生物被生物傷害 ( 人被怪物打、怪物被人打、人打人)
       EntityDeathEvent:生物死亡事件
               getDroppedExp:取得生物死亡掉落的經驗值
               getDrops:取得生物死亡掉落的物品
               setDroppedExp:設置生物死亡掉落的經驗值
       EntityExplodeEvent:生物爆炸事件
               getYield:取得產量 !?
               setYield:設置產量 !?
       EntityPortalEnterEvent:生物進入傳送門事件
       EntityPortalEvent:生物傳送事件
               getPortalTravelAgent:取得生物傳送媒介
               setPortalTravelAgent:設置生物傳送媒介
               useTravelAgent:使用傳送媒介
       EntityPortalExitEvent:生物離開傳送門事件
               getAfter:取得離開後的事情
               getBefore:取得進入前的事情
               setAfter:設置離開後的事情
       EntityRegainHealthEvent:生物血量恢復事件
               RegainReason:恢復血量的原因
                          ╘ CUSTOM   自訂
                          ╘ EATING   吃東西
                          ╘ ENDER_CRYSTAL   終界水晶補血
                          ╘ SATIATED   吃飽喝飽
                          ╘ WITHER_SPAWN   凋零出生
               getAmount:取得恢復的血量值
               getRegainReason:取得恢復血量的原因
               setAmount:設置恢復的血量值
       EntityShootBowEvent:生物射箭事件
               getBow:取得生物射箭的弓
               getForce:取得射箭的力量
               getProjectile:取得射箭的拋物線
               setProjectile:設置射箭的拋物線
       EntityTameEvent:生物被馴服事件
               getOwner:取得被馴服生物的主人
       EntityTargetEvent:生物對某人設為目標事件
               targetReason:被設為目標的原因。
                          ╘ CLOSEST_PLAYER   最接近的玩家
                          ╘ CUSTOM   自訂
                          ╘ DEFEND_VILLAGE   村莊的防禦
                          ╘ FORGOT_TARGET   生物忘記上個目標而轉向你
                          ╘ OWNER_ATTACKED_TARGET   當生物的主人攻擊某物時,某生物的目標就                                             會指向主人攻擊的目標 ( 例:馴服狗然後打僵屍,狗就會攻擊僵屍)
                          ╘ PIG_ZOMBIE_TARGET  僵屍豬人自動指向目標
                          ╘ RANDOM_TARGET   當生物沒有目標時,就會隨機選擇一個
                          ╘ TARGET_ATTACKED_ENTITY   當目標攻擊生物時,生物就會攻擊目標
                          ╘ TARGET_ATTACKED_OWNER   目標攻擊生物的主人,則某生物就會攻擊目標                                        ( 例:主人掛網被僵屍打,則馴服的生物就會攻擊僵屍)
                          ╘ TARGET_DIED   目標生物死亡後而轉向
               getReason:取得原因。
               getTarget:取得被設為目標的生物。
               setTarget:設置目標生物。
       EntityTeleportEvent:生物傳送事件 ( 這邊的傳送指將某生物傳送到某個座標世界)
               getFrom:取得生物從何處傳送過來。
               getTo:取得生物將要被傳到何處。
               setFrom:設置生物從何處傳送過來。
               setTo:設置生物將要被傳到何處。
       ExpBottleEvent:經驗瓶事件
               getExperience:取得經驗瓶的經驗值。
               getShowEffect:取得顯示的效果。
               setExperience:設置經驗瓶的經驗值。
               setShowEffect:設置顯示的效果。
       ExplosionPrimeEvent:爆炸事件
               getFire:取得爆炸火力。
               getRadius:取得爆炸半徑。
               setFire:設置爆炸火力。
               setRadius:設置爆炸半徑。
       FoodLevelChangeEvent:飽滿度改變事件
               getFoodLevel:取得飽滿度的值。
               setFoodLevel:設置飽滿度的值。
       HorseJumpEvent跳躍事件
               getPower:取得馬的跳躍力量。
               setPower:設置馬的跳躍力量。
       PlayerDeathEvent:玩家死亡事件
               getDeathMessage:取得玩家死亡訊息
               getKeepLevel:取得玩家死亡後保持的等級。
               getNewLevel:取得玩家死亡後新的等級。
               getNewExp:取得玩家死亡後新的經驗值。
               getNewTotalExp:取得玩家死亡後的總經驗值。
               setDeathMessage:設置玩家死亡訊息。
               setKeepLevel:設置玩家死亡後保持的等級。
               setNewLevel:設置玩家死亡後新的等級。
               setNewExp:設置玩家死亡後新的經驗值。
               setNewTotalExp:設置玩家死亡後的總經驗值。
       PlayerLeashEntityEvent:玩家繫上栓繩事件
               getLeashHolder:取得栓繩的持有人。
       PotionSplashEvent:藥水噴濺事件
               getAffectedEntities:取得噴濺後影響的生物。
               getIntensity:取得噴濺強度。
               getPotion:取得藥水
               setIntensity:設置噴濺強度。
       SheepDyeWoolEvent:給羊染色事件
               getColor:取得顏色。
               setColor:設置顏色。
       SheepRegrowWoolEvent:羊的毛重新生長事件
       SlimeSplitEvent:史萊姆分裂事件
               getCount:取得分裂數量。
               setCount:設置分裂數量。

inventory (清單、背包) 背包是指玩家按E之後。清單是指各種有格子的 (釀造、箱子)
       BrewEvent:釀造事件
               getContents:取得釀造台裡的內容物。
       ClickType:點擊的類型
               isCreativeAction:在創造模式執行。
               isKeyboardClick:在某按鍵按下後執行。
               isRightClick:在右鍵按下後執行。
               isLeftClick在左鍵按下後執行。
               isShiftClick在Shift鍵按下後執行。
               CONTROL_DROP按下CTRL鍵同時按丟掉鍵 ( 預設Q鍵 )。
               Creative在創造模式下打開背包。
               DOUBLE_CLICL快速點擊滑鼠左鍵兩次。
               DROP丟掉鍵 ( 預設Q )。
               LEFT左鍵。
               MIDDLE滾輪。
               NUMBER_KEY:數字鍵
               RIGHT右鍵。
               SHIFT_LEFT按下SHIFT鍵同時按滑鼠左鍵。
               SHIFT_RIGHT按下SHIFT鍵同時按滑鼠右鍵。
       CraftItemEvent:合成事件
               getInventory取得合成台清單。
               getRecipe取得合成表。
       InventoryInteractEvent:背包、清單與人相互作用事件
               getResult取得結果。
               getWhoClicked取得是誰點擊這個物品。
               setResult設置結果。
       InventoryMoveItemEvent:背包、清單中的物品被移動事件
               getDestination取得物品被移動到哪裡。
               getInitiator取得物品的創始者 ( 假如我合出了一張床,那麼這張床的創始者就是我)。
       InventoryOpenEvent:背包、清單中打開事件
       InventoryPickupItemEvent:玩家撿起物品事件
       InventoryType:背包、清單種類
               SlotType:格子的種類 ( 例:玩家背包的格子、箱子的格子、合成台的格子...等等)
                          ╘ ARMOR  玩家穿裝備的格子
                          ╘ CONTAINER  容器的格子
                          ╘ CRAFTING  合成的格子
                          ╘ QUICKBAR  快捷格子 ( 也就是視窗下方的那9格)
                          ╘ RESULT  結果格子 ( 合成台右邊的那個、熔爐右邊的那個...等等)
               getDefaultSize:取得預設背包、清單大小。
               getDefaultTitle:取得預設背包、清單標題。
               ANVIL:鐵砧。
               BEACON:烽火台
               BREAING:釀造台
               CHEST:箱子
               CRAFTING:玩家身上的4格合成台
               CREATIVE:創造模式
               ENCHANTING:附魔台
               ENDER_CHEST:終界箱
               CREATIVE:創造模式
               FURNACE:熔爐
               MERCHANT:商人
               PLAYER:玩家
               WORKBENCH:9格的工作台

player (玩家) 最多事件的地方,與你進入遊戲後的每個動作息息相關
       PlayerAnimationEvent:玩家的動作
       PlayerAnimationType:玩家動作的種類
               ARM_SWING:手臂擺動
       PlayerBedEnterEvent:玩家上床的動作
       PlayerBedLeaveEvent:玩家下床的動作
       PlayerBucketEmptyEvent:玩家水桶空掉的動作
       PlayerBucketFillEvent:玩家水桶滿的動作
       PlayerWorldChangeEvent:玩家世界改變的動作
               getFrom:取得從何處來
       PlayerChatEvent:玩家聊天的動作
               getFormat:取得聊天格式
               getMessage:取得聊天的訊息
               getRecipients:取得誰接收了聊天訊息
               setFormat:設置聊天格式
               setMessage:設置聊天的訊息
       PlayerCommandPreprocessEvent:玩家指令處理的動作
               setPlayer:設置玩家
       PlayerDropItemEvent:玩家丟棄物品的動作
               getItemDop:取得被玩家丟掉的物品
       PlayerEditBookEvent:玩家寫書的動作
               getNewBookMeta:取得玩家寫的新書的資訊
       PlayerEggThrowEvent:玩家丟雞蛋的動作
               getEgg:取得玩家丟出的蛋
               getHatchingType:取得丟出的蛋會孵化甚麼類型的東西。 ( 預設是 )
               getEgg:取得玩家丟出的蛋
               getNumHatches:取得丟出的蛋會孵化多少
       PlayerExpChangeEvent:玩家經驗值改變的動作
               getAmount:取得改變的經驗值量
               setAmount:設置改變的經驗值量
       PlayerFishEvent:玩家釣魚的動作
               getCaught:取得釣到的東西
               getExpToDrop:取得釣到的東西後的經驗值
               getHook:取得釣竿
               getState:取得釣的時候的階段
               setExpToDrop:設置釣到的東西後的經驗值
       PlayerGameModeChageEvent:玩家模式改變的動作
               getNewGameMode:取得改變後的玩家模式
       PlayerInteractEntityEvent:玩家與某生物相互作用的動作
               getRightClicked:取得被玩家右鍵點擊的生物。
       PlayerInteractEvent:玩家與任何東西相互作用的動作 ( 很常用到 )
               getAction:取得動作 ( 右、左鍵方塊、空氣 )。
               getBlockFace:玩家面向的方塊。
               getClickedBlock:玩家點擊的方塊。
       PlayerItemBreakEvent:玩家的物品爆掉時的動作 ( 例:木稿挖到爆掉 )
               getBrokenItem:取得爆掉的物品。
       PlayerItemHeldEvent:玩家將物品拿在手上的動作
       PlayerJoinEvent:玩家加入遊戲的動作 (與下方Login不同之處在於一個外部,一個內部)
               getJoinMessage:取得玩家加入的訊息。
               setJoinMessage:取得玩家加入的訊息。
       PlayerKickEvent:玩家被踢掉的動作
               getLeaveMessage:取得玩家離開後的訊息。
               getReason:取得玩家被踢的原因。
               setLeaveMessage:設置玩家離開後的訊息。
               setReason:設置玩家被踢的原因。
       PlayerLevelChangeEvent:玩家等級改變的動作
               getNewLevel:取得玩家新的等級。
               getOldLevel:取得玩家舊的等級。
       PlayerLoginEvent:玩家加入伺服器的動作
               Result:加入後的結果。
                       ╘ ALLOWED   允許
                       ╘ KICK_BANNED   不允許,然後B掉
                       ╘ KICK_FULL   不允許,因為伺服器滿人
                       ╘ KICK_OTHER   不允許,因為理由還沒設定
                       ╘ KICK_WHITELIST   不允許,因為不在白名單內
               allow:允許。
               disallow:不允許。
               getAddress:取得登入伺服器的玩家電腦IP位址
               getHostname:取得登入伺服器的玩家電腦名稱
               getKickMessage:取得伺服器踢人的訊息
               getResult:取得登入後的結果
               setKickMessage:設置伺服器踢人的訊息
               setResult:設置登入後的結果
       PlayerMoveEvent:玩家移動的動作
               getFrom:取得從何處移動過來
               getTo:取得移動到何處
               setFrom:設置從何處移動過來
               setTo:設置移動到何處
       PlayerPickupItemEvent:玩家檢物品的動作
       PlayerPortalEvent:玩家傳送門的動作
       PlayerQuitEvent:玩家離開伺服器的動作
               getQuitMessage:取得離開伺服器後的訊息
               setQuitMessage設置離開伺服器後的訊息
       PlayerRespawnEvent:玩家重生的動作
               getRespawnLocation:取得玩家重生後的座標
               isBedSpawn:是否使用床重生
       PlayerTeleportEvent:玩家傳送的動作
               TeleportCause:傳送的原因
                          ╘ COMMAND   指令
                          ╘ ENDER_PORTAL   終界傳送
                          ╘ ENDER_PEARL   終界珍珠
                          ╘ NETHER_PORTAL   地獄傳送
                          ╘ PLUGIN   插件
               getCause:取得傳送的原因
       PlayerToggleFlightEvent:玩家飛行的動作
               setCancelled:設置可否飛行
       PlayerToggleSneakEvent:玩家隱形的動作
               setCancelled:設置可否隱形
       PlayerToggleSprintEvent:玩家跑步的動作
               setCancelled:設置可否跑步

server (伺服器) 有關伺服器的事件
       PluginDisableEvent:伺服器插件關閉的動作
       PluginEnableEvent:伺服器插件開啟的動作
       ServerListPingEvent:伺服器清單
                 getAddress:取得伺服器位置
                 getMaxPlayers:取得最大玩家數
                 getMotd:取得伺服器訊息
                 setMaxPlayers:設置最大玩家數
                 setMotd:設置伺服器訊息

world (世界) 有關遊戲內世界的事件
       PortalCreateEvent:傳送門創造的事件
                 CreateReason:被創造的原因
                          ╘ FIRE   火 ( 地獄傳送門是用火建造的)
                 getBlocks:取得傳送門的方塊
       SpawnChangeEvent:重生點改變的事件
                 getPreviousLocation:取得上個點的座標
       WorldLoadEvent:世界讀取的事件
       WorldSaveEvent:世界存檔的事件
       WorldUnloadEvent:世界卸載的事件

以上,目前用得到EVENT,這只是一部分。因為我學的有限,最多我就只能介紹這麼多。

這邊再複習一次事件的監聽(Listener):
原本:
public class 專案名稱 extends JavaPlugin
改成
public class 專案名稱 extends JavaPlugin implements Listener

並且在 public void onEnable() 函式內加入:
public void onEnable() {
    getServer().getPluginManager().registerEvents(this, this);
}

要使用的事件監聽程式碼:
@EventHandler
public void
自訂 (事件 簡稱) {

}





第四節   本節延續上節挑幾個事件做範例
   上節提的所有事件多到不可能每個都學得會,我會挑幾個下來作範例讓大家可以有一些概念,然後再自己去上面研究其他的。( 請先將事件監聽的程式碼打上後再來做以下 )

Example 1 -  Motd ( 玩家進入遊戲後的訊息 )

如何做 ?
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
    Player p = e.getPlayer();
    p.sendMessage(ChatColor.BLUE + "********************");
    p.sendMessage(ChatColor.AQUA + "    歡迎來到老葉伺服器 ");
    p.sendMessage(ChatColor.GOLD + "     祝您玩得愉快     ");
    p.sendMessage(ChatColor.BLUE + "********************");
}
說明:事件 - PlayerJoinEvent 玩家加入遊戲後的事件。
           Player p = e.getPlayer(); 宣告,將P宣告為觸發這個事件的玩家
           e.getPlayer()的解釋:e為此事件的主目錄,而.getPlayer就是子目錄
           p.sendMessage("") 傳送訊息。

就這樣 ? 沒錯,就是只有這樣 ! 是不是很簡單 ?

Example 2 -  玩家死亡訊息

public void onPlayerDeath(PlayerDeathEvent e) {
    Player p = e.getEntity();
    p.sendMessage(ChatColor.GOLD + "哈哈哈," + p.getName()
    + "居然死在minecraft中!");
}
說明:事件 - PlayerDeathEvent 玩家死亡的事件。
           Player p = e.getEntity();  將P宣告為觸發個事件的生物
           p.sendMessage("")傳送訊息。

Example 3 -  丟雞蛋只會跑出小雞 ?

做點改變,會生出小羊呢 !
public void onPlayerEgg(PlayerEggThrowEvent e) {
    e.setHatchingType(EntityType.SHEEP);
}
說明:事件 - PlayerEggThrowEvent 玩家丟雞蛋後的事件。
           e.setHatchingType( EntityType.______ ); 設定丟出後會變成甚麼東西,底線部分看你想要讓丟出後會生出甚麼就填甚麼。

以上,只要簡簡單單寫,不用30秒就可以做出會讓你驚奇的東西。
以下呢 ? 就要 "稍微稍微" 做深入一點點。

Example 4 -  神秘禁區一踏入就被傳走 ?

這甚麼鬼區域,踩踩看好了 !


甚麼,是禁區 ?

需要用到條件判斷。可以做得很簡單;也可以做得很複雜。
public void onPlayerMove(PlayerMoveEvent e) {
    Player p = e.getPlayer();
    int x = (int) p.getLocation().getX();
    int y = (int) p.getLocation().getY();
    int z = (int) p.getLocation().getZ();

    if(x>158 && x<161 && z>-577 && z<-574 && y==79) {
        p.sendMessage(ChatColor.RED + "因誤踏了神秘禁區,被傳送強制離開!");
        p.teleport(new Location(p.getWorld(),164,79,-574));
    }
}
說明:事件 - PlayerMoveEvent 玩家移動的事件。
            Player p = e.getPlayer();將P宣告為觸發此事件的玩家。
   int x = (int) p.getLocation().getX();
   int y = (int) p.getLocation().getY();
   int z = (int) p.getLocation().getZ();
     以上三點都是宣告,令 x 等於 觸發此事件玩家的座標 X
                    令 y 等於 觸發此事件玩家的座標 y
                    令 z 等於 觸發此事件玩家的座標 z
     (int) 代表的強制轉型因為其實座標並不是整數,所以這樣寫可以讓他強制轉為整數。
/*********************/
    if(x>158 && x<161 && z>-577 && z<-574 && y==79) 先解釋一下裏頭的符號:
  >大於。       <小於。       ==等於。       &&而且、和
這行的中文翻譯就叫做『如果觸發此事件玩家的座標 X 大於158而且 X 小於161而且座標Z 大於-577而且Z小於-574而且座標Y等於79 』就會做以下事情。

而且 的定義是甚麼呢 ? 舉個例子: 媽媽說我要寫完功課 而且 要掃地拖地才能出去玩。
也就說他必須要兩個事情都做了才能出去玩,只做一個是不行的。

所以以上述 if 條件的 X 來解讀,就是 玩家座標的 X 必須 同時 大於158、小於161 』。
舉幾個座標來當例子讓大家更清楚:
1. ( 159 , 79 , -575) : x = 159 是否同時 大於158、小於161,有 !
                                      y = 79 是否等於 79有 !
                                      z = -575 是否同時 大於-577、小於-574,有 !
當玩家所在的座標 (x , y , z) 都滿足條件後,就會執行 if 以下的事;

2. ( 158 , 79 , -575) : x = 158 是否同時 大於158、小於161,沒有 !
                                      y = 79 是否等於 79有 !
                                      z = -575 是否同時 大於-577、小於-574,有 !
當玩家所在座標 (x , y , z) 只要有一個條件不滿足,就不會執行。
/*********************/
             p.teleport(); 傳送,( )裡要填new Location( 世界名稱 , 座標x , 座標y , 座標z )。
             p.getWorld()  取得玩家所在的世界。

Example 5 -  仿副本傳送書

傳送紙 ? 還要在特定區域,管他三七二十一,隨便亂按一通啦!


果真吃鱉。恩 ? 紅色區域特別奇怪,站在上面按好了。


成功 !

我們有時候在玩RPG伺服器的時候,都會有 副本書 這種東西,但是都是要在副本入口前或是哪裡按才會將你傳送進去,在別的地方按是沒有任何效果的。說複雜嗎 ? 其實也還好,我這邊教的這種 副本書 的運作方式基礎:

首先 你必須新增一個自定義物品,確保它是獨一無二的 ( 第一節教過囉 )。
再來就是事件程式碼:
@EventHandler
public void onPlayerInteract(PlayerInteractEvent e) {
    Player p = e.getPlayer();
    int x = (int) p.getLocation().getX();
    int y = (int) p.getLocation().getY();
    int z = (int) p.getLocation().getZ();
/******************************************************/
    if((e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) && p.getItemInHand().equals(item01)) {
        if(x>25 && x<29 && z>-677 && z<-673 && y==65){

            p.sendMessage(ChatColor.GREEN + "傳送成功!");
            p.teleport(new Location(p.getWorld() , 27,65,-679));

        }else{
            p.sendMessage(ChatColor.RED + "必須在特定區域才可傳送!");
        }
    }
}
說明:事件 - PlayerInteractEvent 玩家與甚麼事情的互動事件。
           綠線 上方是上個例子已經講過的了,不懂得朋友們要拉上去看看囉。
                    下方則是重點。

           e.getAction() 取得觸發這個事件玩家的動作。
           Action.RIGHT_CLICK_AIR  對" 空氣 "點右鍵 這個動作
           Action.RIGHT_CLICK_BLOCK  對" 方塊 "點右鍵 這個動作

             * 符號 ||  :這是代表 或是 。也就是說,只要有達成其中一個就會滿足條件。
             * 符號 && 上個例子已經講過囉:而且
所以(e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)這一行的翻譯就是:『玩家的動作是對空氣點右鍵 或是 對方塊點右鍵』。

             p.getItemInHand().equals(甚麼)   取得觸發此事件玩家手上的物品為 甚麼

所以第一個條件判斷  if((e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) && p.getItemInHand().equals(item01)) 的翻譯就是:『如果觸發此事件的玩家對空氣點右鍵 或是 對方塊點右鍵 而且 手上要拿著 item01 』就會執行以下結果。
※要注意的一點是:"&&"的權限位置比" || " 還高,也就是說系統在執行此行時,會先從 && 開始看,才來看 || ,所以要用 || 來比較的區域要用括號括起來。

以下用顏色來表示系統判讀方式:
1.未括號 if ( example || example2 && example3 )
   判讀:如果 example 或是 example2和example3同時做 其中一個有滿足,執行以下。

2.括號後 if (( example || example2 ) && example3 )
   判讀:如果 example 或是 example2 其中一個有做 而且和 example3 同時做,執行以下。

if(x>25 && x<29 && z>-677 && z<-673 && y==65)這個是我們上一個範例已經講過的,判斷區域,比較特別的是 if 結尾後面的 else
通常是長這樣:
if(){
...
}else{
...
}
非常容易理解,就是說當 if 裡的條件判斷不成立時,就不會執行紅色的程式碼,而是執行藍色的程式碼;反過來說,當 if 裡的條件成立時,會直接執行紅色程式碼,而不理會藍色的。

總翻譯:
if((e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) && p.getItemInHand().equals(item01)) {
        if(x>25 && x<29 && z>-677 && z<-673 && y==65){
            p.teleport(new Location(p.getWorld() , 27,65,-679));
            p.sendMessage(ChatColor.GREEN + "傳送成功!");
            

        }else{
            p.sendMessage(ChatColor.RED + "必須在特定區域才可傳送!");
        }
    }
翻譯為 ( 符號我照樣寫上去好比照):
如果 (玩家的動作是對空氣點右鍵 對方塊點右鍵 而且 手上拿著 item01 ) {
    
如果 (玩家在此區域內) {
        發送訊息( "傳送成功" );
        傳送至 ( 此處 );
    }
如果上述條件不成立則{
        發送訊息 ("必須在特定區域才可傳送");
    }

}

有人發問,我想要過幾秒後再傳送過去,該如何寫 ?
詳情請見 #7 樓 mm大大所說明的程式碼。如有朋友們已經寫下這邊的程式碼,請改為mm大大說的程式碼哦~ 真是抱歉嘿 !

今天介紹了一小小小部分的事件寫法,我不可能全部都列出來如何寫,還得靠大家自己摸索摸索呢 !



第五節以後  在 #2 樓喔 ! 請往下拉吧~
107
-
板務人員:

1328 筆精華,前天 更新
一個月內新增 3
歡迎加入共同維護。


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】