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

Input API #7190

Open
wants to merge 16 commits into
base: dev/feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
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
4 changes: 3 additions & 1 deletion src/main/java/ch/njol/skript/Skript.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
import org.skriptlang.skript.bukkit.SkriptMetrics;
import org.skriptlang.skript.bukkit.breeding.BreedingModule;
import org.skriptlang.skript.bukkit.displays.DisplayModule;
import org.skriptlang.skript.bukkit.input.InputModule;
import org.skriptlang.skript.lang.comparator.Comparator;
import org.skriptlang.skript.lang.comparator.Comparators;
import org.skriptlang.skript.lang.converter.Converter;
Expand Down Expand Up @@ -555,8 +556,9 @@ public void onEnable() {
"conditions", "effects", "events", "expressions", "entity", "sections", "structures");
getAddonInstance().loadClasses("org.skriptlang.skript.bukkit", "misc");
// todo: become proper module once registry api is merged
DisplayModule.load();
BreedingModule.load();
DisplayModule.load();
InputModule.load();
} catch (final Exception e) {
exception(e, "Could not load required .class files: " + e.getLocalizedMessage());
setEnabled(false);
Expand Down
10 changes: 1 addition & 9 deletions src/main/java/ch/njol/skript/lang/ExpressionList.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,7 @@ public boolean isSingle() {

@Override
public boolean check(Event event, Checker<? super T> checker, boolean negated) {
for (Expression<? extends T> expr : expressions) {
boolean result = expr.check(event, checker) ^ negated;
// exit early if we find a FALSE and we're ANDing, or a TRUE and we're ORing
if (and && !result)
return false;
if (!and && result)
return true;
}
return and;
return CollectionUtils.check(expressions, expr -> expr.check(event, checker) ^ negated, and);
}

@Override
Expand Down
38 changes: 27 additions & 11 deletions src/main/java/ch/njol/util/coll/CollectionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,13 @@
package ch.njol.util.coll;

import ch.njol.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.function.Predicate;

/**
* Utils for collections and arrays. All methods will not print any errors for <tt>null</tt> collections/arrays, but will return false/-1/etc.
Expand Down Expand Up @@ -102,7 +95,30 @@ public static <T> boolean containsAll(final @Nullable T[] array, final @Nullable
}
return true;
}


/**
* Checks the elements of an array against a given predicate.
*
* @param array the array to check, can be null
* @param predicate the predicate to test the elements against
* @param and if true, all elements must satisfy the predicate; if false, any element satisfying the predicate is enough
* @param <T> the type of elements in the array
* @return true if the condition is met based on the value of the 'and' parameter, false otherwise
*/
public static <T> boolean check(T @Nullable [] array, Predicate<T> predicate, boolean and) {
UnderscoreTud marked this conversation as resolved.
Show resolved Hide resolved
if (array == null)
return false;
for (T value : array) {
boolean result = predicate.test(value);
// exit early if we find a FALSE and we're ANDing, or a TRUE and we're ORing
if (and && !result)
return false;
if (!and && result)
return true;
}
return and;
}

public static int indexOf(final @Nullable int[] array, final int num) {
if (array == null)
return -1;
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/org/skriptlang/skript/bukkit/input/InputKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.skriptlang.skript.bukkit.input;

import org.bukkit.Input;

import java.util.EnumSet;
import java.util.Set;

/**
* Enum representing different movement input keys.
* @see Input
*/
public enum InputKey {

FORWARD,
BACKWARD,
RIGHT,
LEFT,
JUMP,
SNEAK,
SPRINT;

/**
* Checks if the given {@link Input} is pressing this {@link InputKey}.
*
* @param input the input to check
* @return true if the {@link Input} is pressing this {@link InputKey}, false otherwise
*/
public boolean check(Input input) {
return switch (this) {
case FORWARD -> input.isForward();
case BACKWARD -> input.isBackward();
case RIGHT -> input.isRight();
case LEFT -> input.isLeft();
case JUMP -> input.isJump();
case SNEAK -> input.isSneak();
case SPRINT -> input.isSprint();
};
}

/**
* Returns a set of {@link InputKey}s that match the given {@link Input}.
*
* @param input the input to check
* @return a set of {@link InputKey}s that match the given {@link Input}
*/
public static Set<InputKey> fromInput(Input input) {
Set<InputKey> keys = EnumSet.noneOf(InputKey.class);
for (InputKey key : values()) {
if (key.check(input))
keys.add(key);
}
return keys;
}

}
42 changes: 42 additions & 0 deletions src/main/java/org/skriptlang/skript/bukkit/input/InputModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.skriptlang.skript.bukkit.input;

import ch.njol.skript.Skript;
import ch.njol.skript.classes.EnumClassInfo;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.registrations.EventValues;
import ch.njol.skript.util.Getter;
import org.bukkit.event.player.PlayerInputEvent;

import java.io.IOException;

public class InputModule {

public static void load() throws IOException {
if (!Skript.classExists("org.bukkit.Input"))
return;

Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.input", "elements");

Classes.registerClass(new EnumClassInfo<>(InputKey.class, "inputkey", "input keys")
.user("input ?keys?")
.name("Input Key")
.description("Represents a movement input key that is pressed by a player.")
.since("INSERT VERSION")
.requiredPlugins("Minecraft 1.21.3+"));

EventValues.registerEventValue(PlayerInputEvent.class, InputKey[].class, new Getter<>() {
@Override
public InputKey[] get(PlayerInputEvent event) {
return InputKey.fromInput(event.getInput()).toArray(new InputKey[0]);
}
}, EventValues.TIME_NOW);

EventValues.registerEventValue(PlayerInputEvent.class, InputKey[].class, new Getter<>() {
@Override
public InputKey[] get(PlayerInputEvent event) {
return InputKey.fromInput(event.getPlayer().getCurrentInput()).toArray(new InputKey[0]);
}
}, EventValues.TIME_PAST);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.skriptlang.skript.bukkit.input.elements.conditions;

import ch.njol.skript.Skript;
import ch.njol.skript.doc.*;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.Input;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.player.PlayerInputEvent;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.bukkit.input.InputKey;

@Name("Is Pressing Key")
@Description("Checks if a player is pressing a certain input key.")
@Examples({
"on player input:",
"\tif player is pressing forward movement key:",
"\t\tsend \"You are moving forward!\""
})
@Since("INSERT VERSION")
@Keywords({"press", "input"})
@RequiredPlugins("Minecraft 1.21.3+")
public class CondIsPressingKey extends Condition {

static {
Skript.registerCondition(CondIsPressingKey.class,
"%players% (is|are) pressing %inputkeys%",
"%players% (isn't|is not|aren't|are not) pressing %inputkeys%",
"%players% (was|were) pressing %inputkeys%",
"%players% (wasn't|was not|weren't|were not) pressing %inputkeys%"
);
}

private Expression<Player> players;
private Expression<InputKey> inputKeys;
private boolean past;

@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
//noinspection unchecked
players = (Expression<Player>) expressions[0];
//noinspection unchecked
inputKeys = (Expression<InputKey>) expressions[1];
past = matchedPattern > 1;
if (past && !getParser().isCurrentEvent(PlayerInputEvent.class))
Skript.warning("Checking the past state of a player's input outside the 'player input' event has no effect.");
setNegated(matchedPattern == 1 || matchedPattern == 3);
return true;
}

@Override
public boolean check(Event event) {
Player eventPlayer = !past && event instanceof PlayerInputEvent inputEvent ? inputEvent.getPlayer() : null;
UnderscoreTud marked this conversation as resolved.
Show resolved Hide resolved
InputKey[] inputKeys = this.inputKeys.getAll(event);
boolean and = this.inputKeys.getAnd();
return players.check(event, player -> {
Input input;
if (player.equals(eventPlayer)) {
input = ((PlayerInputEvent) event).getInput();
} else {
input = player.getCurrentInput();
}
return CollectionUtils.check(inputKeys, inputKey -> inputKey.check(input), and);
}, isNegated());
}

@Override
public String toString(@Nullable Event event, boolean debug) {
StringBuilder builder = new StringBuilder();
UnderscoreTud marked this conversation as resolved.
Show resolved Hide resolved
builder.append(players.toString(event, debug));
if (past) {
builder.append(players.isSingle() ? " was " : " were ");
} else {
builder.append(players.isSingle() ? " is " : " are ");
}
if (isNegated())
builder.append("not ");
builder.append("pressing ");
builder.append(inputKeys.toString(event, debug));
return builder.toString();
}

}
Loading
Loading