mirror of
https://github.com/LegacyModdingMC/ChunkAPI.git
synced 2026-11-11 16:07:37 +00:00
feat: Ordered data managers
This commit is contained in:
5 files changed
+234
-40
No files matched your search
@@ -31,6 +31,7 @@ import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
/**
|
||||
* This is an API class covered by the additional permissions in the license.
|
||||
@@ -48,12 +49,36 @@ public class DataRegistry {
|
||||
* Registers a ChunkDataManager. Only do this during the init phase.
|
||||
*
|
||||
* @param manager The manager to register.
|
||||
* @param ordering The natural ordering index for the data manager when iterating the list of managers.
|
||||
* <p>
|
||||
* ChunkAPI, Lumi, RPLE, and EndlessIDs all use 0. Negative numbers are sorted earlier. Positive numbers are sorted later.
|
||||
* <p>
|
||||
* Use 0 unless you specifically need to do something later.
|
||||
* <p>
|
||||
* As a convention, do this in increments of 1000 so that other people can order "between" your manager and the base managers.
|
||||
*
|
||||
*
|
||||
* @throws IllegalStateException If the registration stage is over.
|
||||
* @throws IllegalArgumentException If the manager has a duplicate id.
|
||||
*/
|
||||
public static void registerDataManager(DataManager manager, int ordering) throws IllegalStateException, IllegalArgumentException {
|
||||
DataRegistryImpl.registerDataManager(manager, ordering);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a ChunkDataManager. Only do this during the init phase.
|
||||
* Has an implicit ordering index of 0.
|
||||
*
|
||||
* @deprecated Use {@link #registerDataManager(DataManager, int)} with an explicit ordering.
|
||||
*
|
||||
* @param manager The manager to register.
|
||||
*
|
||||
* @throws IllegalStateException If the registration stage is over.
|
||||
* @throws IllegalArgumentException If the manager has a duplicate id.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void registerDataManager(DataManager manager) throws IllegalStateException, IllegalArgumentException {
|
||||
DataRegistryImpl.registerDataManager(manager);
|
||||
DataRegistryImpl.registerDataManager(manager, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,10 +97,22 @@ public class DataRegistry {
|
||||
* The id of a manager is its domain and id separated by a colon. (domain:id)
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
@Deprecated
|
||||
public static @Unmodifiable Set<String> getRegisteredManagers() {
|
||||
return DataRegistryImpl.getRegisteredManagers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable set of all registered ChunkDataManagers.
|
||||
* The id of a manager is its domain and id separated by a colon. (domain:id)
|
||||
* <p>
|
||||
* This function also includes the ordering index of each manager.
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
public static @Unmodifiable SortedSet<OrderedManager> getRegisteredManagersOrdered() {
|
||||
return DataRegistryImpl.getRegisteredManagersOrdered();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies chunk-level data from a source chunk to a target chunk.
|
||||
* DOES NOT copy data contained inside its ExtendedBlockStorage instances!!
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* ChunkAPI
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern, The MEGA Team, LegacyModdingMC contributors
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.chunk.api;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class OrderedManager implements Comparable<OrderedManager> {
|
||||
public final int ordering;
|
||||
public final @NotNull String id;
|
||||
@Override
|
||||
public int compareTo(OrderedManager o) {
|
||||
int ord = Integer.compare(ordering, o.ordering);
|
||||
if (ord != 0)
|
||||
return ord;
|
||||
return id.compareTo(o.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof OrderedManager))
|
||||
return false;
|
||||
val other = (OrderedManager) obj;
|
||||
return id.equals(other.id) && ordering == other.ordering;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(ordering, id);
|
||||
}
|
||||
}
|
||||
@@ -41,11 +41,11 @@ public class ChunkAPI {
|
||||
|
||||
@Mod.EventHandler
|
||||
public void init(FMLInitializationEvent event) {
|
||||
DataRegistry.registerDataManager(new BlockIDManager());
|
||||
DataRegistry.registerDataManager(new MetadataManager());
|
||||
DataRegistry.registerDataManager(new LightingManager());
|
||||
DataRegistry.registerDataManager(new BlocklightManager());
|
||||
DataRegistry.registerDataManager(new SkylightManager());
|
||||
DataRegistry.registerDataManager(new BiomeManager());
|
||||
DataRegistry.registerDataManager(new BlockIDManager(), 0);
|
||||
DataRegistry.registerDataManager(new MetadataManager(), 0);
|
||||
DataRegistry.registerDataManager(new LightingManager(), 0);
|
||||
DataRegistry.registerDataManager(new BlocklightManager(), 0);
|
||||
DataRegistry.registerDataManager(new SkylightManager(), 0);
|
||||
DataRegistry.registerDataManager(new BiomeManager(), 0);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
package com.falsepattern.chunk.internal;
|
||||
|
||||
import com.falsepattern.chunk.api.DataManager;
|
||||
import com.falsepattern.chunk.api.OrderedManager;
|
||||
import lombok.Data;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
@@ -48,15 +49,20 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DataRegistryImpl {
|
||||
private static final Set<String> managers = new HashSet<>();
|
||||
private static final Map<String, PacketManagerInfo> packetManagers = new HashMap<>();
|
||||
private static final Map<String, DataManager.BlockPacketDataManager> blockPacketManagers = new HashMap<>();
|
||||
private static final Map<String, DataManager.StorageDataManager> NBTManagers = new HashMap<>();
|
||||
private static final Map<String, DataManager.ChunkDataManager> chunkNBTManagers = new HashMap<>();
|
||||
private static final Map<String, DataManager.SubChunkDataManager> subChunkNBTManagers = new HashMap<>();
|
||||
private static final Map<String, OrderedManager> managersUnordered = new HashMap<>();
|
||||
private static final SortedSet<OrderedManager> managers = new TreeSet<>();
|
||||
private static final DualMap<PacketManagerInfo> packetManagers = new DualMap<>();
|
||||
private static final DualMap<DataManager.BlockPacketDataManager> blockPacketManagers = new DualMap<>();
|
||||
private static final DualMap<DataManager.StorageDataManager> NBTManagers = new DualMap<>();
|
||||
private static final SortedMap<OrderedManager, DataManager.ChunkDataManager> chunkNBTManagers = new TreeMap<>();
|
||||
private static final SortedMap<OrderedManager, DataManager.SubChunkDataManager> subChunkNBTManagers = new TreeMap<>();
|
||||
private static final Set<String> disabledManagers = new HashSet<>();
|
||||
private static int maxPacketSize = 4;
|
||||
|
||||
@@ -66,12 +72,12 @@ public class DataRegistryImpl {
|
||||
public final DataManager.PacketDataManager manager;
|
||||
}
|
||||
|
||||
public static void registerDataManager(DataManager manager) throws IllegalStateException, IllegalArgumentException {
|
||||
public static void registerDataManager(DataManager manager, int ordering) throws IllegalStateException, IllegalArgumentException {
|
||||
if (Loader.instance().getLoaderState() != LoaderState.INITIALIZATION) {
|
||||
throw new IllegalStateException("ChunkDataManager registration is not allowed at this time! Please register your ChunkDataManager in the init phase.");
|
||||
}
|
||||
var id = manager.domain() + ":" + manager.id();
|
||||
if (managers.contains(id)) {
|
||||
if (managersUnordered.containsKey(id)) {
|
||||
throw new IllegalArgumentException("ChunkDataManager " + manager + " has a duplicate id!");
|
||||
}
|
||||
|
||||
@@ -80,24 +86,27 @@ public class DataRegistryImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
managers.add(id);
|
||||
val ord = new OrderedManager(ordering, id);
|
||||
managersUnordered.put(id, ord);
|
||||
managers.add(ord);
|
||||
if (manager instanceof DataManager.PacketDataManager) {
|
||||
val packetManager = (DataManager.PacketDataManager) manager;
|
||||
val maxSize = packetManager.maxPacketSize();
|
||||
maxPacketSize += 4 + id.getBytes(StandardCharsets.UTF_8).length + 4 + maxSize;
|
||||
packetManagers.put(id, new PacketManagerInfo(maxSize, packetManager));
|
||||
val man = new PacketManagerInfo(maxSize, packetManager);
|
||||
packetManagers.put(ord, man);
|
||||
}
|
||||
if (manager instanceof DataManager.BlockPacketDataManager) {
|
||||
val blockPacketManager = (DataManager.BlockPacketDataManager) manager;
|
||||
blockPacketManagers.put(id, blockPacketManager);
|
||||
blockPacketManagers.put(ord, blockPacketManager);
|
||||
}
|
||||
if (manager instanceof DataManager.StorageDataManager) {
|
||||
NBTManagers.put(id, (DataManager.StorageDataManager) manager);
|
||||
NBTManagers.put(ord, (DataManager.StorageDataManager) manager);
|
||||
if (manager instanceof DataManager.ChunkDataManager) {
|
||||
chunkNBTManagers.put(id, (DataManager.ChunkDataManager) manager);
|
||||
chunkNBTManagers.put(ord, (DataManager.ChunkDataManager) manager);
|
||||
}
|
||||
if (manager instanceof DataManager.SubChunkDataManager) {
|
||||
subChunkNBTManagers.put(id, (DataManager.SubChunkDataManager) manager);
|
||||
subChunkNBTManagers.put(ord, (DataManager.SubChunkDataManager) manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,17 +118,19 @@ public class DataRegistryImpl {
|
||||
Common.LOG.debug("Disabling ChunkDataManager " + id + " in domain " + domain + ". See the stacktrace for the source of this event.\nThis is NOT an error.",
|
||||
new Throwable());
|
||||
val manager = domain + ":" + id;
|
||||
val ord = managersUnordered.remove(manager);
|
||||
//Remove the manager from the list of managers, if it exists
|
||||
if (managers.remove(manager)) {
|
||||
if (ord != null) {
|
||||
managers.remove(ord);
|
||||
//Clear the maps
|
||||
if (packetManagers.containsKey(manager)) {
|
||||
val removed = packetManagers.remove(manager);
|
||||
if (packetManagers.containsKey(ord)) {
|
||||
val removed = packetManagers.remove(ord);
|
||||
maxPacketSize -= 4 + id.getBytes(StandardCharsets.UTF_8).length + 4 + removed.maxPacketSize;
|
||||
}
|
||||
blockPacketManagers.remove(manager);
|
||||
chunkNBTManagers.remove(manager);
|
||||
subChunkNBTManagers.remove(manager);
|
||||
NBTManagers.remove(manager);
|
||||
blockPacketManagers.remove(ord);
|
||||
chunkNBTManagers.remove(ord);
|
||||
subChunkNBTManagers.remove(ord);
|
||||
NBTManagers.remove(ord);
|
||||
}
|
||||
|
||||
//Add the manager to the list of disabled managers, in case it gets registered after this disable call.
|
||||
@@ -171,9 +182,9 @@ public class DataRegistryImpl {
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.putInt(packetManagers.size());
|
||||
for (val pair : packetManagers.entrySet()) {
|
||||
val id = pair.getKey();
|
||||
val ord = pair.getKey();
|
||||
val managerInfo = pair.getValue();
|
||||
writeString(buf, id);
|
||||
writeString(buf, ord.id);
|
||||
int start = buf.position() + 4;
|
||||
val slice = createSlice(buf, start, managerInfo.maxPacketSize);
|
||||
managerInfo.manager.writeToBuffer(chunk, subChunkMask, forceUpdate, slice);
|
||||
@@ -199,9 +210,9 @@ public class DataRegistryImpl {
|
||||
public static void writeBlockPacketToBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException {
|
||||
buffer.writeInt(blockPacketManagers.size());
|
||||
for (val pair : blockPacketManagers.entrySet()) {
|
||||
val id = pair.getKey();
|
||||
val ord = pair.getKey();
|
||||
val manager = pair.getValue();
|
||||
buffer.writeStringToBuffer(id);
|
||||
buffer.writeStringToBuffer(ord.id);
|
||||
manager.writeBlockPacketToBuffer(packet, buffer);
|
||||
}
|
||||
}
|
||||
@@ -300,7 +311,11 @@ public class DataRegistryImpl {
|
||||
}
|
||||
|
||||
public static Set<String> getRegisteredManagers() {
|
||||
return Collections.unmodifiableSet(managers);
|
||||
return Collections.unmodifiableSet(managersUnordered.keySet());
|
||||
}
|
||||
|
||||
public static SortedSet<OrderedManager> getRegisteredManagersOrdered() {
|
||||
return Collections.unmodifiableSortedSet(managers);
|
||||
}
|
||||
|
||||
public static void readLevelDat(NBTTagCompound tag) {
|
||||
@@ -349,7 +364,9 @@ public class DataRegistryImpl {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
val saveManagers = readManagers(tag);
|
||||
val removedManagers = new HashSet<>(saveManagers.keySet());
|
||||
removedManagers.removeAll(NBTManagers.keySet());
|
||||
for (val nbtManager: NBTManagers.keySet()) {
|
||||
removedManagers.remove(nbtManager.id);
|
||||
}
|
||||
if (!removedManagers.isEmpty()) {
|
||||
compatWarning = true;
|
||||
builder.append("\nThe following data managers are no longer present:\n");
|
||||
@@ -370,8 +387,8 @@ public class DataRegistryImpl {
|
||||
}
|
||||
val addedManagers = NBTManagers.keySet()
|
||||
.stream()
|
||||
.filter(manager -> !manager.startsWith("minecraft:"))
|
||||
.filter(manager -> !saveManagers.containsKey(manager))
|
||||
.filter(manager -> !manager.id.startsWith("minecraft:"))
|
||||
.filter(manager -> !saveManagers.containsKey(manager.id))
|
||||
.collect(Collectors.toSet());
|
||||
if (!addedManagers.isEmpty()) {
|
||||
compatWarning = true;
|
||||
@@ -417,12 +434,12 @@ public class DataRegistryImpl {
|
||||
tag.setTag("managers", managers);
|
||||
tag.setString("version", Tags.MOD_VERSION);
|
||||
for (val manager : NBTManagers.entrySet()) {
|
||||
val name = manager.getKey();
|
||||
if (name.startsWith("minecraft:")) {
|
||||
val ord = manager.getKey();
|
||||
if (ord.id.startsWith("minecraft:")) {
|
||||
continue;
|
||||
}
|
||||
val value = manager.getValue();
|
||||
managers.setTag(name, SaveManagerInfo.fromManager(value).toNBT());
|
||||
managers.setTag(ord.id, SaveManagerInfo.fromManager(value).toNBT());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +452,6 @@ public class DataRegistryImpl {
|
||||
return managers;
|
||||
}
|
||||
val managerTag = tag.getCompoundTag("managers");
|
||||
//noinspection unchecked
|
||||
for (val key : managerTag.func_150296_c()) {
|
||||
managers.put(key, SaveManagerInfo.fromNBT(managerTag.getCompoundTag(key)));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* ChunkAPI
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern, The MEGA Team, LegacyModdingMC contributors
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.chunk.internal;
|
||||
|
||||
import com.falsepattern.chunk.api.OrderedManager;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class DualMap<T> {
|
||||
private final Map<String, T> unordered = new HashMap<>();
|
||||
private final SortedMap<OrderedManager, T> ordered = new TreeMap<>();
|
||||
|
||||
public void put(OrderedManager man, T value) {
|
||||
val a = unordered.put(man.id, value);
|
||||
val b = ordered.put(man, value);
|
||||
if (a != b) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return unordered.size();
|
||||
}
|
||||
|
||||
public T get(OrderedManager ord) {
|
||||
return unordered.get(ord.id);
|
||||
}
|
||||
|
||||
public T get(String id) {
|
||||
return unordered.get(id);
|
||||
}
|
||||
|
||||
public T remove(OrderedManager ord) {
|
||||
val a = unordered.remove(ord.id);
|
||||
val b = ordered.remove(ord);
|
||||
if (a != b) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public boolean containsKey(String id) {
|
||||
return unordered.containsKey(id);
|
||||
}
|
||||
|
||||
public boolean containsKey(OrderedManager ord) {
|
||||
return unordered.containsKey(ord.id);
|
||||
}
|
||||
|
||||
public Set<OrderedManager> keySet() {
|
||||
return ordered.keySet();
|
||||
}
|
||||
|
||||
public Set<Map.Entry<OrderedManager, T>> entrySet() {
|
||||
return ordered.entrySet();
|
||||
}
|
||||
|
||||
public Iterable<T> values() {
|
||||
return ordered.values();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user