Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EvtMoveOn bug fixes #4270

Merged
merged 2 commits into from
Aug 30, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 84 additions & 112 deletions src/main/java/ch/njol/skript/events/EvtMoveOn.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,6 @@
*/
package ch.njol.skript.events;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.plugin.EventExecutor;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.SkriptConfig;
import ch.njol.skript.SkriptEventHandler;
Expand All @@ -46,11 +29,30 @@
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.Trigger;
import ch.njol.skript.registrations.Classes;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.plugin.EventExecutor;
import org.eclipse.jdt.annotation.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;


public class EvtMoveOn extends SelfRegisteringSkriptEvent { // TODO on jump

static {
// Register EvtPressurePlate before EvtMoveOn, https://github.com/SkriptLang/Skript/issues/2555
new EvtPressurePlate();
Skript.registerEvent("Move On", EvtMoveOn.class, PlayerMoveEvent.class, "(step|walk)[ing] (on|over) %*itemtypes%")
.description("Called when a player moves onto a certain type of block. Please note that using this event can cause lag if there are many players online.")
.examples("on walking on dirt or grass:", "on stepping on stone:")
Expand All @@ -60,98 +62,82 @@ public class EvtMoveOn extends SelfRegisteringSkriptEvent { // TODO on jump
/**
* Actual fence blocks and fence gates.
*/
private static final ItemType fencePart = Aliases.javaItemType("fence part");
private static final ItemType FENCE_PART = Aliases.javaItemType("fence part");

final static HashMap<Material, List<Trigger>> itemTypeTriggers = new HashMap<>();
@SuppressWarnings("null")
ItemType[] types = null;
private static final HashMap<Material, List<Trigger>> ITEM_TYPE_TRIGGERS = new HashMap<>();

@SuppressWarnings("ConstantConditions")
private ItemType[] types = null;

private static boolean registeredExecutor = false;
private final static EventExecutor executor = new EventExecutor() {
@SuppressWarnings("null")
@Override
public void execute(final @Nullable Listener l, final @Nullable Event event) throws EventException {
if (event == null)
private static final EventExecutor executor = (l, event) -> {
PlayerMoveEvent e = (PlayerMoveEvent) event;
Location from = e.getFrom(), to = e.getTo();

if (!ITEM_TYPE_TRIGGERS.isEmpty()) {
Block block = getOnBlock(to);
if (block == null || block.getType() == Material.AIR)
return;
Material id = block.getType();
List<Trigger> ts = ITEM_TYPE_TRIGGERS.get(id);
if (ts == null)
return;
int y = getBlockY(to.getY(), id);
if (to.getWorld().equals(from.getWorld()) && to.getBlockX() == from.getBlockX() && to.getBlockZ() == from.getBlockZ()
&& y == getBlockY(from.getY(), getOnBlock(from).getType()) && getOnBlock(from).getType() == id)
return;
final PlayerMoveEvent e = (PlayerMoveEvent) event;
final Location from = e.getFrom(), to = e.getTo();

if (!itemTypeTriggers.isEmpty()) {
final Block block = getOnBlock(to);
if (block == null || block.getType() == Material.AIR)
return;
final Material id = block.getType();
final List<Trigger> ts = itemTypeTriggers.get(id);
if (ts == null)
return;
final int y = getBlockY(to.getY(), id);
if (to.getWorld().equals(from.getWorld()) && to.getBlockX() == from.getBlockX() && to.getBlockZ() == from.getBlockZ()
&& y == getBlockY(from.getY(), getOnBlock(from).getType()) && getOnBlock(from).getType() == id)
return;
SkriptEventHandler.logEventStart(e);
triggersLoop: for (final Trigger t : ts) {
final EvtMoveOn se = (EvtMoveOn) t.getEvent();
for (final ItemType i : se.types) {
if (i.isOfType(block)) {
SkriptEventHandler.logTriggerStart(t);
t.execute(e);
SkriptEventHandler.logTriggerEnd(t);
continue triggersLoop;
}

SkriptEventHandler.logEventStart(e);
triggersLoop: for (Trigger t : ts) {
EvtMoveOn se = (EvtMoveOn) t.getEvent();
for (ItemType i : se.types) {
if (i.isOfType(block)) {
SkriptEventHandler.logTriggerStart(t);
t.execute(e);
SkriptEventHandler.logTriggerEnd(t);
continue triggersLoop;
}
}
SkriptEventHandler.logEventEnd();
}
SkriptEventHandler.logEventEnd();
}
};

@Nullable
final static Block getOnBlock(final Location l) {
private static Block getOnBlock(Location l) {
Block block = l.getWorld().getBlockAt(l.getBlockX(), (int) (Math.ceil(l.getY()) - 1), l.getBlockZ());
if (block.getType() == Material.AIR && Math.abs((l.getY() - l.getBlockY()) - 0.5) < Skript.EPSILON) { // Fences
block = l.getWorld().getBlockAt(l.getBlockX(), l.getBlockY() - 1, l.getBlockZ());
if (!fencePart.isOfType(block))
if (!FENCE_PART.isOfType(block))
return null;
}
return block;
}

final static int getBlockY(final double y, final Material id) {
if (fencePart.isOfType(id) && Math.abs((y - Math.floor(y)) - 0.5) < Skript.EPSILON)
private static int getBlockY(double y, Material id) {
if (FENCE_PART.isOfType(id) && Math.abs((y - Math.floor(y)) - 0.5) < Skript.EPSILON)
return (int) Math.floor(y) - 1;
return (int) Math.ceil(y) - 1;
}

public static Block getBlock(final PlayerMoveEvent e) {
public static Block getBlock(PlayerMoveEvent e) {
return e.getTo().clone().subtract(0, 0.5, 0).getBlock();
}

@SuppressWarnings("unchecked")
@Override
public boolean init(final Literal<?>[] args, final int matchedPattern, final ParseResult parser) {
// if (parser.regexes.get(0).group().equalsIgnoreCase("<block>")/* && isValidatingInput*/)
// return true;
// final Matcher m = Pattern.compile("<block:(.+)>").matcher(parser.regexes.get(0).group());
// if (m.matches()) {
// final Block b = (Block) Skript.deserialize("block", m.group(1));
// if (b == null)
// return false;
// world = b.getWorld();
// x = b.getX();
// y = b.getY();
// z = b.getZ();
// } else {
@SuppressWarnings("unchecked")
final Literal<? extends ItemType> l = (Literal<? extends ItemType>) args[0];//SkriptParser.parseLiteral(parser.regexes.get(0).group(), ItemType.class, ParseContext.EVENT);
public boolean init(Literal<?>[] args, int matchedPattern, ParseResult parseResult) {
Literal<? extends ItemType> l = (Literal<? extends ItemType>) args[0];
if (l == null)
return false;
types = l.getAll();
for (final ItemType t : types) {
for (ItemType t : types) {
if (t.isAll()) {
Skript.error("Can't use an 'on walk' event with an alias that matches all blocks");
return false;
}
boolean hasBlock = false;
for (final ItemData d : t) {
for (ItemData d : t) {
if (d.getType().isBlock() && d.getType() != Material.AIR) // don't allow air
hasBlock = true;
}
Expand All @@ -160,64 +146,50 @@ public boolean init(final Literal<?>[] args, final int matchedPattern, final Par
return false;
}
}
// }
return true;
}

@Override
public String toString(final @Nullable Event e, final boolean debug) {
return "walk on " + Classes.toString(types, false);
// return "walk on " + (types != null ? Skript.toString(types, false) : "<block:" + world.getName() + ":" + x + "," + y + "," + z + ">");
}

@Override
public void register(final Trigger trigger) {
// if (types == null) {
// final BlockLocation l = new BlockLocation(world, x, y, z);
// List<Trigger> ts = blockTriggers.get(l);
// if (ts == null)
// blockTriggers.put(l, ts = new ArrayList<Trigger>());
// ts.add(trigger);
// } else {
for (final ItemType t : types) {
for (final ItemData d : t) {
public void register(Trigger trigger) {
Set<Material> materialSet = new HashSet<>();
for (ItemType t : types) {
for (ItemData d : t) {
if (!d.getType().isBlock())
continue;
List<Trigger> ts = itemTypeTriggers.get(d.getType());
if (ts == null)
itemTypeTriggers.put(d.getType(), ts = new ArrayList<>());
ts.add(trigger);
materialSet.add(d.getType());
}
}
// }

for (Material material : materialSet) {
List<Trigger> ts = ITEM_TYPE_TRIGGERS.computeIfAbsent(material, k -> new ArrayList<>());
ts.add(trigger);
}

if (!registeredExecutor) {
Bukkit.getPluginManager().registerEvent(PlayerMoveEvent.class, new Listener() {}, SkriptConfig.defaultEventPriority.value(), executor, Skript.getInstance(), true);
registeredExecutor = true;
}
}

@Override
public void unregister(final Trigger t) {
// final Iterator<Entry<BlockLocation, List<Trigger>>> i = blockTriggers.entrySet().iterator();
// while (i.hasNext()) {
// final List<Trigger> ts = i.next().getValue();
// ts.remove(t);
// if (ts.isEmpty())
// i.remove();
// }
final Iterator<Entry<Material, List<Trigger>>> i2 = itemTypeTriggers.entrySet().iterator();
public void unregister(Trigger t) {
Iterator<Entry<Material, List<Trigger>>> i2 = ITEM_TYPE_TRIGGERS.entrySet().iterator();
while (i2.hasNext()) {
final List<Trigger> ts = i2.next().getValue();
List<Trigger> ts = i2.next().getValue();
ts.remove(t);
if (ts.isEmpty())
i2.remove();
}
}

@Override
public void unregisterAll() {
// blockTriggers.clear();
itemTypeTriggers.clear();
ITEM_TYPE_TRIGGERS.clear();
}


@Override
public String toString(@Nullable Event e, boolean debug) {
return "walk on " + Classes.toString(types, false);
}

}