From 1ca85f604840b5b366d75ae27f6d1f997584f4df Mon Sep 17 00:00:00 2001 From: LeeGodSRC Date: Fri, 12 Jul 2024 17:51:33 +0800 Subject: [PATCH 1/3] feat: Added MetaStorage to replace MetadataMap --- .../platforms/core-platform/build.gradle.kts | 1 + .../data/impl/MetaStorageImplBenchmark.java | 168 +++++++++++++++ .../java/io/fairyproject/data/MetaKey.java | 35 +++ .../io/fairyproject/data/MetaRegistry.java | 18 ++ .../io/fairyproject/data/MetaStorage.java | 46 ++++ .../fairyproject/data/impl/MetaKeyImpl.java | 33 +++ .../data/impl/MetaRegistryImpl.java | 39 ++++ .../data/impl/MetaStorageImpl.java | 202 ++++++++++++++++++ .../data/impl/MetaStorageImplTest.java | 113 ++++++++++ .../RepeatedExecutorScheduledTaskTest.java | 3 +- .../mc/meta/MCMetaRegistries.java | 17 ++ 11 files changed, 674 insertions(+), 1 deletion(-) create mode 100644 framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaStorageImpl.java create mode 100644 framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java create mode 100644 framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java diff --git a/framework/platforms/core-platform/build.gradle.kts b/framework/platforms/core-platform/build.gradle.kts index 301b9acb..6067804e 100644 --- a/framework/platforms/core-platform/build.gradle.kts +++ b/framework/platforms/core-platform/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("io.fairyproject.platform") + id("me.champeau.jmh") version "0.7.2" } dependencies { diff --git a/framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java b/framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java new file mode 100644 index 00000000..5bae2330 --- /dev/null +++ b/framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java @@ -0,0 +1,168 @@ +package io.fairyproject.data.impl; + +import io.fairyproject.data.MetaKey; +import io.fairyproject.metadata.MetadataKey; +import io.fairyproject.metadata.MetadataMap; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.concurrent.CountDownLatch; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + + +public class MetaStorageImplBenchmark { + + public static final int keys = 1000; + + @org.openjdk.jmh.annotations.State(Scope.Thread) + public static class State { + private MetaKey[] metaKeys; + private MetadataKey[] metadataKeys; + + @Setup(Level.Trial) + public void setup() { + MetaKey.ID_COUNTER.set(0); + + metaKeys = new MetaKey[keys]; + for (int i = 0; i < keys; i++) { + metaKeys[i] = new MetaKeyImpl<>("key" + i, Integer.class); + } + + metadataKeys = new MetadataKey[keys]; + for (int i = 0; i < keys; i++) { + metadataKeys[i] = MetadataKey.create("key" + i, Integer.class); + } + } + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 10, time = 500, timeUnit = MILLISECONDS) + @Measurement(iterations = 10, time = 200, timeUnit = MILLISECONDS) + public void metaStorage(State state) { + MetaStorageImpl metaStorage = new MetaStorageImpl(); + + for (int i = 0; i < state.metaKeys.length; i++) { + metaStorage.put(state.metaKeys[i], i); + metaStorage.getOrNull(state.metaKeys[i]); + } + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 10, time = 500, timeUnit = MILLISECONDS) + @Measurement(iterations = 10, time = 200, timeUnit = MILLISECONDS) + public void metadataMap(State state) { + MetadataMap metadataStorage = MetadataMap.create(); + + for (int i = 0; i < state.metadataKeys.length; i++) { + metadataStorage.put(state.metadataKeys[i], i); + metadataStorage.get(state.metadataKeys[i]); + } + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 10, time = 500, timeUnit = MILLISECONDS) + @Measurement(iterations = 10, time = 200, timeUnit = MILLISECONDS) + public void metaStorageConcurrent(State state) throws InterruptedException { + MetaStorageImpl metaStorage = new MetaStorageImpl(); + CountDownLatch countDownLatch = new CountDownLatch(10); + + for (int t = 0; t < 10; t++) { + new Thread() { + @Override + public void run() { + for (int i = 0; i < state.metaKeys.length; i++) { + metaStorage.put(state.metaKeys[i], i); + metaStorage.getOrNull(state.metaKeys[i]); + } + countDownLatch.countDown(); + } + }.start(); + } + + countDownLatch.await(); + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 10, time = 500, timeUnit = MILLISECONDS) + @Measurement(iterations = 10, time = 200, timeUnit = MILLISECONDS) + public void metadataMapConcurrent(State state) throws InterruptedException { + MetadataMap metadataStorage = MetadataMap.create(); + CountDownLatch countDownLatch = new CountDownLatch(10); + + for (int t = 0; t < 10; t++) { + new Thread() { + @Override + public void run() { + for (int i = 0; i < state.metadataKeys.length; i++) { + metadataStorage.put(state.metadataKeys[i], i); + metadataStorage.get(state.metadataKeys[i]); + } + countDownLatch.countDown(); + } + }.start(); + } + + countDownLatch.await(); + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 10, time = 500, timeUnit = MILLISECONDS) + @Measurement(iterations = 10, time = 200, timeUnit = MILLISECONDS) + public void concurrentHashMap(State state) throws InterruptedException { + java.util.concurrent.ConcurrentHashMap map = new java.util.concurrent.ConcurrentHashMap<>(); + + for (int i = 0; i < state.metaKeys.length; i++) { + map.put(state.metaKeys[i].getId(), i); + map.get(state.metaKeys[i].getId()); + } + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 10, time = 500, timeUnit = MILLISECONDS) + @Measurement(iterations = 10, time = 200, timeUnit = MILLISECONDS) + public void concurrentHashMap_concurrent(State state) throws InterruptedException { + java.util.concurrent.ConcurrentHashMap map = new java.util.concurrent.ConcurrentHashMap<>(); + CountDownLatch countDownLatch = new CountDownLatch(10); + + for (int t = 0; t < 10; t++) { + new Thread() { + @Override + public void run() { + for (int i = 0; i < state.metaKeys.length; i++) { + map.put(state.metaKeys[i].getId(), i); + map.get(state.metaKeys[i].getId()); + } + countDownLatch.countDown(); + } + }.start(); + } + + countDownLatch.await(); + } + + public static void main(Object[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(MetaStorageImplBenchmark.class.getSimpleName()) + .forks(1) + .build(); + + new Runner(opt).run(); + } + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java new file mode 100644 index 00000000..dc8871cc --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java @@ -0,0 +1,35 @@ +package io.fairyproject.data; + +import java.lang.ref.Reference; +import java.util.concurrent.atomic.AtomicInteger; + +public interface MetaKey { + + AtomicInteger ID_COUNTER = new AtomicInteger(0); + + int getId(); + + String getName(); + + Class getType(); + + default T cast(Object value) { + if (value == null) + return null; + + if (value instanceof Reference) { + Object obj = ((Reference) value).get(); + if (obj == null) + return null; + + return getType().cast(obj); + } + + return getType().cast(value); + } + + static int getCurrentCapacity() { + return ID_COUNTER.get() + 1; + } + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java new file mode 100644 index 00000000..1a642bc4 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java @@ -0,0 +1,18 @@ +package io.fairyproject.data; + +import java.io.Serializable; +import java.util.Map; + +public interface MetaRegistry { + + MetaStorage provide(K id); + + MetaStorage get(K id); + + void remove(K id); + + void destroy(); + + Map cache(); + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java new file mode 100644 index 00000000..368bfabb --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java @@ -0,0 +1,46 @@ +package io.fairyproject.data; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.Reference; +import java.util.function.Supplier; + +public interface MetaStorage { + + default boolean contains(@NotNull MetaKey key) { + return getOrNull(key) != null; + } + + @Nullable + T getOrNull(@NotNull MetaKey key); + + @NotNull + default T getOrDefault(@NotNull MetaKey key, @NotNull T def) { + T value = getOrNull(key); + return value != null ? value : def; + } + + @NotNull + default T getOrThrow(@NotNull MetaKey key) { + T value = getOrNull(key); + if (value == null) { + throw new NullPointerException("No value found for key: " + key.getName()); + } + return value; + } + + void put(@NotNull MetaKey key, @NotNull T value); + + void putRef(@NotNull MetaKey key, @NotNull Reference reference); + + T computeIfAbsent(@NotNull MetaKey key, @NotNull Supplier value); + + void computeIfAbsentRef(@NotNull MetaKey key, @NotNull Supplier> reference); + + boolean remove(@NotNull MetaKey key); + + void clear(); + + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java new file mode 100644 index 00000000..64206d33 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java @@ -0,0 +1,33 @@ +package io.fairyproject.data.impl; + +import io.fairyproject.data.MetaKey; +import lombok.Getter; + +import java.util.Objects; + +@Getter +public class MetaKeyImpl implements MetaKey { + + private final int id; + private final String name; + private final Class type; + + public MetaKeyImpl(String name, Class type) { + this.id = ID_COUNTER.getAndIncrement(); + this.name = name; + this.type = type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MetaKeyImpl metaKey = (MetaKeyImpl) o; + return id == metaKey.id; + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java new file mode 100644 index 00000000..28dfdb22 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java @@ -0,0 +1,39 @@ +package io.fairyproject.data.impl; + +import io.fairyproject.data.MetaRegistry; +import io.fairyproject.data.MetaStorage; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MetaRegistryImpl implements MetaRegistry { + + private final Map cache = new ConcurrentHashMap<>(); + + @Override + public MetaStorage provide(K id) { + return cache.computeIfAbsent(id, k -> new MetaStorageImpl()); + } + + @Override + public MetaStorage get(K id) { + return cache.get(id); + } + + @Override + public void remove(K id) { + cache.remove(id); + } + + @Override + public void destroy() { + cache.clear(); + } + + @Override + public Map cache() { + return Collections.unmodifiableMap(cache); + } +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaStorageImpl.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaStorageImpl.java new file mode 100644 index 00000000..9fc156cf --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaStorageImpl.java @@ -0,0 +1,202 @@ +package io.fairyproject.data.impl; + +import io.fairyproject.data.MetaKey; +import io.fairyproject.data.MetaStorage; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.Reference; +import java.util.concurrent.locks.StampedLock; +import java.util.function.Supplier; + +public class MetaStorageImpl implements MetaStorage { + + private static final int BUCKET_SIZE = 8; + + private final StampedLock[] buckets = new StampedLock[BUCKET_SIZE]; + private volatile Object[] data = new Object[MetaKey.getCurrentCapacity()]; + + public MetaStorageImpl() { + for (int i = 0; i < buckets.length; i++) { + buckets[i] = new StampedLock(); + } + } + + private long[] lockAll() { + long[] stamps = new long[buckets.length]; + for (int i = 0; i < buckets.length; i++) { + stamps[i] = buckets[i].writeLock(); + } + return stamps; + } + + private void unlockAll(long[] stamps) { + for (int i = 0; i < buckets.length; i++) { + buckets[i].unlockWrite(stamps[i]); + } + } + + protected StampedLock getBucket(int key) { + int hash = Integer.hashCode(key); + + return this.buckets[getBucketCheckMinValue(hash)]; + } + + private int getBucketCheckMinValue(int hash) { + return Math.abs(hash == Integer.MIN_VALUE ? 0 : hash) % BUCKET_SIZE; + } + + private void ensureCapacity(int id) { + if (id >= data.length) { + long[] stamps = this.lockAll(); + try { + // Check again in case another thread already resized the array + if (id >= data.length) { + int newSize = Math.max(data.length * 2, id + 1); + Object[] newData = new Object[newSize]; + System.arraycopy(data, 0, newData, 0, data.length); + data = newData; + } + } finally { + this.unlockAll(stamps); + } + } + } + + @Override + public @Nullable T getOrNull(@NotNull MetaKey key) { + StampedLock bucket = this.getBucket(key.getId()); + long stamp = bucket.tryOptimisticRead(); + Object retVal = getOrNullInternal(key); + + if (bucket.validate(stamp)) { + return key.cast(retVal); + } + + stamp = bucket.readLock(); + try { + return getOrNullInternal(key); + } finally { + bucket.unlockRead(stamp); + } + } + + private @Nullable T getOrNullInternal(@NotNull MetaKey key) { + if (key.getId() >= data.length) + return null; + + Object object = data[key.getId()]; + return key.cast(object); + } + + @Override + public void put(@NotNull MetaKey key, @NotNull T value) { + putInternal(key, value); + } + + @Override + public void putRef(@NotNull MetaKey key, @NotNull Reference reference) { + putInternal(key, reference); + } + + private void putInternal(@NotNull MetaKey key, @NotNull Object value) { + ensureCapacity(key.getId()); + + StampedLock bucket = this.getBucket(key.getId()); + long stamp = bucket.writeLock(); + try { + data[key.getId()] = value; + } finally { + bucket.unlockWrite(stamp); + } + } + + @Override + public T computeIfAbsent(@NotNull MetaKey key, @NotNull Supplier value) { + return key.cast(putIfAbsentInternal(key, value)); + } + + @Override + public void computeIfAbsentRef(@NotNull MetaKey key, @NotNull Supplier> reference) { + putIfAbsentInternal(key, reference); + } + + private Object putIfAbsentInternal(@NotNull MetaKey key, @NotNull Supplier value) { + ensureCapacity(key.getId()); + + StampedLock bucket = this.getBucket(key.getId()); + long stamp = bucket.tryOptimisticRead(); + boolean write = false; + try { + for (; ; stamp = bucket.writeLock(), write = true) { + if (stamp == 0L) + continue; + + Object object = data[key.getId()]; + if (!bucket.validate(stamp)) + continue; + + if (object != null) + return object; + + stamp = bucket.tryConvertToWriteLock(stamp); + if (stamp == 0L) + continue; + + write = true; + Object o = value.get(); + data[key.getId()] = o; + + return o; + } + } finally { + if (write) { + bucket.unlock(stamp); + } + } + } + + @Override + public boolean remove(@NotNull MetaKey key) { + StampedLock bucket = this.getBucket(key.getId()); + long stamp = bucket.tryOptimisticRead(); + boolean write = false; + try { + for (; ; stamp = bucket.writeLock(), write = true) { + if (stamp == 0L) + continue; + + boolean noRemoval = key.getId() >= data.length || data[key.getId()] == null; + + if (!bucket.validate(stamp)) + continue; + + if (noRemoval) + return false; + + stamp = bucket.tryConvertToWriteLock(stamp); + if (stamp == 0L) + continue; + + write = true; + data[key.getId()] = null; + return true; + } + } finally { + if (write) { + bucket.unlock(stamp); + } + } + } + + @Override + public void clear() { + long[] stamps = this.lockAll(); + try { + this.data = new Object[MetaKey.getCurrentCapacity()]; + } finally { + this.unlockAll(stamps); + } + } + +} diff --git a/framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java b/framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java new file mode 100644 index 00000000..908cca9a --- /dev/null +++ b/framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java @@ -0,0 +1,113 @@ +package io.fairyproject.data.impl; + +import io.fairyproject.data.MetaKey; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.lang.ref.WeakReference; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.*; + +class MetaStorageImplTest { + + private MetaStorageImpl metaStorage; + private MetaKey testKey; + + @BeforeEach + void setUp() { + testKey = new MetaKeyImpl<>("test", Integer.class); + metaStorage = new MetaStorageImpl(); + } + + @Test + void putAndGetOrNull() { + assertNull(metaStorage.getOrNull(testKey), "Storage should return null for non-existing key"); + + metaStorage.put(testKey, 123); + assertEquals(123, metaStorage.getOrNull(testKey), "Storage should return the value previously put in"); + } + + @Test + void computeIfAbsent() { + metaStorage.computeIfAbsent(testKey, () -> 123); + assertEquals(123, metaStorage.getOrNull(testKey), "Storage should contain the value put in if absent"); + + metaStorage.computeIfAbsent(testKey, () -> 456); + assertEquals(123, metaStorage.getOrNull(testKey), "Storage should not overwrite existing value with putIfAbsent"); + } + + @Test + void remove() { + assertFalse(metaStorage.remove(testKey), "Removing a non-existing key should return false"); + + metaStorage.put(testKey, 123); + assertTrue(metaStorage.remove(testKey), "Removing an existing key should return true"); + assertNull(metaStorage.getOrNull(testKey), "Storage should return null for removed key"); + } + + @Test + void clear() { + metaStorage.put(testKey, 123); + assertNotNull(metaStorage.getOrNull(testKey), "Storage should return the value previously put in"); + + metaStorage.clear(); + assertNull(metaStorage.getOrNull(testKey), "Storage should return null after clear"); + } + + @Test + void putAndRetrieveReference() { + WeakReference weakReference = new WeakReference<>(123); + metaStorage.putRef(testKey, weakReference); + assertSame(123, metaStorage.getOrNull(testKey), "Storage should return the reference previously put in"); + } + + @Test + void testConcurrentAccess() throws InterruptedException { + for (int k = 0; k < 10; k++) { + MetaStorageImpl metaStorage = new MetaStorageImpl(); + MetaKey testKey = new MetaKeyImpl<>("testKey", Integer.class); + int numberOfThreads = 1000; + ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads); + CountDownLatch startGate = new CountDownLatch(1); + CountDownLatch endGate = new CountDownLatch(numberOfThreads); + AtomicReference testFailed = new AtomicReference<>(null); + AtomicInteger inserted = new AtomicInteger(-1); + + for (int i = 0; i < numberOfThreads; i++) { + int finalI = i; + executorService.submit(() -> { + try { + startGate.await(); + int value = metaStorage.computeIfAbsent(testKey, () -> finalI); + + synchronized (inserted) { + if (inserted.get() == -1) { + inserted.set(value); + } else if (inserted.get() != value) { + testFailed.set("Inserted value does not match: " + inserted.get() + " != " + value); + } + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + endGate.countDown(); + } + }); + } + + startGate.countDown(); + endGate.await(); + executorService.shutdown(); + executorService.awaitTermination(1, TimeUnit.MINUTES); + + String failMessage = testFailed.get(); + assertNull(failMessage, failMessage); + } + } +} \ No newline at end of file diff --git a/framework/platforms/core-platform/src/test/java/io/fairyproject/scheduler/executor/RepeatedExecutorScheduledTaskTest.java b/framework/platforms/core-platform/src/test/java/io/fairyproject/scheduler/executor/RepeatedExecutorScheduledTaskTest.java index ae1580f5..0e255036 100644 --- a/framework/platforms/core-platform/src/test/java/io/fairyproject/scheduler/executor/RepeatedExecutorScheduledTaskTest.java +++ b/framework/platforms/core-platform/src/test/java/io/fairyproject/scheduler/executor/RepeatedExecutorScheduledTaskTest.java @@ -24,6 +24,7 @@ package io.fairyproject.scheduler.executor; +import io.fairyproject.scheduler.repeat.RepeatPredicate; import io.fairyproject.scheduler.response.TaskResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -46,7 +47,7 @@ class RepeatedExecutorScheduledTaskTest { void setUp() { scheduledFuture = Mockito.mock(ScheduledFuture.class); Callable> callable = () -> this.callable.call(); - repeatedExecutorScheduledTask = new RepeatedExecutorScheduledTask<>(callable); + repeatedExecutorScheduledTask = new RepeatedExecutorScheduledTask<>(callable, RepeatPredicate.empty()); repeatedExecutorScheduledTask.setScheduledFuture(scheduledFuture); } diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java new file mode 100644 index 00000000..1ece746e --- /dev/null +++ b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java @@ -0,0 +1,17 @@ +package io.fairyproject.mc.meta; + +import io.fairyproject.data.MetaRegistry; +import io.fairyproject.data.impl.MetaRegistryImpl; + +import java.util.UUID; + +public class MCMetaRegistries { + + private static final MetaRegistry PLAYERS = new MetaRegistryImpl<>(); + private static final MetaRegistry WORLDS = new MetaRegistryImpl<>(); + private static final MetaRegistry ENTITIES = new MetaRegistryImpl<>(); + private static final MetaRegistry BLOCKS = new MetaRegistryImpl<>(); + + + +} From 1bb80845f2d77bd3ed8fbf10a777f2c1b18d1cc0 Mon Sep 17 00:00:00 2001 From: LeeGodSRC Date: Sat, 13 Jul 2024 19:13:43 +0800 Subject: [PATCH 2/3] feat: Added MetaKey collections chore: Replace MetadataMap to MetaStorage usage in fairy itself --- .../command/map/DefaultBukkitCommandMap.java | 14 +- .../map/DefaultBukkitCommandMapTest.java | 11 +- .../java/io/fairyproject/bukkit/gui/Gui.java | 6 +- .../bukkit/util/items/FairyItem.java | 28 ++-- .../behaviour/ItemBehaviourBlockMarker.java | 19 +-- .../bukkit/util/items/impl/FairyItemImpl.java | 8 +- .../io/fairyproject/bukkit/menu/Menu.java | 14 +- .../visual/sender/VisualBlockSender.java | 13 +- .../io/fairyproject/command/BaseCommand.java | 3 +- .../command/BaseCommandInitializer.java | 4 +- .../bukkit/mc/BukkitMCEntity.java | 2 +- .../bukkit/mc/BukkitMCPlayer.java | 2 +- .../fairyproject/bukkit/mc/BukkitMCWorld.java | 1 - .../mc/registry/BukkitMCWorldRegistry.java | 10 +- .../bukkit/metadata/package-info.java | 2 + .../data/impl/MetaStorageImplBenchmark.java | 2 +- .../container/object/ContainerObj.java | 4 +- .../container/object/ContainerObjImpl.java | 9 +- .../SubscribeEventAnnotationProcessor.java | 7 +- .../java/io/fairyproject/data/MetaKey.java | 144 +++++++++++++++++- .../io/fairyproject/data/MetaRegistry.java | 32 +++- .../io/fairyproject/data/MetaStorage.java | 94 ++++++++++++ .../fairyproject/data/impl/MetaKeyImpl.java | 5 +- .../data/impl/MetaRegistryImpl.java | 2 +- .../impl/collection/MetaCollectionKey.java | 71 +++++++++ .../data/impl/collection/MetaListKey.java | 52 +++++++ .../data/impl/collection/MetaMapKey.java | 56 +++++++ .../data/impl/collection/MetaSetKey.java | 19 +++ .../metadata/CommonMetadataRegistries.java | 1 + .../fairyproject/metadata/package-info.java | 3 + .../io/fairyproject/util/TypeLiteral.java | 89 +++++++++++ .../data/impl/MetaStorageImplTest.java | 4 +- .../java/io/fairyproject/mc/MCPlayer.java | 9 +- .../main/java/io/fairyproject/mc/MCWorld.java | 7 + .../io/fairyproject/mc/data/MCMetadata.java | 86 +++++++++++ .../mc/meta/MCMetaRegistries.java | 17 --- .../mc/metadata/PlayerOnlineValue.java | 1 + .../fairyproject/tests/mc/MCPlayerMock.java | 2 +- 38 files changed, 741 insertions(+), 112 deletions(-) create mode 100644 framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/metadata/package-info.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaCollectionKey.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaListKey.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaMapKey.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaSetKey.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/package-info.java create mode 100644 framework/platforms/core-platform/src/main/java/io/fairyproject/util/TypeLiteral.java create mode 100644 framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java delete mode 100644 framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java diff --git a/framework/modules/bukkit/bukkit-command/src/main/java/io/fairyproject/bukkit/command/map/DefaultBukkitCommandMap.java b/framework/modules/bukkit/bukkit-command/src/main/java/io/fairyproject/bukkit/command/map/DefaultBukkitCommandMap.java index b321bb11..8d2c73ba 100644 --- a/framework/modules/bukkit/bukkit-command/src/main/java/io/fairyproject/bukkit/command/map/DefaultBukkitCommandMap.java +++ b/framework/modules/bukkit/bukkit-command/src/main/java/io/fairyproject/bukkit/command/map/DefaultBukkitCommandMap.java @@ -27,6 +27,8 @@ import io.fairyproject.bukkit.command.BukkitCommandExecutor; import io.fairyproject.bukkit.command.sync.SyncCommandHandler; import io.fairyproject.command.BaseCommand; +import io.fairyproject.data.MetaKey; +import io.fairyproject.data.MetaStorage; import io.fairyproject.metadata.MetadataKey; import io.fairyproject.metadata.MetadataMap; import lombok.RequiredArgsConstructor; @@ -38,7 +40,7 @@ @RequiredArgsConstructor public class DefaultBukkitCommandMap implements BukkitCommandMap { - public static final MetadataKey EXECUTOR_KEY = MetadataKey.create("fairy:command-executor", BukkitCommandExecutor.class); + public static final MetaKey EXECUTOR_KEY = MetaKey.create("fairy:command-executor", BukkitCommandExecutor.class); private final CommandMap commandMap; private final Map knownCommands; @@ -59,18 +61,18 @@ public void register(BaseCommand command) { } - command.getMetadata().put(EXECUTOR_KEY, commandExecutor); + command.getMetaStorage().put(EXECUTOR_KEY, commandExecutor); commandMap.register(fallbackPrefix, commandExecutor); syncCommandHandler.sync(); } @Override public void unregister(BaseCommand command) { - MetadataMap metadata = command.getMetadata(); + MetaStorage metaStorage = command.getMetaStorage(); if (!this.isRegistered(command)) throw new IllegalArgumentException("Command not registered"); - metadata.ifPresent(EXECUTOR_KEY, commandExecutor -> { + metaStorage.ifPresent(EXECUTOR_KEY, commandExecutor -> { String fallbackPrefix = commandExecutor.getFallbackPrefix(); unregisterKnownCommand(fallbackPrefix, commandExecutor.getName()); @@ -79,7 +81,7 @@ public void unregister(BaseCommand command) { } commandExecutor.unregister(commandMap); - metadata.remove(EXECUTOR_KEY); + metaStorage.remove(EXECUTOR_KEY); }); syncCommandHandler.sync(); @@ -91,7 +93,7 @@ private boolean isCommandNameRegistered(String name, String fallbackPrefix) { @Override public boolean isRegistered(BaseCommand command) { - return command.getMetadata().has(EXECUTOR_KEY); + return command.getMetaStorage().contains(EXECUTOR_KEY); } private void unregisterKnownCommand(String fallbackPrefix, String alias) { diff --git a/framework/modules/bukkit/bukkit-command/src/test/java/io/fairyproject/command/map/DefaultBukkitCommandMapTest.java b/framework/modules/bukkit/bukkit-command/src/test/java/io/fairyproject/command/map/DefaultBukkitCommandMapTest.java index a5d974c7..609c6b4d 100644 --- a/framework/modules/bukkit/bukkit-command/src/test/java/io/fairyproject/command/map/DefaultBukkitCommandMapTest.java +++ b/framework/modules/bukkit/bukkit-command/src/test/java/io/fairyproject/command/map/DefaultBukkitCommandMapTest.java @@ -31,6 +31,7 @@ import io.fairyproject.bukkit.plugin.impl.RootJavaPluginIdentifier; import io.fairyproject.bukkit.plugin.impl.SpecifyJavaPluginIdentifier; import io.fairyproject.command.BaseCommand; +import io.fairyproject.data.MetaStorage; import io.fairyproject.metadata.MetadataMap; import org.bukkit.command.Command; import org.bukkit.command.CommandMap; @@ -53,15 +54,15 @@ class DefaultBukkitCommandMapTest { private CommandMap commandMap; private Map knownCommands; private BaseCommand command; - private MetadataMap metadata; + private MetaStorage metadata; @BeforeEach void setUp() { commandMap = Mockito.mock(CommandMap.class); command = Mockito.mock(BaseCommand.class); - metadata = MetadataMap.create(); + metadata = MetaStorage.create(); Mockito.when(command.getCommandNames()).thenReturn(new String[]{"test", "test2"}); - Mockito.when(command.getMetadata()).thenReturn(metadata); + Mockito.when(command.getMetaStorage()).thenReturn(metadata); knownCommands = new HashMap<>(); Mockito.when(commandMap.register(Mockito.anyString(), Mockito.any())) @@ -118,7 +119,7 @@ void registerShouldAvoidDuplicateInstance() { void registerShouldAvoidDuplicateNames() { BaseCommand secondCommand = Mockito.mock(BaseCommand.class); Mockito.when(secondCommand.getCommandNames()).thenReturn(new String[]{"test3", "test2"}); - Mockito.when(secondCommand.getMetadata()).thenReturn(MetadataMap.create()); + Mockito.when(secondCommand.getMetaStorage()).thenReturn(MetaStorage.create()); defaultBukkitCommandMap.register(command); @@ -132,7 +133,7 @@ void unregister() { defaultBukkitCommandMap.unregister(command); assertTrue(knownCommands.isEmpty()); - assertFalse(metadata.has(DefaultBukkitCommandMap.EXECUTOR_KEY)); + assertFalse(metadata.contains(DefaultBukkitCommandMap.EXECUTOR_KEY)); assertFalse(executor.isRegistered()); Mockito.verify(syncCommandHandler, Mockito.times(2)).sync(); } diff --git a/framework/modules/bukkit/bukkit-gui/src/main/java/io/fairyproject/bukkit/gui/Gui.java b/framework/modules/bukkit/bukkit-gui/src/main/java/io/fairyproject/bukkit/gui/Gui.java index be4d1a56..b259e137 100644 --- a/framework/modules/bukkit/bukkit-gui/src/main/java/io/fairyproject/bukkit/gui/Gui.java +++ b/framework/modules/bukkit/bukkit-gui/src/main/java/io/fairyproject/bukkit/gui/Gui.java @@ -6,11 +6,11 @@ import io.fairyproject.bukkit.gui.slot.GuiSlot; import io.fairyproject.bukkit.events.BukkitEventFilter; import io.fairyproject.bukkit.events.BukkitEventNode; +import io.fairyproject.data.MetaStorage; import io.fairyproject.event.EventNode; import io.fairyproject.mc.MCAdventure; import io.fairyproject.mc.MCPlayer; import io.fairyproject.mc.scheduler.MCSchedulers; -import io.fairyproject.metadata.MetadataMap; import io.fairyproject.util.ConditionUtils; import lombok.Getter; import net.kyori.adventure.text.Component; @@ -39,7 +39,7 @@ public class Gui { @Getter private final int id; @Getter - private final MetadataMap metadataMap; + private final MetaStorage metaStorage; private final BukkitEventNode bukkitEventNode; private final Map> slotEventNodes; private final List> openCallbacks; @@ -63,7 +63,7 @@ public Gui(BukkitEventNode bukkitEventNode, Component title) { this.openCallbacks = new ArrayList<>(); this.drawCallbacks = new ArrayList<>(); this.closeCallbacks = new ArrayList<>(); - this.metadataMap = MetadataMap.create(); + this.metaStorage = MetaStorage.create(); this.slotEventNodes = new HashMap<>(); this.title = title; this.panes = new ArrayList<>(); diff --git a/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/FairyItem.java b/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/FairyItem.java index 7656a34c..ff04d7bb 100644 --- a/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/FairyItem.java +++ b/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/FairyItem.java @@ -3,10 +3,9 @@ import io.fairyproject.bukkit.util.items.behaviour.ItemBehaviour; import io.fairyproject.bukkit.util.items.impl.FairyItemImpl; import io.fairyproject.container.Autowired; +import io.fairyproject.data.MetaKey; +import io.fairyproject.data.MetaStorage; import io.fairyproject.mc.MCPlayer; -import io.fairyproject.metadata.MetadataKey; -import io.fairyproject.metadata.MetadataMap; -import io.fairyproject.metadata.TransientValue; import io.fairyproject.util.terminable.Terminable; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -27,7 +26,7 @@ static Builder builder(@NotNull String name) { @NotNull String getName(); - @NotNull MetadataMap getMetadataMap(); + @NotNull MetaStorage getMetaStorage(); @NotNull Iterable getBehaviours(); @@ -74,7 +73,7 @@ class Builder { private final String name; private Function itemProvider; - private final MetadataMap metadataMap = MetadataMap.create(); + private final MetaStorage metaStorage = MetaStorage.create(); private final List behaviours = new ArrayList<>(); private Builder(@NotNull String name) { @@ -99,24 +98,19 @@ public Builder item(@NotNull Function itemProvider) { return this; } - public Builder transformMeta(@NotNull Consumer consumer) { - consumer.accept(this.metadataMap); + public Builder transformMeta(@NotNull Consumer consumer) { + consumer.accept(this.metaStorage); return this; } - public Builder put(@NotNull MetadataKey metadataKey, @NotNull T value) { - this.metadataMap.put(metadataKey, value); - return this; - } - - public Builder put(@NotNull MetadataKey metadataKey, @NotNull TransientValue value) { - this.metadataMap.put(metadataKey, value); + public Builder put(@NotNull MetaKey metadataKey, @NotNull T value) { + this.metaStorage.put(metadataKey, value); return this; } @Deprecated public FairyItem build() { - FairyItem fairyItem = new FairyItemImpl(REGISTRY, this.name, this.metadataMap, this.behaviours, this.itemProvider); + FairyItem fairyItem = new FairyItemImpl(REGISTRY, this.name, this.metaStorage, this.behaviours, this.itemProvider); REGISTRY.register(fairyItem); return fairyItem; @@ -124,11 +118,11 @@ public FairyItem build() { @Deprecated public FairyItem create() { - return new FairyItemImpl(REGISTRY, this.name, this.metadataMap, this.behaviours, this.itemProvider); + return new FairyItemImpl(REGISTRY, this.name, this.metaStorage, this.behaviours, this.itemProvider); } public FairyItem create(FairyItemRegistry itemRegistry) { - FairyItem fairyItem = new FairyItemImpl(itemRegistry, this.name, this.metadataMap, this.behaviours, this.itemProvider); + FairyItem fairyItem = new FairyItemImpl(itemRegistry, this.name, this.metaStorage, this.behaviours, this.itemProvider); itemRegistry.register(fairyItem); return fairyItem; diff --git a/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/behaviour/ItemBehaviourBlockMarker.java b/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/behaviour/ItemBehaviourBlockMarker.java index cf693d2d..bf16fa74 100644 --- a/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/behaviour/ItemBehaviourBlockMarker.java +++ b/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/behaviour/ItemBehaviourBlockMarker.java @@ -26,15 +26,12 @@ import com.cryptomorin.xseries.XSound; import io.fairyproject.bukkit.listener.ListenerRegistry; -import io.fairyproject.bukkit.metadata.Metadata; import io.fairyproject.bukkit.util.items.FairyItem; -import io.fairyproject.bukkit.util.items.FairyItemRef; import io.fairyproject.bukkit.util.items.FairyItemRegistry; -import io.fairyproject.container.Autowired; -import io.fairyproject.mc.MCPlayer; +import io.fairyproject.data.MetaKey; +import io.fairyproject.data.MetaStorage; +import io.fairyproject.mc.data.MCMetadata; import io.fairyproject.mc.registry.player.MCPlayerRegistry; -import io.fairyproject.metadata.MetadataKey; -import io.fairyproject.metadata.MetadataMap; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -46,7 +43,7 @@ public class ItemBehaviourBlockMarker extends ItemBehaviourListener { - private static final MetadataKey METADATA = MetadataKey.createStringKey("fairy:block-marker"); + private static final MetaKey METADATA = MetaKey.create("fairy:block-marker", String.class); private final FairyItemRegistry fairyItemRegistry; private final MCPlayerRegistry mcPlayerRegistry; @@ -74,7 +71,7 @@ public void onBlockPlace(BlockPlaceEvent event) { if (item != this.item) return; - Metadata.provideForBlock(block).put(METADATA, this.item.getName()); + MCMetadata.provide(block).put(METADATA, this.item.getName()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -82,13 +79,13 @@ public void onBlockBreak(BlockBreakEvent event) { Player player = event.getPlayer(); final Block block = event.getBlock(); - final MetadataMap metadataMap = Metadata.provideForBlock(block); - final String itemKey = metadataMap.getOrNull(METADATA); + final MetaStorage metaStorage = MCMetadata.provide(block); + final String itemKey = metaStorage.getOrNull(METADATA); if (itemKey == null || !itemKey.equals(this.item.getName())) { return; } - metadataMap.remove(METADATA); + metaStorage.remove(METADATA); final FairyItem item = this.fairyItemRegistry.get(itemKey); if (item == null) return; diff --git a/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/impl/FairyItemImpl.java b/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/impl/FairyItemImpl.java index 5977863a..e69fe67e 100644 --- a/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/impl/FairyItemImpl.java +++ b/framework/modules/bukkit/bukkit-items/src/main/java/io/fairyproject/bukkit/util/items/impl/FairyItemImpl.java @@ -4,8 +4,8 @@ import io.fairyproject.bukkit.util.items.FairyItemRegistry; import io.fairyproject.bukkit.util.items.ItemBuilder; import io.fairyproject.bukkit.util.items.behaviour.ItemBehaviour; +import io.fairyproject.data.MetaStorage; import io.fairyproject.mc.MCPlayer; -import io.fairyproject.metadata.MetadataMap; import lombok.Getter; import lombok.NonNull; import org.bukkit.inventory.ItemStack; @@ -20,7 +20,7 @@ public class FairyItemImpl implements FairyItem { private final FairyItemRegistry itemRegistry; private final String name; - private final MetadataMap metadataMap; + private final MetaStorage metaStorage; private final List behaviours; private final Function itemProvider; @@ -29,12 +29,12 @@ public class FairyItemImpl implements FairyItem { public FairyItemImpl( @NonNull FairyItemRegistry itemRegistry, @NonNull String name, - @NonNull MetadataMap metadataMap, + @NonNull MetaStorage metaStorage, @NonNull List behaviours, @NonNull Function itemProvider) { this.itemRegistry = itemRegistry; this.name = name; - this.metadataMap = metadataMap; + this.metaStorage = metaStorage; this.behaviours = behaviours; this.itemProvider = itemProvider; this.closed = true; diff --git a/framework/modules/bukkit/bukkit-menu/src/main/java/io/fairyproject/bukkit/menu/Menu.java b/framework/modules/bukkit/bukkit-menu/src/main/java/io/fairyproject/bukkit/menu/Menu.java index 5c4c623e..b6de0230 100644 --- a/framework/modules/bukkit/bukkit-menu/src/main/java/io/fairyproject/bukkit/menu/Menu.java +++ b/framework/modules/bukkit/bukkit-menu/src/main/java/io/fairyproject/bukkit/menu/Menu.java @@ -32,12 +32,12 @@ import io.fairyproject.bukkit.events.BukkitEventNode; import io.fairyproject.bukkit.menu.event.ButtonClickEvent; import io.fairyproject.bukkit.menu.event.MenuCloseEvent; -import io.fairyproject.bukkit.metadata.Metadata; import io.fairyproject.container.Autowired; +import io.fairyproject.data.MetaKey; +import io.fairyproject.data.MetaStorage; import io.fairyproject.event.EventNode; +import io.fairyproject.mc.data.MCMetadata; import io.fairyproject.mc.scheduler.MCSchedulers; -import io.fairyproject.metadata.MetadataKey; -import io.fairyproject.metadata.MetadataMap; import io.fairyproject.util.CC; import io.fairyproject.util.terminable.Terminable; import io.fairyproject.util.terminable.TerminableConsumer; @@ -66,7 +66,7 @@ @Setter public abstract class Menu implements TerminableConsumer { - private static final MetadataKey METADATA = MetadataKey.create("fairy:menu", Menu.class); + private static final MetaKey METADATA = MetaKey.create("fairy:menu", Menu.class); private static final Map, List> MENU_BY_TYPE = new ConcurrentHashMap<>(); @Deprecated @@ -323,7 +323,7 @@ public final void open(Player player) { this.openMillis = System.currentTimeMillis(); this.player = player; - Metadata.provide(player).put(METADATA, this); + MCMetadata.provide(player).put(METADATA, this); Menu.addMenu(this); this.render(true); @@ -345,7 +345,7 @@ public void remove() { } this.opening = false; - MetadataMap metadataMap = Metadata.provideForPlayer(this.player); + MetaStorage metadataMap = MCMetadata.provide(this.player); Menu existing = metadataMap.getOrNull(METADATA); if (existing == this) { metadataMap.remove(METADATA); @@ -535,7 +535,7 @@ private static void removeMenu(Menu menu) { } public static Menu getMenuByUuid(UUID uuid) { - return Metadata.provideForPlayer(uuid).getOrNull(METADATA); + return MCMetadata.provide(uuid).getOrNull(METADATA); } public static List getMenusByType(Class type) { diff --git a/framework/modules/bukkit/bukkit-visual/src/main/java/io/fairyproject/bukkit/visual/sender/VisualBlockSender.java b/framework/modules/bukkit/bukkit-visual/src/main/java/io/fairyproject/bukkit/visual/sender/VisualBlockSender.java index 6c3ed0ad..1d79f364 100644 --- a/framework/modules/bukkit/bukkit-visual/src/main/java/io/fairyproject/bukkit/visual/sender/VisualBlockSender.java +++ b/framework/modules/bukkit/bukkit-visual/src/main/java/io/fairyproject/bukkit/visual/sender/VisualBlockSender.java @@ -29,16 +29,16 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerMultiBlockChange; import com.google.common.collect.HashMultimap; import io.fairyproject.Fairy; -import io.fairyproject.bukkit.metadata.Metadata; import io.fairyproject.bukkit.nms.BukkitNMSManager; import io.fairyproject.bukkit.visual.sender.impl.BukkitVisualData; import io.fairyproject.bukkit.visual.sender.impl.NewVisualData; import io.fairyproject.bukkit.visual.sender.impl.OldVisualData; import io.fairyproject.bukkit.visual.util.BlockPositionData; +import io.fairyproject.data.MetaKey; import io.fairyproject.mc.MCPlayer; +import io.fairyproject.mc.data.MCMetadata; import io.fairyproject.mc.protocol.MCProtocol; import io.fairyproject.mc.util.BlockPosition; -import io.fairyproject.metadata.MetadataKey; import org.bukkit.Material; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -47,7 +47,7 @@ public class VisualBlockSender { - public final MetadataKey fakeBlocksMetadataKey = MetadataKey.create(Fairy.METADATA_PREFIX + "FakeBlockMap", VisualContainer.class); + public final MetaKey fakeBlocksMetadataKey = MetaKey.create(Fairy.METADATA_PREFIX + "FakeBlockMap", VisualContainer.class); private final List visualDataList; public VisualBlockSender(BukkitNMSManager nmsManager) { @@ -59,7 +59,7 @@ public VisualBlockSender(BukkitNMSManager nmsManager) { } public void send(Player player, Map blockMap, List replace, boolean send) { - VisualContainer visualContainer = Metadata.provideForPlayer(player).getOrPut(fakeBlocksMetadataKey, VisualContainer::new); + VisualContainer visualContainer = MCMetadata.provide(player).computeIfAbsent(fakeBlocksMetadataKey, VisualContainer::new); HashMultimap map = HashMultimap.create(); for (final Map.Entry entry : blockMap.entrySet()) { @@ -121,8 +121,9 @@ public void send(Player player, Map blockMap, List(visualContainer.keySet()), true); diff --git a/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommand.java b/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommand.java index 45f70299..bd253993 100644 --- a/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommand.java +++ b/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommand.java @@ -30,6 +30,7 @@ import io.fairyproject.command.exception.ArgTransformException; import io.fairyproject.command.util.CoreCommandUtil; import io.fairyproject.container.Autowired; +import io.fairyproject.data.MetaStorage; import io.fairyproject.metadata.MetadataMap; import io.fairyproject.util.entry.Entry; import lombok.Getter; @@ -53,7 +54,7 @@ public abstract class BaseCommand implements ICommand { protected Map tabCompletion; @Getter - protected MetadataMap metadata; + protected MetaStorage metaStorage; protected PresenceProvider presenceProvider; @Nullable diff --git a/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommandInitializer.java b/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommandInitializer.java index f8218675..ff409513 100644 --- a/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommandInitializer.java +++ b/framework/modules/core/core-command/src/main/java/io/fairyproject/command/BaseCommandInitializer.java @@ -6,8 +6,8 @@ import io.fairyproject.command.completion.ArgCompletionHolderList; import io.fairyproject.command.completion.ArgCompletionHolderStringArray; import io.fairyproject.container.Autowired; +import io.fairyproject.data.MetaStorage; import io.fairyproject.log.Log; -import io.fairyproject.metadata.MetadataMap; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.Nullable; @@ -30,7 +30,7 @@ public class BaseCommandInitializer { public void init(String[] names, String permission) { baseCommand.names = names; baseCommand.permission = permission; - baseCommand.metadata = MetadataMap.create(); + baseCommand.metaStorage = MetaStorage.create(); baseCommand.tabCompletion = new HashMap<>(); Order order = baseCommand.getAnnotation(Order.class); diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCEntity.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCEntity.java index b54497e2..d5c0939e 100644 --- a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCEntity.java +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCEntity.java @@ -82,7 +82,7 @@ public Position getPosition() { } @Override - public T as(Class playerClass) { + public T as(@NotNull Class playerClass) { if (!playerClass.isInstance(this.entity)) { throw new ClassCastException(); } diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCPlayer.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCPlayer.java index a32c8c51..0bfe9868 100644 --- a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCPlayer.java +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCPlayer.java @@ -130,7 +130,7 @@ public Channel getChannel() { } @Override - public T as(Class playerClass) { + public T as(@NotNull Class playerClass) { if (!playerClass.isInstance(this.player)) { throw new ClassCastException(); } diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCWorld.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCWorld.java index bf5372e1..f2504d98 100644 --- a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCWorld.java +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCWorld.java @@ -1,6 +1,5 @@ package io.fairyproject.bukkit.mc; -import io.fairyproject.bukkit.FairyBukkitPlatform; import io.fairyproject.bukkit.metadata.Metadata; import io.fairyproject.event.EventNode; import io.fairyproject.event.GlobalEventNode; diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/registry/BukkitMCWorldRegistry.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/registry/BukkitMCWorldRegistry.java index d4b99f4c..530520c8 100644 --- a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/registry/BukkitMCWorldRegistry.java +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/registry/BukkitMCWorldRegistry.java @@ -25,10 +25,10 @@ package io.fairyproject.bukkit.mc.registry; import io.fairyproject.bukkit.mc.BukkitMCWorld; -import io.fairyproject.bukkit.metadata.Metadata; +import io.fairyproject.data.MetaKey; import io.fairyproject.mc.MCWorld; +import io.fairyproject.mc.data.MCMetadata; import io.fairyproject.mc.registry.MCWorldRegistry; -import io.fairyproject.metadata.MetadataKey; import lombok.RequiredArgsConstructor; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.Bukkit; @@ -40,7 +40,7 @@ @RequiredArgsConstructor public class BukkitMCWorldRegistry implements MCWorldRegistry { - private final MetadataKey KEY = MetadataKey.create("fairy:mc-world", MCWorld.class); + private final MetaKey KEY = MetaKey.create("fairy:mc-world", MCWorld.class); private final BukkitAudiences bukkitAudiences; @Override @@ -49,7 +49,9 @@ public MCWorld convert(Object worldObj) { throw new UnsupportedOperationException(); } World world = (World) worldObj; - return Metadata.provideForWorld(world).getOrPut(KEY, () -> new BukkitMCWorld(world, bukkitAudiences)); + return MCMetadata + .provide(world) + .computeIfAbsent(KEY, () -> new BukkitMCWorld(world, bukkitAudiences)); } @Override diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/metadata/package-info.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/metadata/package-info.java new file mode 100644 index 00000000..a186e5ac --- /dev/null +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/metadata/package-info.java @@ -0,0 +1,2 @@ +@Deprecated +package io.fairyproject.bukkit.metadata; \ No newline at end of file diff --git a/framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java b/framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java index 5bae2330..dd4cbffa 100644 --- a/framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java +++ b/framework/platforms/core-platform/src/jmh/java/io/fairyproject/data/impl/MetaStorageImplBenchmark.java @@ -29,7 +29,7 @@ public void setup() { metaKeys = new MetaKey[keys]; for (int i = 0; i < keys; i++) { - metaKeys[i] = new MetaKeyImpl<>("key" + i, Integer.class); + metaKeys[i] = MetaKey.create("key" + i, Integer.class); } metadataKeys = new MetadataKey[keys]; diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObj.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObj.java index 4fa9ae26..94fda403 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObj.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObj.java @@ -3,7 +3,7 @@ import io.fairyproject.container.Threading; import io.fairyproject.container.object.provider.InstanceProvider; import io.fairyproject.container.scope.InjectableScope; -import io.fairyproject.metadata.MetadataMap; +import io.fairyproject.data.MetaStorage; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -33,7 +33,7 @@ static ContainerObj create(Class objClass) { void addDependency(@NotNull Class dependClass); - @NotNull MetadataMap getMetadata(); + @NotNull MetaStorage getMetadata(); default boolean isSingletonScope() { return this.getScope() == InjectableScope.SINGLETON; diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObjImpl.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObjImpl.java index d3236a77..f07ff5d8 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObjImpl.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/container/object/ContainerObjImpl.java @@ -3,6 +3,7 @@ import io.fairyproject.container.Threading; import io.fairyproject.container.object.provider.InstanceProvider; import io.fairyproject.container.scope.InjectableScope; +import io.fairyproject.data.MetaStorage; import io.fairyproject.metadata.MetadataMap; import io.fairyproject.util.AsyncUtils; import org.jetbrains.annotations.NotNull; @@ -13,7 +14,7 @@ public class ContainerObjImpl implements ContainerObj { private final Class type; - private final MetadataMap metadataMap; + private final MetaStorage metaStorage; private final Set> dependencies; private Threading.Mode threadingMode; private InjectableScope scope; @@ -21,7 +22,7 @@ public class ContainerObjImpl implements ContainerObj { public ContainerObjImpl(Class type) { this.type = type; - this.metadataMap = MetadataMap.create(); + this.metaStorage = MetaStorage.create(); this.dependencies = new HashSet<>(); this.threadingMode = Threading.Mode.SYNC; this.scope = InjectableScope.SINGLETON; @@ -77,8 +78,8 @@ public void addDependency(@NotNull Class dependClass) { } @Override - public @NotNull MetadataMap getMetadata() { - return this.metadataMap; + public @NotNull MetaStorage getMetadata() { + return this.metaStorage; } @Override diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/container/processor/injection/SubscribeEventAnnotationProcessor.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/container/processor/injection/SubscribeEventAnnotationProcessor.java index 1b65055e..d0b7baf2 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/container/processor/injection/SubscribeEventAnnotationProcessor.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/container/processor/injection/SubscribeEventAnnotationProcessor.java @@ -27,19 +27,19 @@ import io.fairyproject.container.object.ContainerObj; import io.fairyproject.container.processor.ContainerObjDestroyProcessor; import io.fairyproject.container.processor.ContainerObjInitProcessor; +import io.fairyproject.data.MetaKey; import io.fairyproject.event.Event; import io.fairyproject.event.EventNode; import io.fairyproject.event.EventSubscribeRegistry; import io.fairyproject.event.GlobalEventNode; -import io.fairyproject.metadata.MetadataKey; import io.fairyproject.util.AsyncUtils; import java.util.concurrent.CompletableFuture; public class SubscribeEventAnnotationProcessor implements ContainerObjInitProcessor, ContainerObjDestroyProcessor { - private static final MetadataKey KEY = MetadataKey.create("fairy:event-node", EventNode.class); - + @SuppressWarnings("rawtypes") + private static final MetaKey KEY = MetaKey.create("fairy:event-node", EventNode.class); @Override public CompletableFuture processPostInitialization(ContainerObj object, Object instance) { @@ -56,6 +56,7 @@ public CompletableFuture processPostInitialization(ContainerObj object, Objec } @Override + @SuppressWarnings("unchecked") public void processPreDestroy(ContainerObj object, Object instance) { object.getMetadata().ifPresent(KEY, eventNode -> GlobalEventNode.get().removeChild(eventNode)); } diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java index dc8871cc..cec911ac 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaKey.java @@ -1,18 +1,57 @@ package io.fairyproject.data; +import io.fairyproject.data.impl.MetaKeyImpl; +import io.fairyproject.data.impl.collection.MetaListKey; +import io.fairyproject.data.impl.collection.MetaMapKey; +import io.fairyproject.data.impl.collection.MetaSetKey; +import io.fairyproject.util.TypeLiteral; +import org.jetbrains.annotations.ApiStatus; + import java.lang.ref.Reference; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +/** + * A key for metadata + * + * @param the type of the key + */ public interface MetaKey { + @ApiStatus.Internal AtomicInteger ID_COUNTER = new AtomicInteger(0); + /** + * Get the unique identifier of this key + * + * @return the unique identifier + */ int getId(); + /** + * Get the name of this key + * + * @return the name + */ String getName(); - Class getType(); + /** + * Get the type of this key + * + * @return the type + */ + TypeLiteral getType(); + /** + * Cast the value to the type of this key + * This method will return null if the value is null + * This method will return null if the value is a reference and the reference is null + * + * @param value the value to cast + * @return the casted value + */ default T cast(Object value) { if (value == null) return null; @@ -22,14 +61,113 @@ default T cast(Object value) { if (obj == null) return null; - return getType().cast(obj); + return getType().getType().cast(obj); } - return getType().cast(value); + return getType().getType().cast(value); } + /** + * Get the current capacity of the keys + * + * @return the current capacity + */ static int getCurrentCapacity() { return ID_COUNTER.get() + 1; } + /** + * Create a new meta key + * + * @param name the name of the key + * @param type the type of the key + * @param the type of the key + * @return the new meta key + */ + static MetaKey create(String name, Class type) { + return new MetaKeyImpl<>(name, new TypeLiteral<>(type)); + } + + /** + * Create a new meta key + * + * @param name the name of the key + * @param type the type of the key + * @param the type of the key + * @return the new meta key + */ + static MetaKey create(String name, TypeLiteral type) { + return new MetaKeyImpl<>(name, type); + } + + /** + * Create a list key + * + * @param name the name of the key + * @param type the type of values in the list of the key + */ + @SuppressWarnings("unused") + static MetaListKey createList(String name, Class type) { + return new MetaListKey<>(name, new TypeLiteral>() { + }); + } + + /** + * Create a list key + * + * @param name the name of the key + * @param type the type of values in the list of the key + */ + @SuppressWarnings("unused") + static MetaListKey createList(String name, TypeLiteral> type) { + return new MetaListKey<>(name, type); + } + + /** + * Create a set key + * + * @param name the name of the key + * @param type the type of values in the set of the key + */ + @SuppressWarnings("unused") + static MetaSetKey createSet(String name, Class type) { + return new MetaSetKey<>(name, new TypeLiteral>() { + }); + } + + /** + * Create a set key + * + * @param name the name of the key + * @param type the type of values in the set of the key + */ + @SuppressWarnings("unused") + static MetaSetKey createSet(String name, TypeLiteral> type) { + return new MetaSetKey<>(name, type); + } + + /** + * Create a map key + * + * @param name the name of the key + * @param keyType the type of keys in the map of the key + * @param valueType the type of values in the map of the key + */ + @SuppressWarnings("unused") + static MetaMapKey createMap(String name, Class keyType, Class valueType) { + return new MetaMapKey<>(name, new TypeLiteral>() { + }); + } + + /** + * Create a map key + * + * @param name the name of the key + * @param mapType the type of the map of the key + */ + @SuppressWarnings("unused") + static MetaMapKey createMap(String name, TypeLiteral> mapType) { + return new MetaMapKey<>(name, mapType); + } + } diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java index 1a642bc4..629561eb 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaRegistry.java @@ -3,16 +3,46 @@ import java.io.Serializable; import java.util.Map; +/** + * A registry for MetaStorage + * + * @param the type of the id + */ public interface MetaRegistry { + /** + * Provide a MetaStorage for the given id + * + * @param id the id + * @return the MetaStorage + */ MetaStorage provide(K id); + /** + * Get the MetaStorage for the given id + * + * @param id the id + * @return the MetaStorage + */ MetaStorage get(K id); + /** + * Remove the MetaStorage for the given id + * + * @param id the id + */ void remove(K id); - void destroy(); + /** + * Clear the registry + */ + void clear(); + /** + * Get the cache of the registry + * + * @return the cache + */ Map cache(); } diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java index 368bfabb..a12cab2b 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/MetaStorage.java @@ -1,26 +1,59 @@ package io.fairyproject.data; +import io.fairyproject.data.impl.MetaStorageImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.ref.Reference; +import java.util.function.Consumer; import java.util.function.Supplier; +/** + * A storage for metadata + */ public interface MetaStorage { + /** + * Check if the storage contains a value for the given key + * + * @param key the key + * @return true if the storage contains a value for the key, false otherwise + */ default boolean contains(@NotNull MetaKey key) { return getOrNull(key) != null; } + /** + * Get the value for the given key + * + * @param key the key + * @return the value or null if no value is found + * @param the type of the value + */ @Nullable T getOrNull(@NotNull MetaKey key); + /** + * Get the value for the given key or the default value if no value is found + * + * @param key the key + * @param def the default value + * @return the value or the default value if no value is found + * @param the type of the value + */ @NotNull default T getOrDefault(@NotNull MetaKey key, @NotNull T def) { T value = getOrNull(key); return value != null ? value : def; } + /** + * Get the value for the given key or throw a NullPointerException if no value is found + * + * @param key the key + * @return the value + * @param the type of the value + */ @NotNull default T getOrThrow(@NotNull MetaKey key) { T value = getOrNull(key); @@ -30,17 +63,78 @@ default T getOrThrow(@NotNull MetaKey key) { return value; } + /** + * Put the value for the given key + * + * @param key the key + * @param value the value + * @param the type of the value + */ void put(@NotNull MetaKey key, @NotNull T value); + /** + * Put the reference for the given key + * + * @param key the key + * @param reference the reference + * @param the type of the value + */ void putRef(@NotNull MetaKey key, @NotNull Reference reference); + /** + * Compute the value for the given key if no value is found + * + * @param key the key + * @param value the value supplier + * @return the value from supplier or the value found + * @param the type of the value + */ T computeIfAbsent(@NotNull MetaKey key, @NotNull Supplier value); + /** + * Compute the reference for the given key if no value is found + * + * @param key the key + * @param reference the reference supplier + * @param the type of the value + */ void computeIfAbsentRef(@NotNull MetaKey key, @NotNull Supplier> reference); + /** + * If the value for the given key is present, apply the consumer + * + * @param key the key + * @param consumer the consumer + * @param the type of the value + */ + default void ifPresent(@NotNull MetaKey key, @NotNull Consumer consumer) { + T value = getOrNull(key); + if (value != null) { + consumer.accept(value); + } + } + + /** + * Remove the value for the given key + * + * @param key the key + * @return true if the value was removed, false otherwise + * @param the type of the value + */ boolean remove(@NotNull MetaKey key); + /** + * Clear the storage + */ void clear(); + /** + * Create a new MetaStorage + * + * @return the new MetaStorage + */ + static MetaStorage create() { + return new MetaStorageImpl(); + } } diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java index 64206d33..0b221a33 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaKeyImpl.java @@ -1,6 +1,7 @@ package io.fairyproject.data.impl; import io.fairyproject.data.MetaKey; +import io.fairyproject.util.TypeLiteral; import lombok.Getter; import java.util.Objects; @@ -10,9 +11,9 @@ public class MetaKeyImpl implements MetaKey { private final int id; private final String name; - private final Class type; + private final TypeLiteral type; - public MetaKeyImpl(String name, Class type) { + public MetaKeyImpl(String name, TypeLiteral type) { this.id = ID_COUNTER.getAndIncrement(); this.name = name; this.type = type; diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java index 28dfdb22..33dea35e 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/MetaRegistryImpl.java @@ -28,7 +28,7 @@ public void remove(K id) { } @Override - public void destroy() { + public void clear() { cache.clear(); } diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaCollectionKey.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaCollectionKey.java new file mode 100644 index 00000000..31d38213 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaCollectionKey.java @@ -0,0 +1,71 @@ +package io.fairyproject.data.impl.collection; + +import io.fairyproject.data.MetaStorage; +import io.fairyproject.data.impl.MetaKeyImpl; +import io.fairyproject.util.TypeLiteral; + +import java.util.Collection; + +public abstract class MetaCollectionKey> extends MetaKeyImpl { + + public MetaCollectionKey(String name, TypeLiteral type) { + super(name, type); + + } + + public abstract C createCollection(); + + public C getCollection(MetaStorage storage) { + return this.cast(storage.computeIfAbsent(this, this::createCollection)); + } + + public boolean add(MetaStorage storage, K value) { + return getCollection(storage).add(value); + } + + public boolean remove(MetaStorage storage, K value) { + return getCollection(storage).remove(value); + } + + public boolean contains(MetaStorage storage, K value) { + return getCollection(storage).contains(value); + } + + public void clear(MetaStorage storage) { + storage.remove(this); + } + + public int size(MetaStorage storage) { + return getCollection(storage).size(); + } + + public boolean isEmpty(MetaStorage storage) { + return !storage.contains(this) || getCollection(storage).isEmpty(); + } + + public boolean containsAll(MetaStorage storage, Collection values) { + return storage.contains(this) && getCollection(storage).containsAll(values); + } + + public void addAll(MetaStorage storage, Collection values) { + getCollection(storage).addAll(values); + } + + public void removeAll(MetaStorage storage, Collection values) { + getCollection(storage).removeAll(values); + } + + public void retainAll(MetaStorage storage, Collection values) { + getCollection(storage).retainAll(values); + } + + public Collection getValues(MetaStorage storage) { + return getCollection(storage); + } + + public void setValues(MetaStorage storage, Collection values) { + getCollection(storage).clear(); + getCollection(storage).addAll(values); + } + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaListKey.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaListKey.java new file mode 100644 index 00000000..ad153ca9 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaListKey.java @@ -0,0 +1,52 @@ +package io.fairyproject.data.impl.collection; + +import io.fairyproject.data.MetaStorage; +import io.fairyproject.util.TypeLiteral; + +import java.util.ArrayList; +import java.util.List; + +public class MetaListKey extends MetaCollectionKey> { + + public MetaListKey(String name, TypeLiteral> type) { + super(name, type); + } + + @Override + public List createCollection() { + return new ArrayList<>(); + } + + public K get(MetaStorage storage, int index) { + return getCollection(storage).get(index); + } + + public void set(MetaStorage storage, int index, K value) { + getCollection(storage).set(index, value); + } + + public void add(MetaStorage storage, int index, K value) { + getCollection(storage).add(index, value); + } + + public K remove(MetaStorage storage, int index) { + return getCollection(storage).remove(index); + } + + public int indexOf(MetaStorage storage, K value) { + return getCollection(storage).indexOf(value); + } + + public int lastIndexOf(MetaStorage storage, K value) { + return getCollection(storage).lastIndexOf(value); + } + + public List subList(MetaStorage storage, int fromIndex, int toIndex) { + return getCollection(storage).subList(fromIndex, toIndex); + } + + public void addAll(MetaStorage storage, int index, List values) { + getCollection(storage).addAll(index, values); + } + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaMapKey.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaMapKey.java new file mode 100644 index 00000000..356a5e39 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaMapKey.java @@ -0,0 +1,56 @@ +package io.fairyproject.data.impl.collection; + +import io.fairyproject.data.MetaStorage; +import io.fairyproject.data.impl.MetaKeyImpl; +import io.fairyproject.util.TypeLiteral; + +import java.util.HashMap; +import java.util.Map; + +public class MetaMapKey extends MetaKeyImpl> { + + public MetaMapKey(String name, TypeLiteral> type) { + super(name, type); + } + + public Map createCollection() { + return this.cast(new HashMap<>()); + } + + public Map getCollection(MetaStorage storage) { + return this.cast(storage.computeIfAbsent(this, this::createCollection)); + } + + public V get(MetaStorage storage, K key) { + return getCollection(storage).get(key); + } + + public V put(MetaStorage storage, K key, V value) { + return getCollection(storage).put(key, value); + } + + public V remove(MetaStorage storage, K key) { + return getCollection(storage).remove(key); + } + + public boolean containsKey(MetaStorage storage, K key) { + return getCollection(storage).containsKey(key); + } + + public boolean containsValue(MetaStorage storage, V value) { + return getCollection(storage).containsValue(value); + } + + public void clear(MetaStorage storage) { + getCollection(storage).clear(); + } + + public int size(MetaStorage storage) { + return getCollection(storage).size(); + } + + public boolean isEmpty(MetaStorage storage) { + return getCollection(storage).isEmpty(); + } + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaSetKey.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaSetKey.java new file mode 100644 index 00000000..85ea65dd --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/data/impl/collection/MetaSetKey.java @@ -0,0 +1,19 @@ +package io.fairyproject.data.impl.collection; + +import io.fairyproject.util.TypeLiteral; + +import java.util.HashSet; +import java.util.Set; + +public class MetaSetKey extends MetaCollectionKey> { + + public MetaSetKey(String name, TypeLiteral> type) { + super(name, type); + } + + @Override + public Set createCollection() { + return new HashSet<>(); + } + +} diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/CommonMetadataRegistries.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/CommonMetadataRegistries.java index b878ba71..19d9f6d6 100644 --- a/framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/CommonMetadataRegistries.java +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/CommonMetadataRegistries.java @@ -31,6 +31,7 @@ import java.util.Optional; import java.util.UUID; +@Deprecated @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class CommonMetadataRegistries { diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/package-info.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/package-info.java new file mode 100644 index 00000000..bb547207 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/metadata/package-info.java @@ -0,0 +1,3 @@ +@Deprecated +package io.fairyproject.metadata; + diff --git a/framework/platforms/core-platform/src/main/java/io/fairyproject/util/TypeLiteral.java b/framework/platforms/core-platform/src/main/java/io/fairyproject/util/TypeLiteral.java new file mode 100644 index 00000000..1106b266 --- /dev/null +++ b/framework/platforms/core-platform/src/main/java/io/fairyproject/util/TypeLiteral.java @@ -0,0 +1,89 @@ +package io.fairyproject.util; + +import lombok.Getter; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; + +/** + * Represents a parameterized type. Unfortunately necessary because the JVM doesn't support + * reified generics in all cases. + */ +@SuppressWarnings("unchecked") +@Getter +public class TypeLiteral { + + /** + * The type represented by this type token. + */ + private final Class type; + + /** + * The type parameters to the type represented by this type token. + */ + private final TypeLiteral[] parameters; + + /** + * Creates a new type token for the given type, parameterized with the given type parameters. + */ + public TypeLiteral(Class type, TypeLiteral... parameters) { + this.type = type; + this.parameters = parameters; + } + + /** + * Attempts to create a type token by using the JVM's limited generic reification capabilities. + * This constructor must be invoked from a subtype to work! + */ + protected TypeLiteral() { + Type thisType = getClass().getGenericSuperclass(); + try { + Type tp = ((ParameterizedType) thisType).getActualTypeArguments()[0]; + if (tp instanceof ParameterizedType) { + ParameterizedType ptp = (ParameterizedType) tp; + this.type = (Class) ptp.getRawType(); + this.parameters = Arrays.stream(ptp.getActualTypeArguments()) + .map(TypeLiteral::new).toArray(TypeLiteral[]::new); + } else { + this.type = (Class) tp; + this.parameters = new TypeLiteral[0]; + } + } catch (Exception e) { + throw new UnsupportedOperationException("Could not compute parameterized type for " + thisType, e); + } + } + + /** + * Attempts to create a type token from a reified generic type, assuming all its parameters are also reified. + */ + private TypeLiteral(Type tp) { + try { + if (tp instanceof ParameterizedType) { + ParameterizedType ptp = (ParameterizedType) tp; + this.type = (Class) ptp.getRawType(); + this.parameters = Arrays.stream(ptp.getActualTypeArguments()) + .map(TypeLiteral::new).toArray(TypeLiteral[]::new); + } else { + this.type = (Class) tp; + this.parameters = new TypeLiteral[0]; + } + } catch (Exception e) { + throw new UnsupportedOperationException("Could not compute parameterized type for " + tp, e); + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(type.getSimpleName()); + if (parameters.length > 0) { + buf.append("<").append(parameters[0].toString()); + for (int i = 1; i < parameters.length; i++) { + buf.append(", ").append(parameters[i].toString()); + } + buf.append(">"); + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java b/framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java index 908cca9a..15f7c1cb 100644 --- a/framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java +++ b/framework/platforms/core-platform/src/test/java/io/fairyproject/data/impl/MetaStorageImplTest.java @@ -21,7 +21,7 @@ class MetaStorageImplTest { @BeforeEach void setUp() { - testKey = new MetaKeyImpl<>("test", Integer.class); + testKey = MetaKey.create("test", Integer.class); metaStorage = new MetaStorageImpl(); } @@ -71,7 +71,7 @@ void putAndRetrieveReference() { void testConcurrentAccess() throws InterruptedException { for (int k = 0; k < 10; k++) { MetaStorageImpl metaStorage = new MetaStorageImpl(); - MetaKey testKey = new MetaKeyImpl<>("testKey", Integer.class); + MetaKey testKey = MetaKey.create("testKey", Integer.class); int numberOfThreads = 1000; ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads); CountDownLatch startGate = new CountDownLatch(1); diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java index a6c73635..b25ab1bf 100644 --- a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java +++ b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java @@ -29,14 +29,12 @@ static Collection all() { return Companion.BRIDGE.all(); } - @NotNull - @Deprecated + @Nullable static MCPlayer from(@Nullable T originalPlayer) { - return Containers.get(MCPlayerRegistry.class).findPlayerByPlatformPlayer(originalPlayer); + return Containers.get(MCPlayerRegistry.class).findByPlatform(originalPlayer); } @Nullable - @Deprecated static MCPlayer find(UUID uuid) { return Companion.BRIDGE.find(uuid); } @@ -116,6 +114,7 @@ static MCPlayer find(UUID uuid) { * * @return metadata map */ + @Deprecated default MetadataMap metadata() { return CommonMetadataRegistries.provide(this.getUUID()); } @@ -205,7 +204,6 @@ default void sendMessage(char colorCode, Iterable messages) { */ Channel getChannel(); - @Deprecated class Companion { public static Bridge BRIDGE = null; @@ -213,7 +211,6 @@ class Companion { } - @Deprecated interface Bridge { UUID from(@NotNull Object obj); diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCWorld.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCWorld.java index e6ae4ccf..7fe7abf2 100644 --- a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCWorld.java +++ b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/MCWorld.java @@ -1,6 +1,8 @@ package io.fairyproject.mc; +import io.fairyproject.data.MetaStorage; import io.fairyproject.event.EventNode; +import io.fairyproject.mc.data.MCMetadata; import io.fairyproject.mc.event.trait.MCWorldEvent; import io.fairyproject.mc.util.AudienceProxy; import io.fairyproject.metadata.MetadataMap; @@ -32,8 +34,13 @@ static List all() { EventNode getEventNode(); + @Deprecated MetadataMap getMetadata(); + default MetaStorage getMetaStorage() { + return MCMetadata.provideWorld(this.getName()); + } + List getPlayers(); @UtilityClass diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java new file mode 100644 index 00000000..65c71b36 --- /dev/null +++ b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java @@ -0,0 +1,86 @@ +package io.fairyproject.mc.data; + +import io.fairyproject.data.MetaRegistry; +import io.fairyproject.data.MetaStorage; +import io.fairyproject.data.impl.MetaRegistryImpl; +import io.fairyproject.mc.MCEntity; +import io.fairyproject.mc.MCPlayer; +import io.fairyproject.mc.MCWorld; +import io.fairyproject.mc.util.BlockPosition; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class MCMetadata { + + private static final MetaRegistry PLAYERS = new MetaRegistryImpl<>(); + private static final MetaRegistry WORLDS = new MetaRegistryImpl<>(); + private static final MetaRegistry ENTITIES = new MetaRegistryImpl<>(); + private static final MetaRegistry BLOCKS = new MetaRegistryImpl<>(); + + public static MetaRegistry getPlayerRegistry() { + return PLAYERS; + } + + public static MetaRegistry getWorldRegistry() { + return WORLDS; + } + + public static MetaRegistry getEntityRegistry() { + return ENTITIES; + } + + public static MetaRegistry getBlockRegistry() { + return BLOCKS; + } + + public static MetaStorage providePlayer(MCPlayer player) { + return PLAYERS.provide(player.getUUID()); + } + + public static MetaStorage providePlayer(UUID player) { + return PLAYERS.provide(player); + } + + public static MetaStorage provideWorld(MCWorld world) { + return WORLDS.provide(world.getName()); + } + + public static MetaStorage provideWorld(String world) { + return WORLDS.provide(world); + } + + public static MetaStorage provideEntity(MCEntity entity) { + return ENTITIES.provide(entity.getUUID()); + } + + public static MetaStorage provideEntity(UUID entity) { + return ENTITIES.provide(entity); + } + + public static MetaStorage provideBlock(BlockPosition block) { + return BLOCKS.provide(block.asLong()); + } + + @NotNull + public static MetaStorage provide(Object holder) { + if (holder instanceof MCPlayer) { + return providePlayer((MCPlayer) holder); + } else if (holder instanceof MCWorld) { + return provideWorld((MCWorld) holder); + } else if (holder instanceof MCEntity) { + return provideEntity((MCEntity) holder); + } else if (holder instanceof BlockPosition) { + return provideBlock((BlockPosition) holder); + } + return null; + } + + public static void clear() { + PLAYERS.clear(); + WORLDS.clear(); + ENTITIES.clear(); + BLOCKS.clear(); + } + +} diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java deleted file mode 100644 index 1ece746e..00000000 --- a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/meta/MCMetaRegistries.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.fairyproject.mc.meta; - -import io.fairyproject.data.MetaRegistry; -import io.fairyproject.data.impl.MetaRegistryImpl; - -import java.util.UUID; - -public class MCMetaRegistries { - - private static final MetaRegistry PLAYERS = new MetaRegistryImpl<>(); - private static final MetaRegistry WORLDS = new MetaRegistryImpl<>(); - private static final MetaRegistry ENTITIES = new MetaRegistryImpl<>(); - private static final MetaRegistry BLOCKS = new MetaRegistryImpl<>(); - - - -} diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/metadata/PlayerOnlineValue.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/metadata/PlayerOnlineValue.java index 0dd669b1..fb738581 100644 --- a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/metadata/PlayerOnlineValue.java +++ b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/metadata/PlayerOnlineValue.java @@ -7,6 +7,7 @@ import java.util.Objects; import java.util.UUID; +@Deprecated public class PlayerOnlineValue implements TransientValue { private final T value; diff --git a/framework/tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java b/framework/tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java index 6278fea6..6d3d5255 100644 --- a/framework/tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java +++ b/framework/tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java @@ -112,7 +112,7 @@ public Channel getChannel() { } @Override - public T as(Class playerClass) { + public T as(@NotNull Class playerClass) { if (playerClass.isAssignableFrom(originalInstance.getClass())) { return playerClass.cast(this.originalInstance); } From 72f3742c5acb7dfeb29522c58a84a7c05118a41a Mon Sep 17 00:00:00 2001 From: LeeGodSRC Date: Sat, 13 Jul 2024 20:19:00 +0800 Subject: [PATCH 3/3] chore: Added bridge to provide MetaStorage for bukkit objects directly --- .../bukkit/FairyBukkitPlatform.java | 7 +-- .../bukkit/mc/BukkitMetadataBridge.java | 52 +++++++++++++++++++ .../{impl => plugin}/BukkitPluginHandler.java | 2 +- .../io/fairyproject/mc/data/MCMetadata.java | 5 +- .../mc/data/MCMetadataBridge.java | 10 ++++ global.properties | 2 +- 6 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMetadataBridge.java rename framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/{impl => plugin}/BukkitPluginHandler.java (98%) create mode 100644 framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadataBridge.java diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java index d57dbb1d..163709d9 100644 --- a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java @@ -28,7 +28,7 @@ import io.fairyproject.FairyPlatform; import io.fairyproject.PlatformType; import io.fairyproject.bukkit.events.PostServicesInitialEvent; -import io.fairyproject.bukkit.impl.BukkitPluginHandler; +import io.fairyproject.bukkit.plugin.BukkitPluginHandler; import io.fairyproject.bukkit.listener.FilteredListener; import io.fairyproject.bukkit.listener.RegisterAsListener; import io.fairyproject.bukkit.listener.events.Events; @@ -82,9 +82,10 @@ public FairyBukkitPlatform(File dataFolder) { } PluginManager.initialize(new BukkitPluginHandler()); - // Use log4j for bukkit platform - if (!Debug.UNIT_TEST) + if (!Debug.UNIT_TEST) { + // Use log4j for bukkit platform Log.set(new Log4jLogger()); + } } @Override diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMetadataBridge.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMetadataBridge.java new file mode 100644 index 00000000..fdeb244e --- /dev/null +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMetadataBridge.java @@ -0,0 +1,52 @@ +package io.fairyproject.bukkit.mc; + +import io.fairyproject.container.InjectableComponent; +import io.fairyproject.data.MetaStorage; +import io.fairyproject.mc.data.MCMetadata; +import io.fairyproject.mc.data.MCMetadataBridge; +import io.fairyproject.mc.util.BlockPosition; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.util.BlockVector; +import org.jetbrains.annotations.NotNull; + +@InjectableComponent +public class BukkitMetadataBridge implements MCMetadataBridge { + + public BukkitMetadataBridge() { + MCMetadata.BRIDGE = this; + } + + @Override + public @NotNull MetaStorage provide(@NotNull Object object) { + if (object instanceof Player) { + Player player = (Player) object; + + return MCMetadata.providePlayer(player.getUniqueId()); + } + + if (object instanceof World) { + World world = (World) object; + + return MCMetadata.provideWorld(world.getName()); + } + + if (object instanceof Entity) { + Entity entity = (Entity) object; + + return MCMetadata.provideEntity(entity.getUniqueId()); + } + + if (object instanceof Block) { + Block block = (Block) object; + BlockVector blockVector = block.getLocation().toVector().toBlockVector(); + + return MCMetadata.provideBlock(new BlockPosition(blockVector.getBlockX(), blockVector.getBlockY(), blockVector.getBlockZ())); + } + + throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); + } + +} diff --git a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/impl/BukkitPluginHandler.java b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/plugin/BukkitPluginHandler.java similarity index 98% rename from framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/impl/BukkitPluginHandler.java rename to framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/plugin/BukkitPluginHandler.java index a37c1d4f..5cac6cd5 100644 --- a/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/impl/BukkitPluginHandler.java +++ b/framework/platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/plugin/BukkitPluginHandler.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package io.fairyproject.bukkit.impl; +package io.fairyproject.bukkit.plugin; import io.fairyproject.bukkit.FairyBukkitPlatform; import io.fairyproject.bukkit.util.JavaPluginUtil; diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java index 65c71b36..dd62b0e6 100644 --- a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java +++ b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadata.java @@ -7,6 +7,7 @@ import io.fairyproject.mc.MCPlayer; import io.fairyproject.mc.MCWorld; import io.fairyproject.mc.util.BlockPosition; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -17,6 +18,8 @@ public class MCMetadata { private static final MetaRegistry WORLDS = new MetaRegistryImpl<>(); private static final MetaRegistry ENTITIES = new MetaRegistryImpl<>(); private static final MetaRegistry BLOCKS = new MetaRegistryImpl<>(); + @ApiStatus.Internal + public static MCMetadataBridge BRIDGE; public static MetaRegistry getPlayerRegistry() { return PLAYERS; @@ -73,7 +76,7 @@ public static MetaStorage provide(Object holder) { } else if (holder instanceof BlockPosition) { return provideBlock((BlockPosition) holder); } - return null; + return BRIDGE.provide(holder); } public static void clear() { diff --git a/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadataBridge.java b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadataBridge.java new file mode 100644 index 00000000..3feb2001 --- /dev/null +++ b/framework/platforms/mc-platform/src/main/java/io/fairyproject/mc/data/MCMetadataBridge.java @@ -0,0 +1,10 @@ +package io.fairyproject.mc.data; + +import io.fairyproject.data.MetaStorage; +import org.jetbrains.annotations.NotNull; + +public interface MCMetadataBridge { + + @NotNull MetaStorage provide(@NotNull Object object); + +} diff --git a/global.properties b/global.properties index bf37ce3f..69b85ac8 100644 --- a/global.properties +++ b/global.properties @@ -1 +1 @@ -version = 0.7.6b2-SNAPSHOT \ No newline at end of file +version = 0.7.7b1-SNAPSHOT \ No newline at end of file