/* * 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 de.steamwar.bausystem.region.flags.Flag; import de.steamwar.bausystem.region.utils.RegionExtensionType; import de.steamwar.bausystem.region.utils.RegionType; import de.steamwar.bausystem.shared.SizedStack; 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 yapion.serializing.YAPIONSerializer; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; @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; } private 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; private SizedStack undoSessions; 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); } if (regionConfig.containsKey("linkedWith")) { linkedRegionName = regionConfig.getPlainValue("linkedWith"); } 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); } 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) { switch (regionType) { case BUILD: return prototype != null && prototype.getBuild() != null; case TESTBLOCK: return prototype != null && prototype.getTestblock() != null; default: case NORMAL: return true; } } public String getDisplayName() { return prototype != null ? prototype.getDisplayName() : ""; } private void setLinkedRegion(Consumer regionConsumer) { if (linkedRegionName == null) { return; } if (linkedRegion != null) { regionConsumer.accept(linkedRegion); return; } for (Region region : REGION_LIST) { if (region.name.equals(name)) { linkedRegion = region; regionConsumer.accept(linkedRegion); return; } } } public void setPrototype(@NonNull Prototype prototype) { if (this.prototype == null) { return; } regionData.add("prototype", prototype.getName()); generatePrototypeData(prototype, minPoint); setLinkedRegion(region -> { region.regionData.add("prototype", prototype.getName()); region.generatePrototypeData(prototype, region.minPoint); }); } public void set(Flag flagType, Flag.Value value) { if (flagStorage.set(flagType, value)) { regionData.add("flagStorage", YAPIONSerializer.serialize(flagStorage)); } setLinkedRegion(region -> region.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 void reset(RegionType regionType) { if (!hasType(regionType)) { return; } switch (regionType) { case BUILD: case TESTBLOCK: default: case NORMAL: } } }