#pragma once //////////////////////////////////////////////////////////////////////// // Event System - Make it easier to subscribe game events // // [Examples] // // Event::PlayerJoinEvent::subscribe([](const Event::PlayerJoinEvent& ev) { //Common situation - Const parameter "ev" // ev.mPlayer->sendText("hello world~"); // return true; // }); // // Event::PlayerChatEvent::subscribe_ref([](Event::PlayerChatEvent& ev) { //Need to modify event's parameters - Reference parameter "ev" // ev.mMessage = "[Plugin Modified] " + ev.mMessage; // return true; // }); // // auto listener = Event::PlayerPickupItemEvent::subscribe([](const Event::PlayerPickupItemEvent& ev) { // if(ev.mPlayer->getName() == "Jack") // return false; //Prevent events to be done - return false // else // return true; // }); // ...... // ...... // listener.remove(); //Remove this event listener // //////////////////////////////////////////////////////////////////////// #include <functional> #include <iterator> #include <list> #include <string> #include <unordered_map> #include "Global.h" #include "LoggerAPI.h" #include "llapi/mc/BlockInstance.hpp" #include "llapi/mc/MCRESULT.hpp" #include "LLAPI.h" #include "utils/WinHelper.h" class Actor; class ServerPlayer; class Player; class Block; class Mob; struct ActorDefinitionIdentifier; class ItemStack; class ActorDamageSource; class Certificate; class CommandRegistry; class MobEffectInstance; class Container; class WitherBoss; class ArmorStand; class Objective; struct ScoreboardId; namespace Event { ///////////////////////////// Impl ///////////////////////////// constexpr bool Ok = true; constexpr bool Cancel = false; template <typename EVENT> class EventManager { public: LIAPI static int addEventListener(std::string name, std::function<bool(EVENT)> callback); LIAPI static int addEventListenerRef(std::string name, std::function<bool(EVENT&)> callback); LIAPI static bool removeEventListener(int id); LIAPI static bool hasListener(); LIAPI static bool call(EVENT& ev); LIAPI static bool callToPlugin(std::string pluginName, EVENT& ev); }; template <typename EVENT> class EventListener { private: int listenerId; bool deleted = false; public: EventListener(int id) : listenerId(id) { } void remove() { if (!deleted) { deleted = true; EventManager<EVENT>::removeEventListener(listenerId); } } }; template <typename EVENT> class EventTemplate { public: static EventListener<EVENT> subscribe(std::function<bool(EVENT)> callback) { auto plugin = ll::getPlugin(GetCurrentModule()); return EventListener<EVENT>(EventManager<EVENT>::addEventListener(plugin ? plugin->name : "", callback)); } static EventListener<EVENT> subscribe_ref(std::function<bool(EVENT&)> callback) { auto plugin = ll::getPlugin(GetCurrentModule()); return EventListener<EVENT>(EventManager<EVENT>::addEventListenerRef(plugin ? plugin->name : "", callback)); } static void unsubscribe(const EventListener<EVENT>& listener) { listener.remove(); } static bool hasListener() { return EventManager<EVENT>::hasListener(); } bool call() { return EventManager<EVENT>::call(*(EVENT*)this); } bool callToPlugin(std::string pluginName) { return EventManager<EVENT>::callToPlugin(pluginName, *(EVENT*)this); } ////////////////////// For compatibility DO NOT UPDATE ////////////////////// protected: friend class EventManager<EVENT>; LIAPI static std::list<std::pair<string, std::function<bool(const EVENT&)>>> listeners; LIAPI static std::list<std::pair<string, std::function<bool(EVENT&)>>> listenersNoConst; ////////////////////// For compatibility DO NOT UPDATE ////////////////////// }; ///////////////////////////// Player Events ///////////////////////////// class PlayerPreJoinEvent : public EventTemplate<PlayerPreJoinEvent> { public: Player* mPlayer; string mIP; string mXUID; }; class PlayerJoinEvent : public EventTemplate<PlayerJoinEvent> { public: Player* mPlayer; }; class PlayerLeftEvent : public EventTemplate<PlayerLeftEvent> { public: Player* mPlayer; string mXUID; }; class PlayerRespawnEvent : public EventTemplate<PlayerRespawnEvent> { public: Player* mPlayer; }; class PlayerUseItemEvent : public EventTemplate<PlayerUseItemEvent> { public: Player* mPlayer; ItemStack* mItemStack; }; class PlayerUseItemOnEvent : public EventTemplate<PlayerUseItemOnEvent> { public: Player* mPlayer; ItemStack* mItemStack; BlockInstance mBlockInstance; unsigned char mFace; Vec3 mClickPos; }; class PlayerChatEvent : public EventTemplate<PlayerChatEvent> { public: Player* mPlayer; string mMessage; }; class PlayerChangeDimEvent : public EventTemplate<PlayerChangeDimEvent> { public: Player* mPlayer; int mToDimensionId; }; class PlayerJumpEvent : public EventTemplate<PlayerJumpEvent> { public: Player* mPlayer; }; class PlayerSneakEvent : public EventTemplate<PlayerSneakEvent> { public: Player* mPlayer; bool mIsSneaking; }; class PlayerAttackEvent : public EventTemplate<PlayerAttackEvent> { public: Player* mPlayer; Actor* mTarget; int mAttackDamage; }; class PlayerAttackBlockEvent : public EventTemplate<PlayerAttackBlockEvent> { public: Player* mPlayer; ItemStack* mItemStack; BlockInstance mBlockInstance; }; class PlayerDieEvent : public EventTemplate<PlayerDieEvent> { public: Player* mPlayer; ActorDamageSource* mDamageSource; }; class PlayerPickupItemEvent : public EventTemplate<PlayerPickupItemEvent> { public: Player* mPlayer; Actor* mItemEntity; ItemStack* mItemStack; }; class PlayerDropItemEvent : public EventTemplate<PlayerDropItemEvent> { public: Player* mPlayer; ItemStack* mItemStack; }; class PlayerEatEvent : public EventTemplate<PlayerEatEvent> { public: Player* mPlayer; ItemStack* mFoodItem; }; class PlayerConsumeTotemEvent : public EventTemplate<PlayerConsumeTotemEvent> { public: Player* mPlayer; }; class PlayerCmdEvent : public EventTemplate<PlayerCmdEvent> { public: Player* mPlayer; string mCommand; MCRESULT* mResult; }; class PlayerEffectChangedEvent : public EventTemplate<PlayerEffectChangedEvent> { public: enum class EventType { Add, Remove, Update }; Player* mPlayer; EventType mEventType; MobEffectInstance* mEffect; }; class PlayerStartDestroyBlockEvent : public EventTemplate<PlayerStartDestroyBlockEvent> { public: Player* mPlayer; BlockInstance mBlockInstance; }; class PlayerDestroyBlockEvent : public EventTemplate<PlayerDestroyBlockEvent> { public: Player* mPlayer; BlockInstance mBlockInstance; }; class PlayerPlaceBlockEvent : public EventTemplate<PlayerPlaceBlockEvent> { public: Player* mPlayer; BlockInstance mBlockInstance; }; class BlockPlacedByPlayerEvent : public EventTemplate<BlockPlacedByPlayerEvent> { public: Player* mPlayer; BlockInstance mBlockInstance; }; class PlayerOpenContainerEvent : public EventTemplate<PlayerOpenContainerEvent> { public: Player* mPlayer; BlockInstance mBlockInstance; Container* mContainer; }; class PlayerCloseContainerEvent : public EventTemplate<PlayerCloseContainerEvent> { public: Player* mPlayer; BlockInstance mBlockInstance; Container* mContainer; }; class PlayerInventoryChangeEvent : public EventTemplate<PlayerInventoryChangeEvent> { public: Player* mPlayer; int mSlot; ItemStack* mPreviousItemStack; ItemStack* mNewItemStack; }; class PlayerMoveEvent : public EventTemplate<PlayerMoveEvent> { public: Player* mPlayer; Vec3 mPos; }; class PlayerSprintEvent : public EventTemplate<PlayerSprintEvent> { public: Player* mPlayer; bool mIsSprinting; }; class PlayerSetArmorEvent : public EventTemplate<PlayerSetArmorEvent> { public: Player* mPlayer; int mSlot; ItemStack* mArmorItem; }; class PlayerUseRespawnAnchorEvent : public EventTemplate<PlayerUseRespawnAnchorEvent> { public: Player* mPlayer; BlockInstance mBlockInstance; }; class PlayerOpenContainerScreenEvent : public EventTemplate<PlayerOpenContainerScreenEvent> { public: Player* mPlayer; }; class PlayerUseFrameBlockEvent : public EventTemplate<PlayerUseFrameBlockEvent> { public: enum class Type { Use, Attack }; Type mType; Player* mPlayer; BlockInstance mBlockInstance; }; class PlayerScoreChangedEvent : public EventTemplate<PlayerScoreChangedEvent> { public: Player* mPlayer; int mScore; Objective* mObjective; ScoreboardId* mScoreboardId; }; class PlayerExperienceAddEvent : public EventTemplate<PlayerExperienceAddEvent> { public: Player* mPlayer; int mExp; }; class PlayerInteractEntityEvent : public EventTemplate<PlayerInteractEntityEvent> { public: enum class InteractiveMode { RightClick, LeftClick }; ServerPlayer* mPlayer; ActorRuntimeID mTargetId; InteractiveMode mInteractiveMode; }; ///////////////////////////// Block Events ///////////////////////////// class BlockInteractedEvent : public EventTemplate<BlockInteractedEvent> { public: BlockInstance mBlockInstance; Player* mPlayer; }; class BlockChangedEvent : public EventTemplate<BlockChangedEvent> { public: BlockInstance mPreviousBlockInstance; BlockInstance mNewBlockInstance; }; // TODO 没找到合适点位 class BlockExplodedEvent : public EventTemplate<BlockExplodedEvent> { public: BlockInstance mBlockInstance; Actor* mExplodeSource; }; class FireSpreadEvent : public EventTemplate<FireSpreadEvent> { public: BlockPos mTarget; int mDimensionId; }; class ContainerChangeEvent : public EventTemplate<ContainerChangeEvent> { public: Player* mPlayer; Actor* mActor; BlockInstance mBlockInstance; Container* mContainer; int mSlot; ItemStack* mPreviousItemStack; ItemStack* mNewItemStack; }; class ProjectileHitBlockEvent : public EventTemplate<ProjectileHitBlockEvent> { public: BlockInstance mBlockInstance; Actor* mSource; }; class RedStoneUpdateEvent : public EventTemplate<RedStoneUpdateEvent> { public: BlockInstance mBlockInstance; int mRedStonePower; bool mIsActivated; }; class HopperSearchItemEvent : public EventTemplate<HopperSearchItemEvent> { public: bool isMinecart; BlockInstance mHopperBlock; Vec3 mMinecartPos; int mDimensionId; }; class HopperPushOutEvent : public EventTemplate<HopperPushOutEvent> { public: Vec3 mPos; int mDimensionId; }; class PistonTryPushEvent : public EventTemplate<PistonTryPushEvent> { public: BlockInstance mPistonBlockInstance; BlockInstance mTargetBlockInstance; }; class PistonPushEvent : public EventTemplate<PistonPushEvent> { public: BlockInstance mPistonBlockInstance; BlockInstance mTargetBlockInstance; }; class FarmLandDecayEvent : public EventTemplate<FarmLandDecayEvent> { public: BlockInstance mBlockInstance; Actor* mActor; }; class LiquidSpreadEvent : public EventTemplate<LiquidSpreadEvent> { public: BlockInstance mBlockInstance; BlockPos mTarget; int mDimensionId; }; class CmdBlockExecuteEvent : public EventTemplate<CmdBlockExecuteEvent> { public: string mCommand; bool mIsMinecart; BlockInstance mBlockInstance; Actor* mMinecart; }; class BlockExplodeEvent : public EventTemplate<BlockExplodeEvent> { public: BlockInstance mBlockInstance; float mRadius; float mMaxResistance; bool mBreaking; bool mFire; }; ///////////////////////////// Entity Events ///////////////////////////// class EntityExplodeEvent : public EventTemplate<EntityExplodeEvent> { public: Actor* mActor; Vec3 mPos; BlockSource* mDimension; float mRadius; float mMaxResistance; bool mBreaking; bool mFire; }; class MobHurtEvent : public EventTemplate<MobHurtEvent> { public: Mob* mMob; ActorDamageSource* mDamageSource; int mDamage; }; class MobDieEvent : public EventTemplate<MobDieEvent> { public: Mob* mMob; ActorDamageSource* mDamageSource; }; class ProjectileHitEntityEvent : public EventTemplate<ProjectileHitEntityEvent> { public: Actor* mTarget; Actor* mSource; }; class WitherBossDestroyEvent : public EventTemplate<WitherBossDestroyEvent> { public: WitherBoss* mWitherBoss; AABB mDestroyRange = {{}, {}}; }; class EntityRideEvent : public EventTemplate<EntityRideEvent> { public: Actor* mRider; Actor* mVehicle; }; class EntityStepOnPressurePlateEvent : public EventTemplate<EntityStepOnPressurePlateEvent> { public: Actor* mActor; BlockInstance mBlockInstance; }; class NpcCmdEvent : public EventTemplate<NpcCmdEvent> { public: Actor* mNpc; std::string mCommand; Player* mPlayer; }; class ProjectileSpawnEvent : public EventTemplate<ProjectileSpawnEvent> { public: Actor* mShooter; ActorDefinitionIdentifier* mIdentifier; std::string mType; }; class ProjectileCreatedEvent : public EventTemplate<ProjectileCreatedEvent> { public: Actor* mShooter; Actor* mProjectile; }; class ArmorStandChangeEvent : public EventTemplate<ArmorStandChangeEvent> { public: ArmorStand* mArmorStand; Player* mPlayer; int mSlot; }; class EntityTransformEvent : public EventTemplate<EntityTransformEvent> { public: ActorUniqueID* mBeforeEntityUniqueId; Actor* mAfterEntity; }; ///////////////////////////// Other Events ///////////////////////////// class PostInitEvent : public EventTemplate<PostInitEvent> { }; class ServerStartedEvent : public EventTemplate<ServerStartedEvent> { }; class ServerStoppedEvent : public EventTemplate<ServerStoppedEvent> { }; class ConsoleCmdEvent : public EventTemplate<ConsoleCmdEvent> { public: std::string mCommand; }; class RegCmdEvent : public EventTemplate<RegCmdEvent> { public: CommandRegistry* mCommandRegistry; }; class ConsoleOutputEvent : public EventTemplate<ConsoleOutputEvent> { public: std::string mOutput; }; class PlayerBedEnterEvent : public EventTemplate<PlayerBedEnterEvent> { public: Player* mPlayer; BlockInstance* mBlockInstance; }; class ScriptPluginManagerEvent : public EventTemplate<ScriptPluginManagerEvent> { public: enum class Operation { Load, Unload, Reload }; enum class PluginType { SingleFile, // like .js / .lua PluginPackage, // like .llplugin UncompressedPackage // like plugins/nodejs/ABC }; Operation operation; std::string target; std::string otherInfo; std::string pluginExtention; bool success = false; PluginType pluginType; }; class MobSpawnEvent : public EventTemplate<MobSpawnEvent> { public: string mTypeName; Vec3 mPos; int mDimensionId; }; class FormResponsePacketEvent : public EventTemplate<FormResponsePacketEvent> { public: ServerPlayer* mServerPlayer; unsigned mFormId; string mJsonData; }; class ResourcePackInitEvent : public EventTemplate<ResourcePackInitEvent> { public: ResourcePackRepository* mRepo; }; }; // namespace Event