Citizens2/main/src/main/java/net/citizensnpcs/npc/Template.java

192 lines
6.7 KiB
Java

package net.citizensnpcs.npc;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.DespawnReason;
import net.citizensnpcs.api.event.SpawnReason;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.MemoryDataKey;
import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.api.util.YamlStorage;
import net.citizensnpcs.api.util.YamlStorage.YamlKey;
public class Template {
private final String name;
private final boolean override;
private final Map<String, Object> replacements;
private Template(String name, Map<String, Object> replacements, boolean override) {
this.replacements = replacements;
this.override = override;
this.name = name;
}
@SuppressWarnings("unchecked")
public void apply(NPC npc) {
MemoryDataKey memoryKey = new MemoryDataKey();
boolean wasSpawned = npc.isSpawned();
if (wasSpawned) {
npc.despawn(DespawnReason.PENDING_RESPAWN);
}
npc.save(memoryKey);
List<Node> queue = Lists.newArrayList(new Node("", replacements));
for (int i = 0; i < queue.size(); i++) {
Node node = queue.get(i);
for (Entry<String, Object> entry : node.map.entrySet()) {
String fullKey = node.headKey.isEmpty() ? entry.getKey() : node.headKey + '.' + entry.getKey();
if (entry.getValue() instanceof Map<?, ?>) {
queue.add(new Node(fullKey, (Map<String, Object>) entry.getValue()));
continue;
}
boolean overwrite = memoryKey.keyExists(fullKey) || override;
if (!overwrite || fullKey.equals("uuid")) {
continue;
}
memoryKey.setRaw(fullKey, entry.getValue());
}
}
npc.load(memoryKey);
if (wasSpawned && npc.getStoredLocation() != null) {
npc.spawn(npc.getStoredLocation(), SpawnReason.RESPAWN);
}
}
public void delete() {
new File(getDirectory(), name + ".yml").delete();
}
public String getName() {
return name;
}
public void save() throws IOException {
File file = new File(getDirectory(), name + ".yml");
if (!file.getParentFile().equals(getDirectory()))
throw new IOException();
try {
file.createNewFile();
} catch (IOException e) {
throw e;
}
YamlStorage storage = new YamlStorage(file);
DataKey root = storage.getKey("");
root.setBoolean("override", override);
root.setRaw("replacements", replacements);
storage.save();
}
public static class Builder {
private final String name;
private boolean override = true;
private final Map<String, Object> replacements = Maps.newHashMap();
private Builder(String name) {
this.name = name;
}
public Template buildAndSave() throws IOException {
Template tpl = new Template(name, replacements, override);
tpl.save();
return tpl;
}
public Builder from(NPC npc) {
replacements.clear();
MemoryDataKey key = new MemoryDataKey();
((CitizensNPC) npc).save(key);
replacements.putAll(key.getValuesDeep());
return this;
}
public Builder override(boolean override) {
this.override = override;
return this;
}
public static Builder create(String name) {
return new Builder(name);
}
}
private static class Node {
String headKey;
Map<String, Object> map;
private Node(String headKey, Map<String, Object> map) {
this.headKey = headKey;
this.map = map;
}
}
public static Template byName(String name) {
if (TEMPLATES.containsKey(name))
return TEMPLATES.get(name);
File file = new File(getDirectory(), name + ".yml");
if (!file.exists() || !file.getParentFile().equals(getDirectory()))
return null;
YamlStorage storage = new YamlStorage(file);
storage.load();
YamlKey key = storage.getKey("");
boolean override = key.getBoolean("override", true);
Map<String, Object> replacements = key.getRelative("replacements").getValuesDeep();
Template res = new Template(name, replacements, override);
TEMPLATES.put(name, res);
return res;
}
private static File getDirectory() {
return new File(CitizensAPI.getDataFolder(), "templates");
}
public static Iterable<Template> getTemplates() {
return Arrays.asList(getDirectory().list()).stream().map(f -> new File(getDirectory(), f))
.filter(f -> !f.isDirectory() && Files.getFileExtension(f.getName()).equals("yml"))
.map(f -> byName(Files.getNameWithoutExtension(f.getName()))).collect(Collectors.toList());
}
public static void migrate() {
File folder = getDirectory();
if (!folder.exists()) {
folder.mkdir();
}
File from = new File(CitizensAPI.getDataFolder(), "templates.yml");
if (from.exists()) {
YamlStorage storage = new YamlStorage(from);
storage.load();
for (DataKey key : storage.getKey("").getSubKeys()) {
String name = key.name();
Map<String, Object> replacements = key.getRelative("replacements").getValuesDeep();
boolean override = key.getBoolean("override", true);
try {
new Template(name, replacements, override).save();
} catch (IOException e) {
Messaging.severe("Unable to migrate template", name, "due to invalid filename");
}
}
try {
Files.move(from, new File(CitizensAPI.getDataFolder(), "templates_migrated.yml"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void shutdown() {
TEMPLATES.clear();
}
private static Map<String, Template> TEMPLATES = Maps.newHashMap();
}