PageRenderTime 67ms CodeModel.GetById 41ms RepoModel.GetById 0ms app.codeStats 0ms

/worldguard-legacy/src/main/java/com/sk89q/worldguard/protection/managers/storage/file/YamlRegionFile.java

https://gitlab.com/igserfurtmcschulserver/CustomWorldGuard
Java | 342 lines | 244 code | 56 blank | 42 comment | 36 complexity | f189fc9c4a6d4fa2e4ecf94cbbe854f7 MD5 | raw file
  1. /*
  2. * WorldGuard, a suite of tools for Minecraft
  3. * Copyright (C) sk89q <http://www.sk89q.com>
  4. * Copyright (C) WorldGuard team and contributors
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU Lesser General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  14. * for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.sk89q.worldguard.protection.managers.storage.file;
  20. import com.sk89q.util.yaml.YAMLFormat;
  21. import com.sk89q.util.yaml.YAMLNode;
  22. import com.sk89q.util.yaml.YAMLProcessor;
  23. import com.sk89q.worldedit.BlockVector;
  24. import com.sk89q.worldedit.BlockVector2D;
  25. import com.sk89q.worldedit.Vector;
  26. import com.sk89q.worldguard.domains.DefaultDomain;
  27. import com.sk89q.worldguard.protection.flags.Flags;
  28. import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
  29. import com.sk89q.worldguard.protection.managers.RegionDifference;
  30. import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
  31. import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
  32. import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
  33. import com.sk89q.worldguard.protection.managers.storage.StorageException;
  34. import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
  35. import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
  36. import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
  37. import com.sk89q.worldguard.protection.regions.ProtectedRegion;
  38. import org.yaml.snakeyaml.DumperOptions;
  39. import org.yaml.snakeyaml.DumperOptions.FlowStyle;
  40. import org.yaml.snakeyaml.Yaml;
  41. import org.yaml.snakeyaml.constructor.SafeConstructor;
  42. import org.yaml.snakeyaml.representer.Representer;
  43. import java.io.File;
  44. import java.io.FileNotFoundException;
  45. import java.io.IOException;
  46. import java.util.*;
  47. import java.util.logging.Level;
  48. import java.util.logging.Logger;
  49. import static com.google.common.base.Preconditions.checkNotNull;
  50. /**
  51. * A store that persists regions in a YAML-encoded file.
  52. */
  53. public class YamlRegionFile implements RegionDatabase {
  54. private static final Logger log = Logger.getLogger(YamlRegionFile.class.getCanonicalName());
  55. private static final Yaml ERROR_DUMP_YAML;
  56. private static final String FILE_HEADER = "#\r\n" +
  57. "# WorldGuard regions file\r\n" +
  58. "#\r\n" +
  59. "# WARNING: THIS FILE IS AUTOMATICALLY GENERATED. If you modify this file by\r\n" +
  60. "# hand, be aware that A SINGLE MISTYPED CHARACTER CAN CORRUPT THE FILE. If\r\n" +
  61. "# WorldGuard is unable to parse the file, your regions will FAIL TO LOAD and\r\n" +
  62. "# the contents of this file will reset. Please use a YAML validator such as\r\n" +
  63. "# http://yaml-online-parser.appspot.com (for smaller files).\r\n" +
  64. "#\r\n" +
  65. "# REMEMBER TO KEEP PERIODICAL BACKUPS.\r\n" +
  66. "#";
  67. private final String name;
  68. private final File file;
  69. static {
  70. DumperOptions options = new DumperOptions();
  71. options.setIndent(4);
  72. options.setDefaultFlowStyle(FlowStyle.AUTO);
  73. ERROR_DUMP_YAML = new Yaml(new SafeConstructor(), new Representer(), options);
  74. }
  75. /**
  76. * Create a new instance.
  77. *
  78. * @param name the name of this store
  79. * @param file the file
  80. */
  81. public YamlRegionFile(String name, File file) {
  82. checkNotNull(name, "name");
  83. checkNotNull(file, "file");
  84. this.name = name;
  85. this.file = file;
  86. }
  87. @Override
  88. public String getName() {
  89. return name;
  90. }
  91. @Override
  92. public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException {
  93. Map<String, ProtectedRegion> loaded = new HashMap<String, ProtectedRegion>();
  94. YAMLProcessor config = createYamlProcessor(file);
  95. try {
  96. config.load();
  97. } catch (FileNotFoundException e) {
  98. return new HashSet<ProtectedRegion>(loaded.values());
  99. } catch (IOException e) {
  100. throw new StorageException("Failed to load region data from '" + file + "'", e);
  101. }
  102. Map<String, YAMLNode> regionData = config.getNodes("regions");
  103. if (regionData == null) {
  104. return Collections.emptySet(); // No regions are even configured
  105. }
  106. Map<ProtectedRegion, String> parentSets = new LinkedHashMap<ProtectedRegion, String>();
  107. for (Map.Entry<String, YAMLNode> entry : regionData.entrySet()) {
  108. String id = entry.getKey();
  109. YAMLNode node = entry.getValue();
  110. String type = node.getString("type");
  111. ProtectedRegion region;
  112. try {
  113. if (type == null) {
  114. log.warning("Undefined region type for region '" + id + "'!\n" +
  115. "Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
  116. continue;
  117. } else if (type.equals("cuboid")) {
  118. Vector pt1 = checkNotNull(node.getVector("min"));
  119. Vector pt2 = checkNotNull(node.getVector("max"));
  120. BlockVector min = Vector.getMinimum(pt1, pt2).toBlockVector();
  121. BlockVector max = Vector.getMaximum(pt1, pt2).toBlockVector();
  122. region = new ProtectedCuboidRegion(id, min, max);
  123. } else if (type.equals("poly2d")) {
  124. Integer minY = checkNotNull(node.getInt("min-y"));
  125. Integer maxY = checkNotNull(node.getInt("max-y"));
  126. List<BlockVector2D> points = node.getBlockVector2dList("points", null);
  127. region = new ProtectedPolygonalRegion(id, points, minY, maxY);
  128. } else if (type.equals("global")) {
  129. region = new GlobalProtectedRegion(id);
  130. } else {
  131. log.warning("Unknown region type for region '" + id + "'!\n" +
  132. "Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
  133. continue;
  134. }
  135. Integer priority = checkNotNull(node.getInt("priority"));
  136. region.setPriority(priority);
  137. setFlags(flagRegistry, region, node.getNode("flags"));
  138. region.setOwners(parseDomain(node.getNode("owners")));
  139. region.setMembers(parseDomain(node.getNode("members")));
  140. loaded.put(id, region);
  141. String parentId = node.getString("parent");
  142. if (parentId != null) {
  143. parentSets.put(region, parentId);
  144. }
  145. } catch (NullPointerException e) {
  146. log.log(Level.WARNING,
  147. "Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
  148. "Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) +
  149. "\n\nNote: This region will disappear as a result!", e);
  150. }
  151. }
  152. // Relink parents
  153. RegionDatabaseUtils.relinkParents(loaded, parentSets);
  154. return new HashSet<ProtectedRegion>(loaded.values());
  155. }
  156. @Override
  157. public void saveAll(Set<ProtectedRegion> regions) throws StorageException {
  158. checkNotNull(regions);
  159. File tempFile = new File(file.getParentFile(), file.getName() + ".tmp");
  160. YAMLProcessor config = createYamlProcessor(tempFile);
  161. config.clear();
  162. YAMLNode regionsNode = config.addNode("regions");
  163. Map<String, Object> map = regionsNode.getMap();
  164. for (ProtectedRegion region : regions) {
  165. Map<String, Object> nodeMap = new HashMap<String, Object>();
  166. map.put(region.getId(), nodeMap);
  167. YAMLNode node = new YAMLNode(nodeMap, false);
  168. if (region instanceof ProtectedCuboidRegion) {
  169. ProtectedCuboidRegion cuboid = (ProtectedCuboidRegion) region;
  170. node.setProperty("type", "cuboid");
  171. node.setProperty("min", cuboid.getMinimumPoint());
  172. node.setProperty("max", cuboid.getMaximumPoint());
  173. } else if (region instanceof ProtectedPolygonalRegion) {
  174. ProtectedPolygonalRegion poly = (ProtectedPolygonalRegion) region;
  175. node.setProperty("type", "poly2d");
  176. node.setProperty("min-y", poly.getMinimumPoint().getBlockY());
  177. node.setProperty("max-y", poly.getMaximumPoint().getBlockY());
  178. List<Map<String, Object>> points = new ArrayList<Map<String, Object>>();
  179. for (BlockVector2D point : poly.getPoints()) {
  180. Map<String, Object> data = new HashMap<String, Object>();
  181. data.put("x", point.getBlockX());
  182. data.put("z", point.getBlockZ());
  183. points.add(data);
  184. }
  185. node.setProperty("points", points);
  186. } else if (region instanceof GlobalProtectedRegion) {
  187. node.setProperty("type", "global");
  188. } else {
  189. node.setProperty("type", region.getClass().getCanonicalName());
  190. }
  191. node.setProperty("priority", region.getPriority());
  192. node.setProperty("flags", getFlagData(region));
  193. node.setProperty("owners", getDomainData(region.getOwners()));
  194. node.setProperty("members", getDomainData(region.getMembers()));
  195. ProtectedRegion parent = region.getParent();
  196. if (parent != null) {
  197. node.setProperty("parent", parent.getId());
  198. }
  199. }
  200. config.setHeader(FILE_HEADER);
  201. config.save();
  202. //noinspection ResultOfMethodCallIgnored
  203. file.delete();
  204. if (!tempFile.renameTo(file)) {
  205. throw new StorageException("Failed to rename temporary regions file to " + file.getAbsolutePath());
  206. }
  207. }
  208. @Override
  209. public void saveChanges(RegionDifference difference) throws DifferenceSaveException {
  210. throw new DifferenceSaveException("Not supported");
  211. }
  212. @SuppressWarnings("deprecation")
  213. private DefaultDomain parseDomain(YAMLNode node) {
  214. if (node == null) {
  215. return new DefaultDomain();
  216. }
  217. DefaultDomain domain = new DefaultDomain();
  218. for (String name : node.getStringList("players", null)) {
  219. if (!name.isEmpty()) {
  220. domain.addPlayer(name);
  221. }
  222. }
  223. for (String stringId : node.getStringList("unique-ids", null)) {
  224. try {
  225. domain.addPlayer(UUID.fromString(stringId));
  226. } catch (IllegalArgumentException e) {
  227. log.log(Level.WARNING, "Failed to parse UUID '" + stringId + "'", e);
  228. }
  229. }
  230. for (String name : node.getStringList("groups", null)) {
  231. if (!name.isEmpty()) {
  232. domain.addGroup(name);
  233. }
  234. }
  235. return domain;
  236. }
  237. private Map<String, Object> getFlagData(ProtectedRegion region) {
  238. return Flags.marshal(region.getFlags());
  239. }
  240. private void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
  241. if (flagsData != null) {
  242. region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
  243. }
  244. }
  245. private Map<String, Object> getDomainData(DefaultDomain domain) {
  246. Map<String, Object> domainData = new HashMap<String, Object>();
  247. //noinspection deprecation
  248. setDomainData(domainData, "players", domain.getPlayers());
  249. setDomainData(domainData, "unique-ids", domain.getUniqueIds());
  250. setDomainData(domainData, "groups", domain.getGroups());
  251. return domainData;
  252. }
  253. private void setDomainData(Map<String, Object> domainData, String key, Set<?> domain) {
  254. if (domain.isEmpty()) {
  255. return;
  256. }
  257. List<String> list = new ArrayList<String>();
  258. for (Object str : domain) {
  259. list.add(String.valueOf(str));
  260. }
  261. domainData.put(key, list);
  262. }
  263. /**
  264. * Create a YAML processer instance.
  265. *
  266. * @param file the file
  267. * @return a processor instance
  268. */
  269. private YAMLProcessor createYamlProcessor(File file) {
  270. checkNotNull(file);
  271. return new YAMLProcessor(file, false, YAMLFormat.COMPACT);
  272. }
  273. /**
  274. * Dump the given object as YAML for debugging purposes.
  275. *
  276. * @param object the object
  277. * @return the YAML string or an error string if dumping fals
  278. */
  279. private static String toYamlOutput(Object object) {
  280. try {
  281. return ERROR_DUMP_YAML.dump(object).replaceAll("(?m)^", "\t");
  282. } catch (Throwable t) {
  283. return "<error while dumping object>";
  284. }
  285. }
  286. }