rewrote weighted pocket system. Pockets now get supplied additional information to calculate their weight

This commit is contained in:
CreepyCre 2021-01-26 16:37:03 +01:00
parent 4269ed289e
commit 0af4b02a56
9 changed files with 126 additions and 95 deletions

View file

@ -8,6 +8,7 @@ import org.dimdev.dimdoors.DimensionalDoorsInitializer;
import org.dimdev.dimdoors.ModConfig; import org.dimdev.dimdoors.ModConfig;
import org.dimdev.dimdoors.rift.registry.LinkProperties; import org.dimdev.dimdoors.rift.registry.LinkProperties;
import org.dimdev.dimdoors.rift.targets.VirtualTarget; import org.dimdev.dimdoors.rift.targets.VirtualTarget;
import org.dimdev.dimdoors.util.PocketGenerationParameters;
import org.dimdev.dimdoors.world.level.DimensionalRegistry; import org.dimdev.dimdoors.world.level.DimensionalRegistry;
import org.dimdev.dimdoors.world.ModDimensions; import org.dimdev.dimdoors.world.ModDimensions;
import org.dimdev.dimdoors.world.pocket.Pocket; import org.dimdev.dimdoors.world.pocket.Pocket;
@ -59,11 +60,12 @@ public final class PocketGenerator {
} }
public static Pocket generateRandomPocketFromGroupV2(ServerWorld world, String group, VirtualLocation virtualLocation, VirtualTarget linkTo, LinkProperties linkProperties) { public static Pocket generateRandomPocketFromGroupV2(ServerWorld world, String group, VirtualLocation virtualLocation, VirtualTarget linkTo, LinkProperties linkProperties) {
return generatePocketV2(world, SchematicV2Handler.getInstance().getRandomPocketFromGroup(group), virtualLocation, linkTo, linkProperties); PocketGenerationParameters parameters = new PocketGenerationParameters(world, group, virtualLocation, linkTo, linkProperties);
return generatePocketV2(SchematicV2Handler.getInstance().getRandomPocketFromGroup(group, parameters), parameters);
} }
public static Pocket generatePocketV2(ServerWorld world, VirtualPocket virtualPocket, VirtualLocation virtualLocation, VirtualTarget linkTo, LinkProperties linkProperties) { public static Pocket generatePocketV2(VirtualPocket virtualPocket, PocketGenerationParameters parameters) {
return virtualPocket.prepareAndPlacePocket(world, virtualLocation, linkTo, linkProperties); return virtualPocket.prepareAndPlacePocket(parameters);
} }
/** /**

View file

@ -32,7 +32,7 @@ public class PocketTemplateV2 {
private final int size; private final int size;
private final String id; private final String id;
public PocketTemplateV2(Schematic schematic, String group, int size, String id, float weight) { public PocketTemplateV2(Schematic schematic, String group, int size, String id) {
this.schematic = schematic; this.schematic = schematic;
this.group = group; this.group = group;
this.size = size; this.size = size;

View file

@ -16,7 +16,8 @@ import com.mojang.serialization.JsonOps;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dimdev.dimdoors.util.WeightedSet; import org.dimdev.dimdoors.util.PocketGenerationParameters;
import org.dimdev.dimdoors.util.WeightedList;
import org.dimdev.dimdoors.util.schematic.v2.Schematic; import org.dimdev.dimdoors.util.schematic.v2.Schematic;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -27,7 +28,7 @@ public class SchematicV2Handler {
private static final Gson GSON = new GsonBuilder().setLenient().setPrettyPrinting().create(); private static final Gson GSON = new GsonBuilder().setLenient().setPrettyPrinting().create();
private static final SchematicV2Handler INSTANCE = new SchematicV2Handler(); private static final SchematicV2Handler INSTANCE = new SchematicV2Handler();
private final Map<Identifier, PocketTemplateV2> templates = Maps.newHashMap(); private final Map<Identifier, PocketTemplateV2> templates = Maps.newHashMap();
private final Map<String, WeightedSet<VirtualPocket>> templateMap = Maps.newHashMap(); //TODO: un-ugly-fy private final Map<String, WeightedList<VirtualPocket, PocketGenerationParameters>> templateMap = Maps.newHashMap(); //TODO: un-ugly-fy
private final List<PocketGroup> pocketTypes = Lists.newArrayList(); private final List<PocketGroup> pocketTypes = Lists.newArrayList();
private static final Random RANDOM = new Random(new Random().nextLong()); private static final Random RANDOM = new Random(new Random().nextLong());
private boolean loaded = false; private boolean loaded = false;
@ -70,17 +71,17 @@ public class SchematicV2Handler {
*/ */
private void loadResourceSchematics(PocketGroup type) throws URISyntaxException, IOException { private void loadResourceSchematics(PocketGroup type) throws URISyntaxException, IOException {
String group = type.getGroup(); String group = type.getGroup();
WeightedSet<VirtualPocket> weightedPockets = new WeightedSet<>(); WeightedList<VirtualPocket, PocketGenerationParameters> weightedPockets = new WeightedList<>();
templateMap.put(group, weightedPockets); templateMap.put(group, weightedPockets);
Path basePath = Paths.get(SchematicV2Handler.class.getResource(String.format("/data/dimdoors/pockets/schematic/v2/%s/", group)).toURI()); Path basePath = Paths.get(SchematicV2Handler.class.getResource(String.format("/data/dimdoors/pockets/schematic/v2/%s/", group)).toURI());
for (VirtualPocket virtualPocket : type.getEntries()) { for (VirtualPocket virtualPocket : type.getEntries()) {
weightedPockets.add(virtualPocket, virtualPocket.getWeight()); weightedPockets.add(virtualPocket);
if (virtualPocket instanceof VirtualSchematicPocket) { if (virtualPocket instanceof VirtualSchematicPocket) {
VirtualSchematicPocket schemPocket = (VirtualSchematicPocket) virtualPocket; VirtualSchematicPocket schemPocket = (VirtualSchematicPocket) virtualPocket;
Path schemPath = basePath.resolve(schemPocket.getName() + ".schem"); Path schemPath = basePath.resolve(schemPocket.getName() + ".schem");
CompoundTag schemTag = NbtIo.readCompressed(Files.newInputStream(schemPath)); CompoundTag schemTag = NbtIo.readCompressed(Files.newInputStream(schemPath));
Schematic schematic = Schematic.fromTag(schemTag); Schematic schematic = Schematic.fromTag(schemTag);
PocketTemplateV2 template = new PocketTemplateV2(schematic, group, schemPocket.getSize(), schemPocket.getName(), schemPocket.getWeight()); PocketTemplateV2 template = new PocketTemplateV2(schematic, group, schemPocket.getSize(), schemPocket.getName());
Identifier templateID = new Identifier("dimdoors", schemPocket.getName()); Identifier templateID = new Identifier("dimdoors", schemPocket.getName());
templates.put(templateID, template); templates.put(templateID, template);
schemPocket.setTemplateID(templateID); schemPocket.setTemplateID(templateID);
@ -88,16 +89,16 @@ public class SchematicV2Handler {
} }
} }
public VirtualPocket getRandomPublicPocket() { public VirtualPocket getRandomPublicPocket(PocketGenerationParameters parameters) {
return getRandomPocketFromGroup("public"); return getRandomPocketFromGroup("public", parameters);
} }
public VirtualPocket getRandomPrivatePocket() { public VirtualPocket getRandomPrivatePocket(PocketGenerationParameters parameters) {
return getRandomPocketFromGroup("private"); return getRandomPocketFromGroup("private", parameters);
} }
public VirtualPocket getRandomPocketFromGroup(String group) { public VirtualPocket getRandomPocketFromGroup(String group, PocketGenerationParameters parameters) {
return templateMap.get(group).getRandomWeighted(); return templateMap.get(group).getRandomWeighted(parameters);
} }
public static SchematicV2Handler getInstance() { public static SchematicV2Handler getInstance() {

View file

@ -10,11 +10,17 @@ import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.SimpleRegistry; import net.minecraft.util.registry.SimpleRegistry;
import org.dimdev.dimdoors.rift.registry.LinkProperties; import org.dimdev.dimdoors.rift.registry.LinkProperties;
import org.dimdev.dimdoors.rift.targets.VirtualTarget; import org.dimdev.dimdoors.rift.targets.VirtualTarget;
import org.dimdev.dimdoors.util.PocketGenerationParameters;
import org.dimdev.dimdoors.util.Weighted;
import org.dimdev.dimdoors.world.pocket.Pocket; import org.dimdev.dimdoors.world.pocket.Pocket;
import org.dimdev.dimdoors.world.pocket.VirtualLocation; import org.dimdev.dimdoors.world.pocket.VirtualLocation;
/*
*/
// maybe PocketEntry is a better name? Only realised after I named this that the previous PocketEntry would be redundant. // maybe PocketEntry is a better name? Only realised after I named this that the previous PocketEntry would be redundant.
public abstract class VirtualPocket { public abstract class VirtualPocket implements Weighted<PocketGenerationParameters> {
public static final Registry<VirtualPocketType<? extends VirtualPocket>> REGISTRY = FabricRegistryBuilder.from(new SimpleRegistry<VirtualPocketType<? extends VirtualPocket>>(RegistryKey.ofRegistry(new Identifier("dimdoors", "virtual_pocket_type")), Lifecycle.stable())).buildAndRegister(); public static final Registry<VirtualPocketType<? extends VirtualPocket>> REGISTRY = FabricRegistryBuilder.from(new SimpleRegistry<VirtualPocketType<? extends VirtualPocket>>(RegistryKey.ofRegistry(new Identifier("dimdoors", "virtual_pocket_type")), Lifecycle.stable())).buildAndRegister();
public static final Codec<VirtualPocket> CODEC = new Codec<VirtualPocket>() { public static final Codec<VirtualPocket> CODEC = new Codec<VirtualPocket>() {
@Override @Override
@ -30,12 +36,10 @@ public abstract class VirtualPocket {
}; };
public abstract Pocket prepareAndPlacePocket(ServerWorld world, VirtualLocation virtualLocation, VirtualTarget linkTo, LinkProperties linkProperties); public abstract Pocket prepareAndPlacePocket(PocketGenerationParameters parameters);
public abstract String toString(); public abstract String toString();
// TODO: are equals() and hashCode() necessary? // TODO: are equals() and hashCode() necessary?
public abstract VirtualPocketType<? extends VirtualPocket> getType(); public abstract VirtualPocketType<? extends VirtualPocket> getType();
public abstract int getWeight();
public interface VirtualPocketType<T extends VirtualPocket> { public interface VirtualPocketType<T extends VirtualPocket> {
VirtualPocketType<VirtualSchematicPocket> SCHEMATIC = register("dimdoors:schematic", VirtualSchematicPocket.CODEC); VirtualPocketType<VirtualSchematicPocket> SCHEMATIC = register("dimdoors:schematic", VirtualSchematicPocket.CODEC);

View file

@ -8,7 +8,8 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dimdev.dimdoors.rift.registry.LinkProperties; import org.dimdev.dimdoors.rift.registry.LinkProperties;
import org.dimdev.dimdoors.rift.targets.VirtualTarget; import org.dimdev.dimdoors.rift.targets.VirtualTarget;
import org.dimdev.dimdoors.util.DimensionalRegistry; import org.dimdev.dimdoors.util.PocketGenerationParameters;
import org.dimdev.dimdoors.world.level.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.Pocket; import org.dimdev.dimdoors.world.pocket.Pocket;
import org.dimdev.dimdoors.world.pocket.VirtualLocation; import org.dimdev.dimdoors.world.pocket.VirtualLocation;
@ -18,7 +19,7 @@ public class VirtualSchematicPocket extends VirtualPocket{
public static final Codec<VirtualSchematicPocket> CODEC = RecordCodecBuilder.create(instance -> instance.group( public static final Codec<VirtualSchematicPocket> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.INT.fieldOf("size").forGetter(VirtualSchematicPocket::getSize), Codec.INT.fieldOf("size").forGetter(VirtualSchematicPocket::getSize),
Codec.STRING.fieldOf("id").forGetter(VirtualSchematicPocket::getName), Codec.STRING.fieldOf("id").forGetter(VirtualSchematicPocket::getName),
Codec.INT.optionalFieldOf("weight", 5).forGetter(VirtualSchematicPocket::getWeight) Codec.INT.optionalFieldOf("weight", 5).forGetter(virtualSchematicPocket -> virtualSchematicPocket.getWeight(null))
).apply(instance, VirtualSchematicPocket::new)); ).apply(instance, VirtualSchematicPocket::new));
private final int size; private final int size;
@ -49,15 +50,17 @@ public class VirtualSchematicPocket extends VirtualPocket{
} }
@Override @Override
public int getWeight() { public int getWeight(PocketGenerationParameters parameters){
return this.weight; return this.weight;
} }
@Override @Override
public Pocket prepareAndPlacePocket(ServerWorld world, VirtualLocation virtualLocation, VirtualTarget linkTo, LinkProperties linkProperties) { public Pocket prepareAndPlacePocket(PocketGenerationParameters parameters) {
ServerWorld world = parameters.getWorld();
VirtualLocation virtualLocation = parameters.getVirtualLocation();
VirtualTarget linkTo = parameters.getLinkTo();
LinkProperties linkProperties = parameters.getLinkProperties();
PocketTemplateV2 template = SchematicV2Handler.getInstance().getTemplates().get(templateID); PocketTemplateV2 template = SchematicV2Handler.getInstance().getTemplates().get(templateID);
if (template == null) throw new RuntimeException("Pocket template of id " + templateID + " not found!"); if (template == null) throw new RuntimeException("Pocket template of id " + templateID + " not found!");
LOGGER.info("Generating pocket from template " + template.getId() + " at virtual location " + virtualLocation); LOGGER.info("Generating pocket from template " + template.getId() + " at virtual location " + virtualLocation);

View file

@ -0,0 +1,42 @@
package org.dimdev.dimdoors.util;
import net.minecraft.server.world.ServerWorld;
import org.dimdev.dimdoors.rift.registry.LinkProperties;
import org.dimdev.dimdoors.rift.targets.VirtualTarget;
import org.dimdev.dimdoors.world.pocket.VirtualLocation;
public class PocketGenerationParameters {
private final ServerWorld world;
private final String group;
private final VirtualLocation virtualLocation;
private final VirtualTarget linkTo;
private final LinkProperties linkProperties;
public PocketGenerationParameters(ServerWorld world, String group, VirtualLocation virtualLocation, VirtualTarget linkTo, LinkProperties linkProperties) {
this.world = world;
this.group = group;
this.virtualLocation = virtualLocation;
this.linkTo = linkTo;
this.linkProperties = linkProperties;
}
public ServerWorld getWorld() {
return world;
}
public String getGroup() {
return group;
}
public VirtualLocation getVirtualLocation() {
return virtualLocation;
}
public VirtualTarget getLinkTo() {
return linkTo;
}
public LinkProperties getLinkProperties() {
return linkProperties;
}
}

View file

@ -0,0 +1,9 @@
package org.dimdev.dimdoors.util;
public interface Weighted<P> {
/*
Should always return the same number if the same parameters are provided.
returned number should always be >= 0
*/
int getWeight(P parameters);
}

View file

@ -0,0 +1,39 @@
package org.dimdev.dimdoors.util;
import com.google.common.collect.Lists;
import java.util.*;
public class WeightedList<T extends Weighted<P>, P> {
private final List<T> list;
private final Random random = new Random();
public WeightedList() {
this.list = Lists.newArrayList();
}
public T getRandomWeighted(P parameters) {
int totalWeight = list.stream().mapToInt(weighted -> weighted.getWeight(parameters)).sum();
int cursor = random.nextInt(totalWeight);
for (T weighted : list) {
cursor -= weighted.getWeight(parameters);
if (cursor <= 0) {
return weighted; // should never return an entry with weight 0, unless there are only weight 0 entries
}
}
return null;
}
public boolean add(T t) {
return list.add(t);
}
public boolean remove(T t){
return list.remove(t);
}
// TODO: make weightedList implement List instead
public List<T> getList() {
return list;
}
}

View file

@ -1,69 +0,0 @@
package org.dimdev.dimdoors.util;
import net.minecraft.util.Pair;
import java.util.*;
import java.util.stream.Collectors;
public class WeightedSet<T> {
private final TreeSet<Pair<T, Integer>> set;
private final int defaultWeight;
private int totalWeight = 0;
private boolean dirty = false;
private final Random random = new Random();
public WeightedSet() {
this(1);
}
//TODO: ensure default Weight is >= 0?
public WeightedSet(int defaultWeight) {
this.set = new TreeSet<>((pair1, pair2) -> pair2.getRight().compareTo(pair1.getRight()));
this.defaultWeight = defaultWeight;
}
private void markDirty() {
dirty = true;
}
private void updateTotalWeight() {
if (dirty) totalWeight = set.stream().mapToInt(Pair::getRight).sum();
}
public T getRandomWeighted() {
updateTotalWeight();
int cursor = random.nextInt(totalWeight);
for (Pair<T, Integer> pair : set) {
cursor -= pair.getRight();
if (cursor <= 0) {
return pair.getLeft(); // should never return an entry with weight 0, unless there are only weight 0 entries
}
}
throw new RuntimeException(); // either the list is empty, or it somehow
}
// TODO: ensure weight is >= 0? How about a negativeWeightException?
public boolean add(T t, Integer weight) {
if (set.add(new Pair<>(t, weight))) {
markDirty();
return true;
}
return false;
}
public boolean add(T t) {
return add(t, defaultWeight);
}
public boolean remove(T t){
if (set.remove(set.stream().filter(pair -> pair.getLeft().equals(t)).findFirst().orElse(null))) {
markDirty();
return true;
}
return false;
}
public List<T> getObjectList() {
return set.stream().map(Pair::getLeft).collect(Collectors.toList());
}
}