[1.10.2]Создание и обработка своего события

Eifel

Модератор
1,623
78
608
Привет!

Недавно появилась нужда сделать собственное событие. Полазив немного по классам, накидал одно событие, которое использую в своем моде. Поэтому решил поделиться примером простого создания и обработки своего события, может кому будет полезно.

И так, для примера, допустим у нас есть предмет, при использовании которого, если у игрока меньше 10 жизней, он восстанавливал ему все здоровье. И мы хотим создать событие, которое будет зажигаться при этом использовании и чтобы кто-то потом мог при определенных условиях, к примеру, его отменить или сделать манипуляции над игроком, который его юзнул или самим предметом.

Для начала надо создать заготовку, т.е. сам предмет:
 
Код:
public class ItemEvent extends Item {

public ItemEvent(String ulocalizedName) {
this.setUnlocalizedName(ulocalizedName);
this.setRegistryName(ulocalizedName);
this.setMaxStackSize(1);
}


@Override
public ActionResult<ItemStack> onItemRightClick(ItemStack itemStack, World world, EntityPlayer player, EnumHand hand) {

if(!FMLCommonHandler.instance().getEffectiveSide().isClient()){
//тут будем создавать экземпляр нашего события и отправлять его в шину событий форджа для дальнейшей обработки


} 
return new ActionResult(EnumActionResult.SUCCESS, itemStack);
}

}

Дальше создаем класс самого события, который должен унаследовать класс net.minecraftforge.fml.common.eventhandler.Event:
Код:
public class MyItemUsedEvent extends Event {

//создаем игрока и ItemStack предмета который юзаем, 
//в дальнейшем мы будем их передавать в конструктор нашего события для того, 
//чтоб потом достать их в обработчике
private EntityPlayer player;
private ItemStack stack;


//Инициализируем нашего игрока и предмет
public MyItemUsedEvent(EntityPlayer player, ItemStack stack){
//в данном случае вызывать конструктор супер-класса бесполезно.
super();

this.player = player;
this.stack = stack;
}

//Переопределяем этот метод, если хотим чтоб наше событие можно было отменить
public boolean isCancelable()
   {
       return true;
   }

//Поскольку наш игрок и предмет приватные, создаем геттеры для доступа к ним
public EntityPlayer getPlayer(){
return this.player;
}

public ItemStack getItem(){
return this.stack;
}
}


Таким образом создаем класс события, которое будет принимать игрока и ItemStack с нашим предметом для их дальнейшего доставания и использования в обработчике.




Теперь нужно сделать так, чтобы зажечь наше событие при использовании предмета:

В методе предмета onItemRightClick пишем:
Код:
@Override
public ActionResult<ItemStack> onItemRightClick(ItemStack itemStack, World world, EntityPlayer player, EnumHand hand) {

if(!FMLCommonHandler.instance().getEffectiveSide().isClient()){
//создаем экземпляр нашего события и передаем в него игрока и ItemStack с предметом. Делаем это на серверной стороне
MyItemUsedEvent event = new MyItemUsedEvent(player, itemStack);
//зажигаем наше событие в шине MinecraftForge.EVENT_BUS, да бы его можно было обработать
MinecraftForge.EVENT_BUS.post(event);
//если у игрока меньше 10 хп и наше событие никто не отменил то восстановим ему все хп
if(player.getHealth() < 10.0f && !event.isCanceled()){
player.heal(player.getMaxHealth());
}

} 
return new ActionResult(EnumActionResult.SUCCESS, itemStack);
}



Готово. Теперь при каждом использовании, сработает событие использования предмета, которое мы можем обработать.

Обработать событие можно тем же путем, как и любые другие:
Код:
 @SubscribeEvent
 public void onMyItemUsing(MyItemUsedEvent event){
 //теперь мы можем достать игрока, который использовал предмет и ItemStack с предметом
 //с помощью методов которые мы определили в классе нашего события
 EntityPlayer player = event.getPlayer();
 ItemStack stack = event.getItem();
 //и делать тут что угодно. Например можно отменить это событие, тогда игрока не будет лечить
 event.setCanceled(true);
 
 }



Таким образом мы получили событие, которое происходит во время использования нашего предмета. Его можно обработать и использовать в разных целях. Для ранних версий, и даже для 1.7.10, не пробовал, но думаю там принцип тот же.

Спасибо за внимание.

P.s. мой первый гайд, жду помидоров:)
 
5,018
47
783
Итак что за класс MyItemUsedEvent? Закинь его сюда тоже. Давно было интересно как писать собственные эвенты
 

Eifel

Модератор
1,623
78
608
Maxik001 написал(а):
Итак что за класс MyItemUsedEvent? Закинь его сюда тоже. Давно было интересно как писать собственные эвенты

посмотри внимательно, там все есть(второй спойлер))
 
2,505
81
397
Зачем ивенты для своего мода? Только лишняя нагрузка.


Ты думаешь, что кто-то будет писать аддоны? Маловероятно
 

Eifel

Модератор
1,623
78
608
Не в моем моде дело, я уже заменил эту тему более пригодным. Но раз уже встретился с этим, то решил написать как это делать
 
1,990
18
105
Dahaka написал(а):
Зачем ивенты для своего мода? Только лишняя нагрузка.

Неправда, нагрузки там крайне мало. Фордж для каждого обработчика событий создает отдельный класс (чтобы обходиться без рефлексии), и рассылает событие только нужным листенерам. В итоге все работает ОЧЕНЬ быстро.
А пригодиться это может, если ты пишешь огромный мод, состоящий из множества под-модулей, некоторые из которых должны работать независимо (например, полезно для собственного "ядра", которое может использоваться в разных модах). 
Кейс, конечно, описал редкий, но я привязался к нагрузке :D
 
2,505
81
397
Oldestkon написал(а):
Dahaka написал(а):
Зачем ивенты для своего мода? Только лишняя нагрузка.

Неправда, нагрузки там крайне мало. Фордж для каждого обработчика событий создает отдельный класс (чтобы обходиться без рефлексии), и рассылает событие только нужным листенерам. В итоге все работает ОЧЕНЬ быстро.
А пригодиться это может, если ты пишешь огромный мод, состоящий из множества под-модулей, некоторые из которых должны работать независимо (например, полезно для собственного "ядра", которое может использоваться в разных модах). 
Кейс, конечно, описал редкий, но я привязался к нагрузке :D

Ну дак это все понятно. Просто рассыл по всем листенерам все-равно дольше, чем просто вызов метода :)
 
3,005
192
592
Сверху