/* * This file is a part of the SteamWar software. * * Copyright (C) 2021 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.region; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.bausystem.region.flags.Flag; import de.steamwar.bausystem.region.flags.flagvalues.ColorMode; import de.steamwar.bausystem.region.flags.flagvalues.TNTMode; import de.steamwar.bausystem.region.loader.RegionLoader; import de.steamwar.bausystem.region.utils.RegionExtensionType; import de.steamwar.bausystem.region.utils.RegionType; import de.steamwar.bausystem.shared.SizedStack; import de.steamwar.core.VersionedCallable; import de.steamwar.sql.Schematic; import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; import org.bukkit.Location; import yapion.hierarchy.types.YAPIONObject; import yapion.hierarchy.types.YAPIONType; import yapion.hierarchy.types.YAPIONValue; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; import static de.steamwar.bausystem.region.RegionUtils.paste; @Getter public class Region { private static final List REGION_LIST = new ArrayList<>(); public static Region getRegion(Location location) { for (Region region : REGION_LIST) { if (region.inRegion(location, RegionType.NORMAL, RegionExtensionType.NORMAL)) { return region; } } return GlobalRegion.instance; } public static void setGlobal(Flag flagType, Flag.Value value) { for (Region region : REGION_LIST) { region.set(flagType, value); } } YAPIONObject regionData; private String name; private Prototype prototype; private Set prototypes; private Point minPoint; private Point maxPoint; private Point minPointTestblock; private Point maxPointTestblock; private Point minPointTestblockExtension; private Point maxPointTestblockExtension; private Point minPointBuild; private Point maxPointBuild; private Point minPointBuildExtension; private Point maxPointBuildExtension; private int floorLevel; private int waterLevel; private String linkedRegionName = null; // Nullable private Region linkedRegion = null; // Nullable private FlagStorage flagStorage; @Getter(AccessLevel.PRIVATE) private SizedStack undoSessions; @Getter(AccessLevel.PRIVATE) private SizedStack redoSessions; public Region(String name, Prototype prototype, YAPIONObject regionConfig, FlagStorage flagStorage, YAPIONObject regionData) { this.name = name; this.regionData = regionData; if (prototype != null) { REGION_LIST.add(this); } linkedRegionName = regionConfig.getPlainValueOrDefault("optionsLinkedWith", null); prototypes = new HashSet<>(); if (regionConfig.containsKey("prototypes", YAPIONType.ARRAY)) { regionConfig.getArray("prototypes").forEach(yapionAnyType -> { if (yapionAnyType instanceof YAPIONValue) { prototypes.add(Prototype.PROTOTYPE_MAP.get(((YAPIONValue) yapionAnyType).get())); } }); } this.flagStorage = flagStorage; Point point = null; if (regionConfig.containsKey("minX", Integer.class) && regionConfig.containsKey("minY", Integer.class) && regionConfig.containsKey("minZ", Integer.class)) { point = new Point(regionConfig.getPlainValue("minX"), regionConfig.getPlainValue("minY"), regionConfig.getPlainValue("minZ")); } generatePrototypeData(prototype, point); if (!hasType(RegionType.BUILD) || !hasType(RegionType.TESTBLOCK)) { flagStorage.set(Flag.TNT, TNTMode.DENY); } } private void generatePrototypeData(Prototype prototype, Point point) { if (prototype == null) { return; } if (this.prototype != null && !prototypes.contains(prototype)) { return; } this.prototype = prototype; this.minPoint = point; this.maxPoint = point.add(prototype.getSizeX(), prototype.getSizeY(), prototype.getSizeZ()); if (prototype.getTestblock() != null) { this.minPointTestblock = point.add(prototype.getTestblock().getOffsetX(), prototype.getTestblock().getOffsetY(), prototype.getTestblock().getOffsetZ()); this.maxPointTestblock = this.minPointTestblock.add(prototype.getTestblock().getSizeX(), prototype.getTestblock().getSizeY(), prototype.getTestblock().getSizeZ()); this.minPointTestblockExtension = this.minPointTestblock.substract(prototype.getTestblock().getExtensionNegativeX(), prototype.getTestblock().getExtensionNegativeY(), prototype.getTestblock().getExtensionNegativeZ()); this.maxPointTestblockExtension = this.maxPointTestblock.add(prototype.getTestblock().getExtensionPositiveX(), prototype.getTestblock().getExtensionPositiveY(), prototype.getTestblock().getExtensionPositiveZ()); } if (prototype.getBuild() != null) { this.minPointBuild = point.add(prototype.getBuild().getOffsetX(), prototype.getBuild().getOffsetY(), prototype.getBuild().getOffsetZ()); this.maxPointBuild = this.minPointBuild.add(prototype.getBuild().getSizeX(), prototype.getBuild().getSizeY(), prototype.getBuild().getSizeZ()); this.minPointBuildExtension = this.minPointBuild.substract(prototype.getBuild().getExtensionNegativeX(), prototype.getBuild().getExtensionNegativeY(), prototype.getBuild().getExtensionNegativeZ()); this.maxPointBuildExtension = this.maxPointBuild.add(prototype.getBuild().getExtensionPositiveX(), prototype.getBuild().getExtensionPositiveY(), prototype.getBuild().getExtensionPositiveZ()); } if (prototype.getFloorOffset() != 0) { floorLevel = minPoint.getY() + prototype.getFloorOffset(); } else { floorLevel = 0; } if (prototype.getWaterOffset() != 0) { waterLevel = minPoint.getY() + prototype.getWaterOffset(); } else { waterLevel = 0; } } public boolean inRegion(Location location, RegionType regionType, RegionExtensionType regionExtensionType) { if (!hasType(regionType)) { return false; } switch (regionType) { case BUILD: Point minBPoint = regionExtensionType == RegionExtensionType.EXTENSION ? minPointBuildExtension : minPointBuild; Point maxBPoint = regionExtensionType == RegionExtensionType.EXTENSION ? maxPointBuildExtension : maxPointBuild; return inRegion(location, minBPoint, maxBPoint); case TESTBLOCK: Point minTBPoint = regionExtensionType == RegionExtensionType.EXTENSION ? minPointTestblockExtension : minPointTestblock; Point maxTBPoint = regionExtensionType == RegionExtensionType.EXTENSION ? maxPointTestblockExtension : maxPointTestblock; return inRegion(location, minTBPoint, maxTBPoint); default: case NORMAL: return inRegion(location, minPoint, maxPoint); } } private boolean inRegion(Location location, Point minPoint, Point maxPoint) { return location.getBlockX() >= minPoint.getX() && location.getBlockX() < maxPoint.getX() && location.getBlockY() >= minPoint.getY() && location.getBlockY() < maxPoint.getY() && location.getBlockZ() >= minPoint.getZ() && location.getBlockZ() < maxPoint.getZ(); } public boolean hasType(RegionType regionType) { if (prototype == null) { return false; } if (regionType == null) { return false; } switch (regionType) { case BUILD: return prototype.getBuild() != null; case TESTBLOCK: return prototype.getTestblock() != null; default: case NORMAL: return true; } } public boolean hasExtensionType(RegionType regionType) { if (!hasType(regionType)) { return false; } switch (regionType) { case BUILD: return prototype.getBuild().isExtensionRegistered(); case TESTBLOCK: return prototype.getTestblock().isExtensionRegistered(); default: case NORMAL: return false; } } public String getDisplayName() { return prototype != null ? prototype.getDisplayName() : ""; } private void setLinkedRegion(Predicate regionConsumer) { if (linkedRegionName == null) { return; } if (linkedRegion != null) { if (regionConsumer.test(linkedRegion)) { RegionUtils.save(linkedRegion); } return; } for (Region region : REGION_LIST) { if (region.name.equals(linkedRegionName)) { linkedRegion = region; if (regionConsumer.test(linkedRegion)) { RegionUtils.save(linkedRegion); } return; } } } public void setPrototype(@NonNull Prototype prototype) { if (this.prototype == null) { return; } if (!prototypes.contains(prototype)) { return; } generatePrototypeData(prototype, minPoint); RegionUtils.save(this); setLinkedRegion(region -> { region.generatePrototypeData(prototype, region.minPoint); return true; }); } public void set(Flag flagType, Flag.Value value) { if (flagStorage.set(flagType, value)) { RegionUtils.save(this); } setLinkedRegion(region -> region.flagStorage.set(flagType, value)); } public & Flag.Value> Flag.Value get(Flag flagType) { return flagStorage.get(flagType); } public & Flag.Value> T getPlain(Flag flagType) { return (T) flagStorage.get(flagType).getValue(); } public & Flag.Value> T getPlain(Flag flagType, Class type) { return (T) flagStorage.get(flagType).getValue(); } public Point getMinPoint(RegionType regionType, RegionExtensionType regionExtensionType) { switch (regionType) { case TESTBLOCK: return (regionExtensionType == null || regionExtensionType == RegionExtensionType.NORMAL) ? minPointTestblock : minPointTestblockExtension; case BUILD: return (regionExtensionType == null || regionExtensionType == RegionExtensionType.NORMAL) ? minPointBuild : minPointBuildExtension; default: case NORMAL: return minPoint; } } public Point getMaxPoint(RegionType regionType, RegionExtensionType regionExtensionType) { switch (regionType) { case TESTBLOCK: return (regionExtensionType == null || regionExtensionType == RegionExtensionType.NORMAL) ? maxPointTestblock : maxPointTestblockExtension; case BUILD: return (regionExtensionType == null || regionExtensionType == RegionExtensionType.NORMAL) ? maxPointBuild : maxPointBuildExtension; default: case NORMAL: return maxPoint; } } boolean hasReset(RegionType regionType) { if (!hasType(regionType)) { return false; } switch (regionType) { case TESTBLOCK: return prototype.getTestblock().getSchematicFile() != null; case BUILD: return prototype.getBuild().getSchematicFile() != null; default: case NORMAL: return prototype.getSchematicFile() != null; } } public void reset(RegionType regionType) throws IOException { reset(null, regionType); } public void reset(Schematic schematic, RegionType regionType) throws IOException { reset(schematic, regionType, RegionExtensionType.NORMAL, false); } public void reset(RegionType regionType, RegionExtensionType regionExtensionType) throws IOException { reset(null, regionType, regionExtensionType, false); } public void reset(Schematic schematic, RegionType regionType, RegionExtensionType regionExtensionType) throws IOException { reset(schematic, regionType, regionExtensionType, false); } public void reset(Schematic schematic, RegionType regionType, RegionExtensionType regionExtensionType, boolean ignoreAir) throws IOException { if (!hasReset(regionType)) { return; } if (regionExtensionType == RegionExtensionType.EXTENSION && !hasExtensionType(regionType)) { regionExtensionType = RegionExtensionType.NORMAL; } PasteOptions pasteOptions = new PasteOptions((schematic != null && (schematic.getSchemType().fightType() || schematic.getSchemType().check())), ignoreAir, getPlain(Flag.COLOR, ColorMode.class).getColor(), regionExtensionType == RegionExtensionType.EXTENSION, getMinPoint(regionType, regionExtensionType), getMaxPoint(regionType, regionExtensionType), waterLevel); EditSession editSession = null; switch (regionType) { case BUILD: System.out.println(schematic + " " + prototype.getBuild().getSchematicFile() + " " + regionType + " " + regionExtensionType + " " + minPointBuild); if (schematic != null) { editSession = paste(schematic.load(), minPointBuild, pasteOptions); } else { editSession = paste(prototype.getBuild().getSchematicFile(), minPointBuild, pasteOptions); } break; case TESTBLOCK: System.out.println(schematic + " " + prototype.getBuild().getSchematicFile() + " " + regionType + " " + regionExtensionType + " " + minPointTestblock); if (schematic != null) { editSession = paste(schematic.load(), minPointTestblock, pasteOptions); } else { editSession = paste(prototype.getTestblock().getSchematicFile(), minPointTestblock, pasteOptions); } break; default: case NORMAL: System.out.println(schematic + " " + prototype.getBuild().getSchematicFile() + " " + regionType + " " + regionExtensionType + " " + minPoint); if (schematic != null) { editSession = paste(schematic.load(), minPoint, pasteOptions); } else { editSession = paste(prototype.getSchematicFile(), minPoint, pasteOptions); } break; } initSessions(); undoSessions.push(editSession); } public boolean isGlobal() { return this == GlobalRegion.getInstance(); } 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.flushSession(); } } } 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.flushSession(); } } } }