Skip to content

Commit

Permalink
Merge pull request #69 from TheNextLvl-net/data-container
Browse files Browse the repository at this point in the history
Add DataContainer API
  • Loading branch information
NonSwag authored Nov 2, 2024
2 parents 8c4c688 + a53f0cc commit e27f4a4
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 2 deletions.
3 changes: 1 addition & 2 deletions api/src/main/java/net/thenextlvl/protect/area/Area.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
* The Area interface represents an area inside a world.
*/
@NullMarked
public interface Area extends Container, FlagProvider, Comparable<Area>, TagSerializable {

public interface Area extends Container, FlagProvider, Comparable<Area>, TagSerializable, DataContainer {
/**
* Retrieves the set of parent areas associated with this area.
*
Expand Down
117 changes: 117 additions & 0 deletions api/src/main/java/net/thenextlvl/protect/area/DataContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package net.thenextlvl.protect.area;

import core.nbt.tag.Tag;
import net.kyori.adventure.key.Key;
import org.jspecify.annotations.NullMarked;

import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;

/**
* A data container stores key-value pairs, where keys are of type {@code Key} and values are of type {@code Tag}.
*/
@NullMarked
public interface DataContainer {
/**
* Retrieves the value associated with the specified key if present.
*
* @param <T> the type of the value extending from Tag
* @param key the key whose associated value is to be returned
* @return an {@code Optional} containing the value if present, or an empty {@code Optional} if not
*/
<T extends Tag> Optional<T> get(Key key);

/**
* Removes the entry for the specified key if it is present.
*
* @param <T> the type of the value extending from Tag
* @param key the key whose associated value is to be removed
* @return an {@link Optional} containing the removed value, or {@link Optional#empty()}
*/
<T extends Tag> Optional<T> remove(Key key);

/**
* Retrieves the value associated with the specified key if present, otherwise returns the provided default value.
*
* @param <T> the type of the value extending from Tag
* @param key the key whose associated value is to be returned
* @param defaultValue the default value to return if the key is not present
* @return the value associated with the specified key, or the default value if the key is not present
*/
<T extends Tag> T getOrDefault(Key key, T defaultValue);

/**
* Sets the specified value for the given key in the data container.
*
* @param <T> the type of the value extending from Tag
* @param key the key with which the specified value is to be associated
* @param value the value to be associated with the specified key
*/
<T extends Tag> void set(Key key, T value);

/**
* Retrieves a map of all entries stored in the data container.
* The keys are of type {@code Key} and the values are of type {@code Tag}.
*
* @return an unmodifiable map containing all entries.
*/
Map<Key, Tag> getTags();

/**
* Retrieves a set of all keys present in the data container.
*
* @return an unmodifiable set of keys contained in the data container
*/
Set<Key> getKeys();

/**
* Returns a set view of the entries contained in this data container.
*
* @return an unmodifiable set of all entries
*/
Set<Map.Entry<Key, Tag>> entrySet();

/**
* Checks if the specified key is present in the data container.
*
* @param key the key to check for presence
* @return {@code true} if the key is present, {@code false} otherwise
*/
boolean has(Key key);

/**
* Checks if the data container is empty.
*
* @return {@code true} if the container is empty, {@code false} otherwise
*/
boolean isEmpty();

/**
* Removes all entries from the data container, erasing all stored data.
*/
void clear();

/**
* Copies all entries from the current data container to the specified data container.
*
* @param dataContainer the target data container to which the entries are copied
*/
void copyTo(DataContainer dataContainer);

/**
* Copies all entries from the current data container to the specified data container.
*
* @param dataContainer the target data container to which the entries are copied
* @param replace whether the target data container will be cleared before copying the entries
*/
void copyTo(DataContainer dataContainer, boolean replace);

/**
* Performs the given action for each entry in the data container.
*
* @param action the action to be performed for each entry
*/
void forEach(BiConsumer<Key, Tag> action);
}
79 changes: 79 additions & 0 deletions plugin/src/main/java/net/thenextlvl/protect/area/CraftArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import net.kyori.adventure.key.Key;
import net.thenextlvl.protect.ProtectPlugin;
import net.thenextlvl.protect.area.event.flag.AreaFlagChangeEvent;
import net.thenextlvl.protect.area.event.flag.AreaFlagResetEvent;
Expand All @@ -25,6 +26,8 @@
import org.jspecify.annotations.Nullable;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

@Setter
@ToString
Expand All @@ -44,6 +47,8 @@ public abstract class CraftArea implements Area {
private final Map<Flag<?>, @Nullable Object> flags;
private @Getter int priority;

private final CompoundTag dataContainer = new CompoundTag();

protected CraftArea(ProtectPlugin plugin,
String name,
World world,
Expand Down Expand Up @@ -207,6 +212,7 @@ public CompoundTag serialize() {
}.getType()));
if (!members.isEmpty()) tag.add("members", plugin.nbt.toTag(members, new TypeToken<Set<UUID>>() {
}.getType()));
if (!dataContainer.isEmpty()) tag.add("data", dataContainer);
if (owner != null) tag.add("owner", plugin.nbt.toTag(owner));
tag.add("priority", priority);
var adapter = plugin.areaService().getAdapter(getClass());
Expand All @@ -221,6 +227,7 @@ public void deserialize(Tag tag) {
readMembers(compound).ifPresent(members::addAll);
readOwner(compound).ifPresent(owner -> this.owner = owner);
readPriority(compound).ifPresent(priority -> this.priority = priority);
compound.<CompoundTag>optional("data").ifPresent(dataContainer::addAll);
}

private Optional<Map<Flag<?>, Object>> readFlags(CompoundTag tag) {
Expand All @@ -245,4 +252,76 @@ private Optional<UUID> readOwner(CompoundTag tag) {
private Optional<Integer> readPriority(CompoundTag tag) {
return tag.optional("priority").map(Tag::getAsInt);
}

@Override
public <T extends Tag> Optional<T> get(Key key) {
return dataContainer.optional(key.asString());
}

@Override
@SuppressWarnings("unchecked")
public <T extends Tag> Optional<T> remove(Key key) {
return Optional.ofNullable((T) dataContainer.remove(key.asString()));
}

@Override
public <T extends Tag> T getOrDefault(Key key, T defaultValue) {
return dataContainer.getOrDefault(key.asString(), defaultValue);
}

@Override
public <T extends Tag> void set(Key key, T value) {
dataContainer.add(key.asString(), value);
}

@Override
@SuppressWarnings("PatternValidation")
public Map<Key, Tag> getTags() {
return dataContainer.entrySet().stream()
.map(entry -> Map.entry(Key.key(entry.getKey()), entry.getValue()))
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
}

@Override
public Set<Key> getKeys() {
return dataContainer.keySet().stream()
.map(Key::key)
.collect(Collectors.toUnmodifiableSet());
}

@Override
public Set<Map.Entry<Key, Tag>> entrySet() {
return getTags().entrySet();
}

@Override
public boolean has(Key key) {
return dataContainer.containsKey(key.asString());
}

@Override
public boolean isEmpty() {
return dataContainer.isEmpty();
}

@Override
public void clear() {
dataContainer.entrySet().clear();
}

@Override
public void copyTo(DataContainer dataContainer) {
copyTo(dataContainer, false);
}

@Override
public void copyTo(DataContainer dataContainer, boolean replace) {
if (replace) dataContainer.clear();
forEach(dataContainer::set);
}

@Override
public void forEach(BiConsumer<Key, Tag> action) {
entrySet().forEach(entry -> action.accept(entry.getKey(), entry.getValue()));
}
}

0 comments on commit e27f4a4

Please sign in to comment.