/* * This file is a part of the SteamWar software. * * Copyright (C) 2025 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 de.steamwar.bausystem.region.flags.Flag; import de.steamwar.sql.SchematicNode; import lombok.NonNull; import java.util.*; import java.util.function.Function; import java.util.stream.Stream; public abstract class RegionData { protected RegionDataStore store; private final List> properties = new ArrayList<>(); protected final Map, Flag.Value> flagMap = new HashMap<>(); protected final Property testblockSchematic = new Property<>("testblockSchematic", SchematicNode::byId, SchematicNode::getId); protected RegionData(RegionDataStore store) { this.store = store; initialize(); store.loadRegion(this); } public final void setStore(RegionDataStore store) { this.store = store; store.saveRegion(); } protected void initialize() { } /** * All connected Regions are required to have the same type as their RegionData. */ protected Stream connectedRegions() { return Stream.empty(); } @NonNull public abstract & Flag.Value> RegionFlagPolicy has(@NonNull Flag flag); /** * Returns true if the flag was changed and did not already contain the provided value */ public final & Flag.Value> boolean set(@NonNull Flag flag, @NonNull T value) { if (has(flag).isWritable()) { boolean needsSave = flagMap.put(flag, value) != value; if (needsSave) store.saveRegion(); connectedRegions().forEach(region -> { if (region.getRegionData().flagMap.put(flag, value) != value) { region.saveRegion(); } }); return needsSave; } return false; } @NonNull public final & Flag.Value> FlagOptional get(@NonNull Flag flag) { return FlagOptional.of(flag, (T) flagMap.get(flag)); } public final void clear() { Set remove = new HashSet<>(); for (Flag flag : Flag.getFlags()) { if (has(flag).isWritable()) { flagMap.remove(flag); remove.add(flag); } } properties.forEach(property -> property.set(null)); store.saveRegion(); connectedRegions().forEach(region -> { region.getRegionData().flagMap.keySet().removeAll(remove); region.getRegionData().properties.forEach(property -> property.set(null)); region.saveRegion(); }); } public final Map, Flag.Value> getBackedMap() { return flagMap; } public final List> getBackedProperties() { return (List) properties; } public final SchematicNode getTestblockSchematic() { return testblockSchematic.get(); } public final void setTestblockSchematic(SchematicNode schematic) { testblockSchematic.set(schematic); store.saveRegion(); } @Override public final String toString() { StringBuilder st = new StringBuilder(); st.append(getClass().getSimpleName()).append("{"); st.append("flagMap=").append(flagMap); for (Property p : properties) { st.append(p); } st.append("}"); return st.toString(); } public final class Property { public final String field; public final Function loader; public final Function writer; private T value; private Property(String field, Function loader, Function writer) { this.field = field; this.loader = loader; this.writer = writer; properties.add(this); } public T get() { return value; } public void set(T value) { this.value = value; } @Override public String toString() { Object value = this.value; if (value != null) value = writer.apply((T) value); return ", " + field + "=" + value; } } }