Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix ClientCommandSourceStack crashing or returning improper values for certain method calls #1928

Open
wants to merge 2 commits into
base: 1.21.x
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.stream.Collectors;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.SharedSuggestionProvider;
Expand All @@ -27,6 +28,7 @@
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
Expand All @@ -42,65 +44,84 @@ public ClientCommandSourceStack(CommandSource source, Vec3 position, Vec2 rotati
super(source, position, rotation, null, permission, plainTextName, displayName, null, executing);
}

/**
* {@return the current connection, used to shorten method calls and hide the nullability warnings}
*/
private ClientPacketListener connection() {
return Minecraft.getInstance().getConnection();
}

/**
* Sends a success message without attempting to get the server side list of admins
*/
@Override
public void sendSuccess(Supplier<Component> message, boolean sendToAdmins) {
Minecraft.getInstance().gui.getChat().addMessage(message.get());
//Don't send the message to admins, as that requires querying the server for the list of admins, and would cause a NPE
super.sendSuccess(message, false);
}

/**
* {@return the list of teams from the client side}
*/
@Override
public Collection<String> getAllTeams() {
return Minecraft.getInstance().level.getScoreboard().getTeamNames();
return getScoreboard().getTeamNames();
}

/**
* {@return the list of online player names from the client side}
*/
@Override
public Collection<String> getOnlinePlayerNames() {
return Minecraft.getInstance().getConnection().getOnlinePlayers().stream().map((player) -> player.getProfile().getName()).collect(Collectors.toList());
return connection().getOnlinePlayers().stream().map(player -> player.getProfile().getName()).collect(Collectors.toList());
}

@Override
public CompletableFuture<Suggestions> suggestRegistryElements(
ResourceKey<? extends Registry<?>> p_212330_,
SharedSuggestionProvider.ElementSuggestionType p_212331_,
SuggestionsBuilder p_212332_,
CommandContext<?> p_212333_) {
// TODO 1.21.2: Not sure what to do here. Letting super get called will cause an NPE on this.server.
if (p_212330_ == Registries.RECIPE || p_212330_ == Registries.ADVANCEMENT) {
ResourceKey<? extends Registry<?>> registry,
SharedSuggestionProvider.ElementSuggestionType suggestionType,
SuggestionsBuilder suggestionsBuilder,
CommandContext<?> context) {
if (registry == Registries.RECIPE) {
// TODO 1.21.2: Not sure what to do here as the client doesn't receive recipe names. Letting super get called will cause an NPE on this.server.
return Suggestions.empty();
} else if (registry == Registries.ADVANCEMENT) {
//Only suggest from advancements that are visible to the player
return SharedSuggestionProvider.suggestResource(connection().getAdvancements().getTree().nodes().stream().map(node -> node.holder().id()), suggestionsBuilder);
}
return super.suggestRegistryElements(p_212330_, p_212331_, p_212332_, p_212333_);
return super.suggestRegistryElements(registry, suggestionType, suggestionsBuilder, context);
}

/**
* {@return a set of {@link ResourceKey} for levels from the client side}
*/
@Override
public Set<ResourceKey<Level>> levels() {
return Minecraft.getInstance().getConnection().levels();
return connection().levels();
}

/**
* {@return the {@link RegistryAccess} from the client side}
*/
@Override
public RegistryAccess registryAccess() {
return Minecraft.getInstance().getConnection().registryAccess();
return connection().registryAccess();
}

/**
* {@return the {@link FeatureFlagSet } from the client side}
*/
@Override
public FeatureFlagSet enabledFeatures() {
return connection().enabledFeatures();
}

/**
* {@return the scoreboard from the client side}
*/
@Override
public Scoreboard getScoreboard() {
return Minecraft.getInstance().level.getScoreboard();
return connection().scoreboard();
}

/**
Expand All @@ -109,15 +130,15 @@ public Scoreboard getScoreboard() {
@Override
@Nullable
public AdvancementHolder getAdvancement(ResourceLocation id) {
return Minecraft.getInstance().getConnection().getAdvancements().get(id);
return connection().getAdvancements().get(id);
}

/**
* {@return the level from the client side}
*/
@Override
public Level getUnsidedLevel() {
return Minecraft.getInstance().level;
return connection().getLevel();
}

/**
Expand Down