mirror of
https://github.com/EngineHub/WorldEdit.git
synced 2025-03-07 13:48:00 +08:00
Change //stack and //move to take a full offset
This commit is contained in:
parent
043faaf55f
commit
5f9f10599e
@ -1289,7 +1289,7 @@ public int stackCuboidRegion(Region region, BlockVector3 dir, int count, boolean
|
||||
* Stack a cuboid region.
|
||||
*
|
||||
* @param region the region to stack
|
||||
* @param dir the direction to stack
|
||||
* @param offset how far to move the contents each stack
|
||||
* @param count the number of times to stack
|
||||
* @param copyEntities true to copy entities
|
||||
* @param copyBiomes true to copy biomes
|
||||
@ -1297,17 +1297,17 @@ public int stackCuboidRegion(Region region, BlockVector3 dir, int count, boolean
|
||||
* @return number of blocks affected
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
||||
*/
|
||||
public int stackCuboidRegion(Region region, BlockVector3 dir, int count,
|
||||
public int stackCuboidRegion(Region region, BlockVector3 offset, int count,
|
||||
boolean copyEntities, boolean copyBiomes, Mask mask) throws MaxChangedBlocksException {
|
||||
checkNotNull(region);
|
||||
checkNotNull(dir);
|
||||
checkNotNull(offset);
|
||||
checkArgument(count >= 1, "count >= 1 required");
|
||||
|
||||
BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
|
||||
BlockVector3 to = region.getMinimumPoint();
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to);
|
||||
copy.setRepetitions(count);
|
||||
copy.setTransform(new AffineTransform().translate(dir.multiply(size)));
|
||||
copy.setTransform(new AffineTransform().translate(offset.multiply(size)));
|
||||
copy.setCopyingEntities(copyEntities);
|
||||
copy.setCopyingBiomes(copyBiomes);
|
||||
if (mask != null) {
|
||||
@ -1321,23 +1321,23 @@ public int stackCuboidRegion(Region region, BlockVector3 dir, int count,
|
||||
* Move the blocks in a region a certain direction.
|
||||
*
|
||||
* @param region the region to move
|
||||
* @param dir the direction
|
||||
* @param distance the distance to move
|
||||
* @param offset the offset
|
||||
* @param multiplier the number to multiply the offset by
|
||||
* @param copyAir true to copy air blocks
|
||||
* @param replacement the replacement pattern to fill in after moving, or null to use air
|
||||
* @return number of blocks moved
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
||||
*/
|
||||
public int moveRegion(Region region, BlockVector3 dir, int distance, boolean copyAir, Pattern replacement) throws MaxChangedBlocksException {
|
||||
return moveRegion(region, dir, distance, true, false, copyAir ? new ExistingBlockMask(this) : null, replacement);
|
||||
public int moveRegion(Region region, BlockVector3 offset, int multiplier, boolean copyAir, Pattern replacement) throws MaxChangedBlocksException {
|
||||
return moveRegion(region, offset, multiplier, true, false, copyAir ? new ExistingBlockMask(this) : null, replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the blocks in a region a certain direction.
|
||||
*
|
||||
* @param region the region to move
|
||||
* @param dir the direction
|
||||
* @param distance the distance to move
|
||||
* @param offset the offset
|
||||
* @param multiplier the number to multiply the offset by
|
||||
* @param moveEntities true to move entities
|
||||
* @param copyBiomes true to copy biomes (source biome is unchanged)
|
||||
* @param mask source mask for the operation (only matching blocks are moved)
|
||||
@ -1346,11 +1346,11 @@ public int moveRegion(Region region, BlockVector3 dir, int distance, boolean cop
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
||||
* @throws IllegalArgumentException thrown if the region is not a flat region, but copyBiomes is true
|
||||
*/
|
||||
public int moveRegion(Region region, BlockVector3 dir, int distance,
|
||||
public int moveRegion(Region region, BlockVector3 offset, int multiplier,
|
||||
boolean moveEntities, boolean copyBiomes, Mask mask, Pattern replacement) throws MaxChangedBlocksException {
|
||||
checkNotNull(region);
|
||||
checkNotNull(dir);
|
||||
checkArgument(distance >= 1, "distance >= 1 required");
|
||||
checkNotNull(offset);
|
||||
checkArgument(multiplier >= 1, "multiplier >= 1 required");
|
||||
checkArgument(!copyBiomes || region instanceof FlatRegion, "can't copy biomes from non-flat region");
|
||||
|
||||
BlockVector3 to = region.getMinimumPoint();
|
||||
@ -1364,7 +1364,7 @@ public int moveRegion(Region region, BlockVector3 dir, int distance,
|
||||
// Copy to a buffer so we don't destroy our original before we can copy all the blocks from it
|
||||
ForgetfulExtentBuffer buffer = new ForgetfulExtentBuffer(this, new RegionMask(region));
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(this, region, buffer, to);
|
||||
copy.setTransform(new AffineTransform().translate(dir.multiply(distance)));
|
||||
copy.setTransform(new AffineTransform().translate(offset.multiply(multiplier)));
|
||||
copy.setSourceFunction(remove); // Remove
|
||||
|
||||
copy.setCopyingEntities(moveEntities);
|
||||
|
@ -41,7 +41,7 @@
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.visitor.LayerVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
import com.sk89q.worldedit.internal.annotation.Direction;
|
||||
import com.sk89q.worldedit.internal.annotation.Offset;
|
||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -299,11 +299,11 @@ public int smooth(Actor actor, EditSession editSession, @Selection Region region
|
||||
@Logging(ORIENTATION_REGION)
|
||||
public int move(Actor actor, World world, EditSession editSession, LocalSession session,
|
||||
@Selection Region region,
|
||||
@Arg(desc = "# of blocks to move", def = "1")
|
||||
int count,
|
||||
@Arg(desc = "The direction to move", def = Direction.AIM)
|
||||
@Direction(includeDiagonals = true)
|
||||
BlockVector3 direction,
|
||||
@Arg(desc = "number of times to apply the offset", def = "1")
|
||||
int multiplier,
|
||||
@Arg(desc = "The offset to move", def = Offset.FORWARD)
|
||||
@Offset
|
||||
BlockVector3 offset,
|
||||
@Arg(desc = "The pattern of blocks to leave", def = "air")
|
||||
Pattern replace,
|
||||
@Switch(name = 's', desc = "Shift the selection to the target location")
|
||||
@ -316,7 +316,7 @@ public int move(Actor actor, World world, EditSession editSession, LocalSession
|
||||
boolean copyBiomes,
|
||||
@ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air")
|
||||
Mask mask) throws WorldEditException {
|
||||
checkCommandArgument(count >= 1, "Count must be >= 1");
|
||||
checkCommandArgument(multiplier >= 1, "Multiplier must be >= 1");
|
||||
|
||||
Mask combinedMask;
|
||||
if (ignoreAirBlocks) {
|
||||
@ -329,11 +329,11 @@ public int move(Actor actor, World world, EditSession editSession, LocalSession
|
||||
combinedMask = mask;
|
||||
}
|
||||
|
||||
int affected = editSession.moveRegion(region, direction, count, copyEntities, copyBiomes, combinedMask, replace);
|
||||
int affected = editSession.moveRegion(region, offset, multiplier, copyEntities, copyBiomes, combinedMask, replace);
|
||||
|
||||
if (moveSelection) {
|
||||
try {
|
||||
region.shift(direction.multiply(count));
|
||||
region.shift(offset.multiply(multiplier));
|
||||
|
||||
session.getRegionSelector(world).learnChanges();
|
||||
session.getRegionSelector(world).explainRegionAdjust(actor, session);
|
||||
@ -356,9 +356,9 @@ public int stack(Actor actor, World world, EditSession editSession, LocalSession
|
||||
@Selection Region region,
|
||||
@Arg(desc = "# of copies to stack", def = "1")
|
||||
int count,
|
||||
@Arg(desc = "The direction to stack", def = Direction.AIM)
|
||||
@Direction(includeDiagonals = true)
|
||||
BlockVector3 direction,
|
||||
@Arg(desc = "How far to move the contents each stack", def = Offset.FORWARD)
|
||||
@Offset
|
||||
BlockVector3 offset,
|
||||
@Switch(name = 's', desc = "Shift the selection to the last stacked copy")
|
||||
boolean moveSelection,
|
||||
@Switch(name = 'a', desc = "Ignore air blocks")
|
||||
@ -381,13 +381,13 @@ public int stack(Actor actor, World world, EditSession editSession, LocalSession
|
||||
combinedMask = mask;
|
||||
}
|
||||
|
||||
int affected = editSession.stackCuboidRegion(region, direction, count, copyEntities, copyBiomes, combinedMask);
|
||||
int affected = editSession.stackCuboidRegion(region, offset, count, copyEntities, copyBiomes, combinedMask);
|
||||
|
||||
if (moveSelection) {
|
||||
try {
|
||||
final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
|
||||
|
||||
final BlockVector3 shiftVector = direction.multiply(size).multiply(count);
|
||||
final BlockVector3 shiftVector = offset.multiply(size).multiply(count);
|
||||
region.shift(shiftVector);
|
||||
|
||||
session.getRegionSelector(world).learnChanges();
|
||||
|
@ -25,9 +25,9 @@
|
||||
import com.sk89q.worldedit.UnknownDirectionException;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.internal.annotation.Direction;
|
||||
import com.sk89q.worldedit.internal.annotation.MultiDirection;
|
||||
import com.sk89q.worldedit.internal.annotation.OptionalArg;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import org.enginehub.piston.CommandManager;
|
||||
@ -58,12 +58,12 @@ private static MultiDirection multiDirection(boolean includeDiagonals) {
|
||||
protected static <D> void register(CommandManager commandManager, AbstractDirectionConverter<D> converter,
|
||||
Class<D> keyClass, boolean includeDiagonals) {
|
||||
commandManager.registerConverter(
|
||||
Key.of(keyClass, direction(includeDiagonals)),
|
||||
converter
|
||||
Key.of(keyClass, direction(includeDiagonals)),
|
||||
converter
|
||||
);
|
||||
commandManager.registerConverter(
|
||||
Key.of(keyClass, multiDirection(includeDiagonals)),
|
||||
CommaSeparatedValuesConverter.wrap(converter)
|
||||
Key.of(keyClass, multiDirection(includeDiagonals)),
|
||||
CommaSeparatedValuesConverter.wrap(converter)
|
||||
);
|
||||
}
|
||||
|
||||
@ -93,8 +93,8 @@ protected AbstractDirectionConverter(WorldEdit worldEdit, boolean includeDiagona
|
||||
|
||||
@Override
|
||||
public ConversionResult<D> convert(String argument, InjectedValueAccess context) {
|
||||
Player player = context.injectedValue(Key.of(Actor.class))
|
||||
.filter(Player.class::isInstance).map(Player.class::cast).orElse(null);
|
||||
Player player = context.injectedValue(Key.of(Player.class, OptionalArg.class))
|
||||
.orElse(null);
|
||||
try {
|
||||
return SuccessfulConversion.fromSingle(convertDirection(argument, player, includeDiagonals));
|
||||
} catch (Exception e) {
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
public final class DirectionVectorConverter extends AbstractDirectionConverter<BlockVector3> {
|
||||
|
||||
private DirectionVectorConverter(WorldEdit worldEdit, boolean includeDiagonals) {
|
||||
public DirectionVectorConverter(WorldEdit worldEdit, boolean includeDiagonals) {
|
||||
super(worldEdit, includeDiagonals);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command.argument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.internal.annotation.Offset;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import org.enginehub.piston.CommandManager;
|
||||
import org.enginehub.piston.converter.ArgumentConverter;
|
||||
import org.enginehub.piston.converter.ConversionResult;
|
||||
import org.enginehub.piston.inject.InjectedValueAccess;
|
||||
import org.enginehub.piston.inject.Key;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OffsetConverter implements ArgumentConverter<BlockVector3> {
|
||||
|
||||
public static void register(WorldEdit worldEdit, CommandManager commandManager) {
|
||||
commandManager.registerConverter(
|
||||
Key.of(BlockVector3.class, Offset.class),
|
||||
new OffsetConverter(worldEdit)
|
||||
);
|
||||
}
|
||||
|
||||
private final DirectionVectorConverter directionVectorConverter;
|
||||
private final VectorConverter<Integer, BlockVector3> vectorConverter =
|
||||
VectorConverter.BLOCK_VECTOR_3_CONVERTER;
|
||||
|
||||
private OffsetConverter(WorldEdit worldEdit) {
|
||||
directionVectorConverter = new DirectionVectorConverter(worldEdit, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component describeAcceptableArguments() {
|
||||
return TextComponent.builder()
|
||||
.append(directionVectorConverter.describeAcceptableArguments())
|
||||
.append(", or ")
|
||||
.append(vectorConverter.describeAcceptableArguments())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(String input, InjectedValueAccess context) {
|
||||
return ImmutableList.copyOf(Iterables.concat(
|
||||
directionVectorConverter.getSuggestions(input, context),
|
||||
vectorConverter.getSuggestions(input, context)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversionResult<BlockVector3> convert(String input, InjectedValueAccess context) {
|
||||
return directionVectorConverter.convert(input, context)
|
||||
.orElse(vectorConverter.convert(input, context));
|
||||
}
|
||||
}
|
@ -40,12 +40,22 @@
|
||||
import java.util.function.Function;
|
||||
|
||||
public class VectorConverter<C, T> implements ArgumentConverter<T> {
|
||||
|
||||
private static final CommaSeparatedValuesConverter<Integer> INT_CONVERTER =
|
||||
CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(int.class)));
|
||||
|
||||
public static final VectorConverter<Integer, BlockVector3> BLOCK_VECTOR_3_CONVERTER = new VectorConverter<>(
|
||||
INT_CONVERTER,
|
||||
3,
|
||||
cmps -> BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)),
|
||||
"block vector with x, y, and z"
|
||||
);
|
||||
|
||||
public static void register(CommandManager commandManager) {
|
||||
CommaSeparatedValuesConverter<Integer> intConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(int.class)));
|
||||
CommaSeparatedValuesConverter<Double> doubleConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(double.class)));
|
||||
commandManager.registerConverter(Key.of(BlockVector2.class),
|
||||
new VectorConverter<>(
|
||||
intConverter,
|
||||
INT_CONVERTER,
|
||||
2,
|
||||
cmps -> BlockVector2.at(cmps.get(0), cmps.get(1)),
|
||||
"block vector with x and z"
|
||||
@ -57,13 +67,7 @@ public static void register(CommandManager commandManager) {
|
||||
cmps -> Vector2.at(cmps.get(0), cmps.get(1)),
|
||||
"vector with x and z"
|
||||
));
|
||||
commandManager.registerConverter(Key.of(BlockVector3.class),
|
||||
new VectorConverter<>(
|
||||
intConverter,
|
||||
3,
|
||||
cmps -> BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)),
|
||||
"block vector with x, y, and z"
|
||||
));
|
||||
commandManager.registerConverter(Key.of(BlockVector3.class), BLOCK_VECTOR_3_CONVERTER);
|
||||
commandManager.registerConverter(Key.of(Vector3.class),
|
||||
new VectorConverter<>(
|
||||
doubleConverter,
|
||||
|
@ -77,6 +77,7 @@
|
||||
import com.sk89q.worldedit.command.argument.EnumConverter;
|
||||
import com.sk89q.worldedit.command.argument.FactoryConverter;
|
||||
import com.sk89q.worldedit.command.argument.HeightConverter;
|
||||
import com.sk89q.worldedit.command.argument.OffsetConverter;
|
||||
import com.sk89q.worldedit.command.argument.RegionFactoryConverter;
|
||||
import com.sk89q.worldedit.command.argument.RegistryConverter;
|
||||
import com.sk89q.worldedit.command.argument.SideEffectConverter;
|
||||
@ -90,6 +91,7 @@
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.annotation.OptionalArg;
|
||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||
import com.sk89q.worldedit.internal.command.CommandArgParser;
|
||||
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
|
||||
@ -220,6 +222,7 @@ private void registerArgumentConverters() {
|
||||
WorldConverter.register(commandManager);
|
||||
SideEffectConverter.register(commandManager);
|
||||
HeightConverter.register(commandManager);
|
||||
OffsetConverter.register(worldEdit, commandManager);
|
||||
}
|
||||
|
||||
private void registerAlwaysInjectedValues() {
|
||||
@ -559,6 +562,7 @@ private MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor
|
||||
store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor));
|
||||
if (actor instanceof Player) {
|
||||
store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor));
|
||||
store.injectValue(Key.of(Player.class, OptionalArg.class), ValueProvider.constant((Player) actor));
|
||||
} else {
|
||||
store.injectValue(Key.of(Player.class), context -> {
|
||||
throw new CommandException(TranslatableComponent.of("worldedit.command.player-only"), ImmutableList.of());
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import org.enginehub.piston.inject.InjectAnnotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a {@link BlockVector3} parameter to inject an offset.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
@InjectAnnotation
|
||||
public @interface Offset {
|
||||
String FORWARD = "forward";
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import org.enginehub.piston.inject.InjectAnnotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a parameter to indicate it as optional. This is really a bit of a hack, used to
|
||||
* get a {@link Player} or {@code null} instead of throwing.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
@InjectAnnotation
|
||||
public @interface OptionalArg {
|
||||
}
|
Loading…
Reference in New Issue
Block a user