use of org.spongepowered.api.world.volume.archetype.ArchetypeVolume in project SpongeCommon by SpongePowered.
the class VolumeStreamTest method onGamePreInitialization.
@Listener
public void onGamePreInitialization(final RegisterCommandEvent<Command.Parameterized> event) throws IOException, CommandException {
this.schematicsDir = this.config.resolve("schematics");
Files.createDirectories(this.config);
final Parameter.Value<Biome> biomeKey = Parameter.registryElement(TypeToken.get(Biome.class), ImmutableList.of(VariableValueParameters.RegistryEntryBuilder.WORLD_FROM_LOCATABLE_HOLDER_PROVIDER, VariableValueParameters.RegistryEntryBuilder.WORLD_FROM_CAUSE_HOLDER_PROVIDER), RegistryTypes.BIOME, "minecraft").key("format").build();
event.register(this.plugin, Command.builder().shortDescription(Component.text("Sets the biome in a selected region")).permission(this.plugin.metadata().id() + ".command.setbiome").addParameter(biomeKey).executor(src -> {
if (!(src.cause().root() instanceof ServerPlayer)) {
src.sendMessage(Identity.nil(), Component.text("Player only.", NamedTextColor.RED));
return CommandResult.success();
}
final ServerPlayer player = (ServerPlayer) src.cause().root();
final PlayerData data = VolumeStreamTest.get(player);
if (data.getPos1() == null || data.getPos2() == null) {
player.sendMessage(Identity.nil(), Component.text("You must set both positions before copying", NamedTextColor.RED));
return CommandResult.success();
}
final Vector3i min = data.getPos1().min(data.getPos2());
final Vector3i max = data.getPos1().max(data.getPos2());
final Biome target = src.requireOne(biomeKey);
player.world().biomeStream(min, max, StreamOptions.forceLoadedAndCopied()).map((world, biome, x, y, z) -> target).apply(VolumeCollectors.of(player.world(), VolumePositionTranslators.identity(), VolumeApplicators.applyBiomes()));
return CommandResult.success();
}).build(), "setBiome");
event.register(this.plugin, Command.builder().shortDescription(Component.text("Copies a region of the world to your clipboard")).permission(this.plugin.metadata().id() + ".command.copy").executor(src -> {
if (!(src.cause().root() instanceof Player)) {
src.sendMessage(Identity.nil(), Component.text("Player only.", NamedTextColor.RED));
return CommandResult.success();
}
final Player player = (Player) src.cause().root();
final PlayerData data = VolumeStreamTest.get(player);
if (data.getPos1() == null || data.getPos2() == null) {
player.sendMessage(Identity.nil(), Component.text("You must set both positions before copying", NamedTextColor.RED));
return CommandResult.success();
}
final Vector3i min = data.getPos1().min(data.getPos2());
final Vector3i max = data.getPos1().max(data.getPos2());
data.setOrigin(player.blockPosition());
final ArchetypeVolume archetypeVolume = player.world().createArchetypeVolume(min, max, player.blockPosition());
data.setClipboard(archetypeVolume);
player.sendMessage(Identity.nil(), Component.text("Saved to clipboard.", VolumeStreamTest.GREEN));
return CommandResult.success();
}).build(), "copy");
event.register(this.plugin, Command.builder().shortDescription(Component.text("Pastes your clipboard to where you are standing")).permission(this.plugin.metadata().id() + ".command.paste").executor(src -> {
if (!(src.cause().root() instanceof ServerPlayer)) {
src.sendMessage(Identity.nil(), Component.text("Player only.", NamedTextColor.RED));
return CommandResult.success();
}
final ServerPlayer player = (ServerPlayer) src.cause().root();
final PlayerData data = VolumeStreamTest.get(player);
final ArchetypeVolume volume = data.getClipboard();
if (volume == null) {
player.sendMessage(Identity.nil(), Component.text("You must copy something before pasting", NamedTextColor.RED));
return CommandResult.success();
}
try (final CauseStackManager.StackFrame frame = Sponge.server().causeStackManager().pushCauseFrame()) {
frame.pushCause(this.plugin);
volume.applyToWorld(player.world(), player.blockPosition(), SpawnTypes.PLACEMENT::get);
}
src.sendMessage(Identity.nil(), Component.text("Pasted clipboard into world.", VolumeStreamTest.GREEN));
return CommandResult.success();
}).build(), "paste");
final Parameter.Value<String> fileName = Parameter.string().key("fileName").build();
event.register(this.plugin, Command.builder().shortDescription(Component.text("Pastes your clipboard to where you are standing")).permission(this.plugin.metadata().id() + ".command.paste").addParameter(fileName).executor(src -> {
if (!(src.cause().root() instanceof ServerPlayer)) {
src.sendMessage(Identity.nil(), Component.text("Player only.", NamedTextColor.RED));
return CommandResult.success();
}
final String file = src.requireOne(fileName);
final Path desiredFilePath = this.schematicsDir.resolve(file + VolumeStreamTest.FILE_ENDING);
if (Files.exists(desiredFilePath)) {
throw new CommandException(Component.text(file + " already exists, please delete the file first", NamedTextColor.RED));
}
if (Files.isDirectory(desiredFilePath)) {
throw new CommandException(Component.text(file + "is a directory, please use a file name", NamedTextColor.RED));
}
final ServerPlayer player = (ServerPlayer) src.cause().root();
final PlayerData data = VolumeStreamTest.get(player);
final ArchetypeVolume volume = data.getClipboard();
if (volume == null) {
player.sendMessage(Identity.nil(), Component.text("You must copy something before pasting", NamedTextColor.RED));
return CommandResult.success();
}
final Schematic schematic = Schematic.builder().volume(data.getClipboard()).metaValue(Schematic.METADATA_AUTHOR, player.name()).metaValue(Schematic.METADATA_NAME, file).build();
final DataContainer schematicData = Sponge.dataManager().translator(Schematic.class).orElseThrow(() -> new IllegalStateException("Sponge doesn't have a DataTranslator for Schematics!")).translate(schematic);
try {
final Path output = Files.createFile(desiredFilePath);
DataFormats.NBT.get().writeTo(new GZIPOutputStream(Files.newOutputStream(output)), schematicData);
player.sendMessage(Identity.nil(), Component.text("Saved schematic to " + output.toAbsolutePath(), VolumeStreamTest.SAVE));
} catch (final Exception e) {
e.printStackTrace();
final StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
final Component errorText = Component.text(writer.toString().replace("\t", " ").replace("\r\n", "\n").replace("\r", "\n"));
final TextComponent text = Component.text("Error saving schematic: " + e.getMessage(), NamedTextColor.RED).hoverEvent(HoverEvent.showText(errorText));
return CommandResult.builder().error(text).build();
}
return CommandResult.success();
}).build(), "save");
event.register(this.plugin, Command.builder().shortDescription(Component.text("Load a schematic from file")).permission(this.plugin.metadata().id() + ".command.load").addParameter(fileName).executor(src -> {
if (!(src.cause().root() instanceof ServerPlayer)) {
src.sendMessage(Identity.nil(), Component.text("Player only.", NamedTextColor.RED));
return CommandResult.success();
}
final ServerPlayer player = (ServerPlayer) src.cause().root();
final String file = src.requireOne(fileName);
final Path desiredFilePath = this.schematicsDir.resolve(file + VolumeStreamTest.FILE_ENDING);
if (!Files.isRegularFile(desiredFilePath)) {
throw new CommandException(Component.text("File " + file + " was not a normal schemaic file"));
}
final Schematic schematic;
final DataContainer schematicContainer;
try (final GZIPInputStream stream = new GZIPInputStream(Files.newInputStream(desiredFilePath))) {
schematicContainer = DataFormats.NBT.get().readFrom(stream);
} catch (IOException e) {
e.printStackTrace();
final StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
final Component errorText = Component.text(writer.toString().replace("\t", " ").replace("\r\n", "\n").replace("\r", "\n"));
final TextComponent text = Component.text("Error loading schematic: " + e.getMessage(), NamedTextColor.RED).hoverEvent(HoverEvent.showText(errorText));
return CommandResult.builder().error(text).build();
}
schematic = Sponge.dataManager().translator(Schematic.class).orElseThrow(() -> new IllegalStateException("Expected a DataTranslator for a Schematic")).translate(schematicContainer);
src.sendMessage(Identity.nil(), Component.text("Loaded schematic from " + file, TextColor.color(0x003434)));
final PlayerData data = VolumeStreamTest.get(player);
data.setClipboard(schematic);
data.setOrigin(player.blockPosition());
return CommandResult.success();
}).build(), "load");
final Parameter.Value<Rotation> rotation = Parameter.registryElement(TypeToken.get(Rotation.class), RegistryTypes.ROTATION).key("rotation").build();
event.register(this.plugin, Command.builder().shortDescription(Component.text("Rotate clipboard")).permission(this.plugin.metadata().id() + ".command.rotate").addParameter(rotation).executor(src -> {
if (!(src.cause().root() instanceof ServerPlayer)) {
src.sendMessage(Identity.nil(), Component.text("Player only.", NamedTextColor.RED));
return CommandResult.success();
}
final ServerPlayer player = (ServerPlayer) src.cause().root();
final Rotation desiredRotation = src.requireOne(rotation);
final Schematic schematic;
final PlayerData data = VolumeStreamTest.get(player);
if (data.clipboard == null) {
throw new CommandException(Component.text("Load a clipboard first before trying to rotate it"));
}
final ArchetypeVolume newClipboard = data.clipboard.transform(Transformation.builder().origin(data.clipboard.min().toDouble().add(data.clipboard.size().toDouble().div(2))).rotate(desiredRotation).build());
src.sendMessage(Identity.nil(), Component.text("Rotated clipboard " + desiredRotation.angle().degrees() + " degrees"));
data.setClipboard(newClipboard);
return CommandResult.success();
}).build(), "rotate");
}
use of org.spongepowered.api.world.volume.archetype.ArchetypeVolume in project SpongeCommon by SpongePowered.
the class AbstractReferentArchetypeVolume method applyTransformationsToStream.
private <T> VolumeStream<ArchetypeVolume, T> applyTransformationsToStream(final Vector3i min, final Vector3i max, final StreamOptions options, final StreamCreator<A, T> streamCreator, final VolumeStreamUtils.TriFunction<VolumeElement<ArchetypeVolume, T>, Supplier<Rotation>, Supplier<Mirror>, T> elementTransform) {
final Vector3i transformedMin = this.min();
final Vector3i transformedMax = this.max();
VolumeStreamUtils.validateStreamArgs(min, max, transformedMin, transformedMax, options);
final Vector3i minDiff = min.sub(transformedMin);
final Vector3i maxDiff = transformedMax.sub(max);
final boolean xMirror = this.transformation.mirror(Axis.X);
final boolean zMirror = this.transformation.mirror(Axis.Z);
final Supplier<Mirror> mirror = xMirror ? Mirrors.FRONT_BACK : zMirror ? Mirrors.LEFT_RIGHT : Mirrors.NONE;
return this.applyReference(a -> streamCreator.createStream(a, a.min().add(minDiff), a.max().sub(maxDiff), options)).transform(e -> VolumeElement.of(this, elementTransform.apply(e, this.transformation::rotation, mirror), this.transformStreamBlockPosition(e.position().add(VolumePositionTranslators.BLOCK_OFFSET)).sub(VolumePositionTranslators.BLOCK_OFFSET)));
}
use of org.spongepowered.api.world.volume.archetype.ArchetypeVolume in project SpongeCommon by SpongePowered.
the class VolumeTransformationTest method testTransformationsOfPositions.
@MethodSource("testTransformationsOfPositions")
@ParameterizedTest
void testTransformationsOfPositions(final Vector3i min, final Vector3i max, final Vector3i origin, final Vector3i testForRoundTrip, final int rotationCount, final StubRotations wanted) {
final SpongeArchetypeVolume volume = VolumeTransformationTest.fillVolume(min, max, origin);
final Vector3i size = volume.size();
final Vector3i relativeMin = volume.min();
final Vector3d center = volume.logicalCenter();
ArchetypeVolume intermediary = volume;
for (int i = 0; i < rotationCount; i++) {
intermediary = intermediary.transform(Transformation.builder().origin(center).rotate(wanted).build());
}
Rotation expected = Rotations.NONE.get();
for (int i = 0; i < rotationCount; i++) {
expected = expected.and(wanted);
}
final Transformation expectedTransform = Transformation.builder().origin(center).rotate(expected).build();
final Transformation inverse = expectedTransform.inverse();
final ArchetypeVolume rotated = intermediary;
if (rotationCount > 0) {
final Vector3d preliminaryTransformed = expectedTransform.transformPosition(testForRoundTrip.toDouble());
Vector3i unTransformed = preliminaryTransformed.round().toInt();
for (int i = 0; i < rotationCount; i++) {
unTransformed = ((AbstractReferentArchetypeVolume) rotated).inverseTransform(unTransformed.x(), unTransformed.y(), unTransformed.z());
}
Assertions.assertEquals(testForRoundTrip, unTransformed);
}
for (int x = 0; x < size.x(); x++) {
for (int y = 0; y < size.y(); y++) {
for (int z = 0; z < size.z(); z++) {
final int relativeX = x + relativeMin.x();
final int relativeY = y + relativeMin.y();
final int relativeZ = z + relativeMin.z();
final Vector3d rawRelativePosition = new Vector3d(relativeX, relativeY, relativeZ);
final BlockState untransformedState = volume.block(relativeX, relativeY, relativeZ);
final Vector3i transformedPosition = expectedTransform.transformPosition(rawRelativePosition).toInt();
final BlockState transformedState = rotated.block(transformedPosition.x(), transformedPosition.y(), transformedPosition.z());
Assertions.assertEquals(untransformedState, transformedState, () -> String.format("Block Check Failed!\nOriginal(%d, %d, %d): %s\nTransformed(%d, %d, %d): %s\n", relativeX, relativeY, relativeZ, untransformedState, transformedPosition.x(), transformedPosition.y(), transformedPosition.z(), transformedState));
}
}
}
if (rotationCount < 0) {
return;
}
// At this point, we should have an abstract referent volume at least
rotated.blockStateStream(rotated.min(), rotated.max(), StreamOptions.lazily()).forEach((rotatedRef, type, x, y, z) -> {
final Vector3d transformedPos = new Vector3d(x, y, z);
// We have this offset in the stream, so we have to undo it here.
final Vector3d invertedTransformedPos = inverse.transformPosition(transformedPos.add(VolumePositionTranslators.BLOCK_OFFSET)).sub(VolumePositionTranslators.BLOCK_OFFSET);
final Vector3i invertedBlockPos = invertedTransformedPos.toInt();
final Vector3i expectedPos;
Assertions.assertTrue(type instanceof StubState, () -> String.format("expected state to be a stub state for pos: [%f, %f, %f] but got %s", x, y, z, type));
Assertions.assertNotEquals(((StubState) type).deducedPos, VolumeTransformationTest.INVALID_STUB_POSITION, () -> String.format("expected to have a positioned stub state: [%f, %f, %f] but got %s", x, y, z, type));
expectedPos = ((StubState) type).deducedPos;
Assertions.assertEquals(expectedPos, invertedBlockPos, () -> String.format("expected untransformed position %s for state %s does not match reverse transformed position: %s", expectedPos, type, invertedBlockPos));
final BlockState block = volume.block(expectedPos.x(), expectedPos.y(), expectedPos.z());
Assertions.assertEquals(type, block, () -> String.format("Expected deduced state to be equal from the original target volume but had a mismatch: Original target %s does not match %s", block, type));
});
}
use of org.spongepowered.api.world.volume.archetype.ArchetypeVolume in project SpongeCommon by SpongePowered.
the class LevelMixin_API method createArchetypeVolume.
@Override
public ArchetypeVolume createArchetypeVolume(final Vector3i min, final Vector3i max, final Vector3i origin) {
final Vector3i rawVolMin = Objects.requireNonNull(min, "min").min(Objects.requireNonNull(max, "max"));
final Vector3i volMax = max.max(min);
final Vector3i size = volMax.sub(rawVolMin).add(1, 1, 1);
final Vector3i relativeMin = rawVolMin.sub(Objects.requireNonNull(origin, "origin"));
final SpongeArchetypeVolume volume = new SpongeArchetypeVolume(relativeMin, size, this);
this.blockStateStream(min, max, StreamOptions.lazily()).apply(VolumeCollectors.of(volume, VolumePositionTranslators.offset(origin), VolumeApplicators.applyBlocks()));
this.blockEntityStream(min, max, StreamOptions.lazily()).map((world, blockEntity, x, y, z) -> blockEntity.get().createArchetype()).apply(VolumeCollectors.of(volume, VolumePositionTranslators.offset(origin), VolumeApplicators.applyBlockEntityArchetypes()));
this.biomeStream(min, max, StreamOptions.lazily()).apply(VolumeCollectors.of(volume, VolumePositionTranslators.offset(origin), VolumeApplicators.applyBiomes()));
this.entityStream(min, max, StreamOptions.lazily()).filter((world, entity, x, y, z) -> ((EntityAccessor) entity.get()).invoker$getEncodeId() != null || entity.get().type() == HumanEntity.TYPE).map((world, entity, x, y, z) -> entity.get().createArchetype()).apply(VolumeCollectors.of(volume, VolumePositionTranslators.offset(origin), VolumeApplicators.applyEntityArchetypes()));
return volume;
}
use of org.spongepowered.api.world.volume.archetype.ArchetypeVolume in project SpongeCommon by SpongePowered.
the class SpongeArchetypeVolume method blockStateStream.
@Override
public VolumeStream<ArchetypeVolume, BlockState> blockStateStream(final Vector3i min, final Vector3i max, final StreamOptions options) {
final Vector3i blockMin = this.min();
final Vector3i blockMax = this.max();
VolumeStreamUtils.validateStreamArgs(min, max, blockMin, blockMax, options);
final ArrayMutableBlockBuffer buffer;
if (options.carbonCopy()) {
buffer = this.blocks.copy();
} else {
buffer = this.blocks;
}
final Stream<VolumeElement<ArchetypeVolume, BlockState>> stateStream = IntStream.range(min.x(), max.x() + 1).mapToObj(x -> IntStream.range(min.z(), max.z() + 1).mapToObj(z -> IntStream.range(min.y(), max.y() + 1).mapToObj(y -> VolumeElement.of((ArchetypeVolume) this, () -> buffer.block(x, y, z), new Vector3d(x, y, z)))).flatMap(Function.identity())).flatMap(Function.identity());
return new SpongeVolumeStream<>(stateStream, () -> this);
}
Aggregations