Handle invalid command argument types

The client ignores these presumably for modded servers
Fixes #3806
This commit is contained in:
Nassim Jahnke 2024-04-27 11:25:37 +02:00
parent c9733948b3
commit 7ec6888a30
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
3 changed files with 42 additions and 11 deletions

View File

@ -49,17 +49,17 @@ public interface FullMappings extends BiMappings {
* Returns the unmapped string identifier for the given mapped id. * Returns the unmapped string identifier for the given mapped id.
* *
* @param id unmapped id * @param id unmapped id
* @return unmapped string identifier * @return unmapped string identifier, or null if out of bounds
*/ */
String identifier(int id); @Nullable String identifier(int id);
/** /**
* Returns the mapped string identifier for the given mapped id. * Returns the mapped string identifier for the given mapped id.
* *
* @param mappedId mapped id * @param mappedId mapped id
* @return mapped string identifier * @return mapped string identifier, or null if out of bounds
*/ */
String mappedIdentifier(int mappedId); @Nullable String mappedIdentifier(int mappedId);
/** /**
* Returns the mapped string identifier for the given unmapped identifier. * Returns the mapped string identifier for the given unmapped identifier.

View File

@ -66,12 +66,20 @@ public class FullMappingsBase implements FullMappings {
@Override @Override
public String identifier(final int id) { public String identifier(final int id) {
if (id < 0 || id >= idToString.length) {
return null;
}
final String identifier = idToString[id]; final String identifier = idToString[id];
return Key.namespaced(identifier); return Key.namespaced(identifier);
} }
@Override @Override
public String mappedIdentifier(final int mappedId) { public String mappedIdentifier(final int mappedId) {
if (mappedId < 0 || mappedId >= mappedIdToString.length) {
return null;
}
final String identifier = mappedIdToString[mappedId]; final String identifier = mappedIdToString[mappedId];
return Key.namespaced(identifier); return Key.namespaced(identifier);
} }

View File

@ -18,12 +18,14 @@
package com.viaversion.viaversion.rewriter; package com.viaversion.viaversion.rewriter;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Abstract rewriter for the declare commands packet to handle argument type name and content changes. * Abstract rewriter for the declare commands packet to handle argument type name and content changes.
@ -118,16 +120,23 @@ public class CommandRewriter<C extends ClientboundPacketType> {
if (nodeType == 2) { // Argument node if (nodeType == 2) { // Argument node
int argumentTypeId = wrapper.read(Type.VAR_INT); int argumentTypeId = wrapper.read(Type.VAR_INT);
String argumentType = argumentType(argumentTypeId); String argumentType = argumentType(argumentTypeId);
if (argumentType == null) {
// Modded servers may send unknown argument types that are ignored by the client
// Adjust the id to the hopefully still assumed out-of-bounds pos...
wrapper.write(Type.VAR_INT, mapInvalidArgumentType(argumentTypeId));
continue;
}
String newArgumentType = handleArgumentType(argumentType); String newArgumentType = handleArgumentType(argumentType);
Preconditions.checkNotNull(newArgumentType, "No mapping for argument type %s", argumentType); Preconditions.checkNotNull(newArgumentType, "No mapping for argument type %s", argumentType);
wrapper.write(Type.VAR_INT, mappedArgumentTypeId(newArgumentType)); wrapper.write(Type.VAR_INT, mappedArgumentTypeId(newArgumentType));
// Always call the handler using the previous name // Always call the handler using the previous name
handleArgument(wrapper, argumentType); handleArgument(wrapper, argumentType);
}
if ((flags & 0x10) != 0) { if ((flags & 0x10) != 0) {
wrapper.passthrough(Type.STRING); // Suggestion type wrapper.passthrough(Type.STRING); // Suggestion type
}
} }
} }
@ -148,21 +157,35 @@ public class CommandRewriter<C extends ClientboundPacketType> {
* @param argumentType argument type * @param argumentType argument type
* @return mapped argument type * @return mapped argument type
*/ */
public String handleArgumentType(String argumentType) { public String handleArgumentType(final String argumentType) {
if (protocol.getMappingData() != null && protocol.getMappingData().getArgumentTypeMappings() != null) { if (protocol.getMappingData() != null && protocol.getMappingData().getArgumentTypeMappings() != null) {
return protocol.getMappingData().getArgumentTypeMappings().mappedIdentifier(argumentType); return protocol.getMappingData().getArgumentTypeMappings().mappedIdentifier(argumentType);
} }
return argumentType; return argumentType;
} }
protected String argumentType(int argumentTypeId) { protected @Nullable String argumentType(final int argumentTypeId) {
return protocol.getMappingData().getArgumentTypeMappings().identifier(argumentTypeId); final FullMappings mappings = protocol.getMappingData().getArgumentTypeMappings();
final String identifier = mappings.identifier(argumentTypeId);
// Allow unknown argument types to be passed through as long as they are actually out of bounds
Preconditions.checkArgument(identifier != null || argumentTypeId >= mappings.size(), "Unknown argument type id %s", argumentTypeId);
return identifier;
} }
protected int mappedArgumentTypeId(String mappedArgumentType) { protected int mappedArgumentTypeId(final String mappedArgumentType) {
return protocol.getMappingData().getArgumentTypeMappings().mappedId(mappedArgumentType); return protocol.getMappingData().getArgumentTypeMappings().mappedId(mappedArgumentType);
} }
private int mapInvalidArgumentType(final int id) {
if (id < 0) {
return id;
}
final FullMappings mappings = protocol.getMappingData().getArgumentTypeMappings();
final int idx = id - mappings.size();
return mappings.mappedSize() + idx;
}
@FunctionalInterface @FunctionalInterface
public interface CommandArgumentConsumer { public interface CommandArgumentConsumer {