Compare commits

...

30 Commits

Author SHA1 Message Date
dfsek 942a8c9c8b Merge pull request #131 from xieve/fix-disable-config
Fixed populator disable config (#130)
2021-04-15 10:29:20 -07:00
dfsek 414dcdae3e use vanilla delegate spawn rules 2021-04-15 10:20:14 -07:00
dfsek 1195a6676f implement getHeight on Fabric 2021-04-15 10:00:22 -07:00
dfsek 5501f53056 implement TerraFabricPlugin#getWorld(long) 2021-04-15 09:59:13 -07:00
xieve 41d6e1c648 Fixed populator disable config (#130) 2021-04-15 18:18:27 +02:00
dfsek 5ac7257517 Merge pull request #119 from PolyhedralDev/ver/5.1.3
Fix Fabric Physics, add "dead" entry checking to registries.
2021-04-11 18:56:25 -07:00
dfsek 9f4f9702a6 bump version 2021-04-11 17:54:07 -07:00
dfsek 01d169256e properly relocate dependencies 2021-04-11 17:49:39 -07:00
dfsek 7a703ad091 add publication config to Fabric 2021-04-11 14:15:13 -07:00
dfsek ce9273c7e8 proper fluid updating on Fabric 2021-04-11 00:45:53 -07:00
dfsek 653a414ac1 should(tm) fix fabric physics 2021-04-10 23:49:02 -07:00
dfsek 2080db21ca warn about dead registry entries when debug mode is enabled 2021-04-10 19:22:41 -07:00
dfsek 8a933609ee Merge pull request #107 from PolyhedralDev/ver/5.1.2
5.1.2 LootPopulateEvent patch
2021-04-01 15:14:14 -07:00
dfsek ba4a50e234 add getStructureScript method to LootPopulateEvent 2021-04-01 15:03:48 -07:00
dfsek f8e8ce8bc2 Bump version 2021-03-31 20:50:17 -07:00
dfsek 0013d4e682 Merge pull request #106 from PolyhedralDev/ver/5.1.2
Add LootPopulateEvent and EntitySpawnEvent
2021-03-31 20:49:44 -07:00
dfsek 9a97f1178d release modrinth to beta channel 2021-03-31 08:34:17 -07:00
dfsek e6a551d84d add getter/setter for loot table in LootPopulateEvent 2021-03-30 09:23:21 -07:00
dfsek 92921430d8 add EntitySpawnEvent 2021-03-30 00:27:16 -07:00
dfsek 20c905aae4 add LootPopulateEvent 2021-03-30 00:19:32 -07:00
dfsek ec0730ef73 test commit so version is different B) 2021-03-29 21:14:34 -07:00
dfsek e4576b3405 Add modrinth publish task 2021-03-29 21:09:36 -07:00
dfsek c5800970a8 i totally didnt forget to bump version 2021-03-29 16:39:10 -07:00
dfsek 8f88b1c156 Merge pull request #101 from PolyhedralDev/ver/5.1.1
API to add populators, Buildscript improvements
2021-03-29 16:26:59 -07:00
dfsek 1360994a67 Add options to disable default populators 2021-03-29 11:56:16 -07:00
dfsek e00b28d27e remove sysout 2021-03-29 10:07:25 -07:00
dfsek c5ff5c101d custom biome color configuration 2021-03-29 09:52:54 -07:00
dfsek b1a1001c49 clean up buildscripts 2021-03-26 08:50:58 -07:00
dfsek 77d5162e73 add API for addons to register populators 2021-03-23 11:40:22 -07:00
dfsek 2e8cd54ac2 Merge pull request #96 from PolyhedralDev/ver/5.1.0
Address several issues
2021-03-17 10:53:32 -07:00
49 changed files with 675 additions and 239 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
import com.dfsek.terra.getGitHash
val versionObj = Version("5", "1", "0", true)
val versionObj = Version("5", "1", "3", true)
allprojects {
version = versionObj
@@ -18,4 +18,4 @@ class Version(val major: String, val minor: String, val revision: String, val pr
else //Only use git hash if it's a prerelease.
"$major.$minor.$revision-BETA+${getGitHash()}"
}
}
}
@@ -30,7 +30,7 @@ fun Project.configureCommon() {
}
fun Project.getGitHash(): String {
val stdout = java.io.ByteArrayOutputStream()
val stdout = ByteArrayOutputStream()
exec {
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout
@@ -18,9 +18,7 @@ fun Project.configureDependencies() {
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testImplementation"("org.yaml:snakeyaml:1.27")
"testImplementation"("com.googlecode.json-simple:json-simple:1.1.1")
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"testImplementation"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"compileOnly"("org.jetbrains:annotations:20.1.0")
}
}
@@ -14,13 +14,9 @@ fun Project.configureDistribution() {
apply(plugin = "java-library")
apply(plugin = "com.github.johnrengelman.shadow")
// configurations.create("shaded")
configurations {
val shaded = create("shaded")
getByName("compile").extendsFrom(shaded)
// shaded.extendsFrom(getByName("compile"))
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
@@ -29,11 +25,8 @@ fun Project.configureDistribution() {
getByName("implementation").extendsFrom(shadedImplementation)
}
// tasks.withType<JavaCompile> {
// classpath +=
// }
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
group = "terra"
doFirst {
file("${buildDir}/resources/main/packs/").deleteRecursively()
@@ -69,8 +62,14 @@ fun Project.configureDistribution() {
archiveClassifier.set("shaded")
setVersion(project.version)
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
relocate("parsii", "com.dfsek.terra.lib.parsii")
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
relocate("org.objectweb.asm", "com.dfsek.terra.lib.asm")
relocate("com.google.errorprone", "com.dfsek.terra.lib.google.errorprone")
relocate("com.google.j2objc", "com.dfsek.terra.lib.google.j2objc")
relocate("org.checkerframework", "com.dfsek.terra.lib.checkerframework")
relocate("org.javax.annotation", "com.dfsek.terra.lib.javax.annotation")
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
minimize()
}
convention.getPlugin<BasePluginConvention>().archivesBaseName = project.name
+2 -1
View File
@@ -20,7 +20,8 @@ dependencies {
"shadedApi"("org.ow2.asm:asm:9.0")
"shadedApi"("commons-io:commons-io:2.6")
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")
"shadedApi"("com.googlecode.json-simple:json-simple:1.1.1")
"shadedApi"("org.yaml:snakeyaml:1.27")
"compileOnly"("com.google.guava:guava:30.0-jre")
@@ -160,7 +160,6 @@ public class TerraCommandManager implements CommandManager {
if(field.isAnnotationPresent(SwitchTarget.class)) {
SwitchTarget switchTarget = field.getAnnotation(SwitchTarget.class);
if(!holder.switches.containsValue(switchTarget.value())) {
System.out.println(holder.switches);
throw new MalformedCommandException("Switch Target specifies nonexistent switch \"" + switchTarget.value() + "\"");
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.api.event.events;
import com.dfsek.terra.api.util.mutable.MutableBoolean;
/**
* Abstract class containing basic {@link Cancellable} implementation.
*/
public abstract class AbstractCancellable implements Cancellable {
private final MutableBoolean cancelled = new MutableBoolean(false);
@Override
public boolean isCancelled() {
return cancelled.get();
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled.set(cancelled);
}
}
@@ -1,6 +1,5 @@
package com.dfsek.terra.api.event.events.world;
import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
@@ -9,18 +8,24 @@ import com.dfsek.terra.world.TerraWorld;
/**
* Called upon initialization of a TerraWorld.
*/
public class TerraWorldLoadEvent implements Event {
public class TerraWorldLoadEvent implements PackEvent {
private final TerraWorld world;
private final ConfigPack pack;
public TerraWorldLoadEvent(TerraWorld world) {
public TerraWorldLoadEvent(TerraWorld world, ConfigPack pack) {
this.world = world;
this.pack = pack;
}
public TerraWorld getWorld() {
return world;
}
public WorldConfig getPack() {
public ConfigPack getPack() {
return pack;
}
public WorldConfig getWorldConfig() {
return world.getConfig();
}
}
@@ -0,0 +1,45 @@
package com.dfsek.terra.api.event.events.world.generation;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedEntity;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called when an entity is spawned via {@link BufferedEntity}.
*/
public class EntitySpawnEvent implements PackEvent {
private final ConfigPack pack;
private final Entity entity;
private final Location location;
public EntitySpawnEvent(ConfigPack pack, Entity entity, Location location) {
this.pack = pack;
this.entity = entity;
this.location = location;
}
@Override
public ConfigPack getPack() {
return pack;
}
/**
* Get the entity that triggered the event.
*
* @return The entity.
*/
public Entity getEntity() {
return entity;
}
/**
* Get the location of the entity.
*
* @return Location of the entity.
*/
public Location getLocation() {
return location;
}
}
@@ -0,0 +1,80 @@
package com.dfsek.terra.api.event.events.world.generation;
import com.dfsek.terra.api.event.events.AbstractCancellable;
import com.dfsek.terra.api.event.events.Cancellable;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedLootApplication;
import com.dfsek.terra.config.pack.ConfigPack;
import org.jetbrains.annotations.NotNull;
/**
* Called when loot is populated via {@link BufferedLootApplication}.
*/
public class LootPopulateEvent extends AbstractCancellable implements PackEvent, Cancellable {
private final Block block;
private final Container container;
private LootTable table;
private final ConfigPack pack;
private final StructureScript script;
public LootPopulateEvent(Block block, Container container, LootTable table, ConfigPack pack, StructureScript script) {
this.block = block;
this.container = container;
this.table = table;
this.pack = pack;
this.script = script;
}
@Override
public ConfigPack getPack() {
return pack;
}
/**
* Get the block containing the tile entity loot is applied to.
*
* @return Block at which loot is applied.
*/
public Block getBlock() {
return block;
}
/**
* Get the {@link Container} representing the inventory.
*
* @return Inventory recieving loot.
*/
public Container getContainer() {
return container;
}
/**
* Get the loot table to be populated.
* @return Loot table.
*/
public LootTable getTable() {
return table;
}
/**
* Set the loot table to be populated.
*
* @param table New loot table.
*/
public void setTable(@NotNull LootTable table) {
this.table = table;
}
/**
* Get the script used to generate the structure.
*
* @return Structure script.
*/
public StructureScript getStructureScript() {
return script;
}
}
@@ -68,7 +68,7 @@ public class StructureScript {
.registerFunction("setMark", new SetMarkFunctionBuilder())
.registerFunction("getMark", new GetMarkFunctionBuilder())
.registerFunction("pull", new PullFunctionBuilder(main))
.registerFunction("loot", new LootFunctionBuilder(main, lootRegistry))
.registerFunction("loot", new LootFunctionBuilder(main, lootRegistry, this))
.registerFunction("entity", new EntityFunctionBuilder(main))
.registerFunction("getBiome", new BiomeFunctionBuilder(main))
.registerFunction("getBlock", new CheckBlockFunctionBuilder())
@@ -3,6 +3,7 @@ package com.dfsek.terra.api.structures.script.builders;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.script.functions.LootFunction;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.registry.config.LootRegistry;
@@ -12,16 +13,18 @@ import java.util.List;
public class LootFunctionBuilder implements FunctionBuilder<LootFunction> {
private final TerraPlugin main;
private final LootRegistry registry;
private final StructureScript script;
public LootFunctionBuilder(TerraPlugin main, LootRegistry registry) {
public LootFunctionBuilder(TerraPlugin main, LootRegistry registry, StructureScript script) {
this.main = main;
this.registry = registry;
this.script = script;
}
@SuppressWarnings("unchecked")
@Override
public LootFunction build(List<Returnable<?>> argumentList, Position position) {
return new LootFunction(registry, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), main, position);
return new LootFunction(registry, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), main, position, script);
}
@Override
@@ -21,9 +21,11 @@ public class EntityFunction implements Function<Void> {
private final EntityType data;
private final Returnable<Number> x, y, z;
private final Position position;
private final TerraPlugin main;
public EntityFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, TerraPlugin main, Position position) throws ParseException {
this.position = position;
this.main = main;
if(!(data instanceof ConstantExpression)) throw new ParseException("Entity data must be constant", data.getPosition());
this.data = main.getWorldHandle().getEntity(((ConstantExpression<String>) data).getConstant());
@@ -39,7 +41,7 @@ public class EntityFunction implements Function<Void> {
RotationUtil.rotateVector(xz, arguments.getRotation());
arguments.getBuffer().addItem(new BufferedEntity(data), new Vector3(xz.getX(), y.apply(implementationArguments, variableMap).doubleValue(), xz.getZ()).toLocation(arguments.getBuffer().getOrigin().getWorld()));
arguments.getBuffer().addItem(new BufferedEntity(data, main), new Vector3(xz.getX(), y.apply(implementationArguments, variableMap).doubleValue(), xz.getZ()).toLocation(arguments.getBuffer().getOrigin().getWorld()));
return null;
}
@@ -8,6 +8,7 @@ import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedLootApplication;
@@ -23,8 +24,9 @@ public class LootFunction implements Function<Void> {
private final Returnable<Number> x, y, z;
private final Position position;
private final TerraPlugin main;
private final StructureScript script;
public LootFunction(LootRegistry registry, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, TerraPlugin main, Position position) {
public LootFunction(LootRegistry registry, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, TerraPlugin main, Position position, StructureScript script) {
this.registry = registry;
this.position = position;
this.data = data;
@@ -32,6 +34,7 @@ public class LootFunction implements Function<Void> {
this.y = y;
this.z = z;
this.main = main;
this.script = script;
}
@Override
@@ -49,7 +52,7 @@ public class LootFunction implements Function<Void> {
return null;
}
arguments.getBuffer().addItem(new BufferedLootApplication(table, main), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).intValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld()));
arguments.getBuffer().addItem(new BufferedLootApplication(table, main, script), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).intValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld()));
return null;
}
@@ -1,18 +1,24 @@
package com.dfsek.terra.api.structures.structure.buffer.items;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.event.events.world.generation.EntitySpawnEvent;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
public class BufferedEntity implements BufferedItem {
private final EntityType type;
private final TerraPlugin main;
public BufferedEntity(EntityType type) {
public BufferedEntity(EntityType type, TerraPlugin main) {
this.type = type;
this.main = main;
}
@Override
public void paste(Location origin) {
origin.clone().add(0.5, 0, 0.5).getWorld().spawnEntity(origin, type);
Entity entity = origin.clone().add(0.5, 0, 0.5).getWorld().spawnEntity(origin, type);
main.getEventManager().callEvent(new EntitySpawnEvent(main.getWorld(entity.getWorld()).getGenerator().getConfigPack(), entity, entity.getLocation()));
}
}
@@ -1,31 +1,42 @@
package com.dfsek.terra.api.structures.structure.buffer.items;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.event.events.world.generation.LootPopulateEvent;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.util.FastRandom;
public class BufferedLootApplication implements BufferedItem {
private final LootTable table;
private final TerraPlugin main;
private final StructureScript structure;
public BufferedLootApplication(LootTable table, TerraPlugin main) {
public BufferedLootApplication(LootTable table, TerraPlugin main, StructureScript structure) {
this.table = table;
this.main = main;
this.structure = structure;
}
@Override
public void paste(Location origin) {
try {
BlockState data = origin.getBlock().getState();
Block block = origin.getBlock();
BlockState data = block.getState();
if(!(data instanceof Container)) {
main.logger().severe("Failed to place loot at " + origin + "; block " + data + " is not container.");
return;
}
Container container = (Container) data;
table.fillInventory(container.getInventory(), new FastRandom(origin.hashCode()));
LootPopulateEvent event = new LootPopulateEvent(block, container, table, main.getWorld(block.getLocation().getWorld()).getGenerator().getConfigPack(), structure);
main.getEventManager().callEvent(event);
if(event.isCancelled()) return;
event.getTable().fillInventory(container.getInventory(), new FastRandom(origin.hashCode()));
data.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply loot at " + origin + ": " + e.getMessage());
@@ -5,6 +5,14 @@ import org.jetbrains.annotations.NotNull;
public class MutableBoolean implements MutablePrimitive<Boolean> {
private boolean value;
public MutableBoolean() {
this.value = false;
}
public MutableBoolean(boolean value) {
this.value = value;
}
@Override
public Boolean get() {
return value;
@@ -0,0 +1,7 @@
package com.dfsek.terra.api.world.generation;
/**
* Marker interface that marks a feature as "chunkified" (only modifying one chunk at a time)
*/
public interface Chunkified {
}
@@ -1,8 +0,0 @@
package com.dfsek.terra.api.world.generation;
/**
* The phase of terrain generation. Used for modifying values based on the phase of generation.
*/
public enum GenerationPhase {
BASE, POPULATE, GENERATION_POPULATE, PALETTE_APPLY, POST_GEN
}
@@ -6,10 +6,10 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkData;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Random;
public interface TerraChunkGenerator {
@@ -32,4 +32,6 @@ public interface TerraChunkGenerator {
TerraPlugin getMain();
Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth);
List<TerraBlockPopulator> getPopulators();
}
@@ -63,8 +63,6 @@ public class StructureLoadCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
System.out.println(rotation);
Player player = (Player) sender;
long t = System.nanoTime();
@@ -4,7 +4,10 @@ import com.dfsek.terra.api.platform.world.Biome;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.config.templates.BiomeTemplate;
public interface BiomeBuilder extends SeededBuilder<TerraBiome> {
ProbabilityCollection<Biome> getVanillaBiomes();
BiomeTemplate getTemplate();
}
@@ -66,4 +66,9 @@ public class UserDefinedBiomeBuilder implements BiomeBuilder {
public ProbabilityCollection<Biome> getVanillaBiomes() {
return template.getVanilla();
}
@Override
public BiomeTemplate getTemplate() {
return template;
}
}
@@ -65,7 +65,6 @@ public class ExpressionFunctionTemplate extends SamplerTemplate<ExpressionFuncti
Map<String, Function> noiseFunctionMap = new HashMap<>();
for(Map.Entry<String, FunctionTemplate> entry : expressions.entrySet()) {
System.out.println(entry);
noiseFunctionMap.put(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue(), new Parser(), new Scope()));
}
@@ -139,6 +139,7 @@ public class ConfigPack implements LoaderRegistrar {
selfLoader.load(packPostTemplate, new FileInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
checkDeadEntries(main);
} catch(FileNotFoundException e) {
throw new LoadException("No pack.yml file found in " + folder.getAbsolutePath(), e);
}
@@ -183,6 +184,7 @@ public class ConfigPack implements LoaderRegistrar {
selfLoader.load(packPostTemplate, file.getInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
checkDeadEntries(main);
} catch(IOException e) {
throw new LoadException("Unable to load pack.yml from ZIP file", e);
}
@@ -198,6 +200,16 @@ public class ConfigPack implements LoaderRegistrar {
for(C template : configTemplates) registry.add(template.getID(), factory.build(template, main));
}
private void checkDeadEntries(TerraPlugin main) {
biomeRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in biome registry: '" + id + "'"));
paletteRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in palette registry: '" + id + "'"));
floraRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in flora registry: '" + id + "'"));
carverRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in carver registry: '" + id + "'"));
treeRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in tree registry: '" + id + "'"));
oreRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in ore registry: '" + id + "'"));
}
private void load(long start, TerraPlugin main) throws ConfigException {
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this));
@@ -73,6 +73,46 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Default
private String version = "0.1.0";
@Value("disable.carvers")
@Default
private boolean disableCarvers = false;
@Value("disable.structures")
@Default
private boolean disableStructures = false;
@Value("disable.ores")
@Default
private boolean disableOres = false;
@Value("disable.trees")
@Default
private boolean disableTrees = false;
@Value("disable.flora")
@Default
private boolean disableFlora = false;
public boolean disableCarvers() {
return disableCarvers;
}
public boolean disableFlora() {
return disableFlora;
}
public boolean disableOres() {
return disableOres;
}
public boolean disableStructures() {
return disableStructures;
}
public boolean disableTrees() {
return disableTrees;
}
public LinkedHashMap<String, FunctionTemplate> getFunctions() {
return functions;
}
@@ -190,10 +190,19 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
@Default
private Map<UserDefinedCarver, Integer> carvers = new HashMap<>();
@Value("colors")
@Abstractable
@Default
private Map<String, Integer> colors = new HashMap<>(); // Plain ol' map, so platforms can decide what to do with colors (if anything).
public Set<String> getTags() {
return tags;
}
public Map<String, Integer> getColors() {
return colors;
}
public Map<UserDefinedCarver, Integer> getCarvers() {
return carvers;
}
@@ -7,18 +7,19 @@ import com.dfsek.terra.registry.exception.DuplicateEntryException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* Registry implementation with read/write access. For internal use only.
* @param <T>
*/
public class OpenRegistry<T> implements Registry<T> {
private final Map<String, T> objects = new HashMap<>();
private final Map<String, Entry<T>> objects = new HashMap<>();
@Override
public T load(Type type, Object o, ConfigLoader configLoader) throws LoadException {
@@ -35,6 +36,10 @@ public class OpenRegistry<T> implements Registry<T> {
* @param value Value to add.
*/
public boolean add(String identifier, T value) {
return add(identifier, new Entry<>(value));
}
protected boolean add(String identifier, Entry<T> value) {
boolean exists = objects.containsKey(identifier);
objects.put(identifier, value);
return exists;
@@ -60,22 +65,22 @@ public class OpenRegistry<T> implements Registry<T> {
@Override
public T get(String identifier) {
return objects.get(identifier);
return objects.get(identifier).getValue();
}
@Override
public void forEach(Consumer<T> consumer) {
objects.forEach((id, obj) -> consumer.accept(obj));
objects.forEach((id, obj) -> consumer.accept(obj.getRaw()));
}
@Override
public void forEach(BiConsumer<String, T> consumer) {
objects.forEach(consumer);
objects.forEach((id, entry) -> consumer.accept(id, entry.getRaw()));
}
@Override
public Set<T> entries() {
return new HashSet<>(objects.values());
return objects.values().stream().map(Entry::getRaw).collect(Collectors.toSet());
}
@Override
@@ -83,10 +88,41 @@ public class OpenRegistry<T> implements Registry<T> {
return objects.keySet();
}
public Map<String, T> getDeadEntries() {
Map<String, T> dead = new HashMap<>();
objects.forEach((id, entry) -> {
if(entry.dead()) dead.put(id, entry.value); // dont increment value here.
});
return dead;
}
/**
* Clears all entries from the registry.
*/
public void clear() {
objects.clear();
}
protected static final class Entry<T> {
private final T value;
private final AtomicInteger access = new AtomicInteger(0);
public Entry(T value) {
this.value = value;
}
public T getValue() {
access.incrementAndGet();
return value;
}
private T getRaw() {
return value;
}
public boolean dead() {
return access.get() == 0;
}
}
}
@@ -57,7 +57,9 @@ public class FloraRegistry extends OpenRegistry<Flora> {
private void addItem(String id, Callable<ConstantFlora> flora) {
try {
add(id, flora.call());
Entry<Flora> entry = new Entry<>(flora.call());
entry.getValue(); // Mark as not dead.
add(id, entry);
} catch(Exception e) {
main.logger().warning("Failed to load Flora item: " + id + ": " + e.getMessage());
}
@@ -33,7 +33,7 @@ public class TerraWorld {
this.provider = config.getProvider();
profiler = new WorldProfiler(w);
air = main.getWorldHandle().createBlockData("minecraft:air");
main.getEventManager().callEvent(new TerraWorldLoadEvent(this));
main.getEventManager().callEvent(new TerraWorldLoadEvent(this, c));
safe = true;
}
@@ -10,6 +10,7 @@ import com.dfsek.terra.api.util.world.PaletteUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
@@ -21,9 +22,15 @@ import com.dfsek.terra.world.carving.NoiseCarver;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler2D;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.OrePopulator;
import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class DefaultChunkGenerator2D implements TerraChunkGenerator {
@@ -31,12 +38,18 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
private final TerraPlugin main;
private final Carver carver;
private final List<TerraBlockPopulator> blockPopulators = new ArrayList<>();
private final SamplerCache cache;
public DefaultChunkGenerator2D(ConfigPack c, TerraPlugin main, SamplerCache cache) {
this.configPack = c;
this.main = main;
blockPopulators.add(new CavePopulator(main));
blockPopulators.add(new StructurePopulator(main));
blockPopulators.add(new OrePopulator(main));
blockPopulators.add(new TreePopulator(main));
blockPopulators.add(new TreePopulator(main));
carver = new NoiseCarver(new Range(0, 255), main.getWorldHandle().createBlockData("minecraft:air"), main);
this.cache = cache;
}
@@ -125,4 +138,9 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler2D(chunkX, chunkZ, provider, world, elevationSmooth);
}
@Override
public List<TerraBlockPopulator> getPopulators() {
return blockPopulators;
}
}
@@ -17,6 +17,7 @@ import com.dfsek.terra.api.util.world.PaletteUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.SinglePalette;
@@ -28,8 +29,15 @@ import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler3D;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.FloraPopulator;
import com.dfsek.terra.world.population.OrePopulator;
import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -38,14 +46,21 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
private final TerraPlugin main;
private final BlockType water;
private final SinglePalette<BlockData> blank;
private final List<TerraBlockPopulator> blockPopulators = new ArrayList<>();
private final Carver carver;
public DefaultChunkGenerator3D(ConfigPack c, TerraPlugin main) {
this.configPack = c;
this.main = main;
blockPopulators.add(new CavePopulator(main));
blockPopulators.add(new StructurePopulator(main));
blockPopulators.add(new OrePopulator(main));
blockPopulators.add(new TreePopulator(main));
blockPopulators.add(new FloraPopulator(main));
carver = new NoiseCarver(new Range(0, 255), main.getWorldHandle().createBlockData("minecraft:air"), main);
water = main.getWorldHandle().createBlockData("minecraft:water").getBlockType();
blank = new SinglePalette<>(main.getWorldHandle().createBlockData("minecraft:air"));
@@ -236,4 +251,9 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth);
}
@Override
public List<TerraBlockPopulator> getPopulators() {
return blockPopulators;
}
}
@@ -9,6 +9,7 @@ import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.pack.WorldConfig;
@@ -23,7 +24,7 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
public class CavePopulator implements TerraBlockPopulator {
public class CavePopulator implements TerraBlockPopulator, Chunkified {
private static final Map<BlockType, BlockData> shiftStorage = new HashMap<>(); // Persist BlockData created for shifts, to avoid re-calculating each time.
private final TerraPlugin main;
@@ -41,6 +42,7 @@ public class CavePopulator implements TerraBlockPopulator {
Random random = PopulationUtil.getRandom(chunk);
if(!tw.isSafe()) return;
WorldConfig config = tw.getConfig();
if(config.getTemplate().disableCarvers()) return;
for(UserDefinedCarver c : config.getCarvers()) {
CarverTemplate template = c.getConfig();
@@ -33,6 +33,8 @@ public class FloraPopulator implements TerraBlockPopulator {
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("FloraTime")) {
if(tw.getConfig().getTemplate().disableFlora()) return;
if(!tw.isSafe()) return;
BiomeProvider provider = tw.getBiomeProvider();
Map<Vector2, List<FloraLayer>> layers = new HashMap<>();
@@ -28,6 +28,8 @@ public class OrePopulator implements TerraBlockPopulator {
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("OreTime")) {
if(tw.getConfig().getTemplate().disableOres()) return;
if(!tw.isSafe()) return;
for(int cx = -1; cx <= 1; cx++) {
for(int cz = -1; cz <= 1; cz++) {
@@ -9,6 +9,7 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
@@ -20,7 +21,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Random;
public class StructurePopulator implements TerraBlockPopulator {
public class StructurePopulator implements TerraBlockPopulator, Chunkified {
private final TerraPlugin main;
public StructurePopulator(TerraPlugin main) {
@@ -32,6 +33,8 @@ public class StructurePopulator implements TerraBlockPopulator {
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("StructureTime")) {
if(tw.getConfig().getTemplate().disableStructures()) return;
int cx = (chunk.getX() << 4);
int cz = (chunk.getZ() << 4);
if(!tw.isSafe()) return;
@@ -33,6 +33,8 @@ public class TreePopulator implements TerraBlockPopulator {
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("TreeTime")) {
if(tw.getConfig().getTemplate().disableTrees()) return;
if(!tw.isSafe()) return;
BiomeProvider provider = tw.getBiomeProvider();
Random random = PopulationUtil.getRandom(chunk);
@@ -39,6 +39,7 @@ import com.dfsek.terra.config.loaders.config.biome.templates.provider.SingleBiom
import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.AbstractableTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.registry.config.BiomeRegistry;
import com.dfsek.terra.registry.config.NoiseRegistry;
import com.dfsek.terra.world.TerraWorld;
@@ -306,6 +307,11 @@ public class DistributionTest {
return null;
}
@Override
public BiomeTemplate getTemplate() {
return null;
}
@Override
public Generator getGenerator(World w) {
return null;
+138 -56
View File
@@ -15,12 +15,12 @@ configureCommon()
group = "com.dfsek.terra.bukkit"
repositories {
mavenCentral()
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
}
val mcVersion = "1.16.5"
val testDir = "target/server"
val testMem = "3G"
val paperURL = "https://papermc.io/api/v1/paper/%version%/latest/download/"
val purpurURL = "https://ci.pl3x.net/job/Purpur/lastSuccessfulBuild/artifact/final/purpurclip.jar"
dependencies {
"shadedApi"(project(":common"))
@@ -32,76 +32,159 @@ dependencies {
"compileOnly"("com.sk89q.worldedit:worldedit-bukkit:7.2.0-SNAPSHOT")
"shadedImplementation"("com.google.guava:guava:30.0-jre")
"shadedApi"("com.google.guava:guava:30.0-jre")
}
val testDir = "target/server/"
val jvmFlags = listOf("-XX:+UseG1GC", "-XX:+ParallelRefProcEnabled", "-XX:MaxGCPauseMillis=200",
"-XX:+UnlockExperimentalVMOptions", "-XX:+DisableExplicitGC", "-XX:+AlwaysPreTouch",
"-XX:G1NewSizePercent=30", "-XX:G1MaxNewSizePercent=40", "-XX:G1HeapRegionSize=8M",
"-XX:G1ReservePercent=20", "-XX:G1HeapWastePercent=5", "-XX:G1MixedGCCountTarget=4",
"-XX:InitiatingHeapOccupancyPercent=15", "-XX:G1MixedGCLiveThresholdPercent=90",
"-XX:G1RSetUpdatingPauseTimePercent=5", "-XX:SurvivorRatio=32", "-XX:+PerfDisableSharedMem",
"-XX:MaxTenuringThreshold=1", "-Dusing.aikars.flags=https://mcflags.emc.gs",
"-Daikars.new.flags=true", "-DIReallyKnowWhatIAmDoingISwear", "-javaagent:paperclip.jar")
val setupServer = tasks.create("setupServer") {
dependsOn("shadowJar")
doFirst {
// clean
file("${testDir}/").deleteRecursively()
file("${testDir}/plugins").mkdirs()
fun downloadPaperclip(url: String, dir: String) {
val clip = URL(url.replace("%version%", mcVersion))
val clipReadableByteChannel = Channels.newChannel(clip.openStream())
val clipFile = file("$testDir/$dir/paperclip.jar")
val clipOutputStream = clipFile.outputStream()
val clipFileChannel = clipOutputStream.channel
clipFileChannel.transferFrom(clipReadableByteChannel, 0, Long.MAX_VALUE)
}
// Downloading latest paper jar.
val paperUrl = URL("https://papermc.io/api/v1/paper/1.16.4/latest/download")
val paperReadableByteChannel = Channels.newChannel(paperUrl.openStream())
val paperFile = file("${testDir}/paper.jar")
val paperFileOutputStream = paperFile.outputStream()
val paperFileChannel = paperFileOutputStream.channel
paperFileChannel.transferFrom(paperReadableByteChannel, 0, Long.MAX_VALUE)
// Cloning test setup.
gitClone("https://github.com/PolyhedralDev/WorldGenTestServer")
// Copying plugins
Files.move(Paths.get("WorldGenTestServer/plugins"),
Paths.get("$testDir/plugins"),
StandardCopyOption.REPLACE_EXISTING)
// Copying config
val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText()
file("${testDir}/server.properties").writeText(serverText)
val bukkitText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/bukkit.yml").readText()
file("${testDir}/bukkit.yml").writeText(bukkitText.replace("\${world}", "world").replace("\${gen}", "Terra:DEFAULT"))
File("${testDir}/eula.txt").writeText("eula=true")
// clean up
file("WorldGenTestServer").deleteRecursively()
fun copyTerra(dir: String) {
file("$testDir/$dir").walk().forEach {
if(it.name.startsWith("Terra-") && it.name.endsWith(".jar")) it.delete() // Delete old Terra jar(s)
}
copy {
from("$buildDir/libs/Terra-bukkit-$version-shaded.jar")
into("$testDir/$dir/plugins/")
}
}
val testWithPaper = task<JavaExec>(name = "testWithPaper") {
fun installServer(dir: String) {
// clean
file("$testDir/$dir").deleteRecursively()
file("$testDir/$dir/plugins").mkdirs()
// Cloning test setup.
gitClone("https://github.com/PolyhedralDev/WorldGenTestServer")
// Copying plugins
Files.move(Paths.get("WorldGenTestServer/plugins"),
Paths.get("$testDir/$dir/plugins"),
StandardCopyOption.REPLACE_EXISTING)
// Copying config
val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText()
file("$testDir/$dir/server.properties").writeText(serverText)
val bukkitText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/bukkit.yml").readText()
file("$testDir/$dir/bukkit.yml").writeText(bukkitText.replace("\${world}", "world").replace("\${gen}", "Terra:DEFAULT"))
println("By proceeding, you are agreeing to the Minecraft EULA: https://account.mojang.com/documents/minecraft_eula")
file("$testDir/$dir/eula.txt").writeText("eula=true")
// clean up
file("WorldGenTestServer").deleteRecursively()
}
fun deleteFolder(folder: File) {
if(folder.exists()) folder.deleteRecursively()
}
fun deleteFile(file: File) {
if(file.exists()) file.delete()
}
tasks.create("cleanWorlds") {
group = "bukkit"
doFirst {
deleteFolder(file("$testDir/paper/world"))
deleteFolder(file("$testDir/paper/world_nether"))
deleteFolder(file("$testDir/paper/world_the_end"))
deleteFolder(file("$testDir/purpur/world"))
deleteFolder(file("$testDir/purpur/world_nether"))
deleteFolder(file("$testDir/purpur/world_the_end"))
}
}
tasks.create("updatePaper") {
group = "bukkit"
doFirst {
deleteFile(file("$testDir/paper/paperclip.jar"))
downloadPaperclip(paperURL, "paper")
}
}
tasks.create("updatePurpur") {
group = "bukkit"
doFirst {
deleteFile(file("$testDir/paper/paperclip.jar"))
downloadPaperclip(purpurURL, "purpur")
}
}
tasks.create("installPaper") {
group = "bukkit"
dependsOn("shadowJar")
doFirst {
installServer("paper")
// Downloading latest paper jar.
downloadPaperclip(paperURL, "paper")
}
}
tasks.create("installPurpur") {
group = "bukkit"
dependsOn("shadowJar")
doFirst {
installServer("purpur")
// Downloading latest paper jar.
downloadPaperclip(purpurURL, "purpur")
}
}
task<JavaExec>(name = "runPaper") {
group = "bukkit"
standardInput = System.`in`
dependsOn("shadowJar")
// Copy Terra into dir
doFirst {
copy {
from("${buildDir}/libs/Terra-bukkit-${version}-shaded.jar")
into("${testDir}/plugins/")
}
copyTerra("paper")
}
main = "io.papermc.paperclip.Paperclip"
jvmArgs = listOf("-XX:+UseG1GC", "-XX:+ParallelRefProcEnabled", "-XX:MaxGCPauseMillis=200",
"-XX:+UnlockExperimentalVMOptions", "-XX:+DisableExplicitGC", "-XX:+AlwaysPreTouch",
"-XX:G1NewSizePercent=30", "-XX:G1MaxNewSizePercent=40", "-XX:G1HeapRegionSize=8M",
"-XX:G1ReservePercent=20", "-XX:G1HeapWastePercent=5", "-XX:G1MixedGCCountTarget=4",
"-XX:InitiatingHeapOccupancyPercent=15", "-XX:G1MixedGCLiveThresholdPercent=90",
"-XX:G1RSetUpdatingPauseTimePercent=5", "-XX:SurvivorRatio=32", "-XX:+PerfDisableSharedMem",
"-XX:MaxTenuringThreshold=1", "-Dusing.aikars.flags=https://mcflags.emc.gs",
"-Daikars.new.flags=true", "-DIReallyKnowWhatIAmDoingISwear")
maxHeapSize = "4G"
minHeapSize = "4G"
jvmArgs = jvmFlags
maxHeapSize = testMem
minHeapSize = testMem
//args = listOf("nogui")
workingDir = file("${testDir}/")
classpath = files("${testDir}/paper.jar")
workingDir = file("$testDir/paper")
classpath = files("$testDir/paper/paperclip.jar")
}
task<JavaExec>(name = "runPurpur") {
group = "bukkit"
standardInput = System.`in`
dependsOn("shadowJar")
// Copy Terra into dir
doFirst {
copyTerra("purpur")
}
main = "io.papermc.paperclip.Paperclip"
jvmArgs = jvmFlags
maxHeapSize = testMem
minHeapSize = testMem
//args = listOf("nogui")
workingDir = file("$testDir/purpur")
classpath = files("$testDir/purpur/paperclip.jar")
}
tasks.named<ShadowJar>("shadowJar") {
relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("com.google.common", "com.dfsek.terra.lib.google.common")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
@@ -112,7 +195,6 @@ publishing {
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
@@ -23,6 +23,8 @@ import org.jetbrains.annotations.NotNull;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -40,20 +42,13 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener
private final TerraPlugin main;
private final List<TerraBlockPopulator> populators = new LinkedList<>();
private boolean needsLoad = true;
public BukkitChunkGeneratorWrapper(TerraChunkGenerator delegate) {
this.delegate = delegate;
this.main = delegate.getMain();
popMan = new PopulationManager(main);
popMan.attach(new OrePopulator(main));
popMan.attach(new TreePopulator(main));
popMan.attach(new FloraPopulator(main));
populators.add(new CavePopulator(main));
populators.add(new StructurePopulator(main));
populators.add(popMan);
this.popMan = new PopulationManager(delegate, main);
}
@@ -96,7 +91,7 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener
@Override
public @NotNull List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
return populators.stream().map(BukkitPopulatorWrapper::new).collect(Collectors.toList());
return Arrays.asList(popMan, new BukkitPopulatorWrapper(delegate));
}
@Override
@@ -1,27 +0,0 @@
package com.dfsek.terra.bukkit.generator;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.BlockPopulator;
import com.dfsek.terra.bukkit.world.BukkitChunk;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import java.util.Random;
public class BukkitPopulator implements BlockPopulator {
private final org.bukkit.generator.BlockPopulator handle;
public BukkitPopulator(org.bukkit.generator.BlockPopulator handle) {
this.handle = handle;
}
@Override
public void populate(World world, Random random, Chunk chunk) {
handle.populate(((BukkitWorld) world).getHandle(), random, ((BukkitChunk) chunk).getHandle());
}
@Override
public org.bukkit.generator.BlockPopulator getHandle() {
return handle;
}
}
@@ -1,6 +1,8 @@
package com.dfsek.terra.bukkit.generator;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import org.bukkit.Chunk;
import org.bukkit.World;
@@ -10,14 +12,18 @@ import org.jetbrains.annotations.NotNull;
import java.util.Random;
public class BukkitPopulatorWrapper extends BlockPopulator {
private final TerraBlockPopulator delegate;
private final TerraChunkGenerator delegate;
public BukkitPopulatorWrapper(TerraBlockPopulator delegate) {
public BukkitPopulatorWrapper(TerraChunkGenerator delegate) {
this.delegate = delegate;
}
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk source) {
delegate.populate(BukkitAdapter.adapt(world), BukkitAdapter.adapt(source));
delegate.getPopulators().forEach(populator -> {
if(populator instanceof Chunkified) {
populator.populate(BukkitAdapter.adapt(world), BukkitAdapter.adapt(source));
}
});
}
}
@@ -22,7 +22,9 @@ public class TerraListener implements EventListener {
public void injectTrees(ConfigPackPreLoadEvent event) {
for(TreeType value : TreeType.values()) {
try {
event.getPack().getTreeRegistry().add(BukkitAdapter.TREE_TRANSFORMER.translate(value), new BukkitTree(value, main));
String id = BukkitAdapter.TREE_TRANSFORMER.translate(value);
event.getPack().getTreeRegistry().add(id, new BukkitTree(value, main));
event.getPack().getTreeRegistry().get(id); // Platform trees should never be marked "dead"
} catch(DuplicateEntryException ignore) { // If another addon has already registered trees, do nothing.
}
}
@@ -4,54 +4,35 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.WorldProfiler;
import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
/**
* Cursed management class for the horrors of Bukkit population
*/
public class PopulationManager implements TerraBlockPopulator {
private final List<TerraBlockPopulator> attachedPopulators = new GlueList<>();
public class PopulationManager extends BlockPopulator {
private final TerraChunkGenerator generator;
private final HashSet<ChunkCoordinate> needsPop = new HashSet<>();
private final TerraPlugin main;
private WorldProfiler profiler;
public PopulationManager(TerraPlugin main) {
public PopulationManager(TerraChunkGenerator generator, TerraPlugin main) {
this.generator = generator;
this.main = main;
}
public void attach(TerraBlockPopulator populator) {
this.attachedPopulators.add(populator);
}
@Override
@SuppressWarnings("try")
public void populate(@NotNull World world, @NotNull Chunk chunk) {
try(ProfileFuture ignored = measure()) {
needsPop.add(new ChunkCoordinate(chunk));
int x = chunk.getX();
int z = chunk.getZ();
if(((TerraBukkitPlugin) main).isEnabled()) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
if(world.isChunkGenerated(xi + x, zi + z)) checkNeighbors(xi + x, zi + z, world);
}
}
}
}
}
private ProfileFuture measure() {
if(profiler != null) return profiler.measure("PopulationManagerTime");
return null;
@@ -87,10 +68,30 @@ public class PopulationManager implements TerraBlockPopulator {
long zRand = (random.nextLong() / 2L << 1L) + 1L;
random.setSeed((long) x * xRand + (long) z * zRand ^ w.getSeed());
Chunk currentChunk = w.getChunkAt(x, z);
for(TerraBlockPopulator r : attachedPopulators) {
r.populate(w, currentChunk);
}
generator.getPopulators().forEach(populator -> {
if(!(populator instanceof Chunkified)) {
populator.populate(w, currentChunk);
}
});
needsPop.remove(c);
}
}
@Override
public void populate(org.bukkit.@NotNull World world, @NotNull Random random, org.bukkit.@NotNull Chunk source) {
try(ProfileFuture ignored = measure()) {
Chunk chunk = BukkitAdapter.adapt(source);
needsPop.add(new ChunkCoordinate(chunk));
int x = chunk.getX();
int z = chunk.getZ();
if(((TerraBukkitPlugin) main).isEnabled()) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
if(world.isChunkGenerated(xi + x, zi + z)) checkNeighbors(xi + x, zi + z, BukkitAdapter.adapt(world));
}
}
}
}
}
}
+43 -8
View File
@@ -1,11 +1,14 @@
import com.dfsek.terra.configureCommon
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.modrinth.minotaur.TaskModrinthUpload
import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.task.RemapJarTask
plugins {
`java-library`
`maven-publish`
id("fabric-loom").version("0.6-SNAPSHOT")
id("com.modrinth.minotaur").version("1.1.0")
}
configureCommon()
@@ -19,8 +22,6 @@ group = "com.dfsek.terra.fabric"
dependencies {
"shadedApi"(project(":common"))
"shadedImplementation"("org.yaml:snakeyaml:1.27")
"shadedImplementation"("com.googlecode.json-simple:json-simple:1.1.1")
"minecraft"("com.mojang:minecraft:1.16.5")
"mappings"("net.fabricmc:yarn:1.16.5+build.5:v2")
@@ -29,17 +30,13 @@ dependencies {
"modImplementation"("net.fabricmc.fabric-api:fabric-api:0.31.0+1.16")
}
tasks.named<ShadowJar>("shadowJar") {
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
}
configure<LoomGradleExtension> {
accessWidener("src/main/resources/terra.accesswidener")
}
tasks.register<RemapJarTask>("remapShadedJar") {
val remapped = tasks.register<RemapJarTask>("remapShadedJar") {
group = "fabric"
val shadowJar = tasks.getByName<ShadowJar>("shadowJar")
dependsOn(shadowJar)
input.set(shadowJar.archiveFile)
@@ -47,3 +44,41 @@ tasks.register<RemapJarTask>("remapShadedJar") {
addNestedDependencies.set(true)
remapAccessWidener.set(true)
}
tasks.register<TaskModrinthUpload>("publishModrinth") {
dependsOn("remapShadedJar")
group = "fabric"
token = System.getenv("MODRINTH_SECRET")
projectId = "FIlZB9L0"
versionNumber = project.version.toString()
uploadFile = remapped.get().archiveFile.get().asFile
releaseType = "beta"
addGameVersion("1.16.4")
addGameVersion("1.16.5")
addLoader("fabric")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}
@@ -35,6 +35,7 @@ import com.dfsek.terra.config.builder.BiomeBuilder;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.fabric.inventory.FabricItemHandle;
import com.dfsek.terra.fabric.mixin.GeneratorTypeAccessor;
import com.dfsek.terra.fabric.world.FabricAdapter;
@@ -150,13 +151,18 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
@Override
public TerraWorld getWorld(World world) {
if(worldMap.size() > 1) System.out.println(worldMap.size());
return worldMap.computeIfAbsent(world.getSeed(), w -> {
logger.info("Loading world " + w);
return new TerraWorld(world, ((FabricChunkGeneratorWrapper) ((FabricChunkGenerator) world.getGenerator()).getHandle()).getPack(), this);
});
}
public TerraWorld getWorld(long seed) {
TerraWorld world = worldMap.get(seed);
if(world == null) throw new IllegalArgumentException("No world exists with seed " + seed);
return world;
}
@Override
public Logger logger() {
return logger;
@@ -242,9 +248,8 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
}
private Biome createBiome(BiomeBuilder biome) {
SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder();
DefaultBiomeFeatures.addFarmAnimals(spawnSettings);
DefaultBiomeFeatures.addMonsters(spawnSettings, 95, 5, 100);
BiomeTemplate template = biome.getTemplate();
Map<String, Integer> colors = template.getColors();
Biome vanilla = ((FabricBiome) new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle();
@@ -254,28 +259,37 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
BiomeEffects.Builder effects = new BiomeEffects.Builder()
.waterColor(vanilla.getEffects().waterColor)
.waterFogColor(vanilla.getEffects().waterFogColor)
.fogColor(vanilla.getEffects().fogColor)
.skyColor(vanilla.getEffects().skyColor)
.waterColor(colors.getOrDefault("water", vanilla.getEffects().waterColor))
.waterFogColor(colors.getOrDefault("water-fog", vanilla.getEffects().waterFogColor))
.fogColor(colors.getOrDefault("fog", vanilla.getEffects().fogColor))
.skyColor(colors.getOrDefault("sky", vanilla.getEffects().skyColor))
.grassColorModifier(vanilla.getEffects().grassColorModifier);
vanilla.getEffects().grassColor.ifPresent(effects::grassColor);
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
return (new Biome.Builder())
if(colors.containsKey("grass")) {
effects.grassColor(colors.get("grass"));
} else {
vanilla.getEffects().grassColor.ifPresent(effects::grassColor);
}
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
if(colors.containsKey("foliage")) {
effects.foliageColor(colors.get("foliage"));
} else {
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
}
return new Biome.Builder()
.precipitation(vanilla.getPrecipitation())
.category(vanilla.getCategory())
.depth(vanilla.getDepth())
.scale(vanilla.getScale())
.temperature(vanilla.getTemperature())
.downfall(vanilla.getDownfall())
.effects(vanilla.getEffects()) // TODO: configurable
.spawnSettings(spawnSettings.build())
.effects(effects.build())
.spawnSettings(vanilla.getSpawnSettings())
.generationSettings(generationSettings.build())
.build();
}
@SuppressWarnings("unchecked")
@Override
public void onInitialize() {
instance = this;
@@ -327,10 +341,8 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> {
int max = manager.getMaxArgumentDepth();
System.out.println("MAX:" + max);
RequiredArgumentBuilder<ServerCommandSource, String> arg = argument("arg" + (max - 1), StringArgumentType.word());
for(int i = 0; i < max; i++) {
System.out.println("arg " + i);
RequiredArgumentBuilder<ServerCommandSource, String> next = argument("arg" + (max - i - 1), StringArgumentType.word());
arg = next.then(assemble(arg, manager));
@@ -9,6 +9,7 @@ import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.world.block.state.FabricBlockState;
import com.dfsek.terra.fabric.world.handles.world.FabricWorldAccess;
import net.minecraft.block.FluidBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldAccess;
@@ -21,7 +22,10 @@ public class FabricBlock implements Block {
@Override
public void setBlockData(BlockData data, boolean physics) {
delegate.worldAccess.setBlockState(delegate.position, ((FabricBlockData) data).getHandle(), physics ? 3 : 1042, 0);
delegate.worldAccess.setBlockState(delegate.position, ((FabricBlockData) data).getHandle(), physics ? 3 : 1042);
if(physics && ((FabricBlockData) data).getHandle().getBlock() instanceof FluidBlock) {
delegate.worldAccess.getFluidTickScheduler().schedule(delegate.position, ((FluidBlock) ((FabricBlockData) data).getHandle().getBlock()).getFluidState(((FabricBlockData) data).getHandle()).getFluid(), 0);
}
}
@Override
@@ -27,11 +27,7 @@ public class PopulatorFeature extends Feature<DefaultFeatureConfig> {
FabricChunkGeneratorWrapper gen = (FabricChunkGeneratorWrapper) chunkGenerator;
FabricChunkWorldAccess chunk = new FabricChunkWorldAccess(world, pos.getX() >> 4, pos.getZ() >> 4);
FabricWorld world1 = new FabricWorld(world.toServerWorld(), new FabricChunkGenerator(chunkGenerator));
gen.getCavePopulator().populate(new FabricWorldAccess(world), chunk);
gen.getStructurePopulator().populate(new FabricWorldAccess(world), chunk);
gen.getOrePopulator().populate(world1, chunk);
gen.getTreePopulator().populate(world1, chunk);
gen.getFloraPopulator().populate(world1, chunk);
gen.getHandle().getPopulators().forEach(populator -> populator.populate(world1, chunk));
return true;
}
}
@@ -7,7 +7,9 @@ import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.world.TerraBiomeSource;
import com.dfsek.terra.fabric.world.handles.world.FabricSeededWorldAccess;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.generation.generators.DefaultChunkGenerator3D;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.FloraPopulator;
import com.dfsek.terra.world.population.OrePopulator;
@@ -15,6 +17,7 @@ import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.jafama.FastMath;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.structure.StructureManager;
@@ -50,32 +53,6 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener
return pack;
}
private final FloraPopulator floraPopulator = new FloraPopulator(TerraFabricPlugin.getInstance());
private final OrePopulator orePopulator = new OrePopulator(TerraFabricPlugin.getInstance());
private final TreePopulator treePopulator = new TreePopulator(TerraFabricPlugin.getInstance());
private final StructurePopulator structurePopulator = new StructurePopulator(TerraFabricPlugin.getInstance());
private final CavePopulator cavePopulator = new CavePopulator(TerraFabricPlugin.getInstance());
public TreePopulator getTreePopulator() {
return treePopulator;
}
public OrePopulator getOrePopulator() {
return orePopulator;
}
public FloraPopulator getFloraPopulator() {
return floraPopulator;
}
public StructurePopulator getStructurePopulator() {
return structurePopulator;
}
public CavePopulator getCavePopulator() {
return cavePopulator;
}
public FabricChunkGeneratorWrapper(TerraBiomeSource biomeSource, long seed, ConfigPack configPack) {
super(biomeSource, new StructuresConfig(false));
this.pack = configPack;
@@ -124,6 +101,8 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener
}
@Override
public boolean isStrongholdStartingChunk(ChunkPos chunkPos) {
return false;
@@ -131,7 +110,18 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener
@Override
public int getHeight(int x, int z, Heightmap.Type heightmapType) {
return 0;
TerraWorld world = TerraFabricPlugin.getInstance().getWorld(seed);
Sampler sampler = world.getConfig().getSamplerCache().getChunk(FastMath.floorDiv(x, 16), FastMath.floorDiv(z, 16));
int cx = FastMath.floorMod(x, 16);
int cz = FastMath.floorMod(z, 16);
int height = world.getWorld().getMaxHeight();
while (height >= 0 && sampler.sample(cx, height - 1, cz) < 0) {
height--;
}
return height;
}
@Override