package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MultiCacheDensity extends Density { @Nonnull private final WorkerIndexer.Data threadData; @Nonnull private Density input; public MultiCacheDensity(@Nonnull Density input, int threadCount, int capacity) { this.input = input; this.threadData = new WorkerIndexer.Data<>(threadCount, () -> new MultiCacheDensity.Cache(capacity)); } @Override public double process(@Nonnull Density.Context context) { MultiCacheDensity.Cache cache = this.threadData.get(context.workerId); MultiCacheDensity.Entry matchingEntry = cache.find(context.position); if (matchingEntry == null) { matchingEntry = cache.getNext(); if (matchingEntry.position == null) { matchingEntry.position = new Vector3d(); } matchingEntry.position.assign(context.position); matchingEntry.value = this.input.process(context); } return matchingEntry.value; } @Override public void setInputs(@Nonnull Density[] inputs) { assert inputs.length != 0; assert inputs[0] != null; this.input = inputs[0]; } private static class Cache { MultiCacheDensity.Entry[] entries; int oldestIndex; Cache(int size) { this.entries = new MultiCacheDensity.Entry[size]; for (int i = 0; i < size; i++) { this.entries[i] = new MultiCacheDensity.Entry(); } this.oldestIndex = 0; } MultiCacheDensity.Entry getNext() { MultiCacheDensity.Entry entry = this.entries[this.oldestIndex]; this.oldestIndex++; if (this.oldestIndex >= this.entries.length) { this.oldestIndex = 0; } return entry; } @Nullable MultiCacheDensity.Entry find(@Nonnull Vector3d position) { int startIndex = this.oldestIndex - 1; if (startIndex < 0) { startIndex += this.entries.length; } int index = startIndex; while (!position.equals(this.entries[index].position)) { if (++index >= this.entries.length) { index = 0; } if (index == startIndex) { return null; } } return this.entries[index]; } } private static class Entry { Vector3d position = null; double value = 0.0; Entry() { } } }