Skip to content

Commit

Permalink
Merge pull request #51 from PXAV/development
Browse files Browse the repository at this point in the history
Changes for v0.3.2 - The region update
  • Loading branch information
PXAV committed Mar 19, 2021
2 parents 68cce64 + 06e34de commit 697df31
Show file tree
Hide file tree
Showing 36 changed files with 3,764 additions and 34 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG/kelp-v0.3.2.md
@@ -0,0 +1,17 @@
# v0.3.2
> Release date: 19.03.2021
**The regions update**:
* Add basic region library to the kelp world library.
* Add supertype for regions `KelpRegion`
* Add region implementation `CuboidRegion` representing a cuboid area of blocks
* Add region implementation `EllipsoidRegion` representing ellipsoids including spheres and sphereoids
* Add new event type `KelpRegionEvent`
* Add `PlayerEnterRegionEvent` triggered when a player enters a region
* Add `PlayerLeaveRegionEvent` triggered when a player leaves a region
* Add new multimap type `ConcurrentMultimap` offering multimaps with thread-safety.
* `ConcurrentSetMultimap` using a set in the background
* `ConcurrentListMultimap` using a normal list in the background
* Add a custom implementation of bukkits block face: `KelpBlockFace`
* Add documentation to `KelpChunk`
* Add basic NPC and region tests to `testing-module`
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -125,13 +125,13 @@ There are version implementations for the following version implementations avai
<dependency>
<groupId>com.github.pxav.kelp</groupId>
<artifactId>core</artifactId>
<version>0.3.1</version>
<version>0.3.2</version>
</dependency>
```

### Gradle
```shell script
compile group: 'com.github.pxav.kelp', name: 'core', version: '0.3.1'
compile group: 'com.github.pxav.kelp', name: 'core', version: '0.3.2'
```

### Other build tools
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.github.pxav.kelp</groupId>
<artifactId>parent</artifactId>
<version>0.3.1</version>
<version>0.3.2</version>
</parent>

<modelVersion>4.0.0</modelVersion>
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/de/pxav/kelp/core/KelpPlugin.java
Expand Up @@ -35,7 +35,7 @@
*
* @author pxav
*/
@Plugin(name = "Kelp", version = "0.3.1")
@Plugin(name = "Kelp", version = "0.3.2")
@Author("pxav")
@Description("A cross version spigot framework.")
@Singleton
Expand Down
@@ -0,0 +1,222 @@
package de.pxav.kelp.core.common;

import com.google.common.collect.*;

import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ConcurrentListMultimap<K, V> implements ConcurrentMultimap<K, V> {

private final ConcurrentMap<K, ArrayList<V>> map;

public static <K, V> ConcurrentListMultimap<K, V> create() {
return new ConcurrentListMultimap<>();
}

public static <K, V> ConcurrentListMultimap<K, V> create(Multimap<K, V> source) {
ConcurrentListMultimap<K, V> multimap = new ConcurrentListMultimap<>();
multimap.putAll(source);
return multimap;
}

public static <K, V> ConcurrentListMultimap<K, V> create(Map<K, V> source) {
ConcurrentListMultimap<K, V> multimap = new ConcurrentListMultimap<>();
source.forEach(multimap::put);
multimap.putAll(source);
return multimap;
}

public ConcurrentListMultimap() {
this.map = new ConcurrentHashMap<>();
}

@Override
public int size() {
int size = 0;
for (Collection<V> value : this.map.values()) {
size += value.size();
}
return size;
}

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

@Override
public boolean containsKey(Object o) {
return this.map.containsKey(o);
}

@Override
public boolean containsValue(Object o) {
Iterator<Collection<V>> iterator = this.asMap().values().iterator();

Collection<V> collection;

do {
if (!iterator.hasNext()) {
return false;
}

collection = iterator.next();
} while(!collection.contains(o));

return true;
}

@Override
public boolean containsEntry(Object o, Object o1) {
Collection<V> collection = this.map.get(o);
return collection != null && collection.contains(o1);
}

@Override
public boolean put(K k, V v) {
if (this.get(k) == null) {
this.map.put(k, Lists.newArrayList());
}
return this.get(k).add(v);
}

@Override
public boolean remove(Object key, Object value) {
if (this.map.get(key) == null) {
return false;
}
return this.map.get(key).remove(value);
}

@Override
public boolean putAll(K k, Iterable<? extends V> iterable) {
if (iterable instanceof Collection) {
Collection<V> collection = (Collection<V>) iterable;
if (collection.isEmpty()) {
return false;
}

if (this.get(k) == null) {
this.map.put(k, Lists.newArrayList());
}
return this.get(k).addAll(collection);
} else {
Iterator<? extends V> valueItr = iterable.iterator();
if (!valueItr.hasNext()) {
return false;
}

if (this.get(k) == null) {
this.map.put(k, Lists.newArrayList());
}
return Iterators.addAll(this.get(k), valueItr);
}
}

@Override
public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
for (Map.Entry<? extends K, ? extends V> entry : multimap.entries()) {
this.put(entry.getKey(), entry.getValue());
}
return false;
}

@Override
public void putAll(Map<K, V> newMap) {
for (Map.Entry<K, V> entry : newMap.entrySet()) {
this.put(entry.getKey(), entry.getValue());
}
}

@Override
public Collection<V> replaceValues(K k, Iterable<? extends V> iterable) {
Collection<V> result = this.removeAll(k);
this.putAll(k, iterable);
return result;
}

@Override
public Collection<V> removeAll(Object key) {
if (this.map.get(key) == null) {
return Lists.newArrayList();
}
return this.map.remove(key);
}

@Override
public void clear() {
this.map.clear();
}

@Override
public Collection<V> get(@Nullable K k) {
return this.map.get(k);
}

@Override
public Set<K> keySet() {
return this.map.keySet();
}

@Override
public Multiset<K> keys() {
return HashMultiset.create(this.map.keySet());
}

@Override
public Collection<V> values() {
Iterator<Collection<V>> iterator = this.asMap().values().iterator();
Collection<V> result = Lists.newArrayList();

while (iterator.hasNext()) {
result.addAll(iterator.next());
}

return result;
}

@Override
public Collection<Map.Entry<K, V>> entries() {
Collection<Map.Entry<K, V>> entries = Lists.newArrayList();
this.map.forEach((key, valueSet) -> valueSet.forEach(element -> {
AbstractMap.SimpleEntry<K, V> entry = new AbstractMap.SimpleEntry<>(key, element);
entries.add(entry);
}));
return entries;
}


@Override
public ConcurrentMap<K, Collection<V>> asMap() {
ConcurrentMap<K, Collection<V>> output = Maps.newConcurrentMap();
output.putAll(this.map);
return output;
}

@Override
public boolean containsValue(Collection<V> iterable) {
return this.map.containsValue(iterable);
}

@Override
public Collection<V> getOrDefault(K key, Collection<V> defaultCollection) {
return this.map.getOrDefault(key, Lists.newArrayList(defaultCollection));
}

@Override
public Collection<V> getOrEmpty(K key) {
return this.map.getOrDefault(key, Lists.newArrayList());
}

@Override
public void removeWithValue(V value) {
this.map.forEach((key, valueSet) -> valueSet.forEach(current -> {
if (current.equals(value)) {
this.remove(key, current);
}
}));
}

}
@@ -0,0 +1,67 @@
package de.pxav.kelp.core.common;

import com.google.common.collect.Multimap;

import java.util.Collection;
import java.util.Map;

/**
* This is a custom implementation of Guava's normal {@link Multimap} with the
* only difference that this offers thread-safety and some performance optimizations
* in some operations, while other operations are slightly slower than with a normal
* {@code Multimap}.
*
* @param <K> The key type for each multimap entry
* @param <V> The value type for each multimap entry.
*/
public interface ConcurrentMultimap<K, V> extends Multimap<K, V> {

/**
* Checks whether a single key has all values
* contained by the given collection.
*
* @param iterable The collection to check.
* @return {@code true} of a single key had all of the values contained by the collection.
*/
boolean containsValue(Collection<V> iterable);

/**
* Gets the collection associated with the given
* key. If there is no entry for the given key,
* the given fallback collection will be returned.
*
* @param key The key to get the collection of.
* @param defaultCollection The fallback collection to return
* if there is no collection associated with the given key.
* @return The collection associated with the given key or the given fallback collection.
*/
Collection<V> getOrDefault(K key, Collection<V> defaultCollection);

/**
* Gets the collection associated with the given
* key. If there is no entry for the given key,
* an empty collection (depending on the implementation)
* will be returned.
*
* @param key The key to get the collection of.
* @return The collection associated with the given key or an empty collection.
*/
Collection<V> getOrEmpty(K key);

/**
* Removes all entries with the given value.
*
* @param value The value to remove all entries with.
*/
void removeWithValue(V value);

/**
* Takes a normal map and inserts its values
* into the multimap. If one of the contained keys
* already exists, it will simply be added to the collection.
*
* @param newMap The map to be added to the multimap.
*/
void putAll(Map<K, V> newMap);

}

0 comments on commit 697df31

Please sign in to comment.