All Downloads are FREE. Search and download functionalities are using the official Maven repository.

think.rpgitems.data.Context Maven / Gradle / Ivy

There is a newer version: 3.12.2
Show newest version
package think.rpgitems.data;

import cat.nyaa.nyaacore.Pair;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Context {
    private HashMap> storage = new HashMap<>();

    private static Context instance = new Context();

    public static Context instance() {
        return instance;
    }

    public LivingEntity getLivingEntity(UUID context, String key) {
        ExpiringMap local = storage.get(context);
        if (local == null) return null;
        Object obj = local.get(key);
        if (obj instanceof LivingEntity) {
            return (LivingEntity) obj;
        }
        return null;
    }

    public Boolean getBoolean(UUID context, String key) {
        ExpiringMap local = storage.get(context);
        if (local == null) return null;
        Object obj = local.get(key);
        if (obj instanceof Boolean) {
            return (Boolean) obj;
        }
        return null;
    }

    public Double getDouble(UUID context, String key) {
        ExpiringMap local = storage.get(context);
        if (local == null) return null;
        Object obj = local.get(key);
        if (obj instanceof Double) {
            return (Double) obj;
        }
        return null;
    }

    public Location getLocation(UUID context, String key) {
        ExpiringMap local = storage.get(context);
        if (local == null) return null;
        Object obj = local.get(key);
        if (obj instanceof Location) {
            return (Location) obj;
        }
        return null;
    }

    public Object get(UUID context, String key) {
        ExpiringMap local = storage.get(context);
        if (local == null) return null;
        return local.get(key);
    }

    public void put(UUID context, String key, Object obj) {
        storage.computeIfAbsent(context, (ignored) -> new ExpiringMap<>()).put(key, obj);
    }

    public void putTemp(UUID context, String key, Object obj) {
        storage.computeIfAbsent(context, (ignored) -> new ExpiringMap<>()).putTemp(key, obj);
    }

    public void removeTemp(UUID context, String key){
        storage.computeIfAbsent(context, uuid -> new ExpiringMap<>()).remove(key);
    }

    public void put(UUID context, String key, Object obj, long expire) {
        storage.computeIfAbsent(context, (ignored) -> new ExpiringMap<>()).put(key, obj, expire);
    }

    public void putExpiringSeconds(UUID context, String key, Object obj, int expiringSeconds) {
        put(context, key, obj, getCurrentMillis() + expiringSeconds * 10L);
    }

    public void cleanTemp(UUID context) {
        ExpiringMap local = storage.get(context);
        if (local == null) return;
        local.cleanupTemp();
    }

    public void cleanTick() {
        for (ExpiringMap local : storage.values()) {
            local.cleanup(null, null, ExpiringMap.TICK);
        }
    }

    public static class ExpiringMap implements Map {
        private final int aliveAge;
        private final HashMap birth = new HashMap<>();
        private final HashMap inner;

        private static final long TEMP = Long.MAX_VALUE;
        private static final long TICK = Long.MAX_VALUE - 1;

        public ExpiringMap() {
            this(0);
        }

        public ExpiringMap(int aliveAge) {
            inner = new HashMap<>();
            this.aliveAge = aliveAge;
        }

        public ExpiringMap(int initialCapacity, int aliveAge) {
            inner = new HashMap<>(initialCapacity);
            this.aliveAge = aliveAge;
        }

        private void rec(K i, long birth) {
            this.birth.put(i, birth);
            this.cleanup();
        }

        private void rec(K key) {
            long currentMillis = getCurrentMillis();
            rec(key, currentMillis);
        }

        public void cleanup() {
            cleanup(null, null, null);
        }

        public void cleanupTemp() {
            cleanup(null, null, TEMP);
        }

        @Nullable
        public Pair cleanup(Object findKey, Object findValue, Long removing) {
            long currentMillis = getCurrentMillis();
            Iterator> expireIter = this.birth.entrySet().iterator();

            while (expireIter.hasNext()) {
                Map.Entry entry = expireIter.next();
                K key = entry.getKey();
                V value = inner.get(key);
                Long birth = entry.getValue();

                if ((currentMillis - birth <= (long) this.aliveAge)
                            && !Objects.equals(birth, removing)) {
                    if (Objects.equals(findKey, key)) {
                        return Pair.of(key, value);
                    }
                    if (value != null && Objects.equals(findValue, value)) {
                        return Pair.of(key, value);
                    }
                    continue;
                }

                inner.remove(key);
                expireIter.remove();
            }
            return null;
        }

        @Override
        public int size() {
            this.cleanup();
            return inner.size();
        }

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

        @Override
        public boolean containsKey(Object key) {
            return this.cleanup(key, null, null) == null;
        }

        @Override
        public boolean containsValue(Object value) {
            return this.cleanup(null, value, null) == null;
        }

        @Override
        public V get(Object key) {
            Pair cleanup = this.cleanup(key, null, null);
            if (cleanup == null) {
                return null;
            }
            return cleanup.getValue();
        }

        @Override
        public V put(K i, V value) {
            this.rec(i);
            return inner.put(i, value);
        }

        public V put(K i, V value, long birth) {
            this.rec(i, birth);
            return inner.put(i, value);
        }

        public V putTemp(K i, V value) {
            this.rec(i, TEMP);
            return inner.put(i, value);
        }

        @Override
        public V remove(Object key) {
            birth.remove(key);
            return inner.remove(key);
        }

        @Override
        public void putAll(@Nonnull Map map) {
            long currentMillis = getCurrentMillis();
            birth.putAll(map.keySet().stream().collect(Collectors.toMap(e -> e, e -> currentMillis)));
            inner.putAll(map);
            cleanup();
        }

        @Override
        public void clear() {
            birth.clear();
            inner.clear();
        }

        @Override
        @Nonnull
        public Set keySet() {
            cleanup();
            return birth.keySet();
        }

        @Override
        public V computeIfAbsent(K key, Function value) {
            this.birth.put(key, getCurrentMillis());
            return inner.computeIfAbsent(key, value);
        }

        @Override
        @Nonnull
        public Collection values() {
            this.cleanup();
            return inner.values();
        }

        @Override
        @Nonnull
        public Set> entrySet() {
            this.cleanup();
            return inner.entrySet();
        }
    }

    /**
     * @return monotonic current millis
     */
    public static long getCurrentMillis() {
        return System.nanoTime() / 1000000L;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy