/* * This file is a part of the SteamWar software. * * Copyright (C) 2020 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ package de.steamwar.bausystem.world.regions; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSyntaxException; import com.sk89q.worldedit.EditSession; import de.steamwar.bausystem.commands.CommandTNT.TNTMode; import de.steamwar.bausystem.world.Color; import de.steamwar.bausystem.world.SizedStack; import de.steamwar.sql.NoClipboardException; import de.steamwar.sql.SchematicNode; import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.function.Consumer; import java.util.logging.Level; public class Region { private static final List regions = new ArrayList<>(); static boolean buildArea = false; static boolean extensionArea = false; private static JsonObject regionsObject = new JsonObject(); static { File regionsFile = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "regions.json"); if (regionsFile.exists()) { try { regionsObject = new JsonParser().parse(new FileReader(regionsFile)).getAsJsonObject(); } catch (JsonSyntaxException | IOException e) { Bukkit.getLogger().log(Level.WARNING, "Item JSON error"); } } YamlConfiguration config = new YamlConfiguration(); try { config.load(new File(Bukkit.getWorlds().get(0).getWorldFolder(), "sections.yml")); } catch (InvalidConfigurationException | IOException e) { Bukkit.getLogger().log(Level.SEVERE, "Failed to load sections.yml", e); } ConfigurationSection prototypes = config.getConfigurationSection("prototypes"); assert prototypes != null; for (String prototype : prototypes.getKeys(false)) { new Prototype(Objects.requireNonNull(prototypes.getConfigurationSection(prototype))); } ConfigurationSection regions = config.getConfigurationSection("regions"); assert regions != null; for (String region : regions.getKeys(false)) { new Region(Objects.requireNonNull(regions.getConfigurationSection(region))); } } public static boolean buildAreaEnabled() { return buildArea; } public static boolean extensionAreaEnabled() { return extensionArea; } public static Region getRegion(Location location) { for (Region region : regions) { if (region.inRegion(location, RegionType.NORMAL, RegionExtensionType.NORMAL)) { return region; } } return GlobalRegion.getInstance(); } public static void setGlobalColor(Color color) { for (Region region : regions) { region.setColor(color); } } public static void save() { File colorsFile = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "regions.json"); if (!colorsFile.exists()) { try { colorsFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); return; } } try (FileOutputStream fileOutputStream = new FileOutputStream(colorsFile)) { fileOutputStream.write(regionsObject.toString().getBytes()); } catch (IOException e) { e.printStackTrace(); // Ignored } } private final String name; final Point minPoint; private final Prototype prototype; private final String optionsLinkedWith; // nullable private Region linkedRegion = null; // nullable private SizedStack undosessions; private SizedStack redosessions; private JsonObject regionOptions = new JsonObject(); @Getter private TNTMode tntMode = Region.buildAreaEnabled() ? TNTMode.ONLY_TB : TNTMode.OFF; @Getter private boolean freeze = false; @Getter private boolean fire = false; @Getter private boolean protect = false; @Getter private Color color = Color.YELLOW; private Region(ConfigurationSection config) { name = config.getName(); minPoint = new Point(config.getInt("minX"), config.getInt("minY"), config.getInt("minZ")); prototype = Prototype.prototypes.get(config.getString("prototype")); optionsLinkedWith = config.getString("optionsLinkedWith", null); if (!hasTestblock()) tntMode = TNTMode.OFF; regions.add(this); load(); } public Region(String name) { this.name = name; this.minPoint = new Point(0, 0, 0); this.prototype = null; this.optionsLinkedWith = null; tntMode = TNTMode.OFF; load(); } private void load() { if (regionsObject.has(name)) { regionOptions = regionsObject.getAsJsonObject(name); if (regionOptions.has("tnt")) { String tntName = regionsObject.getAsJsonObject(name).getAsJsonPrimitive("tnt").getAsString(); try { tntMode = TNTMode.valueOf(tntName); } catch (Exception e) { // Ignored } } if (regionOptions.has("fire")) { fire = regionOptions.getAsJsonPrimitive("fire").getAsBoolean(); } if (regionOptions.has("freeze")) { freeze = regionOptions.getAsJsonPrimitive("freeze").getAsBoolean(); } if (regionOptions.has("protect")) { protect = regionOptions.getAsJsonPrimitive("protect").getAsBoolean(); } if (regionOptions.has("color")) { String colorName = regionOptions.getAsJsonPrimitive("color").getAsString(); try { color = Color.valueOf(colorName); } catch (Exception e) { // Ignored } } } else { regionsObject.add(name, regionOptions); } } public void setColor(Color color) { this.color = color; regionOptions.add("color", new JsonPrimitive(color.name())); } private void setLinkedRegion(Consumer regionConsumer) { if (optionsLinkedWith == null) { return; } if (linkedRegion != null) { regionConsumer.accept(linkedRegion); return; } for (Region region : regions) { if (region.name.equals(name)) { linkedRegion = region; regionConsumer.accept(linkedRegion); return; } } } public void setTntMode(TNTMode tntMode) { this.tntMode = tntMode; setLinkedRegion(region -> { region.tntMode = tntMode; region.regionOptions.add("tnt", new JsonPrimitive(tntMode.name())); }); regionOptions.add("tnt", new JsonPrimitive(tntMode.name())); } public void setFreeze(boolean freeze) { this.freeze = freeze; setLinkedRegion(region -> { region.freeze = freeze; region.regionOptions.add("freeze", new JsonPrimitive(freeze)); }); regionOptions.add("freeze", new JsonPrimitive(freeze)); } public void setFire(boolean fire) { this.fire = fire; setLinkedRegion(region -> { region.fire = fire; region.regionOptions.add("fire", new JsonPrimitive(fire)); }); regionOptions.add("fire", new JsonPrimitive(fire)); } public void setProtect(boolean protect) { this.protect = protect; setLinkedRegion(region -> { region.protect = protect; region.regionOptions.add("protect", new JsonPrimitive(protect)); }); regionOptions.add("protect", new JsonPrimitive(protect)); } public Point getMinPoint(RegionType regionType, RegionExtensionType regionExtensionType) { switch (regionType) { case BUILD: return prototype.buildArea.getMinPoint(this, regionExtensionType); case TESTBLOCK: return prototype.testblock.getMinPoint(this, regionExtensionType); default: case NORMAL: return prototype.getMinPoint(this, regionExtensionType); } } public Point getMaxPoint(RegionType regionType, RegionExtensionType regionExtensionType) { switch (regionType) { case BUILD: return prototype.buildArea.getMaxPoint(this, regionExtensionType); case TESTBLOCK: return prototype.testblock.getMaxPoint(this, regionExtensionType); default: case NORMAL: return prototype.getMaxPoint(this, regionExtensionType); } } public boolean inRegion(Location l, RegionType regionType, RegionExtensionType regionExtensionType) { switch (regionType) { case BUILD: return prototype.buildArea.inRegion(this, l, regionExtensionType); case TESTBLOCK: return prototype.testblock.inRegion(this, l, regionExtensionType); default: case NORMAL: return prototype.inRegion(this, l, regionExtensionType); } } public boolean hasBuildRegion() { return prototype.buildArea != null; } public void reset(SchematicNode schem, boolean ignoreAir) throws IOException, NoClipboardException { initSessions(); undosessions.push(prototype.reset(this, schem, ignoreAir, color)); } public boolean hasTestblock() { return prototype.hasTestblock(); } public void resetTestblock(SchematicNode schem, boolean reset) throws IOException, NoClipboardException { initSessions(); undosessions.push(prototype.resetTestblock(this, schem, color, reset)); } public boolean hasProtection() { return prototype.hasProtection(); } public void protect(SchematicNode schem) throws IOException, NoClipboardException { initSessions(); undosessions.push(prototype.protect(this, schem)); } public int getProtectYLevel() { return getMinPoint(RegionType.TESTBLOCK, RegionExtensionType.NORMAL).getY(); } public boolean hasExtensionArea(RegionType regionType) { switch (regionType) { case BUILD: return prototype.buildArea.extensionPrototypeArea; case TESTBLOCK: return prototype.testblock.extensionPrototypeArea; default: case NORMAL: return prototype.extensionPrototypeArea; } } private void initSessions() { if (undosessions == null) { undosessions = new SizedStack<>(20); redosessions = new SizedStack<>(20); } } public boolean undo() { initSessions(); EditSession session = null; try { session = undosessions.pop(); if (session == null) { return false; } session.undo(session); redosessions.push(session); return true; } finally { if (session != null) { session.flushQueue(); } } } public boolean redo() { initSessions(); EditSession session = null; try { session = redosessions.pop(); if (session == null) { return false; } session.redo(session); undosessions.push(session); return true; } finally { if (session != null) { session.flushQueue(); } } } }