/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.pepsoft.worldpainter.layers.bo2; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Random; import java.util.SortedMap; import java.util.TreeMap; import org.pepsoft.worldpainter.objects.WPObject; import static org.pepsoft.worldpainter.objects.WPObject.*; /** * A custom object provider which maintains a collection of objects which it * returns randomly (weighted according to their {@link * WPObject#ATTRIBUTE_FREQUENCY} attributes). * * @author pepijn */ public class Bo2ObjectTube implements Bo2ObjectProvider { public Bo2ObjectTube(String name, List<WPObject> objects) { this.name = name; this.objects = objects; } @Override public String getName() { return name; } @Override public void setSeed(long seed) { random.setSeed(seed); } @Override public WPObject getObject() { if (weightedObjects == null) { weightedObjects = new TreeMap<>(); totalObjectWeight = 0; for (WPObject object: objects) { int frequency = object.getAttribute(ATTRIBUTE_FREQUENCY); totalObjectWeight += frequency; weightedObjects.put(totalObjectWeight, object); } } return weightedObjects.tailMap(random.nextInt(totalObjectWeight)).values().iterator().next(); } @Override public List<WPObject> getAllObjects() { return Collections.unmodifiableList(objects); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); random = new Random(); } /** * Create a new <code>Bo2ObjectTube</code> containing all supported custom * objects from a specific directory. The name of the * <code>Bo2ObjectTube</code> will be set to the name of the directory. * * @param dir The directory containing the objects to load. * @return A new <code>Bo2ObjectTube</code> containing the supported objects * from the specified directory. * @throws IOException If there was an I/O error reading one of the files. */ public static Bo2ObjectTube load(File dir) throws IOException { return load(dir.getName(), dir); } /** * Create a new <code>Bo2ObjectTube</code> with a specific name, containing * all supported custom objects from a specific directory. * * @param name The name of the new <code>Bo2ObjectTube</code>. * @param dir The directory containing the objects to load. * @return A new <code>Bo2ObjectTube</code> containing the supported objects * from the specified directory. * @throws IOException If there was an I/O error reading one of the files. */ public static Bo2ObjectTube load(String name, File dir) throws IOException { File[] files = dir.listFiles((dir1, name1) -> name1.toLowerCase().endsWith(".bo2") || name1.toLowerCase().endsWith(".bo3") || name1.toLowerCase().endsWith(".schematic")); //noinspection ConstantConditions // Responsibility of caller to provide extant directory return load(name, Arrays.asList(files)); } /** * Create a new <code>Bo2ObjectTube</code> with a specific name from a list * of specific custom object files. * * @param name The name of the new <code>Bo2ObjectTube</code>. * @param files The list of files containing the objects to load. * @return A new <code>Bo2ObjectTube</code> containing the custom objects * from the specified file(s). * @throws IOException If there was an I/O error reading one of the files. */ public static Bo2ObjectTube load(String name, Collection<File> files) throws IOException { if (files.isEmpty()) { throw new IllegalArgumentException("Cannot create an object tube with no objects"); } List<WPObject> objects = new ArrayList<>(files.size()); for (File file: files) { String filename = file.getName().toLowerCase(); if (filename.endsWith(".bo2")) { objects.add(Bo2Object.load(file)); } else if (filename.endsWith(".bo3")) { objects.add(Bo3Object.load(file)); } else if (filename.endsWith(".schematic")) { objects.add(Schematic.load(file)); } else { throw new IllegalArgumentException("Unsupported file encountered: " + file); } } return new Bo2ObjectTube(name, objects); } private final String name; private final List<WPObject> objects; private transient Random random = new Random(); private transient SortedMap<Integer, WPObject> weightedObjects; private transient int totalObjectWeight; private static final long serialVersionUID = 1L; }