diff --git a/src/main/java/ch/njol/skript/events/EvtPlayerCommandSend.java b/src/main/java/ch/njol/skript/events/EvtPlayerCommandSend.java
new file mode 100644
index 00000000000..9ef380ada7a
--- /dev/null
+++ b/src/main/java/ch/njol/skript/events/EvtPlayerCommandSend.java
@@ -0,0 +1,75 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package ch.njol.skript.events;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.lang.Literal;
+import ch.njol.skript.lang.SkriptEvent;
+import ch.njol.skript.lang.SkriptParser.ParseResult;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import org.bukkit.event.Event;
+import org.bukkit.event.player.PlayerCommandSendEvent;
+import org.eclipse.jdt.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class EvtPlayerCommandSend extends SkriptEvent {
+
+ static {
+ Skript.registerEvent("Send Command List", EvtPlayerCommandSend.class, PlayerCommandSendEvent.class, "send[ing] [of [the]] [server] command[s] list", "[server] command list send")
+ .description(
+ "Called when the server sends a list of commands to the player. This usually happens on join. The sent commands " +
+ "can be modified via the sent commands expression.",
+ "Modifications will affect what commands show up for the player to tab complete. They will not affect what commands the player can actually run.",
+ "Adding new commands to the list is illegal behavior and will be ignored."
+ )
+ .examples(
+ "on send command list:",
+ "\tset command list to command list where [input does not contain \":\"]",
+ "\tremove \"help\" from command list"
+ )
+ .since("INSERT VERSION");
+ }
+
+ private final Collection originalCommands = new ArrayList<>();
+
+ @Override
+ public boolean init(Literal>[] args, int matchedPattern, ParseResult parseResult) {
+ return true;
+ }
+
+ @Override
+ public boolean check(Event event) {
+ originalCommands.clear();
+ originalCommands.addAll(((PlayerCommandSendEvent) event).getCommands());
+ return true;
+ }
+
+ public ImmutableCollection getOriginalCommands() {
+ return ImmutableList.copyOf(originalCommands);
+ }
+
+ @Override
+ public String toString(@Nullable Event event, boolean debug) {
+ return "sending of the server command list";
+ }
+
+}
diff --git a/src/main/java/ch/njol/skript/expressions/ExprSentCommands.java b/src/main/java/ch/njol/skript/expressions/ExprSentCommands.java
new file mode 100644
index 00000000000..5c4f17ab16e
--- /dev/null
+++ b/src/main/java/ch/njol/skript/expressions/ExprSentCommands.java
@@ -0,0 +1,155 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package ch.njol.skript.expressions;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.classes.Changer.ChangeMode;
+import ch.njol.skript.doc.Description;
+import ch.njol.skript.doc.Events;
+import ch.njol.skript.doc.Examples;
+import ch.njol.skript.doc.Name;
+import ch.njol.skript.doc.Since;
+import ch.njol.skript.events.EvtPlayerCommandSend;
+import ch.njol.skript.lang.Expression;
+import ch.njol.skript.lang.ExpressionType;
+import ch.njol.skript.lang.SkriptParser.ParseResult;
+import ch.njol.skript.lang.util.SimpleExpression;
+import ch.njol.util.Kleenean;
+import com.google.common.collect.Lists;
+import org.bukkit.event.Event;
+import org.bukkit.event.player.PlayerCommandSendEvent;
+import org.eclipse.jdt.annotation.Nullable;
+import org.skriptlang.skript.lang.structure.Structure;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Name("Sent Command List")
+@Description({
+ "The commands that will be sent to the player in a send commands to player event.",
+ "Modifications will affect what commands show up for the player to tab complete. They will not affect what commands the player can actually run.",
+ "Adding new commands to the list is illegal behavior and will be ignored."
+})
+@Examples({
+ "on send command list:",
+ "\tset command list to command list where [input does not contain \":\"]",
+ "\tremove \"help\" from command list"
+})
+@Since("INSERT VERSION")
+@Events("send command list")
+public class ExprSentCommands extends SimpleExpression {
+
+ static {
+ Skript.registerExpression(ExprSentCommands.class, String.class, ExpressionType.SIMPLE, "[the] [sent] [server] command[s] list");
+ }
+
+ private EvtPlayerCommandSend parent;
+
+ @Override
+ public boolean init(Expression>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
+ Structure structure = getParser().getCurrentStructure();
+ if (!(structure instanceof EvtPlayerCommandSend)) {
+ Skript.error("The 'command list' expression can only be used in a 'send command list' event");
+ return false;
+ }
+
+ if (!isDelayed.isFalse()) {
+ Skript.error("Can't change the command list after the event has already passed");
+ return false;
+ }
+ parent = (EvtPlayerCommandSend) structure;
+ return true;
+ }
+
+ @Override
+ @Nullable
+ protected String[] get(Event event) {
+ if (!(event instanceof PlayerCommandSendEvent))
+ return null;
+ return ((PlayerCommandSendEvent) event).getCommands().toArray(new String[0]);
+ }
+
+ @Override
+ @Nullable
+ public Class>[] acceptChange(ChangeMode mode) {
+ switch (mode) {
+ case REMOVE:
+ case DELETE:
+ case SET:
+ case RESET:
+ return new Class[]{String[].class};
+ // note that ADD is not supported, as adding new commands to the commands collection is illegal behaviour
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
+ if (!(event instanceof PlayerCommandSendEvent))
+ return;
+
+ Collection commands = ((PlayerCommandSendEvent) event).getCommands();
+
+ // short circuit if we're just clearing the list
+ if (mode == ChangeMode.DELETE) {
+ commands.clear();
+ return;
+ }
+
+ List deltaCommands = (delta != null && delta.length > 0) ? Lists.newArrayList((String[]) delta) : new ArrayList<>();
+ switch (mode) {
+ case REMOVE:
+ commands.removeAll(deltaCommands);
+ break;
+ case SET:
+ // remove all completely new commands, as adding new commands to the commands collection is illegal behaviour
+ List newCommands = new ArrayList<>(deltaCommands);
+ newCommands.removeAll(parent.getOriginalCommands());
+ deltaCommands.removeAll(newCommands);
+ commands.clear();
+ commands.addAll(deltaCommands);
+ break;
+ case RESET:
+ commands.clear();
+ commands.addAll(parent.getOriginalCommands());
+ break;
+ default:
+ assert false;
+ break;
+ }
+ }
+
+ @Override
+ public boolean isSingle() {
+ return false;
+ }
+
+ @Override
+ public Class extends String> getReturnType() {
+ return String.class;
+ }
+
+ @Override
+ public String toString(@Nullable Event event, boolean debug) {
+ return "the sent server command list";
+ }
+
+}