diff --git a/build.gradle.kts b/build.gradle.kts
index 9cea777e6..4f9c18d05 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -146,6 +146,7 @@ dependencies {
     implementation("com.github.JnCrMx:discord-game-sdk4j:v0.5.5")?.let { clientInclude(it) }
 
     implementation("objects:client:43db9b498cb67058d2e12d394e6507722e71bb45") // Minecraft client jar
+    implementation("com.mojang:brigadier:1.0.18")?.let { clientInclude(it); serverInclude(it) }
 
     implementation("com.formdev:flatlaf:3.1.1")?.let { clientInclude(it) } // Dark theme used by SeedViewer
     
@@ -179,7 +180,9 @@ task("runClient", JavaExec::class) {
     group = "bta"
     mainClass.set("net.minecraft.client.Minecraft")
     classpath = sourceSets["main"].runtimeClasspath
-    jvmArgs = listOf("-XstartOnFirstThread", "-Djava.awt.headless=true")
+    if (arrayOf("Mac OS X", "Darwin").any { System.getProperty("os.name").startsWith(it) }) {
+        jvmArgs = listOf("-XstartOnFirstThread", "-Djava.awt.headless=true")
+    }
 
     systemProperty("java.library.path", layout.buildDirectory.dir("natives").get().asFile.absolutePath)
 }
diff --git a/src/common/resources/lang/en_US/command.lang b/src/common/resources/lang/en_US/command.lang
new file mode 100644
index 000000000..dc37e72b7
--- /dev/null
+++ b/src/common/resources/lang/en_US/command.lang
@@ -0,0 +1,163 @@
+command.argument_types.achievement.invalid_achievement=Invalid achievement ID
+command.argument_types.entity_summon.invalid_entity=Invalid entity ID
+command.argument_types.block.invalid_block=Invalid block ID
+command.argument_types.item.invalid_item=Invalid item ID
+command.argument_types.dimension.invalid_dimension=Invalid dimension ID
+command.argument_types.biome.invalid_biome=Invalid biome ID
+command.argument_types.damage_type.invalid_damage_type=Invalid damage type ID
+command.argument_types.gamerule.invalid_value=Invalid game rule value
+command.argument_types.sound_type.invalid_sound_type=Invalid sound type
+command.argument_types.sound_category.invalid_sound_category=Invalid sound category
+command.argument_types.entity.invalid_selector.single_player_only=Selector includes more than one entity, but command only accepts a single player as an argument
+command.argument_types.entity.invalid_selector.single_entity_only=Selector includes more than one entity, but command only accepts a single entity as an argument
+command.argument_types.entity.invalid_selector.player_only=Selector includes non-player entities, but command only accepts players as an argument
+command.argument_types.entity.invalid_selector.generic=Invalid selector
+command.argument_types.entity.invalid_selector.empty=No entities match the given selector
+command.argument_types.entity.invalid_selector.selectors_not_allowed=Selectors not allowed
+command.argument_types.entity.selector.nearest_player=Nearest player
+command.argument_types.entity.selector.all_players=All players
+command.argument_types.entity.selector.random_player=Random player
+command.argument_types.entity.selector.self=Current entity
+command.argument_types.entity.selector.all_entities=All entities
+command.argument_types.entity.selector.options.inapplicable=Option '%s' isn't applicable here
+command.argument_types.entity.selector.options.unknown=Unknown option '%s'
+command.argument_types.entity.selector.options.unterminated=Expected end of options
+command.argument_types.entity.selector.options.valueless=Expected value for option '%s'
+command.argument_types.entity.selector.options.gamemode.invalid=Invalid or unknown game mode '%s'
+command.argument_types.entity.selector.options.gamemode.description=Players with game mode
+command.argument_types.entity.selector.options.nbt.description=Entities with NBT
+command.argument_types.entity.selector.options.sort.description=Sort the entities
+command.argument_types.entity.selector.options.sort.invalid=Invalid or unknown sort type '%s'
+command.argument_types.entity.selector.options.limit.description=Maximum number of entities to return
+command.argument_types.entity.selector.options.limit.invalid=Limit must be at least 1
+command.argument_types.entity.selector.options.type.description=Entities of type
+command.argument_types.entity.selector.options.type.invalid=Invalid or unknown entity type '%s'
+command.argument_types.entity.selector.options.distance.description=Distance to entity
+command.argument_types.entity.selector.options.distance.invalid=Distance cannot be negative
+command.argument_types.entity.selector.options.name.description=Entity name
+command.argument_types.entity.selector.options.x.description=x position
+command.argument_types.entity.selector.options.y.description=y position
+command.argument_types.entity.selector.options.z.description=z position
+command.argument_types.entity.selector.options.dx.description=Entities between x and x + dx
+command.argument_types.entity.selector.options.dy.description=Entities between y and y + dy
+command.argument_types.entity.selector.options.dz.description=Entities between z and z + dz
+command.exceptions.tag.valueless=Expected value for tag key '%s'
+command.argument_types.item_stack.tag.invalid=Invalid tag key value; must be an integer, floating point, double-precision floating point, boolean or string value
+command.exceptions.metadata.unterminated=Expected end of metadata
+command.exceptions.tag.unterminated=Expected end of tag
+command.argument_types.range.empty=Expected value or range of values
+command.argument_types.range.swapped=Min cannot be bigger than max
+command.argument_types.time.invalid_unit=Invalid unit
+command.argument_types.time.tick_count_too_low=Tick count must not be less than %s, found %s
+command.argument_types.game_mode.invalid_game_mode=Invalid game mode
+command.argument_types.weather.invalid_weather=Invalid weather
+command.argument_types.world_feature.invalid_world_feature=Invalid world feature
+command.argument_types.world_feature.no_parameters=The given world feature expects no parameters
+command.commands.time.query=The time is %s
+command.commands.time.set=Set the time to %s
+command.commands.achievement.grant.exception_already_has_achievement=Player already has achievement
+command.commands.achievement.grant.success_multiple_entities=Granted achievement §5[%s]§r to %s entities
+command.commands.achievement.grant.success_single_entity=Granted achievement §5[%s]§r to %s
+command.commands.achievement.grant.all.success_multiple_entities=Granted all achievements to %s entities
+command.commands.achievement.grant.all.success_single_entity=Granted all achievements to %s
+command.commands.seed.success=Seed: §5[%s]§r
+command.commands.clear.success_single_item_single_entity=%s item slot cleared
+command.commands.clear.success_multiple_items_single_entity=%s item slots cleared
+command.commands.clear.success_single_item_multiple_entities=%s item slot cleared from %s entities
+command.commands.clear.success_multiple_items_multiple_entities=%s item slots cleared from %s entities
+command.commands.clear.exception_failure=No items were cleared
+command.commands.kill.single_entity=Killed %s
+command.commands.kill.multiple_entities=Killed %s entities
+command.commands.kill.exception_failure=No entity was killed
+command.commands.summon.success_single_entity=Summoned %s
+command.commands.summon.success_multiple_entities=Summoned %s entities
+command.commands.teleport.entity.success_single_entity=Teleported %s to %s
+command.commands.teleport.entity.success_multiple_entities=Teleported %s entities to %s
+command.commands.teleport.location.success_single_entity=Teleported %s to %s, %s, %s
+command.commands.teleport.location.success_multiple_entities=Teleported %s entities to %s, %s, %s
+command.commands.setblock.exception_failure=Could not set the block
+command.commands.setblock.success=Changed the block at %s, %s, %s
+command.commands.message.incoming=%s whispers to you: %s
+command.commands.message.outgoing=You whisper to %s: %s
+command.commands.gamemode.success_self=Set own game mode to %s
+command.commands.gamemode.success_other=Set %s's game mode to %s
+command.commands.gamemode.success_receiver=Your game mode has been updated
+command.commands.weather.success=Set the weather to %s
+command.commands.spawn.success=Teleported yourself to the world's spawn point
+command.commands.spawn.success_other=Teleported %s to the world's spawn point
+command.commands.spawn.success_receiver=You were teleported to the world's spawn point
+command.commands.spawn.get=The world's spawn point is located at %s, %s, %s
+command.commands.place.success=Placed feature %s at %s, %s, %s
+command.commands.place.exception_failure=Could not place feature
+command.commands.help.exception_failure=Unknown command or insufficient permissions
+command.commands.give.success_single_entity=Gave %s %s * [%s§r]
+command.commands.give.success_multiple_entities=Gave %s players %s * [%s§r]
+command.commands.stop.success=Stopping the server
+command.commands.op.success=%s is now a server operator
+command.commands.op.success_receiver=You are now a server operator
+command.commands.op.exception_failure=Nothing changed, all players in the given selector are already server operators
+command.commands.deop.success=%s is no longer a server operator
+command.commands.deop.success_receiver=You are no longer a server operator
+command.commands.deop.exception_failure=Nothing changed, there are no server operators in the given selector
+command.commands.list.success_single=There is %s player online: %s
+command.commands.list.success_multiple=There are %s players online: %s
+command.commands.list.success_too_long=There are %s players online; number is too large to show all of them
+command.commands.list.exception_failure=There are no players online
+command.commands.difficulty.query.success=The difficulty is %s
+command.commands.difficulty.query.success_unknown=The difficulty is unknown
+command.commands.difficulty.set.success=Set the game's difficulty to %s
+command.commands.color.get.success=Your color is %s
+command.commands.color.get.success_other=%s's color is %s
+command.commands.color.set.success=Set own color to %s
+command.commands.color.set.success_other=Set %s's color to %s
+command.commands.color.set.success_receiver=Your color has been set to %s
+command.commands.nickname.exception_too_large=The given nickname is too large, should be less than 16 characters
+command.commands.nickname.exception_too_small=The given nickname is too small, should have at least one character
+command.commands.nickname.set.success=Set own nickname to %s
+command.commands.nickname.set.success_other=Set %s's nickname to %s
+command.commands.nickname.set.success_receiver=Your nickname has been set to %s
+command.commands.nickname.get.success=%s's nickname is %s
+command.commands.nickname.reset.success=Reset own nickname
+command.commands.nickname.reset.success_other=Reset %s's nickname
+command.commands.nickname.reset.success_receiver=Your nickname has been reset
+command.commands.chunk.reset.success=Reset chunk at %s, %s
+command.commands.setspawn.success=Set world spawn point to %s, %s, %s
+command.commands.whois.success=%s's username is %s
+command.commands.score.get.success=Your score is %s
+command.commands.score.get.success_other=%s's score is %s
+command.commands.score.set.success=Set own score to %s
+command.commands.score.set.success_other=Set %s's score to %s
+command.commands.score.set.success_receiver=Your score has been set to %s
+command.commands.emotes.success=Available emotes:
+command.commands.gamerule.get=Game rule %s is set to %s
+command.exceptions.incomplete=Incomplete argument
+command.exceptions.not_in_world=Argument requires sender to be in world, but they are not present
+command.exceptions.single_player_world_only=Command requires the sender to be in a single player world
+command.exceptions.multiplayer_world_only=Command requires the sender to be in a multiplayer world
+command.commands.gamerule.set=Set game rule %s to %s
+command.exceptions.volume_too_large=Volume is too large (the maximum 32768 blocks)
+command.commands.fill.success_single=Filled %s block
+command.commands.fill.success_multiple=Filled %s blocks
+command.commands.clone.exception_inside_cloned_area=Destination is inside the cloned area
+command.commands.clone.exception_destination_not_loaded=Destination is not loaded
+command.commands.clone.exception_source_not_loaded=Source is not loaded
+command.commands.clone.exception_nowhere_loaded=Source and destination are not loaded
+command.commands.clone.success_single=%s block cloned
+command.commands.clone.success_multiple=%s blocks cloned
+command.commands.biome.locate.exception_failure=Could not find biome %s at any reasonable distance
+command.commands.biome.locate.success=Biome %s found in position §5[%s, ~, %s]§r
+command.commands.biome.locate.success_in_world_single=Biome %s found in position §5[%s, ~, %s]§r (%s block away)
+command.commands.biome.locate.success_in_world_multiple=Biome %s found in position §5[%s, ~, %s]§r (%s blocks away)
+command.commands.biome.get.success=The biome at position %s, %s, %s is %s
+command.commands.testfor.entity.none=No entities match the given selector
+command.commands.testfor.entity.single=%s entity matches the given selector
+command.commands.testfor.entity.plural=%s entities match the given selector
+command.commands.testfor.block.success=The two blocks are equal
+command.commands.testfor.block.failure=The two blocks are not equal
+command.commands.damage.success_single=Damaged %s entity
+command.commands.damage.success_multiple=Damaged %s entities
+command.commands.heal.success_single=Healed %s entity
+command.commands.heal.success_multiple=Healed %s entities
+command.commands.playsound.success=Played sound %s in category %s at %s, %s, %s
+command.commands.playsound.exception_failure=Could not play sound %s
+command.commands.spawnparticle.success=Spawned particle %s at %s, %s, %s
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/client/Minecraft.java b/src/main/java/net/minecraft/client/Minecraft.java
index 73400c5fa..d9d1eaf00 100644
--- a/src/main/java/net/minecraft/client/Minecraft.java
+++ b/src/main/java/net/minecraft/client/Minecraft.java
@@ -21,8 +21,11 @@ import com.mojang.nbt.CompoundTag;
 import net.minecraft.client.entity.ClientSkinVariantList;
 import net.minecraft.client.gui.*;
 import net.minecraft.client.gui.achievements.AchievementsScreen;
+import net.minecraft.client.gui.chat.ChatScreen;
+import net.minecraft.client.gui.chat.SleepScreenMP;
 import net.minecraft.client.gui.toasts.HudToastsElement;
 import net.minecraft.core.achievement.Achievements;
+import net.minecraft.core.net.command.util.CommandHelper;
 import net.minecraft.core.util.helper.LoggedPrintStream;
 import net.minecraft.core.util.helper.UUIDHelper;
 import net.minecraft.core.world.SpawnerMobs;
@@ -118,7 +121,6 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.PlayerProfile;
-import net.minecraft.core.net.command.ClientCommandHandler;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.player.Session;
 import net.minecraft.core.player.gamemode.Gamemode;
@@ -239,7 +241,6 @@ public class Minecraft
     protected long flyPressedTime = 0;
     public float hotbarSwapAnimationProgress = 0.0f;
     public ScaledResolution resolution;
-    public final ClientCommandHandler commandHandler = new ClientCommandHandler(this);
     public boolean fullbright = false;
     public Renderer renderer;
     public ControllerInput controllerInput;
@@ -407,8 +408,8 @@ public class Minecraft
         // Manually initialize blocks and items
         Blocks.init();
         Items.init();
-
         Dimension.init();
+        CommandHelper.init();
 
 		gameSettings = new GameSettings(this, mcDataDir);
 
diff --git a/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java b/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java
index 1ab8f1887..745fc3481 100644
--- a/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java
+++ b/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java
@@ -1,5 +1,6 @@
 package net.minecraft.client.entity.player;
 
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.CompoundTag;
 
@@ -35,12 +36,8 @@ import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.net.command.ClientCommandHandler;
-import net.minecraft.core.net.command.ClientPlayerCommandSender;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.Commands;
 import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.client.net.command.ClientCommandSource;
 import net.minecraft.core.player.Session;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.player.inventory.menu.InventoryMenu;
@@ -57,14 +54,12 @@ public class LocalPlayer extends Player
     private static final Logger LOGGER = LogUtils.getLogger();
     public PlayerInput input;
     protected Minecraft mc;
-    public final ClientPlayerCommandSender sender;
     protected int sprintTimer;
 
     public LocalPlayer(Minecraft minecraft, World world, Session session, int dimension)
     {
         super(world);
         mc = minecraft;
-        sender = new ClientPlayerCommandSender(minecraft, this);
         this.dimension = dimension;
         username = session.username;
         uuid = session.uuid;
@@ -342,35 +337,12 @@ public class LocalPlayer extends Player
     public void sendChatMessage(String s) {
     	addToSendHistory(s);
         if (s.startsWith("/")) {
-            try{
-                String[] args = s.substring(1).split(" ");
-                String[] args1 = new String[args.length - 1];
-                System.arraycopy(args, 1, args1, 0, args.length - 1);
-
-                ClientCommandHandler handler = mc.commandHandler;
-
-                for(Command command : Commands.commands) {
-                    if(command.isName(args[0])) {
-                        if(!sender.isAdmin() && command.opRequired(args1)) {
-                            sender.sendMessage("You don't have permission to use this command!");
-                            return;
-                        }
-                        try {
-                            boolean success = command.execute(handler, sender, args1);
-                            if(!success) {
-                                command.sendCommandSyntax(handler, sender);
-                            }
-                        }catch (CommandError e) {
-                            sender.sendMessage(TextFormatting.RED + e.getMessage());
-                        }
-                        return;
-                    }
-                }
-                sender.sendMessage(TextFormatting.RED + "Command '" + args[0] + "' does not exist!");
-            }catch (Exception e) {
-                LOGGER.error("Exception while trying to perform command '" + s + "'!", e);
-                mc.ingameHud.addChatMessage(TextFormatting.RED + "Error!");
-                mc.ingameHud.addChatMessage(TextFormatting.RED + e.getMessage());
+            String command = s.substring(1);
+            ClientCommandSource clientCommandSource = new ClientCommandSource(mc);
+            try {
+                this.world.getCommandManager().execute(command, clientCommandSource);
+            } catch (CommandSyntaxException e) {
+                mc.thePlayer.sendMessage(TextFormatting.RED + e.getMessage());
             }
         } else {
             mc.ingameHud.addChatMessage("<" + getDisplayName() + TextFormatting.RESET + "> " + TextFormatting.WHITE + s);
diff --git a/src/main/java/net/minecraft/client/gui/ItemElement.java b/src/main/java/net/minecraft/client/gui/ItemElement.java
index c613e0079..e2fb3ba1c 100644
--- a/src/main/java/net/minecraft/client/gui/ItemElement.java
+++ b/src/main/java/net/minecraft/client/gui/ItemElement.java
@@ -14,7 +14,7 @@ import net.minecraft.core.WeightedRandomLootObject;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.inventory.slot.Slot;
-import net.minecraft.core.player.inventory.slot.GuidebookSlot;
+import net.minecraft.client.gui.guidebook.GuidebookSlot;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.opengl.GL12;
 
diff --git a/src/main/java/net/minecraft/client/gui/TooltipElement.java b/src/main/java/net/minecraft/client/gui/TooltipElement.java
index a323d73db..9bc2f815f 100644
--- a/src/main/java/net/minecraft/client/gui/TooltipElement.java
+++ b/src/main/java/net/minecraft/client/gui/TooltipElement.java
@@ -12,7 +12,7 @@ import net.minecraft.core.player.inventory.slot.Slot;
 import net.minecraft.core.player.inventory.slot.ResultSlot;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.player.inventory.slot.GuidebookSlot;
+import net.minecraft.client.gui.guidebook.GuidebookSlot;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
diff --git a/src/main/java/net/minecraft/client/gui/ChatEmotePickerElement.java b/src/main/java/net/minecraft/client/gui/chat/ChatEmotePickerElement.java
similarity index 98%
rename from src/main/java/net/minecraft/client/gui/ChatEmotePickerElement.java
rename to src/main/java/net/minecraft/client/gui/chat/ChatEmotePickerElement.java
index 69cecf1cc..261302c7f 100644
--- a/src/main/java/net/minecraft/client/gui/ChatEmotePickerElement.java
+++ b/src/main/java/net/minecraft/client/gui/chat/ChatEmotePickerElement.java
@@ -1,6 +1,7 @@
-package net.minecraft.client.gui;
+package net.minecraft.client.gui.chat;
 
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
 import net.minecraft.client.render.Scissor;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.net.ChatEmotes;
diff --git a/src/main/java/net/minecraft/client/gui/ChatScreen.java b/src/main/java/net/minecraft/client/gui/chat/ChatScreen.java
similarity index 54%
rename from src/main/java/net/minecraft/client/gui/ChatScreen.java
rename to src/main/java/net/minecraft/client/gui/chat/ChatScreen.java
index 51462267d..ded531c91 100644
--- a/src/main/java/net/minecraft/client/gui/ChatScreen.java
+++ b/src/main/java/net/minecraft/client/gui/chat/ChatScreen.java
@@ -1,6 +1,9 @@
-package net.minecraft.client.gui;
+package net.minecraft.client.gui.chat;
 
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.gui.hud.component.ComponentAnchor;
 import net.minecraft.client.gui.text.TextFieldEditor;
+import net.minecraft.client.render.Font;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.net.ChatEmotes;
 import org.lwjgl.input.Keyboard;
@@ -17,6 +20,7 @@ public class ChatScreen extends Screen implements ITextField {
 	private final TextFieldEditor editor;
 	protected ChatEmotePickerElement emotePicker;
 	protected boolean showEmotePicker = false;
+	private ChatSuggestionsElement suggestionsElement;
 
 	public ChatScreen() {
 		this("");
@@ -35,6 +39,20 @@ public class ChatScreen extends Screen implements ITextField {
 		int emotePickerYCells = (int)MathHelper.clamp(Math.ceil(ChatEmotes.getEmotes().size() / 5.0), 0, 4);
 		emotePicker = new ChatEmotePickerElement(mc, this, 5, emotePickerYCells);
 		showEmotePicker = false;
+		suggestionsElement = new ChatSuggestionsElement(
+			mc,
+			editor,
+			this,
+			(parent, child, minecraft, followParameters) -> 16 + (followParameters ? suggestionsElement.getDefaultParameterPosition() - 1 : 0),
+			(parent, child, minecraft, followParameters) -> minecraft.resolution.getScaledHeightScreenCoords() - 14,
+			ComponentAnchor.BOTTOM_LEFT
+		);
+		if (!this.getText().startsWith("/")) {
+			this.suggestionsElement.hidden = true;
+		} else {
+			this.suggestionsElement.updateSuggestions();
+		}
+
 	}
 
 	@Override
@@ -56,45 +74,73 @@ public class ChatScreen extends Screen implements ITextField {
 				mc.ingameHud.chatScroll += dWheel / 1;
 			}
 		}
+
+		if (this.suggestionsElement != null) {
+			this.suggestionsElement.hidden = !this.getText().startsWith("/");
+			this.suggestionsElement.updateScreen(dWheel);
+		}
 	}
 
 	@Override
 	public void keyPressed(char eventCharacter, int eventKey, int mx, int my) {
-		if (eventKey == Keyboard.KEY_UP && mc.thePlayer.messageHistory.size() > 0) {
-			if (currentIndex == 0)
-			{
-				originalMessage = getText();
+		boolean handled = false;
+
+		if (eventKey == Keyboard.KEY_UP) {
+			if (this.suggestionsElement != null) {
+				if (this.suggestionsElement.getCommandIndex() != -1) {
+					this.suggestionsElement.cycleThroughSuggestions(-1);
+					handled = true;
+				}
 			}
-			if (currentIndex < mc.thePlayer.messageHistory.size())
-			{
-				currentIndex++;
-				setText(getMessage(currentIndex));
-				this.editor.setCursor(10000);
+			if (!handled && !mc.thePlayer.messageHistory.isEmpty()) {
+				if (currentIndex == 0)
+				{
+					originalMessage = getText();
+				}
+				if (currentIndex < mc.thePlayer.messageHistory.size())
+				{
+					currentIndex++;
+					setText(getMessage(currentIndex));
+					this.editor.setCursor(10000);
+				}
+				editor.setCursor(10000);
+				if (this.suggestionsElement != null) {
+					this.suggestionsElement.updateSuggestions();
+				}
+				handled = true;
 			}
-			editor.setCursor(10000);
-			return;
 		}
-		if (eventKey == Keyboard.KEY_DOWN && currentIndex > 0)
+		if (eventKey == Keyboard.KEY_DOWN)
 		{
-			if (currentIndex-1 == 0)
-			{
-				currentIndex--;
-				setText(originalMessage);
-				this.editor.setCursor(10000);
-
+			if (this.suggestionsElement != null) {
+				if (this.suggestionsElement.getCommandIndex() != -1) {
+					this.suggestionsElement.cycleThroughSuggestions();
+					handled = true;
+				}
 			}
-			else
-			{
-				currentIndex--;
-				setText(getMessage(currentIndex));
-				this.editor.setCursor(10000);
+			if (!handled && currentIndex > 0) {
+				if (currentIndex-1 == 0)
+				{
+					currentIndex--;
+					setText(originalMessage);
+					this.editor.setCursor(10000);
+				}
+				else
+				{
+					currentIndex--;
+					setText(getMessage(currentIndex));
+					this.editor.setCursor(10000);
+				}
+				editor.setCursor(10000);
+				if (this.suggestionsElement != null) {
+					this.suggestionsElement.updateSuggestions();
+				}
+				handled = true;
 			}
-			editor.setCursor(10000);
-			return;
 		}
 		if (eventKey == Keyboard.KEY_ESCAPE && !(this instanceof SleepScreenMP)) {
 			mc.displayScreen(null);
-			return;
+			handled = true;
 		}
 		if (eventKey == Keyboard.KEY_RETURN) {
 			String s = message.trim();
@@ -103,9 +149,14 @@ public class ChatScreen extends Screen implements ITextField {
 				mc.thePlayer.sendChatMessage(s1);
 			}
 			mc.displayScreen(null);
-			return;
+			handled = true;
+		}
+		if (!handled) {
+			editor.handleInput(eventKey, eventCharacter);
+		}
+		if (this.suggestionsElement != null) {
+			this.suggestionsElement.keyTyped(eventCharacter, eventKey);
 		}
-		editor.handleInput(eventKey, eventCharacter);
 	}
 
 	@Override
@@ -123,9 +174,10 @@ public class ChatScreen extends Screen implements ITextField {
 
 		drawRect(16, height - 14, width - 2, height - 2, 0x80000000);
 
+		font.drawStringWithShadow(this.suggestionsElement.getSuggestionPreview(), 16 + suggestionsElement.getDefaultParameterPosition(), mc.resolution.getScaledHeightScreenCoords() - 12, 0xFFFFFF);
 		boolean drawCursor = (updateCounter / 6) % 2 == 0;
 		int cursor = editor.getCursor();
-		drawString(font, message, 18, height - 12, 0xE0E0E0);
+		drawString(font, this.suggestionsElement.colorCodeText(message, true), 18, height - 12, 0xE0E0E0);
 		if (drawCursor)
 		{
 			int width = font.getStringWidth(message);
@@ -141,22 +193,31 @@ public class ChatScreen extends Screen implements ITextField {
 		}
 
 		super.render(xm, ym, partialTick);
+		if (this.suggestionsElement != null) {
+			this.suggestionsElement.drawScreen();
+		}
 	}
 
 	@Override
 	public void mouseClicked(int mx, int my, int buttonNum) {
 		super.mouseClicked(mx, my, buttonNum);
+		boolean handled = false;
 		if (buttonNum == 0) {
 			if (mx >= 2 && mx < 14 && my >= height - 14 && my < height - 2) {
 				showEmotePicker = !showEmotePicker;
-				return;
+				handled = true;
 			}
-			if (showEmotePicker) {
+			if (!handled && showEmotePicker) {
 				Character c = emotePicker.click(mx - 2, my - (height - 16 - emotePicker.getHeight()));
 				if (c != null) {
 					editor.handleInput(0, c);
 					if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && !Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) showEmotePicker = false;
-					return;
+					handled = true;
+				}
+			}
+			if (!handled) {
+				if (this.suggestionsElement != null) {
+					this.suggestionsElement.mouseClicked(mx, my, buttonNum);
 				}
 			}
 		}
diff --git a/src/main/java/net/minecraft/client/gui/chat/ChatSuggestionsElement.java b/src/main/java/net/minecraft/client/gui/chat/ChatSuggestionsElement.java
new file mode 100644
index 000000000..02e6e6563
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/chat/ChatSuggestionsElement.java
@@ -0,0 +1,521 @@
+package net.minecraft.client.gui.chat;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.context.CommandContextBuilder;
+import com.mojang.brigadier.context.ParsedArgument;
+import com.mojang.brigadier.context.StringRange;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestion;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.tree.CommandNode;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.TooltipElement;
+import net.minecraft.client.gui.hud.component.ComponentAnchor;
+import net.minecraft.client.gui.text.ITextField;
+import net.minecraft.client.gui.text.TextFieldEditor;
+import net.minecraft.client.net.command.ClientCommandSource;
+import net.minecraft.client.render.Font;
+import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.net.command.*;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.packet.RequestCommandManagerPacket;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+@SuppressWarnings({"OptionalGetWithoutIsPresent", "unused"})
+public class ChatSuggestionsElement extends Gui {
+    private final TextFieldEditor editor;
+    private final ITextField textField;
+    private final Minecraft mc;
+    private final Font fontRenderer;
+    private final CommandSource commandSource;
+    private final PositionSupplier<Integer> xSupplier;
+    private final PositionSupplier<Integer> ySupplier;
+    private ComponentAnchor anchor;
+    @Nullable
+    private ParseResults<CommandSource> parseResults;
+    @Nullable
+    private CompletableFuture<Suggestions> pendingSuggestions;
+    private int commandIndex = -1;
+    private String tablessMessage;
+    private int tablessCursor;
+    private List<Suggestion> suggestions = new ArrayList<>();
+    private int scroll = 0;
+    TooltipElement tooltip;
+    public static JsonObject serverSuggestions;
+
+    private static final int MAX_SUGGESTIONS = 10;
+    private static final boolean SUGGESTIONS_FOLLOW_PARAMETERS = true;
+    private static final List<String> ARGUMENT_STYLES = new ArrayList<>();
+    static {
+        ARGUMENT_STYLES.add(TextFormatting.LIGHT_BLUE.toString());
+        ARGUMENT_STYLES.add(TextFormatting.YELLOW.toString());
+        ARGUMENT_STYLES.add(TextFormatting.LIME.toString());
+        ARGUMENT_STYLES.add(TextFormatting.PINK.toString());
+        ARGUMENT_STYLES.add(TextFormatting.ORANGE.toString());
+    }
+
+    public boolean hidden = false;
+
+    public ChatSuggestionsElement(Minecraft mc, TextFieldEditor textFieldEditor, ITextField textField, PositionSupplier<Integer> xSupplier, PositionSupplier<Integer> ySupplier, ComponentAnchor anchor) {
+        this.mc = mc;
+        this.xSupplier = xSupplier;
+        this.ySupplier = ySupplier;
+        this.anchor = anchor;
+        this.fontRenderer = this.mc.font;
+        this.commandSource = new ClientCommandSource(this.mc);
+        this.editor = textFieldEditor;
+        this.textField = textField;
+        this.tablessMessage = this.textField.getText();
+        this.tablessCursor = this.editor.getCursor();
+        this.tooltip = new TooltipElement(this.mc);
+        serverSuggestions = new JsonObject();
+    }
+
+    public CommandManager getManager() {
+        return this.mc.theWorld == null ? new CommandManager(false) : mc.theWorld.getCommandManager();
+    }
+
+    public void drawScreen() {
+        if (this.hidden) return;
+        CommandSyntaxException parseException;
+
+        if (!this.suggestions.isEmpty()) {
+            this.renderSuggestions(this.fontRenderer, this.tablessMessage, this.suggestions.get(0).getRange().getStart());
+        } else if (this.parseResults != null) {
+            if (!this.parseResults.getExceptions().isEmpty()) {
+                int i = 0;
+                for (Exception e : this.parseResults.getExceptions().values()) {
+                    this.renderSingleSuggestionLine(this.mc.font, TextFormatting.RED + e.getMessage(), i, false);
+                    i++;
+                }
+            } else if ((parseException = CommandManager.getParseException(this.parseResults)) != null) {
+                this.renderSingleSuggestionLine(this.mc.font, TextFormatting.RED + parseException.getMessage(), 0, false);
+            } else {
+                List<String> commandUsage = getCommandUsage(this.tablessCursor);
+                for (int i = 0; i < commandUsage.size(); i++) {
+                    this.renderSingleSuggestionLine(this.mc.font, TextFormatting.LIGHT_GRAY + commandUsage.get(i), i, true);
+                }
+            }
+        } else if (!serverSuggestions.isEmpty()) {
+            if (serverSuggestions.has(CommandManagerPacketKeys.USAGE) && !serverSuggestions.getAsJsonArray(CommandManagerPacketKeys.USAGE).isEmpty()) {
+                for (int i = 0; i < serverSuggestions.getAsJsonArray(CommandManagerPacketKeys.USAGE).size(); i++) {
+                    this.renderSingleSuggestionLine(this.mc.font, TextFormatting.LIGHT_GRAY + serverSuggestions.getAsJsonArray(CommandManagerPacketKeys.USAGE).get(i).getAsJsonObject().get(CommandManagerPacketKeys.VALUE).getAsString(), i, true);
+                }
+            } else if (!serverSuggestions.getAsJsonArray(CommandManagerPacketKeys.EXCEPTIONS).isEmpty()) {
+                int i = 0;
+                for (JsonElement exception : serverSuggestions.getAsJsonArray(CommandManagerPacketKeys.EXCEPTIONS)) {
+                    this.renderSingleSuggestionLine(this.mc.font, TextFormatting.RED + exception.getAsJsonObject().get(CommandManagerPacketKeys.VALUE).getAsString(), i, false);
+                    i++;
+                }
+            }
+        }
+    }
+
+    private void renderSuggestions(Font fontRenderer, String message, int start) {
+        int mouseX = getScaledMouseX(this.mc);
+        int mouseY = getScaledMouseY(this.mc) - 1;
+
+        int leftMargin = this.xSupplier.get(this.textField, this, this.mc, SUGGESTIONS_FOLLOW_PARAMETERS);
+
+        int largestSuggestion = 0;
+        for (Suggestion suggestion : this.suggestions)
+            if (fontRenderer.getStringWidth(suggestion.getText()) > largestSuggestion)
+                largestSuggestion = fontRenderer.getStringWidth(suggestion.getText());
+
+        leftMargin -= (int) (this.anchor.xPosition * (largestSuggestion + 2));
+
+        int minY = this.ySupplier.get(this.textField, this, this.mc, SUGGESTIONS_FOLLOW_PARAMETERS);
+        int suggestionBoxHeight = Math.min(this.suggestions.size(), MAX_SUGGESTIONS) * 12;
+
+        minY += (int) CommandHelper.linearInterpolation(this.anchor.yPosition, 1, -suggestionBoxHeight - 1);
+
+        this.drawRect(leftMargin, minY, largestSuggestion + leftMargin + 1, minY + suggestionBoxHeight, Integer.MIN_VALUE);
+        if (this.scroll < this.suggestions.size() - MAX_SUGGESTIONS)
+            drawDottedRect(this, leftMargin, minY + suggestionBoxHeight, largestSuggestion + leftMargin + 1, minY + suggestionBoxHeight + 1, Color.WHITE.getRGB(), 1);
+        if (this.scroll != 0)
+            drawDottedRect(this, leftMargin, minY - 1, largestSuggestion + leftMargin + 1, minY, Color.WHITE.getRGB(), 1);
+
+        for (int i = 0; i < Math.min(this.suggestions.size(), MAX_SUGGESTIONS); i++) {
+            String suggestionText = this.suggestions.get(i + this.scroll).getText();
+            int suggestionHeight = 12 * (-i + Math.min(this.suggestions.size(), MAX_SUGGESTIONS) - 2) + 25;
+            String colorCode;
+            if (i + this.scroll == this.commandIndex || (this.isHoveringOverSuggestions(mouseX, mouseY) && i + this.scroll == this.getIndexOfSuggestionBeingHoveredOver(mouseX, mouseY).get())) {
+                colorCode = TextFormatting.YELLOW.toString();
+            } else {
+                colorCode = TextFormatting.LIGHT_GRAY.toString();
+            }
+
+            int textX = (int) (leftMargin + 1 + (this.anchor.xPosition * (largestSuggestion - fontRenderer.getStringWidth(suggestionText))));
+
+            fontRenderer.drawStringWithShadow(colorCode + suggestionText, textX, minY + suggestionBoxHeight - suggestionHeight + 3, 0xE0E0E0);
+        }
+
+        if (this.isHoveringOverSuggestions(mouseX, mouseY) && this.suggestions.get(this.getIndexOfSuggestionBeingHoveredOver(mouseX, mouseY).get()).getTooltip() != null) {
+            this.tooltip.render(this.suggestions.get(this.getIndexOfSuggestionBeingHoveredOver(mouseX, mouseY).get()).getTooltip().getString(), mouseX, mouseY, 0, 0);
+        }
+    }
+
+    private void renderSingleSuggestionLine(Font fontRenderer, String text, int heightIndex, boolean followParameters) {
+        int leftMargin = this.xSupplier.get(this.textField, this, this.mc, SUGGESTIONS_FOLLOW_PARAMETERS && followParameters);
+        int stringWidth = fontRenderer.getStringWidth(text);
+
+        leftMargin -= (int) (this.anchor.xPosition * (stringWidth + 2));
+
+        int minY = this.ySupplier.get(this.textField, this, this.mc, SUGGESTIONS_FOLLOW_PARAMETERS && followParameters);
+
+        minY += (int) CommandHelper.linearInterpolation(this.anchor.yPosition, heightIndex * 12, -12 - heightIndex * 12);
+
+        this.drawRect(leftMargin, minY, stringWidth + leftMargin + 1, minY + 12, Integer.MIN_VALUE);
+        fontRenderer.drawStringWithShadow(text, leftMargin + 1, minY + 2, 0xE0E0E0);
+    }
+
+    private List<String> getCommandUsage(int cursor) {
+        List<String> commandUsage = new ArrayList<>();
+        if (this.parseResults == null || this.parseResults.getContext().getRootNode() == null || this.parseResults.getContext().getRange().getStart() > cursor)
+            return commandUsage;
+        for (Map.Entry<CommandNode<CommandSource>, String> entry : this.getManager().getDispatcher().getSmartUsage(this.parseResults.getContext().findSuggestionContext(cursor).parent, this.commandSource).entrySet()) {
+            if (entry.getKey() instanceof LiteralCommandNode) continue;
+            commandUsage.add(entry.getValue());
+        }
+        return commandUsage;
+    }
+
+    public void keyTyped(char c, int key) {
+        int mouseX = getScaledMouseX(this.mc);
+        int mouseY = getScaledMouseY(this.mc) - 1;
+
+        int TAB = 15;
+        int LEFT_SHIFT = 42;
+
+        if (key == TAB) {
+            if (this.commandIndex == -1 && this.isHoveringOverSuggestions(mouseX, mouseY)) {
+                this.cycleToSuggestion(this.getIndexOfSuggestionBeingHoveredOver(mouseX, mouseY).get());
+            } else if (Keyboard.isKeyDown(LEFT_SHIFT)) {
+                this.cycleThroughSuggestions(-1);
+            } else {
+                this.cycleThroughSuggestions();
+            }
+            return;
+        }
+
+        if (!this.shouldApplySuggestion(c, key)) return;
+
+        updateSuggestions();
+    }
+
+    public void updateSuggestions() {
+        this.resetAllManagerVariables();
+        String text = this.editor.getText();
+        int cursor = this.editor.getCursor();
+        if (this.parseResults != null && !this.parseResults.getReader().getString().equals(text)) {
+            this.parseResults = null;
+        }
+
+        StringReader stringReader = new StringReader(text);
+
+        if (this.mc.isMultiplayerWorld()) {
+            this.parseResults = null;
+            this.mc.getSendQueue().addToSendQueue(new RequestCommandManagerPacket(this.mc.thePlayer.username, text, cursor));
+        } else {
+            if (stringReader.canRead() && stringReader.peek() == '/') stringReader.skip();
+            CommandDispatcher<CommandSource> dispatcher = this.getManager().getDispatcher();
+            if (this.parseResults == null) {
+                this.parseResults = dispatcher.parse(stringReader, this.commandSource);
+            }
+            if (cursor >= 1 || text.isEmpty()) {
+                this.pendingSuggestions = dispatcher.getCompletionSuggestions(this.parseResults, cursor);
+                this.pendingSuggestions.thenRun(() -> {
+                    if (this.pendingSuggestions.isDone()) {
+                        this.finishUpdatingSuggestions();
+                    }
+                });
+            }
+        }
+    }
+
+    private boolean shouldApplySuggestion(char c, int key) {
+        return this.textField.isCharacterAllowed(c)
+            || ((key == 46 || key == 47) && (Keyboard.isKeyDown(29) || Keyboard.isKeyDown(157)))
+            || key == 199
+            || key == 207
+            || key == 203
+            || key == 205
+            || key == 14
+            || key == 211;
+    }
+
+    private void finishUpdatingSuggestions() {
+        this.suggestions = new ArrayList<>();
+        if (this.hidden) return;
+        if (!serverSuggestions.isEmpty()) {
+            for (JsonElement jsonSuggestion : serverSuggestions.getAsJsonArray(CommandManagerPacketKeys.SUGGESTIONS)) {
+                Suggestion suggestion;
+                if (jsonSuggestion.getAsJsonObject().has(CommandManagerPacketKeys.TOOLTIP)) {
+                    suggestion = new Suggestion(new StringRange(jsonSuggestion.getAsJsonObject().get(CommandManagerPacketKeys.RANGE).getAsJsonObject().get(CommandManagerPacketKeys.RANGE_START).getAsInt(), jsonSuggestion.getAsJsonObject().get(CommandManagerPacketKeys.RANGE).getAsJsonObject().get(CommandManagerPacketKeys.RANGE_END).getAsInt()), jsonSuggestion.getAsJsonObject().get(CommandManagerPacketKeys.VALUE).getAsString(), () -> jsonSuggestion.getAsJsonObject().get(CommandManagerPacketKeys.TOOLTIP).getAsString());
+                } else {
+                    suggestion = new Suggestion(new StringRange(jsonSuggestion.getAsJsonObject().get(CommandManagerPacketKeys.RANGE).getAsJsonObject().get(CommandManagerPacketKeys.RANGE_START).getAsInt(), jsonSuggestion.getAsJsonObject().get(CommandManagerPacketKeys.RANGE).getAsJsonObject().get(CommandManagerPacketKeys.RANGE_END).getAsInt()), jsonSuggestion.getAsJsonObject().get(CommandManagerPacketKeys.VALUE).getAsString());
+                }
+                if (this.tablessCursor <= this.tablessMessage.length() && suggestion.getText().startsWith(this.tablessMessage.substring(Math.min(suggestion.getRange().getStart(), this.tablessMessage.length()), Math.min(this.tablessCursor, Math.min(suggestion.getRange().getStart(), this.tablessMessage.length()))))) {
+                    this.suggestions.add(suggestion);
+                }
+            }
+        } else if (this.pendingSuggestions != null && this.pendingSuggestions.isDone()) {
+            Suggestions suggestions = this.pendingSuggestions.join();
+            this.suggestions.addAll(suggestions.getList());
+        }
+    }
+
+    public void updateScreen(int dWheel) {
+        this.finishUpdatingSuggestions();
+        int cursorX = getScaledMouseX(this.mc);
+        int cursorY = getScaledMouseY(this.mc);
+        if (this.isHoveringOverSuggestions(cursorX, cursorY) && dWheel != 0) {
+            this.scroll(Math.round(Math.signum(dWheel)) * -1);
+        }
+    }
+
+    public void mouseClicked(int x, int y, int button) {
+        if (isHoveringOverSuggestions(x, y) && button == 0) {
+            this.cycleToSuggestion(this.getIndexOfSuggestionBeingHoveredOver(x, y).get());
+        }
+    }
+
+    public boolean isHoveringOverSuggestions(int cursorX, int cursorY) {
+        return this.getIndexOfSuggestionBeingHoveredOver(cursorX, cursorY).isPresent();
+    }
+
+    public Optional<Integer> getIndexOfSuggestionBeingHoveredOver(int cursorX, int cursorY) {
+        if (this.suggestions.isEmpty() || this.hidden) return Optional.empty();
+
+        int minX = this.xSupplier.get(this.textField, this, this.mc, SUGGESTIONS_FOLLOW_PARAMETERS);
+
+        int largestSuggestion = 0;
+        for (Suggestion suggestion : this.suggestions)
+            if (this.fontRenderer.getStringWidth(suggestion.getText()) > largestSuggestion)
+                largestSuggestion = this.fontRenderer.getStringWidth(suggestion.getText());
+
+        minX -= (int) (this.anchor.xPosition * (largestSuggestion + 2));
+
+        int minY = this.ySupplier.get(this.textField, this, this.mc, SUGGESTIONS_FOLLOW_PARAMETERS);
+        int suggestionBoxHeight = Math.min(this.suggestions.size(), MAX_SUGGESTIONS) * 12;
+
+        minY += (int) CommandHelper.linearInterpolation(this.anchor.yPosition, 1, -suggestionBoxHeight - 1);
+
+        int maxX = largestSuggestion + minX + 1;
+        for (int i = 0; i < Math.min(this.suggestions.size(), MAX_SUGGESTIONS); i++) {
+            int suggestionHeight = 12 * (-i + Math.min(this.suggestions.size(), MAX_SUGGESTIONS) - 2) + 25;
+            int suggestionMinY = minY + suggestionBoxHeight - suggestionHeight + 2;
+            int suggestionMaxY = suggestionMinY + 12;
+
+            if (cursorX >= minX && cursorX < maxX && cursorY >= suggestionMinY && cursorY < suggestionMaxY) {
+                return Optional.of(i + this.scroll);
+            }
+        }
+        return Optional.empty();
+    }
+
+    private void resetAllManagerVariables() {
+        this.commandIndex = -1;
+        this.tablessMessage = this.textField.getText();
+        this.tablessCursor = this.editor.getCursor();
+        this.scroll = 0;
+    }
+
+    public void scroll(int amount) {
+        if (this.scroll + amount >= 0 && this.scroll + amount <= this.suggestions.size() - MAX_SUGGESTIONS) {
+            this.scroll += amount;
+        }
+    }
+
+    public void cycleThroughSuggestions() {
+        this.cycleThroughSuggestions(1);
+    }
+
+    public void cycleThroughSuggestions(int amount) {
+        this.cycleToSuggestion(this.commandIndex + amount);
+    }
+
+    public void cycleToSuggestion(int index) {
+        if (this.suggestions.isEmpty()) return;
+        if (index < 0) index += this.suggestions.size();
+        this.commandIndex = index % this.suggestions.size();
+        Suggestion suggestion = this.suggestions.get(this.commandIndex);
+        this.editor.setText(suggestion.apply(this.tablessMessage));
+        this.editor.setCursor(suggestion.getRange().getStart() + suggestion.getText().length());
+        if (this.commandIndex >= this.scroll + MAX_SUGGESTIONS) {
+            this.scroll = this.commandIndex - MAX_SUGGESTIONS + 1;
+        } else if (this.commandIndex < this.scroll) {
+            this.scroll = this.commandIndex;
+        }
+    }
+
+    public List<Suggestion> getSuggestions() {
+        return new ArrayList<>(this.suggestions);
+    }
+
+    public int getScroll() {
+        return this.scroll;
+    }
+
+    public int getCommandIndex() {
+        return this.commandIndex;
+    }
+
+    public String getMessage() {
+        return this.tablessMessage;
+    }
+
+    public int getCursor() {
+        return this.tablessCursor;
+    }
+
+    public @Nullable ParseResults<CommandSource> getParseResults() {
+        return this.parseResults;
+    }
+
+    public CommandSource getCommandSource() {
+        return this.commandSource;
+    }
+
+    public int getSuggestionRangeStart() {
+        if (!this.suggestions.isEmpty()) {
+            return this.suggestions.get(0).getRange().getStart();
+        } else if (serverSuggestions.has(CommandManagerPacketKeys.SUGGESTION_CONTEXT_START_POS)) {
+            return serverSuggestions.get(CommandManagerPacketKeys.SUGGESTION_CONTEXT_START_POS).getAsInt();
+        }
+        return this.parseResults != null ? this.parseResults.getContext().findSuggestionContext(this.tablessCursor).startPos : 0;
+    }
+
+    public void setAnchor(ComponentAnchor anchor) {
+        this.anchor = anchor;
+    }
+
+    public String colorCodeText(String text, boolean requireSlash) {
+        if (this.parseResults != null && !this.parseResults.getReader().getString().equals(text)) {
+            this.parseResults = null;
+        }
+
+        StringReader stringReader = new StringReader(text);
+        boolean isCommand = (stringReader.canRead() && stringReader.peek() == '/') || !requireSlash;
+        if (!isCommand || text.isEmpty()) return text;
+        if (!serverSuggestions.isEmpty() && serverSuggestions.get(CommandManagerPacketKeys.LAST_CHILD) != null && serverSuggestions.get(CommandManagerPacketKeys.LAST_CHILD).getAsJsonObject().get(CommandManagerPacketKeys.ARGUMENTS) != null) {
+            StringBuilder stringToDrawBuilder = new StringBuilder();
+            int currentArgumentEnd = 0;
+            int currentColor = 0;
+            for (JsonElement jsonElement : serverSuggestions.getAsJsonObject(CommandManagerPacketKeys.LAST_CHILD).getAsJsonArray(CommandManagerPacketKeys.ARGUMENTS)) {
+                int rangeStart = jsonElement.getAsJsonObject().getAsJsonObject(CommandManagerPacketKeys.RANGE).get(CommandManagerPacketKeys.RANGE_START).getAsInt();
+                int rangeEnd = jsonElement.getAsJsonObject().getAsJsonObject(CommandManagerPacketKeys.RANGE).get(CommandManagerPacketKeys.RANGE_END).getAsInt();
+
+                stringToDrawBuilder.append(TextFormatting.LIGHT_GRAY).append(text, Math.min(currentArgumentEnd, text.length()), Math.min(rangeStart, text.length()));
+                stringToDrawBuilder.append(ARGUMENT_STYLES.get(currentColor)).append(text, Math.min(rangeStart, text.length()), Math.min(rangeEnd, text.length()));
+
+                currentArgumentEnd = rangeEnd;
+                if (++currentColor >= ARGUMENT_STYLES.size()) {
+                    currentColor = 0;
+                }
+            }
+            if (serverSuggestions.getAsJsonObject(CommandManagerPacketKeys.READER).get(CommandManagerPacketKeys.READER_CAN_READ).getAsBoolean() && currentArgumentEnd < text.length()) {
+                int remainingTextLength = serverSuggestions.getAsJsonObject(CommandManagerPacketKeys.READER).get(CommandManagerPacketKeys.READER_REMAINING_TEXT_LENGTH).getAsInt();
+                stringToDrawBuilder.append(TextFormatting.LIGHT_GRAY).append(text, currentArgumentEnd, Math.min(serverSuggestions.getAsJsonObject(CommandManagerPacketKeys.READER).get(CommandManagerPacketKeys.READER_CURSOR).getAsInt(), text.length()));
+                stringToDrawBuilder.append(TextFormatting.RED).append(text, Math.min(serverSuggestions.getAsJsonObject(CommandManagerPacketKeys.READER).get(CommandManagerPacketKeys.READER_CURSOR).getAsInt(), text.length()), Math.min(remainingTextLength, text.length()));
+                currentArgumentEnd = remainingTextLength;
+            }
+            stringToDrawBuilder.append(TextFormatting.LIGHT_GRAY).append(text.substring(Math.min(currentArgumentEnd, text.length())));
+
+            return stringToDrawBuilder.toString();
+        } else {
+            if (stringReader.canRead() && stringReader.peek() == '/') stringReader.skip();
+            CommandDispatcher<CommandSource> dispatcher = this.getManager().getDispatcher();
+            if (this.parseResults == null) {
+                this.parseResults = dispatcher.parse(stringReader, this.getCommandSource());
+            }
+            StringBuilder stringToDrawBuilder = new StringBuilder();
+            CommandContextBuilder<CommandSource> builder = this.parseResults.getContext().getLastChild();
+            int readerCursor;
+            int currentArgumentEnd = 0;
+            int currentColor = -1;
+            for (ParsedArgument<CommandSource, ?> parsedArgument : builder.getArguments().values()) {
+                int rangeStart;
+                if (++currentColor >= ARGUMENT_STYLES.size()) {
+                    currentColor = 0;
+                }
+                if ((rangeStart = Math.max(parsedArgument.getRange().getStart(), 0)) >= text.length()) break;
+                int rangeEnd = Math.min(parsedArgument.getRange().getEnd(), text.length());
+                if (rangeEnd <= 0) continue;
+                stringToDrawBuilder.append(TextFormatting.LIGHT_GRAY).append(text, currentArgumentEnd, rangeStart);
+                stringToDrawBuilder.append(ARGUMENT_STYLES.get(currentColor)).append(text, rangeStart, rangeEnd);
+                currentArgumentEnd = rangeEnd;
+            }
+            if (this.parseResults.getReader().canRead() && (readerCursor = Math.max(this.parseResults.getReader().getCursor(), 0)) < text.length()) {
+                int remainingTextLength = Math.min(readerCursor + this.parseResults.getReader().getRemainingLength(), text.length());
+                stringToDrawBuilder.append(TextFormatting.LIGHT_GRAY).append(text, currentArgumentEnd, readerCursor);
+                stringToDrawBuilder.append(TextFormatting.RED).append(text, readerCursor, remainingTextLength);
+                currentArgumentEnd = remainingTextLength;
+            }
+            stringToDrawBuilder.append(TextFormatting.LIGHT_GRAY).append(text.substring(currentArgumentEnd));
+            return stringToDrawBuilder.toString();
+        }
+    }
+
+    public String getSuggestionPreview() {
+        int mouseX = getScaledMouseX(this.mc);
+        int mouseY = getScaledMouseY(this.mc) - 1;
+
+        if (this.shouldDrawSuggestionPreview()) {
+            Suggestion suggestionToRender = null;
+            if (this.isHoveringOverSuggestions(mouseX, mouseY)) {
+                suggestionToRender = this.getSuggestions().get(this.getIndexOfSuggestionBeingHoveredOver(mouseX, mouseY).get());
+            } else if (!this.getSuggestions().isEmpty()) {
+                suggestionToRender = this.getSuggestions().get(0);
+            }
+
+            if (suggestionToRender != null && suggestionToRender.getText().startsWith(this.editor.getText().substring(Math.min(suggestionToRender.getRange().getStart(), this.editor.getText().length())))) {
+                return TextFormatting.LIGHT_GRAY + suggestionToRender.getText();
+            }
+        }
+        return "";
+    }
+
+    private boolean shouldDrawSuggestionPreview() {
+        boolean basedOnParseResults = this.parseResults != null && (this.tablessCursor == this.parseResults.getReader().getString().trim().length() || this.tablessCursor == this.parseResults.getReader().getString().length());
+        boolean basedOnServer = serverSuggestions.has(CommandManagerPacketKeys.READER) && (this.tablessCursor == serverSuggestions.getAsJsonObject(CommandManagerPacketKeys.READER).get(CommandManagerPacketKeys.READER_STRING).getAsString().trim().length() || this.tablessCursor == serverSuggestions.getAsJsonObject(CommandManagerPacketKeys.READER).get(CommandManagerPacketKeys.READER_STRING).getAsString().length());
+        return basedOnParseResults || basedOnServer;
+    }
+
+    public int getDefaultParameterPosition() {
+        return this.fontRenderer.getStringWidth(this.getMessage().substring(0, Math.min(this.getSuggestionRangeStart(), this.getMessage().length()))) + 2;
+    }
+
+    public static void drawDottedRect(Gui gui, int minX, int minY, int maxX, int maxY, int argb, int dotSize) {
+        for (int i = 0; i < (maxX - minX) / dotSize; i++) {
+            for (int j = 0; j < (maxY - minY) / dotSize; j++) {
+                if ((i + j) % 2 == 0) {
+                    gui.drawRect(minX + i * dotSize, minY + j * dotSize, minX + i * dotSize + dotSize, minY + j * dotSize + dotSize, argb);
+                }
+            }
+        }
+    }
+
+    public static int getScaledMouseX(Minecraft mc) {
+        return Mouse.getX() / mc.resolution.getScale();
+    }
+
+    public static int getScaledMouseY(Minecraft mc) {
+        return mc.resolution.getScaledHeightScreenCoords() - (Mouse.getY() / mc.resolution.getScale());
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/chat/PositionSupplier.java b/src/main/java/net/minecraft/client/gui/chat/PositionSupplier.java
new file mode 100644
index 000000000..36c6ed783
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/chat/PositionSupplier.java
@@ -0,0 +1,10 @@
+package net.minecraft.client.gui.chat;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.text.ITextField;
+
+@FunctionalInterface
+public interface PositionSupplier<T extends Number> {
+    T get(ITextField parent, Gui child, Minecraft mc, boolean followParameters);
+}
diff --git a/src/main/java/net/minecraft/client/gui/SleepScreenMP.java b/src/main/java/net/minecraft/client/gui/chat/SleepScreenMP.java
similarity index 95%
rename from src/main/java/net/minecraft/client/gui/SleepScreenMP.java
rename to src/main/java/net/minecraft/client/gui/chat/SleepScreenMP.java
index 93e9c15f9..e67cd2f9f 100644
--- a/src/main/java/net/minecraft/client/gui/SleepScreenMP.java
+++ b/src/main/java/net/minecraft/client/gui/chat/SleepScreenMP.java
@@ -1,6 +1,7 @@
-package net.minecraft.client.gui;
+package net.minecraft.client.gui.chat;
 
 import net.minecraft.client.entity.player.MultiplayerLocalPlayer;
+import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.net.handler.ClientPacketHandler;
 import net.minecraft.core.net.packet.PlayerCommandPacket;
 import net.minecraft.core.util.helper.MathHelper;
@@ -28,6 +29,7 @@ public class SleepScreenMP extends ChatScreen
 		int emotePickerYCells = (int)MathHelper.clamp(Math.ceil(ChatEmotes.getEmotes().size() / 5.0), 0, 4);
 		emotePicker = new ChatEmotePickerElement(mc, this, 5, emotePickerYCells);
 		showEmotePicker = false;
+        super.init();
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/core/player/inventory/slot/GuidebookSlot.java b/src/main/java/net/minecraft/client/gui/guidebook/GuidebookSlot.java
similarity index 93%
rename from src/main/java/net/minecraft/core/player/inventory/slot/GuidebookSlot.java
rename to src/main/java/net/minecraft/client/gui/guidebook/GuidebookSlot.java
index 631e25bc5..5c974c092 100644
--- a/src/main/java/net/minecraft/core/player/inventory/slot/GuidebookSlot.java
+++ b/src/main/java/net/minecraft/client/gui/guidebook/GuidebookSlot.java
@@ -1,5 +1,6 @@
-package net.minecraft.core.player.inventory.slot;
+package net.minecraft.client.gui.guidebook;
 
+import net.minecraft.client.Minecraft;
 import net.minecraft.client.entity.player.LocalPlayer;
 import net.minecraft.core.WeightedRandomBag;
 import net.minecraft.core.WeightedRandomLootObject;
@@ -8,9 +9,9 @@ import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
 import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel;
 import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.gamemode.Gamemode;
+import net.minecraft.core.player.inventory.slot.Slot;
 
 import java.util.List;
 import java.util.Random;
@@ -116,7 +117,8 @@ public class GuidebookSlot extends Slot
 	public boolean getIsDiscovered(Player player){
 		if (item == null || discovered) return true;
 		if (player instanceof LocalPlayer){
-			if (!((LocalPlayer) player).sender.minecraft.gameSettings.hideUndiscoveredItems.value) return true;
+			Minecraft mc = Minecraft.getMinecraft(this);
+			if (!mc.gameSettings.hideUndiscoveredItems.value) return true;
 		}
 		return player.getStat(item.getItem().getStat(StatList.STAT_PICKED_UP)) > 0 || player.getGamemode() == Gamemode.creative;
 	}
diff --git a/src/main/java/net/minecraft/client/gui/guidebook/crafting/CraftingPage.java b/src/main/java/net/minecraft/client/gui/guidebook/crafting/CraftingPage.java
index c1d084552..ee9512c2e 100644
--- a/src/main/java/net/minecraft/client/gui/guidebook/crafting/CraftingPage.java
+++ b/src/main/java/net/minecraft/client/gui/guidebook/crafting/CraftingPage.java
@@ -20,7 +20,7 @@ import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingShaped;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingShapeless;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.player.inventory.slot.Slot;
-import net.minecraft.core.player.inventory.slot.GuidebookSlot;
+import net.minecraft.client.gui.guidebook.GuidebookSlot;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
diff --git a/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobPage.java b/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobPage.java
index fd208ccdb..68385cd6a 100644
--- a/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobPage.java
+++ b/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobPage.java
@@ -18,7 +18,7 @@ import net.minecraft.core.entity.animal.FireflyClusterMob;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.player.inventory.slot.Slot;
-import net.minecraft.core.player.inventory.slot.GuidebookSlot;
+import net.minecraft.client.gui.guidebook.GuidebookSlot;
 import net.minecraft.core.world.World;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
diff --git a/src/main/java/net/minecraft/client/gui/guidebook/smelting/BlastSmeltingPage.java b/src/main/java/net/minecraft/client/gui/guidebook/smelting/BlastSmeltingPage.java
index 25779dde6..6e2d40968 100644
--- a/src/main/java/net/minecraft/client/gui/guidebook/smelting/BlastSmeltingPage.java
+++ b/src/main/java/net/minecraft/client/gui/guidebook/smelting/BlastSmeltingPage.java
@@ -18,7 +18,7 @@ import net.minecraft.core.data.registry.recipe.SearchQuery;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryBlastFurnace;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.player.inventory.slot.Slot;
-import net.minecraft.core.player.inventory.slot.GuidebookSlot;
+import net.minecraft.client.gui.guidebook.GuidebookSlot;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
diff --git a/src/main/java/net/minecraft/client/gui/guidebook/smelting/SmeltingPage.java b/src/main/java/net/minecraft/client/gui/guidebook/smelting/SmeltingPage.java
index 29faa9f19..7aeb8a6cd 100644
--- a/src/main/java/net/minecraft/client/gui/guidebook/smelting/SmeltingPage.java
+++ b/src/main/java/net/minecraft/client/gui/guidebook/smelting/SmeltingPage.java
@@ -18,7 +18,7 @@ import net.minecraft.core.data.registry.recipe.SearchQuery;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryFurnace;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.player.inventory.slot.Slot;
-import net.minecraft.core.player.inventory.slot.GuidebookSlot;
+import net.minecraft.client.gui.guidebook.GuidebookSlot;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
diff --git a/src/main/java/net/minecraft/client/gui/guidebook/trommeling/TrommelPage.java b/src/main/java/net/minecraft/client/gui/guidebook/trommeling/TrommelPage.java
index 43beb1898..aa9c5a0bc 100644
--- a/src/main/java/net/minecraft/client/gui/guidebook/trommeling/TrommelPage.java
+++ b/src/main/java/net/minecraft/client/gui/guidebook/trommeling/TrommelPage.java
@@ -21,7 +21,7 @@ import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.inventory.slot.Slot;
-import net.minecraft.core.player.inventory.slot.GuidebookSlot;
+import net.minecraft.client.gui.guidebook.GuidebookSlot;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
diff --git a/src/main/java/net/minecraft/client/gui/hud/IngameHud.java b/src/main/java/net/minecraft/client/gui/hud/IngameHud.java
index 49aea0227..45d7d43f4 100644
--- a/src/main/java/net/minecraft/client/gui/hud/IngameHud.java
+++ b/src/main/java/net/minecraft/client/gui/hud/IngameHud.java
@@ -11,7 +11,7 @@ import java.util.Map;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.entity.player.MultiplayerLocalPlayer;
-import net.minecraft.client.gui.ChatScreen;
+import net.minecraft.client.gui.chat.ChatScreen;
 import net.minecraft.client.gui.Gui;
 import net.minecraft.client.gui.HeldItemTooltipElement;
 import net.minecraft.client.gui.PhotoModeScreen;
diff --git a/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java b/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java
index 0fd3d1677..29434eb2c 100644
--- a/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java
+++ b/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java
@@ -3,7 +3,7 @@ package net.minecraft.client.gui.options.components;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.IntegerSliderElement;
 import net.minecraft.client.option.EnumOption;
-import net.minecraft.client.option.enums.Difficulty;
+import net.minecraft.core.enums.Difficulty;
 import net.minecraft.core.lang.I18n;
 
 public class DifficultyOptionComponent extends ButtonComponent {
diff --git a/src/main/java/net/minecraft/client/net/command/ClientCommandSource.java b/src/main/java/net/minecraft/client/net/command/ClientCommandSource.java
new file mode 100644
index 000000000..5589746bb
--- /dev/null
+++ b/src/main/java/net/minecraft/client/net/command/ClientCommandSource.java
@@ -0,0 +1,136 @@
+package net.minecraft.client.net.command;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ClientCommandSource implements CommandSource {
+    private final Minecraft mc;
+
+    public ClientCommandSource(Minecraft mc) {
+        this.mc = mc;
+    }
+
+    @Override
+    public Collection<String> getPlayerNames() {
+        List<String> list = new ArrayList<>();
+        for (Player player : this.mc.theWorld.players) {
+            list.add(player.username);
+        }
+        return list;
+    }
+
+    @Override
+    public Collection<String> getEntitySuggestions() {
+        List<String> suggestions = new ArrayList<>(this.getPlayerNames());
+        if (this.mc.objectMouseOver != null && this.mc.objectMouseOver.entity != null) {
+            suggestions.add(EntitySelector.ENTITY_PREFIX + this.mc.objectMouseOver.entity.hashCode());
+        }
+        return suggestions;
+    }
+
+    @Override
+    public String toString() {
+        return "ClientCommandSource{" + this.mc + "}";
+    }
+
+    @Override
+    public @NotNull Player getSender() {
+        return this.mc.thePlayer;
+    }
+
+    @Override
+    public boolean hasAdmin() {
+        return true;
+    }
+
+    @Override
+    public @NotNull Vec3 getCoordinates(boolean offsetHeight) {
+        Vec3 position = this.getSender().getPosition(1.0f);
+        if (offsetHeight) return position.add(0.0f, -this.getSender().heightOffset, 0.0f);
+        return position;
+    }
+
+    @Override
+    public @NotNull Vec3 getBlockCoordinates() {
+        if (this.mc.objectMouseOver != null) {
+            return Vec3.getTempVec3(this.mc.objectMouseOver.x, this.mc.objectMouseOver.y, this.mc.objectMouseOver.z);
+        }
+        Vec3 playerCoordinates = this.getCoordinates(true);
+        return Vec3.getTempVec3(MathHelper.floor(playerCoordinates.x), MathHelper.floor(playerCoordinates.y), MathHelper.floor(playerCoordinates.z));
+    }
+
+    @Override
+    public boolean messageMayBeMultiline() {
+        return !this.mc.thePlayer.username.equals("pr_ib");
+    }
+
+    @Override
+    public void sendMessage(String message) {
+        if (!this.mc.isMultiplayerWorld()) this.mc.ingameHud.addChatMessage(message);
+    }
+
+    @Override
+    public void sendMessage(Player player, String message) {
+        if (player == this.mc.thePlayer) {
+            this.sendMessage(message);
+        }
+    }
+
+    @Override
+    public void sendMessageToAllPlayers(String message) {
+        this.mc.thePlayer.sendChatMessage(message);
+    }
+
+    @Override
+    public World getWorld() {
+        return this.mc.theWorld;
+    }
+
+    @Override
+    public World getWorld(int dimension) {
+        return this.mc.theWorld.dimension.id == dimension ? this.mc.theWorld : new World(this.mc.theWorld, Dimension.getDimensionList().get(dimension));
+    }
+
+    public void movePlayerToDimension(Player player, int dimension) {
+        Dimension lastDim = Dimension.getDimensionList().get(player.dimension);
+        Dimension newDim = Dimension.getDimensionList().get(dimension);
+        System.out.println("Switching to dimension \"" + newDim.getTranslatedName() + "\"!!");
+        player.dimension = dimension;
+        this.mc.theWorld.setEntityDead(player);
+        this.mc.thePlayer.removed = false;
+        double x = player.x;
+        double y = player.y + 64;
+        double z = player.z;
+        player.moveTo(x *= Dimension.getCoordScale(lastDim, newDim), y, z *= Dimension.getCoordScale(lastDim, newDim), player.yRot, player.xRot);
+        if (player.isAlive()) {
+            this.mc.theWorld.updateEntityWithOptionalForce(player, false);
+        }
+        World world = new World(this.mc.theWorld, newDim);
+        if (newDim == lastDim.homeDim) {
+            this.mc.changeWorld(world, "Leaving " + lastDim.getTranslatedName(), player);
+        } else {
+            this.mc.changeWorld(world, "Entering " + newDim.getTranslatedName(), player);
+        }
+        player.world = this.mc.theWorld;
+        if (player.isAlive()) {
+            player.moveTo(x, y, z, player.yRot, player.xRot);
+            this.mc.theWorld.updateEntityWithOptionalForce(player, false);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return this.mc.thePlayer.username;
+    }
+}
diff --git a/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java b/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java
index 92d104a91..7c4ca71ac 100644
--- a/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java
+++ b/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java
@@ -9,6 +9,7 @@ import net.minecraft.client.entity.player.RemotePlayer;
 import net.minecraft.client.gui.ConnectFailedScreen;
 import net.minecraft.client.gui.DownloadTerrainScreen;
 import net.minecraft.client.gui.PauseScreen;
+import net.minecraft.client.gui.chat.ChatSuggestionsElement;
 import net.minecraft.client.gui.guidebook.GuidebookScreen;
 import net.minecraft.client.gui.guidebook.PageManager;
 import net.minecraft.client.gui.guidebook.search.SearchPage;
@@ -43,67 +44,7 @@ import net.minecraft.core.net.NetworkManager;
 import net.minecraft.core.net.PlayerProfile;
 import net.minecraft.core.net.entity.NetEntityHandler;
 import net.minecraft.core.net.handler.PacketHandler;
-import net.minecraft.core.net.packet.AESSendKeyPacket;
-import net.minecraft.core.net.packet.AddEntityPacket;
-import net.minecraft.core.net.packet.AddItemEntityPacket;
-import net.minecraft.core.net.packet.AddMobPacket;
-import net.minecraft.core.net.packet.AddPaintingPacket;
-import net.minecraft.core.net.packet.AddParticlePacket;
-import net.minecraft.core.net.packet.AddPlayerPacket;
-import net.minecraft.core.net.packet.AnimatePacket;
-import net.minecraft.core.net.packet.BedMessagePacket;
-import net.minecraft.core.net.packet.BlockEventPacket;
-import net.minecraft.core.net.packet.BlockRegionUpdatePacket;
-import net.minecraft.core.net.packet.BlockUpdatePacket;
-import net.minecraft.core.net.packet.ChatPacket;
-import net.minecraft.core.net.packet.ChunkBlocksUpdatePacket;
-import net.minecraft.core.net.packet.ChunkVisibilityPacket;
-import net.minecraft.core.net.packet.ContainerAckPacket;
-import net.minecraft.core.net.packet.ContainerClosePacket;
-import net.minecraft.core.net.packet.ContainerOpenPacket;
-import net.minecraft.core.net.packet.ContainerSetContentPacket;
-import net.minecraft.core.net.packet.ContainerSetDataPacket;
-import net.minecraft.core.net.packet.ContainerSetSlotPacket;
-import net.minecraft.core.net.packet.CustomPayloadPacket;
-import net.minecraft.core.net.packet.DisconnectPacket;
-import net.minecraft.core.net.packet.EnitityEventPacket;
-import net.minecraft.core.net.packet.EntityNicknamePacket;
-import net.minecraft.core.net.packet.SetEntityDataPacket;
-import net.minecraft.core.net.packet.EntityTagDataPacket;
-import net.minecraft.core.net.packet.ExplosionPacket;
-import net.minecraft.core.net.packet.FlagOpenPacket;
-import net.minecraft.core.net.packet.GameRulePacket;
-import net.minecraft.core.net.packet.LoginPacket;
-import net.minecraft.core.net.packet.MapDataPacket;
-import net.minecraft.core.net.packet.MoveEntityPacket;
-import net.minecraft.core.net.packet.MovePlayerPacket;
-import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.PhotoModePacket;
-import net.minecraft.core.net.packet.PlaySoundEffectDirectPacket;
-import net.minecraft.core.net.packet.PlaySoundEffectPacket;
-import net.minecraft.core.net.packet.PlayerGamemodePacket;
-import net.minecraft.core.net.packet.PlayerListPacket;
-import net.minecraft.core.net.packet.PreLoginPacket;
-import net.minecraft.core.net.packet.RecipeSyncPacket;
-import net.minecraft.core.net.packet.RemoveEntityPacket;
-import net.minecraft.core.net.packet.RespawnPacket;
-import net.minecraft.core.net.packet.SetCarriedItemPacket;
-import net.minecraft.core.net.packet.SetEntityMotionPacket;
-import net.minecraft.core.net.packet.SetEquippedItemPacket;
-import net.minecraft.core.net.packet.SetHealthPacket;
-import net.minecraft.core.net.packet.SetMobSpawnerPacket;
-import net.minecraft.core.net.packet.SetRidingPacket;
-import net.minecraft.core.net.packet.SetSpawnPositionPacket;
-import net.minecraft.core.net.packet.SetTimePacket;
-import net.minecraft.core.net.packet.SleepPacket;
-import net.minecraft.core.net.packet.StatisticPacket;
-import net.minecraft.core.net.packet.SyncIDsPacket;
-import net.minecraft.core.net.packet.TakeItemEntityPacket;
-import net.minecraft.core.net.packet.TeleportEntityPacket;
-import net.minecraft.core.net.packet.BlockEntityDataPacket;
-import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
-import net.minecraft.core.net.packet.WeatherEffectPacket;
-import net.minecraft.core.net.packet.WeatherStatusPacket;
+import net.minecraft.core.net.packet.*;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.player.inventory.menu.AbstractContainerMenu;
 import net.minecraft.core.player.inventory.container.SimpleContainer;
@@ -1218,4 +1159,9 @@ public class ClientPacketHandler extends PacketHandler
             worldClient.addRainbow(rainbowTicks);
         }
     }
+
+    @Override
+    public void handleCommandManagerPacket(CommandManagerPacket packet) {
+        ChatSuggestionsElement.serverSuggestions = packet.suggestions;
+    }
 }
diff --git a/src/main/java/net/minecraft/client/option/GameSettings.java b/src/main/java/net/minecraft/client/option/GameSettings.java
index e22ff9c99..9492cf108 100644
--- a/src/main/java/net/minecraft/client/option/GameSettings.java
+++ b/src/main/java/net/minecraft/client/option/GameSettings.java
@@ -17,7 +17,7 @@ import net.minecraft.client.discord.RichPresenceHandlerThread;
 import net.minecraft.client.gui.hud.component.HudComponents;
 import net.minecraft.client.input.InputDevice;
 import net.minecraft.client.option.enums.Colorblindness;
-import net.minecraft.client.option.enums.Difficulty;
+import net.minecraft.core.enums.Difficulty;
 import net.minecraft.client.option.enums.LightmapStyle;
 import net.minecraft.client.option.enums.MipmapType;
 import net.minecraft.client.option.enums.RenderScale;
diff --git a/src/main/java/net/minecraft/core/achievement/stat/Stat.java b/src/main/java/net/minecraft/core/achievement/stat/Stat.java
index 0b4e4f960..a404feb9c 100644
--- a/src/main/java/net/minecraft/core/achievement/stat/Stat.java
+++ b/src/main/java/net/minecraft/core/achievement/stat/Stat.java
@@ -44,6 +44,10 @@ public class Stat
         return I18n.getInstance().translateKey(statKey);
     }
 
+    public String getStatKey() {
+        return statKey;
+    }
+
     public Stat setClientside()
     {
         clientside = true;
diff --git a/src/main/java/net/minecraft/core/entity/LightningEntity.java b/src/main/java/net/minecraft/core/entity/LightningEntity.java
index 55cfd57ef..6c9b2afdb 100644
--- a/src/main/java/net/minecraft/core/entity/LightningEntity.java
+++ b/src/main/java/net/minecraft/core/entity/LightningEntity.java
@@ -1,6 +1,6 @@
 package net.minecraft.core.entity;
 
-import net.minecraft.client.option.enums.Difficulty;
+import net.minecraft.core.enums.Difficulty;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.phys.AABB;
diff --git a/src/main/java/net/minecraft/core/entity/Mob.java b/src/main/java/net/minecraft/core/entity/Mob.java
index f238746cc..98992f22b 100644
--- a/src/main/java/net/minecraft/core/entity/Mob.java
+++ b/src/main/java/net/minecraft/core/entity/Mob.java
@@ -2,7 +2,6 @@ package net.minecraft.core.entity;
 
 import com.b100.utils.StringUtils;
 import com.mojang.nbt.CompoundTag;
-import net.minecraft.client.Minecraft;
 import net.minecraft.core.Global;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.WeightedRandomLootObject;
diff --git a/src/main/java/net/minecraft/core/entity/PaintingEntity.java b/src/main/java/net/minecraft/core/entity/PaintingEntity.java
index 062487d35..b587eb6ea 100644
--- a/src/main/java/net/minecraft/core/entity/PaintingEntity.java
+++ b/src/main/java/net/minecraft/core/entity/PaintingEntity.java
@@ -14,7 +14,6 @@ import net.minecraft.core.world.World;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.util.helper.DamageType;
-import net.minecraft.server.MinecraftServer;
 
 import java.util.*;
 
@@ -25,12 +24,14 @@ import java.util.*;
 
 public class PaintingEntity extends Entity
 {
+    public static final int DATA_ITEM_ID = 16;
+    public static final int DATA_ITEM_METADATA_ID = 17;
+
     private int updateCounter;
     public int direction;
     public int blockX;
     public int blockY;
     public int blockZ;
-    public ItemStack borderStack;
     public ArtType art;
 
     public PaintingEntity(World world)
@@ -63,6 +64,8 @@ public class PaintingEntity extends Entity
     @Override
     protected void defineSynchedData()
     {
+        entityData.define(DATA_ITEM_ID, 0);
+        entityData.define(DATA_ITEM_METADATA_ID, 0);
     }
 
     public void setDirection(int direction)
@@ -332,12 +335,23 @@ public class PaintingEntity extends Entity
     }
 
     public ItemStack getBorderStack() {
-        return borderStack;
+        int id = entityData.getShort(DATA_ITEM_ID);
+        int meta = Byte.toUnsignedInt(entityData.getByte(DATA_ITEM_METADATA_ID));
+
+        if (id != 0) {
+            return new ItemStack(id, 1, meta);
+        } else {
+            return null;
+        }
     }
+
     public void setStack(ItemStack stack){
-        borderStack = stack;
-        if (Global.isServer){
-            MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(new AddPaintingPacket(this), world.dimension.id);
+        if (stack != null){
+            entityData.set(DATA_ITEM_ID, (short) stack.itemID);
+            entityData.set(DATA_ITEM_METADATA_ID, (byte) stack.getMetadata());
+        } else {
+            entityData.set(DATA_ITEM_ID, (short) 0);
+            entityData.set(DATA_ITEM_METADATA_ID, (byte) 0);
         }
     }
     private static final HashMap<String, NamespaceID> borderMaterialMap = new HashMap<>();
diff --git a/src/main/java/net/minecraft/core/entity/player/Player.java b/src/main/java/net/minecraft/core/entity/player/Player.java
index 5810f7bed..b580af12f 100644
--- a/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -2,7 +2,7 @@ package net.minecraft.core.entity.player;
 
 import com.mojang.nbt.CompoundTag;
 import com.mojang.nbt.ListTag;
-import net.minecraft.client.option.enums.Difficulty;
+import net.minecraft.core.enums.Difficulty;
 import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.achievement.stat.Stat;
 import net.minecraft.core.achievement.stat.StatList;
diff --git a/src/main/java/net/minecraft/client/option/enums/Difficulty.java b/src/main/java/net/minecraft/core/enums/Difficulty.java
similarity index 93%
rename from src/main/java/net/minecraft/client/option/enums/Difficulty.java
rename to src/main/java/net/minecraft/core/enums/Difficulty.java
index 7330795f4..df3685602 100644
--- a/src/main/java/net/minecraft/client/option/enums/Difficulty.java
+++ b/src/main/java/net/minecraft/core/enums/Difficulty.java
@@ -1,4 +1,4 @@
-package net.minecraft.client.option.enums;
+package net.minecraft.core.enums;
 
 import org.jetbrains.annotations.NotNull;
 
diff --git a/src/main/java/net/minecraft/core/net/command/ClientCommand.java b/src/main/java/net/minecraft/core/net/command/ClientCommand.java
deleted file mode 100644
index 82244087b..000000000
--- a/src/main/java/net/minecraft/core/net/command/ClientCommand.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.client.Minecraft;
-
-public abstract class ClientCommand extends Command{
-
-	public final Minecraft minecraft;
-	
-	public ClientCommand(Minecraft minecraft, String name, String... names) {
-		super(name, names);
-		
-		this.minecraft = minecraft;
-	}
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/ClientCommandHandler.java b/src/main/java/net/minecraft/core/net/command/ClientCommandHandler.java
deleted file mode 100644
index 2025f9f48..000000000
--- a/src/main/java/net/minecraft/core/net/command/ClientCommandHandler.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.world.World;
-import org.jetbrains.annotations.Nullable;
-
-public class ClientCommandHandler implements CommandHandler{
-
-	public final Minecraft minecraft;
-	
-	public ClientCommandHandler(Minecraft minecraft) {
-		this.minecraft = minecraft;
-		
-		Commands.initClientCommands(minecraft);
-	}
-	
-	@Override
-	public synchronized void sendMessageToAdmins(String msg) {
-		if(minecraft.theWorld.getLevelData().getCheatsEnabled()) {
-			minecraft.ingameHud.addChatMessage(msg);
-		}
-	}
-
-	@Override
-	public synchronized void sendMessageToAllPlayers(String msg) {
-		minecraft.ingameHud.addChatMessage(msg);
-	}
-
-	@Override
-	public synchronized @Nullable Player getPlayer(String name) {
-		if(minecraft.thePlayer.username.equalsIgnoreCase(name)) {
-			return minecraft.thePlayer;
-		}else {
-			return null;
-		}
-	}
-
-	@Override
-	public synchronized void sendMessageToPlayer(Player player, String msg) {
-		if(player == minecraft.thePlayer) {
-			minecraft.ingameHud.addChatMessage(msg);
-		}
-	}
-
-	@Override
-	public synchronized boolean playerExists(String name) {
-		return name.equalsIgnoreCase(minecraft.thePlayer.username);
-	}
-
-	@Override
-	public synchronized void sendCommandFeedback(CommandSender sender, String message) {
-		sender.sendMessage(message);
-	}
-	
-	@Override
-	public synchronized World getWorld(int dimension) {
-		return minecraft.theWorld;
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/ClientPlayerCommandSender.java b/src/main/java/net/minecraft/core/net/command/ClientPlayerCommandSender.java
deleted file mode 100644
index 404335045..000000000
--- a/src/main/java/net/minecraft/core/net/command/ClientPlayerCommandSender.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.entity.player.LocalPlayer;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.world.World;
-
-public class ClientPlayerCommandSender extends PlayerCommandSender{
-	
-	public final Minecraft minecraft;
-	public final LocalPlayer player;
-	
-	public ClientPlayerCommandSender(Minecraft minecraft, LocalPlayer player) {
-		if(minecraft == null) throw new NullPointerException();
-		
-		this.minecraft = minecraft;
-		this.player = player;
-	}
-
-	@Override
-	public boolean isAdmin() {
-		return minecraft.theWorld.getLevelData().getCheatsEnabled();
-	}
-
-	@Override
-	public void sendMessage(String string) {
-		minecraft.ingameHud.addChatMessage(string);
-	}
-
-	@Override
-	public Player getPlayer() {
-		return player;
-	}
-
-	@Override
-	public String getName() {
-		return player.getDisplayName();
-	}
-
-	@Override
-	public World getWorld() {
-		return minecraft.theWorld;
-	}
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/Command.java b/src/main/java/net/minecraft/core/net/command/Command.java
deleted file mode 100644
index 8b028b665..000000000
--- a/src/main/java/net/minecraft/core/net/command/Command.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package net.minecraft.core.net.command;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public abstract class Command {
-	
-	private final List<String> names = new ArrayList<>();
-	
-	public Command(String name, String... alts) {
-		if(name == null) throw new NullPointerException();
-		this.names.add(name);
-		
-		if(alts != null) {
-			for(String n : alts) {
-				names.add(n);
-			}
-		}
-	}
-	
-	/**
-	 * @return false if the command was not executed successfully, the command syntax will be sent to the sender
-	 */
-	public abstract boolean execute(CommandHandler handler, CommandSender sender, String[] args);
-	
-	/**
-	 * Used to decide if a player can use this command, and if this command appears in the /help list.
-	 * When /help is called, args is null.  
-	 */
-	public abstract boolean opRequired(String[] args);
-	
-	public boolean isName(String name) {
-		for(String n : names) {
-			if(n.equalsIgnoreCase(name)) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
-	@Override
-	public String toString() {
-		return names.get(0);
-	}
-	
-	public abstract void sendCommandSyntax(CommandHandler handler, CommandSender sender);
-	
-	public String getName() {
-		return names.get(0);
-	}
-
-	public List<String> getNames() {
-		return names;
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/CommandError.java b/src/main/java/net/minecraft/core/net/command/CommandError.java
deleted file mode 100644
index 4a07c1111..000000000
--- a/src/main/java/net/minecraft/core/net/command/CommandError.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.minecraft.core.net.command;
-
-public class CommandError extends RuntimeException{
-
-	private static final long serialVersionUID = 1L;
-	
-	public CommandError(String message) {
-		super(message);
-	}
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/CommandHandler.java b/src/main/java/net/minecraft/core/net/command/CommandHandler.java
deleted file mode 100644
index 60f9564f6..000000000
--- a/src/main/java/net/minecraft/core/net/command/CommandHandler.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.world.World;
-import org.jetbrains.annotations.Nullable;
-
-public interface CommandHandler {
-	
-	/**
-	 * Sends command feedback to the player who sent the command, and to all admins
-	 */
-    void sendCommandFeedback(CommandSender sender, String message);
-	
-	void sendMessageToAdmins(String msg);
-	
-	void sendMessageToAllPlayers(String msg);
-	
-	void sendMessageToPlayer(Player player, String messsage);
-
-	@Nullable Player getPlayer(String name);
-	
-	boolean playerExists(String name);
-	
-	World getWorld(int dimension);
-
-	
-	default World getWorld(Player player) {
-		return getWorld(player.dimension);
-	}
-	
-	default boolean isServer() {
-		return this instanceof ServerCommandHandler;
-	}
-	
-	default boolean isClient() {
-		return this instanceof ClientCommandHandler;
-	}
-	
-	default ServerCommandHandler asServer() {
-		return (ServerCommandHandler) this;
-	}
-	
-	default ClientCommandHandler asClient() {
-		return (ClientCommandHandler) this;
-	}
-
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/CommandManager.java b/src/main/java/net/minecraft/core/net/command/CommandManager.java
new file mode 100644
index 000000000..3cd797ba5
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/CommandManager.java
@@ -0,0 +1,109 @@
+package net.minecraft.core.net.command;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.net.command.commands.*;
+import net.minecraft.server.net.command.commands.*;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+@SuppressWarnings("unused")
+public class CommandManager {
+    private final boolean isServer;
+
+    public CommandManager(boolean isServer) {
+        this.isServer = isServer;
+    }
+
+    private final CommandDispatcher<CommandSource> DISPATCHER = new CommandDispatcher<>();
+    private static final Collection<CommandRegistry> externalCommands = new ArrayList<>();
+    private static final Collection<CommandRegistry> externalServerCommands = new ArrayList<>();
+
+    public void init() {
+        AchievementCommand.register(DISPATCHER);
+        ClearCommand.register(DISPATCHER);
+        KillCommand.register(DISPATCHER);
+        SeedCommand.register(DISPATCHER);
+        SetBlockCommand.register(DISPATCHER);
+        SummonCommand.register(DISPATCHER);
+        TeleportCommand.register(DISPATCHER);
+        MessageCommand.register(DISPATCHER);
+        SetSpawnCommand.register(DISPATCHER);
+        TimeCommand.register(DISPATCHER);
+        GameModeCommand.register(DISPATCHER);
+        WeatherCommand.register(DISPATCHER);
+        SpawnCommand.register(DISPATCHER);
+        PlaceCommand.register(DISPATCHER);
+        HelpCommand.register(DISPATCHER);
+        ChunkCommand.register(DISPATCHER);
+        GiveCommand.register(DISPATCHER);
+        GameRuleCommand.register(DISPATCHER);
+        FillCommand.register(DISPATCHER);
+        CloneCommand.register(DISPATCHER);
+        BiomeCommand.register(DISPATCHER);
+        SayCommand.register(DISPATCHER);
+        TellRawCommand.register(DISPATCHER);
+        TestForCommand.register(DISPATCHER);
+        DamageCommand.register(DISPATCHER);
+        HealCommand.register(DISPATCHER);
+
+        if (this.isServer) {
+            StopCommand.register(DISPATCHER);
+            OpCommand.register(DISPATCHER);
+            DeopCommand.register(DISPATCHER);
+            ListCommand.register(DISPATCHER);
+            DifficultyCommand.register(DISPATCHER);
+            ColorCommand.register(DISPATCHER);
+            NicknameCommand.register(DISPATCHER);
+            WhoIsCommand.register(DISPATCHER);
+            ScoreCommand.register(DISPATCHER);
+            MeCommand.register(DISPATCHER);
+            EmotesCommand.register(DISPATCHER);
+            for (CommandRegistry registry : externalServerCommands) {
+                registry.register(DISPATCHER);
+            }
+        }
+
+        for (CommandRegistry registry : externalCommands) {
+            registry.register(DISPATCHER);
+        }
+    }
+
+    public int execute(String s, CommandSource commandSource) throws CommandSyntaxException {
+        return this.DISPATCHER.execute(s, commandSource);
+    }
+
+    public CommandDispatcher<CommandSource> getDispatcher() {
+        return this.DISPATCHER;
+    }
+
+    @Nullable
+    public static <S> CommandSyntaxException getParseException(ParseResults<S> parseResults) {
+        if (!parseResults.getReader().canRead()) {
+            return null;
+        }
+        if (parseResults.getExceptions().size() == 1) {
+            return parseResults.getExceptions().values().iterator().next();
+        }
+        if (parseResults.getContext().getRange().isEmpty()) {
+            return CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(parseResults.getReader());
+        }
+        return CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(parseResults.getReader());
+    }
+
+    public static void registerCommand(CommandRegistry registry) {
+        externalCommands.add(registry);
+    }
+
+    public static void registerServerCommand(CommandRegistry registry) {
+        externalServerCommands.add(registry);
+    }
+
+    @FunctionalInterface
+    public interface CommandRegistry {
+        void register(CommandDispatcher<CommandSource> dispatcher);
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/CommandManagerPacketKeys.java b/src/main/java/net/minecraft/core/net/command/CommandManagerPacketKeys.java
new file mode 100644
index 000000000..190fe9b87
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/CommandManagerPacketKeys.java
@@ -0,0 +1,21 @@
+package net.minecraft.core.net.command;
+
+public class CommandManagerPacketKeys {
+    public static final String READER_CAN_READ = "a";
+    public static final String READER_CURSOR = "b";
+    public static final String READER_REMAINING_TEXT_LENGTH = "c";
+    public static final String READER_STRING = "d";
+    public static final String READER = "e";
+
+    public static final String VALUE = "f";
+    public static final String RANGE = "g";
+    public static final String RANGE_START = "h";
+    public static final String RANGE_END = "i";
+    public static final String TOOLTIP = "j";
+    public static final String LAST_CHILD = "k";
+    public static final String ARGUMENTS = "l";
+    public static final String SUGGESTIONS = "m";
+    public static final String EXCEPTIONS = "n";
+    public static final String USAGE = "o";
+    public static final String SUGGESTION_CONTEXT_START_POS = "p";
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/command/CommandSender.java b/src/main/java/net/minecraft/core/net/command/CommandSender.java
deleted file mode 100644
index 791a0c467..000000000
--- a/src/main/java/net/minecraft/core/net/command/CommandSender.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.world.World;
-
-public interface CommandSender {
-	
-	public boolean isAdmin();
-	
-	public Player getPlayer();
-	
-	public World getWorld();
-
-	public void sendMessage(String string);
-	
-	public String getName();
-	
-	public default boolean isPlayer() {
-		return this instanceof PlayerCommandSender;
-	}
-	
-	public default boolean isConsole() {
-		return this instanceof ConsoleCommandSender;
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/CommandSource.java b/src/main/java/net/minecraft/core/net/command/CommandSource.java
new file mode 100644
index 000000000..475eb99fb
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/CommandSource.java
@@ -0,0 +1,57 @@
+package net.minecraft.core.net.command;
+
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.World;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public interface CommandSource {
+    Collection<String> getPlayerNames();
+
+    default Collection<String> getChatSuggestions() {
+        return this.getPlayerNames();
+    }
+
+    default Collection<String> getEntitySuggestions() {
+        return Collections.emptyList();
+    }
+
+    String toString();
+
+    @Nullable
+    Player getSender();
+
+    boolean hasAdmin();
+
+    @Nullable Vec3 getCoordinates(boolean offsetHeight);
+
+    @Nullable Vec3 getBlockCoordinates();
+
+    boolean messageMayBeMultiline();
+
+    void sendMessage(String message);
+
+    void sendMessage(Player player, String message);
+
+    default void sendTranslatableMessage(String message, Object... args) {
+        this.sendMessage(I18n.getInstance().translateKeyAndFormat(message, args));
+    }
+
+    default void sendTranslatableMessage(Player player, String message, Object... args) {
+        this.sendMessage(player, I18n.getInstance().translateKeyAndFormat(message, args));
+    }
+
+    void sendMessageToAllPlayers(String message);
+
+    World getWorld();
+
+    World getWorld(int dimension);
+
+    void movePlayerToDimension(Player player, int dimension);
+
+    String getName();
+}
diff --git a/src/main/java/net/minecraft/core/net/command/Commands.java b/src/main/java/net/minecraft/core/net/command/Commands.java
deleted file mode 100644
index 3825ee241..000000000
--- a/src/main/java/net/minecraft/core/net/command/Commands.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.core.net.command.commands.*;
-import net.minecraft.core.net.command.servercommands.BanCommand;
-import net.minecraft.core.net.command.servercommands.BanIpCommand;
-import net.minecraft.core.net.command.servercommands.ColorCommand;
-import net.minecraft.core.net.command.servercommands.DeopCommand;
-import net.minecraft.core.net.command.servercommands.DifficultyCommand;
-import net.minecraft.core.net.command.servercommands.EmotesCommand;
-import net.minecraft.core.net.command.servercommands.KickCommand;
-import net.minecraft.core.net.command.servercommands.ListCommand;
-import net.minecraft.core.net.command.servercommands.MeCommand;
-import net.minecraft.core.net.command.servercommands.NicknameCommand;
-import net.minecraft.core.net.command.servercommands.OpCommand;
-import net.minecraft.core.net.command.servercommands.PardonCommand;
-import net.minecraft.core.net.command.servercommands.PardonIpCommand;
-import net.minecraft.core.net.command.servercommands.SaveCommand;
-import net.minecraft.core.net.command.servercommands.SayCommand;
-import net.minecraft.core.net.command.servercommands.ScoreCommand;
-import net.minecraft.core.net.command.servercommands.ScoreboardCommand;
-import net.minecraft.core.net.command.servercommands.StopCommand;
-import net.minecraft.core.net.command.servercommands.WhitelistCommand;
-import net.minecraft.core.net.command.servercommands.WhoisCommand;
-import net.minecraft.server.MinecraftServer;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public final class Commands {
-	
-	public static List<Command> commands = new ArrayList<>();
-	
-	public static void initCommands() {
-		if(commands.size() > 0) throw new RuntimeException();
-		
-		commands.add(new TeleportCommand());
-		commands.add(new WhisperCommand());
-		commands.add(new GiveCommand());
-		commands.add(new HelpCommand());
-		commands.add(new WeatherCommand());
-		commands.add(new SummonCommand());
-		commands.add(new TimeCommand());
-		commands.add(new ClearCommand());
-		commands.add(new SeedCommand());
-		commands.add(new GamemodeCommand());
-		commands.add(new SetSpawnCommand());
-		commands.add(new SpawnCommand());
-		commands.add(new SetBlockCommand());
-		commands.add(new KillCommand());
-		commands.add(new GenerateCommand());
-		commands.add(new ChunkCommand());
-		commands.add(new GameruleCommand());
-		commands.add(new BiomeCommand());
-		commands.add(new SpawnParticleCommand());
-		commands.add(new PlaySoundCommand());
-		commands.add(new HarmCommand());
-		commands.add(new MobSpawningCommand());
-	}
-	
-	public static void initServerCommands(MinecraftServer server) {
-		if(commands.size() > 0) throw new RuntimeException();
-		
-		initCommands();
-
-		commands.add(new BanCommand(server));
-		commands.add(new BanIpCommand(server));
-		commands.add(new StopCommand(server));
-		commands.add(new OpCommand(server));
-		commands.add(new DeopCommand(server));
-		commands.add(new ListCommand(server));
-		commands.add(new DifficultyCommand(server));
-		commands.add(new ColorCommand(server));
-		commands.add(new NicknameCommand(server));
-		commands.add(new WhoisCommand(server));
-		commands.add(new ScoreCommand(server));
-		commands.add(new MeCommand(server));
-		commands.add(new EmotesCommand(server));
-		commands.add(new WhitelistCommand(server));
-		commands.add(new SaveCommand(server));
-		commands.add(new PardonCommand(server));
-		commands.add(new PardonIpCommand(server));
-		commands.add(new KickCommand(server));
-		commands.add(new SayCommand(server));
-		commands.add(new ScoreboardCommand(server));
-	}
-	
-	public static void initClientCommands(Minecraft minecraft) {
-		if(commands.size() > 0) throw new RuntimeException();
-		
-		initCommands();
-	}
-
-	public static Command getCommand(String string) {
-		for(Command command : commands) {
-			for(String name : command.getNames()) {
-				if(name.equalsIgnoreCase(string)) {
-					return command;
-				}
-			}
-		}
-		return null;
-	}
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/ConsoleCommandSender.java b/src/main/java/net/minecraft/core/net/command/ConsoleCommandSender.java
deleted file mode 100644
index 16eb8d552..000000000
--- a/src/main/java/net/minecraft/core/net/command/ConsoleCommandSender.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package net.minecraft.core.net.command;
-
-import com.mojang.logging.LogUtils;
-import net.minecraft.core.util.helper.LoggedPrintStream;
-import org.slf4j.Logger;
-
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.world.World;
-import net.minecraft.server.MinecraftServer;
-
-public class ConsoleCommandSender implements CommandSender{
-	
-	public final MinecraftServer minecraftServer;
-	
-	private static final Logger LOGGER = LogUtils.getLogger();
-	
-	public ConsoleCommandSender(MinecraftServer minecraftServer) {
-		this.minecraftServer = minecraftServer;
-	}
-	
-	@Override
-	public boolean isAdmin() {
-		return true;
-	}
-
-	@Override
-	public Player getPlayer() {
-		return null;
-	}
-
-	@Override
-	public void sendMessage(String string) {
-		LOGGER.info(LoggedPrintStream.removeColorCodes(string));
-	}
-
-	@Override
-	public String getName() {
-		return "Console";
-	}
-
-	@Override
-	public World getWorld() {
-		return minecraftServer.getDimensionWorld(0);
-	}
-
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/LocationTarget.java b/src/main/java/net/minecraft/core/net/command/LocationTarget.java
deleted file mode 100644
index 67b3d1d7c..000000000
--- a/src/main/java/net/minecraft/core/net/command/LocationTarget.java
+++ /dev/null
@@ -1,193 +0,0 @@
-package net.minecraft.core.net.command;
-
-import static net.minecraft.core.util.helper.Utils.*;
-
-import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.world.World;
-
-public class LocationTarget {
-	
-	private CommandHandler handler;
-	private CommandSender sender;
-	
-	private World world;
-	
-	private Entity locationEntity;
-	private Double x;
-	private Double y;
-	private Double z;
-	
-	public LocationTarget(CommandHandler handler, CommandSender sender) {
-		this.handler = handler;
-		this.sender = sender;
-		
-		if(sender.isPlayer()) {
-			this.world = sender.getPlayer().world;
-			
-			this.locationEntity = sender.getPlayer();
-			this.x = sender.getPlayer().x;
-			this.y = sender.getPlayer().y;
-			this.z = sender.getPlayer().z;
-		}
-	}
-	
-	public World getWorld() {
-		if(world == null) {
-			throw new CommandError("Must be used by a player, or a dimension ID must be provided!");
-		}
-		return world;
-	}
-	
-	private void checkPosition() {
-		if(x == null || y == null || z == null) {
-			throw new CommandError("Must be used by a player, or coordinates must be provided!");
-		}
-	}
-	
-	public int parse(String[] args, int offset) {
-		try {
-			if(!isNumber(args[offset])) {
-				Player player = handler.getPlayer(args[offset]);
-				
-				if(player != null) {
-					setLocation(player);
-					
-					return 1;
-				}else {
-					throw new CommandError("Player \""+args[offset]+"\" not found!");
-				}
-			}
-			if(args.length < offset + 3) {
-				throw new CommandError("Not enough arguments");
-			}
-			
-			this.locationEntity = null;
-			this.x = parse(x, args[offset + 0]);
-			this.y = parse(y, args[offset + 1]);
-			this.z = parse(z, args[offset + 2]);
-			
-			return 3;
-		}catch (CommandError e) {
-			throw new CommandError("Error parsing location: "+e.getMessage());
-		}catch (Exception e) {
-			throw new CommandError("Error parsing location");
-		}
-	}
-	
-	private Double parse(Double pos, String str) {
-		double newPos = 0.0;
-
-		if (str.equals("~"))
-		{
-			if (pos == null)
-			{
-				newPos = 0;
-			}
-			else
-			{
-				newPos = pos;
-			}
-		}
-		else if(str.startsWith("~"))
-		{
-			if(pos == null)
-			{
-				newPos = parseDouble(str.substring(1));
-			}
-			else
-			{
-				newPos = pos + parseDouble(str.substring(1));
-			}
-		}
-		else
-		{
-			newPos = parseDouble(str);
-		}
-		
-		return newPos;
-	}
-	
-	private void setLocation(Entity entity) {
-		this.locationEntity = entity;
-		this.x = entity.x;
-		this.y = entity.y;
-		this.z = entity.z;
-	}
-	
-	public double getX() {
-		checkPosition();
-		
-		return x;
-	}
-	
-	public double getY() {
-		checkPosition();
-		
-		return y;
-	}
-	
-	public double getZ() {
-		checkPosition();
-		
-		return z;
-	}
-	
-	public int getBlockX() {
-		checkPosition();
-		
-		return MathHelper.floor(x);
-	}
-	
-	public int getBlockY() {
-		checkPosition();
-		
-		return MathHelper.floor(y);
-	}
-	
-	public int getBlockZ() {
-		checkPosition();
-		
-		return MathHelper.floor(z);
-	}
-	
-	public boolean isLocationEntity() {
-		return locationEntity != null && locationEntity instanceof Player;
-	}
-	
-	public String getLocationEntityName() {
-		if(locationEntity == null) return null;
-		if(locationEntity instanceof Player) {
-			Player entityPlayer = (Player) locationEntity;
-			return entityPlayer.username;
-		}
-		return null;
-	}
-	
-	@Override
-	public String toString() {
-		if(x != null && y != null && z != null) {
-			return "x: "+floor10(x)+" y: "+floor10(y)+" z: "+floor10(z);
-		}
-		return null;
-	}
-	
-	public static boolean isNumber(String str) {
-		for(int i=0; i < str.length(); i++) {
-			if(numberChars.indexOf(str.charAt(i)) == -1) return false;
-		}
-		return true;
-	}
-	
-	public static double parseDouble(String str) {
-		try {
-			return Double.parseDouble(str);
-		}catch (Exception e) {
-			throw new CommandError("Not a number: \""+str+"\"");
-		}
-	}
-	
-	public static String numberChars = "0123456789.-~";
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/PlayerCommandSender.java b/src/main/java/net/minecraft/core/net/command/PlayerCommandSender.java
deleted file mode 100644
index 2a7877ab2..000000000
--- a/src/main/java/net/minecraft/core/net/command/PlayerCommandSender.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.core.entity.player.Player;
-
-public abstract class PlayerCommandSender implements CommandSender{
-	
-	public PlayerCommandSender() {}
-
-	@Override
-	public abstract Player getPlayer();
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/ServerCommand.java b/src/main/java/net/minecraft/core/net/command/ServerCommand.java
deleted file mode 100644
index 7a7f80b14..000000000
--- a/src/main/java/net/minecraft/core/net/command/ServerCommand.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.server.MinecraftServer;
-
-public abstract class ServerCommand extends Command{
-
-	public final MinecraftServer server;
-	
-	public ServerCommand(MinecraftServer server, String name, String... names) {
-		super(name, names);
-		
-		this.server = server;
-	}
-
-	public void sendNoticeToOps(String name, String message)
-	{
-		String formattedMessage = name + TextFormatting.LIGHT_GRAY +  ": " + message;
-		server.playerList.sendChatMessageToAllOps(TextFormatting.LIGHT_GRAY + "(" + formattedMessage + ")");
-		MinecraftServer.LOGGER.info(formattedMessage);
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/ServerCommandHandler.java b/src/main/java/net/minecraft/core/net/command/ServerCommandHandler.java
deleted file mode 100644
index b147a3fe5..000000000
--- a/src/main/java/net/minecraft/core/net/command/ServerCommandHandler.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.net.packet.ChatPacket;
-import net.minecraft.core.util.helper.AES;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.core.world.World;
-import org.jetbrains.annotations.Nullable;
-
-public class ServerCommandHandler implements CommandHandler{
-
-	public final MinecraftServer minecraftServer;
-	
-	public ServerCommandHandler(MinecraftServer minecraftServer) {
-		this.minecraftServer = minecraftServer;
-	}
-	
-	@Override
-	public synchronized void sendMessageToAdmins(String msg) {
-		minecraftServer.playerList.sendChatMessageToAllOps(msg);
-	}
-
-	@Override
-	public synchronized @Nullable Player getPlayer(String name) {
-		return minecraftServer.playerList.getPlayerEntity(name);
-	}
-
-	@Override
-	public synchronized void sendMessageToAllPlayers(String msg) {
-		minecraftServer.playerList.sendEncryptedChatToAllPlayers(msg);
-	}
-
-	@Override
-	public synchronized void sendMessageToPlayer(Player player, String messsage) {
-		minecraftServer.playerList.sendPacketToPlayer(player.username, new ChatPacket(messsage, AES.keyChain.get(player.username)));
-	}
-
-	@Override
-	public synchronized boolean playerExists(String name) {
-		return minecraftServer.playerList.getPlayerEntity(name) != null;
-	}
-
-	@Override
-	public synchronized void sendCommandFeedback(CommandSender sender, String message) {
-		sender.sendMessage(message);
-		
-		String message2 = "\2477" + sender.getName() + ": " + message;
-		
-		for(Player p : minecraftServer.playerList.playerEntities) {
-			if(minecraftServer.playerList.isOp(p.uuid)) {
-				if(sender.getPlayer() == null || sender.getPlayer() != p) {
-					sendMessageToPlayer(p, message2);
-				}
-			}
-		}
-		
-		minecraftServer.logInfo(message2);
-	}
-
-	@Override
-	public synchronized World getWorld(int dimension) {
-		return minecraftServer.getDimensionWorld(dimension);
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/ServerPlayerCommandSender.java b/src/main/java/net/minecraft/core/net/command/ServerPlayerCommandSender.java
deleted file mode 100644
index 623468b23..000000000
--- a/src/main/java/net/minecraft/core/net/command/ServerPlayerCommandSender.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package net.minecraft.core.net.command;
-
-import net.minecraft.core.net.packet.ChatPacket;
-import net.minecraft.core.util.helper.AES;
-import net.minecraft.core.world.World;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.server.entity.player.ServerPlayer;
-
-public class ServerPlayerCommandSender extends PlayerCommandSender{
-
-	public final MinecraftServer server;
-	public final ServerPlayer player;
-	
-	public ServerPlayerCommandSender(MinecraftServer server, ServerPlayer player) {
-		this.player = player;
-		this.server = server;
-	}
-
-	@Override
-	public boolean isAdmin() {
-		return server.playerList.isOp(player.uuid);
-	}
-
-	@Override
-	public void sendMessage(String string) {
-		player.playerNetServerHandler.sendPacket(new ChatPacket(string, AES.keyChain.get(player.username)));
-	}
-
-	@Override
-	public Player getPlayer() {
-		return player;
-	}
-	
-	public ServerPlayer getPlayerMP() {
-		return player;
-	}
-
-	@Override
-	public String getName() {
-		return player.getDisplayName();
-	}
-
-	@Override
-	public World getWorld() {
-		return player.world;
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/AchievementArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/AchievementArgumentType.java
new file mode 100644
index 000000000..2308ab8a3
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/AchievementArgumentType.java
@@ -0,0 +1,52 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.achievement.Achievement;
+import net.minecraft.core.achievement.Achievements;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+public class AchievementArgumentType implements ArgumentType<Achievement> {
+    private static final Collection<String> EXAMPLES = Arrays.asList("achievement.acquireIron", "acquireIron");
+
+    public static ArgumentType<Achievement> achievement() {
+        return new AchievementArgumentType();
+    }
+
+    @Override
+    public Achievement parse(StringReader reader) throws CommandSyntaxException {
+        final String string = reader.readString();
+
+        for (Achievement achievement : Achievements.achievementList) {
+            if (CommandHelper.matchesKeyString(achievement.getStatKey(), string)) {
+                return achievement;
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.achievement.invalid_achievement"));
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
+        String remaining = builder.getRemainingLowerCase();
+        for (Achievement achievement : Achievements.achievementList) {
+            Optional<String> optional = CommandHelper.getStringToSuggest(achievement.getStatKey(), remaining);
+            optional.ifPresent(builder::suggest);
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/BiomeArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/BiomeArgumentType.java
new file mode 100644
index 000000000..f2eb235fa
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/BiomeArgumentType.java
@@ -0,0 +1,67 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.data.registry.Registries;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.world.biome.Biome;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+public class BiomeArgumentType implements ArgumentType<Biome> {
+    private static final Collection<String> EXAMPLES = Arrays.asList("overworld", "nether");
+
+    public static BiomeArgumentType biome() {
+        return new BiomeArgumentType();
+    }
+
+    @Override
+    public Biome parse(StringReader reader) throws CommandSyntaxException {
+        final String string = readResourceLocation(reader);
+
+        for (Biome biome : Registries.BIOMES) {
+            if (CommandHelper.matchesKeyString(Registries.BIOMES.getKey(biome), string)) {
+                return biome;
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.biome.invalid_biome"));
+    }
+
+    public String readResourceLocation(StringReader reader) {
+        if (!reader.canRead()) {
+            return "";
+        }
+        final int start = reader.getCursor();
+        while (reader.canRead() && isAllowedInResourceLocation(reader.peek())) {
+            reader.skip();
+        }
+        return reader.getString().substring(start, reader.getCursor());
+    }
+
+    public static boolean isAllowedInResourceLocation(char c) {
+        return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c == '_' || c == ':' || c == '/' || c == '.' || c == '-';
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        String remaining = builder.getRemainingLowerCase();
+        for (Biome biome : Registries.BIOMES) {
+            Optional<String> optional = CommandHelper.getStringToSuggest(Registries.BIOMES.getKey(biome), remaining);
+            optional.ifPresent(builder::suggest);
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/BlockArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/BlockArgumentType.java
new file mode 100644
index 000000000..6d2518474
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/BlockArgumentType.java
@@ -0,0 +1,56 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.net.command.helpers.BlockArgumentParser;
+import net.minecraft.core.net.command.helpers.BlockInput;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.CompletableFuture;
+
+public class BlockArgumentType implements ArgumentType<BlockInput> {
+    private static final List<String> EXAMPLES = Arrays.asList("tile.stone", "stone", "tile.log[1]");
+
+    public static ArgumentType<BlockInput> block() {
+        return new BlockArgumentType();
+    }
+
+    @Override
+    public BlockInput parse(StringReader reader) throws CommandSyntaxException {
+        BlockArgumentParser parser = new BlockArgumentParser(reader);
+        return parser.parse();
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        StringReader stringReader = new StringReader(builder.getInput());
+        stringReader.setCursor(builder.getStart());
+        BlockArgumentParser parser = new BlockArgumentParser(stringReader);
+        try {
+            parser.parse();
+        } catch (CommandSyntaxException ignored) {}
+        return parser.fillSuggestions(builder, suggestionsBuilder -> {
+            String remaining = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
+            for (Block block : Block.blocksList) {
+                if (block == null) continue;
+                CommandHelper.getStringToSuggest(block.getKey(), remaining).ifPresent(suggestionsBuilder::suggest);
+                CommandHelper.getStringToSuggest("tile.air", remaining).ifPresent(suggestionsBuilder::suggest);
+            }
+            suggestionsBuilder.buildFuture();
+        });
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/ChunkCoordinatesArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/ChunkCoordinatesArgumentType.java
new file mode 100644
index 000000000..4ab680257
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/ChunkCoordinatesArgumentType.java
@@ -0,0 +1,88 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.Coordinates2D;
+import net.minecraft.core.net.command.helpers.IntegerCoordinate;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.phys.Vec3;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class ChunkCoordinatesArgumentType implements ArgumentType<Coordinates2D> {
+    private static final List<String> EXAMPLES = Arrays.asList("~ ~", "0 0 0", "~60 ~", "~-20 -25");
+
+    public static ChunkCoordinatesArgumentType chunkCoordinates() {
+        return new ChunkCoordinatesArgumentType();
+    }
+
+    @Override
+    public Coordinates2D parse(StringReader reader) throws CommandSyntaxException {
+        int i = reader.getCursor();
+        IntegerCoordinate x = IntegerCoordinate.parse(reader);
+        if (!reader.canRead() || reader.peek() != ' ') {
+            if (reader.peek() == 'f' || reader.peek() == 'd') {
+                reader.skip();
+                if (!reader.canRead() || reader.peek() != ' ') {
+                    reader.setCursor(i);
+                    throw CommandExceptions.incomplete().createWithContext(reader);
+                }
+            } else {
+                reader.setCursor(i);
+                throw CommandExceptions.incomplete().createWithContext(reader);
+            }
+        }
+        reader.skip();
+        IntegerCoordinate z = IntegerCoordinate.parse(reader);
+        return new Coordinates2D(x, z);
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        String string = builder.getRemaining();
+        Vec3 coordinates = ((CommandSource)context.getSource()).getBlockCoordinates();
+
+        if (coordinates == null) return builder.buildFuture();
+
+        int[] roundedCoordinates = new int[]{
+                MathHelper.floor(coordinates.x / 16.0),
+                MathHelper.floor(coordinates.z / 16.0)
+        };
+
+        if (string.isEmpty()) {
+            String allCoordinates = roundedCoordinates[0] + " " + roundedCoordinates[1];
+            try {
+                this.parse(new StringReader(allCoordinates));
+                builder.suggest(String.valueOf(roundedCoordinates[0]));
+                builder.suggest(roundedCoordinates[0] + " " + roundedCoordinates[1]);
+                builder.suggest(allCoordinates);
+            } catch (CommandSyntaxException ignored) {}
+        } else {
+            String[] strings = string.split(" ");
+            String allCoordinates;
+            if (strings.length == 1) {
+                allCoordinates = strings[0] + " " + roundedCoordinates[1];
+                try {
+                    this.parse(new StringReader(allCoordinates));
+                    builder.suggest(strings[0] + " " + roundedCoordinates[1]);
+                    builder.suggest(allCoordinates);
+                } catch (CommandSyntaxException ignored) {}
+            }
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/DamageTypeArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/DamageTypeArgumentType.java
new file mode 100644
index 000000000..8454fe8d2
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/DamageTypeArgumentType.java
@@ -0,0 +1,51 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.util.helper.DamageType;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+public class DamageTypeArgumentType implements ArgumentType<DamageType> {
+    private static final Collection<String> EXAMPLES = Arrays.asList("damagetype.combat", "damagetype.blast");
+
+    public static DamageTypeArgumentType damageType() {
+        return new DamageTypeArgumentType();
+    }
+
+    @Override
+    public DamageType parse(StringReader reader) throws CommandSyntaxException {
+        final String string = reader.readString();
+
+        for (DamageType damageType : DamageType.values()) {
+            if (CommandHelper.matchesKeyString(damageType.getLanguageKey(), string)) {
+                return damageType;
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.damage_type.invalid_damage_type"));
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
+        String remaining = builder.getRemainingLowerCase();
+        for (DamageType damageType : DamageType.values()) {
+            Optional<String> optional = CommandHelper.getStringToSuggest(damageType.getLanguageKey(), remaining);
+            optional.ifPresent(builder::suggest);
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/DimensionArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/DimensionArgumentType.java
new file mode 100644
index 000000000..7667e1779
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/DimensionArgumentType.java
@@ -0,0 +1,52 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.world.Dimension;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+public class DimensionArgumentType implements ArgumentType<Dimension> {
+    private static final Collection<String> EXAMPLES = Arrays.asList("overworld", "nether");
+
+    public static DimensionArgumentType dimension() {
+        return new DimensionArgumentType();
+    }
+
+    @Override
+    public Dimension parse(StringReader reader) throws CommandSyntaxException {
+        final String string = reader.readString();
+
+        for (Map.Entry<Integer, Dimension> dimension : Dimension.getDimensionList().entrySet()) {
+            if (CommandHelper.matchesKeyString(dimension.getValue().languageKey, string) || string.equals(String.valueOf(dimension.getKey()))) {
+                return dimension.getValue();
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.dimension.invalid_dimension"));
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        String remaining = builder.getRemainingLowerCase();
+        for (Dimension dimension : Dimension.getDimensionList().values()) {
+            Optional<String> optional = CommandHelper.getStringToSuggest(dimension.languageKey, remaining);
+            optional.ifPresent(builder::suggest);
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/EntityArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/EntityArgumentType.java
new file mode 100644
index 000000000..6bd8e6da8
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/EntityArgumentType.java
@@ -0,0 +1,89 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.net.command.helpers.EntitySelectorParser;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.util.ConcatIterable;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+public class EntityArgumentType implements ArgumentType<EntitySelector> {
+    private static final Collection<String> EXAMPLES = Arrays.asList("Player", "0123", "@e", "@e[type=foo]", EntitySelector.ENTITY_PREFIX + "11203");
+
+    private final boolean singleEntity, playerOnly;
+
+    private EntityArgumentType(boolean singleEntity, boolean playerOnly) {
+        this.singleEntity = singleEntity;
+        this.playerOnly = playerOnly;
+    }
+
+    public static EntityArgumentType entities() {
+        return new EntityArgumentType(false, false);
+    }
+
+    public static EntityArgumentType entity() {
+        return new EntityArgumentType(true, false);
+    }
+
+    public static EntityArgumentType players() {
+        return new EntityArgumentType(false, true);
+    }
+
+    public static EntityArgumentType player() {
+        return new EntityArgumentType(true, true);
+    }
+
+    @Override
+    public EntitySelector parse(StringReader reader) throws CommandSyntaxException {
+        int cursor = reader.getCursor();
+        EntitySelectorParser entitySelectorParser = new EntitySelectorParser(reader);
+        EntitySelector entitySelector = entitySelectorParser.parse();
+        if (this.singleEntity && entitySelector.getMaxResults() > 1) {
+            reader.setCursor(cursor);
+            if (this.playerOnly) {
+                throw CommandExceptions.singlePlayerOnly().createWithContext(reader);
+            }
+            throw CommandExceptions.singleEntityOnly().createWithContext(reader);
+        }
+        if (this.playerOnly && entitySelector.includesEntities() && !entitySelector.isCurrentEntity()) {
+            reader.setCursor(cursor);
+            throw CommandExceptions.playerOnly().createWithContext(reader);
+        }
+        return entitySelector;
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        S s = context.getSource();
+        if (s instanceof CommandSource) {
+            CommandSource source = (CommandSource)s;
+            StringReader stringReader = new StringReader(builder.getInput());
+            stringReader.setCursor(builder.getStart());
+            EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, source.hasAdmin());
+            try {
+                entitySelectorParser.parse();
+            } catch (CommandSyntaxException ignored) {}
+            return entitySelectorParser.fillSuggestions(builder, suggestionsBuilder -> {
+                Collection<String> collection = source.getPlayerNames();
+                Iterable<String> iterable = this.playerOnly ? collection : new ConcatIterable<>(collection, source.getEntitySuggestions());
+                CommandHelper.suggest(iterable, suggestionsBuilder);
+            });
+        }
+        return Suggestions.empty();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/EntitySummonArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/EntitySummonArgumentType.java
new file mode 100644
index 000000000..2033a84c2
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/EntitySummonArgumentType.java
@@ -0,0 +1,51 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.EntityDispatcher;
+import net.minecraft.core.lang.I18n;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class EntitySummonArgumentType implements ArgumentType<Class<? extends Entity>> {
+    private static final List<String> EXAMPLES = Arrays.asList("Creeper", "Skeleton", "Slime");
+
+    public static ArgumentType<Class<? extends Entity>> entity() {
+        return new EntitySummonArgumentType();
+    }
+
+    @Override
+    public Class<? extends Entity> parse(StringReader reader) throws CommandSyntaxException {
+        final String string = reader.readString();
+
+        for (String entityName : EntityDispatcher.keyToClassMap.keySet()) {
+            if (entityName.equals(string)) {
+                return EntityDispatcher.keyToClassMap.get(entityName);
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.entity_summon.invalid_entity"));
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        for (String entityName : EntityDispatcher.keyToClassMap.keySet()) {
+            if (entityName.toLowerCase().startsWith(builder.getRemainingLowerCase())) {
+                builder.suggest(entityName);
+            }
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/GameModeArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/GameModeArgumentType.java
new file mode 100644
index 000000000..247a5cc2d
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/GameModeArgumentType.java
@@ -0,0 +1,51 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.player.gamemode.Gamemode;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+public class GameModeArgumentType implements ArgumentType<Gamemode> {
+    private static final Collection<String> EXAMPLES = Arrays.asList(Gamemode.creative.getLanguageKey(), Gamemode.survival.getLanguageKey());
+
+    public static ArgumentType<Gamemode> gameMode() {
+        return new GameModeArgumentType();
+    }
+
+    @Override
+    public Gamemode parse(StringReader reader) throws CommandSyntaxException {
+        final String string = reader.readString();
+
+        for (Gamemode gamemode : Gamemode.gamemodesList) {
+            if (CommandHelper.matchesKeyString(gamemode.getLanguageKey(), string) || string.equals(String.valueOf(gamemode.getId()))) {
+                return gamemode;
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.game_mode.invalid_game_mode"));
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        String remaining = builder.getRemainingLowerCase();
+        for (Gamemode gamemode : Gamemode.gamemodesList) {
+            Optional<String> optional = CommandHelper.getStringToSuggest(gamemode.getLanguageKey(), remaining);
+            optional.ifPresent(builder::suggest);
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/GenericGameRuleArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/GenericGameRuleArgumentType.java
new file mode 100644
index 000000000..fc9d36aef
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/GenericGameRuleArgumentType.java
@@ -0,0 +1,44 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.data.gamerule.GameRule;
+import net.minecraft.core.lang.I18n;
+
+import java.util.concurrent.CompletableFuture;
+
+public class GenericGameRuleArgumentType implements ArgumentType<Object> {
+    private final GameRule<?> gameRule;
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.gamerule.invalid_value"));
+
+    private GenericGameRuleArgumentType(GameRule<?> gameRule) {
+        this.gameRule = gameRule;
+    }
+
+    public static GenericGameRuleArgumentType gameRule(GameRule<?> gameRule) {
+        return new GenericGameRuleArgumentType(gameRule);
+    }
+
+    @Override
+    public Object parse(StringReader reader) throws CommandSyntaxException {
+        StringBuilder read = new StringBuilder();
+        Object value = null;
+        while (reader.canRead() && (StringReader.isQuotedStringStart(reader.peek()) || StringReader.isAllowedInUnquotedString(reader.peek())) && value == null) {
+            read.append(reader.readString());
+            value = this.gameRule.parseFromString(read.toString());
+        }
+
+        if (value != null) return value;
+        throw FAILURE.create();
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        return ArgumentType.super.listSuggestions(context, builder);
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/IntegerCoordinatesArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/IntegerCoordinatesArgumentType.java
new file mode 100644
index 000000000..4ac4ce3ec
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/IntegerCoordinatesArgumentType.java
@@ -0,0 +1,112 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.IntegerCoordinate;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.phys.Vec3;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class IntegerCoordinatesArgumentType implements ArgumentType<IntegerCoordinates> {
+    private static final List<String> EXAMPLES = Arrays.asList("~ ~ ~", "0 0 0", "~ ~60 ~", "~-20 ~10 -25");
+
+    public static IntegerCoordinatesArgumentType intCoordinates() {
+        return new IntegerCoordinatesArgumentType();
+    }
+
+    @Override
+    public IntegerCoordinates parse(StringReader reader) throws CommandSyntaxException {
+        int i = reader.getCursor();
+        IntegerCoordinate x = IntegerCoordinate.parse(reader);
+        if (!reader.canRead() || reader.peek() != ' ') {
+            if (reader.peek() == 'f' || reader.peek() == 'd') {
+                reader.skip();
+                if (!reader.canRead() || reader.peek() != ' ') {
+                    reader.setCursor(i);
+                    throw CommandExceptions.incomplete().createWithContext(reader);
+                }
+            } else {
+                reader.setCursor(i);
+                throw CommandExceptions.incomplete().createWithContext(reader);
+            }
+        }
+        reader.skip();
+        IntegerCoordinate y = IntegerCoordinate.parse(reader);
+        if (!reader.canRead() || reader.peek() != ' ') {
+            if (reader.peek() == 'f' || reader.peek() == 'd') {
+                reader.skip();
+                if (!reader.canRead() || reader.peek() != ' ') {
+                    reader.setCursor(i);
+                    throw CommandExceptions.incomplete().createWithContext(reader);
+                }
+            } else {
+                reader.setCursor(i);
+                throw CommandExceptions.incomplete().createWithContext(reader);
+            }
+        }
+        reader.skip();
+        IntegerCoordinate z = IntegerCoordinate.parse(reader);
+        return new IntegerCoordinates(x, y, z);
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        String string = builder.getRemaining();
+        Vec3 coordinates = ((CommandSource)context.getSource()).getBlockCoordinates();
+
+        if (coordinates == null) return builder.buildFuture();
+
+        int[] roundedCoordinates = new int[]{
+                MathHelper.floor(coordinates.x),
+                MathHelper.floor(coordinates.y),
+                MathHelper.floor(coordinates.z)
+        };
+
+        if (string.isEmpty()) {
+            String allCoordinates = roundedCoordinates[0] + " " + roundedCoordinates[1] + " " + roundedCoordinates[2];
+            try {
+                this.parse(new StringReader(allCoordinates));
+                builder.suggest(String.valueOf(roundedCoordinates[0]));
+                builder.suggest(roundedCoordinates[0] + " " + roundedCoordinates[1]);
+                builder.suggest(allCoordinates);
+            } catch (CommandSyntaxException ignored) {}
+        } else {
+            String[] strings = string.split(" ");
+            String allCoordinates;
+            switch (strings.length) {
+                case 1:
+                    allCoordinates = strings[0] + " " + roundedCoordinates[1] + " " + roundedCoordinates[2];
+                    try {
+                        this.parse(new StringReader(allCoordinates));
+                        builder.suggest(strings[0] + " " + roundedCoordinates[1]);
+                        builder.suggest(allCoordinates);
+                    } catch (CommandSyntaxException ignored) {}
+                    break;
+                case 2:
+                    allCoordinates = strings[0] + " " + strings[1] + " " + roundedCoordinates[2];
+                    try {
+                        this.parse(new StringReader(allCoordinates));
+                        builder.suggest(allCoordinates);
+                    } catch (CommandSyntaxException ignored) {}
+                    break;
+            }
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/ItemStackArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/ItemStackArgumentType.java
new file mode 100644
index 000000000..ac08acbd0
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/ItemStackArgumentType.java
@@ -0,0 +1,55 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.net.command.helpers.ItemStackArgumentParser;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.CompletableFuture;
+
+public class ItemStackArgumentType implements ArgumentType<ItemStack> {
+    private static final List<String> EXAMPLES = Arrays.asList("tool.sword.iron", "tool.sword.iron{name:\"Sword\", overrideName: true}", "tile.log");
+
+    public static ArgumentType<ItemStack> itemStack() {
+        return new ItemStackArgumentType();
+    }
+
+    @Override
+    public ItemStack parse(StringReader reader) throws CommandSyntaxException {
+        ItemStackArgumentParser parser = new ItemStackArgumentParser(reader);
+        return parser.parse();
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        StringReader stringReader = new StringReader(builder.getInput());
+        stringReader.setCursor(builder.getStart());
+        ItemStackArgumentParser parser = new ItemStackArgumentParser(stringReader);
+        try {
+            parser.parse();
+        } catch (CommandSyntaxException ignored) {}
+        return parser.fillSuggestions(builder, suggestionsBuilder -> {
+            String remaining = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
+            for (Item item : Item.itemsList) {
+                if (item == null) continue;
+                CommandHelper.getStringToSuggest(item.getKey(), remaining).ifPresent(suggestionsBuilder::suggest);
+            }
+            suggestionsBuilder.buildFuture();
+        });
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/TimeArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/TimeArgumentType.java
new file mode 100644
index 000000000..b75757b98
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/TimeArgumentType.java
@@ -0,0 +1,76 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+public class TimeArgumentType implements ArgumentType<Integer> {
+    private static final Collection<String> EXAMPLES = Arrays.asList("0d", "0s", "0t", "0");
+    private static final SimpleCommandExceptionType ERROR_INVALID_UNIT = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.time.invalid_unit"));
+    private static final Dynamic2CommandExceptionType ERROR_TICK_COUNT_TOO_LOW = new Dynamic2CommandExceptionType((object, object2) -> () -> I18n.getInstance().translateKeyAndFormat("command.argument_types.time.tick_count_too_low", object2, object));
+    private static final Map<String, Integer> UNITS = new HashMap<>();
+    final int minimum;
+
+    private TimeArgumentType(int i) {
+        this.minimum = i;
+    }
+
+    public static TimeArgumentType time() {
+        return new TimeArgumentType(0);
+    }
+
+    public static TimeArgumentType time(int i) {
+        return new TimeArgumentType(i);
+    }
+
+    @Override
+    public Integer parse(StringReader stringReader) throws CommandSyntaxException {
+        float f = stringReader.readFloat();
+        String string = stringReader.readUnquotedString();
+        int i = UNITS.getOrDefault(string, 0);
+        if (i == 0) {
+            throw ERROR_INVALID_UNIT.create();
+        }
+        int j = Math.round(f * (float)i);
+        if (j < this.minimum) {
+            throw ERROR_TICK_COUNT_TOO_LOW.create(j, this.minimum);
+        }
+        return j;
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> commandContext, SuggestionsBuilder suggestionsBuilder) {
+        StringReader stringReader = new StringReader(suggestionsBuilder.getRemaining());
+        try {
+            stringReader.readFloat();
+        } catch (CommandSyntaxException commandSyntaxException) {
+            return suggestionsBuilder.buildFuture();
+        }
+        return CommandHelper.suggest(UNITS.keySet(), suggestionsBuilder.createOffset(suggestionsBuilder.getStart() + stringReader.getCursor()));
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+
+    static {
+        UNITS.put("d", 24000);
+        UNITS.put("s", 20);
+        UNITS.put("t", 1);
+        UNITS.put("", 1);
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/Vec3ArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/Vec3ArgumentType.java
new file mode 100644
index 000000000..a23b840b4
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/Vec3ArgumentType.java
@@ -0,0 +1,108 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.DoubleCoordinate;
+import net.minecraft.core.net.command.helpers.DoubleCoordinates;
+import net.minecraft.core.util.phys.Vec3;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class Vec3ArgumentType implements ArgumentType<DoubleCoordinates> {
+    private static final List<String> EXAMPLES = Arrays.asList("~ ~ ~", "0 0 0", "~ ~60 ~", "~-20 ~10 ~-25.5");
+
+    public static Vec3ArgumentType vec3d() {
+        return new Vec3ArgumentType();
+    }
+
+    @Override
+    public DoubleCoordinates parse(StringReader reader) throws CommandSyntaxException {
+        int i = reader.getCursor();
+        DoubleCoordinate x = DoubleCoordinate.parse(reader);
+        if (!reader.canRead() || reader.peek() != ' ') {
+            if (reader.peek() == 'f' || reader.peek() == 'd') {
+                reader.skip();
+                if (!reader.canRead() || reader.peek() != ' ') {
+                    reader.setCursor(i);
+                    throw CommandExceptions.incomplete().createWithContext(reader);
+                }
+            } else {
+                reader.setCursor(i);
+                throw CommandExceptions.incomplete().createWithContext(reader);
+            }
+        }
+        reader.skip();
+        DoubleCoordinate y = DoubleCoordinate.parse(reader);
+        if (!reader.canRead() || reader.peek() != ' ') {
+            if (reader.peek() == 'f' || reader.peek() == 'd') {
+                reader.skip();
+                if (!reader.canRead() || reader.peek() != ' ') {
+                    reader.setCursor(i);
+                    throw CommandExceptions.incomplete().createWithContext(reader);
+                }
+            } else {
+                reader.setCursor(i);
+                throw CommandExceptions.incomplete().createWithContext(reader);
+            }
+        }
+        reader.skip();
+        DoubleCoordinate z = DoubleCoordinate.parse(reader);
+        return new DoubleCoordinates(x, y, z);
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        String string = builder.getRemaining();
+        Vec3 coordinates = ((CommandSource) context.getSource()).getCoordinates(true);
+
+        if (coordinates == null) return builder.buildFuture();
+
+        if (string.isEmpty()) {
+            String allCoordinates = coordinates.x + " " + coordinates.y + " " + coordinates.z;
+            try {
+                this.parse(new StringReader(allCoordinates));
+                builder.suggest(String.valueOf(coordinates.x));
+                builder.suggest(coordinates.x + " " + coordinates.y);
+                builder.suggest(allCoordinates);
+            } catch (CommandSyntaxException ignored) {
+            }
+        } else {
+            String[] strings = string.split(" ");
+            String allCoordinates;
+            switch (strings.length) {
+                case 1:
+                    allCoordinates = strings[0] + " " + coordinates.y + " " + coordinates.z;
+                    try {
+                        this.parse(new StringReader(allCoordinates));
+                        builder.suggest(strings[0] + " " + coordinates.y);
+                        builder.suggest(allCoordinates);
+                    } catch (CommandSyntaxException ignored) {
+                    }
+                    break;
+                case 2:
+                    allCoordinates = strings[0] + " " + strings[1] + " " + coordinates.z;
+                    try {
+                        this.parse(new StringReader(allCoordinates));
+                        builder.suggest(allCoordinates);
+                    } catch (CommandSyntaxException ignored) {
+                    }
+                    break;
+            }
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/WeatherArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/WeatherArgumentType.java
new file mode 100644
index 000000000..46aaa0d04
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/WeatherArgumentType.java
@@ -0,0 +1,54 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.world.weather.Weather;
+import net.minecraft.core.world.weather.Weathers;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+public class WeatherArgumentType implements ArgumentType<Weather> {
+    private static final Collection<String> EXAMPLES = Arrays.asList(Weathers.OVERWORLD_CLEAR.languageKey, Weathers.OVERWORLD_FOG.languageKey);
+
+    public static WeatherArgumentType weather() {
+        return new WeatherArgumentType();
+    }
+
+    @Override
+    public Weather parse(StringReader reader) throws CommandSyntaxException {
+        final String string = reader.readString();
+
+        for (Weather weather : Weathers.WEATHERS) {
+            if (weather == null) continue;
+            if (CommandHelper.matchesKeyString(weather.languageKey, string)) {
+                return weather;
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.weather.invalid_weather"));
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+        String remaining = builder.getRemainingLowerCase();
+        for (Weather weather : Weathers.WEATHERS) {
+            if (weather == null) continue;
+            Optional<String> optional = CommandHelper.getStringToSuggest(weather.languageKey, remaining);
+            optional.ifPresent(builder::suggest);
+        }
+        return builder.buildFuture();
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/arguments/WorldFeatureArgumentType.java b/src/main/java/net/minecraft/core/net/command/arguments/WorldFeatureArgumentType.java
new file mode 100644
index 000000000..d57950592
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/arguments/WorldFeatureArgumentType.java
@@ -0,0 +1,47 @@
+package net.minecraft.core.net.command.arguments;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.net.command.helpers.WorldFeatureParser;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.world.generate.feature.WorldFeature;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+public class WorldFeatureArgumentType implements ArgumentType<WorldFeature> {
+    private static final Collection<String> EXAMPLES = Arrays.asList("Dungeon[2, 2, 2]", "Cactus");
+
+    public static ArgumentType<WorldFeature> worldFeature() {
+        return new WorldFeatureArgumentType();
+    }
+
+    @Override
+    public WorldFeature parse(StringReader reader) throws CommandSyntaxException {
+        WorldFeatureParser parser = new WorldFeatureParser(reader);
+        return parser.parse();
+    }
+
+    @Override
+    public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
+        StringReader stringReader = new StringReader(builder.getInput());
+        stringReader.setCursor(builder.getStart());
+        WorldFeatureParser worldFeatureParser = new WorldFeatureParser(stringReader);
+        try {
+            worldFeatureParser.parse();
+        } catch (CommandSyntaxException ignored) {
+        }
+        return worldFeatureParser.fillSuggestions(builder, suggestionsBuilder ->
+            CommandHelper.suggest(CommandHelper.WORLD_FEATURES.keySet(), suggestionsBuilder));
+    }
+
+    @Override
+    public Collection<String> getExamples() {
+        return EXAMPLES;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/AchievementCommand.java b/src/main/java/net/minecraft/core/net/command/commands/AchievementCommand.java
new file mode 100644
index 000000000..cabed5bcb
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/AchievementCommand.java
@@ -0,0 +1,95 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.achievement.Achievement;
+import net.minecraft.core.achievement.Achievements;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.AchievementArgumentType;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AchievementCommand {
+    private static final SimpleCommandExceptionType PLAYER_ALREADY_HAS_ACHIEVEMENT = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.achievement.grant.exception_already_has_achievement"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(((LiteralArgumentBuilder.<CommandSource>literal("achievement"))
+            .requires(CommandSource::hasAdmin)
+            .then((LiteralArgumentBuilder.<CommandSource>literal("grant"))
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("entities", EntityArgumentType.players())
+                    .then(RequiredArgumentBuilder.<CommandSource, Achievement>argument("achievement", AchievementArgumentType.achievement())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            List<? extends Entity> entities = c.getArgument("entities", EntitySelector.class).get(source);
+                            Achievement achievement = c.getArgument("achievement", Achievement.class);
+
+                            if (entities.size() == 1 && ((Player) entities.get(0)).getStat(achievement) != 0) {
+                                throw PLAYER_ALREADY_HAS_ACHIEVEMENT.create();
+                            }
+
+                            List<Achievement> achievements = new ArrayList<>();
+                            achievements.add(achievement);
+
+                            while (achievements.get(achievements.size() - 1).parent != null) {
+                                achievements.add(achievements.get(achievements.size() - 1).parent);
+                            }
+                            for (int i = 0; i < achievements.size(); i++) {
+                                for (Entity entity : entities) {
+                                    ((Player) entity).triggerAchievement(achievements.get(achievements.size() - 1 - i));
+                                }
+                            }
+
+                            sendContextualMessage(source, entities, achievement);
+
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("*")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            List<? extends Entity> entities = c.getArgument("entities", EntitySelector.class).get(source);
+
+                            for (Achievement achievement : Achievements.achievementList) {
+                                List<Achievement> achievements = new ArrayList<>();
+                                achievements.add(achievement);
+                                while (achievements.get(achievements.size() - 1).parent != null) {
+                                    achievements.add(achievements.get(achievements.size() - 1).parent);
+                                }
+                                for (int i = 0; i < achievements.size(); i++) {
+                                    for (Entity entity : entities) {
+                                        ((Player) entity).triggerAchievement(achievements.get(achievements.size() - 1 - i));
+                                    }
+                                }
+                            }
+
+                            sendWildcardContextualMessage(source, entities);
+
+                            return Command.SINGLE_SUCCESS;
+                        }))))));
+    }
+
+    private static void sendContextualMessage(CommandSource source, List<? extends Entity> entities, Achievement achievement) {
+        if (entities.size() == 1) {
+            source.sendTranslatableMessage("command.commands.achievement.grant.success_single_entity", achievement.getStatName().trim(), ((Mob) entities.get(0)).getDisplayName());
+        } else {
+            source.sendTranslatableMessage("command.commands.achievement.grant.success_multiple_entities", achievement.getStatName(), entities.size());
+        }
+    }
+
+    private static void sendWildcardContextualMessage(CommandSource source, List<? extends Entity> entities) {
+        if (entities.size() == 1) {
+            source.sendTranslatableMessage("command.commands.achievement.grant.all.success_single_entity", ((Mob) entities.get(0)).getDisplayName());
+        } else {
+            source.sendTranslatableMessage("command.commands.achievement.grant.all.success_multiple_entities", entities.size());
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/BiomeCommand.java b/src/main/java/net/minecraft/core/net/command/commands/BiomeCommand.java
index 389259946..827916db2 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/BiomeCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/BiomeCommand.java
@@ -1,143 +1,82 @@
 package net.minecraft.core.net.command.commands;
 
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
 import net.minecraft.core.data.registry.Registries;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.net.command.*;
-import net.minecraft.core.world.World;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.chunk.Chunk;
-import net.minecraft.core.world.chunk.ChunkSection;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.BiomeArgumentType;
+import net.minecraft.core.net.command.arguments.IntegerCoordinatesArgumentType;
+import net.minecraft.core.net.command.helpers.Coordinates2D;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
 
-public class BiomeCommand
-extends Command {
-    public BiomeCommand() {
-        super("biome");
-    }
+public class BiomeCommand {
+    private static final DynamicCommandExceptionType FAILURE = new DynamicCommandExceptionType(arg -> () -> I18n.getInstance().translateKeyAndFormat("command.commands.biome.locate.exception_failure", arg));
 
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length == 0 && sender instanceof PlayerCommandSender) {
-            Player p = sender.getPlayer();
-            World world = p.world;
-            Biome biome = world.getBlockBiome((int) p.x, (int) p.y, (int) p.z);
-            sender.sendMessage("Current biome: " + Registries.BIOMES.getKey(biome));
-            return true;
-        } else if (args.length >= 1) {
-            if (args[0].equalsIgnoreCase("list")) {
-                sender.sendMessage("Biomes:");
-                for (Biome biome : Registries.BIOMES) {
-                    String key = Registries.BIOMES.getKey(biome);
-                    if (args.length == 1 || (args.length == 2 && key.startsWith(args[1]))) {
-                        sender.sendMessage(" - " + Registries.BIOMES.getKey(biome));
-                    }
-                }
-                return true;
-            } else if (args.length == 2 && args[0].equalsIgnoreCase("locate") && sender instanceof PlayerCommandSender) {
-                Biome biome = Registries.BIOMES.getItem(args[1]);
-                if (biome == null) {
-                    sender.sendMessage("Unknown biome: " + args[1]);
-                } else {
-                    int[] nearest = getBiomeCoords(biome, sender.getPlayer());
-                    if (nearest == null) {
-                        sender.sendMessage("No biome found!");
-                    } else {
-                        sender.sendMessage("Biome located at: " + nearest[0] + ", " + nearest[1]);
-                    }
-                }
-                return true;
-            } else if (args.length == 2 && args[0].equalsIgnoreCase("set") && sender instanceof PlayerCommandSender) {
-                Biome biome = Registries.BIOMES.getItem(args[1]);
-                if (biome == null) {
-                    sender.sendMessage("Unknown biome: " + args[1]);
-                } else {
-                    Chunk chunk = sender.getPlayer().world.getChunkFromBlockCoords((int) sender.getPlayer().x, (int) sender.getPlayer().z);
-                    for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
-                        for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
-                            for (int y = 0; y < Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y; y++) {
-                                chunk.setBlockBiome(x, y, z, biome);
-                            }
-                        }
-                    }
-                    sender.sendMessage("Set chunk biome to " + args[1]);
-                }
-                return true;
-            } else if (args.length <= 2 && args[0].equalsIgnoreCase("reset") && sender instanceof PlayerCommandSender) {
-                int radius = 1;
-                if (args.length == 2){
-                     radius = Integer.parseInt(args[1]);
-                }
-                for (int _x = -radius; _x < radius; _x++) {
-                    for (int _z = -radius; _z < radius; _z++) {
-                        int chunkX = sender.getPlayer().chunkCoordX + _x;
-                        int chunkZ = sender.getPlayer().chunkCoordZ + _z;
-                        if (!sender.getPlayer().world.isChunkLoaded(chunkX, chunkZ)) continue;
-                        Chunk chunk = sender.getPlayer().world.getChunkFromChunkCoords(chunkX, chunkZ);
-                        for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
-                            for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
-                                for (int y = 0; y < Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y; y++) {
-                                    chunk.setBlockBiome(x, y, z, sender.getPlayer().world.getBiomeProvider().getBiome(chunk.xPosition * Chunk.CHUNK_SIZE_X + x, y, chunk.zPosition * Chunk.CHUNK_SIZE_Z + z));
-                                }
-                            }
-                        }
-                    }
-                }
-                sender.sendMessage("Reset chunk biomes");
-                return true;
-            } else {
-                return false;
-            }
-        } else {
-            return false;
-        }
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("biome")
+                .requires(CommandSource::hasAdmin)
+                .then(LiteralArgumentBuilder.<CommandSource>literal("get")
+                        .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("position", IntegerCoordinatesArgumentType.intCoordinates())
+                                .executes(c -> {
+                                    IntegerCoordinates position = c.getArgument("position", IntegerCoordinates.class);
+                                    Biome biome = c.getSource().getWorld().getBlockBiome(position.getX(c.getSource()), position.getY(c.getSource(), true), position.getZ(c.getSource()));
+                                    c.getSource().sendTranslatableMessage("command.commands.biome.get.success", position.getX(c.getSource()), position.getY(c.getSource(), true), position.getZ(c.getSource()), Registries.BIOMES.getKey(biome));
+                                    return Command.SINGLE_SUCCESS;
+                                })))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("locate")
+                        .then(RequiredArgumentBuilder.<CommandSource, Biome>argument("biome", BiomeArgumentType.biome())
+                                .executes(c -> {
+                                    Biome biome = c.getArgument("biome", Biome.class);
+                                    Coordinates2D biomeLocation = getBiomeCoords(biome, c.getSource());
+                                    if (biomeLocation == null) throw FAILURE.create(Registries.BIOMES.getKey(biome));
+                                    Vec3 sourcePos = c.getSource().getBlockCoordinates();
+                                    if (sourcePos == null) {
+                                        c.getSource().sendTranslatableMessage("command.commands.biome.locate.success", Registries.BIOMES.getKey(biome), biomeLocation.getX(c.getSource()), biomeLocation.getZ(c.getSource()));
+                                    } else {
+                                        int distance = (int)sourcePos.distanceTo(Vec3.getTempVec3(biomeLocation.getX(c.getSource()), sourcePos.y, biomeLocation.getZ(c.getSource())));
+                                        c.getSource().sendTranslatableMessage(distance == 1 ? "command.commands.biome.locate.success_in_world_single" : "command.commands.biome.locate.success_in_world_multiple", Registries.BIOMES.getKey(biome), biomeLocation.getX(c.getSource()), biomeLocation.getZ(c.getSource()), distance);
+                                    }
+                                    return Command.SINGLE_SUCCESS;
+                                }))));
     }
 
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        if (sender instanceof PlayerCommandSender) {
-            sender.sendMessage("/biome");
-        }
-        sender.sendMessage("/biome list [filter]");
-        if (sender instanceof PlayerCommandSender) {
-            sender.sendMessage("/biome locate <biome>");
-            sender.sendMessage("/biome set <biome>");
-            sender.sendMessage("/biome reset [range]");
-        }
-    }
-
-    private int[] getBiomeCoords(Biome biome, Player source) {
-        int[] xPattern = new int[] { 0, 1, 0, -1 };
-        int[] zPattern = new int[] { 1, 0, -1, 0 };
+    private static Coordinates2D getBiomeCoords(Biome biome, CommandSource source) {
+        int[] xPattern = new int[]{0, 1, 0, -1};
+        int[] zPattern = new int[]{1, 0, -1, 0};
+        Vec3 sourcePos = source.getBlockCoordinates();
+        if (sourcePos == null) sourcePos = Vec3.getTempVec3(0.0, 0.0, 0.0);
         int runLength = 2;
-        int chunkX = (int) (source.x / 16);
-        int y = (int) source.y;
-        int chunkZ = (int) (source.z / 16);
+        int chunkX = (int)(sourcePos.x / 16.0);
+        int y = (int)sourcePos.y;
+        int chunkZ = (int)(sourcePos.z / 16.0);
         int passes = 1024;
+        if (source.getWorld().getBlockBiome((int)sourcePos.x, y, (int)sourcePos.z) == biome) {
+            return new Coordinates2D((int)sourcePos.x, (int)sourcePos.z);
+        } else {
+            --chunkX;
+            --chunkZ;
 
-        if (source.world.getBlockBiome(chunkX * 16, y, chunkZ * 16) == biome) {
-            return new int[] { chunkX * 16, chunkZ * 16 };
-        }
-
-        chunkX--;
-        chunkZ--;
-
-        for (int pass = 0; pass < passes; pass++) {
-            for (int i = 0; i < 4; i++) {
-                for (int j = runLength - 1; j >= 0; j--) {
-                    chunkX += xPattern[i];
-                    chunkZ += zPattern[i];
-                    if (source.world.getBlockBiome(chunkX * 16, y, chunkZ * 16) == biome) {
-                        return new int[] { chunkX * 16, chunkZ * 16 };
+            for(int pass = 0; pass < passes; ++pass) {
+                for(int i = 0; i < 4; ++i) {
+                    for(int j = runLength - 1; j >= 0; --j) {
+                        chunkX += xPattern[i];
+                        chunkZ += zPattern[i];
+                        if (source.getWorld().getBlockBiome(chunkX * 16, y, chunkZ * 16) == biome) {
+                            return new Coordinates2D(chunkX * 16, chunkZ * 16);
+                        }
                     }
                 }
+
+                ++runLength;
             }
-            runLength++;
-        }
 
-        return null;
+            return null;
+        }
     }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/ChunkCommand.java b/src/main/java/net/minecraft/core/net/command/commands/ChunkCommand.java
index 353a82056..dddb37b1a 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/ChunkCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/ChunkCommand.java
@@ -1,94 +1,35 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.core.net.command.*;
-import net.minecraft.core.world.World;
-
-public class ChunkCommand extends Command
-{
-    public ChunkCommand()
-    {
-        super("chunk");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args)
-    {
-        if (args[0].equalsIgnoreCase("regen"))
-        {
-            World world = null;
-            int x = Integer.MAX_VALUE;
-            int z = Integer.MAX_VALUE;
-
-            if(sender instanceof PlayerCommandSender)
-            {
-                world = sender.getPlayer().world;
-                if (args.length == 3)
-                {
-                    if (args[1].equalsIgnoreCase("~"))
-                    {
-                        x = sender.getPlayer().chunkCoordX;
-                    }
-                    else
-                    {
-                        x = Integer.parseInt(args[1]);
-                    }
-                    if (args[2].equalsIgnoreCase("~"))
-                    {
-                        z = sender.getPlayer().chunkCoordZ;
-                    }
-                    else
-                    {
-                        z = Integer.parseInt(args[2]);
-                    }
-                }
-            }
-
-            if(handler instanceof ServerCommandHandler)
-            {
-                if(args.length == 4)
-                {
-                    ServerCommandHandler server = (ServerCommandHandler) handler;
-                    int dim = Integer.parseInt(args[3]);
-
-                    world = server.minecraftServer.getDimensionWorld(dim);
-                    x = Integer.parseInt(args[1]);
-                    z = Integer.parseInt(args[2]);
-
-                }
-            }
-
-            if(world == null) throw new CommandError("Must be used by a player, or a dimension must be defined!");
-            if (x == Integer.MAX_VALUE || z == Integer.MAX_VALUE)
-            {
-                throw new CommandError("Please provide a valid value for X/Z!");
-            }
-
-            world.getChunkProvider().regenerateChunk(x, z);
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
-
-    @Override
-    public boolean opRequired(String[] args)
-    {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender)
-    {
-        if (sender instanceof PlayerCommandSender)
-        {
-            sender.sendMessage("/chunk regen <x> <z>");
-            sender.sendMessage("/chunk regen ~ ~");
-        }
-        else
-        {
-            sender.sendMessage("/chunk regen <x> <z> <dimension>");
-        }
-    }
-}
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.ChunkCoordinatesArgumentType;
+import net.minecraft.core.net.command.helpers.Coordinates2D;
+import net.minecraft.core.world.LevelListener;
+import net.minecraft.core.world.World;
+
+public class ChunkCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("chunk")
+            .requires(CommandSource::hasAdmin)
+            .then(LiteralArgumentBuilder.<CommandSource>literal("reset")
+                .then(RequiredArgumentBuilder.<CommandSource, Coordinates2D>argument("position", ChunkCoordinatesArgumentType.chunkCoordinates())
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        Coordinates2D coordinates2D = c.getArgument("position", Coordinates2D.class);
+                        World world = source.getWorld();
+
+                        int x = coordinates2D.getX(source);
+                        int z = coordinates2D.getZ(source);
+
+                        world.getChunkProvider().regenerateChunk(x, z);
+                        for (LevelListener listener : world.listeners) {
+                            listener.allChanged(false, true);
+                        }
+                        source.sendTranslatableMessage("command.commands.chunk.reset.success", x, z);
+                        return Command.SINGLE_SUCCESS;
+                    }))));
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/command/commands/ClearCommand.java b/src/main/java/net/minecraft/core/net/command/commands/ClearCommand.java
index af5c9e909..2d8738511 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/ClearCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/ClearCommand.java
@@ -1,52 +1,136 @@
 package net.minecraft.core.net.command.commands;
 
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.Tag;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.PlayerCommandSender;
-
-import java.util.Arrays;
-
-public class ClearCommand extends Command{
-
-	public ClearCommand() {
-		super("clear");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		Player player = null;
-		
-		if(args.length == 0) {
-			player = sender.getPlayer();
-		}
-		if(args.length == 1) {
-			player = handler.getPlayer(args[0]);
-		}
-		
-		if(player == null) throw new CommandError("Must be used by a player, or define a player name!");
-		
-		for(int i = 0; i < player.inventory.getContainerSize(); i++) {
-			player.inventory.setItem(i, null);
-		}
-		Arrays.fill(player.inventory.armorInventory, null);
-		
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		if(sender instanceof PlayerCommandSender) {
-			sender.sendMessage("/clear");
-		}
-		sender.sendMessage("/clear <player>");
-	}
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.arguments.ItemStackArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class ClearCommand {
+    private static final Logger LOGGER = LogUtils.getLogger();
+
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.clear.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("clear")
+            .requires(CommandSource::hasAdmin)
+            .executes(c -> {
+                CommandSource source = c.getSource();
+                Player sender = source.getSender();
+
+                if (sender == null) throw CommandExceptions.notInWorld().create();
+
+                int itemsCleared = clearItemsFromEntity(sender, null);
+
+                if (itemsCleared == 0) throw FAILURE.create();
+                source.sendMessage(getMessage(itemsCleared, Collections.singletonList(sender)));
+
+                return Command.SINGLE_SUCCESS;
+            })
+            .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("players", EntityArgumentType.players())
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    List<? extends Entity> players = c.getArgument("players", EntitySelector.class).get(source);
+
+                    int itemsCleared = 0;
+
+                    for (Entity player : players) {
+                        itemsCleared += clearItemsFromEntity((Player) player, null);
+                    }
+
+                    if (itemsCleared == 0) throw FAILURE.create();
+                    source.sendMessage(getMessage(itemsCleared, players));
+
+                    return Command.SINGLE_SUCCESS;
+                })
+                .then(RequiredArgumentBuilder.<CommandSource, ItemStack>argument("item", ItemStackArgumentType.itemStack())
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        List<? extends Entity> players = c.getArgument("players", EntitySelector.class).get(source);
+                        ItemStack itemStack = c.getArgument("item", ItemStack.class);
+
+                        int itemsCleared = 0;
+
+                        for (Entity player : players) {
+                            itemsCleared += clearItemsFromEntity((Player) player, itemStack);
+                        }
+
+                        if (itemsCleared == 0) throw FAILURE.create();
+                        source.sendMessage(getMessage(itemsCleared, players));
+
+                        return Command.SINGLE_SUCCESS;
+                    }))));
+    }
+
+    private static int clearItemsFromEntity(Player entityPlayer, @Nullable ItemStack itemStack) {
+        int itemsCleared = 0;
+
+        for (int i = 0; i < entityPlayer.inventory.getContainerSize(); ++i) {
+            ItemStack stackInSlot = entityPlayer.inventory.getItem(i);
+            if (stackInSlot != null && (itemStack == null || matchesItemStack(itemStack, stackInSlot))) {
+                itemsCleared++;
+                entityPlayer.inventory.setItem(i, null);
+            }
+        }
+
+        return itemsCleared;
+    }
+
+    private static boolean matchesItemStack(ItemStack checkedStack, ItemStack input) {
+        ItemStack checkedStackCopy = checkedStack.copy();
+        ItemStack inputCopy = input.copy();
+        checkedStackCopy.stackSize = 1;
+        inputCopy.stackSize = 1;
+        if (checkedStackCopy.getData().getValues().isEmpty()) {
+            return checkedStackCopy.isStackEqual(inputCopy);
+        }
+        LOGGER.info(checkedStackCopy.itemID + ", " + inputCopy.itemID + ", " + (checkedStackCopy.itemID == inputCopy.itemID));
+        LOGGER.info(checkedStackCopy.getMetadata() + ", " + inputCopy.getMetadata() + ", " + (checkedStackCopy.getMetadata() == inputCopy.getMetadata()));
+        LOGGER.info(checkedStackCopy.getData().getValues() + ", " + inputCopy.getData().getValues() + ", " + inputCopy.getData().getValues().containsAll(checkedStackCopy.getData().getValues()));
+        return checkedStackCopy.isStackEqual(inputCopy) && matchesTag(checkedStackCopy, inputCopy);
+    }
+
+    private static boolean matchesTag(ItemStack checkedStack, ItemStack input) {
+        for (Map.Entry<String, Tag<?>> entry : checkedStack.getData().getValue().entrySet()) {
+            if (!input.getData().getValue().containsKey(entry.getKey())
+                || (input.getData().getValue().get(entry.getKey()).getValue() != entry.getValue().getValue() && !input.getData().getValue().get(entry.getKey()).getValue().equals(entry.getValue().getValue()))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static String getMessage(int itemsCleared, List<? extends Entity> players) {
+        StringBuilder keyBuilder = new StringBuilder("command.commands.clear.success_");
+        if (itemsCleared > 1) {
+            keyBuilder.append("multiple_items_");
+        } else if (itemsCleared == 1) {
+            keyBuilder.append("single_item_");
+        }
+
+        if (players.size() > 1) {
+            keyBuilder.append("multiple_entities");
+        } else if (players.size() == 1) {
+            keyBuilder.append("single_entity");
+        }
+
+        return I18n.getInstance().translateKeyAndFormat(keyBuilder.toString(), itemsCleared, players.size());
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/CloneCommand.java b/src/main/java/net/minecraft/core/net/command/commands/CloneCommand.java
new file mode 100644
index 000000000..c5d1a7170
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/CloneCommand.java
@@ -0,0 +1,192 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.ArgumentBuilder;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.World;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.BlockArgumentType;
+import net.minecraft.core.net.command.arguments.DimensionArgumentType;
+import net.minecraft.core.net.command.arguments.IntegerCoordinatesArgumentType;
+import net.minecraft.core.net.command.helpers.BlockInput;
+import net.minecraft.core.net.command.helpers.ClonedBlock;
+import net.minecraft.core.net.command.helpers.IntegerCoordinate;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CloneCommand {
+    private static final SimpleCommandExceptionType INSIDE_CLONED_AREA = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.clone.exception_inside_cloned_area"));
+    private static final SimpleCommandExceptionType DESTINATION_NOT_LOADED = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.clone.exception_destination_not_loaded"));
+    private static final SimpleCommandExceptionType SOURCE_NOT_LOADED = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.clone.exception_source_not_loaded"));
+    private static final SimpleCommandExceptionType NOWHERE_LOADED = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.clone.exception_nowhere_loaded"));
+
+    public static void register(CommandDispatcher<CommandSource> commandDispatcher) {
+        commandDispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("clone")
+                .requires(CommandSource::hasAdmin)
+                .then(beginEndDestinationAndModeSuffix(c -> {
+                    return c.getSource().getWorld();
+                }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("from")
+                        .then((RequiredArgumentBuilder.<CommandSource, Dimension>argument("sourceDimension", DimensionArgumentType.dimension()))
+                                .then(beginEndDestinationAndModeSuffix(c -> {
+                                    return c.getSource().getWorld(c.getArgument("sourceDimension", Dimension.class).id);
+                                })))));
+    }
+
+    private static ArgumentBuilder<CommandSource, ?> beginEndDestinationAndModeSuffix(CommandFunction<CommandContext<CommandSource>, World> commandFunction) {
+        return RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("begin", IntegerCoordinatesArgumentType.intCoordinates())
+                .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("end", IntegerCoordinatesArgumentType.intCoordinates())
+                        .then(destinationAndModeSuffix(commandFunction, c -> {
+                            return c.getSource().getWorld();
+                        }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("to")
+                                .then((RequiredArgumentBuilder.<CommandSource, Dimension>argument("targetDimension", DimensionArgumentType.dimension()))
+                                        .then(destinationAndModeSuffix(commandFunction, c -> {
+                                            return c.getSource().getWorld(c.getArgument("targetDimension", Dimension.class).id);
+                                        })))));
+    }
+
+    private static WorldAndPosition getWorldAndPosition(CommandContext<CommandSource> commandContext, World world, String string) {
+        IntegerCoordinates coordinates = commandContext.getArgument(string, IntegerCoordinates.class);
+        return new WorldAndPosition(world, coordinates);
+    }
+
+    private static ArgumentBuilder<CommandSource, ?> destinationAndModeSuffix(CommandFunction<CommandContext<CommandSource>, World> commandFunction, CommandFunction<CommandContext<CommandSource>, World> commandFunction2) {
+        CommandFunction<CommandContext<CommandSource>, WorldAndPosition> commandFunction3 = c -> getWorldAndPosition(c, commandFunction.apply(c), "begin");
+        CommandFunction<CommandContext<CommandSource>, WorldAndPosition> commandFunction4 = c -> getWorldAndPosition(c, commandFunction.apply(c), "end");
+        CommandFunction<CommandContext<CommandSource>, WorldAndPosition> commandFunction5 = c -> getWorldAndPosition(c, commandFunction2.apply(c), "destination");
+        return RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("destination", IntegerCoordinatesArgumentType.intCoordinates())
+                .executes(c -> {
+                    return clone(c.getSource(), commandFunction3.apply(c), commandFunction4.apply(c), commandFunction5.apply(c), null, CloneMode.NORMAL);
+                })
+                .then(wrapWithCloneMode(commandFunction3, commandFunction4, commandFunction5, (commandContext) -> null, LiteralArgumentBuilder.<CommandSource>literal("replace")
+                        .executes(c -> {
+                            return clone(c.getSource(), commandFunction3.apply(c), commandFunction4.apply(c), commandFunction5.apply(c), null, CloneMode.NORMAL);
+                        })))
+                .then(wrapWithCloneMode(commandFunction3, commandFunction4, commandFunction5, commandContext -> new BlockInput(null, 0, new CompoundTag()), LiteralArgumentBuilder.<CommandSource>literal("masked")
+                        .executes(c -> {
+                            return clone(c.getSource(), commandFunction3.apply(c), commandFunction4.apply(c), commandFunction5.apply(c), new BlockInput(null, 0, new CompoundTag()), CloneMode.NORMAL);
+                        })))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("filtered")
+                        .then(wrapWithCloneMode(commandFunction3, commandFunction4, commandFunction5, c -> {
+                            return c.getArgument("filter", BlockInput.class);
+                            }, RequiredArgumentBuilder.<CommandSource, BlockInput>argument("filter", BlockArgumentType.block())
+                                .executes(c -> {
+                                    return clone(c.getSource(), commandFunction3.apply(c), commandFunction4.apply(c), commandFunction5.apply(c), c.getArgument("filter", BlockInput.class), CloneMode.NORMAL);
+                                }))));
+    }
+
+    private static ArgumentBuilder<CommandSource, ?> wrapWithCloneMode(CommandFunction<CommandContext<CommandSource>, WorldAndPosition> commandFunction, CommandFunction<CommandContext<CommandSource>, WorldAndPosition> commandFunction2, CommandFunction<CommandContext<CommandSource>, WorldAndPosition> commandFunction3, CommandFunction<CommandContext<CommandSource>, BlockInput> commandFunction4, ArgumentBuilder<CommandSource, ?> argumentBuilder) {
+        return argumentBuilder.then(LiteralArgumentBuilder.<CommandSource>literal("force")
+                .executes(c -> {
+                    return clone(c.getSource(), commandFunction.apply(c), commandFunction2.apply(c), commandFunction3.apply(c), commandFunction4.apply(c), CloneMode.FORCE);
+                }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("move")
+                        .executes(c -> {
+                            return clone(c.getSource(), commandFunction.apply(c), commandFunction2.apply(c), commandFunction3.apply(c), commandFunction4.apply(c), CloneMode.MOVE);
+                        }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("normal")
+                        .executes(c -> {
+                            return clone(c.getSource(), commandFunction.apply(c), commandFunction2.apply(c), commandFunction3.apply(c), commandFunction4.apply(c), CloneMode.NORMAL);
+                        }));
+    }
+
+    @FunctionalInterface
+    interface CommandFunction<T, R> {
+        R apply(T object) throws CommandSyntaxException;
+    }
+
+    public static class WorldAndPosition {
+        private final World world;
+        private final IntegerCoordinates position;
+
+        WorldAndPosition(World world, IntegerCoordinates position) {
+            this.world = world;
+            this.position = position;
+        }
+
+        public World getWorld() {
+            return this.world;
+        }
+
+        public IntegerCoordinates getPosition() {
+            return this.position;
+        }
+    }
+
+    public static int clone(CommandSource source, WorldAndPosition start, WorldAndPosition end, WorldAndPosition destination, @Nullable BlockInput filter, CloneMode cloneMode) throws CommandSyntaxException {
+        int minX = Math.min(start.getPosition().getX(source), end.getPosition().getX(source));
+        int minY = Math.min(start.getPosition().getY(source, true), end.getPosition().getY(source, true));
+        int minZ = Math.min(start.getPosition().getZ(source), end.getPosition().getZ(source));
+        int maxX = Math.max(start.getPosition().getX(source), end.getPosition().getX(source));
+        int maxY = Math.max(start.getPosition().getY(source, true), end.getPosition().getY(source, true));
+        int maxZ = Math.max(start.getPosition().getZ(source), end.getPosition().getZ(source));
+
+        int destinationX = destination.getPosition().getX(source);
+        int destinationY = destination.getPosition().getY(source, true);
+        int destinationZ = destination.getPosition().getZ(source);
+
+        if (cloneMode == CloneMode.NORMAL && AABB.getTemporaryBB(minX, minY, minZ, maxX, maxY, maxZ).contains(Vec3.getTempVec3(destinationX, destinationY, destinationZ)) && start.getWorld() == destination.getWorld()) {
+            throw INSIDE_CLONED_AREA.create();
+        }
+
+        start.getWorld().editingBlocks = true;
+        Map<IntegerCoordinates, ClonedBlock> map = new HashMap<>();
+        for (int x = minX; x <= maxX; x++) {
+            for (int y = minY; y <= maxY; y++) {
+                for (int z = minZ; z <= maxZ; z++) {
+                    if (!start.getWorld().isBlockLoaded(x, y, z)) {
+                        if (!destination.getWorld().isBlockLoaded(destinationX, destinationY, destinationZ)) throw NOWHERE_LOADED.create();
+                        else throw SOURCE_NOT_LOADED.create();
+                    }
+                    map.put(new IntegerCoordinates(new IntegerCoordinate(false, x - minX), new IntegerCoordinate(false, y - minY), new IntegerCoordinate(false, z - minZ)), new ClonedBlock(start.getWorld().getBlock(x, y, z), start.getWorld().getBlockMetadata(x, y, z), start.getWorld().getBlockEntity(x, y, z)));
+                    if (cloneMode == CloneMode.MOVE) {
+                        start.getWorld().setBlockWithNotify(x, y, z, 0);
+                    }
+                }
+            }
+        }
+        if (!destination.getWorld().isBlockLoaded(destinationX, destinationY, destinationZ)) throw DESTINATION_NOT_LOADED.create();
+        start.getWorld().editingBlocks = false;
+
+        int clonedBlocks = 0;
+        destination.getWorld().editingBlocks = true;
+        for (Map.Entry<IntegerCoordinates, ClonedBlock> entry : map.entrySet()) {
+            int offsetDestinationX = destinationX + entry.getKey().getX(source);
+            int offsetDestinationY = destinationY + entry.getKey().getY(source, true);
+            int offsetDestinationZ = destinationZ + entry.getKey().getZ(source);
+            CompoundTag blockTag = new CompoundTag();
+            BlockEntity blockEntity = destination.getWorld().getBlockEntity(offsetDestinationX, offsetDestinationY, offsetDestinationZ);
+            if (blockEntity != null) blockEntity.writeToNBT(blockTag);
+            if (filter == null || (destination.getWorld().getBlockId(offsetDestinationX, offsetDestinationY, offsetDestinationZ) == filter.getBlockId() && destination.getWorld().getBlockMetadata(offsetDestinationX, offsetDestinationY, offsetDestinationZ) == filter.getMetadata() && (filter.getTag().getValues().isEmpty() || CommandHelper.blockEntitiesAreEqual(blockTag, filter.getTag())))) {
+                if (destination.getWorld().getBlockId(offsetDestinationX, offsetDestinationY, offsetDestinationZ) != entry.getValue().getBlockId() || destination.getWorld().getBlockMetadata(offsetDestinationX, offsetDestinationY, offsetDestinationZ) != entry.getValue().getMetadata()) ++clonedBlocks;
+                destination.getWorld().setBlockWithNotify(offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getBlockId());
+                destination.getWorld().setBlockMetadataWithNotify(offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getMetadata());
+                CommandHelper.setBlockEntity(destination.getWorld(), offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getBlockEntity());
+            }
+        }
+        destination.getWorld().editingBlocks = false;
+        source.sendTranslatableMessage(clonedBlocks == 1 ? "command.commands.clone.success_single" : "command.commands.clone.success_multiple", clonedBlocks);
+        return clonedBlocks;
+    }
+
+    public enum CloneMode {
+        FORCE,
+        MOVE,
+        NORMAL
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/DamageCommand.java b/src/main/java/net/minecraft/core/net/command/commands/DamageCommand.java
new file mode 100644
index 000000000..f1cad1e5b
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/DamageCommand.java
@@ -0,0 +1,35 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.util.helper.DamageType;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.DamageTypeArgumentType;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+
+import java.util.List;
+
+public class DamageCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("damage")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("entities", EntityArgumentType.entities())
+                        .then(RequiredArgumentBuilder.<CommandSource, DamageType>argument("type", DamageTypeArgumentType.damageType())
+                                .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(0, 32768))
+                                        .executes(c -> {
+                                            List<? extends Entity> entities = c.getArgument("entities", EntitySelector.class).get(c.getSource());
+                                            DamageType type = c.getArgument("type", DamageType.class);
+                                            int amount = c.getArgument("amount", Integer.class);
+                                            int entitiesAffected = 0;
+                                            for (Entity entity : entities) {
+                                                if (entity.hurt(null, amount, type)) ++entitiesAffected;
+                                            }
+                                            c.getSource().sendTranslatableMessage("command.commands.damage.success_" + (entitiesAffected == 1 ? "single" : "multiple"), entitiesAffected);
+                                            return entitiesAffected;
+                                        })))));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/FillCommand.java b/src/main/java/net/minecraft/core/net/command/commands/FillCommand.java
new file mode 100644
index 000000000..0ef81bbe1
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/FillCommand.java
@@ -0,0 +1,214 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.enums.EnumDropCause;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.BlockArgumentType;
+import net.minecraft.core.net.command.arguments.IntegerCoordinatesArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.BlockInput;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.world.World;
+import org.jetbrains.annotations.Nullable;
+
+public class FillCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("fill")
+            .requires(CommandSource::hasAdmin)
+            .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("first", IntegerCoordinatesArgumentType.intCoordinates())
+                .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("second", IntegerCoordinatesArgumentType.intCoordinates())
+                    .then(RequiredArgumentBuilder.<CommandSource, BlockInput>argument("block", BlockArgumentType.block())
+                        .executes(c -> {
+                            IntegerCoordinates first = c.getArgument("first", IntegerCoordinates.class);
+                            IntegerCoordinates second = c.getArgument("second", IntegerCoordinates.class);
+                            BlockInput block = c.getArgument("block", BlockInput.class);
+                            if (CommandHelper.getVolume(c.getSource(), first, second) > 32768)
+                                throw CommandExceptions.volumeTooLarge().create();
+                            int blocksFilled = fillReplace(c.getSource(), c.getSource().getWorld(), first, second, block);
+                            c.getSource().sendTranslatableMessage(blocksFilled == 1 ? "command.commands.fill.success_single" : "commands.fill.success_multiple", blocksFilled);
+                            return blocksFilled;
+                        })
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("replace")
+                            .executes(c -> {
+                                IntegerCoordinates first = c.getArgument("first", IntegerCoordinates.class);
+                                IntegerCoordinates second = c.getArgument("second", IntegerCoordinates.class);
+                                BlockInput block = c.getArgument("block", BlockInput.class);
+                                if (CommandHelper.getVolume(c.getSource(), first, second) > 32768)
+                                    throw CommandExceptions.volumeTooLarge().create();
+                                int blocksFilled = fillReplace(c.getSource(), c.getSource().getWorld(), first, second, block);
+                                c.getSource().sendTranslatableMessage(blocksFilled == 1 ? "command.commands.fill.success_single" : "commands.fill.success_multiple", blocksFilled);
+                                return blocksFilled;
+                            })
+                            .then(RequiredArgumentBuilder.<CommandSource, BlockInput>argument("filter", BlockArgumentType.block())
+                                .executes(c -> {
+                                    IntegerCoordinates first = c.getArgument("first", IntegerCoordinates.class);
+                                    IntegerCoordinates second = c.getArgument("second", IntegerCoordinates.class);
+                                    BlockInput block = c.getArgument("block", BlockInput.class);
+                                    BlockInput filter = c.getArgument("filter", BlockInput.class);
+                                    if (CommandHelper.getVolume(c.getSource(), first, second) > 32768)
+                                        throw CommandExceptions.volumeTooLarge().create();
+                                    int blocksFilled = fillReplace(c.getSource(), c.getSource().getWorld(), first, second, block, filter);
+                                    c.getSource().sendTranslatableMessage(blocksFilled == 1 ? "command.commands.fill.success_single" : "commands.fill.success_multiple", blocksFilled);
+                                    return blocksFilled;
+                                })))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("hollow")
+                            .executes(c -> {
+                                IntegerCoordinates first = c.getArgument("first", IntegerCoordinates.class);
+                                IntegerCoordinates second = c.getArgument("second", IntegerCoordinates.class);
+                                BlockInput block = c.getArgument("block", BlockInput.class);
+                                if (CommandHelper.getVolume(c.getSource(), first, second) > 32768)
+                                    throw CommandExceptions.volumeTooLarge().create();
+                                int blocksFilled = fillHollow(c.getSource(), c.getSource().getWorld(), first, second, block);
+                                c.getSource().sendTranslatableMessage(blocksFilled == 1 ? "command.commands.fill.success_single" : "commands.fill.success_multiple", blocksFilled);
+                                return blocksFilled;
+                            }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("outline")
+                            .executes(c -> {
+                                IntegerCoordinates first = c.getArgument("first", IntegerCoordinates.class);
+                                IntegerCoordinates second = c.getArgument("second", IntegerCoordinates.class);
+                                BlockInput block = c.getArgument("block", BlockInput.class);
+                                if (CommandHelper.getVolume(c.getSource(), first, second) > 32768)
+                                    throw CommandExceptions.volumeTooLarge().create();
+                                int blocksFilled = fillOutline(c.getSource(), c.getSource().getWorld(), first, second, block);
+                                c.getSource().sendTranslatableMessage(blocksFilled == 1 ? "command.commands.fill.success_single" : "commands.fill.success_multiple", blocksFilled);
+                                return blocksFilled;
+                            }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("keep")
+                            .executes(c -> {
+                                IntegerCoordinates first = c.getArgument("first", IntegerCoordinates.class);
+                                IntegerCoordinates second = c.getArgument("second", IntegerCoordinates.class);
+                                BlockInput block = c.getArgument("block", BlockInput.class);
+                                if (CommandHelper.getVolume(c.getSource(), first, second) > 32768)
+                                    throw CommandExceptions.volumeTooLarge().create();
+                                int blocksFilled = fillKeep(c.getSource(), c.getSource().getWorld(), first, second, block);
+                                c.getSource().sendTranslatableMessage(blocksFilled == 1 ? "command.commands.fill.success_single" : "commands.fill.success_multiple", blocksFilled);
+                                return blocksFilled;
+                            }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("destroy")
+                            .executes(c -> {
+                                IntegerCoordinates first = c.getArgument("first", IntegerCoordinates.class);
+                                IntegerCoordinates second = c.getArgument("second", IntegerCoordinates.class);
+                                BlockInput block = c.getArgument("block", BlockInput.class);
+                                if (CommandHelper.getVolume(c.getSource(), first, second) > 32768)
+                                    throw CommandExceptions.volumeTooLarge().create();
+                                int blocksFilled = fillDestroy(c.getSource(), c.getSource().getWorld(), first, second, block);
+                                c.getSource().sendTranslatableMessage(blocksFilled == 1 ? "command.commands.fill.success_single" : "commands.fill.success_multiple", blocksFilled);
+                                return blocksFilled;
+                            }))))));
+    }
+
+    public static int fillReplace(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block) throws CommandSyntaxException {
+        return fillReplace(source, world, first, second, block, null);
+    }
+
+    public static int fillReplace(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block, @Nullable BlockInput filter) throws CommandSyntaxException {
+        return fillReplace(source, world, first, second, block, filter, false);
+    }
+
+    public static int fillReplace(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block, @Nullable BlockInput filter, boolean destroy) throws CommandSyntaxException {
+        world.editingBlocks = true;
+        int minX = Math.min(first.getX(source), second.getX(source));
+        int minY = Math.min(first.getY(source, true), second.getY(source, true));
+        int minZ = Math.min(first.getZ(source), second.getZ(source));
+        int maxX = Math.max(first.getX(source), second.getX(source));
+        int maxY = Math.max(first.getY(source, true), second.getY(source, true));
+        int maxZ = Math.max(first.getZ(source), second.getZ(source));
+
+        int blocksFilled = 0;
+        for (int x = minX; x <= maxX; x++) {
+            for (int y = minY; y <= maxY; y++) {
+                for (int z = minZ; z <= maxZ; z++) {
+                    CompoundTag blockTag = new CompoundTag();
+                    BlockEntity blockEntity = world.getBlockEntity(x, y, z);
+                    if (blockEntity != null) blockEntity.writeToNBT(blockTag);
+                    if ((block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getBlockEntity(x, y, z)))) && (filter == null || (world.getBlockId(x, y, z) == filter.getBlockId() && world.getBlockMetadata(x, y, z) == filter.getMetadata() && (filter.getTag().getValues().isEmpty() || CommandHelper.blockEntitiesAreEqual(blockTag, filter.getTag()))))) {
+                        ++blocksFilled;
+                        if (destroy && world.getBlock(x, y, z) != null)
+                            world.getBlock(x, y, z).getBreakResult(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), world.getBlockEntity(x, y, z));
+                    }
+                    if (filter == null || (world.getBlockId(x, y, z) == filter.getBlockId() && world.getBlockMetadata(x, y, z) == filter.getMetadata() && (!filter.getTag().getValue().isEmpty() || CommandHelper.blockEntitiesAreEqual(CommandHelper.tagFrom(world.getBlockEntity(x, y, z)), filter.getTag())))) {
+                        world.setBlockWithNotify(x, y, z, block.getBlockId());
+                        world.setBlockMetadataWithNotify(x, y, z, block.getMetadata());
+                        CommandHelper.setBlockEntity(world, x, y, z, block.getTag());
+                    }
+                }
+            }
+        }
+        world.editingBlocks = false;
+
+        return blocksFilled;
+    }
+
+    public static int fillHollow(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block) throws CommandSyntaxException {
+        world.editingBlocks = true;
+        int minX = Math.min(first.getX(source), second.getX(source));
+        int minY = Math.min(first.getY(source, true), second.getY(source, true));
+        int minZ = Math.min(first.getZ(source), second.getZ(source));
+        int maxX = Math.max(first.getX(source), second.getX(source));
+        int maxY = Math.max(first.getY(source, true), second.getY(source, true));
+        int maxZ = Math.max(first.getZ(source), second.getZ(source));
+
+        int blocksFilled = 0;
+        for (int x = minX; x <= maxX; x++) {
+            for (int y = minY; y <= maxY; y++) {
+                for (int z = minZ; z <= maxZ; z++) {
+                    boolean isOutline = x == minX || x == maxX || y == minY || y == maxY || z == minZ || z == maxZ;
+                    if ((isOutline && (block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getBlockEntity(x, y, z))))) || (!isOutline && world.getBlockId(x, y, z) != 0)) {
+                        ++blocksFilled;
+                        if (!isOutline && world.getBlock(x, y, z) != null)
+                            world.getBlock(x, y, z).getBreakResult(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), world.getBlockEntity(x, y, z));
+                    }
+                    world.setBlockWithNotify(x, y, z, isOutline ? block.getBlockId() : 0);
+                    world.setBlockMetadataWithNotify(x, y, z, isOutline ? block.getMetadata() : 0);
+                    CommandHelper.setBlockEntity(world, x, y, z, block.getTag());
+                }
+            }
+        }
+        world.editingBlocks = false;
+
+        return blocksFilled;
+    }
+
+    public static int fillOutline(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block) throws CommandSyntaxException {
+        world.editingBlocks = true;
+        int minX = Math.min(first.getX(source), second.getX(source));
+        int minY = Math.min(first.getY(source, true), second.getY(source, true));
+        int minZ = Math.min(first.getZ(source), second.getZ(source));
+        int maxX = Math.max(first.getX(source), second.getX(source));
+        int maxY = Math.max(first.getY(source, true), second.getY(source, true));
+        int maxZ = Math.max(first.getZ(source), second.getZ(source));
+
+        int blocksFilled = 0;
+        for (int x = minX; x <= maxX; x++) {
+            for (int y = minY; y <= maxY; y++) {
+                for (int z = minZ; z <= maxZ; z++) {
+                    boolean isOutline = x == minX || x == maxX || y == minY || y == maxY || z == minZ || z == maxZ;
+                    if (isOutline && (block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getBlockEntity(x, y, z)))))
+                        ++blocksFilled;
+                    if (isOutline) {
+                        world.setBlockWithNotify(x, y, z, block.getBlockId());
+                        world.setBlockMetadataWithNotify(x, y, z, block.getMetadata());
+                        CommandHelper.setBlockEntity(world, x, y, z, block.getTag());
+                    }
+                }
+            }
+        }
+        world.editingBlocks = false;
+
+        return blocksFilled;
+    }
+
+    public static int fillKeep(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block) throws CommandSyntaxException {
+        return fillReplace(source, world, first, second, block, new BlockInput(null, 0, new CompoundTag()));
+    }
+
+    public static int fillDestroy(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block) throws CommandSyntaxException {
+        return fillReplace(source, world, first, second, block, null, true);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/command/commands/GameModeCommand.java b/src/main/java/net/minecraft/core/net/command/commands/GameModeCommand.java
new file mode 100644
index 000000000..fbf3b7865
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/GameModeCommand.java
@@ -0,0 +1,63 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.arguments.GameModeArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.player.gamemode.Gamemode;
+
+import java.util.List;
+
+public class GameModeCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("gamemode")
+            .requires(CommandSource::hasAdmin)
+            .then(RequiredArgumentBuilder.<CommandSource, Gamemode>argument("gamemode", GameModeArgumentType.gameMode())
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    Gamemode gameMode = c.getArgument("gamemode", Gamemode.class);
+
+                    if (source.getSender() == null) {
+                        throw CommandExceptions.notInWorld().create();
+                    }
+
+                    source.getSender().setGamemode(gameMode);
+                    source.sendTranslatableMessage("command.commands.gamemode.success_self", I18n.getInstance().translateKey(gameMode.getLanguageKey() + ".name"));
+                    return Command.SINGLE_SUCCESS;
+                })
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("targets", EntityArgumentType.players())
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        Gamemode gameMode = c.getArgument("gamemode", Gamemode.class);
+                        EntitySelector entitySelector = c.getArgument("targets", EntitySelector.class);
+
+                        List<? extends Entity> entities = entitySelector.get(c.getSource());
+
+                        for (Entity entity : entities) {
+                            ((Player) entity).setGamemode(gameMode);
+                            if (entity != source.getSender()) {
+                                source.sendTranslatableMessage((Player) entity, "command.commands.gamemode.success_receiver");
+                            }
+                        }
+
+                        if (entities.size() == 1) {
+                            if (entities.get(0) == source.getSender()) {
+                                source.sendTranslatableMessage("command.commands.gamemode.success_self", I18n.getInstance().translateKey(gameMode.getLanguageKey() + ".name"));
+                            } else {
+                                source.sendTranslatableMessage("command.commands.gamemode.success_other", CommandHelper.getEntityName(entities.get(0)), I18n.getInstance().translateKey(gameMode.getLanguageKey() + ".name"));
+                            }
+                        }
+                        return Command.SINGLE_SUCCESS;
+                    })))
+        );
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/GameRuleCommand.java b/src/main/java/net/minecraft/core/net/command/commands/GameRuleCommand.java
new file mode 100644
index 000000000..b05c38594
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/GameRuleCommand.java
@@ -0,0 +1,48 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.BoolArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.data.gamerule.GameRule;
+import net.minecraft.core.data.gamerule.GameRuleBoolean;
+import net.minecraft.core.data.registry.Registries;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.GenericGameRuleArgumentType;
+
+public class GameRuleCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        final LiteralArgumentBuilder<CommandSource> argumentBuilder = LiteralArgumentBuilder.<CommandSource>literal("gamerule").requires(CommandSource::hasAdmin);
+        for (final GameRule<?> gameRule : Registries.GAME_RULES) {
+            RequiredArgumentBuilder<CommandSource, ?> gameRuleValueArgument;
+            if (gameRule instanceof GameRuleBoolean) {
+                gameRuleValueArgument = RequiredArgumentBuilder.<CommandSource, Boolean>argument("value", BoolArgumentType.bool())
+                        .executes(c -> {
+                            c.getSource().getWorld().getLevelData().getGameRules().setValue((GameRule<? super Object>) gameRule, BoolArgumentType.getBool(c, "value"));
+                            c.getSource().sendTranslatableMessage("command.commands.gamerule.set", gameRule.getKey(), BoolArgumentType.getBool(c, "value"));
+                            return Command.SINGLE_SUCCESS;
+                        });
+            } else {
+                gameRuleValueArgument = RequiredArgumentBuilder.<CommandSource, Object>argument("value", GenericGameRuleArgumentType.gameRule(gameRule))
+                        .executes(c -> {
+                            Object o = c.getArgument("value", Object.class);
+                            c.getSource().getWorld().getLevelData().getGameRules().setValue((GameRule<? super Object>) gameRule, o);
+                            c.getSource().sendTranslatableMessage("command.commands.gamerule.set", gameRule.getKey(), o);
+                            return Command.SINGLE_SUCCESS;
+                        });
+            }
+            argumentBuilder.then(LiteralArgumentBuilder.<CommandSource>literal(gameRule.getKey())
+                    .executes(c -> {
+                        c.getSource().sendTranslatableMessage("command.commands.gamerule.get", gameRule.getKey(), c.getSource().getWorld().getGameRuleValue(gameRule));
+                        return Command.SINGLE_SUCCESS;
+                    })
+                    .then(gameRuleValueArgument));
+        }
+        CommandNode<CommandSource> commandNode = dispatcher.register(argumentBuilder);
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("gr")
+                .requires(CommandSource::hasAdmin)
+                .redirect(commandNode));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/GamemodeCommand.java b/src/main/java/net/minecraft/core/net/command/commands/GamemodeCommand.java
deleted file mode 100644
index 537f6b502..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/GamemodeCommand.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.core.net.command.PlayerCommandSender;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.player.gamemode.Gamemode;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-
-public class GamemodeCommand extends Command{
-
-	public GamemodeCommand() {
-		super("gamemode", "gm");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 0) return false;
-		
-		String gamemodeString = args[0];
-		
-		Gamemode gamemode;
-		Player player;
-		
-		try {
-			gamemode = Gamemode.gamemodesList[Integer.parseInt(gamemodeString)];
-		}catch (Exception e) {
-			gamemode = getGamemode(gamemodeString);
-		}
-		
-		if(gamemode == null) throw new CommandError("Can't find gamemode \""+gamemodeString+"\"!");
-		
-		player = sender.getPlayer();
-		
-		if(args.length > 1) {
-			player = handler.getPlayer(args[1]);
-		}
-		
-		if(player == null) {
-			throw new CommandError("Must be used by a player, or a player name must be defined!");
-		}
-		player.setGamemode(gamemode);
-		handler.sendCommandFeedback(sender, "Set gamemode to "+gamemode.getLanguageKey().substring(9)+" for " + player.getDisplayName());
-		
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		if (sender instanceof PlayerCommandSender){
-			sender.sendMessage("/gamemode <gamemode>");
-		}
-		sender.sendMessage("/gamemode <gamemode> <player>");
-	}
-	
-	public static Gamemode getGamemode(String string) {
-		for(Gamemode gamemode : Gamemode.gamemodesList) {
-			if(string.equalsIgnoreCase(gamemode.getLanguageKey().substring(9))) {
-				return gamemode;
-			}
-		}
-		return null;
-	}
-	
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/GameruleCommand.java b/src/main/java/net/minecraft/core/net/command/commands/GameruleCommand.java
deleted file mode 100644
index ebab270f7..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/GameruleCommand.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.core.data.gamerule.GameRule;
-import net.minecraft.core.data.gamerule.GameRuleCollection;
-import net.minecraft.core.data.registry.Registries;
-import net.minecraft.core.net.command.*;
-import net.minecraft.core.net.packet.GameRulePacket;
-
-public class GameruleCommand
-    extends Command
-{
-    public GameruleCommand() {
-        super("gamerule", "gr");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args)
-    {
-        if (!(args.length == 1 || args.length == 2)) return false;
-
-        if (args[0].equalsIgnoreCase("list"))
-        {
-            sender.sendMessage("List of game rules:");
-            for (GameRule<?> gameRule : Registries.GAME_RULES)
-            {
-                sender.sendMessage(" - " + gameRule.getKey());
-            }
-            return true;
-        }
-
-        GameRule<?> gameRule = null;
-
-        for (GameRule<?> gr : Registries.GAME_RULES)
-        {
-            if (gr.getKey().equalsIgnoreCase(args[0]))
-            {
-                gameRule = gr;
-                break;
-            }
-        }
-
-        if (gameRule == null)
-        {
-            throw new CommandError("Can't find game rule \"" + args[0] + "\"!");
-        }
-
-        GameRuleCollection gameRules = handler.getWorld(0).getLevelData().getGameRules();
-
-        if (args.length == 1)
-        {
-            handler.sendCommandFeedback(sender, "Value of game rule \"" + gameRule.getKey() + "\" is " + gameRules.getValue(gameRule) + ".");
-            return true;
-        }
-        else
-        {
-            String valStr = args[1];
-
-            Object o = gameRule.parseFromString(valStr);
-            if (o == null)
-            {
-                throw new CommandError("Could not parse value!");
-            }
-
-            gameRules.setValue((GameRule)gameRule, o);
-            handler.sendCommandFeedback(sender, "Value of game rule \"" + gameRule.getKey() + "\" was set to " + gameRules.getValue(gameRule) + ".");
-
-            if (handler.isServer())
-            {
-                ServerCommandHandler serverHandler = (ServerCommandHandler) handler;
-                serverHandler.minecraftServer.playerList.sendPacketToAllPlayers(new GameRulePacket(gameRules));
-            }
-
-            return true;
-        }
-    }
-
-    @Override
-    public boolean opRequired(String[] args)
-    {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender)
-    {
-        handler.sendCommandFeedback(sender, "/gamerule list");
-        handler.sendCommandFeedback(sender, "/gamerule <rule>");
-        handler.sendCommandFeedback(sender, "/gamerule <rule> <value>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/GenerateCommand.java b/src/main/java/net/minecraft/core/net/command/commands/GenerateCommand.java
deleted file mode 100644
index c7a655604..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/GenerateCommand.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import com.b100.utils.Utils;
-import com.mojang.logging.LogUtils;
-import net.minecraft.core.Global;
-import net.minecraft.core.block.Block;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.util.helper.ReflectionHelper;
-import net.minecraft.core.world.generate.feature.MethodParametersAnnotation;
-import net.minecraft.core.world.generate.feature.WorldFeature;
-import org.slf4j.Logger;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Parameter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.Set;
-
-public class GenerateCommand extends Command {
-	private static final Logger LOGGER = LogUtils.getLogger();
-	private static final Map<String, Class<? extends WorldFeature>> worldFeatures = new HashMap<>();
-
-	public GenerateCommand() {
-		super("generate", "gen");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(!sender.isPlayer()) throw new CommandError("Must be used by a player!");
-		Player player = sender.getPlayer();
-		
-		if(args.length < 1) return false;
-
-		if(args[0].equalsIgnoreCase("list")) {
-			sender.sendMessage(TextFormatting.LIGHT_GRAY + "Available world features: ");
-			Set<String> keys = worldFeatures.keySet();
-			StringBuilder string = new StringBuilder();
-			
-			int i=0;
-			for(String key : keys) {
-				if(i > 0) string.append(", ");
-				string.append(key);
-				i++;
-			}
-			
-			sender.sendMessage(string.toString());
-			
-			return true;
-		}
-		
-		Class<? extends WorldFeature> worldFeatureClass = getWorldFeature(args[0]);
-		if(worldFeatureClass == null)  throw new CommandError("Feature " + args[0] + " doesn't exist!");
-		
-		List<Object> featureArgs = null;
-		Constructor<?> constructor = null;
-		
-		//Find constructor that matches the given arguments
-		for(Constructor<?> c : worldFeatureClass.getConstructors()) {
-			if(c.getParameterCount() == args.length - 1) {
-				List<Object> featureArgsList = new ArrayList<>();
-				
-				int i=0;					
-				for(Parameter parameter : c.getParameters()) {
-					Class<?> type = parameter.getType();
-					String arg = args[i + 1];
-					
-					if(type == String.class) {
-						featureArgsList.add(arg);
-					}else if(type == int.class) {
-						featureArgsList.add(Integer.parseInt(arg));
-					}else if(type == Block.class) {
-						Block block;
-						try {
-							block = Block.blocksList[Integer.parseInt(arg)];
-						}catch (Exception e) {
-							block = Block.getBlockByName(arg);
-						}
-						if(block != null) {
-							featureArgsList.add(block);
-						}else {
-							throw new CommandError("Can't find block: "+arg);
-						}
-					}else {
-						throw new RuntimeException("Can't parse type: "+type.getName());
-					}
-					
-					i++;
-				}
-				
-				constructor = c;
-				featureArgs = featureArgsList;
-			}
-			
-		}
-		
-		if(constructor == null) {
-			sender.sendMessage("Feature " + worldFeatureClass.getSimpleName() + " requires arguments: ");
-			for(Constructor<?> c : worldFeatureClass.getConstructors()) {
-				StringBuilder argString = new StringBuilder();
-				MethodParametersAnnotation annotation = null;
-				if (c.isAnnotationPresent(MethodParametersAnnotation.class)){
-					annotation = c.getAnnotation(MethodParametersAnnotation.class);
-				}
-				int i=0;
-				for(Parameter parameter : c.getParameters()) {
-					if(i > 0) argString.append(", ");
-					String argname;
-					if (annotation != null && annotation.names().length > i){
-						argname = annotation.names()[i];
-					} else {
-						argname = parameter.getName();
-					}
-					argString.append(argname).append(" (").append(parameter.getType().getSimpleName()).append(")");
-					i++;
-				}
-				
-				sender.sendMessage(argString.toString());
-			}
-			
-			return true;
-		}
-		
-		WorldFeature feature = createWorldFeature(worldFeatureClass, constructor, featureArgs);
-		if(!feature.place(handler.getWorld(player), new Random(), MathHelper.floor(player.x), MathHelper.floor(player.y), MathHelper.floor(player.z))) {
-			throw new CommandError("Could not spawn feature here!");
-		}
-
-		return true;
-	}
-	
-	public static WorldFeature createWorldFeature(Class<? extends WorldFeature> worldFeatureClass, Constructor<?> constructor, List<Object> featureArgs) {
-		if(featureArgs.size() != constructor.getParameterCount()) throw new RuntimeException("Invalid Parameter Count!");
-		
-		try {
-			return (WorldFeature) constructor.newInstance(Utils.toArray(Object.class, featureArgs));
-		}catch (Throwable e) {
-			throw new RuntimeException(e);
-		}
-	}
-	
-	public static Class<? extends WorldFeature> getWorldFeature(String name) {
-		for(Entry<String, Class<? extends WorldFeature>> entry : worldFeatures.entrySet()) {
-			if(entry.getKey().equalsIgnoreCase(name)) return entry.getValue();
-		}
-		return null;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/generate <feature> [params...]");
-		sender.sendMessage("/generate <list>");
-	}
-	
-	static {
-		try {
-			for (Class<?> clazz : ReflectionHelper.getAllClasses((className) -> className.startsWith("net.minecraft.core.world.generate.feature"))) {
-				if(WorldFeature.class.isAssignableFrom(clazz) && clazz != WorldFeature.class) {
-					@SuppressWarnings("unchecked")
-					Class<? extends WorldFeature> worldGenClass = (Class<? extends WorldFeature>) clazz;
-					worldFeatures.put(clazz.getSimpleName().substring(12), worldGenClass);
-				}
-			}
-		} catch (Exception e) {
-			LOGGER.error("Reflection hacking WorldFeatures failed!", e);
-		}
-	}
-}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/GiveCommand.java b/src/main/java/net/minecraft/core/net/command/commands/GiveCommand.java
index 777a6bc47..d9dba700c 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/GiveCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/GiveCommand.java
@@ -1,116 +1,84 @@
 package net.minecraft.core.net.command.commands;
 
-import net.minecraft.client.entity.player.LocalPlayer;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.item.Item;
-import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.PlayerCommandSender;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.arguments.ItemStackArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
 
-public class GiveCommand extends Command{
+import java.util.List;
 
-	public GiveCommand() {
-		super("give", "item", "i");
-	}
+public class GiveCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("give")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.players())
+                        .then(RequiredArgumentBuilder.<CommandSource, ItemStack>argument("item", ItemStackArgumentType.itemStack())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    ItemStack itemStack = c.getArgument("item", ItemStack.class);
+                                    int amount = itemStack.stackSize;
+                                    EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                                    List<? extends Entity> entities = entitySelector.get(source);
 
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		Player player;
-		Item item;
-		int count = 1;
-		int meta = 0;
-		
-		int arg = 0;
-		if(args.length == 0) return false;
-		
-		if(handler.playerExists(args[0])) {
-			player = handler.getPlayer(args[0]);
-			arg++;
-		}else {
-			player = sender.getPlayer();
-		}
-		
-		if(player == null) {
-			throw new CommandError("no player");
-		}
+                                    for (Entity player : entities) {
+                                        ((Player)player).inventory.insertItem(itemStack, true);
+                                        if (itemStack.stackSize > 0) {
+                                            ((Player)player).dropPlayerItem(itemStack);
+                                        }
+                                    }
 
-		String[] ids = args[arg].split(":");
-		
-		item = getItem(ids[0]);
-		if(item == null) {
-			throw new CommandError("Item not found: \""+ids[0]+"\"");
-		}
-		
-		if(ids.length > 1) {
-			meta = Integer.parseInt(ids[1]);
-		}
-		arg++;
-		
-		if(args.length > arg) {
-			count = Integer.parseInt(args[arg]);
-		}
+                                    if (entities.size() == 1) {
+                                        source.sendTranslatableMessage("command.commands.give.success_single_entity", CommandHelper.getEntityName(entities.get(0)), amount, itemStack.getDisplayName());
+                                    } else {
+                                        source.sendTranslatableMessage("command.commands.give.success_single_entity", entities.size(), amount, itemStack.getDisplayName());
+                                    }
 
-		ItemStack itemStack = new ItemStack(item, count, meta);
-		
-		return givePlayerItem(handler, sender, player, itemStack); 
-	}
+                                    return Command.SINGLE_SUCCESS;
+                                })
+                                .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(1, 6400))
+                                        .executes(c -> {
+                                            CommandSource source = c.getSource();
+                                            ItemStack itemStack = c.getArgument("item", ItemStack.class);
+                                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                                            List<? extends Entity> entities = entitySelector.get(source);
+                                            int amount = c.getArgument("amount", Integer.class);
 
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
+                                            for (Entity player : entities) {
+                                                int incompleteStack = amount % 64;
+                                                for (int i = 0; i < (amount - incompleteStack) / 64; i++) {
+                                                    ItemStack itemStack1 = ItemStack.copyItemStack(itemStack);
+                                                    itemStack1.stackSize = 64;
+                                                    ((Player) player).inventory.insertItem(itemStack1, true);
+                                                    if (itemStack1.stackSize > 0) {
+                                                        ((Player) player).dropPlayerItem(itemStack1);
+                                                    }
+                                                }
+                                                if (incompleteStack > 0) {
+                                                    ItemStack itemStack1 = ItemStack.copyItemStack(itemStack);
+                                                    itemStack1.stackSize = incompleteStack;
+                                                    ((Player) player).inventory.insertItem(itemStack1, true);
+                                                    if (itemStack1.stackSize > 0) {
+                                                        ((Player) player).dropPlayerItem(itemStack1);
+                                                    }
+                                                }
+                                            }
 
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/give <Player> <ID:Meta> <Count>");
-		if(sender instanceof PlayerCommandSender) {
-			sender.sendMessage("/give <ID:Meta> <Count>");
-		}
-	}
-	
-	public static Item getItem(String id) {
-		try {
-			int i = Integer.parseInt(id);
-			return getItem(i);
-		}catch (Exception e) {
-			String id2 = "tile."+id;
-			String id3 = "item."+id;
-			for(Item item : Item.itemsList) {
-				if(item != null) {
-					if(item.getKey().equalsIgnoreCase(id)) return item;
-					if(item.getKey().equalsIgnoreCase(id2)) return item;
-					if(item.getKey().equalsIgnoreCase(id3)) return item;
-				}
-			}
-			return null;
-		}
-	}
-	
-	public static Item getItem(int id) {
-		return Item.itemsList[id];
-	}
-	
-	public static boolean givePlayerItem(CommandHandler handler, CommandSender sender, Player player, ItemStack item) {
-		if(player instanceof LocalPlayer) {
-			player.inventory.insertItem(item, true);
-			if(item.stackSize > 0) {
-				player.dropPlayerItem(item);
-			}
-			return true;
-		}
-		if(player instanceof ServerPlayer) {
-			handler.sendCommandFeedback(sender, "Gave "+item.stackSize+" of "+ item.getItemKey() +" to "+player.getDisplayName());
-			
-			ServerPlayer playerMP = (ServerPlayer) player;
-			playerMP.dropPlayerItem(item);
-			return true;
-		}
-		return false;
-	}
+                                            if (entities.size() == 1) {
+                                                source.sendTranslatableMessage("command.commands.give.success_single_entity", CommandHelper.getEntityName(entities.get(0)), amount, itemStack.getDisplayName());
+                                            } else {
+                                                source.sendTranslatableMessage("command.commands.give.success_single_entity", entities.size(), amount, itemStack.getDisplayName());
+                                            }
 
+                                            return Command.SINGLE_SUCCESS;
+                                        })))));
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/HarmCommand.java b/src/main/java/net/minecraft/core/net/command/commands/HarmCommand.java
deleted file mode 100644
index 112d1f5a0..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/HarmCommand.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.util.helper.DamageType;
-
-public class HarmCommand extends Command
-{
-    public HarmCommand() {
-        super("harm");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args)
-    {
-        if (args.length == 0)
-        {
-            Player player = sender.getPlayer();
-            player.hurt(player, 1, DamageType.GENERIC);
-
-            sender.sendMessage("Harmed player " + player.getDisplayName() + "for 1");
-            return true;
-        }
-        else if (args.length == 1)
-        {
-            Player player = handler.getPlayer(args[0]);
-            if (player == null) return false;
-
-            player.hurt(player, 1, DamageType.GENERIC);
-            sender.sendMessage("Harmed player " + player.getDisplayName() + "for 1");
-            return true;
-        }
-        else if (args.length == 2)
-        {
-            Player player = handler.getPlayer(args[0]);
-            int damageAmount = parseInt(args[1]);
-            if (player == null) return false;
-
-            player.hurt(player, damageAmount, DamageType.GENERIC);
-            sender.sendMessage("Harmed player " + player.getDisplayName() + "for " + damageAmount);
-            return true;
-        }
-
-        return false;
-    }
-
-    public int parseInt(String str) {
-        try {
-            return Integer.parseInt(str);
-        }catch (Exception e) {
-            throw new CommandError("Not an integer: \""+str+"\"");
-        }
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/harm");
-        sender.sendMessage("/harm <username> <amount>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/HealCommand.java b/src/main/java/net/minecraft/core/net/command/commands/HealCommand.java
new file mode 100644
index 000000000..f11a5d3b6
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/HealCommand.java
@@ -0,0 +1,45 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+public class HealCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("heal")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("entities", EntityArgumentType.entities())
+                        .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(0, 32768))
+                                .executes(c -> {
+                                    List<? extends Entity> entities = c.getArgument("entities", EntitySelector.class).get(c.getSource());
+                                    int amount = c.getArgument("amount", Integer.class);
+
+                                    int entitiesAffected = 0;
+                                    for (Entity entity : entities) {
+                                        if (entity instanceof Mob) {
+                                            int maxHealth = 20;
+                                            try {
+                                                maxHealth = ((Mob)entity.getClass().getConstructor(World.class).newInstance(c.getSource().getWorld())).getMaxHealth();
+                                            } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ignored) {
+                                            }
+                                            int originalHealth = ((Mob)entity).getHealth();
+                                            ((Mob)entity).setHealthRaw(MathHelper.clamp(((Mob)entity).getHealth() + amount, 0, maxHealth));
+                                            if (((Mob)entity).getHealth() != originalHealth) ++entitiesAffected;
+                                        }
+                                    }
+                                    c.getSource().sendTranslatableMessage("command.commands.heal.success_" + (entitiesAffected == 1 ? "single" : "multiple"), entitiesAffected);
+                                    return entitiesAffected;
+                                }))));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/HelpCommand.java b/src/main/java/net/minecraft/core/net/command/commands/HelpCommand.java
index b8e7bc8e0..5119abc86 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/HelpCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/HelpCommand.java
@@ -1,82 +1,48 @@
 package net.minecraft.core.net.command.commands;
 
-import net.minecraft.core.net.command.ConsoleCommandSender;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.Commands;
-
-import java.util.ArrayList;
-import java.util.Comparator;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.util.Iterables;
+
+import java.util.Arrays;
 import java.util.List;
-
-public class HelpCommand extends Command{
-
-	public HelpCommand() {
-		super("help", "?");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 1) {
-			Command command = Commands.getCommand(args[0]);
-			
-			if(command == null) {
-				throw new CommandError("Can't find command: \""+args[0]+"\"");
-			}
-			
-			if(!sender.isAdmin() && command.opRequired(args)) {
-				throw new CommandError("You don't have permission to use this command!");
-			}
-			if(command.getNames().size() > 1) {
-				StringBuilder aliasStr = new StringBuilder();
-				aliasStr.append(TextFormatting.LIGHT_GRAY).append("Aliases: ");
-				for(int i=0; i < command.getNames().size(); i++) {
-					if(i > 0) {
-						aliasStr.append(", ");
-					}
-					aliasStr.append(command.getNames().get(i));
-				}
-				sender.sendMessage(aliasStr.toString());
-			}
-			sender.sendMessage(TextFormatting.LIGHT_GRAY + "Syntax: ");
-			command.sendCommandSyntax(handler, sender);
-			
-			return true;
-		}
-		
-		StringBuilder commandsString = new StringBuilder();
-
-		List<Command> commandList = new ArrayList<>(Commands.commands);
-		commandList.sort(Comparator.comparing(Command::getName)); // Sort commands by name
-
-		for(Command command : commandList) {
-			if(sender.isAdmin() || !command.opRequired(null)) {
-				if (sender instanceof ConsoleCommandSender) {
-					commandsString.append("\n").append("*    ");
-				} else {
-					commandsString.append(", ");
-				}
-				commandsString.append(command.getName());
-			}
-		}
-		
-		commandsString = new StringBuilder(TextFormatting.LIGHT_GRAY + "Commands: " + TextFormatting.WHITE + commandsString.substring(2));
-		sender.sendMessage(commandsString.toString());
-		
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return false;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/help");
-	}
-
+import java.util.Map;
+
+public class HelpCommand {
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.help.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> commandDispatcher) {
+        commandDispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("help")
+            .executes(c -> {
+                CommandSource source = c.getSource();
+                Map<CommandNode<CommandSource>, String> map = commandDispatcher.getSmartUsage(commandDispatcher.getRoot(), source);
+                if (!source.messageMayBeMultiline()) {
+                    source.sendMessage("Cannot display help on single-line command source");
+                    return 0;
+                }
+                for (String string : map.values()) {
+                    source.sendMessage("/" + string);
+                }
+                return map.size();
+            })
+            .then(RequiredArgumentBuilder.<CommandSource, String>argument("command", StringArgumentType.greedyString())
+                .executes(commandContext -> {
+                    ParseResults<CommandSource> parseResults = commandDispatcher.parse(StringArgumentType.getString(commandContext, "command"), commandContext.getSource());
+                    if (parseResults.getContext().getNodes().isEmpty()) {
+                        throw FAILURE.create();
+                    }
+                    Map<CommandNode<CommandSource>, String> map = commandDispatcher.getSmartUsage(Iterables.getLast(parseResults.getContext().getNodes()).getNode(), commandContext.getSource());
+                    for (String string : map.values()) {
+                        commandContext.getSource().sendMessage("/" + parseResults.getReader().getString() + " " + string);
+                    }
+                    return map.size();
+                })));
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/KillCommand.java b/src/main/java/net/minecraft/core/net/command/commands/KillCommand.java
index dbcbd88cf..13e5df255 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/KillCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/KillCommand.java
@@ -1,48 +1,63 @@
 package net.minecraft.core.net.command.commands;
 
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-
-public class KillCommand extends Command
-{
-    public KillCommand() {
-        super("kill");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args)
-    {
-        if (args.length == 0)
-        {
-            Player player = sender.getPlayer();
-            player.killPlayer();
-
-            sender.sendMessage("Killed player " + player.getDisplayName());
-            return true;
-        }
-        else if (args.length == 1)
-        {
-            Player player = handler.getPlayer(args[0]);
-            if (player == null) return false;
-
-            player.killPlayer();
-            sender.sendMessage("Killed player " + player.getDisplayName());
-            return true;
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/kill");
-        sender.sendMessage("/kill <username>");
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class KillCommand {
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.kill.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("kill")
+                .requires(CommandSource::hasAdmin)
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    Player sender = source.getSender();
+
+                    if (sender == null) throw CommandExceptions.notInWorld().create();
+
+                    sender.killPlayer();
+
+                    source.sendTranslatableMessage("command.commands.kill.single_entity", sender.getDisplayName());
+
+                    return Command.SINGLE_SUCCESS;
+                })
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("entities", EntityArgumentType.entities())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("entities", EntitySelector.class);
+                            CopyOnWriteArrayList<? extends Entity> entities = new CopyOnWriteArrayList<>(entitySelector.get(source));
+
+                            int entityCount = entities.size();
+
+                            if (entityCount == 0) throw FAILURE.create();
+                            else if (entityCount == 1) source.sendTranslatableMessage("command.commands.kill.single_entity", CommandHelper.getEntityName(entities.get(0)));
+                            else source.sendTranslatableMessage("command.commands.kill.multiple_entities", entityCount);
+
+                            for (Entity entity : entities) {
+                                if (entity instanceof Player) {
+                                    ((Player) entity).killPlayer();
+                                } else if (entity instanceof Mob) {
+                                    entity.hurt(null, 100, null);
+                                } else {
+                                    entity.remove();
+                                }
+                            }
+
+                            return Command.SINGLE_SUCCESS;
+                        })));
     }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/MessageCommand.java b/src/main/java/net/minecraft/core/net/command/commands/MessageCommand.java
new file mode 100644
index 000000000..0d52eb076
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/MessageCommand.java
@@ -0,0 +1,48 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.util.helper.LoggedPrintStream;
+
+import java.util.List;
+
+public class MessageCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("message")
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("targets", EntityArgumentType.players())
+                        .then(RequiredArgumentBuilder.<CommandSource, String>argument("message", StringArgumentType.greedyString())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    EntitySelector entitySelector = c.getArgument("targets", EntitySelector.class);
+                                    String message = c.getArgument("message", String.class);
+
+                                    String senderName = source.getName();
+
+                                    List<? extends Entity> players = entitySelector.get(source);
+
+                                    for (Entity player : players) {
+                                        source.sendMessage(TextFormatting.LIGHT_GRAY.toString() + TextFormatting.ITALIC.toString() + I18n.getInstance().translateKeyAndFormat("command.commands.message.outgoing", LoggedPrintStream.removeColorCodes(((Player)player).getDisplayName()), message));
+                                        source.sendMessage((Player)player, TextFormatting.LIGHT_GRAY + (TextFormatting.ITALIC + I18n.getInstance().translateKeyAndFormat("command.commands.message.incoming", senderName, message)));
+                                    }
+
+                                    return Command.SINGLE_SUCCESS;
+                                }))));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("msg")
+                .redirect(command));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("whisper")
+                .redirect(command));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("tell")
+                .redirect(command));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/MobSpawningCommand.java b/src/main/java/net/minecraft/core/net/command/commands/MobSpawningCommand.java
deleted file mode 100644
index 466ecff29..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/MobSpawningCommand.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.core.entity.EntityDispatcher;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.world.SpawnerMobs;
-import net.minecraft.core.world.World;
-
-import java.util.Collection;
-import java.util.Locale;
-
-public class MobSpawningCommand extends Command {
-    public MobSpawningCommand() {
-        super("mobspawning");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length == 0) return false;
-
-        World world = handler.getWorld(0);
-        SpawnerMobs.SpawnerConfig config = world.spawningConfig;
-        switch (args[0].toLowerCase(Locale.ROOT)) {
-            case "list": // Lists out all mobs and their current spawn state
-            {
-                Collection<String> ids = EntityDispatcher.classToKeyMap.values();
-                for (String s : ids) {
-                    sender.sendMessage(String.format("%s : %s", s, config.canMobSpawn(s)));
-                }
-                sender.sendMessage("Passive Spawning : " + config.canPassiveSpawn(world));
-                sender.sendMessage("Hostile Spawning : " + config.canHostileSpawn(world));
-                return true;
-            }
-            case "set": // Sets the spawning state of a specific mob id
-            {
-                if (args.length != 3) return false;
-                String mobId = args[1];
-                boolean value = Boolean.parseBoolean(args[2].toLowerCase(Locale.ROOT));
-                config.setMobSpawn(mobId, value);
-                sender.sendMessage(String.format("Set '%s' to '%s'", mobId, value));
-                return true;
-            }
-            case "passive": // Special case for setting state of all peaceful mobs
-            {
-                if (args.length != 2) return false;
-                boolean value = Boolean.parseBoolean(args[1].toLowerCase(Locale.ROOT));
-                config.setPassiveSpawning(value);
-                sender.sendMessage(String.format("Passive spawning to '%s'", value));
-                return true;
-            }
-            case "hostile": // Special case for setting state of all hostile mobs
-            {
-                if (args.length != 2) return false;
-                boolean value = Boolean.parseBoolean(args[1].toLowerCase(Locale.ROOT));
-                config.setHostileSpawning(value);
-                sender.sendMessage(String.format("Hostile spawning to '%s'", value));
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/mobspawning list");
-        sender.sendMessage("/mobspawning set <id> <value>");
-        sender.sendMessage("/mobspawning passive <value>");
-        sender.sendMessage("/mobspawning hostile <value>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/PlaceCommand.java b/src/main/java/net/minecraft/core/net/command/commands/PlaceCommand.java
new file mode 100644
index 000000000..5bb224441
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/PlaceCommand.java
@@ -0,0 +1,57 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.LevelListener;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.IntegerCoordinatesArgumentType;
+import net.minecraft.core.net.command.arguments.WorldFeatureArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
+
+public class PlaceCommand {
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.place.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("place")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, WorldFeature>argument("feature", WorldFeatureArgumentType.worldFeature())
+                        .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("position", IntegerCoordinatesArgumentType.intCoordinates())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    WorldFeature feature = c.getArgument("feature", WorldFeature.class);
+                                    IntegerCoordinates coordinates = c.getArgument("position", IntegerCoordinates.class);
+                                    World world = source.getWorld();
+
+                                    if (coordinates == null) throw CommandExceptions.notInWorld().create();
+
+                                    int x = coordinates.getX(source);
+                                    int y = coordinates.getY(source, true);
+                                    int z = coordinates.getZ(source);
+
+                                    boolean success = feature.place(world, source.getWorld().rand, x, y, z);
+                                    if (success) {
+                                        for (LevelListener listener : world.listeners) {
+                                            listener.allChanged(true, false);
+                                        }
+                                        source.sendTranslatableMessage("command.commands.place.success", feature.getClass().getSimpleName().substring(12), x, y, z);
+                                    } else {
+                                        throw FAILURE.create();
+                                    }
+                                    return Command.SINGLE_SUCCESS;
+                                }))));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("generate")
+                .requires(CommandSource::hasAdmin)
+                .redirect(command));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("gen")
+                .requires(CommandSource::hasAdmin)
+                .redirect(command));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/PlaySoundCommand.java b/src/main/java/net/minecraft/core/net/command/commands/PlaySoundCommand.java
deleted file mode 100644
index eb0586d4f..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/PlaySoundCommand.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.core.net.command.ClientCommandHandler;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommandHandler;
-import net.minecraft.core.net.packet.PlaySoundEffectDirectPacket;
-import net.minecraft.core.sound.SoundTypes;
-import net.minecraft.core.sound.SoundCategory;
-
-import java.util.Locale;
-
-public class PlaySoundCommand extends Command {
-    public PlaySoundCommand() {
-        super("playsound", "play");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        String soundPath = null;
-        SoundCategory soundType = null;
-        Float x = null;
-        Float y = null;
-        Float z = null;
-        int dimension = 0;
-        if (sender.getPlayer() != null){
-            x = (float) sender.getPlayer().x;
-            y = (float) sender.getPlayer().y;
-            z = (float) sender.getPlayer().z;
-            dimension = sender.getPlayer().dimension;
-        }
-        float volume = 1f;
-        float pitch = 1f;
-        if (args.length >= 2){
-            soundPath = args[0];
-            soundType = SoundCategory.valueOf(args[1].toUpperCase(Locale.ROOT));
-            if (args.length >= 5){
-                x = Float.parseFloat(args[2]);
-                y = Float.parseFloat(args[3]);
-                z = Float.parseFloat(args[4]);
-                if (args.length >= 7){
-                    volume = Float.parseFloat(args[4]);
-                    pitch = Float.parseFloat(args[5]);
-                }
-            }
-        }
-        if (soundPath != null && x != null){
-            if (handler instanceof ServerCommandHandler){
-                int soundId = SoundTypes.getSoundId(soundPath);
-                if(soundId < 0) {
-                    throw new CommandError("Invalid Sound: '" + soundPath + "'!");
-                }
-                ((ServerCommandHandler) handler).minecraftServer.playerList.sendPacketToPlayersAroundPoint(x, y,z, 128f, dimension, new PlaySoundEffectDirectPacket(soundId, soundType, x, y, z, volume, pitch));
-            } else if (handler instanceof ClientCommandHandler){
-                ((ClientCommandHandler) handler).minecraft.sndManager.playSoundAt(soundPath, soundType, x, y, z, volume, pitch);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        if (sender.getPlayer() != null){
-            sender.sendMessage("/playsound <SoundPath> <SoundType>");
-        }
-        sender.sendMessage("/playsound <SoundPath> <SoundType> <x> <y> <z>");
-        sender.sendMessage("/playsound <SoundPath> <SoundType> <x> <y> <z> <Volume> <Pitch>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/SayCommand.java b/src/main/java/net/minecraft/core/net/command/commands/SayCommand.java
new file mode 100644
index 000000000..260d02158
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/SayCommand.java
@@ -0,0 +1,23 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.net.command.CommandSource;
+
+public class SayCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("say")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, String>argument("message", StringArgumentType.greedyString())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            String message = StringArgumentType.getString(c, "message");
+                            String senderName = source.getName();
+                            source.sendMessageToAllPlayers("[" + senderName + "§r] " + message);
+                            return Command.SINGLE_SUCCESS;
+                        })));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/SeedCommand.java b/src/main/java/net/minecraft/core/net/command/commands/SeedCommand.java
index 8aff21c0f..77845be9e 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/SeedCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/SeedCommand.java
@@ -1,64 +1,19 @@
 package net.minecraft.core.net.command.commands;
 
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.StringSelection;
-
-import net.minecraft.core.world.World;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.PlayerCommandSender;
-import net.minecraft.core.net.command.ServerCommandHandler;
-
-public class SeedCommand extends Command{
-
-	public SeedCommand() {
-		super("seed");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		World world = null;
-		
-		if(sender instanceof PlayerCommandSender) {
-			world = sender.getPlayer().world;
-		}
-		
-		if(handler instanceof ServerCommandHandler) {
-			if(args.length > 0) {
-				ServerCommandHandler server = (ServerCommandHandler) handler;
-				int dim = Integer.parseInt(args[0]);
-				
-				world = server.minecraftServer.getDimensionWorld(dim);
-			}
-		}
-		
-		if(world == null) throw new CommandError("Must be used by a player, or a dimension must be defined!");
-		
-		sender.sendMessage("Seed: " + TextFormatting.LIME + world.getRandomSeed());
-		
-		if(handler.isClient()) {
-			Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
-			clipboard.setContents(new StringSelection(String.valueOf(world.getRandomSeed())), null);
-			sender.sendMessage("Copied to clipboard!");
-		}
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		if(sender instanceof PlayerCommandSender) {
-			sender.sendMessage("/seed");
-		}
-		sender.sendMessage("/seed <dimension>");
-	}
-
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import net.minecraft.core.net.command.CommandSource;
+
+public class SeedCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("seed")
+                .requires(CommandSource::hasAdmin)
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    source.sendTranslatableMessage("command.commands.seed.success", source.getWorld().getRandomSeed());
+                    return Command.SINGLE_SUCCESS;
+                })
+        );
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/SetBlockCommand.java b/src/main/java/net/minecraft/core/net/command/commands/SetBlockCommand.java
index f57fd4e2b..7fdc85895 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/SetBlockCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/SetBlockCommand.java
@@ -1,127 +1,46 @@
 package net.minecraft.core.net.command.commands;
 
-import net.minecraft.core.block.Block;
-import net.minecraft.core.block.Blocks;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-
-public class SetBlockCommand extends Command{
-
-	public SetBlockCommand() {
-		super("setblock");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length < 4) return false;
-		if(!sender.isPlayer()) throw new CommandError("Must be sent by a player!");
-
-		int blockIDOffset;
-
-		int x1 = Integer.parseInt(args[0]);
-		int y1 = Integer.parseInt(args[1]);
-		int z1 = Integer.parseInt(args[2]);
-		int x2, y2, z2;
-
-		if (args.length == 4)
-		{
-			x2 = x1;
-			y2 = y1;
-			z2 = z1;
-			blockIDOffset = 3;
-		}
-		else if (args.length == 7)
-		{
-			x2 = Integer.parseInt(args[3]);
-			y2 = Integer.parseInt(args[4]);
-			z2 = Integer.parseInt(args[5]);
-			blockIDOffset = 6;
-		}
-		else
-		{
-			return false;
-		}
-
-		// Swap parameters if needed
-		if (x1 > x2)
-		{
-			int temp = x1;
-			x1 = x2;
-			x2 = temp;
-		}
-		if (y1 > y2)
-		{
-			int temp = y1;
-			y1 = y2;
-			y2 = temp;
-		}
-		if (z1 > z2)
-		{
-			int temp = z1;
-			z1 = z2;
-			z2 = temp;
-		}
-		
-		String[] id = args[blockIDOffset].split(":");
-		
-		int meta = 0;
-		
-		if(id.length >= 2) {
-			meta = Integer.parseInt(id[1]);
-		}
-		
-		int blockId = getBlock(id[0], meta);
-		if (blockId == -1) return false;
-
-		for (int x = x1; x <= x2; x++)
-		{
-			for (int z = z1; z <= z2; z++)
-			{
-				for (int y = y1; y <= y2; y++)
-				{
-					sender.getPlayer().world.setBlockAndMetadataWithNotify(x, y, z, blockId, meta);
-				}
-			}
-		}
-
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/setblock <x> <y> <z> <block>");
-		sender.sendMessage("/setblock <x1> <y1> <z1> <x2> <y2> <z2> <block>");
-	}
-	
-	public static Block getBlock(int id) {
-		return Block.blocksList[id];
-	}
-	
-	public static int getBlock(String id, int meta) {
-		try {
-			int i = Integer.parseInt(id);
-			if (i == 0 || Block.blocksList[i] != null)
-			{
-				return i;
-			}
-			else return -1;
-		}catch (Exception e) {
-			String id2 = "tile."+id;
-			for(Block block : Block.blocksList) {
-				if(block != null) {
-					if(block.getKey().equalsIgnoreCase(id)) return block.id;
-					if(block.getKey().equalsIgnoreCase(id2)) return block.id;
-				}
-			}
-			return -1;
-		}
-	}
-
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.*;
+import net.minecraft.core.net.command.helpers.BlockInput;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
+
+public class SetBlockCommand {
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.commands.setblock.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("setblock")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("position", IntegerCoordinatesArgumentType.intCoordinates())
+                        .then(RequiredArgumentBuilder.<CommandSource, BlockInput>argument("block", BlockArgumentType.block())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    IntegerCoordinates coordinates = c.getArgument("position", IntegerCoordinates.class);
+                                    BlockInput blockInput = c.getArgument("block", BlockInput.class);
+                                    World world = source.getWorld();
+
+                                    int x = coordinates.getX(source);
+                                    int y = coordinates.getY(source, true);
+                                    int z = coordinates.getZ(source);
+
+                                    if (!world.isBlockLoaded(x, y, z)) {
+                                        throw FAILURE.create();
+                                    } else {
+                                        world.setBlockWithNotify(x, y, z, blockInput.getBlockId());
+                                        world.setBlockMetadataWithNotify(x, y, z, blockInput.getMetadata());
+                                        CommandHelper.setBlockEntity(world, x, y, z, blockInput.getTag());
+                                        source.sendTranslatableMessage("command.commands.setblock.success", coordinates.getX(source), coordinates.getY(source, true), coordinates.getZ(source));
+                                    }
+
+                                    return Command.SINGLE_SUCCESS;
+                                }))));
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/SetSpawnCommand.java b/src/main/java/net/minecraft/core/net/command/commands/SetSpawnCommand.java
index e59663dbb..fd27ebdf1 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/SetSpawnCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/SetSpawnCommand.java
@@ -1,64 +1,35 @@
 package net.minecraft.core.net.command.commands;
 
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.CommandNode;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.world.World;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.PlayerCommandSender;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.IntegerCoordinatesArgumentType;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
 
-public class SetSpawnCommand extends Command{
+public class SetSpawnCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("setworldspawn")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("position", IntegerCoordinatesArgumentType.intCoordinates())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            IntegerCoordinates coordinates = c.getArgument("position", IntegerCoordinates.class);
 
-	public SetSpawnCommand() {
-		super("setworldspawn", "setspawn");
-	}
+                            int x = coordinates.getX(source);
+                            int y = coordinates.getY(source, true);
+                            int z = coordinates.getZ(source);
 
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		Player player = sender.getPlayer();
-		
-		int x, y, z;
-		
-		if(args.length > 0) {
-			try {
-				x = Integer.parseInt(args[0]);
-				y = Integer.parseInt(args[1]);
-				z = Integer.parseInt(args[2]);
-			}
-			catch (NumberFormatException nfe){
-				throw new CommandError("Coordinates must be integers!");
-			}
-		}else {
-			if(player == null) throw new CommandError("Must be used by a player, or define coordinates!");
-			
-			x = (int) Math.floor(player.x);
-			y = (int) Math.floor(player.y);
-			z = (int) Math.floor(player.z);
-		}
-		
-		ChunkCoordinates pos = new ChunkCoordinates(x, y, z);
-		World world = handler.getWorld(0);
-		world.setSpawnPoint(pos);
-		handler.sendCommandFeedback(sender, "Set spawn location to x: "+x+" y: "+y+" z: "+z);
-		
-		return true;
-	}
+                            source.getWorld().setSpawnPoint(new ChunkCoordinates(x, y, z));
+                            source.sendTranslatableMessage("command.commands.setspawn.success", x, y, z);
 
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		if(sender instanceof PlayerCommandSender) {
-			sender.sendMessage("/setworldspawn");
-		}
-		sender.sendMessage("/setworldspawn <x> <y> <z>");
-	}
-	
-	
-	
+                            return Command.SINGLE_SUCCESS;
+                        })));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("setspawn")
+                .requires(CommandSource::hasAdmin)
+                .redirect(command));
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/SpawnCommand.java b/src/main/java/net/minecraft/core/net/command/commands/SpawnCommand.java
index 86927b514..57ed015ab 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/SpawnCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/SpawnCommand.java
@@ -1,57 +1,66 @@
 package net.minecraft.core.net.command.commands;
 
-import net.minecraft.core.world.chunk.ChunkCoordinates;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
-import net.minecraft.server.entity.player.ServerPlayer;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
 import net.minecraft.core.world.World;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.PlayerCommandSender;
+import net.minecraft.core.world.chunk.ChunkCoordinates;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
 
-public class SpawnCommand extends Command{
+import java.util.List;
 
-	public SpawnCommand() {
-		super("spawn");
-	}
+public class SpawnCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("spawn")
+                .requires(CommandSource::hasAdmin)
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    Player sender = source.getSender();
+                    World world = source.getWorld(0);
+                    ChunkCoordinates spawnCoordinates = world.getSpawnPoint();
 
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(sender instanceof PlayerCommandSender) {
-			Player player = sender.getPlayer();
-			
-			World world = handler.getWorld(player);
-			
-			ChunkCoordinates pos = world.getSpawnPoint();
-			
-			sender.sendMessage("Teleporting to spawn...");
-			
-			if(player instanceof ServerPlayer) {
-				ServerPlayer playerMP = (ServerPlayer) player;
-				if(playerMP.dimension != 0) {
-					playerMP.mcServer.playerList.sendPlayerToOtherDimension(playerMP, 0, false);
-				}
-				playerMP.playerNetServerHandler.teleportAndRotate(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, 0, 0);
-			}
-			player.absMoveTo(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, 0, 0);
-			
-			return true;
-		}else {
-			throw new CommandError("Must be used by a player!");
-		}
-	}
+                    if (sender == null) throw CommandExceptions.notInWorld().create();
 
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
+                    if (sender.dimension != 0) source.movePlayerToDimension(sender, 0);
+                    sender.absMoveTo(spawnCoordinates.x + 0.5, spawnCoordinates.y, spawnCoordinates.z + 0.5, sender.yRot, sender.xRot);
+                    source.sendTranslatableMessage("command.commands.spawn.success");
+                    return Command.SINGLE_SUCCESS;
+                })
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("players", EntityArgumentType.players())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            Player sender = source.getSender();
+                            World world = source.getWorld(0);
+                            ChunkCoordinates spawnCoordinates = world.getSpawnPoint();
+                            EntitySelector entitySelector = c.getArgument("players", EntitySelector.class);
+                            List<? extends Entity> players = entitySelector.get(source);
 
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/spawn");
-	}
-	
-	
-	
+                            for (Entity entity : players) {
+                                if (((Player)entity).dimension != 0) source.movePlayerToDimension((Player) entity, 0);
+                                entity.absMoveTo(spawnCoordinates.x + 0.5, spawnCoordinates.y, spawnCoordinates.z + 0.5, entity.yRot, entity.xRot);
+                                if (entity == sender) {
+                                    source.sendTranslatableMessage("command.commands.spawn.success");
+                                } else {
+                                    source.sendTranslatableMessage("command.commands.spawn.success_receiver");
+                                    source.sendTranslatableMessage("command.commands.spawn.success_other", CommandHelper.getEntityName(entity));
+                                }
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("get")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            ChunkCoordinates spawnCoordinates = source.getWorld(0).getSpawnPoint();
+                            source.sendMessage(I18n.getInstance().translateKeyAndFormat("command.commands.spawn.get", spawnCoordinates.x, spawnCoordinates.y, spawnCoordinates.z));
+                            return Command.SINGLE_SUCCESS;
+                        })));
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/SpawnParticleCommand.java b/src/main/java/net/minecraft/core/net/command/commands/SpawnParticleCommand.java
deleted file mode 100644
index 74a1cd079..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/SpawnParticleCommand.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.client.entity.particle.ParticleDispatcher;
-import net.minecraft.core.net.command.ClientCommandHandler;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommandHandler;
-import net.minecraft.core.net.packet.AddParticlePacket;
-
-public class SpawnParticleCommand extends Command {
-    public SpawnParticleCommand() {
-        super("spawnparticle", "particle");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        String particleKey = null;
-        Double x = null;
-        Double y = null;
-        Double z = null;
-        int dimension = 0;
-        if (sender.getPlayer() != null){
-            x = sender.getPlayer().x;
-            y = sender.getPlayer().y;
-            z = sender.getPlayer().z;
-            dimension = sender.getPlayer().dimension;
-        }
-        double motionX = 0;
-        double motionY = 0;
-        double motionZ = 0;
-        int data = 0;
-        Double maxDistance = null;
-        if (args.length >= 1){
-            particleKey = args[0];
-
-            if (particleKey.equalsIgnoreCase("list")){
-                sender.sendMessage("List of particles:");
-                for (String s: ParticleDispatcher.getInstance().getParticleIds())
-                {
-                    sender.sendMessage(" - " + s);
-                }
-                return true;
-            }
-
-            if (args.length >= 4){
-                x = Double.parseDouble(args[1]);
-                y = Double.parseDouble(args[2]);
-                z = Double.parseDouble(args[3]);
-                if (args.length >= 7){
-                    motionX = Double.parseDouble(args[4]);
-                    motionY = Double.parseDouble(args[5]);
-                    motionZ = Double.parseDouble(args[6]);
-                    if (args.length >= 8){
-                        data = Integer.parseInt(args[7]);
-                        if (args.length == 9){
-                            maxDistance = Double.parseDouble(args[8]);
-                        }
-                    }
-                }
-            }
-        }
-        if (particleKey != null && x != null){
-            if (handler instanceof ServerCommandHandler){
-                ((ServerCommandHandler) handler).minecraftServer.playerList.sendPacketToPlayersAroundPoint(x, y, z, maxDistance == null ? 16 : maxDistance, dimension, new AddParticlePacket(particleKey, x, y, z, motionX, motionY, motionZ, data));
-            } else if (handler instanceof ClientCommandHandler){
-                if (maxDistance == null){
-                    ((ClientCommandHandler) handler).minecraft.renderGlobal.addParticle(particleKey, x, y, z, motionX, motionY, motionZ, data);
-                } else {
-                    ((ClientCommandHandler) handler).minecraft.renderGlobal.addParticle(particleKey, x, y, z, motionX, motionY, motionZ, data, maxDistance);
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/spawnparticle list");
-        if (sender.getPlayer() != null){
-            sender.sendMessage("/spawnparticle <ParticleKey>");
-        }
-        sender.sendMessage("/spawnparticle <ParticleKey> <x> <y> <z>");
-        sender.sendMessage("/spawnparticle <ParticleKey> <x> <y> <z> <MotionX> <MotionY> <MotionZ>");
-        sender.sendMessage("/spawnparticle <ParticleKey> <x> <y> <z> <MotionX> <MotionY> <MotionZ> <data>");
-        sender.sendMessage("/spawnparticle <ParticleKey> <x> <y> <z> <MotionX> <MotionY> <MotionZ> <data> <MaxDistance>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/SummonCommand.java b/src/main/java/net/minecraft/core/net/command/commands/SummonCommand.java
index 05aadab7b..21530fc3b 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/SummonCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/SummonCommand.java
@@ -1,109 +1,76 @@
 package net.minecraft.core.net.command.commands;
 
-import java.util.Set;
-
-import com.mojang.logging.LogUtils;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.context.CommandContext;
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.EntityDispatcher;
+import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.World;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.LocationTarget;
-import net.minecraft.core.net.command.PlayerCommandSender;
-import org.jetbrains.annotations.NotNull;
-import org.slf4j.Logger;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntitySummonArgumentType;
+import net.minecraft.core.net.command.arguments.Vec3ArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.DoubleCoordinates;
+
+public class SummonCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("summon")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, Class<? extends Entity>>argument("entity", EntitySummonArgumentType.entity())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            Vec3 coordinates = source.getCoordinates(false);
+                            if (source.getSender() == null || coordinates == null) throw CommandExceptions.notInWorld().create();
+
+                            Entity entity = summonEntityAt(c, coordinates.x, coordinates.y - source.getSender().heightOffset, coordinates.z, 0.0f, 0.0f);
+
+                            source.sendTranslatableMessage("command.commands.summon.success_single_entity", CommandHelper.getEntityName(entity));
+
+                            return Command.SINGLE_SUCCESS;
+                        })
+                        .then(RequiredArgumentBuilder.<CommandSource, DoubleCoordinates>argument("position", Vec3ArgumentType.vec3d())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    DoubleCoordinates coordinates = c.getArgument("position", DoubleCoordinates.class);
+
+                                    Entity entity = summonEntityAt(c, coordinates.getX(source), coordinates.getY(source, true), coordinates.getZ(source), 0.0f, 0.0f);
+
+                                    source.sendTranslatableMessage("command.commands.summon.success_single_entity", CommandHelper.getEntityName(entity));
 
-public class SummonCommand extends Command{
-	private static final Logger LOGGER = LogUtils.getLogger();
-	public SummonCommand() {
-		super("summon");
-	}
+                                    return Command.SINGLE_SUCCESS;
+                                })
+                                .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(1, 255))
+                                        .executes(c -> {
+                                            CommandSource source = c.getSource();
+                                            DoubleCoordinates coordinates = c.getArgument("position", DoubleCoordinates.class);
+                                            int amount = c.getArgument("amount", Integer.class);
 
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 0) return false;
-		
-		if(args[0].equalsIgnoreCase("list")) {
-			StringBuilder builder = new StringBuilder().append(TextFormatting.LIGHT_GRAY).append("Entities: ").append(TextFormatting.WHITE);
-			int i=0;
-			for(String string : EntityDispatcher.keyToClassMap.keySet()) {
-				if(i > 0) {
-					builder.append(", ");
-				}
-				builder.append(string);
-				i++;
-			}
-			sender.sendMessage(builder.toString());
-			return true;
-		}
-		
-		Set<String> keySet = EntityDispatcher.keyToClassMap.keySet();
-		
-		String entityID = args[0];
-		Class<? extends Entity> entityClass = null;
-		
-		for(String str : keySet) {
-			if(str.equalsIgnoreCase(entityID)) {
-				entityID = str;
-				entityClass = EntityDispatcher.keyToClassMap.get(entityID);
-			}
-		}
-		
-		if(entityClass == null) {
-			throw new CommandError("Could not find entity \""+entityID+"\"");
-		}
-		
-		LocationTarget location = new LocationTarget(handler, sender);
-		
-		int count = 1;
-		int offset = 1;
-		
-		if(args.length > 1) {
-			offset += location.parse(args, offset);
-		}
-		
-		if(args.length > offset) {
-			count = Integer.parseInt(args[offset]);
-		}
-		
-		if(handler.isServer()) {
-			count = Math.min(count, handler.asServer().minecraftServer.summonLimit);
-		}
-		
-		for(int i=0; i < count; i++) {
-			Entity entity = createEntity(entityClass, location.getWorld());
-			entity.spawnInit();
-			entity.moveTo(location.getX(), location.getY(), location.getZ(), 0, 0);
-			location.getWorld().entityJoinedWorld(entity);
+                                            for (int i = 0; i < amount; i++) {
+                                                summonEntityAt(c, coordinates.getX(source), coordinates.getY(source, true), coordinates.getZ(source), 0.0f, 0.0f);
+                                            }
 
-		}
-		
-		handler.sendCommandFeedback(sender, "Summoned "+count+" "+entityID+" at "+location);
-		return true;
-	}
-	
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
+                                            source.sendTranslatableMessage("command.commands.summon.success_multiple_entities", amount);
 
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		if(sender instanceof PlayerCommandSender) {
-			sender.sendMessage("/summon <entity> <position> <count>");
-		}
-	}
-	
-	public static Entity createEntity(@NotNull Class<? extends Entity> entityClass, World world) {
-		try {
-			return entityClass.getConstructor(World.class).newInstance(world);
-		}catch (Exception e) {
-            LOGGER.warn("Could not create Entity for class '{}'!", entityClass.getSimpleName());
-			throw new CommandError("Could not create Entity!");
-		}
-	}
+                                            return Command.SINGLE_SUCCESS;
+                                        })))));
+    }
 
+    @SuppressWarnings({"SameParameterValue", "unchecked"})
+    private static Entity summonEntityAt(CommandContext<CommandSource> c, double x, double y, double z, float yaw, float pitch) {
+        Class<? extends Entity> entityClass = c.getArgument("entity", Class.class);
+        Entity entity;
+        try {
+            entity = entityClass.getConstructor(World.class).newInstance(c.getSource().getWorld());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        entity.spawnInit();
+        entity.moveTo(x, y, z, yaw, pitch);
+        c.getSource().getWorld().entityJoinedWorld(entity);
+        return entity;
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/TeleportCommand.java b/src/main/java/net/minecraft/core/net/command/commands/TeleportCommand.java
index 5f6db4c01..c8695b61d 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/TeleportCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/TeleportCommand.java
@@ -1,138 +1,79 @@
 package net.minecraft.core.net.command.commands;
 
-import com.mojang.logging.LogUtils;
-import net.minecraft.core.Global;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.PlayerCommandSender;
-import net.minecraft.core.net.command.ServerCommandHandler;
-import org.slf4j.Logger;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.arguments.Vec3ArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.DoubleCoordinates;
+import net.minecraft.core.net.command.helpers.EntitySelector;
 
-public class TeleportCommand extends Command{
-	private static final Logger LOGGER = LogUtils.getLogger();
-	public TeleportCommand() {
-		super("tp");
-	}
+import java.util.List;
 
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		LOGGER.info("TP Command");
-        LOGGER.info("handler: {}", handler);
-        LOGGER.info("sender: {}", sender);
-		
-		boolean sentByPlayer = sender instanceof PlayerCommandSender;
-		
-		if(args.length > 0) {
-			if(args.length <= 2) {
-				Player from = null;
-				Player to = null;
-				
-				if(args.length == 1) {
-					if(sentByPlayer) {
-						from = sender.getPlayer();
-						to = getPlayer(handler, args[0]);
-					}else {
-						return false;
-					}
-				}
-				if(args.length == 2) {
-					from = getPlayer(handler, args[0]);
-					to = getPlayer(handler, args[1]);
-				}
-				
-				teleport(handler, sender, from, to);
-				return true;
-			}
-			
-			Player player = null;
-			double x = 0.0;
-			double y = 0.0;
-			double z = 0.0;
-			
-			if(args.length == 3 && sentByPlayer) {
-				x = parseDouble(args[0]);
-				y = parseDouble(args[1]);
-				z = parseDouble(args[2]);
-				player = sender.getPlayer();
-			}
-			
-			if(args.length == 4) {
-				player = getPlayer(handler, args[0]);
-				x = parseDouble(args[1]);
-				y = parseDouble(args[2]);
-				z = parseDouble(args[3]);
-			}
-			x = MathHelper.clamp(x, -32000000D, 32000000D);
-			z = MathHelper.clamp(z, -32000000D, 32000000D);
-			teleport(handler, sender, player, null, x, y, z, player.yRot, player.xRot, null);
-			return true;
-		}
-		
-		return false;
-	}
-	
-	public double parseDouble(String str) {
-		try {
-			return Double.parseDouble(str);
-		}catch (Exception e) {
-			throw new CommandError("Not a number: \""+str+"\"");
-		}
-	}
-	
-	public Player getPlayer(CommandHandler handler, String name) {
-		Player player = handler.getPlayer(name);
-		if(player == null) throw new CommandError("Player not found: "+name);
-		return player;
-	}
-	
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		boolean server = handler instanceof ServerCommandHandler;
-		boolean sentByPlayer = sender instanceof PlayerCommandSender;
-		
-		if(server) sender.sendMessage("/tp <FromPlayer> <ToPlayer>");
-		if(sentByPlayer && server) sender.sendMessage("/tp <ToPlayer>");
-		if(server) sender.sendMessage("/tp <Player> <x> <y> <z>");
-		if(sentByPlayer) sender.sendMessage("/tp <x> <y> <z>");
-	}
+public class TeleportCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("teleport")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, DoubleCoordinates>argument("position", Vec3ArgumentType.vec3d())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            DoubleCoordinates targetCoordinates = c.getArgument("position", DoubleCoordinates.class);
 
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-	
-	public static void teleport(CommandHandler handler, CommandSender sender, Player p1, Integer dimension, double x, double y, double z, double yaw, double pitch, Player p2) {
-		if(p1 instanceof ServerPlayer) {
-			
-			ServerPlayer p1MP = (ServerPlayer) p1;
-			if(dimension != null && p1MP.dimension != dimension && handler instanceof ServerCommandHandler) {
-				ServerCommandHandler serverCommandHandler = (ServerCommandHandler) handler;
-				serverCommandHandler.minecraftServer.playerList.sendPlayerToOtherDimension(p1MP, dimension, false);
-			}
-			p1MP.playerNetServerHandler.teleportAndRotate(x, y, z, p1MP.yRot, p1MP.xRot);
-		}else {
-			p1.absMoveTo(x, y, z, p1.yRot, p1.xRot);
-		}
-		
-		if(p2 != null) {
-			handler.sendCommandFeedback(sender, "Teleporting " + p1.getDisplayName() + TextFormatting.WHITE + " to " + p2.getDisplayName());
-		}else {
-			handler.sendCommandFeedback(sender, "Teleporting " + p1.getDisplayName() + TextFormatting.WHITE + " to x: " + floor10(x) + " y: "+floor10(y) + " z: "+floor10(z));
-		}
-	}
-	
-	public static void teleport(CommandHandler handler, CommandSender sender, Player p1, Player p2) {
-		teleport(handler, sender, p1, p2.dimension, p2.x, p2.y, p2.z, p2.yRot, p2.xRot, p2);
-	}
-	
-	public static double floor10(double a) {
-		return ((int)(a * 10)) / 10.0;
-	}
+                            if (source.getSender() != null) {
+                                source.getSender().moveTo(targetCoordinates.getX(source), targetCoordinates.getY(source, true), targetCoordinates.getZ(source), source.getSender().yRot, source.getSender().xRot);
+                                source.sendTranslatableMessage("command.commands.teleport.location.success_single_entity", source.getSender().getDisplayName(), targetCoordinates.getX(source), targetCoordinates.getY(source, true), targetCoordinates.getZ(source));
+                            } else {
+                                throw CommandExceptions.notInWorld().create();
+                            }
 
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("entity", EntityArgumentType.entities())
+                        .then(RequiredArgumentBuilder.<CommandSource, DoubleCoordinates>argument("position", Vec3ArgumentType.vec3d())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    EntitySelector entitySelector = c.getArgument("entity", EntitySelector.class);
+                                    DoubleCoordinates targetCoordinates = c.getArgument("position", DoubleCoordinates.class);
+
+                                    List<? extends Entity> entities = entitySelector.get(source);
+                                    for (Entity entity : entities) {
+                                        entity.moveTo(targetCoordinates.getX(source), targetCoordinates.getY(source, true), targetCoordinates.getZ(source), entity.yRot, entity.xRot);
+                                    }
+
+                                    double x = targetCoordinates.getX(source);
+                                    double y = targetCoordinates.getY(source, true);
+                                    double z = targetCoordinates.getZ(source);
+
+                                    if (entities.size() == 1) source.sendTranslatableMessage("command.commands.teleport.location.success_single_entity", CommandHelper.getEntityName(entities.get(0)), x, y, z);
+                                    else if (entities.size() > 1) source.sendTranslatableMessage("command.commands.teleport.location.success_multiple_entities", entities.size(), x, y, z);
+
+                                    return Command.SINGLE_SUCCESS;
+                                }))
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.entity())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("entity", EntitySelector.class);
+                            EntitySelector targetEntitySelector = c.getArgument("target", EntitySelector.class);
+                            Entity targetEntity = targetEntitySelector.get(c.getSource()).get(0);
+
+                            List<? extends Entity> entities = entitySelector.get(c.getSource());
+                            for (Entity entity : entities) {
+                                entity.moveTo(targetEntity.x, targetEntity.y - targetEntity.heightOffset, targetEntity.z, entity.yRot, entity.xRot);
+                            }
+
+                            if (entities.size() == 1) source.sendTranslatableMessage("command.commands.teleport.entity.success_single_entity", CommandHelper.getEntityName(entities.get(0)), CommandHelper.getEntityName(targetEntity));
+                            else if (entities.size() > 1) source.sendTranslatableMessage("command.commands.teleport.entity.success_multiple_entities", entities.size(), CommandHelper.getEntityName(targetEntity));
+
+                            return Command.SINGLE_SUCCESS;
+                        }))));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("tp")
+                .requires(CommandSource::hasAdmin)
+                .redirect(command));
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/TellRawCommand.java b/src/main/java/net/minecraft/core/net/command/commands/TellRawCommand.java
new file mode 100644
index 000000000..d37e09736
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/TellRawCommand.java
@@ -0,0 +1,36 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+
+import java.util.List;
+
+public class TellRawCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("tellraw")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("targets", EntityArgumentType.players())
+                        .then(RequiredArgumentBuilder.<CommandSource, String>argument("message", StringArgumentType.greedyString())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    EntitySelector entitySelector = c.getArgument("targets", EntitySelector.class);
+                                    String message = c.getArgument("message", String.class);
+
+                                    List<? extends Entity> players = entitySelector.get(source);
+
+                                    for (Entity player : players) {
+                                        source.sendMessage((Player) player, message);
+                                    }
+
+                                    return Command.SINGLE_SUCCESS;
+                                }))));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/TestCommand.java b/src/main/java/net/minecraft/core/net/command/commands/TestCommand.java
new file mode 100644
index 000000000..5c3cf94ec
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/TestCommand.java
@@ -0,0 +1,26 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.AchievementArgumentType;
+
+@SuppressWarnings("unchecked")
+public class TestCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register((LiteralArgumentBuilder)(((LiteralArgumentBuilder)LiteralArgumentBuilder.literal("test"))
+                .then(((LiteralArgumentBuilder)LiteralArgumentBuilder.<CommandSource>literal("grant")
+                ).then(RequiredArgumentBuilder.argument("achievement", AchievementArgumentType.achievement())
+                        .then(RequiredArgumentBuilder.argument("achievement1", AchievementArgumentType.achievement())
+                                .then(RequiredArgumentBuilder.argument("achievement2", AchievementArgumentType.achievement())
+                                        .then(RequiredArgumentBuilder.argument("achievement3", AchievementArgumentType.achievement())
+                                                .then(RequiredArgumentBuilder.argument("achievement4", AchievementArgumentType.achievement())
+                                                        .then(RequiredArgumentBuilder.argument("achievement5", AchievementArgumentType.achievement())
+                                                                .executes(c -> {
+                                                                    ((CommandSource)c.getSource()).getSender().sendMessage("Command run!");
+                                                                    return Command.SINGLE_SUCCESS;
+                                                                }))))))))));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/TestForCommand.java b/src/main/java/net/minecraft/core/net/command/commands/TestForCommand.java
new file mode 100644
index 000000000..ed9e35aca
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/TestForCommand.java
@@ -0,0 +1,87 @@
+package net.minecraft.core.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.BlockArgumentType;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.arguments.IntegerCoordinatesArgumentType;
+import net.minecraft.core.net.command.helpers.*;
+
+import java.util.List;
+
+public class TestForCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("testfor")
+                .requires(CommandSource::hasAdmin)
+                .then(LiteralArgumentBuilder.<CommandSource>literal("entity")
+                        .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("entities", EntityArgumentType.entities())
+                                .executes(c -> {
+                                    List<? extends Entity> entities = c.getArgument("entities", EntitySelector.class).get(c.getSource());
+                                    c.getSource().sendTranslatableMessage("command.commands.testfor.entity." + (entities.isEmpty() ? "none" : entities.size() == 1 ? "single" : "multiple"), entities.size());
+                                    return entities.size();
+                                })))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("block")
+                        .then(RequiredArgumentBuilder.<CommandSource, BlockInput>argument("block", BlockArgumentType.block())
+                                .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("second", IntegerCoordinatesArgumentType.intCoordinates())
+                                        .executes(c -> {
+                                            BlockInput block = c.getArgument("block", BlockInput.class);
+                                            IntegerCoordinates secondPos = c.getArgument("second", IntegerCoordinates.class);
+                                            CompoundTag blockInWorldCompoundTag = new CompoundTag();
+                                            BlockEntity blockEntity = c.getSource().getWorld().getBlockEntity(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
+                                            if (blockEntity != null) blockEntity.writeToNBT(blockInWorldCompoundTag);
+                                            if (c.getSource().getWorld().getBlock(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource())) == block.getBlock()
+                                            && c.getSource().getWorld().getBlockMetadata(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource())) == block.getMetadata()
+                                            && (blockInWorldCompoundTag == block.getTag() || block.getTag().getValues().isEmpty())) {
+                                                c.getSource().sendTranslatableMessage("command.commands.testfor.block.success");
+                                                return Command.SINGLE_SUCCESS;
+                                            }
+                                            c.getSource().sendTranslatableMessage("command.commands.testfor.block.failure");
+                                            return 0;
+                                        })))
+                        .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("first", IntegerCoordinatesArgumentType.intCoordinates())
+                                .then(RequiredArgumentBuilder.<CommandSource, IntegerCoordinates>argument("second", IntegerCoordinatesArgumentType.intCoordinates())
+                                        .executes(c -> {
+                                            IntegerCoordinates firstPos = c.getArgument("first", IntegerCoordinates.class);
+                                            IntegerCoordinates secondPos = c.getArgument("second", IntegerCoordinates.class);
+
+                                            Block firstBlock = c.getSource().getWorld().getBlock(firstPos.getX(c.getSource()), firstPos.getY(c.getSource(), true), firstPos.getZ(c.getSource()));
+                                            Block secondBlock = c.getSource().getWorld().getBlock(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
+
+                                            if (firstBlock != secondBlock) {
+                                                c.getSource().sendTranslatableMessage("command.commands.testfor.block.failure");
+                                                return 0;
+                                            }
+
+                                            int firstMetadata = c.getSource().getWorld().getBlockMetadata(firstPos.getX(c.getSource()), firstPos.getY(c.getSource(), true), firstPos.getZ(c.getSource()));
+                                            int secondMetadata = c.getSource().getWorld().getBlockMetadata(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
+
+                                            if (firstMetadata != secondMetadata) {
+                                                c.getSource().sendTranslatableMessage("command.commands.testfor.block.failure");
+                                                return 0;
+                                            }
+
+                                            CompoundTag firstTag = new CompoundTag();
+                                            BlockEntity firstBlockEntity = c.getSource().getWorld().getBlockEntity(firstPos.getX(c.getSource()), firstPos.getY(c.getSource(), true), firstPos.getZ(c.getSource()));
+                                            if (firstBlockEntity != null) firstBlockEntity.writeToNBT(firstTag);
+                                            CompoundTag secondTag = new CompoundTag();
+                                            BlockEntity secondBlockEntity = c.getSource().getWorld().getBlockEntity(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
+                                            if (secondBlockEntity != null) secondBlockEntity.writeToNBT(secondTag);
+
+                                            if (!CommandHelper.blockEntitiesAreEqual(firstTag, secondTag)) {
+                                                c.getSource().sendTranslatableMessage("command.commands.testfor.block.failure");
+                                                return 0;
+                                            }
+
+                                            c.getSource().sendTranslatableMessage("command.commands.testfor.block.success");
+                                            return Command.SINGLE_SUCCESS;
+                                        })))));
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/commands/TimeCommand.java b/src/main/java/net/minecraft/core/net/command/commands/TimeCommand.java
index 340e8deb7..4a02e4725 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/TimeCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/TimeCommand.java
@@ -1,201 +1,95 @@
 package net.minecraft.core.net.command.commands;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import net.minecraft.core.Global;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
 import net.minecraft.core.world.LevelListener;
-import net.minecraft.core.world.season.Season;
 import net.minecraft.core.world.World;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.PlayerCommandSender;
-import net.minecraft.core.net.command.ServerCommandHandler;
-import net.minecraft.core.world.season.SeasonManager;
-import net.minecraft.core.world.season.SeasonManagerCycle;
-import net.minecraft.core.world.season.Seasons;
-
-public class TimeCommand extends Command {
-
-	public TimeCommand() {
-		super("time");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if (args.length == 0)
-			return false;
-
-		World world = null;
-
-		if (sender instanceof PlayerCommandSender) {
-			world = sender.getPlayer().world;
-		}
-		if (handler instanceof ServerCommandHandler) {
-			ServerCommandHandler server = (ServerCommandHandler) handler;
-
-			if (args[0].equalsIgnoreCase("get") && args.length > 1)
-				world = server.minecraftServer.getDimensionWorld(Integer.parseInt(args[1]));
-			if ((args[0].equalsIgnoreCase("set") || args[0].equalsIgnoreCase("add")) && args.length > 2)
-				world = server.minecraftServer.getDimensionWorld(Integer.parseInt(args[2]));
-		}
-		if (world == null) {
-			throw new CommandError("Must be used by a player, or a dimension must be defined.");
-		}
-
-		if (args[0].equalsIgnoreCase("get")) {
-			sender.sendMessage("The time in dimension " + world.dimension.id + " is " + world.getWorldTime());
-			return true;
-		}
-		if (args[0].equalsIgnoreCase("set")) {
-			String timeStr = args[1];
-			long time = parseTime(timeStr, world);
-			if (time < 0) time = 0;
-			world.setWorldTime(time);
-			handler.sendCommandFeedback(sender, "Set the time to " + time + " in dimension " + world.dimension.id);
-
-			for (LevelListener listener : world.listeners)
-			{
-				listener.allChanged(true, true);
-			}
-
-			return true;
-		}
-		if (args[0].equalsIgnoreCase("add")) {
-			String timeStr = args[1];
-			long time = Long.parseLong(timeStr);
-			world.setWorldTime(world.getWorldTime() + time);
-			handler.sendCommandFeedback(sender, "Set the time to " + world.getWorldTime() + " in dimension " + world.dimension.id);
-
-			for (LevelListener listener : world.listeners)
-			{
-				listener.allChanged(true, true);
-			}
-
-			return true;
-		}
-		return false;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/time get [dimension]");
-		sender.sendMessage("/time set <time> [dimension]");
-		sender.sendMessage("/time add <time> [dimension]");
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	public static long parseTime(String timeString, World world) {
-		int daylength = Global.DAY_LENGTH_TICKS;
-		long time = (world.getWorldTime() / daylength) * daylength; //Start of day
-
-		if(isNumber(timeString)) {
-			return Long.parseLong(timeString);
-		}
-
-		// Parse Day
-		if (timeString.startsWith("day")) {
-			timeString = timeString.substring(3);
-			if(isNumber(timeString)) {
-				return Long.parseLong(timeString) * Global.DAY_LENGTH_TICKS;
-			}
-		}
-
-		SeasonManager seasonManager = world.getSeasonManager();
-		if (seasonManager instanceof SeasonManagerCycle)
-		{
-			SeasonManagerCycle cycleManager = (SeasonManagerCycle) seasonManager;
-			//Parse Season
-			Entry<String, Season> seasonEntry = getEntryStartsWithIgnoreCase(seasonStrings, timeString);
-			if(seasonEntry != null) {
-				timeString = timeString.substring(seasonEntry.getKey().length());
-
-				int yearLength = 0;
-				Integer seasonStart = null;
-
-				List<Season> seasons = world.getSeasonManager().getSeasons();
-				for(Season season : seasons) {
-					if(season == seasonEntry.getValue()) seasonStart = yearLength;
-					yearLength += cycleManager.getConfig().getSeasonLength(season) * Global.DAY_LENGTH_TICKS;
-				}
-				if(seasonStart == null) throw new CommandError("Invalid Season "+seasonEntry.getValue().getTranslatedName()+" for dimension "+world.dimension.getTranslatedName());
-
-				time = (time / yearLength) * yearLength; //Start of year
-				time += seasonStart;
-
-				if(isNumber(timeString)) {
-					int i = Integer.parseInt(timeString);
-
-					int seasonDays = cycleManager.getConfig().getSeasonLength(seasonEntry.getValue());
-					if(i >= seasonDays) throw new CommandError("Season "+seasonEntry.getValue().getTranslatedName()+" only has "+seasonDays+" days!");
-
-					time += (long) i * daylength;
-				}
-			}
-		}
-
-		//Parse Daytime
-		Entry<String, Integer> dayTimeEntry = getEntryStartsWithIgnoreCase(dayTimeStrings, timeString);
-		if(dayTimeEntry != null) {
-			timeString = timeString.substring(dayTimeEntry.getKey().length());
-			time += dayTimeEntry.getValue();
-		}
-
-		return time;
-	}
-
-	public static boolean startsWithIgnoreCase(String a, String b) {
-		if (a.length() < b.length())
-			return false;
-		return a.substring(0, b.length()).equalsIgnoreCase(b);
-	}
-
-	public static boolean isNumber(String s) {
-		if(s == null || s.length() < 1) return false;
-		for(int i=0; i < s.length(); i++) {
-			if(!isNumber(s.charAt(i))) return false;
-		} return true;
-	}
-
-	public static boolean isNumber(char c) {
-		return c >= '0' && c <= '9';
-	}
-
-	public static <E> Entry<String, E> getEntryStartsWithIgnoreCase(Map<String, E> map, String str) {
-		for(Entry<String, E> entry : map.entrySet()) {
-			if(startsWithIgnoreCase(str, entry.getKey())) return entry;
-		} return null;
-	}
-
-	public static Map<String, Integer> dayTimeStrings = new HashMap<>();
-
-	static {
-		dayTimeStrings.put("sunrise", 0);
-		dayTimeStrings.put("day", 1000);
-		dayTimeStrings.put("noon", 6000);
-		dayTimeStrings.put("evening", 12000);
-		dayTimeStrings.put("dusk", 12000);
-		dayTimeStrings.put("sunset", 12000);
-		dayTimeStrings.put("night", 15000);
-		dayTimeStrings.put("midnight", 18000);
-	}
-
-	public static Map<String, Season> seasonStrings = new HashMap<>();
-
-	static {
-		seasonStrings.put("spring", Seasons.OVERWORLD_SPRING);
-		seasonStrings.put("summer", Seasons.OVERWORLD_SUMMER);
-		seasonStrings.put("autumn", Seasons.OVERWORLD_FALL);
-		seasonStrings.put("fall", Seasons.OVERWORLD_FALL);
-		seasonStrings.put("winter", Seasons.OVERWORLD_WINTER);
-	}
-
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.TimeArgumentType;
+
+public class TimeCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("time")
+                .requires(CommandSource::hasAdmin)
+                .then(LiteralArgumentBuilder.<CommandSource>literal("query")
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("daytime")
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    source.sendTranslatableMessage("command.commands.time.query", c.getSource().getWorld().getWorldTime() % 24000L);
+
+                                    return Command.SINGLE_SUCCESS;
+                                }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("gametime")
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    source.sendTranslatableMessage("command.commands.time.query", source.getWorld().getWorldTime() % Integer.MAX_VALUE);
+
+                                    return Command.SINGLE_SUCCESS;
+                                }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("day")
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    source.sendTranslatableMessage("command.commands.time.query", source.getWorld().getWorldTime() / 24000L % Integer.MAX_VALUE);
+
+                                    return Command.SINGLE_SUCCESS;
+                                })))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("set")
+                        .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("time", TimeArgumentType.time())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    int time = c.getArgument("time", Integer.class);
+                                    setWorldTime(source, source.getWorld(), time);
+                                    return Command.SINGLE_SUCCESS;
+                                }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("day")
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    setDayTime(source, source.getWorld(), 1000);
+                                    return Command.SINGLE_SUCCESS;
+                                }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("noon")
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    setDayTime(source, source.getWorld(), 6000);
+                                    return Command.SINGLE_SUCCESS;
+                                }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("night")
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    setDayTime(source, source.getWorld(), 13000);
+                                    return Command.SINGLE_SUCCESS;
+                                }))
+                        .then(LiteralArgumentBuilder.<CommandSource>literal("midnight")
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    setDayTime(source, source.getWorld(), 18000);
+                                    return Command.SINGLE_SUCCESS;
+                                })))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("add")
+                        .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("time", TimeArgumentType.time())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    int time = c.getArgument("time", Integer.class);
+                                    addWorldTime(source, source.getWorld(), time);
+                                    return Command.SINGLE_SUCCESS;
+                                }))));
+    }
+
+    private static void setDayTime(CommandSource source, World world, long time) {
+        setWorldTime(source, world, world.getWorldTime() - (world.getWorldTime() % 24000L) + time);
+    }
+
+    private static void setWorldTime(CommandSource source, World world, long time) {
+        world.setWorldTime(time);
+        for (LevelListener listener : world.listeners) {
+            listener.allChanged(true, true);
+        }
+        source.sendTranslatableMessage("command.commands.time.set", time);
+    }
+
+    private static void addWorldTime(CommandSource source, World world, long time) {
+        setWorldTime(source, world, world.getWorldTime() + time);
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/WeatherCommand.java b/src/main/java/net/minecraft/core/net/command/commands/WeatherCommand.java
index 33acbc9fa..863ed6fc4 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/WeatherCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/WeatherCommand.java
@@ -1,112 +1,53 @@
 package net.minecraft.core.net.command.commands;
 
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.TextFormatting;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.FloatArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.CommandNode;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.weather.Weather;
-import net.minecraft.core.world.weather.Weathers;
-
-public class WeatherCommand extends Command{
-
-	public WeatherCommand() {
-		super("weather", "w");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 0) {
-			return false;
-		}
-		
-		if(args[0].equals("list")) {
-			StringBuilder weatherString = new StringBuilder();
-			
-			weatherString.append(TextFormatting.LIGHT_GRAY + "Available weathers: " + TextFormatting.WHITE);
-			weatherString.append("clear");
-			
-			for(Weather weather : Weathers.WEATHERS) {
-				if(weather != null) {
-					weatherString.append(", ");
-					weatherString.append(weather.languageKey.substring(8));
-				}
-			}
-			
-			sender.sendMessage(weatherString.toString());
-			
-			return true;
-		}
-		
-		World world = sender.getWorld();
-		if(args[0].equals("next")) {
-			world.weatherManager.skip();
-			handler.sendCommandFeedback(sender, "Skipping to next weather");
-			return true;
-		}
-		
-		int offset = 0;
-		if(args[0].equals("set")) {
-			offset = 1;
-		}
-		
-		String weatherId = args[offset];
-		Weather weather = getWeather(weatherId, world);
-		if(weather == null) {
-			throw new CommandError("Weather \"" + weatherId + "\" doesn't exist!");
-		}
-		
-		Long duration = null;
-		if(args.length > offset + 1) {
-			duration = Long.parseLong(args[offset + 1]) * 20;
-		}
-		
-		Float power = null;
-		if(args.length > offset + 2) {
-			power = Float.parseFloat(args[offset + 2]);
-		}
-
-		if(duration != null && power != null) {
-			world.weatherManager.overrideWeather(weather, duration, power);
-		}else if(duration != null) {
-			world.weatherManager.overrideWeather(weather, duration);
-		}else {
-			world.weatherManager.overrideWeather(weather);
-		}
-		
-		handler.sendCommandFeedback(sender, TextFormatting.LIGHT_GRAY + "Changing weather to " + TextFormatting.WHITE + weather.getLanguageKey().substring(8));
-		
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/weather list");
-		sender.sendMessage("/weather next");
-		sender.sendMessage("/weather set <weather> [duration (sec)] [power (0.0-1.0)]");
-		sender.sendMessage("/weather <weather> [duration (sec)] [power (0.0-1.0)]");
-	}
-	
-	public static Weather getWeather(String string, World world) {
-		try {
-			return Weathers.getWeather(Integer.parseInt(string));
-		}catch (NumberFormatException e) {}
-
-		if(string.equalsIgnoreCase("clear")) {
-			Weather weather = world.worldType.getDefaultWeather();
-			if(weather == null) {
-				throw new CommandError("Dimension " + world.dimension.getTranslatedName() + " does not have a default weather!");
-			}
-			return weather;
-		}
-		
-		return Weathers.getWeatherByLanguageKey(string);
-	}
-
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.TimeArgumentType;
+import net.minecraft.core.net.command.arguments.WeatherArgumentType;
+
+public class WeatherCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("weather")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, Weather>argument("weather", WeatherArgumentType.weather())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            World world = source.getWorld();
+                            Weather weather = c.getArgument("weather", Weather.class);
+
+                            world.weatherManager.overrideWeather(weather);
+                            source.sendTranslatableMessage("command.commands.weather.success", weather.getTranslatedName());
+                            return Command.SINGLE_SUCCESS;
+                        })
+                        .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("duration", TimeArgumentType.time())
+                                .executes(c -> {
+                                    CommandSource source = c.getSource();
+                                    World world = source.getWorld();
+                                    Weather weather = c.getArgument("weather", Weather.class);
+
+                                    world.weatherManager.overrideWeather(weather, c.getArgument("duration", Integer.class));
+                                    source.sendTranslatableMessage("command.commands.weather.success", weather.getTranslatedName());
+                                    return Command.SINGLE_SUCCESS;
+                                })
+                                .then(RequiredArgumentBuilder.<CommandSource, Float>argument("power", FloatArgumentType.floatArg())
+                                        .executes(c -> {
+                                            CommandSource source = c.getSource();
+                                            World world = source.getWorld();
+                                            Weather weather = c.getArgument("weather", Weather.class);
+
+                                            world.weatherManager.overrideWeather(weather, c.getArgument("duration", Integer.class), c.getArgument("power", Float.class));
+                                            source.sendTranslatableMessage("command.commands.weather.success", weather.getTranslatedName());
+                                            return Command.SINGLE_SUCCESS;
+                                        })))));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("w")
+                .requires(CommandSource::hasAdmin)
+                .redirect(command));
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/WhisperCommand.java b/src/main/java/net/minecraft/core/net/command/commands/WhisperCommand.java
deleted file mode 100644
index eb6a16c54..000000000
--- a/src/main/java/net/minecraft/core/net/command/commands/WhisperCommand.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package net.minecraft.core.net.command.commands;
-
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-
-public class WhisperCommand extends Command{
-	
-	public WhisperCommand() {
-		super("tell", "msg", "whisper");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length < 2) {
-			return false;
-		}
-		Player player = handler.getPlayer(args[0]);
-		
-		StringBuilder builder = new StringBuilder();
-		
-		for(int i=1; i < args.length; i++) {
-			builder.append(args[i] + " ");
-		}
-		
-		String msg = builder.toString();
-		msg = sender.getName() + TextFormatting.GRAY + " >> " + player.getDisplayName() + TextFormatting.GRAY + ": " + TextFormatting.LIGHT_GRAY + msg;
-		sender.sendMessage(msg);
-		
-		if(sender.getPlayer() != player) {
-			handler.sendMessageToPlayer(player, msg);
-		}
-		
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return false;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/msg <username> <message>");
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/exceptions/CommandExceptions.java b/src/main/java/net/minecraft/core/net/command/exceptions/CommandExceptions.java
new file mode 100644
index 000000000..6bd498c07
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/exceptions/CommandExceptions.java
@@ -0,0 +1,73 @@
+package net.minecraft.core.net.command.exceptions;
+
+import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.lang.I18n;
+
+public class CommandExceptions {
+    private static final SimpleCommandExceptionType INCOMPLETE_ARGUMENT = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.exceptions.incomplete"));
+    private static final SimpleCommandExceptionType NOT_IN_WORLD = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.exceptions.not_in_world"));
+    private static final SimpleCommandExceptionType EMPTY_SELECTOR = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.invalid_selector.empty"));
+    private static final SimpleCommandExceptionType INVALID_SELECTOR = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.invalid_selector.generic"));
+    private static final SimpleCommandExceptionType SINGLE_ENTITY_ONLY = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.invalid_selector.single_entity_only"));
+    private static final SimpleCommandExceptionType SINGLE_PLAYER_ONLY = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.invalid_selector.single_player_only"));
+    private static final SimpleCommandExceptionType PLAYER_ONLY = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.invalid_selector.player_only"));
+    private static final SimpleCommandExceptionType SINGLE_PLAYER_WORLD_ONLY = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.exceptions.single_player_world_only"));
+    private static final SimpleCommandExceptionType MULTIPLAYER_WORLD_ONLY = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.exceptions.multiplayer_world_only"));
+    private static final SimpleCommandExceptionType VOLUME_TOO_LARGE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.exceptions.volume_too_large"));
+    private static final SimpleCommandExceptionType EXPECTED_END_OF_METADATA = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKeyAndFormat("command.exceptions.metadata.unterminated"));
+    private static final SimpleCommandExceptionType EXPECTED_END_OF_TAG = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKeyAndFormat("command.exceptions.tag.unterminated"));
+    private static final DynamicCommandExceptionType EXPECTED_TAG_KEY_VALUE = new DynamicCommandExceptionType((value) -> () -> I18n.getInstance().translateKeyAndFormat("command.exceptions.tag.valueless", value));
+
+    public static SimpleCommandExceptionType incomplete() {
+        return INCOMPLETE_ARGUMENT;
+    }
+
+    public static SimpleCommandExceptionType notInWorld() {
+        return NOT_IN_WORLD;
+    }
+
+    public static SimpleCommandExceptionType emptySelector() {
+        return EMPTY_SELECTOR;
+    }
+
+    public static SimpleCommandExceptionType invalidSelector() {
+        return INVALID_SELECTOR;
+    }
+
+    public static SimpleCommandExceptionType singleEntityOnly() {
+        return SINGLE_ENTITY_ONLY;
+    }
+
+    public static SimpleCommandExceptionType singlePlayerOnly() {
+        return SINGLE_PLAYER_ONLY;
+    }
+
+    public static SimpleCommandExceptionType playerOnly() {
+        return PLAYER_ONLY;
+    }
+
+    public static SimpleCommandExceptionType singlePlayerWorldOnly() {
+        return SINGLE_PLAYER_WORLD_ONLY;
+    }
+
+    public static SimpleCommandExceptionType multiplayerWorldOnly() {
+        return MULTIPLAYER_WORLD_ONLY;
+    }
+
+    public static SimpleCommandExceptionType volumeTooLarge() {
+        return VOLUME_TOO_LARGE;
+    }
+
+    public static SimpleCommandExceptionType expectedEndOfTag() {
+        return EXPECTED_END_OF_TAG;
+    }
+
+    public static SimpleCommandExceptionType expectedEndOfMetadata() {
+        return EXPECTED_END_OF_METADATA;
+    }
+
+    public static DynamicCommandExceptionType expectedTagKeyValue() {
+        return EXPECTED_TAG_KEY_VALUE;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/ArgumentParser.java b/src/main/java/net/minecraft/core/net/command/helpers/ArgumentParser.java
new file mode 100644
index 000000000..3ea6759d9
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/ArgumentParser.java
@@ -0,0 +1,71 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.util.NbtHelper;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+public abstract class ArgumentParser {
+    protected StringReader reader;
+    protected int startPosition = 0;
+    protected BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> suggestions = CommandHelper.NO_SUGGESTIONS;
+
+    protected ArgumentParser(StringReader reader) {
+        this.reader = reader;
+    }
+
+    public CompletableFuture<Suggestions> fillSuggestions(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        return this.suggestions.apply(suggestionsBuilder.createOffset(this.reader.getCursor()), consumer);
+    }
+
+    protected int parseMetadata() throws CommandSyntaxException {
+        this.suggestions = CommandHelper.NO_SUGGESTIONS;
+        this.reader.skip();
+        this.reader.skipWhitespace();
+        int cursor = this.reader.getCursor();
+        int metadata = this.reader.readInt();
+        if (metadata < 0) {
+            this.reader.setCursor(cursor);
+            throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.integerTooLow().createWithContext(this.reader, metadata, 0);
+        }
+        this.reader.skipWhitespace();
+        this.suggestions = this::suggestCloseMetadata;
+        if (this.reader.canRead() && this.reader.peek() == ']') {
+            this.suggestions = this::suggestOpenTag;
+            this.reader.skip();
+            return metadata;
+        } else {
+            throw CommandExceptions.expectedEndOfMetadata().createWithContext(this.reader);
+        }
+    }
+
+    protected CompoundTag parseCompound() throws CommandSyntaxException {
+        return NbtHelper.parseNbt(this.reader);
+    }
+
+    protected CompletableFuture<Suggestions> suggestOpenMetadataOrTag(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        if (!this.reader.canRead()) {
+            suggestionsBuilder.suggest(String.valueOf('['));
+            suggestionsBuilder.suggest(String.valueOf('{'));
+        }
+        return suggestionsBuilder.buildFuture();
+    }
+
+    protected CompletableFuture<Suggestions> suggestOpenTag(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        if (!this.reader.canRead()) suggestionsBuilder.suggest(String.valueOf('{'));
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestCloseMetadata(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        if (!this.reader.canRead()) suggestionsBuilder.suggest(String.valueOf(']'));
+        return suggestionsBuilder.buildFuture();
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/BlockArgumentParser.java b/src/main/java/net/minecraft/core/net/command/helpers/BlockArgumentParser.java
new file mode 100644
index 000000000..abba3832b
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/BlockArgumentParser.java
@@ -0,0 +1,71 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+public class BlockArgumentParser extends ArgumentParser {
+    private static final SimpleCommandExceptionType INVALID_BLOCK = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.block.invalid_block"));
+
+    private Block block;
+    private int metadata = 0;
+    private CompoundTag tag = new CompoundTag();
+
+    public BlockArgumentParser(StringReader reader) {
+        super(reader);
+    }
+
+    private CompletableFuture<Suggestions> suggestBlocks(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        SuggestionsBuilder suggestionsBuilder2 = suggestionsBuilder.createOffset(this.startPosition);
+        consumer.accept(suggestionsBuilder2);
+        return suggestionsBuilder.add(suggestionsBuilder2).buildFuture();
+    }
+
+    public BlockInput parse() throws CommandSyntaxException {
+        this.startPosition = this.reader.getCursor();
+
+        this.suggestions = this::suggestBlocks;
+        this.parseBlock();
+
+        this.suggestions = this::suggestOpenMetadataOrTag;
+        if (this.reader.canRead() && this.reader.peek() == '[') {
+            this.metadata = this.parseMetadata();
+        }
+
+        if (this.reader.canRead() && this.reader.peek() == '{') {
+            this.reader.skip();
+            this.suggestions = CommandHelper.NO_SUGGESTIONS;
+            this.tag = this.parseCompound();
+        }
+
+        return new BlockInput(this.block, this.metadata, this.tag);
+    }
+
+    private void parseBlock() throws CommandSyntaxException {
+        String string = this.reader.readString();
+        boolean isAir = false;
+        for (Block blockInList : Block.blocksList) {
+            if (blockInList == null) continue;
+            if (CommandHelper.matchesKeyString(blockInList.getKey(), string)) {
+                this.block = blockInList;
+            } else if (CommandHelper.matchesKeyString("tile.air", string)) {
+                this.block = null;
+                isAir = true;
+            }
+        }
+        if (this.block == null && !isAir) throw INVALID_BLOCK.createWithContext(this.reader);
+    }
+
+    public CompletableFuture<Suggestions> fillSuggestions(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        return this.suggestions.apply(suggestionsBuilder.createOffset(this.reader.getCursor()), consumer);
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/BlockInput.java b/src/main/java/net/minecraft/core/net/command/helpers/BlockInput.java
new file mode 100644
index 000000000..f1ef4e5ec
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/BlockInput.java
@@ -0,0 +1,34 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.block.Block;
+import org.jetbrains.annotations.Nullable;
+
+public class BlockInput {
+    @Nullable
+    private final Block block;
+    private final int metadata;
+    private final CompoundTag tag;
+
+    public BlockInput(@Nullable Block block, int metadata, CompoundTag tag) {
+        this.block = block;
+        this.metadata = metadata;
+        this.tag = tag;
+    }
+
+    public @Nullable Block getBlock() {
+        return this.block;
+    }
+
+    public int getBlockId() {
+        return this.block == null ? 0 : this.block.id;
+    }
+
+    public int getMetadata() {
+        return this.metadata;
+    }
+
+    public CompoundTag getTag() {
+        return this.tag;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/ClonedBlock.java b/src/main/java/net/minecraft/core/net/command/helpers/ClonedBlock.java
new file mode 100644
index 000000000..969189c34
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/ClonedBlock.java
@@ -0,0 +1,35 @@
+package net.minecraft.core.net.command.helpers;
+
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.BlockEntity;
+import org.jetbrains.annotations.Nullable;
+
+public class ClonedBlock {
+    @Nullable
+    private final Block block;
+    private final int metadata;
+    @Nullable
+    private final BlockEntity blockEntity;
+
+    public ClonedBlock(@Nullable Block block, int metadata, @Nullable BlockEntity blockEntity) {
+        this.block = block;
+        this.metadata = metadata;
+        this.blockEntity = blockEntity;
+    }
+
+    public @Nullable Block getBlock() {
+        return this.block;
+    }
+
+    public int getBlockId() {
+        return this.block == null ? 0 : this.block.id;
+    }
+
+    public int getMetadata() {
+        return this.metadata;
+    }
+
+    public BlockEntity getBlockEntity() {
+        return this.blockEntity;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/Coordinates2D.java b/src/main/java/net/minecraft/core/net/command/helpers/Coordinates2D.java
new file mode 100644
index 000000000..f435adaea
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/Coordinates2D.java
@@ -0,0 +1,66 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import org.jetbrains.annotations.Nullable;
+
+public class Coordinates2D {
+    private final IntegerCoordinate x;
+    private final IntegerCoordinate z;
+
+    public Coordinates2D(IntegerCoordinate x, IntegerCoordinate z) {
+        this.x = x;
+        this.z = z;
+    }
+
+    public Coordinates2D(int x, int z) {
+        this(new IntegerCoordinate(false, x), new IntegerCoordinate(false, z));
+    }
+
+    public int getX(@Nullable Integer sourceX) throws CommandSyntaxException {
+        return this.x.get(sourceX == null ? null : MathHelper.floor((double)sourceX / 16.0));
+    }
+
+    public int getZ(@Nullable Integer sourceZ) throws CommandSyntaxException {
+        return this.z.get(sourceZ == null ? null : MathHelper.floor((double)sourceZ / 16.0));
+    }
+
+    public int getX(@Nullable Double sourceX) throws CommandSyntaxException {
+        return this.x.get(sourceX == null ? null : MathHelper.floor(sourceX / 16.0));
+    }
+
+    public int getZ(@Nullable Double sourceZ) throws CommandSyntaxException {
+        return this.z.get(sourceZ == null ? null : MathHelper.floor(sourceZ / 16.0));
+    }
+
+    public int getX(CommandSource source) throws CommandSyntaxException {
+        Vec3 sourceCoordinates = source.getCoordinates(true);
+        if (sourceCoordinates == null) {
+            if (!this.x.isRelative()) {
+                return this.x.get(0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.x.get(MathHelper.floor(sourceCoordinates.x / 16.0));
+    }
+
+    public int getZ(CommandSource source) throws CommandSyntaxException {
+        Vec3 sourceCoordinates = source.getCoordinates(true);
+        if (sourceCoordinates == null) {
+            if (!this.z.isRelative()) {
+                return this.z.get(0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.z.get(MathHelper.floor(sourceCoordinates.z / 16.0));
+    }
+
+    public boolean hasRelativeCoordinate() {
+        return this.x.isRelative() || this.z.isRelative();
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/DoubleCoordinate.java b/src/main/java/net/minecraft/core/net/command/helpers/DoubleCoordinate.java
new file mode 100644
index 000000000..d5559c6cd
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/DoubleCoordinate.java
@@ -0,0 +1,50 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+
+public class DoubleCoordinate {
+    private final boolean isRelative;
+    private final double coordinate;
+
+    public DoubleCoordinate(boolean isRelative, double coordinate) {
+        this.isRelative = isRelative;
+        this.coordinate = coordinate;
+    }
+
+    public double get(Double sourceCoordinate) throws CommandSyntaxException {
+        if (this.isRelative) {
+            if (sourceCoordinate != null) {
+                return sourceCoordinate + this.coordinate;
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+
+        return this.coordinate;
+    }
+
+    public static DoubleCoordinate parse(StringReader reader) throws CommandSyntaxException {
+        if (!reader.canRead()) throw CommandExceptions.incomplete().createWithContext(reader);
+
+        if (reader.peek() == '~') {
+            reader.skip();
+            if (reader.canRead() && reader.peek() != ' ') {
+                double coordinate = reader.readDouble();
+                return new DoubleCoordinate(true, coordinate);
+            } else {
+                return new DoubleCoordinate(true, 0.0);
+            }
+        } else if (reader.peek() != ' ') {
+            double coordinate = reader.readDouble();
+            return new DoubleCoordinate(false, coordinate);
+        }
+
+        throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.readerExpectedDouble().createWithContext(reader);
+    }
+
+    public boolean isRelative() {
+        return this.isRelative;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/DoubleCoordinates.java b/src/main/java/net/minecraft/core/net/command/helpers/DoubleCoordinates.java
new file mode 100644
index 000000000..3e7ef40a5
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/DoubleCoordinates.java
@@ -0,0 +1,66 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+
+public class DoubleCoordinates {
+    private final DoubleCoordinate x;
+    private final DoubleCoordinate y;
+    private final DoubleCoordinate z;
+
+    public DoubleCoordinates(DoubleCoordinate x, DoubleCoordinate y, DoubleCoordinate z) {
+        this.x = x;
+        this.y = y;
+        this.z = z;
+    }
+
+    public double getX(double sourceX) throws CommandSyntaxException {
+        return this.x.get(sourceX);
+    }
+
+    public double getY(double sourceY) throws CommandSyntaxException {
+        return this.y.get(sourceY);
+    }
+
+    public double getZ(double sourceZ) throws CommandSyntaxException {
+        return this.z.get(sourceZ);
+    }
+
+    public double getX(CommandSource source) throws CommandSyntaxException {
+        if (source.getCoordinates(false) == null) {
+            if (!this.x.isRelative()) {
+                return this.x.get(0.0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.x.get(source.getCoordinates(false).x);
+    }
+
+    public double getY(CommandSource source, boolean offsetHeight) throws CommandSyntaxException {
+        if (source.getCoordinates(offsetHeight) == null) {
+            if (!this.y.isRelative()) {
+                return this.y.get(0.0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.y.get(source.getCoordinates(offsetHeight).y);
+    }
+
+    public double getZ(CommandSource source) throws CommandSyntaxException {
+        if (source.getCoordinates(false) == null) {
+            if (!this.z.isRelative()) {
+                return this.z.get(0.0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.z.get(source.getCoordinates(false).z);
+    }
+
+    public boolean hasRelativeCoordinates() {
+        return this.x.isRelative() || this.y.isRelative() || this.z.isRelative();
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/EntitySelector.java b/src/main/java/net/minecraft/core/net/command/helpers/EntitySelector.java
new file mode 100644
index 000000000..f8d01420f
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/EntitySelector.java
@@ -0,0 +1,148 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.util.phys.Vec3;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class EntitySelector {
+    public static final String ENTITY_PREFIX = "entity.";
+
+    private final int maxResults;
+    private final boolean includesEntities;
+    private final BiConsumer<Entity, List<? extends Entity>> order;
+    private final @Nullable Class<? extends Entity> limitToType;
+    private final boolean typeInverse;
+    private final boolean currentEntity;
+    private final Predicate<Entity> predicate;
+    private final @Nullable String entityId;
+    private final @Nullable String playerName;
+    private final MinMaxBounds.Doubles distance;
+    private final Function<Vec3, Vec3> position;
+    private final @Nullable AABB aABB;
+
+    public EntitySelector(int maxResults, boolean includesEntities, BiConsumer<Entity, List<? extends Entity>> order, @Nullable Class<? extends Entity> limitToType, boolean typeInverse, boolean currentEntity, Predicate<Entity> predicate, @Nullable String entityId, @Nullable String playerName, MinMaxBounds.Doubles distance, Function<Vec3, Vec3> position, @Nullable AABB aABB) {
+        this.maxResults = maxResults;
+        this.includesEntities = includesEntities;
+        this.order = order;
+        this.limitToType = limitToType;
+        this.typeInverse = typeInverse;
+        this.currentEntity = currentEntity;
+        this.predicate = predicate;
+        this.entityId = entityId;
+        this.playerName = playerName;
+        this.distance = distance;
+        this.position = position;
+        this.aABB = aABB;
+    }
+
+    public List<? extends Entity> get(CommandSource source) throws CommandSyntaxException {
+        // Entity ID/player
+        if (this.entityId != null) {
+            List<Entity> entities = new ArrayList<>();
+            for (Entity entity : source.getWorld().loadedEntityList) {
+                if ((ENTITY_PREFIX + entity.hashCode()).equals(this.entityId)) {
+                    entities.add(entity);
+                }
+            }
+            return entities.subList(0, Math.min(entities.size(), this.maxResults));
+        } else if (this.playerName != null) {
+            List<Player> players = new ArrayList<>();
+            for (Player player : source.getWorld().players) {
+                if (player.username.equals(this.playerName) || player.nickname.equals(this.playerName)) {
+                    players.add(player);
+                }
+            }
+            return players.subList(0, Math.min(players.size(), this.maxResults));
+        }
+
+        List<? extends Entity> entities;
+        if (this.currentEntity) {
+            if (source.getSender() == null) {
+                throw CommandExceptions.notInWorld().create();
+            } else {
+                entities = Collections.singletonList(source.getSender());
+            }
+        } else if (this.includesEntities) {
+            entities = source.getWorld().loadedEntityList;
+        } else {
+            entities = source.getWorld().players;
+        }
+
+        Vec3 sourceCoordinates = source.getCoordinates(true); // Should I leave it as true or should I make it false? I don't know
+        Vec3 position;
+        if (sourceCoordinates != null) {
+            position = this.position.apply(sourceCoordinates);
+            if (this.aABB != null) {
+                this.aABB.minX = this.aABB.minX + position.x;
+                this.aABB.maxX = this.aABB.maxX + position.x;
+                this.aABB.minY = this.aABB.minY + position.y;
+                this.aABB.maxY = this.aABB.maxY + position.y;
+                this.aABB.minZ = this.aABB.minZ + position.z;
+                this.aABB.maxZ = this.aABB.maxZ + position.z;
+            }
+        } else {
+            position = this.position.apply(Vec3.getTempVec3(0, 0, 0));
+        }
+
+        List<? extends Entity> temp = new ArrayList<>(entities);
+        for (Entity entity : entities) {
+            if ((limitToType != null && limitToType.isInstance(entity) == this.typeInverse)
+                || !predicate.test(entity)
+                || !this.distanceContains(entity, position.x, position.y, position.z)
+                || !aABBIntersectsWithAABB(this.aABB, entity.bb)) {
+                temp.remove(entity);
+            }
+        }
+        entities = temp;
+
+        // Sorting order
+        this.order.accept(source.getSender(), entities);
+
+        // Predicate
+        List<Entity> listAfterPredicate = new ArrayList<>();
+        for (Entity entity : entities) {
+            if (!predicate.test(entity)) continue;
+            listAfterPredicate.add(entity);
+        }
+
+        // Maximum amount of results
+        listAfterPredicate = listAfterPredicate.subList(0, Math.min(listAfterPredicate.size(), this.maxResults));
+
+        if (listAfterPredicate.isEmpty()) throw CommandExceptions.emptySelector().create();
+        return listAfterPredicate;
+    }
+
+    private boolean distanceContains(Entity entity, double x, double y, double z) {
+        if (this.distance.isAny()) return true;
+        return this.distance.contains(entity.distanceTo(x, y, z));
+    }
+
+    private static boolean aABBIntersectsWithAABB(AABB aABB1, AABB aABB2) {
+        if (aABB1 == null) return true;
+        return aABB2 != null && aABB1.intersects(aABB2);
+    }
+
+    public int getMaxResults() {
+        return this.maxResults;
+    }
+
+    public boolean includesEntities() {
+        return this.includesEntities;
+    }
+
+    public boolean isCurrentEntity() {
+        return this.currentEntity;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorOptions.java b/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorOptions.java
new file mode 100644
index 000000000..c974674ba
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorOptions.java
@@ -0,0 +1,290 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import com.mojang.nbt.CompoundTag;
+import com.mojang.nbt.Tag;
+import net.minecraft.client.lang.text.ChainText;
+import net.minecraft.client.lang.text.Text;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.EntityDispatcher;
+import net.minecraft.core.entity.ItemEntity;
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.util.NbtHelper;
+import net.minecraft.core.player.gamemode.Gamemode;
+import net.minecraft.core.util.helper.LoggedPrintStream;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.Predicate;
+
+public class EntitySelectorOptions {
+    private static final DynamicCommandExceptionType INAPPLICABLE_OPTION = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("command.argument_types.entity.selector.options.inapplicable", value)));
+    private static final DynamicCommandExceptionType UNKNOWN_OPTION = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("command.argument_types.entity.selector.options.unknown", value)));
+    private static final DynamicCommandExceptionType UNKNOWN_GAME_MODE = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("command.argument_types.entity.selector.options.gamemode.invalid", value)));
+    private static final DynamicCommandExceptionType UNKNOWN_SORT = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("command.argument_types.entity.selector.options.sort.invalid", value)));
+    private static final DynamicCommandExceptionType UNKNOWN_ENTITY_TYPE = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("command.argument_types.entity.selector.options.type.invalid", value)));
+    private static final SimpleCommandExceptionType NEGATIVE_DISTANCE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.selector.options.distance.invalid"));
+    private static final SimpleCommandExceptionType LIMIT_TOO_SMALL = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.selector.options.limit.invalid"));
+
+    private final StringReader reader;
+    private final String key;
+
+    private static final Map<String, Option> OPTIONS = new HashMap<>();
+
+    public EntitySelectorOptions(StringReader reader, String key) {
+        this.reader = reader;
+        this.key = key;
+    }
+
+    public static void register(String key, Modifier modifier, Predicate<EntitySelectorParser> canUse, Text description) {
+        OPTIONS.put(key, new Option(modifier, canUse, description));
+    }
+
+    static {
+        EntitySelectorOptions.register("x", (parser) -> {
+            double x = parser.getReader().readDouble();
+            parser.setX(x);
+        }, entitySelectorParser -> entitySelectorParser.getX() == null, ChainText.text().trans("command.argument_types.entity.selector.options.x.description"));
+        EntitySelectorOptions.register("y", (parser) -> {
+            double y = parser.getReader().readDouble();
+            parser.setY(y);
+        }, entitySelectorParser -> entitySelectorParser.getY() == null, ChainText.text().trans("command.argument_types.entity.selector.options.y.description"));
+        EntitySelectorOptions.register("z", (parser) -> {
+            double z = parser.getReader().readDouble();
+            parser.setZ(z);
+        }, entitySelectorParser -> entitySelectorParser.getZ() == null, ChainText.text().trans("command.argument_types.entity.selector.options.z.description"));
+        EntitySelectorOptions.register("dx", (parser) -> {
+            double dx = parser.getReader().readDouble();
+            parser.setDeltaX(dx);
+        }, entitySelectorParser -> entitySelectorParser.getDeltaX() == null, ChainText.text().trans("command.argument_types.entity.selector.options.dx.description"));
+        EntitySelectorOptions.register("dy", (parser) -> {
+            double dy = parser.getReader().readDouble();
+            parser.setDeltaY(dy);
+        }, entitySelectorParser -> entitySelectorParser.getDeltaY() == null, ChainText.text().trans("command.argument_types.entity.selector.options.dy.description"));
+        EntitySelectorOptions.register("dz", (parser) -> {
+            double dz = parser.getReader().readDouble();
+            parser.setDeltaZ(dz);
+        }, entitySelectorParser -> entitySelectorParser.getDeltaZ() == null, ChainText.text().trans("command.argument_types.entity.selector.options.dz.description"));
+        EntitySelectorOptions.register("name", (parser) -> {
+            int i = parser.getReader().getCursor();
+            boolean bl = parser.shouldInvertValue();
+            String string = parser.getReader().readString();
+            if (parser.hasNameNotEquals() && !bl) {
+                parser.getReader().setCursor(i);
+                throw INAPPLICABLE_OPTION.createWithContext(parser.getReader(), "name");
+            }
+            if (bl) {
+                parser.setHasNameNotEquals(true);
+            } else {
+                parser.setHasNameEquals(true);
+            }
+            parser.addPredicate(entity -> {
+                if (!(entity instanceof Mob))
+                    return entity instanceof ItemEntity && ((ItemEntity) entity).item != null ? LoggedPrintStream.removeColorCodes(((ItemEntity) entity).item.getDisplayName()).equals(string) : bl;
+                else if (entity instanceof Player) return ((Player) entity).username.equals(string) != bl;
+                else return LoggedPrintStream.removeColorCodes(((Mob) entity).getDisplayName()).equals(string) != bl;
+            });
+        }, entitySelectorParser -> !entitySelectorParser.hasNameEquals(), ChainText.text().trans("command.argument_types.entity.selector.options.name.description"));
+        register("distance", (parser) -> {
+            int cursor = parser.getReader().getCursor();
+            MinMaxBounds.Doubles bounds = MinMaxBounds.Doubles.fromReader(parser.getReader());
+            if ((bounds.getMin() != null && bounds.getMin() < 0) || (bounds.getMax() != null && bounds.getMax() < 0)) {
+                parser.getReader().setCursor(cursor);
+                throw NEGATIVE_DISTANCE.createWithContext(parser.getReader());
+            }
+            parser.setDistance(bounds);
+        }, parser -> parser.getDistance().isAny(), ChainText.text().trans("command.argument_types.entity.selector.options.distance.description"));
+        register("type", (parser) -> {
+            int cursor = parser.getReader().getCursor();
+            boolean invert = parser.shouldInvertValue();
+
+            parser.setSuggestions((builder, consumer) -> {
+                String string = builder.getRemaining().toLowerCase(Locale.ROOT);
+                if (!string.isEmpty()) {
+                    if (string.charAt(0) == '!') {
+                        string = string.substring(1);
+                    }
+                }
+                CommandHelper.suggest("!Player", builder);
+                CommandHelper.suggest("Player", builder);
+                for (String key : EntityDispatcher.keyToClassMap.keySet()) {
+                    if (!key.toLowerCase(Locale.ROOT).startsWith(string)) continue;
+                    CommandHelper.suggest("!" + key, builder);
+                    if (invert) continue;
+                    CommandHelper.suggest(key, builder);
+                }
+                return builder.buildFuture();
+            });
+
+            if (parser.isTypeInverse() && !invert) {
+                parser.getReader().setCursor(cursor);
+                throw INAPPLICABLE_OPTION.createWithContext(parser.getReader(), "type");
+            }
+            if (invert) {
+                parser.setTypeInverse(true);
+            }
+            String type = parser.getReader().readUnquotedString();
+            if (type.equals("Player")) {
+                parser.setLimitToType(Player.class);
+            } else {
+                if (EntityDispatcher.keyToClassMap.containsKey(type)) {
+                    parser.setLimitToType(EntityDispatcher.keyToClassMap.get(type));
+                } else {
+                    parser.getReader().setCursor(cursor);
+                    throw UNKNOWN_ENTITY_TYPE.createWithContext(parser.getReader(), type);
+                }
+            }
+        }, parser -> !parser.hasType(), ChainText.text().trans("command.argument_types.entity.selector.options.type.description"));
+        register("limit", (parser) -> {
+            int cursor = parser.getReader().getCursor();
+            int limit = parser.getReader().readInt();
+            if (limit < 1) {
+                parser.getReader().setCursor(cursor);
+                throw LIMIT_TOO_SMALL.createWithContext(parser.getReader());
+            }
+            parser.setMaxResults(limit);
+            parser.setHasLimit(true);
+        }, parser -> !parser.isCurrentEntity() && !parser.hasLimit(), ChainText.text().trans("command.argument_types.entity.selector.options.limit.description"));
+        register("sort", (parser) -> {
+            int i = parser.getReader().getCursor();
+            String string = parser.getReader().readUnquotedString();
+            parser.setSuggestions((suggestionsBuilder, consumer) -> CommandHelper.suggest(Arrays.asList("nearest", "furthest", "random", "arbitrary"), suggestionsBuilder));
+            BiConsumer<Entity, List<? extends Entity>> sort;
+            switch (string) {
+                case "nearest":
+                    sort = EntitySelectorParser.ORDER_NEAREST;
+                    break;
+                case "furthest":
+                    sort = EntitySelectorParser.ORDER_FURTHEST;
+                    break;
+                case "random":
+                    sort = EntitySelectorParser.ORDER_RANDOM;
+                    break;
+                case "arbitrary":
+                    sort = EntitySelectorParser.ORDER_ARBITRARY;
+                    break;
+                default:
+                    parser.getReader().setCursor(i);
+                    throw UNKNOWN_SORT.createWithContext(parser.getReader(), string);
+            }
+            parser.setOrder(sort);
+            parser.setSorted(true);
+        }, parser -> !parser.isSorted(), ChainText.text().trans("command.argument_types.entity.selector.options.sort.description"));
+        register("gamemode", (parser) -> {
+            parser.setSuggestions((builder, consumer) -> {
+                String string = builder.getRemaining().toLowerCase(Locale.ROOT);
+                boolean bl = !parser.hasGamemodeNotEquals();
+                boolean bl2 = true;
+                if (!string.isEmpty()) {
+                    if (string.charAt(0) == '!') {
+                        bl = false;
+                        string = string.substring(1);
+                    } else {
+                        bl2 = false;
+                    }
+                }
+                for (Gamemode gameMode : Gamemode.gamemodesList) {
+                    if (!CommandHelper.getStringToSuggest(gameMode.getLanguageKey(), string).isPresent()) continue;
+                    String stringToSuggest = CommandHelper.getStringToSuggest(gameMode.getLanguageKey(), string).get();
+                    if (bl2) {
+                        builder.suggest("!" + stringToSuggest);
+                    }
+                    if (!bl) continue;
+                    builder.suggest(stringToSuggest);
+                }
+                return builder.buildFuture();
+            });
+            int cursor = parser.getReader().getCursor();
+            boolean invert = parser.shouldInvertValue();
+            String value = parser.getReader().readUnquotedString();
+
+            Gamemode gamemode = null;
+            for (Gamemode iteratedGameMode : Gamemode.gamemodesList) {
+                if (CommandHelper.matchesKeyString(iteratedGameMode.getLanguageKey(), value)) {
+                    gamemode = iteratedGameMode;
+                }
+            }
+            if (gamemode == null) {
+                parser.getReader().setCursor(cursor);
+                throw UNKNOWN_GAME_MODE.createWithContext(parser.getReader(), value);
+            }
+
+            parser.setIncludesEntities(false);
+            parser.addPredicate((entity) -> {
+                if (!(entity instanceof Player)) return false;
+                return CommandHelper.matchesKeyString(((Player) entity).gamemode.getLanguageKey(), value) != invert;
+            });
+
+            if (invert) {
+                parser.setHasGamemodeNotEquals(true);
+            } else {
+                parser.setHasGamemodeEquals(true);
+            }
+        }, parser -> !parser.hasGamemodeEquals(), ChainText.text().trans("command.argument_types.entity.selector.options.gamemode.description"));
+        register("nbt", (parser) -> {
+            boolean invert = parser.shouldInvertValue();
+            CompoundTag nbt = NbtHelper.parseNbt(parser.getReader());
+            parser.addPredicate((entity) -> {
+                if (nbt.getValue().isEmpty()) return !invert;
+                CompoundTag entityNbt = new CompoundTag();
+                entity.addAdditionalSaveData(entityNbt);
+                for (Map.Entry<String, Tag<?>> entry : nbt.getValue().entrySet()) {
+                    if (!entityNbt.getValue().containsKey(entry.getKey()) || (entityNbt.getValue().get(entry.getKey()) != entry.getValue() && !entityNbt.getValue().get(entry.getKey()).equals(entry.getValue()) && !entityNbt.getValue().get(entry.getKey()).getValue().equals(entry.getValue().getValue()))) {
+                        if (!invert) return false;
+                    }
+                }
+                return true;
+            });
+            if (invert) {
+                parser.setHasNotNbt(true);
+            } else {
+                parser.setHasNbt(true);
+            }
+        }, parser -> !parser.hasNbt(), ChainText.text().trans("command.argument_types.entity.selector.options.nbt.description"));
+    }
+
+    public static Modifier get(EntitySelectorParser entitySelectorParser, String string, int i) throws CommandSyntaxException {
+        Option option = OPTIONS.get(string);
+        if (option != null) {
+            if (option.canUse.test(entitySelectorParser)) {
+                return option.modifier;
+            }
+            throw INAPPLICABLE_OPTION.createWithContext(entitySelectorParser.getReader(), string);
+        }
+        entitySelectorParser.getReader().setCursor(i);
+        throw UNKNOWN_OPTION.createWithContext(entitySelectorParser.getReader(), string);
+    }
+
+    public static void suggestNames(EntitySelectorParser entitySelectorParser, SuggestionsBuilder suggestionsBuilder) {
+        String string = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
+        for (Map.Entry<String, Option> entry : OPTIONS.entrySet()) {
+            if (!entry.getValue().canUse.test(entitySelectorParser) || !entry.getKey().toLowerCase(Locale.ROOT).startsWith(string))
+                continue;
+            suggestionsBuilder.suggest(entry.getKey() + "=", () -> entry.getValue().description.toString());
+        }
+    }
+
+    static class Option {
+        final Modifier modifier;
+        final Predicate<EntitySelectorParser> canUse;
+        final Text description;
+
+        Option(Modifier modifier, Predicate<EntitySelectorParser> canUse, Text description) {
+            this.modifier = modifier;
+            this.canUse = canUse;
+            this.description = description;
+        }
+    }
+
+    @FunctionalInterface
+    interface Modifier {
+        void handle(EntitySelectorParser parser) throws CommandSyntaxException;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorParser.java b/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorParser.java
new file mode 100644
index 000000000..d7eaae07c
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorParser.java
@@ -0,0 +1,458 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.util.phys.Vec3;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.*;
+
+public class EntitySelectorParser {
+    private static final SimpleCommandExceptionType EXPECTED_END_OF_OPTIONS = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.selector.options.unterminated"));
+    private static final DynamicCommandExceptionType EXPECTED_OPTION_VALUE = new DynamicCommandExceptionType((value) -> () -> I18n.getInstance().translateKeyAndFormat("command.argument_types.entity.selector.options.valueless", value));
+
+    public static final BiConsumer<Entity, List<? extends Entity>> ORDER_RANDOM = (sender, entities) -> Collections.shuffle(entities);
+    public static final BiConsumer<Entity, List<? extends Entity>> ORDER_ARBITRARY = (sender, entities) -> {
+    };
+    public static final BiConsumer<Entity, List<? extends Entity>> ORDER_NEAREST = (sender, entities) -> entities.sort((firstEntity, secondEntity) -> Double.compare(firstEntity.distanceTo(sender), secondEntity.distanceTo(sender)));
+    public static final BiConsumer<Entity, List<? extends Entity>> ORDER_FURTHEST = (sender, entities) -> entities.sort((firstEntity, secondEntity) -> Double.compare(secondEntity.distanceTo(sender), firstEntity.distanceTo(sender)));
+
+    private final SimpleCommandExceptionType SELECTORS_NOT_ALLOWED = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.entity.invalid_selector.selectors_not_allowed"));
+
+    private final StringReader reader;
+    private int startPosition;
+
+    private Predicate<Entity> predicate = entity -> true;
+
+    private int maxResults;
+    private boolean includesEntities;
+    private BiConsumer<Entity, List<? extends Entity>> order;
+    private @Nullable Class<? extends Entity> limitToType;
+    private boolean typeInverse = false;
+    private boolean currentEntity;
+    private String entityId;
+    private String playerName;
+    private MinMaxBounds.Doubles distance = MinMaxBounds.Doubles.ANY;
+    private Double x;
+    private Double y;
+    private Double z;
+    private Double deltaX;
+    private Double deltaY;
+    private Double deltaZ;
+    private final boolean allowSelectors;
+
+    private BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> suggestions = CommandHelper.NO_SUGGESTIONS;
+
+    public EntitySelectorParser(StringReader reader) {
+        this(reader, true);
+    }
+
+    public EntitySelectorParser(StringReader reader, boolean allowSelectors) {
+        this.reader = reader;
+        this.allowSelectors = allowSelectors;
+    }
+
+    private void parseSelector() throws CommandSyntaxException {
+        this.reader.skip();
+        this.suggestions = this::suggestSelector;
+        if (!this.reader.canRead()) throw CommandExceptions.invalidSelector().createWithContext(this.reader);
+
+        switch (this.reader.read()) {
+            case 'p':
+                this.maxResults = 1;
+                this.includesEntities = false;
+                this.order = ORDER_NEAREST;
+                this.setLimitToType(Player.class);
+                this.currentEntity = false;
+                break;
+            case 'a':
+                this.maxResults = Integer.MAX_VALUE;
+                this.includesEntities = false;
+                this.order = ORDER_ARBITRARY;
+                this.setLimitToType(Player.class);
+                this.currentEntity = false;
+                break;
+            case 'r':
+                this.maxResults = 1;
+                this.includesEntities = false;
+                this.order = ORDER_RANDOM;
+                this.setLimitToType(Player.class);
+                this.currentEntity = false;
+                break;
+            case 's':
+                this.maxResults = 1;
+                this.includesEntities = true;
+                this.order = ORDER_ARBITRARY;
+                this.currentEntity = true;
+                break;
+            case 'e':
+                this.maxResults = Integer.MAX_VALUE;
+                this.includesEntities = true;
+                this.order = ORDER_ARBITRARY;
+                this.currentEntity = false;
+                break;
+            default:
+                throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(this.reader);
+        }
+        this.suggestions = this::suggestOpenOptions;
+        if (this.reader.canRead() && this.reader.peek() == '[') {
+            this.reader.skip();
+            this.suggestions = this::suggestOptionsKeyOrClose;
+            this.parseOptions();
+        }
+        if (this.reader.canRead() && this.reader.peek() != ' ') {
+            this.suggestions = CommandHelper.NO_SUGGESTIONS;
+        }
+    }
+
+    private void parseNameOrEntityId() throws CommandSyntaxException {
+        if (this.reader.canRead()) {
+            this.suggestions = this::suggestName;
+        }
+        String string = this.reader.readString();
+        this.maxResults = 1;
+        if (string.startsWith(EntitySelector.ENTITY_PREFIX)) {
+            this.includesEntities = true;
+            this.entityId = string;
+        } else {
+            this.includesEntities = false;
+            this.playerName = string;
+        }
+    }
+
+    public EntitySelector parse() throws CommandSyntaxException {
+        this.startPosition = this.reader.getCursor();
+        this.suggestions = this::suggestNameOrSelector;
+        if (this.reader.canRead() && this.reader.peek() == '@') {
+            if (!this.allowSelectors) {
+                throw SELECTORS_NOT_ALLOWED.createWithContext(this.reader);
+            }
+            this.parseSelector();
+        } else {
+            this.parseNameOrEntityId();
+        }
+        return this.getSelector();
+    }
+
+    private void parseOptions() throws CommandSyntaxException {
+        this.suggestions = this::suggestOptionsKey;
+        this.reader.skipWhitespace();
+        while (this.reader.canRead() && this.reader.peek() != ']') {
+            this.reader.skipWhitespace();
+            int i = this.reader.getCursor();
+            String key = this.reader.readString();
+            EntitySelectorOptions.Modifier modifier = EntitySelectorOptions.get(this, key, i);
+            this.reader.skipWhitespace();
+            if (!this.reader.canRead() || this.reader.peek() != '=') {
+                this.reader.setCursor(i);
+                throw EXPECTED_OPTION_VALUE.createWithContext(this.reader, key);
+            }
+            this.reader.skip();
+            this.reader.skipWhitespace();
+            this.suggestions = CommandHelper.NO_SUGGESTIONS;
+            modifier.handle(this);
+            this.reader.skipWhitespace();
+            this.suggestions = this::suggestOptionsNextOrClose;
+            if (!this.reader.canRead()) continue;
+            if (this.reader.peek() == ',') {
+                this.reader.skip();
+                this.suggestions = this::suggestOptionsKey;
+                continue;
+            }
+            if (this.reader.peek() == ']') break;
+            throw EXPECTED_END_OF_OPTIONS.createWithContext(this.reader);
+        }
+        if (!this.reader.canRead()) {
+            throw EXPECTED_END_OF_OPTIONS.createWithContext(this.reader);
+        }
+        this.reader.skip();
+        this.suggestions = CommandHelper.NO_SUGGESTIONS;
+    }
+
+    public EntitySelector getSelector() {
+        AABB aABB;
+        if (this.deltaX != null || this.deltaY != null || this.deltaZ != null) {
+            aABB = this.createAabb(this.deltaX == null ? 0.0 : this.deltaX, this.deltaY == null ? 0.0 : this.deltaY, this.deltaZ == null ? 0.0 : this.deltaZ);
+        } else if (this.distance.getMax() != null) {
+            double d = (Double) this.distance.getMax();
+            aABB = AABB.getTemporaryBB(-d, -d, -d, d + 1.0, d + 1.0, d + 1.0);
+        } else {
+            aABB = null;
+        }
+        Function<Vec3, Vec3> position = this.x == null && this.y == null && this.z == null ? vec3 -> vec3 : vec3 -> Vec3.getTempVec3(this.x == null ? vec3.x : this.x, this.y == null ? vec3.y : this.y, this.z == null ? vec3.z : this.z);
+        return new EntitySelector(this.maxResults, this.includesEntities, this.order, this.limitToType, this.typeInverse, this.currentEntity, this.predicate, this.entityId, this.playerName, this.distance, position, aABB);
+    }
+
+    private AABB createAabb(double d, double e, double f) {
+        boolean bl = d < 0.0;
+        boolean bl2 = e < 0.0;
+        boolean bl3 = f < 0.0;
+        double g = bl ? d : 0.0;
+        double h = bl2 ? e : 0.0;
+        double i = bl3 ? f : 0.0;
+        double j = (bl ? 0.0 : d) + 1.0;
+        double k = (bl2 ? 0.0 : e) + 1.0;
+        double l = (bl3 ? 0.0 : f) + 1.0;
+        return AABB.getTemporaryBB(g, h, i, j, k, l);
+    }
+
+    public void addPredicate(Predicate<Entity> predicate) {
+        this.predicate = this.predicate.and(predicate);
+    }
+
+    public boolean shouldInvertValue() {
+        this.reader.skipWhitespace();
+        if (this.reader.canRead() && this.reader.peek() == '!') {
+            this.reader.skip();
+            this.reader.skipWhitespace();
+            return true;
+        }
+        return false;
+    }
+
+    public StringReader getReader() {
+        return this.reader;
+    }
+
+    private static void fillSelectorSuggestions(SuggestionsBuilder builder) {
+        builder.suggest("@p", () -> I18n.getInstance().translateKey("command.argument_types.entity.selector.nearest_player"));
+        builder.suggest("@a", () -> I18n.getInstance().translateKey("command.argument_types.entity.selector.all_players"));
+        builder.suggest("@r", () -> I18n.getInstance().translateKey("command.argument_types.entity.selector.random_player"));
+        builder.suggest("@s", () -> I18n.getInstance().translateKey("command.argument_types.entity.selector.self"));
+        builder.suggest("@e", () -> I18n.getInstance().translateKey("command.argument_types.entity.selector.all_entities"));
+    }
+
+    public void setSuggestions(BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> biFunction) {
+        this.suggestions = biFunction;
+    }
+
+    private CompletableFuture<Suggestions> suggestNameOrSelector(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        consumer.accept(suggestionsBuilder);
+        fillSelectorSuggestions(suggestionsBuilder);
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestName(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        SuggestionsBuilder suggestionsBuilder2 = suggestionsBuilder.createOffset(this.startPosition);
+        consumer.accept(suggestionsBuilder2);
+        return suggestionsBuilder.add(suggestionsBuilder2).buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestSelector(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        SuggestionsBuilder suggestionsBuilder2 = suggestionsBuilder.createOffset(suggestionsBuilder.getStart() - 1);
+        EntitySelectorParser.fillSelectorSuggestions(suggestionsBuilder2);
+        suggestionsBuilder.add(suggestionsBuilder2);
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestOpenOptions(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        if (!this.reader.canRead()) suggestionsBuilder.suggest(String.valueOf('['));
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestOptionsKeyOrClose(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        if (!this.reader.canRead()) suggestionsBuilder.suggest(String.valueOf(']'));
+        EntitySelectorOptions.suggestNames(this, suggestionsBuilder);
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestOptionsKey(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        EntitySelectorOptions.suggestNames(this, suggestionsBuilder);
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestOptionsNextOrClose(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        if (!this.reader.canRead()) {
+            suggestionsBuilder.suggest(String.valueOf(','));
+            suggestionsBuilder.suggest(String.valueOf(']'));
+        }
+        return suggestionsBuilder.buildFuture();
+    }
+
+    public CompletableFuture<Suggestions> fillSuggestions(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        return this.suggestions.apply(suggestionsBuilder.createOffset(this.reader.getCursor()), consumer);
+    }
+
+    public BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> getSuggestions() {
+        return this.suggestions;
+    }
+
+    private boolean hasGamemodeEquals = false;
+    private boolean hasGamemodeNotEquals = false;
+    private boolean isSorted = false;
+    private boolean hasLimit = false;
+    private boolean hasType = false;
+    private boolean hasNameEquals = false;
+    private boolean hasNameNotEquals = false;
+    private boolean hasNbt = false;
+    private boolean hasNotNbt = false;
+
+    public boolean hasGamemodeEquals() {
+        return this.hasGamemodeEquals;
+    }
+
+    public void setHasGamemodeEquals(boolean bl) {
+        this.hasGamemodeEquals = bl;
+    }
+
+    public boolean hasGamemodeNotEquals() {
+        return this.hasGamemodeNotEquals;
+    }
+
+    public void setHasGamemodeNotEquals(boolean bl) {
+        this.hasGamemodeNotEquals = bl;
+    }
+
+    public boolean isSorted() {
+        return this.isSorted;
+    }
+
+    public void setSorted(boolean bl) {
+        this.isSorted = bl;
+    }
+
+    public boolean hasLimit() {
+        return this.hasLimit;
+    }
+
+    public void setHasLimit(boolean bl) {
+        this.hasLimit = bl;
+    }
+
+    public boolean hasType() {
+        return this.limitToType != null;
+    }
+
+    public boolean isTypeInverse() {
+        return this.typeInverse;
+    }
+
+    public void setTypeInverse(boolean bl) {
+        this.typeInverse = bl;
+    }
+
+    public MinMaxBounds.Doubles getDistance() {
+        return this.distance;
+    }
+
+    public void setDistance(MinMaxBounds.Doubles distance) {
+        this.distance = distance;
+    }
+
+    public boolean hasNameEquals() {
+        return this.hasNameEquals;
+    }
+
+    public void setHasNameEquals(boolean bl) {
+        this.hasNameEquals = bl;
+    }
+
+    public boolean hasNameNotEquals() {
+        return this.hasNameNotEquals;
+    }
+
+    public void setHasNameNotEquals(boolean bl) {
+        this.hasNameNotEquals = bl;
+    }
+
+    public void setMaxResults(int maxResults) {
+        this.maxResults = maxResults;
+    }
+
+    public void setIncludesEntities(boolean includesEntities) {
+        this.includesEntities = includesEntities;
+    }
+
+    public void setOrder(BiConsumer<Entity, List<? extends Entity>> order) {
+        this.order = order;
+    }
+
+    public void setLimitToType(Class<? extends Entity> type) {
+        this.limitToType = type;
+    }
+
+    public void setCurrentEntity(boolean currentEntity) {
+        this.currentEntity = currentEntity;
+    }
+
+    public boolean hasNbt() {
+        return this.hasNbt;
+    }
+
+    public void setHasNbt(boolean bl) {
+        this.hasNbt = bl;
+    }
+
+    public boolean hasNotNbt() {
+        return this.hasNotNbt;
+    }
+
+    public void setHasNotNbt(boolean bl) {
+        this.hasNotNbt = bl;
+    }
+
+    public void setX(double x) {
+        this.x = x;
+    }
+
+    public void setY(double y) {
+        this.y = y;
+    }
+
+    public void setZ(double z) {
+        this.z = z;
+    }
+
+    public void setDeltaX(double deltaX) {
+        this.deltaX = deltaX;
+    }
+
+    public void setDeltaY(double deltaY) {
+        this.deltaY = deltaY;
+    }
+
+    public void setDeltaZ(double deltaZ) {
+        this.deltaZ = deltaZ;
+    }
+
+    public Double getX() {
+        return this.x;
+    }
+
+    public Double getY() {
+        return this.y;
+    }
+
+    public Double getZ() {
+        return this.z;
+    }
+
+    public Double getDeltaX() {
+        return this.deltaX;
+    }
+
+    public Double getDeltaY() {
+        return this.deltaY;
+    }
+
+    public Double getDeltaZ() {
+        return this.deltaZ;
+    }
+
+    public boolean isCurrentEntity() {
+        return this.currentEntity;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/IntegerCoordinate.java b/src/main/java/net/minecraft/core/net/command/helpers/IntegerCoordinate.java
new file mode 100644
index 000000000..02e3b32b5
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/IntegerCoordinate.java
@@ -0,0 +1,51 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import org.jetbrains.annotations.Nullable;
+
+public class IntegerCoordinate {
+    private final boolean isRelative;
+    private final int coordinate;
+
+    public IntegerCoordinate(boolean isRelative, int coordinate) {
+        this.isRelative = isRelative;
+        this.coordinate = coordinate;
+    }
+
+    public int get(@Nullable Integer sourceCoordinate) throws CommandSyntaxException {
+        if (this.isRelative) {
+            if (sourceCoordinate != null) {
+                return sourceCoordinate + this.coordinate;
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+
+        return this.coordinate;
+    }
+
+    public static IntegerCoordinate parse(StringReader reader) throws CommandSyntaxException {
+        if (!reader.canRead()) throw CommandExceptions.incomplete().createWithContext(reader);
+
+        if (reader.peek() == '~') {
+            reader.skip();
+            if (reader.canRead() && reader.peek() != ' ') {
+                int coordinate = reader.readInt();
+                return new IntegerCoordinate(true, coordinate);
+            } else {
+                return new IntegerCoordinate(true, 0);
+            }
+        } else if (reader.peek() != ' ') {
+            int coordinate = reader.readInt();
+            return new IntegerCoordinate(false, coordinate);
+        }
+
+        throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.readerExpectedInt().createWithContext(reader);
+    }
+
+    public boolean isRelative() {
+        return this.isRelative;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/IntegerCoordinates.java b/src/main/java/net/minecraft/core/net/command/helpers/IntegerCoordinates.java
new file mode 100644
index 000000000..e207a616c
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/IntegerCoordinates.java
@@ -0,0 +1,82 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import org.jetbrains.annotations.Nullable;
+
+public class IntegerCoordinates {
+    private final IntegerCoordinate x;
+    private final IntegerCoordinate y;
+    private final IntegerCoordinate z;
+
+    public IntegerCoordinates(IntegerCoordinate x, IntegerCoordinate y, IntegerCoordinate z) {
+        this.x = x;
+        this.y = y;
+        this.z = z;
+    }
+
+    public int getX(@Nullable Integer sourceX) throws CommandSyntaxException {
+        return this.x.get(sourceX);
+    }
+
+    public int getY(@Nullable Integer sourceY) throws CommandSyntaxException {
+        return this.y.get(sourceY);
+    }
+
+    public int getZ(@Nullable Integer sourceZ) throws CommandSyntaxException {
+        return this.z.get(sourceZ);
+    }
+
+    public int getX(@Nullable Double sourceX) throws CommandSyntaxException {
+        if (sourceX == null) return this.x.get(null);
+        return this.x.get((int) Math.floor(sourceX));
+    }
+
+    public int getY(@Nullable Double sourceY) throws CommandSyntaxException {
+        if (sourceY == null) return this.y.get(null);
+        return this.y.get((int) Math.floor(sourceY));
+    }
+
+    public int getZ(@Nullable Double sourceZ) throws CommandSyntaxException {
+        if (sourceZ == null) return this.z.get(null);
+        return this.z.get((int) Math.floor(sourceZ));
+    }
+
+    public int getX(CommandSource source) throws CommandSyntaxException {
+        if (source.getCoordinates(true) == null) {
+            if (!this.x.isRelative()) {
+                return this.x.get(0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.x.get((int) Math.floor(source.getCoordinates(true).x));
+    }
+
+    public int getY(CommandSource source, boolean offsetHeight) throws CommandSyntaxException {
+        if (source.getCoordinates(offsetHeight) == null) {
+            if (!this.y.isRelative()) {
+                return this.y.get(0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.y.get((int) Math.floor(source.getCoordinates(offsetHeight).y));
+    }
+
+    public int getZ(CommandSource source) throws CommandSyntaxException {
+        if (source.getCoordinates(true) == null) {
+            if (!this.z.isRelative()) {
+                return this.z.get(0);
+            } else {
+                throw CommandExceptions.notInWorld().create();
+            }
+        }
+        return this.z.get((int) Math.floor(source.getCoordinates(true).z));
+    }
+
+    public boolean hasRelativeCoordinate() {
+        return this.x.isRelative() || this.y.isRelative() || this.z.isRelative();
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/ItemStackArgumentParser.java b/src/main/java/net/minecraft/core/net/command/helpers/ItemStackArgumentParser.java
new file mode 100644
index 000000000..ce1c34d85
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/ItemStackArgumentParser.java
@@ -0,0 +1,71 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+public class ItemStackArgumentParser extends ArgumentParser {
+    private static final SimpleCommandExceptionType INVALID_ITEM = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.item.invalid_item"));
+
+    private Item item;
+    private int metadata = 0;
+    private CompoundTag tag = new CompoundTag();
+
+    public ItemStackArgumentParser(StringReader reader) {
+        super(reader);
+    }
+
+    private CompletableFuture<Suggestions> suggestItems(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        SuggestionsBuilder suggestionsBuilder2 = suggestionsBuilder.createOffset(this.startPosition);
+        consumer.accept(suggestionsBuilder2);
+        return suggestionsBuilder.add(suggestionsBuilder2).buildFuture();
+    }
+    
+    public ItemStack parse() throws CommandSyntaxException {
+        this.startPosition = this.reader.getCursor();
+
+        this.suggestions = this::suggestItems;
+        this.parseItem();
+
+        if (this.item == null) throw INVALID_ITEM.createWithContext(this.reader);
+
+        this.suggestions = this::suggestOpenMetadataOrTag;
+        if (this.reader.canRead() && this.reader.peek() == '[') {
+            this.metadata = this.parseMetadata();
+        }
+
+        if (this.reader.canRead() && this.reader.peek() == '{') {
+            this.suggestions = CommandHelper.NO_SUGGESTIONS;
+            this.tag = this.parseCompound();
+        }
+
+        if (this.item != null) {
+            return new ItemStack(this.item, 1, this.metadata, this.tag);
+        }
+        throw INVALID_ITEM.createWithContext(this.reader);
+    }
+
+    private void parseItem() throws CommandSyntaxException {
+        String string = this.reader.readString();
+        for (Item itemInList : Item.itemsList) {
+            if (itemInList == null) continue;
+            if (CommandHelper.matchesKeyString(itemInList.getKey(), string)) {
+                this.item = itemInList;
+            }
+        }
+    }
+
+    public CompletableFuture<Suggestions> fillSuggestions(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        return this.suggestions.apply(suggestionsBuilder.createOffset(this.reader.getCursor()), consumer);
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/MinMaxBounds.java b/src/main/java/net/minecraft/core/net/command/helpers/MinMaxBounds.java
new file mode 100644
index 000000000..884c50dc1
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/MinMaxBounds.java
@@ -0,0 +1,144 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public abstract class MinMaxBounds<T extends Number> {
+    private static final SimpleCommandExceptionType EMPTY_VALUE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.range.empty"));
+    private static final SimpleCommandExceptionType SWAPPED_VALUES = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.range.swapped"));
+
+    @Nullable
+    protected final T min;
+    @Nullable
+    protected final T max;
+
+    public MinMaxBounds(@Nullable T min, @Nullable T max) {
+        this.min = min;
+        this.max = max;
+    }
+
+    public T getMax() {
+        return this.max;
+    }
+
+    public T getMin() {
+        return this.min;
+    }
+
+    public boolean isAny() {
+        return this.max == null && this.min == null;
+    }
+
+    public static <T extends Number, R extends MinMaxBounds<T>> R fromReader(StringReader reader, Function<String, T> parser, Supplier<SimpleCommandExceptionType> supplier, BoundsFromReaderFactory<T, R> boundsFromReaderFactory) throws CommandSyntaxException {
+        if (!reader.canRead()) throw EMPTY_VALUE.createWithContext(reader);
+        int cursor = reader.getCursor();
+        try {
+            T number1 = readNumber(reader, parser, supplier);
+            T number2;
+            if (reader.canRead(2) && reader.peek() == '.' && reader.peek(1) == '.') {
+                reader.skip();
+                reader.skip();
+                number2 = readNumber(reader, parser, supplier);
+            } else {
+                number2 = number1;
+            }
+            if (number1 == null && number2 == null) {
+                throw EMPTY_VALUE.createWithContext(reader);
+            }
+            return boundsFromReaderFactory.create(reader, number1, number2);
+        } catch (CommandSyntaxException exception) {
+            reader.setCursor(cursor);
+            throw EMPTY_VALUE.createWithContext(reader);
+        }
+    }
+
+    private static <T extends Number> T readNumber(StringReader reader, Function<String, T> parser, Supplier<SimpleCommandExceptionType> supplier) throws CommandSyntaxException {
+        int cursor = reader.getCursor();
+        while (reader.canRead() && isAllowedChatCharacter(reader)) {
+            reader.skip();
+        }
+        String numberString = reader.getString().substring(cursor, reader.getCursor());
+        if (numberString.isEmpty()) {
+            return null;
+        }
+        try {
+            return parser.apply(numberString);
+        } catch (NumberFormatException e) {
+            throw supplier.get().createWithContext(reader);
+        }
+    }
+
+    private static boolean isAllowedChatCharacter(StringReader reader) {
+        char c = reader.peek();
+        if (c >= '0' && c <= '9' || c == '-') {
+            return true;
+        }
+        if (c == '.') {
+            return !reader.canRead(2) || reader.peek(1) != '.';
+        }
+        return false;
+    }
+
+    @FunctionalInterface
+    protected interface BoundsFromReaderFactory<T extends Number, R extends MinMaxBounds<T>> {
+        R create(StringReader reader, T min, T max) throws CommandSyntaxException;
+    }
+
+    public static class Integers extends MinMaxBounds<Integer> {
+        public static Integers ANY = new Integers(null, null);
+
+        public Integers(@Nullable Integer min, @Nullable Integer max) {
+            super(min, max);
+        }
+
+        private static Integers create(StringReader stringReader, @Nullable Integer integer1, @Nullable Integer integer2) throws CommandSyntaxException {
+            if (integer1 != null && integer2 != null && integer1 > integer2) {
+                throw SWAPPED_VALUES.createWithContext(stringReader);
+            }
+            return new Integers(integer1, integer2);
+        }
+
+        public boolean contains(int number) {
+            if (this.min != null && this.min > number) {
+                return false;
+            }
+            return this.max == null || this.max >= number;
+        }
+
+        public static MinMaxBounds.Integers fromReader(StringReader reader) throws CommandSyntaxException {
+            return MinMaxBounds.fromReader(reader, Integer::parseInt, CommandSyntaxException.BUILT_IN_EXCEPTIONS::readerExpectedInt, Integers::create);
+        }
+    }
+
+    public static class Doubles extends MinMaxBounds<Double> {
+        public static Doubles ANY = new Doubles(null, null);
+
+        public Doubles(@Nullable Double min, @Nullable Double max) {
+            super(min, max);
+        }
+
+        private static Doubles create(StringReader stringReader, @Nullable Double double1, @Nullable Double double2) throws CommandSyntaxException {
+            if (double1 != null && double2 != null && double1 > double2) {
+                throw SWAPPED_VALUES.createWithContext(stringReader);
+            }
+            return new Doubles(double1, double2);
+        }
+
+        public boolean contains(double number) {
+            if (this.min != null && this.min > number) {
+                return false;
+            }
+            return this.max == null || this.max >= number;
+        }
+
+        public static MinMaxBounds.Doubles fromReader(StringReader reader) throws CommandSyntaxException {
+            return MinMaxBounds.fromReader(reader, Double::parseDouble, CommandSyntaxException.BUILT_IN_EXCEPTIONS::readerExpectedInt, Doubles::create);
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/WorldFeatureParameterTypes.java b/src/main/java/net/minecraft/core/net/command/helpers/WorldFeatureParameterTypes.java
new file mode 100644
index 000000000..e13c5cf3f
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/WorldFeatureParameterTypes.java
@@ -0,0 +1,53 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class WorldFeatureParameterTypes {
+    private static final Map<Class<?>, ReadFunction> FEATURE_MAP = new HashMap<>();
+
+    static {
+        FEATURE_MAP.put(Integer.TYPE, (reader, parser) -> reader.readInt());
+        FEATURE_MAP.put(Block.class, WorldFeatureParameterTypes::parseBlock);
+        FEATURE_MAP.put(String.class, (reader, parser) -> reader.readString());
+    }
+
+    public static void register(Class<?> clazz, ReadFunction function) {
+        FEATURE_MAP.put(clazz, function);
+    }
+
+    public static Map<Class<?>, ReadFunction> getFeatures() {
+        return new HashMap<>(FEATURE_MAP);
+    }
+
+    public static Object get(Class<?> clazz, StringReader stringReader, WorldFeatureParser parser) throws CommandSyntaxException {
+        if (FEATURE_MAP.containsKey(clazz)) return FEATURE_MAP.get(clazz).handle(stringReader, parser);
+        throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(stringReader);
+    }
+
+    private static Block parseBlock(StringReader reader, WorldFeatureParser parser) throws CommandSyntaxException {
+        parser.setSuggestions(CommandHelper.SUGGEST_BLOCKS);
+
+        int cursor = reader.getCursor();
+        final String string = reader.readString();
+
+        for (Block blockInList : Block.blocksList) {
+            if (blockInList == null) continue;
+            if (CommandHelper.matchesKeyString(blockInList.getKey(), string)) {
+                return blockInList;
+            }
+        }
+        reader.setCursor(cursor);
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.block.invalid_block"));
+    }
+
+    public interface ReadFunction {
+        Object handle(StringReader reader, WorldFeatureParser parser) throws CommandSyntaxException;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/helpers/WorldFeatureParser.java b/src/main/java/net/minecraft/core/net/command/helpers/WorldFeatureParser.java
new file mode 100644
index 000000000..a52b0462a
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/helpers/WorldFeatureParser.java
@@ -0,0 +1,155 @@
+package net.minecraft.core.net.command.helpers;
+
+import com.b100.utils.Utils;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.net.command.util.CommandHelper;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+public class WorldFeatureParser {
+    private final SimpleCommandExceptionType NO_PARAMETERS = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.world_feature.no_parameters"));
+
+    private final StringReader reader;
+    private int startPosition = 0;
+    
+    private BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> suggestions = CommandHelper.NO_SUGGESTIONS;
+    
+    public WorldFeatureParser(StringReader reader) {
+        this.reader = reader;
+    }
+
+    private CompletableFuture<Suggestions> suggestWorldFeatures(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        SuggestionsBuilder suggestionsBuilder2 = suggestionsBuilder.createOffset(this.startPosition);
+        consumer.accept(suggestionsBuilder2);
+        return suggestionsBuilder.add(suggestionsBuilder2).buildFuture();
+    }
+
+    public WorldFeature parse() throws CommandSyntaxException {
+        this.startPosition = this.reader.getCursor();
+        this.suggestions = this::suggestWorldFeatures;
+        final String string = this.reader.readString();
+        Class<? extends WorldFeature> worldFeatureClass = null;
+
+        for (Map.Entry<String, Class<? extends WorldFeature>> entry : CommandHelper.WORLD_FEATURES.entrySet()) {
+            if (CommandHelper.matchesKeyString(entry.getKey(), string)) {
+                worldFeatureClass = entry.getValue();
+            }
+        }
+
+        if (worldFeatureClass == null) throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(this.reader);
+
+        boolean hasParameters = false;
+        Constructor<?> constructor = null;
+
+        for (Constructor<?> c : worldFeatureClass.getConstructors()) {
+            constructor = c;
+            hasParameters = c.getParameters().length != 0;
+        }
+
+        if (!hasParameters && constructor != null) {
+            if (this.reader.canRead() && this.reader.peek() == '[') {
+                throw NO_PARAMETERS.createWithContext(this.reader);
+            }
+            try {
+                return (WorldFeature) constructor.newInstance();
+            } catch (Exception e) {
+                throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.world_feature.invalid_world_feature"));
+            }
+        }
+
+        return this.parseParameters(worldFeatureClass);
+    }
+
+    private WorldFeature parseParameters(Class<? extends WorldFeature> worldFeatureClass) throws CommandSyntaxException {
+        this.suggestions = this::suggestOpenParameters;
+        Constructor<?> constructor;
+        if (this.reader.canRead()) this.suggestions = CommandHelper.NO_SUGGESTIONS;
+        if (this.reader.canRead() && this.reader.peek() == '[') {
+            List<Object> parameters = new ArrayList<>();
+            this.reader.skip();
+
+            Constructor<?> c = getConstructorWithMostParameters(worldFeatureClass.getConstructors());
+
+            if (c == null) throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(this.reader);
+
+            for (Parameter parameter : c.getParameters()) {
+                this.suggestions = CommandHelper.NO_SUGGESTIONS;
+                this.reader.skipWhitespace();
+                Object parsedParameter = this.parseParameter(parameter);
+                parameters.add(parsedParameter);
+
+                boolean lastParameter = parameters.size() == c.getParameters().length;
+
+                this.reader.skipWhitespace();
+                if (!this.reader.canRead()) {
+                    this.suggestions = lastParameter ? this::suggestParametersClose : this::suggestParametersNext;
+                    throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(this.reader);
+                }
+                if ((lastParameter && this.reader.peek() == ']') || (!lastParameter && this.reader.peek() == ','))
+                    this.reader.skip();
+                else throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(this.reader);
+            }
+
+            constructor = c;
+            this.suggestions = CommandHelper.NO_SUGGESTIONS;
+
+            try {
+                return (WorldFeature) constructor.newInstance(Utils.toArray(Object.class, parameters));
+            } catch (Exception e) {
+                throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.world_feature.invalid_world_feature"));
+            }
+        }
+        throw new CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), () -> I18n.getInstance().translateKey("command.argument_types.world_feature.invalid_world_feature"));
+    }
+
+    private Object parseParameter(Parameter parameter) throws CommandSyntaxException {
+        this.suggestions = CommandHelper.NO_SUGGESTIONS;
+        return WorldFeatureParameterTypes.get(parameter.getType(), this.reader, this);
+    }
+
+    private CompletableFuture<Suggestions> suggestOpenParameters(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        suggestionsBuilder.suggest(String.valueOf('['));
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestParametersNext(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        suggestionsBuilder.suggest(String.valueOf(','));
+        return suggestionsBuilder.buildFuture();
+    }
+
+    private CompletableFuture<Suggestions> suggestParametersClose(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        suggestionsBuilder.suggest(String.valueOf(']'));
+        return suggestionsBuilder.buildFuture();
+    }
+
+    public void setSuggestions(BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> biFunction) {
+        this.suggestions = biFunction;
+    }
+
+    public CompletableFuture<Suggestions> fillSuggestions(SuggestionsBuilder suggestionsBuilder, Consumer<SuggestionsBuilder> consumer) {
+        return this.suggestions.apply(suggestionsBuilder.createOffset(this.reader.getCursor()), consumer);
+    }
+
+    private static Constructor<?> getConstructorWithMostParameters(Constructor<?>[] constructors) {
+        if (constructors.length == 0) return null;
+        Constructor<?> constructor = constructors[0];
+        for (Constructor<?> c : constructors) {
+            if (c.getParameters().length <= constructor.getParameters().length) continue;
+            constructor = c;
+        }
+        return constructor;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/BanCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/BanCommand.java
deleted file mode 100644
index da7a5e8bf..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/BanCommand.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.core.util.helper.UUIDHelper;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-
-public class BanCommand extends ServerCommand {
-    public BanCommand(MinecraftServer server) {
-        super(server, "ban");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length != 1) return false;
-        String senderName = sender.getName();
-
-        String nameToBan = args[0];
-
-
-        ServerPlayer player = server.playerList.getPlayerEntity(nameToBan);
-        if(player != null) {
-            server.playerList.banPlayer(player.uuid);
-            sendNoticeToOps(senderName, "Banning " + nameToBan);
-            player.playerNetServerHandler.kickPlayer("Banned by admin");
-        } else {
-            UUIDHelper.runConversionAction(nameToBan, (uuid) -> {
-                server.playerList.banPlayer(uuid);
-                sendNoticeToOps(senderName, "Banning " + nameToBan);
-            }, (username) -> handler.sendCommandFeedback(sender,"Could not retrieve UUID of player '" + username + "'"));
-        }
-
-
-
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/ban <username>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/BanIpCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/BanIpCommand.java
deleted file mode 100644
index 9e990b52f..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/BanIpCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-
-public class BanIpCommand extends ServerCommand {
-    public BanIpCommand(MinecraftServer server) {
-        super(server, "ban-ip");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length != 1) return false;
-        String senderName = sender.getName();
-
-        String nameToBan = args[0];
-        server.playerList.banIP(nameToBan);
-        
-        sendNoticeToOps(senderName, "Banning ip " + nameToBan);
-
-        ServerPlayer player = server.playerList.getPlayerEntity(nameToBan);
-        if(player != null)
-        {
-            player.playerNetServerHandler.kickPlayer("Banned by admin");
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/ban-ip <username>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/ColorCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/ColorCommand.java
deleted file mode 100644
index 8fd585dbd..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/ColorCommand.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
-import net.minecraft.core.net.command.*;
-
-public class ColorCommand extends ServerCommand {
-
-	public ColorCommand(MinecraftServer server) {
-		super(server, "color", "colour", "c");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(!sender.isPlayer()) throw new CommandError("Must be used by a player!");
-		ServerPlayer player = (ServerPlayer) sender.getPlayer();
-		
-		if(args.length == 0) {
-			{
-				TextFormatting color = TextFormatting.get(player.chatColor);
-				sender.sendMessage(TextFormatting.LIGHT_GRAY + "Your color is " + color + color.getNames()[0]);
-			}
-			{
-				StringBuilder builder = new StringBuilder();
-				builder.append(TextFormatting.LIGHT_GRAY + "Available colors: ");
-				int c = 0;
-				for (int i = 0; i < 16; i++) {
-					TextFormatting color = TextFormatting.get(i);
-					if(c > 0) builder.append(", ");
-					builder.append(color).append(color.getNames()[0]);
-					c++;
-				}
-				sender.sendMessage(builder.toString());
-			}
-			return true;
-		}
-		if(args.length > 0 && args[0].equalsIgnoreCase("set")) {
-			String[] args2 = new String[args.length - 1];
-			for(int i = 1; i < args.length; i++) {
-				args2[i - 1] = args[i];
-			}
-			args = args2;
-		}
-		StringBuilder enteredColorStr = new StringBuilder();
-		for(int i=0; i < args.length; i++) enteredColorStr.append(args[i].toLowerCase());
-		
-		String enteredColor = enteredColorStr.toString();
-		TextFormatting color = TextFormatting.getColorFormatting(enteredColor);
-
-		if (color == null) {
-			throw new CommandError("Can't find color: \""+enteredColor+"\"");
-		}
-		
-		byte newColor;
-		
-		newColor = (byte) color.id;
-		player.chatColor = newColor;
-		player.hadNicknameSet = true;
-		player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, newColor, true, player.isOperator()));
-		sender.sendMessage(TextFormatting.LIGHT_GRAY + "You changed your color to " + color + color.getNames()[0]);
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return false;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/color");
-		sender.sendMessage("/color <color>");
-	}
-
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/DeopCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/DeopCommand.java
deleted file mode 100644
index e37bc3777..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/DeopCommand.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.util.helper.UUIDHelper;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-
-public class DeopCommand extends ServerCommand{
-
-	public DeopCommand(MinecraftServer server) {
-		super(server, "deop");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 0) return false;
-		String name = args[0];
-
-		ServerPlayer player = (ServerPlayer) handler.getPlayer(name);
-		if(player != null) {
-			boolean wasOp = player.isOperator();
-
-			server.playerList.deopPlayer(player.uuid);
-			if (wasOp) {
-				handler.sendCommandFeedback(sender, "De-opping " + name);
-				handler.sendMessageToPlayer(player, TextFormatting.YELLOW + "You are no longer op!");
-				player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-			}
-		} else {
-			UUIDHelper.runConversionAction(name, (uuid) -> {
-				if (server.playerList.isOp(uuid)) {
-					server.playerList.deopPlayer(uuid);
-					handler.sendCommandFeedback(sender, "De-opping " + name);
-				} else {
-					handler.sendCommandFeedback(sender, name + " was not an operator");
-				}
-			}, (username) -> handler.sendCommandFeedback(sender,"Could not retrieve UUID of player '" + username + "'"));
-		}
-		
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/deop <Player>");
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/DifficultyCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/DifficultyCommand.java
deleted file mode 100644
index 10a0b7dfe..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/DifficultyCommand.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.core.world.World;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-
-public class DifficultyCommand extends ServerCommand{
-	
-	public static String[] diffString = new String[] {"Peaceful", "Easy", "Normal", "Hard"};
-	
-	public DifficultyCommand(MinecraftServer server) {
-		super(server, "difficulty", "dif");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 0) {
-			sender.sendMessage("The difficulty is "+diffString[handler.asServer().getWorld(0).getDifficulty().id()]);
-			return true;
-		}
-		if(args.length == 1) {
-			int diff = Integer.parseInt(args[0]);
-			
-			if(diff < 0 || diff > 3) throw new CommandError("Invalid Difficulty!");
-			
-			for(World world : server.dimensionWorlds) {
-				world.setDifficulty(diff, true);
-			}
-			server.difficulty = diff;
-			
-			handler.sendCommandFeedback(sender, "Set difficulty to "+diff);
-			
-			return true;
-		}
-		
-		return false;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		if(args == null || args.length == 0) return false;
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/difficulty");
-		if(sender.isAdmin()) {
-			sender.sendMessage("/difficulty <0-3>");
-		}
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/EmotesCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/EmotesCommand.java
deleted file mode 100644
index c925a40fe..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/EmotesCommand.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.core.net.ChatEmotes;
-
-import java.util.*;
-
-public class EmotesCommand
-    extends ServerCommand
-{
-    public EmotesCommand(MinecraftServer server) {
-        super(server, "emotes", ":");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args)
-    {
-        sender.sendMessage("Emotes:");
-
-        ArrayList<Map.Entry<String, Character>> entryList = new ArrayList<>(ChatEmotes.getEmotes().entrySet());
-        entryList.sort(Map.Entry.comparingByKey());
-
-        for (Map.Entry<String, Character> entry : entryList)
-        {
-            sender.sendMessage(" - " + TextFormatting.CYAN + entry.getKey().substring(1, entry.getKey().length() - 1) + TextFormatting.RESET + " -> " + entry.getValue());
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args)
-    {
-        return false;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender)
-    {
-        sender.sendMessage("/emotes");
-        sender.sendMessage("/:");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/KickCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/KickCommand.java
deleted file mode 100644
index 361692a6c..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/KickCommand.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-
-public class KickCommand extends ServerCommand {
-    public KickCommand(MinecraftServer server) {
-        super(server, "kick");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length != 1) return false;
-        String senderName = sender.getName();
-
-        String nameToKick = args[0];
-
-        ServerPlayer playerToKick = null;
-        for (ServerPlayer playerMP : server.playerList.playerEntities){
-            if(playerMP.username.equalsIgnoreCase(nameToKick))
-            {
-                playerToKick = playerMP;
-                break;
-            }
-        }
-
-        if(playerToKick != null)
-        {
-            playerToKick.playerNetServerHandler.kickPlayer("Kicked by admin");
-            sendNoticeToOps(senderName, "Kicking " + playerToKick.getDisplayName());
-        } else
-        {
-            server.logInfo("Can't find user " + nameToKick + ". No kick attempted.");
-        }
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/kick <username>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/ListCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/ListCommand.java
deleted file mode 100644
index 34ad7f6f1..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/ListCommand.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-
-public class ListCommand extends ServerCommand{
-
-	public ListCommand(MinecraftServer server) {
-		super(server, "list");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		int playerCount = server.playerList.playerEntities.size();
-		
-		String text = null;
-		
-		if(playerCount < 100) {
-			StringBuilder builder = new StringBuilder();
-			
-			for(int i = 0; i < server.playerList.playerEntities.size(); i++) {
-				if(i > 0) builder.append(", ");
-				builder.append(server.playerList.playerEntities.get(i).getDisplayName());
-			}
-			
-			text = playerCount + (playerCount == 1 ? " Player online: " : " Players online: ") + builder.toString();
-		}else {
-			text = playerCount + " Players online";
-		}
-		
-		sender.sendMessage(text);
-		
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return false;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/list");
-	}
-	
-	
-	
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/MeCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/MeCommand.java
deleted file mode 100644
index ab3c7fa2c..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/MeCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.server.MinecraftServer;
-
-public class MeCommand extends ServerCommand {
-	
-	public MeCommand(MinecraftServer server) {
-		super(server, "me");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 0) return false;
-		
-		String name = sender.getName();
-		
-		StringBuilder msg = new StringBuilder();
-		
-		for(int i=0; i < args.length; i++) {
-			if(i > 0)msg.append(' ');
-			msg.append(args[i]);
-		}
-		
-		handler.sendMessageToAllPlayers(TextFormatting.GRAY + " * " + name + " " + msg);
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return false;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/me <msg>");
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/NicknameCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/NicknameCommand.java
deleted file mode 100644
index fa3577ee9..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/NicknameCommand.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
-import net.minecraft.core.net.command.*;
-
-public class NicknameCommand extends ServerCommand
-{
-    public NicknameCommand(MinecraftServer server) {
-        super(server, "nickname", "nick");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length == 0) {
-            return false;
-        }
-
-
-        ServerPlayer player = (ServerPlayer) sender.getPlayer();
-
-        if (args[0].equalsIgnoreCase("set"))
-        {
-            if(!sender.isPlayer()) throw new CommandError("Must be used by a player!");
-            if (args.length == 1) throw new CommandError("Enter a nickname!");
-
-            StringBuilder enteredNicknameStr = new StringBuilder();
-            for (int i = 1; i < args.length; i++) enteredNicknameStr.append(args[i]).append(" ");
-
-            String enteredNickname = TextFormatting.removeAllFormatting(enteredNicknameStr.substring(0, enteredNicknameStr.length() - 1));
-            System.out.println(enteredNickname);
-            if (enteredNickname.length() > 16) enteredNickname = enteredNickname.substring(0, 16);
-
-            player.nickname = enteredNickname;
-            player.hadNicknameSet = true;
-            player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-            sender.sendMessage("You set your nickname to " + player.getDisplayName());
-            return true;
-        }
-        else if (args[0].equalsIgnoreCase("get"))
-        {
-            if(!sender.isPlayer()) throw new CommandError("Must be used by a player!");
-            if (args.length != 1) return false;
-            sender.sendMessage("Your nickname is " + player.getDisplayName());
-            return true;
-        }
-        else if (args[0].equalsIgnoreCase("clear"))
-        {
-            if(!sender.isPlayer()) throw new CommandError("Must be used by a player!");
-            if (args.length != 1) return false;
-            player.nickname = "";
-            player.hadNicknameSet = true;
-            player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-            sender.sendMessage("You cleared your nickname.");
-            return true;
-        }
-        else
-        {
-            player = (ServerPlayer)handler.getPlayer(args[0]);
-            if (player == null) throw new CommandError("Unknown username!");
-            if (args.length < 2) return false;
-            if (!sender.isAdmin() && !sender.isConsole()) return false;
-
-            if (args[1].equalsIgnoreCase("set"))
-            {
-                if (args.length < 3) return false;
-                StringBuilder enteredNicknameStr = new StringBuilder();
-                for (int i = 2; i < args.length; i++) enteredNicknameStr.append(args[i]).append(" ");
-
-                String enteredNickname = TextFormatting.removeAllFormatting(enteredNicknameStr.substring(0, enteredNicknameStr.length() - 1));
-                System.out.println(enteredNickname);
-                if (enteredNickname.length() > 16) enteredNickname = enteredNickname.substring(0, 16);
-
-                player.nickname = enteredNickname;
-                player.hadNicknameSet = true;
-                player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-                sender.sendMessage("Set " + player.username + "'s nickname to " + player.getDisplayName());
-                handler.sendMessageToPlayer(player, "Your nickname was set to " + player.getDisplayName());
-                return true;
-            }
-            else if (args[1].equalsIgnoreCase("get"))
-            {
-                if (args.length != 2) return false;
-                sender.sendMessage("" + player.username + "'s nickname is " + player.getDisplayName());
-                return true;
-            }
-            else if (args[1].equalsIgnoreCase("clear"))
-            {
-                if (args.length != 2) return false;
-                player.nickname = "";
-                player.hadNicknameSet = true;
-                player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-                sender.sendMessage("Cleared " + player.username + "'s nickname.");
-                handler.sendMessageToPlayer(player, "Your nickname was cleared.");
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return false;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/nickname set <value>");
-        sender.sendMessage("/nickname get");
-        sender.sendMessage("/nickname clear");
-        if (sender.isConsole() || sender.isAdmin())
-        {
-            sender.sendMessage("/nickname <username> set <value>");
-            sender.sendMessage("/nickname <username> get");
-            sender.sendMessage("/nickname <username> clear");
-        }
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/OpCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/OpCommand.java
deleted file mode 100644
index 731c07846..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/OpCommand.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.util.helper.UUIDHelper;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-
-public class OpCommand extends ServerCommand{
-
-	public OpCommand(MinecraftServer server) {
-		super(server, "op");
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		if(args.length == 0) return false;
-		String name = args[0];
-
-		ServerPlayer player = (ServerPlayer) handler.getPlayer(name);
-		if(player != null) {
-			server.playerList.opPlayer(player.uuid);
-			handler.sendCommandFeedback(sender, "Opping "+name);
-
-			handler.sendMessageToPlayer(player, TextFormatting.YELLOW + "You are now op!");
-			player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-		} else {
-			UUIDHelper.runConversionAction(name, (uuid) -> {
-				server.playerList.opPlayer(uuid);
-				handler.sendCommandFeedback(sender, "Opping "+name);
-			}, (username) -> handler.sendCommandFeedback(sender,"Could not retrieve UUID of player '" + username + "'"));
-		}
-
-
-		return true;
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		sender.sendMessage("/op <player>");
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/PardonCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/PardonCommand.java
deleted file mode 100644
index 39a15a414..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/PardonCommand.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.core.util.helper.UUIDHelper;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-
-public class PardonCommand extends ServerCommand {
-    public PardonCommand(MinecraftServer server) {
-        super(server, "pardon");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length != 1) return false;
-        String senderName = sender.getName();
-
-        String nameToPardon = args[0];
-
-        ServerPlayer player = server.playerList.getPlayerEntity(nameToPardon);
-        if(player != null) {
-            server.playerList.pardonPlayer(player.uuid);
-            sendNoticeToOps(senderName, "Pardoning " + nameToPardon);
-        } else {
-            UUIDHelper.runConversionAction(nameToPardon, (uuid) -> {
-                server.playerList.pardonPlayer(uuid);
-                sendNoticeToOps(senderName, "Pardoning " + nameToPardon);
-            }, (username) -> handler.sendCommandFeedback(sender,"Could not retrieve UUID of player '" + username + "'"));
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/pardon <username>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/PardonIpCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/PardonIpCommand.java
deleted file mode 100644
index cfdb32836..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/PardonIpCommand.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.server.MinecraftServer;
-
-public class PardonIpCommand extends ServerCommand {
-    public PardonIpCommand(MinecraftServer server) {
-        super(server, "pardon-ip");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length != 1) return false;
-        String senderName = sender.getName();
-
-        String nameToPardon = args[0];
-
-        server.playerList.pardonIP(nameToPardon);
-        sendNoticeToOps(senderName, "Pardoning ip " + nameToPardon);
-
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/pardon-ip <username>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/SaveCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/SaveCommand.java
deleted file mode 100644
index 2d95ff2b8..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/SaveCommand.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.world.WorldServer;
-
-public class SaveCommand extends ServerCommand {
-    public SaveCommand(MinecraftServer server) {
-        super(server, "save");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        String senderName = sender.getName();
-        if(args.length < 1)
-        {
-            return false;
-        }
-        String subCommand = args[0].toLowerCase();
-
-        switch (subCommand){
-            case "all":
-                sendNoticeToOps(senderName, "Forcing save..");
-                if(server.playerList != null) {
-                    server.playerList.savePlayerStates();
-                }
-                for(int i = 0; i < server.dimensionWorlds.length; i++) {
-                    WorldServer worldserver = server.dimensionWorlds[i];
-                    worldserver.saveWorld(true, null, i == 0);
-                }
-
-                sendNoticeToOps(senderName, "Save complete.");
-                return true;
-            case "on":
-                sendNoticeToOps(senderName, "Enabling level saving..");
-                for(int k = 0; k < server.dimensionWorlds.length; k++)
-                {
-                    WorldServer worldserver2 = server.dimensionWorlds[k];
-                    worldserver2.levelSaving = false;
-                }
-                return true;
-            case "off":
-                sendNoticeToOps(senderName, "Disabling level saving..");
-                for(int j = 0; j < server.dimensionWorlds.length; j++)
-                {
-                    WorldServer worldserver1 = server.dimensionWorlds[j];
-                    worldserver1.levelSaving = true;
-                }
-                return true;
-            case "interval":
-                if (args.length < 2) {
-                    sender.sendMessage("Current save interval is " + server.propertyManager.getIntProperty("autosaveInterval", server.autoSaveInterval));
-                    return true;
-                }
-                int interval = Integer.parseInt(args[1]);
-                server.propertyManager.setProperty("autosaveInterval", interval);
-                server.autoSaveInterval = interval;
-                sendNoticeToOps(senderName, "Setting save interval to " + interval);
-                return true;
-            case "amount":
-                if (args.length < 2) {
-                    sender.sendMessage("Current chunks saved per autosave is " + server.propertyManager.getIntProperty("maxChunksSavedPerAutosave", server.chunksSavedPerAutosave));
-                    return true;
-                }
-                int amount = Integer.parseInt(args[1]);
-                server.propertyManager.setProperty("maxChunksSavedPerAutosave", amount);
-                server.chunksSavedPerAutosave = amount;
-                sendNoticeToOps(senderName, "Setting max chunks saved to " + amount);
-                return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/save on");
-        sender.sendMessage("/save off");
-        sender.sendMessage("/save all");
-        sender.sendMessage("/save interval");
-        sender.sendMessage("/save interval <seconds>");
-        sender.sendMessage("/save amount");
-        sender.sendMessage("/save amount <chunks>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/SayCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/SayCommand.java
deleted file mode 100644
index 413ab441a..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/SayCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.packet.ChatPacket;
-import net.minecraft.server.MinecraftServer;
-
-public class SayCommand extends ServerCommand {
-    public SayCommand(MinecraftServer server) {
-        super(server, "say");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length < 1) return false;
-
-        String senderName = sender.getName();
-
-        StringBuilder messageBuilder = new StringBuilder();
-        for (String arg : args){
-            messageBuilder.append(arg).append(" ");
-        }
-        String message = messageBuilder.toString().trim();
-
-        MinecraftServer.LOGGER.info("[" + senderName + "] " + message);
-        server.playerList.sendPacketToAllPlayers(new ChatPacket(TextFormatting.PINK + "[Server] " + message));
-
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/say <message>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/ScoreCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/ScoreCommand.java
deleted file mode 100644
index af1d06567..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/ScoreCommand.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-
-public class ScoreCommand extends ServerCommand
-{
-
-    public ScoreCommand(MinecraftServer server) {
-        super(server, "score");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length < 2) return false;
-
-        ServerPlayer player = (ServerPlayer)handler.getPlayer(args[0]);
-        if (player == null) return false;
-
-        if (args[1].equalsIgnoreCase("set"))
-        {
-            if (args.length != 3) return false;
-
-            int newScore = Integer.parseInt(args[2]);
-
-            player.score = newScore;
-            server.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-            sender.sendMessage("Set " + player.getDisplayName() + TextFormatting.WHITE + "'s score to " + player.score);
-            handler.sendMessageToPlayer(player, "Your score was set to " + player.score);
-            return true;
-        }
-        if (args[1].equalsIgnoreCase("get"))
-        {
-            sender.sendMessage(player.getDisplayName() + "\247f's score is " + player.score);
-            return true;
-        }
-        if (args[1].equalsIgnoreCase("reset"))
-        {
-            player.score = 0;
-            server.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
-            sender.sendMessage("Set " + player.getDisplayName() + TextFormatting.WHITE + "'s score to " + player.score);
-            handler.sendMessageToPlayer(player, "Your score was set to " + player.score);
-            return true;
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/score <username> get");
-        sender.sendMessage("/score <username> set <value>");
-        sender.sendMessage("/score <username> reset");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/ScoreboardCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/ScoreboardCommand.java
deleted file mode 100644
index 12fdc4110..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/ScoreboardCommand.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ScoreboardCommand extends ServerCommand {
-    public ScoreboardCommand(MinecraftServer server) {
-        super(server, "scoreboard");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        StringBuilder scoreBoardMessage = new StringBuilder();
-        List<ServerPlayer> players = new ArrayList<>(server.playerList.playerEntities);
-
-        players.sort((o1, o2) -> o2.score - o1.score);
-
-        for (int i = 0; i < players.size(); i++)
-        {
-            if (i > 0)
-            {
-                scoreBoardMessage.append(", ");
-            }
-            ServerPlayer player = players.get(i);
-            scoreBoardMessage.append(player.getDisplayName()).append(": ").append(TextFormatting.YELLOW).append(player.score).append("pts").append(TextFormatting.WHITE);
-        }
-        sender.sendMessage(scoreBoardMessage.toString());
-        return true;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return false;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/scoreboard");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/StopCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/StopCommand.java
deleted file mode 100644
index b951f4f16..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/StopCommand.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-
-public class StopCommand extends ServerCommand{
-
-	public StopCommand(MinecraftServer server) {
-		super(server, "stop");
-	}
-
-	@Override
-	public boolean opRequired(String[] args) {
-		return true;
-	}
-
-	@Override
-	public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-		handler.sendCommandFeedback(sender, "Stopping Server!");
-		if(server.playerList != null) {
-			server.playerList.savePlayerStates();
-		}
-		for(int i = 0; i < server.dimensionWorlds.length; i++) {
-			server.dimensionWorlds[i].saveWorld(true, null, i == 0);
-		}
-		server.initiateShutdown();
-		return true;
-	}
-
-	@Override
-	public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-		
-	}
-
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/WhitelistCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/WhitelistCommand.java
deleted file mode 100644
index 560e608a2..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/WhitelistCommand.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-import net.minecraft.core.util.helper.UUIDHelper;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-
-import java.util.Set;
-import java.util.UUID;
-
-public class WhitelistCommand extends ServerCommand {
-    public WhitelistCommand(MinecraftServer server) {
-        super(server, "whitelist");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        String senderName = sender.getName();
-        if(args.length < 1)
-        {
-            return false;
-        }
-        String subCommand = args[0].toLowerCase();
-
-        switch (subCommand){
-            case "on":
-                sendNoticeToOps(senderName, "Turned on white-listing");
-                server.propertyManager.setProperty("white-list", true);
-                return true;
-            case "off":
-                sendNoticeToOps(senderName, "Turned off white-listing");
-                server.propertyManager.setProperty("white-list", false);
-                return true;
-            case "list":
-                Set<UUID> set = server.playerList.getWhitelist();
-                StringBuilder builder = new StringBuilder();
-                for (UUID uuid : set) {
-                    builder.append("\"").append(uuid).append("\"").append(", ");
-                }
-
-                String message = builder.toString();
-                if (message.endsWith(", ")){
-                    message = message.substring(0, message.length()-2);
-                }
-
-                sender.sendMessage("White-listed players: " + message);
-                return true;
-            case "add":{
-                if (args.length != 2) return false;
-                String nameToAdd = args[1].toLowerCase();
-
-                ServerPlayer player = server.playerList.getPlayerEntity(nameToAdd);
-                if(player != null) {
-                    server.playerList.addToWhiteList(player.uuid);
-                    sendNoticeToOps(senderName, "Added " + nameToAdd + " to white-list");
-                } else {
-                    UUIDHelper.runConversionAction(nameToAdd, (uuid) -> {
-                        server.playerList.addToWhiteList(uuid);
-                        sendNoticeToOps(senderName, "Added " + nameToAdd + " to white-list");
-                    }, (username) -> handler.sendCommandFeedback(sender,"Could not retrieve UUID of player '" + username + "'"));
-                }
-                return true;
-            }
-            case "remove": {
-                if (args.length != 2) return false;
-                String nameToRemove = args[1].toLowerCase();
-
-                ServerPlayer player = server.playerList.getPlayerEntity(nameToRemove);
-                if(player != null) {
-                    server.playerList.removeFromWhiteList(player.uuid);
-                    sendNoticeToOps(senderName, "Removed " + nameToRemove + " from white-list");
-                } else {
-                    UUIDHelper.runConversionAction(nameToRemove, (uuid) -> {
-                        server.playerList.removeFromWhiteList(uuid);
-                        sendNoticeToOps(senderName, "Removed " + nameToRemove + " from white-list");
-                    }, (username) -> handler.sendCommandFeedback(sender,"Could not retrieve UUID of player '" + username + "'"));
-                }
-                return true;
-            }
-            case "reload":
-                server.playerList.reloadWhiteList();
-                sendNoticeToOps(senderName, "Reloaded white-list from file");
-                return true;
-        }
-        return false;
-    }
-    @Override
-    public boolean opRequired(String[] args) {
-        return true;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/whitelist on");
-        sender.sendMessage("/whitelist off");
-        sender.sendMessage("/whitelist list");
-        sender.sendMessage("/whitelist add <player>");
-        sender.sendMessage("/whitelist remove <player>");
-        sender.sendMessage("/whitelist reload");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/servercommands/WhoisCommand.java b/src/main/java/net/minecraft/core/net/command/servercommands/WhoisCommand.java
deleted file mode 100644
index 57e6cc5ce..000000000
--- a/src/main/java/net/minecraft/core/net/command/servercommands/WhoisCommand.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package net.minecraft.core.net.command.servercommands;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.entity.player.ServerPlayer;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.CommandHandler;
-import net.minecraft.core.net.command.CommandSender;
-import net.minecraft.core.net.command.ServerCommand;
-
-public class WhoisCommand extends ServerCommand {
-    public WhoisCommand(MinecraftServer server) {
-        super(server, "whois", "who");
-    }
-
-    @Override
-    public boolean execute(CommandHandler handler, CommandSender sender, String[] args) {
-        if (args.length == 0) {
-            return false;
-        }
-
-        StringBuilder enteredNicknameStr = new StringBuilder();
-        for (int i = 0; i < args.length; i++) enteredNicknameStr.append(args[i]).append(" ");
-
-        String enteredNickname = enteredNicknameStr.substring(0, enteredNicknameStr.length() - 1);
-        if (enteredNickname.length() > 16) enteredNickname = enteredNickname.substring(0, 16);
-
-        for (ServerPlayer player : server.playerList.playerEntities)
-        {
-            String name = TextFormatting.removeAllFormatting(player.getDisplayName());
-            if (name.equals(enteredNickname))
-            {
-                sender.sendMessage(player.getDisplayName() + TextFormatting.WHITE + "'s username is " + player.username);
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean opRequired(String[] args) {
-        return false;
-    }
-
-    @Override
-    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
-        sender.sendMessage("/whois <nickname>");
-    }
-}
diff --git a/src/main/java/net/minecraft/core/net/command/util/BeautifulNbt.java b/src/main/java/net/minecraft/core/net/command/util/BeautifulNbt.java
new file mode 100644
index 000000000..6907afe06
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/util/BeautifulNbt.java
@@ -0,0 +1,76 @@
+package net.minecraft.core.net.command.util;
+
+import com.mojang.nbt.*;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class BeautifulNbt {
+    public static String toBeautifulNbt(@NotNull CompoundTag nbt) {
+        StringBuilder builder = new StringBuilder("{");
+        boolean comma = false;
+        for (Tag<?> tag : nbt.getValue().values()) {
+            if (comma) builder.append(", ");
+            builder.append(tag.getTagName()).append(": ").append(element(tag instanceof CompoundTag ? tag : tag.getValue()));
+            comma = true;
+        }
+        return builder.append("}").toString();
+    }
+
+    private static String element(Object o) {
+        if (o instanceof byte[] || o instanceof short[] || o instanceof double[] || o instanceof List<?>) {
+            return collection(o);
+        }
+        if (o instanceof Byte) {
+            return o + "b";
+        }
+        if (o instanceof Short) {
+            return o + "s";
+        }
+        if (o instanceof Long) {
+            return o + "l";
+        }
+        if (o instanceof Float) {
+            return o + "f";
+        }
+        if (o instanceof String) {
+            return "\"" + o + "\"";
+        }
+        return o instanceof CompoundTag ? toBeautifulNbt((CompoundTag) o) : o.toString();
+    }
+
+    private static String collection(Object o) {
+        StringBuilder result = new StringBuilder("[");
+        boolean comma = false;
+        if (o instanceof byte[]) {
+            result.append("B; ");
+            for (byte element : ((byte[])o)) {
+                if (comma) result.append(", ");
+                result.append(element(element));
+                comma = true;
+            }
+        } else if (o instanceof short[]) {
+            result.append("S; ");
+            for (short element : ((short[])o)) {
+                if (comma) result.append(", ");
+                result.append(element(element));
+                comma = true;
+            }
+        } else if (o instanceof double[]) {
+            result.append("D; ");
+            for (double element : ((double[])o)) {
+                if (comma) result.append(", ");
+                result.append(element(element));
+                comma = true;
+            }
+        } else if (o instanceof List<?>) {
+            //noinspection unchecked
+            for (Tag<?> element : ((List<Tag<?>>)o)) {
+                if (comma) result.append(", ");
+                result.append(element(element.getValue()));
+                comma = true;
+            }
+        }
+        return result.append("]").toString();
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java b/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
new file mode 100644
index 000000000..d459e8ae3
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
@@ -0,0 +1,160 @@
+package net.minecraft.core.net.command.util;
+
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import com.mojang.nbt.CompoundTag;
+import com.mojang.nbt.Tag;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.EntityDispatcher;
+import net.minecraft.core.entity.ItemEntity;
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.helpers.IntegerCoordinates;
+import net.minecraft.core.util.helper.LoggedPrintStream;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.WorldSource;
+import net.minecraft.core.world.generate.feature.WorldFeature;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+public class CommandHelper {
+    public static final Map<String, Class<? extends WorldFeature>> WORLD_FEATURES = new HashMap<>();
+
+    public static final BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> NO_SUGGESTIONS = (builder, consumer) -> builder.buildFuture();
+    public static final BiFunction<SuggestionsBuilder, Consumer<SuggestionsBuilder>, CompletableFuture<Suggestions>> SUGGEST_BLOCKS = (builder, consumer) -> {
+        String remaining = builder.getRemaining().toLowerCase(Locale.ROOT);
+        for (Block block : Block.blocksList) {
+            if (block == null) continue;
+            CommandHelper.getStringToSuggest(block.getKey(), remaining).ifPresent(builder::suggest);
+        }
+        return builder.buildFuture();
+    };
+
+    public static CompletableFuture<Suggestions> suggest(String string, SuggestionsBuilder suggestionsBuilder) {
+        String stringRemaining = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
+        if (matchesSubStr(stringRemaining, string.toLowerCase(Locale.ROOT))) suggestionsBuilder.suggest(string);
+        return suggestionsBuilder.buildFuture();
+    }
+
+    public static CompletableFuture<Suggestions> suggest(Iterable<String> iterable, SuggestionsBuilder suggestionsBuilder) {
+        String string = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
+        for (String string2 : iterable) {
+            if (!matchesSubStr(string, string2.toLowerCase(Locale.ROOT))) continue;
+            suggestionsBuilder.suggest(string2);
+        }
+        return suggestionsBuilder.buildFuture();
+    }
+
+    public static boolean matchesSubStr(String string, String string2) {
+        int i = 0;
+        while (!string2.startsWith(string, i)) {
+            if ((i = string2.indexOf(95, i)) < 0) {
+                return false;
+            }
+            ++i;
+        }
+        return true;
+    }
+
+    public static Optional<String> getStringToSuggest(String checkedString, String input) {
+        if (checkedString.toLowerCase(Locale.ROOT).startsWith(input.toLowerCase(Locale.ROOT))) {
+            return Optional.of(checkedString);
+        } else {
+            if (checkedString.contains(":") && checkedString.length() - 1 >= checkedString.indexOf(':') + 1) {
+                if (checkedString.toLowerCase(Locale.ROOT).substring(checkedString.indexOf(':') + 1).startsWith(input.toLowerCase(Locale.ROOT)))
+                    return Optional.of(checkedString.substring(checkedString.indexOf(':') + 1));
+                else return Optional.empty();
+            } else if (checkedString.contains(".") && checkedString.length() - 1 >= checkedString.indexOf('.') + 1 && checkedString.toLowerCase(Locale.ROOT).substring(checkedString.indexOf('.') + 1).startsWith(input.toLowerCase(Locale.ROOT))) {
+                return Optional.of(checkedString.substring(checkedString.indexOf('.') + 1));
+            }
+        }
+        return Optional.empty();
+    }
+
+    public static boolean matchesKeyString(String checkedString, String input) {
+        if (checkedString.equals(input)) {
+            return true;
+        }
+        if (checkedString.contains(":") && checkedString.length() - 1 >= checkedString.indexOf(':') + 1) {
+            return checkedString.substring(checkedString.indexOf(':') + 1).equals(input);
+        }
+        return checkedString.contains(".") && checkedString.length() - 1 >= checkedString.indexOf('.') + 1 && checkedString.substring(checkedString.indexOf('.') + 1).equals(input);
+    }
+
+    public static String getEntityName(Entity entity) {
+        if (entity instanceof Mob) {
+            if (!LoggedPrintStream.removeColorCodes(((Mob) entity).getDisplayName()).isEmpty()) {
+                return LoggedPrintStream.removeColorCodes(((Mob) entity).getDisplayName());
+            }
+        } else if (entity instanceof ItemEntity && ((ItemEntity) entity).item != null) {
+            return LoggedPrintStream.removeColorCodes(((ItemEntity) entity).item.getDisplayName());
+        }
+        return EntityDispatcher.getEncodeId(entity);
+    }
+
+    public static int getVolume(CommandSource source, IntegerCoordinates first, IntegerCoordinates second) throws CommandSyntaxException {
+        return (int) (MathHelper.abs(first.getX(source) - second.getX(source)) * MathHelper.abs(first.getY(source, true) - second.getY(source, true)) * MathHelper.abs(first.getZ(source) - second.getZ(source)));
+    }
+
+    public static float linearInterpolation(float factor, float min, float max) {
+        return min + factor * (max - min);
+    }
+
+    public static boolean blockEntitiesAreEqual(CompoundTag first, CompoundTag second) {
+        if (first == null && second == null) return true;
+        if (first == null || second == null) return false;
+        for (Map.Entry<String, Tag<?>> entry : first.getValue().entrySet()) {
+            if (entry.getKey().equals("x") || entry.getKey().equals("y") || entry.getKey().equals("z")) continue;
+            if (!second.getValue().containsKey(entry.getKey()) || (second.getValue().get(entry.getKey()) != entry.getValue() && !second.getValue().get(entry.getKey()).equals(entry.getValue()) && !second.getValue().get(entry.getKey()).getValue().equals(entry.getValue().getValue()))) {
+                return false;
+            }
+        }
+        for (Map.Entry<String, Tag<?>> entry : second.getValue().entrySet()) {
+            if (entry.getKey().equals("x") || entry.getKey().equals("y") || entry.getKey().equals("z")) continue;
+            if (!first.getValue().containsKey(entry.getKey()) || (first.getValue().get(entry.getKey()) != entry.getValue() && !first.getValue().get(entry.getKey()).equals(entry.getValue()) && !first.getValue().get(entry.getKey()).getValue().equals(entry.getValue().getValue()))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static void setBlockEntity(WorldSource world, int x, int y, int z, CompoundTag tag) {
+        if (tag == null || world.getBlockEntity(x, y, z) == null) return;
+        tag.putInt("x", x);
+        tag.putInt("y", y);
+        tag.putInt("z", z);
+        world.getBlockEntity(x, y, z).readFromNBT(tag);
+    }
+
+    public static void setBlockEntity(WorldSource world, int x, int y, int z, BlockEntity blockEntity) {
+        setBlockEntity(world, x, y, z, tagFrom(blockEntity));
+    }
+
+    public static CompoundTag tagFrom(BlockEntity blockEntity) {
+        CompoundTag tag = new CompoundTag();
+        if (blockEntity != null) blockEntity.writeToNBT(tag);
+        return tag;
+    }
+
+    public static void init() {
+        try {
+            for (Class<?> aClass : CommandReflectionHelper.getAllClasses((className) -> className.startsWith("net.minecraft.core.world.generate.feature"))) {
+                if (WorldFeature.class.isAssignableFrom(aClass) && aClass != WorldFeature.class) {
+                    Class<? extends WorldFeature> worldGenClass = (Class<? extends WorldFeature>) aClass;
+                    WORLD_FEATURES.put(aClass.getSimpleName().substring(12), worldGenClass);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/util/CommandReflectionHelper.java b/src/main/java/net/minecraft/core/net/command/util/CommandReflectionHelper.java
new file mode 100644
index 000000000..00ba01ef8
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/util/CommandReflectionHelper.java
@@ -0,0 +1,61 @@
+package net.minecraft.core.net.command.util;
+
+import com.b100.utils.FileUtils;
+import com.b100.utils.interfaces.Condition;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class CommandReflectionHelper {
+    public static List<Class<?>> getAllClasses(Condition<String> classNameCondition) {
+        String[] classPathEntries;
+        ArrayList classes = new ArrayList();
+        for (String classPathEntry : classPathEntries = System.getProperty("java.class.path").split(";")) {
+            File file = new File(classPathEntry);
+            if (file.isDirectory()) {
+                int l = file.getAbsolutePath().length() + 1;
+                List<File> files = FileUtils.getAllFiles(file);
+                for (File file2 : files) {
+                    if (!file2.getName().endsWith(".class")) continue;
+                    tryAddClass(classes, file2.getAbsolutePath().substring(l), classNameCondition);
+                }
+            }
+            if (!file.isFile()) continue;
+            try {
+                ZipFile zip = new ZipFile(file);
+                Enumeration<? extends ZipEntry> entries = zip.entries();
+                while (entries.hasMoreElements()) {
+                    String entry = ((Object)entries.nextElement()).toString();
+                    if (!entry.endsWith(".class")) continue;
+                    tryAddClass(classes, entry, classNameCondition);
+                }
+                zip.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return classes;
+    }
+
+    private static void tryAddClass(List<Class<?>> classes, String fileName, Condition<String> classNameCondition) {
+        String className = fileName.substring(0, fileName.length() - 6);
+        className = className.replace('\\', '.');
+        className = className.replace('/', '.');
+        if (classNameCondition == null || classNameCondition.isTrue(className)) {
+            Class<?> clazz = null;
+            try {
+                clazz = Class.forName(className);
+            } catch (Throwable e) {
+                System.err.println(e.getClass().getName() + ": " + e.getMessage());
+            }
+            if (clazz != null) {
+                classes.add(clazz);
+            }
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/util/ConcatIterable.java b/src/main/java/net/minecraft/core/net/command/util/ConcatIterable.java
new file mode 100644
index 000000000..515e90142
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/util/ConcatIterable.java
@@ -0,0 +1,48 @@
+package net.minecraft.core.net.command.util;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Iterator;
+
+public class ConcatIterable<T> implements Iterable<T> {
+    private final Iterable<T> first;
+    private final Iterable<T> second;
+
+    public ConcatIterable(Iterable<T> first, Iterable<T> second) {
+        this.first = first;
+        this.second = second;
+    }
+
+    @Override
+    public @NotNull Iterator<T> iterator() {
+        return new Iterator<T>() {
+            private final Iterator<T> firstIterator = first.iterator();
+            private final Iterator<T> secondIterator = second.iterator();
+            private boolean firstIteratorActive = true;
+
+            @Override
+            public boolean hasNext() {
+                if (firstIteratorActive) {
+                    if (firstIterator.hasNext()) {
+                        return true;
+                    } else {
+                        firstIteratorActive = false;
+                    }
+                }
+                return secondIterator.hasNext();
+            }
+
+            @Override
+            public T next() {
+                if (firstIteratorActive) {
+                    if (firstIterator.hasNext()) {
+                        return firstIterator.next();
+                    } else {
+                        firstIteratorActive = false;
+                    }
+                }
+                return secondIterator.next();
+            }
+        };
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/util/Iterables.java b/src/main/java/net/minecraft/core/net/command/util/Iterables.java
new file mode 100644
index 000000000..daec97807
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/util/Iterables.java
@@ -0,0 +1,25 @@
+package net.minecraft.core.net.command.util;
+
+public abstract class Iterables {
+    public static <T> T getLast(Iterable<? extends T> iterable) {
+        if (iterable instanceof java.util.List) {
+            java.util.List<? extends T> list = (java.util.List<? extends T>) iterable;
+            if (list.isEmpty()) {
+                throw new java.util.NoSuchElementException();
+            }
+            return list.get(list.size() - 1);
+        } else {
+            java.util.Iterator<? extends T> iterator = iterable.iterator();
+            if (!iterator.hasNext()) {
+                throw new java.util.NoSuchElementException();
+            }
+            T last = iterator.next();
+            do {
+                if (!iterator.hasNext()) {
+                    return last;
+                }
+                last = iterator.next();
+            } while (true);
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/util/NbtHelper.java b/src/main/java/net/minecraft/core/net/command/util/NbtHelper.java
new file mode 100644
index 000000000..487d2eecd
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/util/NbtHelper.java
@@ -0,0 +1,229 @@
+package net.minecraft.core.net.command.util;
+
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.nbt.*;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class NbtHelper {
+    private static final Pattern DOUBLE_PATTERN_NO_SUFFIX = Pattern.compile("[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?", Pattern.CASE_INSENSITIVE);
+    private static final Pattern DOUBLE_PATTERN = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", Pattern.CASE_INSENSITIVE);
+    private static final Pattern FLOAT_PATTERN = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f", Pattern.CASE_INSENSITIVE);
+    private static final Pattern BYTE_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)b", Pattern.CASE_INSENSITIVE);
+    private static final Pattern LONG_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)l", Pattern.CASE_INSENSITIVE);
+    private static final Pattern SHORT_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)s", Pattern.CASE_INSENSITIVE);
+    private static final Pattern INT_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)");
+
+    public static CompoundTag parseNbt(String string) throws CommandSyntaxException {
+        return parseNbt(new StringReader(string));
+    }
+
+    public static CompoundTag parseNbt(StringReader reader) throws CommandSyntaxException {
+        CompoundTag tag = new CompoundTag();
+        if (!reader.canRead() || reader.peek() != '{') return tag;
+        int cursor = reader.getCursor();
+        reader.skip();
+        reader.skipWhitespace();
+        while (reader.canRead() && reader.peek() != '}') {
+            String key = reader.readString();
+            reader.skipWhitespace();
+            if (!reader.canRead() || reader.peek() != ':') {
+                reader.setCursor(cursor);
+                throw CommandExceptions.expectedTagKeyValue().createWithContext(reader, key);
+            }
+            reader.skip();
+            reader.skipWhitespace();
+            Tag<?> value = parseTag(reader);
+            tag.put(key, value);
+            reader.skipWhitespace();
+            if (reader.canRead() && reader.peek() == ',') {
+                reader.skip();
+                reader.skipWhitespace();
+                continue;
+            }
+            if (reader.canRead() && reader.peek() == '}') break;
+            throw CommandExceptions.expectedEndOfTag().createWithContext(reader);
+        }
+        if (!reader.canRead()) throw CommandExceptions.expectedEndOfTag().createWithContext(reader);
+        reader.skip();
+        return tag;
+    }
+
+    public static Tag<?> parseTag(StringReader reader) throws CommandSyntaxException {
+        if (!reader.canRead()) throw CommandExceptions.incomplete().create();
+        if (reader.peek() == '{') {
+            return parseNbt(reader);
+        } else if (reader.peek() == '[') {
+            reader.skip();
+            return collection(reader);
+        }
+        return type(reader.readString());
+    }
+
+    private static Tag<?> collection(StringReader reader) throws CommandSyntaxException {
+        reader.skipWhitespace();
+        if (!reader.canRead()) throw CommandExceptions.incomplete().create();
+        if (reader.peek() == 'B') {
+            reader.skip();
+            reader.skipWhitespace();
+            if (!reader.canRead()) throw CommandExceptions.incomplete().create();
+            if (reader.peek() == ']') return new ByteArrayTag();
+            else if (reader.peek() == ';') {
+                reader.skip();
+                List<Byte> bytes = new ArrayList<>();
+                while (reader.canRead() && reader.peek() != ']') {
+                    reader.skipWhitespace();
+                    String byteAsString = reader.readString();
+                    if (!BYTE_PATTERN.matcher(byteAsString).matches()) throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.readerExpectedSymbol().create("byte");
+                    byte parsedByte = Byte.parseByte(byteAsString.substring(0, byteAsString.length() - 1));
+                    bytes.add(parsedByte);
+                    reader.skipWhitespace();
+                    if (!reader.canRead() || reader.peek() != ',') break;
+                    reader.skip();
+                }
+                reader.skipWhitespace();
+                if (reader.canRead() && reader.peek() == ']') {
+                    reader.skip();
+                    return new ByteArrayTag(byteListToArray(bytes));
+                }
+                throw CommandExceptions.expectedEndOfTag().create();
+            }
+        } else if (reader.peek() == 'S') {
+            reader.skip();
+            reader.skipWhitespace();
+            if (!reader.canRead()) throw CommandExceptions.incomplete().create();
+            if (reader.peek() == ']') {
+                reader.skip();
+                return new ShortArrayTag();
+            }
+            else if (reader.peek() == ';') {
+                reader.skip();
+                List<Short> shorts = new ArrayList<>();
+                while (reader.canRead() && reader.peek() != ']') {
+                    reader.skipWhitespace();
+                    String shortAsString = reader.readString();
+                    if (!SHORT_PATTERN.matcher(shortAsString).matches()) throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.readerExpectedSymbol().create("short");
+                    short parsedShort = Short.parseShort(shortAsString.substring(0, shortAsString.length() - 1));
+                    shorts.add(parsedShort);
+                    reader.skipWhitespace();
+                    if (!reader.canRead() || reader.peek() != ',') break;
+                    reader.skip();
+                }
+                reader.skipWhitespace();
+
+                if (reader.canRead() && reader.peek() == ']') {
+                    reader.skip();
+                    return new ShortArrayTag(shortListToArray(shorts));
+                }
+                else throw CommandExceptions.expectedEndOfTag().create();
+            }
+        } else if (reader.peek() == 'D') {
+            reader.skip();
+            reader.skipWhitespace();
+            if (!reader.canRead()) throw CommandExceptions.incomplete().create();
+            if (reader.peek() == ']') {
+                reader.skip();
+                return new DoubleArrayTag();
+            }
+            else if (reader.peek() == ';') {
+                reader.skip();
+                List<Double> doubles = new ArrayList<>();
+                while (reader.canRead() && reader.peek() != ']') {
+                    reader.skipWhitespace();
+                    String doubleAsString = reader.readString();
+                    double parsedDouble;
+                    if (DOUBLE_PATTERN.matcher(doubleAsString).matches()) {
+                        parsedDouble = Double.parseDouble(doubleAsString.substring(0, doubleAsString.length() - 1));
+                    } else if (DOUBLE_PATTERN_NO_SUFFIX.matcher(doubleAsString).matches()) {
+                        parsedDouble = Double.parseDouble(doubleAsString);
+                    }
+                    else throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.readerExpectedDouble().create();
+                    doubles.add(parsedDouble);
+                    reader.skipWhitespace();
+                    if (!reader.canRead() || reader.peek() != ',') break;
+                    reader.skip();
+                }
+                reader.skipWhitespace();
+                if (reader.canRead() && reader.peek() == ']') {
+                    reader.skip();
+                    return new DoubleArrayTag(doubles.stream().mapToDouble(Double::doubleValue).toArray());
+                }
+                else throw CommandExceptions.expectedEndOfTag().create();
+            }
+        } else {
+            List<Tag<?>> tags = new ArrayList<>();
+            while (reader.canRead() && reader.peek() != ']') {
+                reader.skipWhitespace();
+                tags.add(parseTag(reader));
+                reader.skipWhitespace();
+                if (!reader.canRead() || reader.peek() != ',') break;
+                reader.skip();
+            }
+            reader.skipWhitespace();
+            if (reader.canRead() && reader.peek() == ']') {
+                reader.skip();
+                return new ListTag(tags);
+            }
+            else throw CommandExceptions.expectedEndOfTag().create();
+        }
+        throw CommandExceptions.incomplete().create();
+    }
+
+    private static short[] shortListToArray(List<Short> shorts) {
+        short[] arr = new short[shorts.size()];
+
+        for (int i = 0; i < shorts.size(); i++) {
+            arr[i] = shorts.get(i);
+        }
+
+        return arr;
+    }
+
+    private static byte[] byteListToArray(List<Byte> bytes) {
+        byte[] arr = new byte[bytes.size()];
+
+        for (int i = 0; i < bytes.size(); i++) {
+            arr[i] = bytes.get(i);
+        }
+
+        return arr;
+    }
+
+    private static Tag<?> type(String string) {
+        try {
+            if ("true".equalsIgnoreCase(string)) {
+                return new ByteTag((byte) 1);
+            }
+            if ("false".equalsIgnoreCase(string)) {
+                return new ByteTag((byte) 0);
+            }
+            if (BYTE_PATTERN.matcher(string).matches()) {
+                return new ByteTag(Byte.parseByte(string.substring(0, string.length() - 1)));
+            }
+            if (SHORT_PATTERN.matcher(string).matches()) {
+                return new ShortTag(Short.parseShort(string.substring(0, string.length() - 1)));
+            }
+            if (INT_PATTERN.matcher(string).matches()) {
+                return new IntTag(Integer.parseInt(string));
+            }
+            if (LONG_PATTERN.matcher(string).matches()) {
+                return new LongTag(Long.parseLong(string.substring(0, string.length() - 1)));
+            }
+            if (FLOAT_PATTERN.matcher(string).matches()) {
+                return new FloatTag(Float.parseFloat(string.substring(0, string.length() - 1)));
+            }
+            if (DOUBLE_PATTERN.matcher(string).matches()) {
+                return new DoubleTag(Double.parseDouble(string.substring(0, string.length() - 1)));
+            }
+            if (DOUBLE_PATTERN_NO_SUFFIX.matcher(string).matches()) {
+                return new DoubleTag(Double.parseDouble(string));
+            }
+        } catch (NumberFormatException ignored) {
+        }
+        return new StringTag(string);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/net/handler/PacketHandler.java b/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
index 842280c2c..cffa6be0f 100644
--- a/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
+++ b/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
@@ -372,4 +372,12 @@ public abstract class PacketHandler
     public void handleCustomPayload(CustomPayloadPacket packet) {
     	handleInvalidPacket(packet);
     }
+
+    public void handleCommandManagerPacket(CommandManagerPacket packet) {
+        handleInvalidPacket(packet);
+    }
+
+    public void handleRequestCommandManagerPacket(RequestCommandManagerPacket packet) {
+        handleInvalidPacket(packet);
+    }
 }
diff --git a/src/main/java/net/minecraft/core/net/packet/CommandManagerPacket.java b/src/main/java/net/minecraft/core/net/packet/CommandManagerPacket.java
new file mode 100644
index 000000000..5046af2d5
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/packet/CommandManagerPacket.java
@@ -0,0 +1,189 @@
+package net.minecraft.core.net.packet;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.context.CommandContextBuilder;
+import com.mojang.brigadier.context.ParsedArgument;
+import com.mojang.brigadier.context.SuggestionContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestion;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import com.mojang.brigadier.tree.CommandNode;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import net.minecraft.core.net.command.CommandManagerPacketKeys;
+import net.minecraft.core.net.command.CommandManager;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.handler.PacketHandler;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+
+public class CommandManagerPacket extends Packet {
+    private CommandDispatcher<CommandSource> dispatcher;
+    private CommandSource source;
+    private String text;
+    private int cursor;
+
+    public JsonObject suggestions;
+
+    public CommandManagerPacket(CommandDispatcher<CommandSource> dispatcher, CommandSource source, String text, int cursor) {
+        this.dispatcher = dispatcher;
+        this.source = source;
+        this.text = text;
+        this.cursor = cursor;
+    }
+
+    public CommandManagerPacket() {
+    }
+
+    @Override
+    public void read(DataInputStream dis) throws IOException {
+        String str = dis.readUTF();
+        this.suggestions = JsonParser.parseString(str).getAsJsonObject();
+    }
+
+    @Override
+    public void write(DataOutputStream dos) throws IOException {
+        String str = getDispatcherSuggestions(this.dispatcher, this.source, this.text, this.cursor).toString();
+        dos.writeUTF(str);
+    }
+
+    private static JsonObject getDispatcherSuggestions(CommandDispatcher<CommandSource> dispatcher, CommandSource source, String text, int cursor) {
+        final JsonObject object = new JsonObject();
+        final JsonArray suggestions = new JsonArray();
+        final JsonArray exceptions = new JsonArray();
+        final JsonArray usage = new JsonArray();
+        StringReader reader = new StringReader(text);
+        if (reader.canRead() && reader.peek() == '/') reader.skip();
+        ParseResults<CommandSource> parseResults = dispatcher.parse(reader, source);
+        JsonObject readerJson = new JsonObject();
+        readerJson.addProperty(CommandManagerPacketKeys.READER_CAN_READ, parseResults.getReader().canRead());
+        int readerCursor = Math.max(parseResults.getReader().getCursor(), 0);
+        readerJson.addProperty(CommandManagerPacketKeys.READER_CURSOR, readerCursor);
+        int remainingTextLength = Math.min(readerCursor + parseResults.getReader().getRemainingLength(), text.length());
+        readerJson.addProperty(CommandManagerPacketKeys.READER_REMAINING_TEXT_LENGTH, remainingTextLength);
+        readerJson.addProperty(CommandManagerPacketKeys.READER_STRING, parseResults.getReader().getString());
+        object.add(CommandManagerPacketKeys.READER, readerJson);
+        object.addProperty(CommandManagerPacketKeys.SUGGESTION_CONTEXT_START_POS, parseResults.getContext().findSuggestionContext(cursor).startPos);
+
+        CompletableFuture<Suggestions> pendingSuggestions = getCompletionSuggestions(parseResults, cursor, source);
+        pendingSuggestions.thenRun(() -> {
+            if (pendingSuggestions.isDone()) {
+                for (Suggestion suggestion : pendingSuggestions.join().getList()) {
+                    JsonObject suggestionJson = new JsonObject();
+                    suggestionJson.addProperty(CommandManagerPacketKeys.VALUE, suggestion.getText());
+                    JsonObject range = new JsonObject();
+                    range.addProperty(CommandManagerPacketKeys.RANGE_START, suggestion.getRange().getStart());
+                    range.addProperty(CommandManagerPacketKeys.RANGE_END, suggestion.getRange().getEnd());
+                    suggestionJson.add(CommandManagerPacketKeys.RANGE, range);
+                    if (suggestion.getTooltip() != null)
+                        suggestionJson.addProperty(CommandManagerPacketKeys.TOOLTIP, suggestion.getTooltip().getString());
+                    suggestions.add(suggestionJson);
+                }
+            }
+        });
+        CommandSyntaxException parseException = CommandManager.getParseException(parseResults);
+        if (!parseResults.getExceptions().isEmpty()) {
+            for (CommandSyntaxException entry : parseResults.getExceptions().values()) {
+                JsonObject exceptionJson = new JsonObject();
+                exceptionJson.addProperty(CommandManagerPacketKeys.VALUE, entry.getMessage());
+                exceptions.add(exceptionJson);
+            }
+        } else if (parseException != null) {
+            JsonObject exceptionJson = new JsonObject();
+            exceptionJson.addProperty(CommandManagerPacketKeys.VALUE, parseException.getMessage());
+            exceptions.add(exceptionJson);
+        } else if (parseResults.getContext().getRootNode() != null && parseResults.getContext().getRange().getStart() <= cursor) {
+            JsonObject commandUsage = new JsonObject();
+            for (Map.Entry<CommandNode<CommandSource>, String> entry : dispatcher.getSmartUsage(parseResults.getContext().findSuggestionContext(cursor).parent, source).entrySet()) {
+                if (entry.getKey() instanceof LiteralCommandNode) continue;
+                commandUsage.addProperty(CommandManagerPacketKeys.VALUE, entry.getValue());
+                usage.add(commandUsage);
+            }
+        }
+
+        JsonObject lastChild = getLastChild(parseResults);
+        object.add(CommandManagerPacketKeys.LAST_CHILD, lastChild);
+        object.add(CommandManagerPacketKeys.SUGGESTIONS, suggestions);
+        object.add(CommandManagerPacketKeys.EXCEPTIONS, exceptions);
+        object.add(CommandManagerPacketKeys.USAGE, usage);
+        return object;
+    }
+
+    private static CompletableFuture<Suggestions> getCompletionSuggestions(final ParseResults<CommandSource> parse, int cursor, CommandSource source) {
+        final CommandContextBuilder<CommandSource> context = parse.getContext();
+
+        final SuggestionContext<CommandSource> nodeBeforeCursor = context.findSuggestionContext(cursor);
+        final CommandNode<CommandSource> parent = nodeBeforeCursor.parent;
+        if (parent == null) return Suggestions.empty();
+        final int start = Math.min(nodeBeforeCursor.startPos, cursor);
+
+        final String fullInput = parse.getReader().getString();
+        final String truncatedInput = fullInput.substring(0, cursor);
+        final String truncatedInputLowerCase = truncatedInput.toLowerCase(Locale.ROOT);
+        List<CompletableFuture<Suggestions>> futuresList = new ArrayList<>();
+        int i = 0;
+        for (final CommandNode<CommandSource> node : parent.getChildren()) {
+            if (!node.canUse(source)) continue;
+            CompletableFuture<Suggestions> future = Suggestions.empty();
+            try {
+                future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start));
+            } catch (final CommandSyntaxException ignored) {
+            }
+            futuresList.add(future);
+            i++;
+        }
+
+        @SuppressWarnings("unchecked") final CompletableFuture<Suggestions>[] futures = new CompletableFuture[i];
+        for (int j = 0; j < futures.length; j++) {
+            futures[j] = futuresList.get(j);
+        }
+
+        final CompletableFuture<Suggestions> result = new CompletableFuture<>();
+        CompletableFuture.allOf(futures).thenRun(() -> {
+            final List<Suggestions> suggestions = new ArrayList<>();
+            for (final CompletableFuture<Suggestions> future : futuresList) {
+                suggestions.add(future.join());
+            }
+            result.complete(Suggestions.merge(fullInput, suggestions));
+        });
+
+        return result;
+    }
+
+    @NotNull
+    private static JsonObject getLastChild(ParseResults<CommandSource> parseResults) {
+        JsonObject lastChild = new JsonObject();
+        CommandContextBuilder<CommandSource> builder = parseResults.getContext().getLastChild();
+        JsonArray arguments = new JsonArray();
+        for (ParsedArgument<CommandSource, ?> parsedArgument : builder.getArguments().values()) {
+            JsonObject argument = new JsonObject();
+            JsonObject range = new JsonObject();
+            range.addProperty(CommandManagerPacketKeys.RANGE_START, parsedArgument.getRange().getStart());
+            range.addProperty(CommandManagerPacketKeys.RANGE_END, parsedArgument.getRange().getEnd());
+            argument.add(CommandManagerPacketKeys.RANGE, range);
+            arguments.add(argument);
+        }
+        lastChild.add(CommandManagerPacketKeys.ARGUMENTS, arguments);
+        return lastChild;
+    }
+
+    @Override
+    public void handlePacket(PacketHandler packetHandler) {
+        packetHandler.handleCommandManagerPacket(this);
+    }
+
+    @Override
+    public int getEstimatedSize() {
+        return 1;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/packet/Packet.java b/src/main/java/net/minecraft/core/net/packet/Packet.java
index f11ea80bd..f771af942 100644
--- a/src/main/java/net/minecraft/core/net/packet/Packet.java
+++ b/src/main/java/net/minecraft/core/net/packet/Packet.java
@@ -310,6 +310,8 @@ public abstract class Packet
         addMapping(106, true, true, ContainerAckPacket.class);
         addMapping(107, false, true, UpdateCreativeInventoryPacket.class);
         addMapping(108, false, true, SetHotbarOffsetPacket.class);
+        addMapping(120, true, false, CommandManagerPacket.class);
+        addMapping(121, false, true, RequestCommandManagerPacket.class);
         addMapping(130, false, true, SignUpdatePacket.class);
         addMapping(131, true, false, MapDataPacket.class);
         addMapping(132, true, true, SetMobSpawnerPacket.class);
diff --git a/src/main/java/net/minecraft/core/net/packet/RequestCommandManagerPacket.java b/src/main/java/net/minecraft/core/net/packet/RequestCommandManagerPacket.java
new file mode 100644
index 000000000..d7b9e4f2d
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/packet/RequestCommandManagerPacket.java
@@ -0,0 +1,46 @@
+package net.minecraft.core.net.packet;
+
+import net.minecraft.core.net.handler.PacketHandler;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class RequestCommandManagerPacket extends Packet {
+    public String username;
+    public String text;
+    public int cursor;
+
+    public RequestCommandManagerPacket(String username, String text, int cursor) {
+        this.username = username;
+        this.text = text;
+        this.cursor = cursor;
+    }
+
+    public RequestCommandManagerPacket() {
+    }
+
+    @Override
+    public void read(DataInputStream dis) throws IOException {
+        this.username = dis.readUTF();
+        this.text = dis.readUTF();
+        this.cursor = dis.readInt();
+    }
+
+    @Override
+    public void write(DataOutputStream dos) throws IOException {
+        dos.writeUTF(this.username);
+        dos.writeUTF(this.text);
+        dos.writeInt(this.cursor);
+    }
+
+    @Override
+    public void handlePacket(PacketHandler packetHandler) {
+        packetHandler.handleRequestCommandManagerPacket(this);
+    }
+
+    @Override
+    public int getEstimatedSize() {
+        return 10;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/world/World.java b/src/main/java/net/minecraft/core/world/World.java
index a0c38fa64..4412efabb 100644
--- a/src/main/java/net/minecraft/core/world/World.java
+++ b/src/main/java/net/minecraft/core/world/World.java
@@ -16,7 +16,7 @@ import java.util.UUID;
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.CompoundTag;
 
-import net.minecraft.client.option.enums.Difficulty;
+import net.minecraft.core.enums.Difficulty;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.camera.ICamera;
 import net.minecraft.client.render.colorizer.Colorizers;
@@ -27,6 +27,7 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.BlockEntity;
 import net.minecraft.core.entity.ItemEntity;
 import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.CommandManager;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.NextTickListEntry;
 import net.minecraft.core.block.Block;
@@ -135,6 +136,8 @@ public class World implements WorldSource {
 
     public final WeatherManager weatherManager;
 
+    private CommandManager commandManager;
+
     //Usually called when a world is loaded or generated (Singleplayer & Server)
     public World(LevelStorage saveHandler, String name, long seed, Dimension dimension, WorldType worldType, SpawnerMobs.SpawnerConfig spawningConfig)
     {
@@ -221,6 +224,9 @@ public class World implements WorldSource {
             getInitialSpawnLocation();
         }
         updateSkyBrightness();
+
+        this.commandManager = new CommandManager(isServer);
+        this.commandManager.init();
     }
 
     //Usually called when going through portals
@@ -263,6 +269,8 @@ public class World implements WorldSource {
 
         auroraProvider = new AuroraProvider(this, this.getRandomSeed());
 
+        this.commandManager = new CommandManager(isServer);
+        this.commandManager.init();
     }
 
     //Usually called when joining a server
@@ -285,7 +293,11 @@ public class World implements WorldSource {
         biomeProvider = this.worldType.createBiomeProvider(this);
 
         spawningConfig = new SpawnerMobs.SpawnerConfig();
+
+        this.commandManager = new CommandManager(isServer);
+        this.commandManager.init();
     }
+
     // Used for the model viewer
     public World(){
         this.dimension = Dimension.overworld;
@@ -320,6 +332,10 @@ public class World implements WorldSource {
         return biomeProvider;
     }
 
+    public CommandManager getCommandManager() {
+        return commandManager;
+    }
+
     protected IChunkProvider createChunkProvider()
     {
         IChunkLoader chunkLoader = saveHandler.getChunkLoader(dimension);
diff --git a/src/main/java/net/minecraft/core/world/save/LevelData.java b/src/main/java/net/minecraft/core/world/save/LevelData.java
index 49f65145d..3f1f53b8f 100644
--- a/src/main/java/net/minecraft/core/world/save/LevelData.java
+++ b/src/main/java/net/minecraft/core/world/save/LevelData.java
@@ -1,7 +1,7 @@
 package net.minecraft.core.world.save;
 
 import com.mojang.logging.LogUtils;
-import net.minecraft.client.option.enums.Difficulty;
+import net.minecraft.core.enums.Difficulty;
 import net.minecraft.core.data.gamerule.GameRuleCollection;
 import net.minecraft.core.entity.player.Player;
 import com.mojang.nbt.CompoundTag;
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index a6511c78c..359137987 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1,5 +1,6 @@
 package net.minecraft.server;
 
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.CompoundTag;
 import net.minecraft.core.Global;
@@ -17,7 +18,8 @@ import net.minecraft.core.net.IUpdatePlayerListBox;
 import net.minecraft.core.net.NetworkManager;
 import net.minecraft.core.net.PropertyManager;
 import net.minecraft.core.net.ServerCommandEntry;
-import net.minecraft.core.net.command.ServerCommandHandler;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.server.net.command.ConsoleCommandSource;
 import net.minecraft.core.net.packet.SetTimePacket;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.sound.SoundTypes;
@@ -46,7 +48,6 @@ import net.minecraft.server.entity.EntityTracker;
 import net.minecraft.server.entity.ServerSkinVariantList;
 import net.minecraft.server.entity.player.ServerPlayer;
 import net.minecraft.server.gui.ServerGui;
-import net.minecraft.server.net.ConsoleCommandHandler;
 import net.minecraft.server.net.NetworkListenThread;
 import net.minecraft.server.net.PlayerList;
 import net.minecraft.server.world.ConvertProgressUpdater;
@@ -82,7 +83,6 @@ public class MinecraftServer
     public PropertyManager propertyManager;
     public WorldServer[] dimensionWorlds;
     public PlayerList playerList;
-    private ConsoleCommandHandler commandHandler;
     private boolean serverRunning;
     public boolean serverStopped;
     int deathTime;
@@ -97,7 +97,6 @@ public class MinecraftServer
     public int spawnProtectionRange;
     public WorldType defaultWorldType;
     public int difficulty;
-    public final ServerCommandHandler serverCommandHandler = new ServerCommandHandler(this);
     public String joinMessage = null;
     public int summonLimit;
     public String language;
@@ -143,7 +142,6 @@ public class MinecraftServer
     {
         instance = this;
         isServer = true;
-        commandHandler = new ConsoleCommandHandler(this);
         Thread commandReadingThreads = new Thread(() -> {
             BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in));
             String s = null;
@@ -168,8 +166,8 @@ public class MinecraftServer
         // Manually initialize blocks and items
         Blocks.init();
         Items.init();
-
         Dimension.init();
+        CommandHelper.init();
 
         LOGGER.info("Loading properties");
         propertyManager = new PropertyManager(new File("server.properties"));
@@ -683,10 +681,16 @@ public class MinecraftServer
 
     public void commandLineParser()
     {
-        ServerCommandEntry servercommand;
-        for (; commands.size() > 0; commandHandler.handleCommand(servercommand))
+        while (!commands.isEmpty())
         {
-            servercommand = commands.remove(0);
+            ServerCommandEntry serverCommand = commands.remove(0);
+            String command = serverCommand.command;
+            ConsoleCommandSource source = new ConsoleCommandSource(this);
+            try {
+                getDimensionWorld(0).getCommandManager().execute(command, source);
+            } catch (CommandSyntaxException e) {
+                source.sendMessage(e.getMessage());
+            }
         }
 
     }
diff --git a/src/main/java/net/minecraft/server/net/ConsoleCommandHandler.java b/src/main/java/net/minecraft/server/net/ConsoleCommandHandler.java
deleted file mode 100644
index 580f2c0ec..000000000
--- a/src/main/java/net/minecraft/server/net/ConsoleCommandHandler.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.minecraft.server.net;
-
-
-import net.minecraft.core.net.ServerCommandEntry;
-
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.Commands;
-import net.minecraft.core.net.command.ConsoleCommandSender;
-
-public class ConsoleCommandHandler
-{
-
-    private final MinecraftServer minecraftServer;
-    public final ConsoleCommandSender sender;
-
-    public ConsoleCommandHandler(MinecraftServer server)
-    {
-        minecraftServer = server;
-        
-        Commands.initServerCommands(server);
-        
-        this.sender = new ConsoleCommandSender(server);
-    }
-
-    public void handleCommand(ServerCommandEntry serverCommandEntry) {
-    	minecraftServer.logInfo("ServerCommand: "+ serverCommandEntry.command);
-
-    	String[] args = serverCommandEntry.command.split(" ");
-    	String[] args1 = new String[args.length - 1];
-    	System.arraycopy(args, 1, args1, 0, args.length - 1);
-
-    	for(Command command : Commands.commands) {
-    		if(command.isName(args[0])) {
-    			try {
-        			boolean success = command.execute(minecraftServer.serverCommandHandler, sender, args1);
-        			if(!success) {
-        				command.sendCommandSyntax(minecraftServer.serverCommandHandler, sender);
-        			}
-    			}catch (CommandError e) {
-    				sender.sendMessage(TextFormatting.RED + e.getMessage());
-				}
-    			return;
-    		}
-    	}
-        sender.sendMessage(TextFormatting.RED + "Command '" + args[0] + "' does not exist!");
-    }
-}
diff --git a/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java b/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java
new file mode 100644
index 000000000..399b3dc81
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java
@@ -0,0 +1,114 @@
+package net.minecraft.server.net.command;
+
+import com.mojang.logging.LogUtils;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.packet.ChatPacket;
+import net.minecraft.core.util.helper.AES;
+import net.minecraft.core.util.helper.LoggedPrintStream;
+import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.World;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.entity.player.ServerPlayer;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ConsoleCommandSource implements CommandSource, IServerCommandSource {
+    private static final Logger LOGGER = LogUtils.getLogger();
+
+    public final MinecraftServer server;
+
+    public ConsoleCommandSource(MinecraftServer server) {
+        this.server = server;
+    }
+
+    @Override
+    public Collection<String> getPlayerNames() {
+        List<String> list = new ArrayList<>();
+        for (Player player : server.playerList.playerEntities) {
+            list.add(player.username);
+        }
+        return list;
+    }
+
+    @Override
+    public Collection<String> getEntitySuggestions() {
+        return this.getPlayerNames();
+    }
+
+    @Override
+    public String toString() {
+        return "ConsoleCommandSource{" + this.server + "}";
+    }
+
+    @Override
+    public Player getSender() {
+        return null;
+    }
+
+    @Override
+    public boolean hasAdmin() {
+        return true;
+    }
+
+    @Override
+    public @Nullable Vec3 getCoordinates(boolean offsetHeight) {
+        return null;
+    }
+
+    @Override
+    public @Nullable Vec3 getBlockCoordinates() {
+        return null;
+    }
+
+    @Override
+    public boolean messageMayBeMultiline() {
+        return true;
+    }
+
+    @Override
+    public void sendMessage(String message) {
+        LOGGER.info(LoggedPrintStream.removeColorCodes(message));
+    }
+
+    @Override
+    public void sendMessage(Player player, String message) {
+        this.server.playerList.sendPacketToPlayer(player.username, new ChatPacket(message, AES.keyChain.get(player.username)));
+    }
+
+    @Override
+    public void sendMessageToAllPlayers(String message) {
+        this.getServer().playerList.sendPacketToAllPlayers(new ChatPacket(message));
+    }
+
+    @Override
+    public World getWorld() {
+        return this.server.getDimensionWorld(0);
+    }
+
+    @Override
+    public World getWorld(int dimension) {
+        return this.server.getDimensionWorld(dimension);
+    }
+
+    @Override
+    public void movePlayerToDimension(Player player, int dimension) {
+        if (player instanceof ServerPlayer)
+            this.server.playerList.sendPlayerToOtherDimension((ServerPlayer) player, dimension, false);
+        else throw new IllegalStateException("Player is not an instance of ServerPlayer");
+    }
+
+    @Override
+    public String getName() {
+        return "Server";
+    }
+
+    @Override
+    public MinecraftServer getServer() {
+        return this.server;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/server/net/command/IServerCommandSource.java b/src/main/java/net/minecraft/server/net/command/IServerCommandSource.java
new file mode 100644
index 000000000..4ce157913
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/IServerCommandSource.java
@@ -0,0 +1,7 @@
+package net.minecraft.server.net.command;
+
+import net.minecraft.server.MinecraftServer;
+
+public interface IServerCommandSource {
+    MinecraftServer getServer();
+}
diff --git a/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java b/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
new file mode 100644
index 000000000..ec5e577ff
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
@@ -0,0 +1,115 @@
+package net.minecraft.server.net.command;
+
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.packet.ChatPacket;
+import net.minecraft.core.util.helper.AES;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.World;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.entity.player.ServerPlayer;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ServerCommandSource implements CommandSource, IServerCommandSource {
+    public final MinecraftServer server;
+    public final ServerPlayer player;
+
+    public ServerCommandSource(MinecraftServer server, ServerPlayer player) {
+        this.server = server;
+        this.player = player;
+    }
+
+    @Override
+    public Collection<String> getPlayerNames() {
+        List<String> list = new ArrayList<>();
+        for (Player player : server.playerList.playerEntities) {
+            list.add(player.username);
+        }
+        return list;
+    }
+
+    @Override
+    public Collection<String> getEntitySuggestions() {
+        return this.getPlayerNames();
+    }
+
+    @Override
+    public String toString() {
+        return "ServerCommandSource{" + this.server + ", " + this.player + "}";
+    }
+
+    @Override
+    public @NotNull Player getSender() {
+        return this.player;
+    }
+
+    @Override
+    public boolean hasAdmin() {
+        return this.server.playerList.isOp(this.getSender().uuid);
+    }
+
+    @Override
+    public @NotNull Vec3 getCoordinates(boolean offsetHeight) {
+        Vec3 position = this.getSender().getPosition(1.0f);
+        if (offsetHeight) return position.add(0.0f, -this.getSender().heightOffset, 0.0f);
+        return position;
+    }
+
+    @Override
+    public @NotNull Vec3 getBlockCoordinates() {
+        Vec3 coordinates = this.getCoordinates(true);
+        return Vec3.getTempVec3(MathHelper.floor(coordinates.x), MathHelper.floor(coordinates.y), MathHelper.floor(coordinates.z));
+    }
+
+    @Override
+    public boolean messageMayBeMultiline() {
+        return !this.getSender().username.equals("pr_ib");
+    }
+
+    @Override
+    public void sendMessage(String message) {
+        this.player.playerNetServerHandler.sendPacket(new ChatPacket(message, AES.keyChain.get(this.player.username)));
+    }
+
+    @Override
+    public void sendMessage(Player player, String message) {
+        this.server.playerList.sendPacketToPlayer(player.username, new ChatPacket(message, AES.keyChain.get(player.username)));
+    }
+
+    @Override
+    public void sendMessageToAllPlayers(String message) {
+        this.getServer().playerList.sendPacketToAllPlayers(new ChatPacket(message));
+    }
+
+    @Override
+    public World getWorld() {
+        return this.player == null ? this.server.getDimensionWorld(0) : this.player.world;
+    }
+
+    @Override
+    public World getWorld(int dimension) {
+        return this.server.getDimensionWorld(dimension);
+    }
+
+    @Override
+    public void movePlayerToDimension(Player player, int dimension) {
+        if (player instanceof ServerPlayer)
+            this.server.playerList.sendPlayerToOtherDimension((ServerPlayer) player, dimension, false);
+        else throw new IllegalStateException("Player is not an instance of ServerPlayer");
+    }
+
+    @Override
+    public String getName() {
+        return this.player.username;
+    }
+
+    @Override
+    public MinecraftServer getServer() {
+        return this.server;
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/ColorCommand.java b/src/main/java/net/minecraft/server/net/command/commands/ColorCommand.java
new file mode 100644
index 000000000..b3b11947c
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/ColorCommand.java
@@ -0,0 +1,313 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.server.entity.player.ServerPlayer;
+
+import java.util.List;
+
+public class ColorCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("color")
+            .then(LiteralArgumentBuilder.<CommandSource>literal("get")
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    if (!(source instanceof IServerCommandSource))
+                        throw CommandExceptions.multiplayerWorldOnly().create();
+
+                    ServerPlayer player = (ServerPlayer) source.getSender();
+                    if (player == null) throw CommandExceptions.notInWorld().create();
+
+                    TextFormatting color = TextFormatting.get(player.chatColor);
+                    source.sendMessage(I18n.getInstance().translateKeyAndFormat("commands.commander.color.get.success", color + color.getNames()[0]));
+                    return Command.SINGLE_SUCCESS;
+                })
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.player())
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        if (!(source instanceof IServerCommandSource))
+                            throw CommandExceptions.multiplayerWorldOnly().create();
+
+                        EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                        ServerPlayer player = (ServerPlayer) entitySelector.get(source).get(0);
+
+                        TextFormatting color = TextFormatting.get(player.chatColor);
+                        source.sendMessage(I18n.getInstance().translateKeyAndFormat("commands.commander.color.get.success_other", color + color.getNames()[0]));
+                        return Command.SINGLE_SUCCESS;
+                    })))
+            .then(LiteralArgumentBuilder.<CommandSource>literal("set")
+                .then(LiteralArgumentBuilder.<CommandSource>literal("white")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 0);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("orange")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 1);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("magenta")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 2);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("light_blue")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 3);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("yellow")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 4);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("lime")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 5);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("pink")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 6);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("gray")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 7);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("light_gray")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 8);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("cyan")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 9);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("purple")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 10);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("blue")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 11);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("brown")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 12);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("green")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 13);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("red")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 14);
+                    }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("black")
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        return setColor((ServerPlayer) source.getSender(), source, (byte) 15);
+                    }))
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.players())
+                    .requires(CommandSource::hasAdmin)
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("white")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 0);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("orange")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 1);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("magenta")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 2);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("light_blue")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 3);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("yellow")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 4);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("lime")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 5);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("pink")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 6);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("gray")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 7);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("light_gray")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 8);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("cyan")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 9);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("purple")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 10);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("blue")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 11);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("brown")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 12);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("green")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 13);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("red")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 14);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        }))
+                    .then(LiteralArgumentBuilder.<CommandSource>literal("black")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            for (Entity entity : entities) {
+                                setColor((ServerPlayer) entity, source, (byte) 15);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        })))));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("colour")
+            .redirect(command));
+    }
+
+    private static int setColor(ServerPlayer player, CommandSource source, byte colorId) throws CommandSyntaxException {
+        if (!(source instanceof IServerCommandSource)) throw CommandExceptions.multiplayerWorldOnly().create();
+
+        if (player == null) throw CommandExceptions.notInWorld().create();
+
+        player.chatColor = colorId;
+        TextFormatting color = TextFormatting.get(colorId);
+        if (player == source.getSender()) {
+            source.sendTranslatableMessage("commands.commander.color.set.success", color + color.getNames()[0]);
+        } else {
+            source.sendTranslatableMessage("commands.commander.color.set.success_other", CommandHelper.getEntityName(player), color + color.getNames()[0]);
+            source.sendTranslatableMessage(player, "commands.commander.color.set.success_receiver", color + color.getNames()[0]);
+        }
+        return Command.SINGLE_SUCCESS;
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/DeopCommand.java b/src/main/java/net/minecraft/server/net/command/commands/DeopCommand.java
new file mode 100644
index 000000000..6b0436b5e
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/DeopCommand.java
@@ -0,0 +1,55 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.entity.player.ServerPlayer;
+
+import java.util.List;
+
+public class DeopCommand {
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("commands.commander.deop.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("deop")
+            .requires(CommandSource::hasAdmin)
+            .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.players())
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    if (!(source instanceof IServerCommandSource))
+                        throw CommandExceptions.multiplayerWorldOnly().create();
+
+                    EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                    List<? extends Entity> entities = entitySelector.get(source);
+                    MinecraftServer server = ((IServerCommandSource) source).getServer();
+
+                    boolean deoppedSomeone = false;
+
+                    for (Entity entity : entities) {
+                        ServerPlayer player = (ServerPlayer) entity;
+                        if (player.isOperator()) {
+                            deoppedSomeone = true;
+                            server.playerList.deopPlayer(player.uuid);
+                            source.sendTranslatableMessage("commands.commander.deop.success", player.username);
+                            source.sendTranslatableMessage(player, "commands.commander.deop.success_receiver");
+                        }
+                        server.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
+                    }
+                    if (!deoppedSomeone) {
+                        throw FAILURE.create();
+                    }
+                    return Command.SINGLE_SUCCESS;
+                })));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/DifficultyCommand.java b/src/main/java/net/minecraft/server/net/command/commands/DifficultyCommand.java
new file mode 100644
index 000000000..14de55a97
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/DifficultyCommand.java
@@ -0,0 +1,78 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class DifficultyCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("difficulty")
+                .requires(CommandSource::hasAdmin)
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    switch (source.getWorld().getDifficulty()) {
+                        case PEACEFUL:
+                            source.sendTranslatableMessage("commands.commander.difficulty.query.success", I18n.getInstance().translateKey("options.difficulty.peaceful"));
+                            break;
+                        case EASY:
+                            source.sendTranslatableMessage("commands.commander.difficulty.query.success", I18n.getInstance().translateKey("options.difficulty.easy"));
+                            break;
+                        case NORMAL:
+                            source.sendTranslatableMessage("commands.commander.difficulty.query.success", I18n.getInstance().translateKey("options.difficulty.normal"));
+                            break;
+                        case HARD:
+                            source.sendTranslatableMessage("commands.commander.difficulty.query.success", I18n.getInstance().translateKey("options.difficulty.hard"));
+                            break;
+                        default:
+                            source.sendTranslatableMessage("commands.commander.difficulty.query.success_unknown");
+                            break;
+                    }
+                    return Command.SINGLE_SUCCESS;
+                })
+                .then(LiteralArgumentBuilder.<CommandSource>literal("peaceful")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            return setDifficulty(source, 0);
+                        }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("easy")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            return setDifficulty(source, 1);
+                        }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("normal")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            return setDifficulty(source, 2);
+                        }))
+                .then(LiteralArgumentBuilder.<CommandSource>literal("hard")
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            return setDifficulty(source, 3);
+                        })));
+    }
+
+    private static final List<String> difficultyStrings = Arrays.asList("peaceful", "easy", "normal", "hard");
+
+    private static int setDifficulty(CommandSource source, int difficulty) throws CommandSyntaxException {
+        if (!(source instanceof IServerCommandSource)) throw CommandExceptions.multiplayerWorldOnly().create();
+
+        MinecraftServer server = ((IServerCommandSource)source).getServer();
+
+        for (World world : server.dimensionWorlds) {
+            world.setDifficulty(difficulty, true);
+        }
+        server.difficulty = difficulty;
+        source.sendTranslatableMessage("commands.commander.difficulty.set.success", I18n.getInstance().translateKey("options.difficulty." + difficultyStrings.get(difficulty)));
+        return Command.SINGLE_SUCCESS;
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/EmotesCommand.java b/src/main/java/net/minecraft/server/net/command/commands/EmotesCommand.java
new file mode 100644
index 000000000..148f5182c
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/EmotesCommand.java
@@ -0,0 +1,26 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import net.minecraft.core.net.ChatEmotes;
+import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.net.command.CommandSource;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+public class EmotesCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("emotes")
+            .executes(c -> {
+                CommandSource source = c.getSource();
+                source.sendTranslatableMessage("commands.commander.emotes.success");
+                ArrayList<Map.Entry<String, Character>> entryList = new ArrayList<Map.Entry<String, Character>>(ChatEmotes.getEmotes().entrySet());
+                entryList.sort(Map.Entry.comparingByKey());
+                for (Map.Entry<String, Character> entry : entryList) {
+                    source.sendMessage(":" + TextFormatting.CYAN + entry.getKey().substring(1, entry.getKey().length() - 1) + TextFormatting.RESET + ":" + " -> " + entry.getValue());
+                }
+                return entryList.size();
+            }));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/ListCommand.java b/src/main/java/net/minecraft/server/net/command/commands/ListCommand.java
new file mode 100644
index 000000000..81fffcc7c
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/ListCommand.java
@@ -0,0 +1,47 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+
+public class ListCommand {
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("commands.commander.list.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("list")
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    if (!(source instanceof IServerCommandSource)) throw CommandExceptions.multiplayerWorldOnly().create();
+
+                    MinecraftServer server = ((IServerCommandSource)source).getServer();
+
+                    int playerCount = server.playerList.playerEntities.size();
+                    if (playerCount < 100) {
+                        if (playerCount == 0) throw FAILURE.create();
+                        StringBuilder builder = new StringBuilder();
+                        for (int i = 0; i < server.playerList.playerEntities.size(); ++i) {
+                            if (i > 0) {
+                                builder.append(", ");
+                            }
+                            builder.append(CommandHelper.getEntityName(server.playerList.playerEntities.get(i)));
+                        }
+                        if (playerCount == 1) {
+                            source.sendTranslatableMessage("commands.commander.list.success_single", playerCount, builder.toString());
+                        } else {
+                            source.sendTranslatableMessage("commands.commander.list.success_multiple", playerCount, builder.toString());
+                        }
+                    } else {
+                        source.sendTranslatableMessage("commands.commander.list.success_too_long", playerCount);
+                    }
+
+                    return Command.SINGLE_SUCCESS;
+                }));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/MeCommand.java b/src/main/java/net/minecraft/server/net/command/commands/MeCommand.java
new file mode 100644
index 000000000..fc1cddca8
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/MeCommand.java
@@ -0,0 +1,40 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.BoolArgumentType;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.packet.ChatPacket;
+
+public class MeCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("me")
+            .then(RequiredArgumentBuilder.<CommandSource, Boolean>argument("asterisk", BoolArgumentType.bool())
+                .then(RequiredArgumentBuilder.<CommandSource, String>argument("message", StringArgumentType.greedyString())
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        String message = StringArgumentType.getString(c, "message");
+                        boolean asterisk = BoolArgumentType.getBool(c, "asterisk");
+                        if (!(source instanceof IServerCommandSource))
+                            throw CommandExceptions.multiplayerWorldOnly().create();
+                        String senderName = source.getName();
+                        ((IServerCommandSource) source).getServer().playerList.sendPacketToAllPlayers(new ChatPacket((asterisk ? "* " : "") + senderName + message));
+                        return Command.SINGLE_SUCCESS;
+                    })))
+            .then(RequiredArgumentBuilder.<CommandSource, String>argument("message", StringArgumentType.greedyString())
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    String message = StringArgumentType.getString(c, "message");
+                    if (!(source instanceof IServerCommandSource))
+                        throw CommandExceptions.multiplayerWorldOnly().create();
+                    String senderName = source.getName();
+                    ((IServerCommandSource) source).getServer().playerList.sendPacketToAllPlayers(new ChatPacket("* " + senderName + message));
+                    return Command.SINGLE_SUCCESS;
+                })));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/NicknameCommand.java b/src/main/java/net/minecraft/server/net/command/commands/NicknameCommand.java
new file mode 100644
index 000000000..f828b62c0
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/NicknameCommand.java
@@ -0,0 +1,121 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
+import net.minecraft.server.entity.player.ServerPlayer;
+
+import java.util.List;
+
+public class NicknameCommand {
+    private static final SimpleCommandExceptionType NICKNAME_TOO_LARGE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("commands.commander.nickname.exception_too_large"));
+    private static final SimpleCommandExceptionType NICKNAME_TOO_SMALL = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("commands.commander.nickname.exception_too_small"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("nickname")
+            .then(LiteralArgumentBuilder.<CommandSource>literal("set")
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.player())
+                    .requires(CommandSource::hasAdmin)
+                    .then(RequiredArgumentBuilder.<CommandSource, String>argument("nickname", StringArgumentType.greedyString())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            String nickname = c.getArgument("nickname", String.class);
+                            if (nickname.length() > 16) throw NICKNAME_TOO_LARGE.create();
+                            if (nickname.isEmpty()) throw NICKNAME_TOO_SMALL.create();
+                            List<? extends Entity> entities = entitySelector.get(source);
+
+                            ServerPlayer player = (ServerPlayer) entities.get(0);
+
+                            player.nickname = nickname;
+                            player.hadNicknameSet = true;
+                            player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
+                            if (source.getSender() == player) {
+                                source.sendTranslatableMessage("commands.commander.nickname.set.success", nickname);
+                            } else {
+                                source.sendTranslatableMessage("commands.commander.nickname.set.success_other", player.username, nickname);
+                                source.sendTranslatableMessage(player, "commands.commander.nickname.set.success_receiver", nickname);
+                            }
+                            return Command.SINGLE_SUCCESS;
+                        })))
+                .then(RequiredArgumentBuilder.<CommandSource, String>argument("nickname", StringArgumentType.greedyString())
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        String nickname = c.getArgument("nickname", String.class);
+                        if (nickname.length() > 16) throw NICKNAME_TOO_LARGE.create();
+                        if (nickname.isEmpty()) throw NICKNAME_TOO_SMALL.create();
+
+                        ServerPlayer player = (ServerPlayer) source.getSender();
+
+                        if (player == null) throw CommandExceptions.notInWorld().create();
+
+                        player.nickname = nickname;
+                        player.hadNicknameSet = true;
+                        player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
+
+                        source.sendTranslatableMessage("commands.commander.nickname.set.success", nickname);
+
+                        return Command.SINGLE_SUCCESS;
+                    })))
+            .then(LiteralArgumentBuilder.<CommandSource>literal("get")
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.player())
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                        List<? extends Entity> entities = entitySelector.get(source);
+                        ServerPlayer player = (ServerPlayer) entities.get(0);
+
+                        source.sendTranslatableMessage("commands.commander.nickname.get.success", player.username, player.nickname);
+                        return Command.SINGLE_SUCCESS;
+                    })))
+            .then(LiteralArgumentBuilder.<CommandSource>literal("reset")
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.player())
+                    .requires(CommandSource::hasAdmin)
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                        List<? extends Entity> entities = entitySelector.get(source);
+
+                        ServerPlayer player = (ServerPlayer) entities.get(0);
+
+                        player.nickname = "";
+                        player.hadNicknameSet = false;
+                        player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
+                        if (source.getSender() == player) {
+                            source.sendTranslatableMessage("commands.commander.nickname.reset.success");
+                        } else {
+                            source.sendTranslatableMessage("commands.commander.nickname.reset.success_other", player.username);
+                            source.sendTranslatableMessage(player, "commands.commander.nickname.reset.success_receiver");
+                        }
+                        return Command.SINGLE_SUCCESS;
+                    }))
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+
+                    ServerPlayer player = (ServerPlayer) source.getSender();
+
+                    if (player == null) throw CommandExceptions.notInWorld().create();
+
+                    player.nickname = "";
+                    player.hadNicknameSet = false;
+                    player.mcServer.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
+
+                    source.sendTranslatableMessage("commands.commander.nickname.reset.success", player.username);
+
+                    return Command.SINGLE_SUCCESS;
+                })));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("nick")
+            .redirect(command));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/OpCommand.java b/src/main/java/net/minecraft/server/net/command/commands/OpCommand.java
new file mode 100644
index 000000000..26f73684b
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/OpCommand.java
@@ -0,0 +1,55 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.entity.player.ServerPlayer;
+
+import java.util.List;
+
+public class OpCommand {
+    private static final SimpleCommandExceptionType FAILURE = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("commands.commander.op.exception_failure"));
+
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("op")
+            .requires(CommandSource::hasAdmin)
+            .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.players())
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    if (!(source instanceof IServerCommandSource))
+                        throw CommandExceptions.multiplayerWorldOnly().create();
+
+                    EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                    List<? extends Entity> entities = entitySelector.get(source);
+                    MinecraftServer server = ((IServerCommandSource) source).getServer();
+
+                    boolean oppedSomeone = false;
+
+                    for (Entity entity : entities) {
+                        ServerPlayer player = (ServerPlayer) entity;
+                        if (!player.isOperator()) {
+                            oppedSomeone = true;
+                            server.playerList.opPlayer(player.uuid);
+                            source.sendTranslatableMessage("commands.commander.op.success", player.username);
+                            source.sendTranslatableMessage(player, "commands.commander.op.success_receiver");
+                        }
+                        server.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
+                    }
+                    if (!oppedSomeone) {
+                        throw FAILURE.create();
+                    }
+                    return Command.SINGLE_SUCCESS;
+                })));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/ScoreCommand.java b/src/main/java/net/minecraft/server/net/command/commands/ScoreCommand.java
new file mode 100644
index 000000000..997c96d3f
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/ScoreCommand.java
@@ -0,0 +1,88 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.entity.player.ServerPlayer;
+
+import java.util.List;
+
+public class ScoreCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("score")
+            .then(LiteralArgumentBuilder.<CommandSource>literal("get")
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    Player player = source.getSender();
+                    if (player == null) throw CommandExceptions.notInWorld().create();
+                    source.sendTranslatableMessage("commands.commander.score.get.success", player.score);
+                    return player.score;
+                })
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.player())
+                    .requires(CommandSource::hasAdmin)
+                    .executes(c -> {
+                        CommandSource source = c.getSource();
+                        EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                        Player player = (Player) entitySelector.get(source).get(0);
+                        if (player == source.getSender()) {
+                            source.sendTranslatableMessage("commands.commander.score.get.success", player.score);
+                        } else {
+                            source.sendTranslatableMessage("commands.commander.score.get.success_other", CommandHelper.getEntityName(player), player.score);
+                        }
+                        return player.score;
+                    })))
+            .then(LiteralArgumentBuilder.<CommandSource>literal("set")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.players())
+                    .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("score", IntegerArgumentType.integer(0, Integer.MAX_VALUE))
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            int score = c.getArgument("score", Integer.class);
+                            for (Entity entity : entities) {
+                                setPlayerScore(source, (ServerPlayer) entity, score);
+                            }
+                            return score;
+                        }))))
+            .then(LiteralArgumentBuilder.<CommandSource>literal("add")
+                .requires(CommandSource::hasAdmin)
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.players())
+                    .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("score", IntegerArgumentType.integer(0, Integer.MAX_VALUE))
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            List<? extends Entity> entities = entitySelector.get(source);
+                            int score = c.getArgument("score", Integer.class);
+                            for (Entity entity : entities) {
+                                setPlayerScore(source, (ServerPlayer) entity, ((ServerPlayer) entity).score + score);
+                            }
+                            return score;
+                        })))));
+    }
+
+    private static void setPlayerScore(CommandSource source, ServerPlayer player, int score) throws CommandSyntaxException {
+        if (!(source instanceof IServerCommandSource)) throw CommandExceptions.multiplayerWorldOnly().create();
+        MinecraftServer server = ((IServerCommandSource) source).getServer();
+        player.score = score;
+        server.playerList.sendPacketToAllPlayers(new UpdatePlayerProfilePacket(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator()));
+        if (player == source.getSender()) {
+            source.sendTranslatableMessage("commands.commander.score.set.success", score);
+        } else {
+            source.sendTranslatableMessage("commands.commander.score.set.success_other", CommandHelper.getEntityName(player), score);
+            source.sendTranslatableMessage(player, "commands.commander.score.set.success_receiver", score);
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/StopCommand.java b/src/main/java/net/minecraft/server/net/command/commands/StopCommand.java
new file mode 100644
index 000000000..fbfc0e334
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/StopCommand.java
@@ -0,0 +1,32 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.server.net.command.IServerCommandSource;
+import net.minecraft.core.net.command.exceptions.CommandExceptions;
+
+public class StopCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("stop")
+                .requires(CommandSource::hasAdmin)
+                .executes(c -> {
+                    CommandSource source = c.getSource();
+                    if (!(source instanceof IServerCommandSource)) throw CommandExceptions.multiplayerWorldOnly().create();
+
+                    MinecraftServer server = ((IServerCommandSource)source).getServer();
+
+                    source.sendTranslatableMessage("commands.commander.stop.success");
+                    if (server.playerList != null) {
+                        server.playerList.savePlayerStates();
+                    }
+                    for (int i = 0; i < server.dimensionWorlds.length; ++i) {
+                        server.dimensionWorlds[i].saveWorld(true, null, true);
+                    }
+                    server.initiateShutdown();
+                    return Command.SINGLE_SUCCESS;
+                }));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/command/commands/WhoIsCommand.java b/src/main/java/net/minecraft/server/net/command/commands/WhoIsCommand.java
new file mode 100644
index 000000000..09c82d5b7
--- /dev/null
+++ b/src/main/java/net/minecraft/server/net/command/commands/WhoIsCommand.java
@@ -0,0 +1,29 @@
+package net.minecraft.server.net.command.commands;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.CommandNode;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.net.command.CommandSource;
+import net.minecraft.core.net.command.arguments.EntityArgumentType;
+import net.minecraft.core.net.command.helpers.EntitySelector;
+
+public class WhoIsCommand {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        CommandNode<CommandSource> command = dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("whois")
+                .then(RequiredArgumentBuilder.<CommandSource, EntitySelector>argument("target", EntityArgumentType.player())
+                        .executes(c -> {
+                            CommandSource source = c.getSource();
+                            EntitySelector entitySelector = c.getArgument("target", EntitySelector.class);
+                            Player player = (Player) entitySelector.get(source).get(0);
+
+                            source.sendTranslatableMessage("commands.commander.whois.success", CommandHelper.getEntityName(player), player.username);
+                            return Command.SINGLE_SUCCESS;
+                        })));
+        dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("realname")
+                .redirect(command));
+    }
+}
diff --git a/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java b/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java
index 8f350b750..0429c77f2 100644
--- a/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java
+++ b/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java
@@ -4,6 +4,7 @@ import com.mojang.logging.LogUtils;
 import net.minecraft.core.Global;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
+import net.minecraft.server.net.command.ServerCommandSource;
 import net.minecraft.core.net.handler.PacketHandler;
 import net.minecraft.core.util.helper.UUIDHelper;
 import net.minecraft.server.entity.player.ServerPlayer;
@@ -211,6 +212,7 @@ public class LoginPacketHandler extends PacketHandler
             }
             player.playerNetServerHandler.sendPacket(new PhotoModePacket(mcServer.disablePhotoMode));
             player.playerNetServerHandler.sendPacket(new GameRulePacket(mcServer.getDimensionWorld(0).getLevelData().getGameRules()));
+            player.playerNetServerHandler.sendPacket(new CommandManagerPacket(this.mcServer.getDimensionWorld(player.dimension).getCommandManager().getDispatcher(), new ServerCommandSource(this.mcServer, player), "", 0));
 
             for (RecipeEntryBase<?, ?, ?> recipe : Registries.RECIPES.getAllSerializableRecipes()) {
                 player.playerNetServerHandler.sendPacket(new RecipeSyncPacket(recipe,Registries.RECIPES.getAllSerializableRecipes().size()));
diff --git a/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java b/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java
index 413f87bc7..471820fca 100644
--- a/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java
+++ b/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java
@@ -1,5 +1,6 @@
 package net.minecraft.server.net.handler;
 
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
 import com.mojang.logging.LogUtils;
 import net.minecraft.core.block.entity.BlockEntity;
 import net.minecraft.core.block.entity.FlagBlockEntity;
@@ -15,41 +16,10 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.ChatEmotes;
 import net.minecraft.core.net.ICommandListener;
 import net.minecraft.core.net.NetworkManager;
-import net.minecraft.core.net.command.Command;
-import net.minecraft.core.net.command.CommandError;
-import net.minecraft.core.net.command.Commands;
-import net.minecraft.core.net.command.PlayerCommandSender;
-import net.minecraft.core.net.command.ServerCommandHandler;
-import net.minecraft.core.net.command.ServerPlayerCommandSender;
 import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.server.net.command.ServerCommandSource;
 import net.minecraft.core.net.handler.PacketHandler;
-import net.minecraft.core.net.packet.ChatPacket;
-import net.minecraft.core.net.packet.PlayerCommandPacket;
-import net.minecraft.core.net.packet.InteractPacket;
-import net.minecraft.core.net.packet.KeepAlivePacket;
-import net.minecraft.core.net.packet.MovePlayerPacket;
-import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.ContainerClosePacket;
-import net.minecraft.core.net.packet.ContainerClickPacket;
-import net.minecraft.core.net.packet.ContainerSetSlotPacket;
-import net.minecraft.core.net.packet.ContainerAckPacket;
-import net.minecraft.core.net.packet.UpdateCreativeInventoryPacket;
-import net.minecraft.core.net.packet.SetHotbarOffsetPacket;
-import net.minecraft.core.net.packet.SignUpdatePacket;
-import net.minecraft.core.net.packet.SetMobSpawnerPacket;
-import net.minecraft.core.net.packet.GuidebookPacket;
-import net.minecraft.core.net.packet.SetItemNamePacket;
-import net.minecraft.core.net.packet.SetPaintingArtPacket;
-import net.minecraft.core.net.packet.PlayerActionPacket;
-import net.minecraft.core.net.packet.UseItemPacket;
-import net.minecraft.core.net.packet.SetCarriedItemPacket;
-import net.minecraft.core.net.packet.AnimatePacket;
-import net.minecraft.core.net.packet.CustomPayloadPacket;
-import net.minecraft.core.net.packet.DisconnectPacket;
-import net.minecraft.core.net.packet.BoatControlPacket;
-import net.minecraft.core.net.packet.BlockUpdatePacket;
-import net.minecraft.core.net.packet.UpdatePlayerProfilePacket;
-import net.minecraft.core.net.packet.RespawnPacket;
+import net.minecraft.core.net.packet.*;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.player.inventory.menu.FlagMenu;
 import net.minecraft.core.player.inventory.menu.CreativeInventoryMenu;
@@ -535,46 +505,12 @@ public class ServerPacketHandler extends PacketHandler
 
     private void handleSlashCommand(String s)
     {
-        PlayerCommandSender sender = new ServerPlayerCommandSender(mcServer, playerEntity);
-        ServerCommandHandler handler = new ServerCommandHandler(mcServer);
-
-        String[] args = s.substring(1).split(" ");
-        String[] args1 = new String[args.length - 1];
-        System.arraycopy(args, 1, args1, 0, args.length - 1);
-
-        for (Command command : Commands.commands)
-        {
-            if (command.isName(args[0]))
-            {
-                if (!sender.isAdmin() && command.opRequired(args1))
-                {
-                    LOGGER.info("Player {} tried command: {}", sender.getPlayer().username, s);
-                    sender.sendMessage(TextFormatting.RED + "You don't have permission to use this command!");
-                    return;
-                }
-
-                LOGGER.info("Player {} used command: {}", sender.getPlayer().username, s);
-                try
-                {
-                    boolean success = command.execute(handler, sender, args1);
-                    if (!success)
-                    {
-                        command.sendCommandSyntax(handler, sender);
-                    }
-                }
-                catch (CommandError e)
-                {
-                    sender.sendMessage(TextFormatting.RED + e.getMessage());
-                }
-                catch (Throwable e)
-                {
-                    LOGGER.error("Exception while trying to perform command '{}'!", s, e);
-                    sender.sendMessage(TextFormatting.RED + "Error!");
-                }
-                return;
-            }
+        ServerCommandSource serverCommandSource = new ServerCommandSource(mcServer, playerEntity);
+        try {
+            playerEntity.world.getCommandManager().execute(s.substring(1), serverCommandSource);
+        } catch (CommandSyntaxException e) {
+            playerEntity.playerNetServerHandler.sendPacket(new ChatPacket(TextFormatting.RED + e.getMessage(), AES.keyChain.get(playerEntity.username)));
         }
-        sender.sendMessage(TextFormatting.RED + "Command '" + args[0] + "' does not exist!");
     }
 
     @Override
@@ -868,6 +804,21 @@ public class ServerPacketHandler extends PacketHandler
         }
     }
 
+    @Override
+    public void handleRequestCommandManagerPacket(RequestCommandManagerPacket packet) {
+        ServerPlayer player = this.mcServer.playerList.getPlayerEntity(packet.username);
+        if (player == null) return;
+        player.playerNetServerHandler.sendPacket(
+            new CommandManagerPacket(
+                this.mcServer.getDimensionWorld(player.dimension)
+                    .getCommandManager().getDispatcher(),
+                new ServerCommandSource(this.mcServer, player),
+                packet.text,
+                packet.cursor
+            )
+        );
+    }
+
     @Override
     public boolean isServerHandler()
     {
diff --git a/src/main/java/net/minecraft/server/world/WorldServer.java b/src/main/java/net/minecraft/server/world/WorldServer.java
index 4291a924d..b3eaea5b7 100644
--- a/src/main/java/net/minecraft/server/world/WorldServer.java
+++ b/src/main/java/net/minecraft/server/world/WorldServer.java
@@ -5,12 +5,10 @@ import java.util.List;
 
 import net.minecraft.core.Global;
 import net.minecraft.core.block.entity.BlockEntity;
-import net.minecraft.core.entity.animal.Animal;
 import net.minecraft.core.util.collection.IntHashMap;
 import net.minecraft.core.world.*;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.entity.animal.WaterAnimal;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.net.packet.*;
diff --git a/src/main/resources/credits.txt b/src/main/resources/credits.txt
index 47de95318..186cd7487 100644
--- a/src/main/resources/credits.txt
+++ b/src/main/resources/credits.txt
@@ -22,6 +22,7 @@ Orknarok_666
 DirtPiper
 Vivian (vivianfox.)
 Snowman64
+AndroidDr (Pedro270707)
 
 !Thank you for playing
 !Better than Adventure!
\ No newline at end of file
