package me.km.snuviscript; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.stream.Collectors; import me.hammerle.snuviscript.code.Script; import me.hammerle.snuviscript.code.SnuviUtils; import me.hammerle.snuviscript.inputprovider.Variable; import me.km.utils.Utils; import me.km.entities.EntityHuman; import me.km.entities.EntityItemProjectile; import me.km.events.CommandEvent; import me.km.events.PlayerTabListNameEvent; import me.km.inventory.ModInventory; import me.km.permissions.PermissionManager; import me.km.utils.Location; import net.minecraft.command.ICommandSource; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.passive.SheepEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.ClickType; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.EntityRayTraceResult; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.event.ServerChatEvent; import net.minecraftforge.event.entity.EntityMountEvent; import net.minecraftforge.event.entity.ProjectileImpactEvent; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.living.*; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.entity.player.EntityItemPickupEvent; import net.minecraftforge.event.entity.player.FillBucketEvent; import net.minecraftforge.event.entity.player.ItemFishedEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.ExplosionEvent; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.event.entity.player.PlayerEvent; public class ScriptEvents { private final Scripts scripts; private final MinecraftServer server; private final PermissionManager perms; public ScriptEvents(Scripts scripts, MinecraftServer server, PermissionManager perms) { this.scripts = scripts; this.server = server; this.perms = perms; } // ------------------------------------------------------------------------- // basics // ------------------------------------------------------------------------- private void handleEvent(PlayerEntity p, String event, Consumer<Script> before, Consumer<Script> after) { scripts.getScriptManager().callEvent(event, (sc) -> { ScriptVars.setPlayerVars(sc, p); before.accept(sc); }, after); if(p != null) { Script data = scripts.getScript(p); if(data != null) { scripts.getScriptManager().callEvent(event, data, (sc) -> { ScriptVars.setPlayerVars(sc, p); before.accept(sc); }, after); } } } private void handleEvent(PlayerEntity p, String event, Consumer<Script> before) { handleEvent(p, event, before, null); } private void ifVarNotNull(Script sc, String name, Consumer<Variable> c) { Variable v = sc.getVar(name); if(v != null) { c.accept(v); } } private void simpleCancel(Script sc, Event e, String name) { try { ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print(String.format("invalid var in '%s' event", name), ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } } // ------------------------------------------------------------------------- // events // ------------------------------------------------------------------------- public void onPlayerDataTick(PlayerEntity p, String var) { handleEvent(p, "player_data_tick", sc -> { sc.setVar("var", var); }); } public void onPlayerMove(PlayerEntity p, int id) { handleEvent(p, "player_move", sc -> { sc.setVar("id", (double) id); }); } public boolean onInventoryClick(Script script, ITextComponent text, ModInventory inv, int slot, ClickType click, PlayerEntity p) { scripts.getScriptManager().callEvent("inv_click", script, sc -> { ScriptVars.setPlayerVars(sc, p); sc.setVar("inv", inv); sc.setVar("inv_id", (double) inv.getModId()); sc.setVar("inv_name", text.getFormattedText()); sc.setVar("inv_slot", (double) slot); ScriptVars.setItemVars(sc, inv.getStackInSlot(slot)); sc.setVar("cancel", false); }, null); Variable v = script.getVar("cancel"); return v != null && v.getBoolean(script); } public void onInventoryClose(Script script, ITextComponent text, ModInventory inv, PlayerEntity p) { scripts.getScriptManager().callEvent("inv_close", script, sc -> { ScriptVars.setPlayerVars(sc, p); sc.setVar("inv", inv); sc.setVar("inv_id", (double) inv.getModId()); sc.setVar("inv_name", text.getFormattedText()); }, null); } public void onHumanHurt(PlayerEntity p, EntityHuman h) { handleEvent(p, "human_hurt", sc -> ScriptVars.setEntityVars(sc, h)); } @SubscribeEvent public void onPlayerPostRespawn(PlayerEvent.PlayerRespawnEvent e) { handleEvent(e.getPlayer(), "player_post_respawn", sc -> {}); } public void onPlayerPreRespawn(PlayerEntity p) { handleEvent(p, "player_pre_respawn", sc -> {}); } @SubscribeEvent public void onPlayerDamage(LivingHurtEvent e) { if(!(e.getEntityLiving() instanceof ServerPlayerEntity)) { return; } PlayerEntity p = (PlayerEntity) e.getEntityLiving(); handleEvent(p, "player_hurt", (sc) -> { sc.setVar("player_killed", p.getHealth() <= e.getAmount()); sc.setVar("player_damage", (double) e.getAmount()); sc.setVar("player_damage_cause", e.getSource()); PlayerEntity ent = Utils.getDamager(e.getSource()); if(ent != null) { sc.setVar("player_involved", true); ScriptVars.setSecPlayer(sc, ent); } else { sc.setVar("player_involved", false); } sc.setVar("cancel", e.isCanceled()); }, (sc) -> { try { ifVarNotNull(sc, "player_damage", v -> e.setAmount(v.getFloat(sc))); ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'player_hurt' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } @SubscribeEvent public void onPlayerAttack(LivingAttackEvent e) { LivingEntity liv = e.getEntityLiving(); if(liv instanceof PlayerEntity) { PlayerEntity p = (PlayerEntity) liv; handleEvent(p, "player_is_attacked", (sc) -> { sc.setVar("player_killed", p.getHealth() <= e.getAmount()); sc.setVar("player_damage_cause", e.getSource()); PlayerEntity ent = Utils.getDamager(e.getSource()); if(ent != null) { sc.setVar("player_involved", true); ScriptVars.setSecPlayer(sc, ent); } else { sc.setVar("player_involved", false); } sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "player_is_attacked"); }); } else { PlayerEntity p = Utils.getDamager(e.getSource()); if(p != null) { handleEvent(p, "player_attacks", (sc) -> { ScriptVars.setEntityVars(sc, liv); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "player_attacks"); }); } } } @SubscribeEvent public void onPlayerDamage(LivingHealEvent e) { if(e.getEntityLiving() instanceof PlayerEntity) { handleEvent((PlayerEntity) e.getEntityLiving(), "player_heal", (sc) -> { sc.setVar("heal", (double) e.getAmount()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { try { ifVarNotNull(sc, "heal", v -> e.setAmount(v.getFloat(sc))); ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'player_heal' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } } @SubscribeEvent public void onLivingDeath(LivingDeathEvent e) { if(!(e.getEntityLiving() instanceof PlayerEntity)) { PlayerEntity p = Utils.getDamager(e.getSource()); handleEvent(p, "entity_death", (sc) -> { sc.setVar("entity_damage_cause", e.getSource()); LivingEntity ent = e.getEntityLiving(); ScriptVars.setEntityVars(sc, ent); sc.setVar("player_involved", p != null); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "entity_death"); }); return; } PlayerEntity p = (PlayerEntity) e.getEntity(); handleEvent(p, "player_death", (sc) -> { sc.setVar("clear", false); sc.setVar("player_damage_cause", e.getSource()); PlayerEntity ent = Utils.getDamager(e.getSource()); if(ent != null) { ScriptVars.setSecPlayer(sc, ent); } sc.setVar("cancel", e.isCanceled()); }, (sc) -> { try { Variable clear = sc.getVar("clear"); if(clear != null && clear.getBoolean(sc)) { p.inventory.clear(); } ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'player_death' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } @SubscribeEvent public void onEntityDamage(LivingHurtEvent e) { PlayerEntity p = Utils.getDamager(e.getSource()); if(p == null) { return; } handleEvent(p, "entity_hurt", (sc) -> { sc.setVar("entity_killed", e.getEntityLiving().getHealth() <= e.getAmount()); ScriptVars.setEntityVars(sc, e.getEntity()); sc.setVar("entity_damage", (double) e.getAmount()); sc.setVar("entity_damage_cause", e.getSource()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { try { ifVarNotNull(sc, "entity_damage", v -> e.setAmount(v.getFloat(sc))); ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'entity_hurt' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } @SubscribeEvent public void onEntityDrop(LivingDropsEvent e) { try { PlayerEntity p = Utils.getDamager(e.getSource()); handleEvent(p, "entity_drop", (sc) -> { sc.setVar("drops", e.getDrops()); ScriptVars.setEntityVars(sc, e.getEntityLiving()); sc.setVar("player_involved", p != null); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "entity_drop"); }); } catch(NullPointerException ex) { scripts.getLogger().print(ex); } } @SubscribeEvent public void onPlayerDrop(LivingDropsEvent e) { if(!(e.getEntityLiving() instanceof PlayerEntity)) { return; } handleEvent((PlayerEntity) e.getEntityLiving(), "player_drop", (sc) -> { sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "player_drop"); }); } @SubscribeEvent public void onProjectileHit(ProjectileImpactEvent e) { Entity hitEntity; boolean hit; if(e.getRayTraceResult().getType() == RayTraceResult.Type.ENTITY && e.getRayTraceResult() instanceof EntityRayTraceResult) { hit = true; hitEntity = ((EntityRayTraceResult) e.getRayTraceResult()).getEntity(); } else { hit = false; hitEntity = null; } handleEvent(Utils.getPlayerFromProjectile(e.getEntity()), "throw_hit", (sc) -> { sc.setVar("is_entity_hit", hit); sc.setVar("entity_hit", hitEntity); ScriptVars.setEntityVars(sc, e.getEntity()); }); } public void onEntityItemProjectileHit(EntityItemProjectile ent, PlayerEntity p, ItemStack stack, List<Entity> ents) { handleEvent(p, "item_hit", (sc) -> { ScriptVars.setEntityVars(sc, ent); ScriptVars.setItemVars(sc, stack); sc.setVar("entities", ents); }); } @SubscribeEvent public void onEntityShear(PlayerInteractEvent.EntityInteract e) { if(e.getHand() == Hand.OFF_HAND || !(e.getTarget() instanceof SheepEntity)) { return; } PlayerEntity p = e.getEntityPlayer(); if(p.getHeldItemMainhand().getItem() != Items.SHEARS) { return; } SheepEntity sheep = (SheepEntity) e.getTarget(); handleEvent(p, "entity_shear", (sc) -> { ScriptVars.setEntityVars(sc, sheep); sc.setVar("entity_sheared", sheep.getSheared()); sc.setVar("entity_color", sheep.getFleeceColor().toString()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "entity_shear"); }); } @SubscribeEvent public void onBlockBreak(BlockEvent.BreakEvent e) { handleEvent(e.getPlayer(), "block_break", (sc) -> { ScriptVars.setBlockVars(sc, e.getWorld(), e.getPos()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "block_break"); }); } @SubscribeEvent public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent e) { PlayerEntity p = e.getPlayer(); if(p == null) { return; } handleEvent(p, "player_login", (sc) -> { PlayerList list = server.getPlayerList(); sc.setVar("is_banned", list.getBannedPlayers().isBanned(p.getGameProfile())); sc.setVar("is_whitelisted", list.getWhitelistedPlayers().isWhitelisted(p.getGameProfile())); }); } @SubscribeEvent public void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent e) { PlayerEntity p = e.getPlayer(); if(p == null || e.getPlayer().ticksExisted < 20) { return; } handleEvent(p, "player_logout", sc -> {}); } @SubscribeEvent public void onBucketFill(FillBucketEvent e) { handleEvent(e.getEntityPlayer(), "bucket_use", (sc) -> { RayTraceResult ray = e.getTarget(); if(ray != null || ray.hitInfo != null || ray.hitInfo instanceof BlockPos) { BlockPos pos = (BlockPos) ray.hitInfo; sc.setVar("has_block", true); ScriptVars.setBlockVars(sc, e.getWorld(), pos); } else { sc.setVar("has_block", false); } sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "bucket_use"); }); } @SubscribeEvent public void onBlockPlace(BlockEvent.EntityPlaceEvent e) { if(!(e.getEntity() instanceof PlayerEntity)) { return; } handleEvent((PlayerEntity) e.getEntity(), "block_place", (sc) -> { sc.setVar("block_type_after", e.getPlacedBlock().getBlock().getRegistryName()); ScriptVars.setBlockVars(sc, e.getWorld(), e.getPos()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "block_place"); }); } @SubscribeEvent public void onRightClickBlock(PlayerInteractEvent.RightClickBlock e) { if(e.getHand() == Hand.OFF_HAND) { return; } handleEvent(e.getEntityPlayer(), "block_click", (sc) -> { sc.setVar("action", "right"); ScriptVars.setBlockVars(sc, e.getWorld(), e.getPos()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "block_click"); }); } @SubscribeEvent public void onLeftClickBlock(PlayerInteractEvent.LeftClickBlock e) { if(e.getHand() == Hand.OFF_HAND) { return; } handleEvent(e.getEntityPlayer(), "block_click", (sc) -> { sc.setVar("action", "left"); ScriptVars.setBlockVars(sc, e.getWorld(), e.getPos()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "block_click"); }); } @SubscribeEvent(receiveCanceled = true) public void onEntityClick(PlayerInteractEvent.EntityInteract e) { if(e.getHand() != Hand.OFF_HAND) { handleEvent(e.getEntityPlayer(), "entity_click", (sc) -> { ScriptVars.setEntityVars(sc, e.getTarget()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "entity_click"); }); } } @SubscribeEvent public void onFishing(ItemFishedEvent e) { handleEvent(e.getEntityPlayer(), "fishing", (sc) -> { sc.setVar("drops", e.getDrops()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "fishing"); }); } @SubscribeEvent public void onItemClick(PlayerInteractEvent.RightClickItem e) { handleEvent(e.getEntityPlayer(), "item_air_click", (sc) -> { ScriptVars.setItemVars(sc, e.getItemStack()); sc.setVar("hand", e.getHand().toString()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "item_air_click"); }); } public void onArmSwing(PlayerEntity p, Hand hand) { handleEvent(p, "arm_swing", (sc) -> { sc.setVar("hand", hand); }); } @SubscribeEvent public void onItemUseStart(LivingEntityUseItemEvent.Start e) { if(!(e.getEntityLiving() instanceof PlayerEntity)) { return; } handleEvent((PlayerEntity) e.getEntityLiving(), "item_use_start", (sc) -> { sc.setVar("duration", (double) e.getDuration()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { try { ifVarNotNull(sc, "duration", v -> e.setDuration(v.getInt(sc))); ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'item_use_start' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } @SubscribeEvent public void onConsuming(LivingEntityUseItemEvent.Finish e) { if(!(e.getEntityLiving() instanceof PlayerEntity)) { return; } handleEvent((PlayerEntity) e.getEntityLiving(), "item_use_finish", (sc) -> { sc.setVar("result_stack", e.getResultStack()); }); } @SubscribeEvent public void onCrafting(PlayerEvent.ItemCraftedEvent e) { handleEvent(e.getPlayer(), "craft", (sc) -> { ScriptVars.setItemVars(sc, e.getCrafting()); }); } @SubscribeEvent public void onItemDrop(ItemTossEvent e) { handleEvent(e.getPlayer(), "player_toss", (sc) -> { ScriptVars.setItemVars(sc, e.getEntityItem().getItem()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "player_toss"); }); } @SubscribeEvent public void onItemPickup(EntityItemPickupEvent e) { handleEvent(e.getEntityPlayer(), "player_pickup", (sc) -> { ScriptVars.setEntityVars(sc, e.getItem()); ScriptVars.setItemVars(sc, e.getItem().getItem()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "player_pickup"); }); } @SubscribeEvent public void onVehicleEnter(EntityMountEvent e) { if(!(e.getEntityMounting() instanceof PlayerEntity)) { return; } PlayerEntity p = (PlayerEntity) e.getEntityMounting(); handleEvent(p, "entity_mount", (sc) -> { sc.setVar("mounting", e.isMounting()); ScriptVars.setEntityVars(sc, e.getEntityBeingMounted()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "entity_mount"); }); } @SubscribeEvent public void onPlayerUsePortal(PlayerEvent.PlayerChangedDimensionEvent e) { handleEvent(e.getPlayer(), "portal", (sc) -> { sc.setVar("from", e.getFrom().getRegistryName().getPath()); sc.setVar("to", e.getTo().getRegistryName().getPath()); }); } public void onCommand(CommandEvent e) { handleEvent(e.getPlayer(), "command", (sc) -> { sc.setVar("command", e.getName()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { try { ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'command' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } public void onCustomCommand(PlayerEntity p, String command, String[] args) { handleEvent(p, "custom_command", (sc) -> { sc.setVar("command", command); if(args.length == 0) { sc.setVar("args", new ArrayList<>()); } else { sc.setVar("args", Arrays.stream(args).map(s -> SnuviUtils.convert(s)).collect(Collectors.toList())); } }); } public void onFunctionKey(ServerPlayerEntity p, int key) { handleEvent(p, "function_key", (sc) -> { sc.setVar("key", (double) key); }); } @SubscribeEvent public void onChatEvent(ServerChatEvent e) { handleEvent(e.getPlayer(), "chat", (sc) -> { String text = e.getMessage(); if(perms.hasPermission(e.getPlayer(), "color")) { text = text.replace('&', 'ยง'); } else { text = text.replaceAll("&.", ""); } sc.setVar("message", text); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { try { ifVarNotNull(sc, "message", v -> e.setComponent(new StringTextComponent(v.getString(sc)))); ifVarNotNull(sc, "cancel", v -> e.setCanceled(v.getBoolean(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'chat' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } public void onGetPlayerName(PlayerTabListNameEvent e) { handleEvent(e.getPlayer(), "tab_list", (sc) -> { sc.setVar("tab_name", e.getName()); }, (sc) -> { try { ifVarNotNull(sc, "tab_name", v -> e.setName(v.getString(sc))); } catch(Exception ex) { scripts.getLogger().print("invalid var in 'tab_list' event", ex, null, sc.getName(), sc, sc.getActiveSourceLine()); } }); } @SubscribeEvent(priority = EventPriority.HIGHEST) public void onExplosion(ExplosionEvent.Start e) { e.setCanceled(true); handleEvent(null, "explosion", (sc) -> { sc.setVar("loc", new Location(e.getWorld(), e.getExplosion().getPosition())); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "explosion"); }); } private static String getName(ICommandSource cs) { if(cs instanceof PlayerEntity) { return ((PlayerEntity) cs).getName().getFormattedText(); } else if(cs instanceof MinecraftServer) { return "Server"; } return null; } public void onMissingCommand(ICommandSource cs, String command) { PlayerEntity p = null; if(cs instanceof PlayerEntity) { p = (PlayerEntity) cs; } handleEvent(p, "missing_command", (sc) -> { sc.setVar("command_name", command); sc.setVar("sender_name", getName(cs)); }); } public void onMissingPermission(ICommandSource cs, String command) { PlayerEntity p = null; if(cs instanceof PlayerEntity) { p = (PlayerEntity) cs; } handleEvent(p, "missing_perm", (sc) -> { sc.setVar("command_name", command); sc.setVar("sender_name", getName(cs)); }); } @SubscribeEvent(priority = EventPriority.HIGHEST) public void onEntityHit(AttackEntityEvent e) { handleEvent(e.getPlayer(), "player_attack_entity", (sc) -> { ScriptVars.setEntityVars(sc, e.getTarget()); sc.setVar("cancel", e.isCanceled()); }, (sc) -> { simpleCancel(sc, e, "player_attack_entity"); }); } }