Load structure scripts into registry

This commit is contained in:
dfsek
2020-12-23 02:35:07 -07:00
parent e9dc7428b8
commit 405a96034c
13 changed files with 117 additions and 52 deletions

View File

@@ -50,6 +50,7 @@ import java.util.Map;
public class Parser {
private final String data;
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
private String id;
public Parser(String data) {
this.data = data;
@@ -60,6 +61,10 @@ public class Parser {
return this;
}
public String getID() {
return id;
}
/**
* Parse input
*
@@ -75,6 +80,14 @@ public class Parser {
} catch(TokenizerException e) {
throw new ParseException("Failed to tokenize input", e);
}
// Parse ID
ParserUtil.checkType(tokens.remove(0), Token.Type.ID); // First token must be ID
Token idToken = tokens.get(0);
ParserUtil.checkType(tokens.remove(0), Token.Type.STRING); // Second token must be string literal containing ID
ParserUtil.checkType(tokens.remove(0), Token.Type.STATEMENT_END);
this.id = idToken.getContent();
// Check for dangling brackets
int blockLevel = 0;
for(Token t : tokens) {

View File

@@ -1,4 +1,50 @@
package com.dfsek.terra.api.structures.script;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.structures.parser.Parser;
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.parser.lang.Block;
import com.dfsek.terra.api.structures.script.builders.BlockFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.CheckFunctionBuilder;
import com.dfsek.terra.api.structures.structure.Rotation;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
public class StructureScript {
private final Block block;
private final String id;
public StructureScript(InputStream inputStream, TerraPlugin main) {
Parser parser;
try {
parser = new Parser(IOUtils.toString(inputStream));
} catch(IOException e) {
throw new RuntimeException(e);
}
parser.addFunction("block", new BlockFunctionBuilder(main))
.addFunction("check", new CheckFunctionBuilder(main));
try {
block = parser.parse();
} catch(ParseException e) {
throw new RuntimeException(e);
}
this.id = parser.getID();
}
public void execute(Location location, Rotation rotation) {
block.apply(location, rotation);
}
public void execute(Location location, Chunk chunk, Rotation rotation) {
block.apply(location, chunk, rotation);
}
public String getId() {
return id;
}
}

View File

@@ -206,6 +206,10 @@ public class Token {
/**
* Break statement
*/
BREAK
BREAK,
/**
* ID declaration
*/
ID
}
}

View File

@@ -141,6 +141,9 @@ public class Tokenizer {
if(tokenString.equals("break"))
return new Token(tokenString, Token.Type.BREAK, new Position(reader.getLine(), reader.getIndex()));
if(tokenString.equals("id"))
return new Token(tokenString, Token.Type.ID, new Position(reader.getLine(), reader.getIndex()));
return new Token(tokenString, Token.Type.IDENTIFIER, new Position(reader.getLine(), reader.getIndex()));
}

View File

@@ -8,6 +8,7 @@ import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.LoaderRegistrar;
import com.dfsek.terra.api.loot.LootTable;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
@@ -44,6 +45,7 @@ import com.dfsek.terra.registry.CarverRegistry;
import com.dfsek.terra.registry.FloraRegistry;
import com.dfsek.terra.registry.OreRegistry;
import com.dfsek.terra.registry.PaletteRegistry;
import com.dfsek.terra.registry.ScriptRegistry;
import com.dfsek.terra.registry.StructureRegistry;
import com.dfsek.terra.registry.TerraRegistry;
import com.dfsek.terra.registry.TreeRegistry;
@@ -78,6 +80,7 @@ public class ConfigPack implements LoaderRegistrar {
private final FloraRegistry floraRegistry;
private final OreRegistry oreRegistry = new OreRegistry();
private final TreeRegistry treeRegistry;
private final ScriptRegistry scriptRegistry = new ScriptRegistry();
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final ConfigLoader selfLoader = new ConfigLoader();
@@ -141,13 +144,19 @@ public class ConfigPack implements LoaderRegistrar {
abstractConfigLoader
.registerLoader(LootTable.class, new LootTableLoader(loader, main)); // These loaders need access to the Loader instance to get files.
loader
.open("palettes").then(streams -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.load(streams, PaletteTemplate::new), main)).close()
.open("palettes").thenNames(names -> names.forEach(System.out::println)).close()
.open("ores").then(streams -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.load(streams, OreTemplate::new), main)).close()
.open("flora").then(streams -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.load(streams, FloraTemplate::new), main)).close()
.open("carving").then(streams -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.load(streams, CarverTemplate::new), main)).close()
.open("biomes").then(streams -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.load(streams, () -> new BiomeTemplate(this, main)), main)).close()
.open("grids").then(streams -> buildAll(new BiomeGridFactory(), biomeGridRegistry, abstractConfigLoader.load(streams, BiomeGridTemplate::new), main)).close();
.open("palettes", ".yml").then(streams -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.load(streams, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(streams -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.load(streams, OreTemplate::new), main)).close()
.open("flora", ".yml").then(streams -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.load(streams, FloraTemplate::new), main)).close()
.open("carving", ".yml").then(streams -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.load(streams, CarverTemplate::new), main)).close()
.open("biomes", ".yml").then(streams -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.load(streams, () -> new BiomeTemplate(this, main)), main)).close()
.open("grids", ".yml").then(streams -> buildAll(new BiomeGridFactory(), biomeGridRegistry, abstractConfigLoader.load(streams, BiomeGridTemplate::new), main)).close();
loader.open("structures/data", ".tesf").then(streams -> streams.forEach(stream -> {
StructureScript structureScript = new StructureScript(stream, main);
scriptRegistry.add(structureScript.getId(), structureScript);
})).close();
for(UserDefinedBiome b : biomeRegistry.entries()) {
try {
Objects.requireNonNull(b.getErode()); // Throws NPE if it cannot load erosion biomes.
@@ -231,6 +240,10 @@ public class ConfigPack implements LoaderRegistrar {
.registerLoader(Tree.class, treeRegistry);
}
public ScriptRegistry getScriptRegistry() {
return scriptRegistry;
}
public BiomeRegistry getBiomeRegistry() {
return biomeRegistry;
}

View File

@@ -25,11 +25,11 @@ public class FolderLoader extends Loader {
}
@Override
protected void load(String directory) {
protected void load(String directory, String extension) {
File newPath = new File(path.toFile(), directory);
newPath.mkdirs();
try(Stream<Path> paths = Files.walk(newPath.toPath())) {
paths.filter(Files::isRegularFile).filter(file -> file.toString().toLowerCase().endsWith(".yml")).forEach(file -> {
paths.filter(Files::isRegularFile).filter(file -> file.toString().toLowerCase().endsWith(extension)).forEach(file -> {
try {
streams.put(newPath.toURI().relativize(file.toUri()).getPath(), new FileInputStream(file.toFile()));
} catch(FileNotFoundException e) {

View File

@@ -45,14 +45,15 @@ public abstract class Loader {
* Open a subdirectory.
*
* @param directory Directory to open
* @param extension
*/
public Loader open(String directory) {
public Loader open(String directory, String extension) {
if(streams.size() != 0) throw new IllegalStateException("Attempted to load new directory before closing existing InputStreams");
load(directory);
load(directory, extension);
return this;
}
protected abstract void load(String directory);
protected abstract void load(String directory, String extension);
/**
* Close all InputStreams opened.

View File

@@ -24,11 +24,11 @@ public class ZIPLoader extends Loader {
}
@Override
protected void load(String directory) {
protected void load(String directory, String extension) {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().startsWith(directory) && entry.getName().endsWith(".yml")) {
if(!entry.isDirectory() && entry.getName().startsWith(directory) && entry.getName().endsWith(extension)) {
try {
streams.put(entry.getName(), file.getInputStream(entry));
} catch(IOException e) {

View File

@@ -0,0 +1,6 @@
package com.dfsek.terra.registry;
import com.dfsek.terra.api.structures.script.StructureScript;
public class ScriptRegistry extends TerraRegistry<StructureScript> {
}

View File

@@ -1,3 +1,5 @@
id "testScript";
test("minecraft:green_w" + "ool", (2 * (3+1) * (2 * (1+1))));
//

View File

@@ -1,5 +1,7 @@
package com.dfsek.terra.bukkit.command.command.structure.load;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.bukkit.command.DebugCommand;
import com.dfsek.terra.bukkit.command.PlayerCommand;
import org.bukkit.command.Command;
@@ -7,9 +9,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FilenameFilter;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -20,17 +19,14 @@ public class LoadCommand extends PlayerCommand implements DebugCommand {
super(parent);
}
public List<String> getStructureNames() {
public List<String> getStructureNames(World world) {
List<String> names = new ArrayList<>();
File structureDir = new File(getMain().getDataFolder() + File.separator + "export" + File.separator + "structures");
if(!structureDir.exists()) return Collections.emptyList();
Path structurePath = structureDir.toPath();
TerraWorld terraWorld = getMain().getWorld(world);
terraWorld.getConfig().getScriptRegistry().forEach(script -> {
names.add(script.getId());
});
FilenameFilter filter = (dir, name) -> name.endsWith(".tstructure");
for(File f : structureDir.listFiles(filter)) {
String path = structurePath.relativize(f.toPath()).toString();
names.add(path.substring(0, path.length() - 11));
}
return names;
}

View File

@@ -62,7 +62,7 @@ public class LoadFullCommand extends LoadCommand implements DebugCommand {
public List<String> getTabCompletions(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] args) {
switch(args.length) {
case 1:
return getStructureNames().stream().filter(string -> string.toUpperCase().startsWith(args[0].toUpperCase())).collect(Collectors.toList());
return Collections.emptyList(); //getStructureNames().stream().filter(string -> string.toUpperCase().startsWith(args[0].toUpperCase())).collect(Collectors.toList());
case 2:
return Stream.of("0", "90", "180", "270").filter(string -> string.toUpperCase().startsWith(args[1].toUpperCase())).collect(Collectors.toList());
}

View File

@@ -1,24 +1,16 @@
package com.dfsek.terra.bukkit.command.command.structure.load;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.structures.parser.Parser;
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.parser.lang.Block;
import com.dfsek.terra.api.structures.script.builders.BlockFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.CheckFunctionBuilder;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.bukkit.BukkitWorld;
import com.dfsek.terra.bukkit.command.DebugCommand;
import org.apache.commons.io.IOUtils;
import org.bukkit.block.Sign;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
@@ -37,24 +29,13 @@ public class LoadRawCommand extends LoadCommand implements DebugCommand {
} else sign.setLine(2, data);
}
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
try {
Parser parser = new Parser(IOUtils.toString(new FileInputStream(new File(getMain().getDataFolder(), "test.tesf"))));
parser.addFunction("block", new BlockFunctionBuilder(getMain()))
.addFunction("check", new CheckFunctionBuilder(getMain()));
TerraWorld terraWorld = getMain().getWorld(new BukkitWorld(sender.getWorld()));
System.out.println("Parsing...");
terraWorld.getConfig().getScriptRegistry().get(args[0]).execute(new Location(new BukkitWorld(sender.getWorld()), sender.getLocation().getX(), sender.getLocation().getY(), sender.getLocation().getZ()), Rotation.fromDegrees(90 * ThreadLocalRandom.current().nextInt(4)));
Block main = parser.parse();
System.out.println("Done parsing");
main.apply(new Location(new BukkitWorld(sender.getWorld()), sender.getLocation().getX(), sender.getLocation().getY(), sender.getLocation().getZ()), Rotation.fromDegrees(90 * ThreadLocalRandom.current().nextInt(4)));
} catch(IOException | ParseException e) {
e.printStackTrace();
}
/*
try {
WorldHandle handle = ((TerraBukkitPlugin) getMain()).getWorldHandle();
@@ -130,7 +111,7 @@ public class LoadRawCommand extends LoadCommand implements DebugCommand {
@Override
public List<String> getTabCompletions(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] args) {
if(args.length == 1) {
return getStructureNames().stream().filter(string -> string.toUpperCase().startsWith(args[0].toUpperCase())).collect(Collectors.toList());
return getStructureNames(new BukkitWorld(((Player) commandSender).getWorld())).stream().filter(string -> string.toUpperCase().startsWith(args[0].toUpperCase())).collect(Collectors.toList());
}
return Collections.emptyList();
}