Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id("com.falsepattern.fpgradle-mc") version("0.18.0")
id("com.falsepattern.fpgradle-mc") version("2.1.0")
}

group = "com.falsepattern"
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
5 changes: 1 addition & 4 deletions gradlew
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac

CLASSPATH="\\\"\\\""


# Determine the Java command to use to start the JVM.
Expand Down Expand Up @@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

JAVACMD=$( cygpath --unix "$JAVACMD" )

Expand Down Expand Up @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"

Expand Down
3 changes: 1 addition & 2 deletions gradlew.bat
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,10 @@ goto fail
:execute
@rem Setup the command line

set CLASSPATH=


@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*

:end
@rem End local scope for the variables with windows NT shell
Expand Down
39 changes: 38 additions & 1 deletion src/main/java/com/falsepattern/chunk/api/DataRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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.
Expand All @@ -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);
}

/**
Expand All @@ -72,10 +97,22 @@ public static void disableDataManager(String domain, String id) throws IllegalSt
* 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!!
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/com/falsepattern/chunk/api/OrderedManager.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
12 changes: 6 additions & 6 deletions src/main/java/com/falsepattern/chunk/internal/ChunkAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
82 changes: 49 additions & 33 deletions src/main/java/com/falsepattern/chunk/internal/DataRegistryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -48,15 +49,20 @@
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;

Expand All @@ -66,12 +72,12 @@ private static class PacketManagerInfo {
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!");
}

Expand All @@ -80,24 +86,27 @@ public static void registerDataManager(DataManager manager) throws IllegalStateE
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);
}
}
}
Expand All @@ -109,17 +118,19 @@ public static void disableDataManager(String domain, String id) {
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.
Expand Down Expand Up @@ -171,9 +182,9 @@ public static int writeToBuffer(Chunk chunk, int subChunkMask, boolean forceUpda
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);
Expand All @@ -199,9 +210,9 @@ public static void readBlockFromPacket(Chunk chunk, int x, int y, int z, S23Pack
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);
}
}
Expand Down Expand Up @@ -300,7 +311,11 @@ public static void cloneSubChunk(Chunk fromChunk, ExtendedBlockStorage from, Ext
}

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) {
Expand Down Expand Up @@ -349,7 +364,9 @@ private static String verifyManagerCompatibility(NBTTagCompound tag) {
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");
Expand All @@ -370,8 +387,8 @@ private static String verifyManagerCompatibility(NBTTagCompound tag) {
}
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;
Expand Down Expand Up @@ -417,12 +434,12 @@ public static void writeLevelDat(NBTTagCompound tag) {
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());
}
}

Expand All @@ -435,7 +452,6 @@ private static Map<String, SaveManagerInfo> readManagers(NBTTagCompound tag) {
return managers;
}
val managerTag = tag.getCompoundTag("managers");
//noinspection unchecked
for (val key : managerTag.func_150296_c()) {
managers.put(key, SaveManagerInfo.fromNBT(managerTag.getCompoundTag(key)));
}
Expand Down
Loading