/* * 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 yapion.hierarchy.types.YAPIONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; public abstract class RegionData { private final List> properties = new ArrayList<>(); protected final YAPIONObject data; protected final YAPIONObject flagData; protected final Runnable onChange; protected final Map, Flag.Value> flagMap = new HashMap<>(); private Property testblockSchematic = new Property<>("testblockSchematic", SchematicNode::byId, SchematicNode::getId); protected RegionData(YAPIONObject data, Runnable onChange) { this.data = data; this.flagData = data.getObjectOrSetDefault("flagStorage", new YAPIONObject()); this.onChange = onChange; initialize(); for (final Flag flag : Flag.getFlags()) { if (!has(flag).isWritable()) continue; try { String s = flagData.getPlainValue(flag.name()); flagMap.put(flag, flag.valueOfValue(s)); } catch (Exception e) { flagMap.put(flag, (Flag.Value) flag.getDefaultValue()); } } properties.forEach(Property::load); } protected void initialize() { } @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()) { if (flagMap.put(flag, value) != value) { flagData.put(flag.name(), value.name()); onChange.run(); return true; } } return false; } @NonNull public final & Flag.Value> FlagOptional get(@NonNull Flag flag) { return FlagOptional.of(flag, (T) flagMap.get(flag)); } public final void clear() { for (Flag flag : Flag.getFlags()) { if (has(flag).isWritable()) { flagMap.remove(flag); flagData.remove(flag.name()); } } properties.forEach(property -> property.set(null)); onChange.run(); } public final Map, Flag.Value> getBackedMap() { return flagMap; } public SchematicNode getTestblockSchematic() { return testblockSchematic.get(); } public void setTestblockSchematic(SchematicNode schematic) { testblockSchematic.set(schematic); onChange.run(); } @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(); } private final class Property { private final String field; private final Function loader; private final Function writer; private T value; public Property(String field, Function loader, Function writer) { this.field = field; this.loader = loader; this.writer = writer; properties.add(this); } public void load() { if (flagData.containsKey(field)) { value = loader.apply(flagData.getPlainValue(field)); } else { value = null; } } public T get() { return value; } public void set(T value) { this.value = value; if (value == null) { flagData.remove(field); } else { flagData.put(field, writer.apply(value)); } } @Override public String toString() { Object value = this.value; if (value != null) value = writer.apply((T) value); return ", " + field + "=" + value; } } }