Merge pull request #169 from BoogieMonster1O1/1.16-fabric

Better schematic handling and some schematic conversion
This commit is contained in:
Waterpicker 2020-09-22 02:07:27 -05:00 committed by GitHub
commit 9b1ecfde14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 196 additions and 151 deletions

View file

@ -1,6 +1,5 @@
plugins {
id 'fabric-loom' version '0.5-SNAPSHOT'
id 'com.github.johnrengelman.shadow' version '6.0.0'
}
apply plugin: "java"
@ -12,7 +11,6 @@ repositories {
maven { url = 'https://maven.fabricmc.net/' }
maven { url 'https://jitpack.io' }
mavenCentral()
maven { url = 'https://dl.bintray.com/boogiemonster1o1/cool-mods/' }
maven { url = 'https://www.cursemaven.com' }
}
@ -22,19 +20,20 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
implementation 'com.flowpowered:flow-math:1.0.3'
shadow 'com.flowpowered:flow-math:1.0.3'
include 'com.flowpowered:flow-math:1.0.3'
implementation 'org.jgrapht:jgrapht-core:1.1.0'
shadow 'org.jgrapht:jgrapht-core:1.1.0'
include 'org.jgrapht:jgrapht-core:1.1.0'
implementation 'com.github.DimensionalDevelopment:poly2tri.java:0.1.1'
shadow 'com.github.DimensionalDevelopment:poly2tri.java:0.1.1'
include 'com.github.DimensionalDevelopment:poly2tri.java:0.1.1'
modApi("com.github.Waterpicker:OpenWorlds:c5a1ced") {
exclude module: "fabric-api"
}
include 'com.github.Waterpicker:OpenWorlds:c5a1ced'
compileOnly 'com.google.code.findbugs:jsr305:+'
modImplementation("io.github.boogiemonster1o1:libcbe:${libcbe_version}")
include("io.github.boogiemonster1o1:libcbe:${libcbe_version}") // Includes LibCBE as a Jar-in-Jar embedded dependency
include("io.github.boogiemonster1o1:libcbe:${libcbe_version}") // Includes LibCBE as a Jar-in-Jar embedded dependency
modImplementation("curse.maven:worldedit:3039223") // For saving schematics
modImplementation("curse.maven:wecui:2995033") // Cos why not
}
version "4.0.0+alpha.3"

View file

@ -13,6 +13,7 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Property;
import net.minecraft.util.Identifier;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.util.registry.Registry;
public class SchematicBlockPalette {
@ -65,7 +66,7 @@ public class SchematicBlockPalette {
if (state.get(property) instanceof Enum<?>) {
// Enum might have override toString
builder.append(((Enum<?>) state.get(property)).name());
builder.append(((StringIdentifiable) state.get(property)).asString());
} else {
builder.append(state.get(property).toString());
}

View file

@ -22,7 +22,7 @@ public final class SchematicMetadata {
private final long date;
private final List<String> requiredMods;
protected SchematicMetadata(String name, String author, long date, List<String> requiredMods) {
public SchematicMetadata(String name, String author, long date, List<String> requiredMods) {
this.name = name;
this.author = author;
this.date = date;

View file

@ -31,7 +31,7 @@ import net.minecraft.text.LiteralText;
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
public abstract class RiftBlockEntity extends BlockEntity implements BlockEntityClientSerializable, Target, EntityTarget {
private static Codec<RiftData> CODEC = RiftData.CODEC;
private static final Codec<RiftData> CODEC = RiftData.CODEC;
private static final Logger LOGGER = LogManager.getLogger();
protected RiftData data = new RiftData();
@ -45,7 +45,7 @@ public abstract class RiftBlockEntity extends BlockEntity implements BlockEntity
// NBT
@Override
public void fromTag(BlockState state, CompoundTag nbt) {
deserialize(nbt);
this.deserialize(nbt);
}
protected void deserialize(CompoundTag nbt) {
@ -54,123 +54,123 @@ public abstract class RiftBlockEntity extends BlockEntity implements BlockEntity
@Override
public CompoundTag toTag(CompoundTag tag) {
serialize(tag);
this.serialize(tag);
return super.toTag(tag);
}
protected CompoundTag serialize(CompoundTag tag) {
if(data != null) tag.put("data", NbtUtil.serialize(data, CODEC));
if(this.data != null) tag.put("data", NbtUtil.serialize(this.data, CODEC));
return tag;
}
@Override
public void fromClientTag(CompoundTag tag) {
deserialize(tag);
this.deserialize(tag);
}
@Override
public CompoundTag toClientTag(CompoundTag tag) {
return serialize(tag);
return this.serialize(tag);
}
public void setDestination(VirtualTarget destination) {
System.out.println("setting Destination " + destination);
if (this.getDestination() != null && isRegistered()) {
if (this.getDestination() != null && this.isRegistered()) {
this.getDestination().unregister();
}
this.data.setDestination(destination);
if (destination != null) {
if (world != null && pos != null) {
destination.setLocation(new Location((ServerWorld) world, pos));
if (this.world != null && this.pos != null) {
destination.setLocation(new Location((ServerWorld) this.world, this.pos));
}
if (isRegistered()) destination.register();
if (this.isRegistered()) destination.register();
}
riftStateChanged = true;
markDirty();
updateColor();
this.riftStateChanged = true;
this.markDirty();
this.updateColor();
}
public void setColor(RGBA color) {
data.setColor(color);
markDirty();
this.data.setColor(color);
this.markDirty();
}
public void setProperties(LinkProperties properties) {
data.setProperties(properties);
updateProperties();
markDirty();
this.data.setProperties(properties);
this.updateProperties();
this.markDirty();
}
public void markStateChanged() {
riftStateChanged = true;
markDirty();
this.riftStateChanged = true;
this.markDirty();
}
public boolean isRegistered() {
return !PocketTemplate.isReplacingPlaceholders() && RiftRegistry.instance().isRiftAt(new Location((ServerWorld) world, pos));
return !PocketTemplate.isReplacingPlaceholders() && RiftRegistry.instance().isRiftAt(new Location((ServerWorld) this.world, this.pos));
}
public void register() {
if (isRegistered()) {
if (this.isRegistered()) {
return;
}
Location loc = new Location((ServerWorld) world, pos);
Location loc = new Location((ServerWorld) this.world, this.pos);
RiftRegistry.instance().addRift(loc);
if (data.getDestination() != VirtualTarget.NoneTarget.DUMMY) data.getDestination().register();
updateProperties();
updateColor();
if (this.data.getDestination() != VirtualTarget.NoneTarget.DUMMY) this.data.getDestination().register();
this.updateProperties();
this.updateColor();
}
public void updateProperties() {
if (isRegistered())
RiftRegistry.instance().setProperties(new Location((ServerWorld) world, pos), data.getProperties());
markDirty();
if (this.isRegistered())
RiftRegistry.instance().setProperties(new Location((ServerWorld) this.world, this.pos), this.data.getProperties());
this.markDirty();
}
public void unregister() {
if (isRegistered()) {
RiftRegistry.instance().removeRift(new Location((ServerWorld) world, pos));
if (this.isRegistered()) {
RiftRegistry.instance().removeRift(new Location((ServerWorld) this.world, this.pos));
}
}
public void updateType() {
if (!isRegistered()) return;
Rift rift = RiftRegistry.instance().getRift(new Location((ServerWorld) world, pos));
rift.isDetached = isDetached();
if (!this.isRegistered()) return;
Rift rift = RiftRegistry.instance().getRift(new Location((ServerWorld) this.world, this.pos));
rift.isDetached = this.isDetached();
rift.markDirty();
}
public void handleTargetGone(Location location) {
if (data.getDestination().shouldInvalidate(location)) {
data.setDestination(null);
markDirty();
if (this.data.getDestination().shouldInvalidate(location)) {
this.data.setDestination(null);
this.markDirty();
}
updateColor();
this.updateColor();
}
public void handleSourceGone(Location location) {
updateColor();
this.updateColor();
}
public Target getTarget() {
if (data.getDestination() == VirtualTarget.NoneTarget.DUMMY) {
if (this.data.getDestination() == VirtualTarget.NoneTarget.DUMMY) {
return new MessageTarget("rifts.unlinked1");
} else {
data.getDestination().setLocation(new Location((ServerWorld) world, pos));
return data.getDestination();
this.data.getDestination().setLocation(new Location((ServerWorld) this.world, this.pos));
return this.data.getDestination();
}
}
public boolean teleport(Entity entity) {
riftStateChanged = false;
this.riftStateChanged = false;
// Attempt a teleport
try {
EntityTarget target = getTarget().as(Targets.ENTITY);
EntityTarget target = this.getTarget().as(Targets.ENTITY);
if (target.receiveEntity(entity, entity.yaw)) {
VirtualLocation vloc = VirtualLocation.fromLocation(new Location((ServerWorld) entity.world, entity.getBlockPos()));
@ -186,17 +186,17 @@ public abstract class RiftBlockEntity extends BlockEntity implements BlockEntity
}
public void updateColor() {
if (data.isForcedColor()) return;
if (!isRegistered()) {
data.setColor(new RGBA(0, 0, 0, 1));
} else if (data.getDestination() == VirtualTarget.NoneTarget.DUMMY) {
data.setColor(new RGBA(0.7f, 0.7f, 0.7f, 1));
if (this.data.isForcedColor()) return;
if (!this.isRegistered()) {
this.data.setColor(new RGBA(0, 0, 0, 1));
} else if (this.data.getDestination() == VirtualTarget.NoneTarget.DUMMY) {
this.data.setColor(new RGBA(0.7f, 0.7f, 0.7f, 1));
} else {
data.getDestination().setLocation(new Location((ServerWorld) world, pos));
RGBA newColor = data.getDestination().getColor();
if (data.getColor() == RGBA.NONE && newColor != RGBA.NONE || !Objects.equals(data.getColor(), newColor)) {
data.setColor(newColor);
markDirty();
this.data.getDestination().setLocation(new Location((ServerWorld) this.world, this.pos));
RGBA newColor = this.data.getDestination().getColor();
if (this.data.getColor() == RGBA.NONE && newColor != RGBA.NONE || !Objects.equals(this.data.getColor(), newColor)) {
this.data.setColor(newColor);
this.markDirty();
}
}
}
@ -205,30 +205,30 @@ public abstract class RiftBlockEntity extends BlockEntity implements BlockEntity
public void copyFrom(DetachedRiftBlockEntity rift) {
data.setDestination(rift.data.getDestination());
data.setProperties(rift.data.getProperties());
data.setAlwaysDelete(rift.data.isAlwaysDelete());
data.setForcedColor(rift.data.isForcedColor());
this.data.setDestination(rift.data.getDestination());
this.data.setProperties(rift.data.getProperties());
this.data.setAlwaysDelete(rift.data.isAlwaysDelete());
this.data.setForcedColor(rift.data.isForcedColor());
}
public VirtualTarget getDestination() {
return data.getDestination();
return this.data.getDestination();
}
public LinkProperties getProperties() {
return data.getProperties();
return this.data.getProperties();
}
public boolean isAlwaysDelete() {
return data.isAlwaysDelete();
return this.data.isAlwaysDelete();
}
public boolean isForcedColor() {
return data.isForcedColor();
return this.data.isForcedColor();
}
public RGBA getColor() {
return data.getColor();
return this.data.getColor();
}
public void setData(RiftData data) {
@ -236,6 +236,6 @@ public abstract class RiftBlockEntity extends BlockEntity implements BlockEntity
}
public RiftData getData() {
return data;
return this.data;
}
}

View file

@ -17,6 +17,10 @@ public class DimTeleportCommand {
dispatcher.register(CommandManager.literal("dimteleport")
.then(CommandManager
.argument("dimension", DimensionArgumentType.dimension())
.executes(ctx -> {
ServerPlayerEntity player = ctx.getSource().getPlayer();
return teleport(player, DimensionArgumentType.getDimensionArgument(ctx, "dimension"), player.getPos());
})
.then(CommandManager
.argument("coordinates", Vec3ArgumentType.vec3())
.executes(ctx -> {

View file

@ -6,9 +6,9 @@ public final class ModCommands {
public static void init() {
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> {
DimTeleportCommand.register(dispatcher);
SchematicCommand.register(dispatcher);
PocketCommand.register(dispatcher);
SaveSchemCommand.register(dispatcher);
SchematicV2Command.register(dispatcher);
SchematicCommand.register(dispatcher);
});
}
}

View file

@ -1,49 +0,0 @@
package org.dimdev.dimdoors.command;
import com.flowpowered.math.vector.Vector3i;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import org.dimdev.dimcore.schematic.Schematic;
import org.dimdev.dimdoors.pockets.SchematicHandler;
import org.dimdev.dimdoors.world.ModDimensions;
import org.dimdev.dimdoors.world.pocket.Pocket;
import org.dimdev.dimdoors.world.pocket.PocketRegistry;
import net.minecraft.command.CommandException;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.Vec3i;
public class SaveSchemCommand {
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(CommandManager.literal("saveschem")
.then(CommandManager
.argument("name", StringArgumentType.string())
.executes(ctx -> {
ServerPlayerEntity player = ctx.getSource().getPlayer();
if (!ModDimensions.isDimDoorsPocketDimension(player.world)) {
throw new CommandException(new TranslatableText("commands.generic.dimdoors.not_in_pocket"));
}
Pocket pocket = PocketRegistry.instance(player.getServerWorld().getRegistryKey()).getPocketAt(player.getBlockPos());
if (pocket == null)
throw new CommandException(new TranslatableText("commands.generic.dimdoors.not_in_pocket"));
Vector3i size = pocket.getSize().add(1, 1, 1).mul(16).sub(1, 1, 1);
Schematic schematic = Schematic.createFromWorld(player.world, pocket.getOrigin(), pocket.getOrigin().add(new Vec3i(size.getX(), size.getY(), size.getZ())));
String name = StringArgumentType.getString(ctx, "name");
schematic.name = name;
schematic.author = player.getName().getString();
SchematicHandler.INSTANCE.saveSchematicForEditing(schematic, name);
ctx.getSource().sendError(new TranslatableText("commands.saveschem.success"));
return 1;
}))
);
}
}

View file

@ -1,23 +1,25 @@
package org.dimdev.dimdoors.command;
import java.io.IOException;
import java.io.InputStream;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import org.dimdev.dimcore.schematic.Schematic;
import org.dimdev.dimcore.schematic.SchematicConverter;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.minecraft.nbt.NbtIo;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
public class SchematicCommand {
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(CommandManager.literal("schematic")
.then(CommandManager.literal("place")
.then(CommandManager.argument("schematic_name", StringArgumentType.string())
dispatcher.register(literal("schematicold")
.then(literal("place")
.then(argument("schematic_name", StringArgumentType.string())
.executes(ctx -> {
SchematicConverter.reloadConversions();
ServerPlayerEntity player = ctx.getSource().getPlayer();
@ -26,13 +28,13 @@ public class SchematicCommand {
try (InputStream in = SchematicCommand.class.getResourceAsStream("/data/dimdoors/pockets/schematic/ruins/" + id + ".schem")) {
Schematic.fromTag(NbtIo.readCompressed(in))
.place(
(ServerWorld) player.world,
player.world,
(int) player.getPos().x,
(int) player.getPos().y,
(int) player.getPos().z
);
} catch (Throwable t) {
t.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(id + " placed");

View file

@ -0,0 +1,58 @@
package org.dimdev.dimdoors.command;
import java.io.IOException;
import java.io.InputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dimdev.dimcore.schematic.v2.Schematic;
import org.dimdev.dimcore.schematic.v2.SchematicPlacer;
import org.dimdev.dimdoors.DimensionalDoorsInitializer;
import org.dimdev.dimdoors.command.arguments.SchematicNamespaceArgumentType;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.nbt.NbtIo;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
public class SchematicV2Command {
private static final Logger LOGGER = LogManager.getLogger();
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(literal("schematicv2")
.then(argument("namespace", new SchematicNamespaceArgumentType())
.then(argument("schematic_name", StringArgumentType.string())
.executes(SchematicV2Command::place)
)
)
);
}
private static int place(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
ServerPlayerEntity player = ctx.getSource().getPlayer();
String id = StringArgumentType.getString(ctx, "schematic_name");
String ns = SchematicNamespaceArgumentType.getValue(ctx, "namespace");
try (InputStream in = DimensionalDoorsInitializer.class.getResourceAsStream("/data/dimdoors/pockets/schematic/v2/" + ns + "/" + id + ".schem")) {
SchematicPlacer.place(
Schematic.fromTag(NbtIo.readCompressed(in)),
ctx.getSource().getWorld(),
ctx.getSource().getPlayer().getBlockPos()
);
} catch (IOException e) {
e.printStackTrace();
throw new SimpleCommandExceptionType(new TranslatableText("command.dimdoors.schematicv2.unknownSchematic", id, ns)).create();
}
LOGGER.info(String.format("Placed schematic %s from namespace %s at %s in world %s", id, ns, player.getBlockPos(), player.getServerWorld().getRegistryKey().getValue()));
return 1;
}
}

View file

@ -0,0 +1,44 @@
package org.dimdev.dimdoors.command.arguments;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import com.google.common.collect.ImmutableList;
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.server.command.CommandSource;
import net.minecraft.text.TranslatableText;
public class SchematicNamespaceArgumentType implements ArgumentType<String> {
private static final Collection<String> NAMESPACES = ImmutableList.of("ruins", "blank", "nether", "private", "public");
@Override
public String parse(StringReader reader) throws CommandSyntaxException {
String value = Objects.requireNonNull(reader.readString());
if (!NAMESPACES.contains(value)) {
throw new SimpleCommandExceptionType(new TranslatableText("argument.dimdoors.schematic.invalidNamespace", String.join(", ", NAMESPACES), value)).create();
}
return value;
}
@Override
public Collection<String> getExamples() {
return NAMESPACES;
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return CommandSource.suggestMatching(NAMESPACES, builder);
}
public static String getValue(CommandContext<?> context, final String name) {
return context.getArgument(name, String.class);
}
}

View file

@ -22,37 +22,21 @@ import net.minecraft.world.gen.feature.Feature;
import net.fabricmc.loader.api.FabricLoader;
public final class ModFeatures {
public static final Feature<SchematicGatewayFeatureConfig> GATEWAY_FEATURE = Registry.register(Registry.FEATURE, new Identifier("dimdoors", "gateway"), new SchematicGatewayFeature(SchematicGatewayFeatureConfig.CODEC));
public static final Feature<SchematicV2GatewayFeatureConfig> GATEWAY_FEATURE_V2 = Registry.register(Registry.FEATURE, new Identifier("dimdoors", "gateway_v2"), new SchematicV2GatewayFeature(SchematicV2GatewayFeatureConfig.CODEC));
public static final SchematicGateway SANDSTONE_PILLARS_GATEWAY;
public static final SchematicGateway TWO_PILLARS_GATEWAY;
public static final SchematicV2Gateway SANDSTONE_PILLARS_GATEWAY_V2;
public static final ConfiguredFeature<?, ?> SANDSTONE_PILLARS_FEATURE_V2;
public static final ConfiguredFeature<?, ?> SANDSTONE_PILLARS_FEATURE;
public static final ConfiguredFeature<?, ?> TWO_PILLARS_FEATURE;
public static void init() {
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier("dimdoors", "sandstone_pillars_v2"), SANDSTONE_PILLARS_FEATURE_V2);
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier("dimdoors", "sandstone_pillars"), SANDSTONE_PILLARS_FEATURE);
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier("dimdoors", "two_pillars"), TWO_PILLARS_FEATURE);
}
static {
ModBlocks.init();
SANDSTONE_PILLARS_GATEWAY = new SandstonePillarsGateway();
TWO_PILLARS_GATEWAY = new TwoPillarsGateway();
SANDSTONE_PILLARS_GATEWAY_V2 = new SandstonePillarsV2Gateway();
int gatewayChance = FabricLoader.getInstance().isDevelopmentEnvironment() ? 50 : ModConfig.WORLD.gatewayGenChance;
int gatewayChance = FabricLoader.getInstance().isDevelopmentEnvironment() ? 20 : ModConfig.WORLD.gatewayGenChance;
SANDSTONE_PILLARS_FEATURE_V2 = GATEWAY_FEATURE_V2.configure(new SchematicV2GatewayFeatureConfig(SchematicV2Gateway.SCHEMATIC_ID_MAP.get(SANDSTONE_PILLARS_GATEWAY_V2)))
.decorate(ConfiguredFeatures.Decorators.SQUARE_TOP_SOLID_HEIGHTMAP
.applyChance(gatewayChance));
SANDSTONE_PILLARS_FEATURE = GATEWAY_FEATURE.configure(new SchematicGatewayFeatureConfig(SchematicGateway.SCHEMATIC_ID_MAP.get(SANDSTONE_PILLARS_GATEWAY)))
.decorate(ConfiguredFeatures.Decorators.SQUARE_TOP_SOLID_HEIGHTMAP
.applyChance(gatewayChance));
TWO_PILLARS_FEATURE = GATEWAY_FEATURE.configure(new SchematicGatewayFeatureConfig(SchematicGateway.SCHEMATIC_ID_MAP.get(TWO_PILLARS_GATEWAY)))
.decorate(ConfiguredFeatures.Decorators.SQUARE_TOP_SOLID_HEIGHTMAP
.applyChance(gatewayChance));
}
}

View file

@ -184,5 +184,7 @@
"dimdoors.graphics.riftSize": "Rift Size",
"dimdoors.graphics.riftSize.tooltip": "Multiplier affecting how large rifts should be rendered, 1 being the default size.",
"dimdoors.graphics.riftJitter": "Rift Jitter",
"dimdoors.graphics.riftJitter.tooltip": "Multiplier affecting how much rifts should jitter, 1 being the default size."
"dimdoors.graphics.riftJitter.tooltip": "Multiplier affecting how much rifts should jitter, 1 being the default size.",
"argument.dimdoors.schematic.invalidNamespace": "Invalid schematic namespace. Expected one of %s, found %s.",
"command.dimdoors.schematicv2.unknownSchematic": "Unknown schematic \"%s\" in namespace \"%s\" "
}