33 Commits
Author SHA1 Message Date
FalsePattern ee3b8d2faa ci: update gradle and buildscript 2026-08-09 15:30:43 +02:00
FalsePattern a8ebbb530c ci: update gradle and buildscript 2026-08-09 15:30:11 +02:00
FalsePattern a05638f671 Merge commit 'e68cbb570bcd7b344009292dc4455f4418c4bb1d' into dev 2026-07-27 22:26:54 +02:00
RecursivePineapple e68cbb570b Fix NPE in SkylightManager 2026-07-25 10:18:06 -04:00
FalsePattern 7b885a5f12 docs: add NEID compatibility notice to readme 2026-05-21 23:52:51 +02:00
FalsePattern 18f7d15f3a Merge remote-tracking branch 'GTNewHorizons/fix-backup' into dev 2026-05-21 23:43:57 +02:00
FalsePattern 039017a286 Merge remote-tracking branch 'iocmet/patch-1' into dev 2026-05-21 23:42:55 +02:00
boubou19 40d27c7ee6 Do not ignore the fml.doNotBackup property 2026-05-21 15:48:32 +02:00
FalsePattern d7b4afe9c3 docs: update readme 2026-05-17 15:54:52 +02:00
IOcmet 1ba33b64a0 Use a more reliable Thermos check
Signed-off-by: IOcmet <63492966+iocmet@users.noreply.github.com>
2026-04-29 05:44:25 +03:00
FalsePattern a3165a0cca fix: crash when joining server due to buggy thermos compat patch 2026-03-07 16:11:32 +01:00
rjnasers 3c4ffe502c Actually fiixng it 2026-03-07 15:48:06 +01:00
rjnasers 68f297faba Merge branch 'master' of https://github.com/Cardinalstars/ChunkAPI-Cardinalstar 2026-03-07 15:22:21 +01:00
rjnasers 02f2321339 Fixing really stupid mistake I made 2026-03-07 15:22:15 +01:00
FalsePattern 220755b3f3 feat: Thermos compat
Closes: https://github.com/LegacyModdingMC/ChunkAPI/pull/22
2026-02-06 20:54:23 +01:00
rjnasers 5be9cb6ad7 Formatting 2026-01-27 16:15:10 +01:00
rjnasers 18e590236b Separating mixin implementations to be more DRY 2026-01-27 16:13:36 +01:00
rjnasers c40cebaa90 copyright 2026-01-27 15:44:34 +01:00
rjnasers 7efe0cbcf4 Some cleanup 2026-01-27 14:00:20 +01:00
rjnasers d00d40e0e4 A start 2026-01-24 01:18:05 +01:00
FalsePattern 01de5f589a Merge remote-tracking branch 'pr18/cc-compat' 2026-01-23 20:04:36 +01:00
RecursivePineapple 023d9c96ee Cubic Chunks Compatibility 2025-11-26 11:06:09 -05:00
FalsePattern b94617d502 feat: Spool compat 2025-10-16 15:35:27 +02:00
FalsePattern 66365292a4 docs: Remove fplib dep in readme 2025-10-16 15:32:26 +02:00
FalsePattern 98cb70ab42 chore: Port to V2 mixins 2025-10-16 15:32:17 +02:00
FalsePattern 3da2da2846 build: Update foojay resolver 2025-10-16 15:18:15 +02:00
FalsePattern f1a2c011e2 build: Add gradle caching 2025-10-16 15:17:42 +02:00
FalsePattern bd9a1d1f81 build: Update gradle and buildscript 2025-09-27 20:54:17 +02:00
FalsePattern 5d44d49968 feat: Ordered data managers 2025-09-27 20:53:20 +02:00
FalsePattern 643e0e2881 update buildscript and gradle 2025-06-25 02:34:07 +02:00
FalsePattern 090d58f18f remove fplib dep 2025-06-25 02:32:44 +02:00
FalsePattern 31060c07c5 replace fplib StableAPI with jetbrains annotations 2025-06-25 02:30:11 +02:00
FalsePattern a9081e049b shadow in fplib mixin helper 2025-06-25 02:25:49 +02:00
44 changed files with 1190 additions and 217 deletions

No files matched your search

+1 -1
View File
@@ -10,7 +10,7 @@ permissions:
jobs:
release-tags:
uses: FalsePattern/fpgradle-workflows/.github/workflows/release-tags.yml@master
uses: FalsePattern/fpgradle-workflows/.github/workflows/release-tags-2.yml@master
with:
workspace: "setupCIWorkspace"
secrets:
+2 -11
View File
@@ -1,5 +1,5 @@
plugins {
id("com.falsepattern.fpgradle-mc") version("0.17.1")
id("com.falsepattern.fpgradle-mc") version("4.1.0")
}
group = "com.falsepattern"
@@ -17,7 +17,6 @@ minecraft_fp {
mixin {
pkg = "internal.mixin.mixins"
pluginClass = "internal.mixin.plugin.MixinPlugin"
}
core {
@@ -37,27 +36,19 @@ minecraft_fp {
}
curseforge {
projectId = "844484"
dependencies {
required("fplib")
}
side = Both
}
modrinth {
projectId = "y0vBUOla"
dependencies {
required("fplib")
}
}
}
}
repositories {
cursemavenEX()
exclusive(maven("mavenpattern", "https://mvn.falsepattern.com/releases/"), "com.falsepattern")
}
dependencies {
apiSplit("com.falsepattern:falsepatternlib-mc1.7.10:1.5.9")
//LookingGlass 0.2.0.01
compileOnly(deobfCurse("lookingglass-230541:2321557"))
}
+2
View File
@@ -0,0 +1,2 @@
org.gradle.caching=true
org.gradle.configuration-cache=true
Binary file not shown.
+3 -1
View File
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+4 -7
View File
@@ -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.
@@ -20,7 +20,7 @@
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
# gradlew start up script for POSIX generated by Gradle.
#
# Important for running:
#
@@ -29,7 +29,7 @@
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
# ksh gradlew
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -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" )
@@ -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" \
"$@"
Vendored
+12 -24
View File
@@ -19,12 +19,12 @@
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem gradlew startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@@ -51,7 +51,7 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -65,30 +65,18 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
"%COMSPEC%" /c exit 1
: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" %*
@rem Execute gradlew
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%
+19 -1
View File
@@ -11,6 +11,15 @@ loading hooks, and more.
### Mod logo by Houstonruss
NotEnoughIDs Compatibility Notice
-----
This mod is NOT compatible with NotEnoughIDs (both the original and the GTNH variant). use [EndlessIDs](https://github.com/GTMEGA/EndlessIDs) instead.
**BACKUP YOUR SAVE FIRST!**
If you only need ID extension on block/item IDs, you can turn off the extensions of other ID types in EndlessIDs to prevent compatibility issues!
Goals
-----
@@ -112,10 +121,19 @@ Manager data:
| 4 | int | (m) Manager data length |
| m | byte[m] | Manager data |
## Strict No LLM / No AI Policy
No LLMs for issues.
No LLMs for patches / pull requests.
No LLMs for comments on the bug tracker, including translation.
English is encouraged, but not required. You are welcome to post in your native
language and rely on others to have their own translation tools of choice to
interpret your words.
Dependencies
------------
[FalsePatternLib](https://github.com/Falsepattern/FalsePatternLib)
[UniMixins](https://github.com/LegacyModdingMC/UniMixins)
+1 -1
View File
@@ -1,5 +1,5 @@
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version("0.9.0")
id("org.gradle.toolchains.foojay-resolver-convention") version("1.0.0")
}
rootProject.name = "ChunkAPI"
@@ -22,7 +22,7 @@
package com.falsepattern.chunk.api;
import com.falsepattern.lib.StableAPI;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import net.minecraft.world.chunk.NibbleArray;
@@ -33,11 +33,13 @@ import java.util.Arrays;
* This is an API class covered by the additional permissions in the license.
* <p>
* Miscellaneous utilities for in-place array transfer (where possible).
* @version 0.5.0
* @since 0.5.0
*/
@StableAPI(since = "0.5.0")
@ApiStatus.NonExtendable
@SuppressWarnings("DuplicatedCode")
public class ArrayUtil {
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -52,7 +54,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -67,7 +68,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -82,7 +82,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -97,7 +96,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -112,7 +110,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -127,7 +124,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -142,7 +138,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -157,7 +152,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -172,7 +166,6 @@ public class ArrayUtil {
return dst;
}
@StableAPI.Expose
@Contract(value = "null, _ -> null;" +
"!null, null -> new;",
mutates = "param2")
@@ -22,7 +22,7 @@
package com.falsepattern.chunk.api;
import com.falsepattern.lib.StableAPI;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,20 +51,17 @@ import java.nio.ByteBuffer;
* @see DataRegistry
* @since 0.5.0
*/
@StableAPI(since = "0.5.0")
public interface DataManager {
/**
* @return The domain of this manager. Usually the modid of the mod that owns this manager.
*/
@StableAPI.Expose
@Contract(pure = true)
String domain();
/**
* @return The id of this manager. Usually the name of the manager. Unique per domain.
*/
@StableAPI.Expose
@Contract(pure = true)
String id();
@@ -72,10 +69,8 @@ public interface DataManager {
* Implement this interface if you want to synchronize your data with the client.
*
* @author FalsePattern
* @version 0.5.0
* @since 0.5.0
*/
@StableAPI(since = "0.5.0")
interface PacketDataManager extends DataManager {
/**
* @return The maximum amount of bytes your data can take up in a packet.
@@ -83,7 +78,6 @@ public interface DataManager {
* @implSpec This is used to determine the size of the packet compression/decompression buffer.
* Only called ONCE, during registration!
*/
@StableAPI.Expose
@Contract(pure = true)
int maxPacketSize();
@@ -91,22 +85,65 @@ public interface DataManager {
* Serializes your data into a packet.
*
* @param chunk The chunk to serialize.
* @param subChunkMask The mask that controls which subchunks need to be serialized. This will be 0 when cubic chunks is
* present - only chunk-specific information (like biomes) should be sent in this case.
* @param forceUpdate True when the chunk is first synced.
*/
@Contract(mutates = "param4")
@StableAPI.Expose
void writeToBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, ByteBuffer buffer);
/**
* Deserializes your data from a packet.
*
* @param chunk The chunk to deserialize.
* @param buffer The packet buffer to read from.
* @param chunk The chunk to deserialize.
* @param subChunkMask The mask that controls which subchunks need to be deserialized. This will be 0 when cubic chunks is
* present - only chunk-specific information (like biomes) should be sent in this case.
* @param forceUpdate True when the chunk is first synced.
*/
@Contract(mutates = "param1,param4")
@StableAPI.Expose
void readFromBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, ByteBuffer buffer);
}
/**
* A cube-specific variant of {@link PacketDataManager}. This is only used by cubic chunks.
*
* @author RecursivePineapple
* @since 0.7.1
* @apiNote Cubes, subchunks, and ExtendedBlockStorages are equivalent. A cube is a subchunk and a cube contains an EBS.
* To keep dependencies simple, cube-specific information is not available to this interface, but a cube's location can be
* retrieved by combining the chunk location and the EBS Y level. Note that the EBS's Y level can be <0 and >= 16.
*/
@ApiStatus.Experimental
interface CubicPacketDataManager extends DataManager {
/**
* @return The maximum amount of bytes your data can take up in a packet.
*
* @implSpec This is used to determine the size of the packet compression/decompression buffer.
* Only called ONCE, during registration!
*/
@Contract(pure = true)
int maxPacketSizeCubic();
/**
* Serializes your data into a packet.
*
* @param chunk The chunk that contains the subchunk.
* @param blockStorage The subchunk (cube) that was updated.
*/
@Contract(mutates = "param3")
void writeToBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer);
/**
* Deserializes your data from a packet.
*
* @param chunk The chunk that contains the subchunk.
* @param blockStorage The subchunk (cube) that was updated.
*/
@Contract(mutates = "param1,param2,param3")
void readFromBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer);
}
/**
* Implement this interface if you additionally want to synchronize your data on single and multi-block updates,
* not just chunk updates.
@@ -115,28 +152,23 @@ public interface DataManager {
* @version 0.6.0
* @since 0.6.0
*/
@StableAPI(since = "0.6.0")
interface BlockPacketDataManager extends DataManager {
@Contract(mutates = "param1")
@StableAPI.Expose
void writeBlockToPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet);
@Contract(mutates = "param1,param5")
@StableAPI.Expose
void readBlockFromPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet);
/**
* Serializes your block data into a buffer.
*/
@Contract(mutates = "param2")
@StableAPI.Expose
void writeBlockPacketToBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException;
/**
* Deserializes your block data from a buffer.
*/
@Contract(mutates = "param1,param2")
@StableAPI.Expose
void readBlockPacketFromBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException;
}
@@ -148,12 +180,10 @@ public interface DataManager {
* @version 0.5.0
* @since 0.5.0
*/
@StableAPI(since = "0.5.0")
interface StorageDataManager extends DataManager {
/**
* @return The current version of the data manager
*/
@StableAPI.Expose
@Contract(pure = true)
@NotNull String version();
@@ -161,7 +191,6 @@ public interface DataManager {
* @return The message to show to users when a world is opened with this mod for the first time.
* Return null to show no message, and treat the manager as fully compatible with vanilla.
*/
@StableAPI.Expose
@Contract(pure = true)
@Nullable String newInstallDescription();
@@ -169,7 +198,6 @@ public interface DataManager {
* @return The message to show to users when this manager is removed, AND they try to load the world (stored in the
* world's NBT during previous saves)
*/
@StableAPI.Expose
@Contract(pure = true)
@NotNull String uninstallMessage();
@@ -179,7 +207,6 @@ public interface DataManager {
* @return A warning message to show to the user when upgrading.\
* If null, the manager is treated as fully compatible with the old version, and no warning is shown.
*/
@StableAPI.Expose
@Contract(pure = true)
@Nullable String versionChangeMessage(String priorVersion);
}
@@ -191,7 +218,6 @@ public interface DataManager {
* @version 0.5.0
* @since 0.5.0
*/
@StableAPI(since = "0.5.0")
interface ChunkDataManager extends StorageDataManager {
/**
* If false, the given nbt compound will be a freshly created object that gets inserted into the actual
@@ -201,7 +227,6 @@ public interface DataManager {
*
* @implNote This is used internally for reimplementing the vanilla logic. Only change this if you know what you're doing.
*/
@StableAPI.Expose
@Contract(pure = true)
default boolean chunkPrivilegedAccess() {
return false;
@@ -211,7 +236,6 @@ public interface DataManager {
* Serializes your data into an NBT tag. This is used when saving the chunk to disk.
*/
@Contract(mutates = "param2")
@StableAPI.Expose
void writeChunkToNBT(Chunk chunk, NBTTagCompound nbt);
@@ -222,7 +246,6 @@ public interface DataManager {
* In this case, you should initialize the data to a sane default.
*/
@Contract(mutates = "param1")
@StableAPI.Expose
void readChunkFromNBT(Chunk chunk, NBTTagCompound nbt);
/**
@@ -232,7 +255,6 @@ public interface DataManager {
* @param to The chunk to copy data to.
*/
@Contract(mutates = "param2")
@StableAPI.Expose
void cloneChunk(Chunk from, Chunk to);
}
@@ -244,7 +266,6 @@ public interface DataManager {
* @version 0.5.0
* @since 0.5.0
*/
@StableAPI(since = "0.5.0")
interface SubChunkDataManager extends StorageDataManager {
/**
* If false, the given nbt compound will be a freshly created object that gets inserted into the actual
@@ -254,7 +275,6 @@ public interface DataManager {
*
* @implNote This is used internally for reimplementing the vanilla logic. Only change this if you know what you're doing.
*/
@StableAPI.Expose
@Contract(pure = true)
default boolean subChunkPrivilegedAccess() {
return false;
@@ -264,7 +284,6 @@ public interface DataManager {
* Serializes your data into an NBT tag. This is used when saving the chunk to disk.
*/
@Contract(mutates = "param3")
@StableAPI.Expose
void writeSubChunkToNBT(Chunk chunk, ExtendedBlockStorage subChunk, NBTTagCompound nbt);
/**
@@ -274,7 +293,6 @@ public interface DataManager {
* In this case, you should initialize the data to a sane default.
*/
@Contract(mutates = "param2")
@StableAPI.Expose
void readSubChunkFromNBT(Chunk chunk, ExtendedBlockStorage subChunk, NBTTagCompound nbt);
/**
@@ -285,7 +303,6 @@ public interface DataManager {
* @param to The subChunk to copy data to.
*/
@Contract(mutates = "param3")
@StableAPI.Expose
void cloneSubChunk(Chunk fromChunk, ExtendedBlockStorage from, ExtendedBlockStorage to);
}
}
@@ -23,7 +23,7 @@
package com.falsepattern.chunk.api;
import com.falsepattern.chunk.internal.DataRegistryImpl;
import com.falsepattern.lib.StableAPI;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Unmodifiable;
@@ -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.
@@ -42,19 +43,42 @@ import java.util.Set;
* @see DataManager
* @since 0.5.0
*/
@StableAPI(since = "0.5.0")
@ApiStatus.NonExtendable
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.
*/
@StableAPI.Expose
@Deprecated
public static void registerDataManager(DataManager manager) throws IllegalStateException, IllegalArgumentException {
DataRegistryImpl.registerDataManager(manager);
DataRegistryImpl.registerDataManager(manager, 0);
}
/**
@@ -64,7 +88,6 @@ public class DataRegistry {
*
* @throws IllegalStateException If the disable stage is over.
*/
@StableAPI.Expose
public static void disableDataManager(String domain, String id) throws IllegalStateException {
DataRegistryImpl.disableDataManager(domain, id);
}
@@ -74,11 +97,22 @@ public class DataRegistry {
* The id of a manager is its domain and id separated by a colon. (domain:id)
*/
@Contract(pure = true)
@StableAPI.Expose
@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!!
@@ -87,7 +121,6 @@ public class DataRegistry {
* @param to The chunk to write the data to
*/
@Contract(mutates = "param2")
@StableAPI.Expose(since = "0.5.0")
public static void cloneChunk(Chunk from, Chunk to) {
DataRegistryImpl.cloneChunk(from, to);
}
@@ -100,7 +133,6 @@ public class DataRegistry {
* @param to The subChunk to write the data to
*/
@Contract(mutates = "param3")
@StableAPI.Expose(since = "0.5.0")
public static void cloneSubChunk(Chunk fromChunk, ExtendedBlockStorage from, ExtendedBlockStorage to) {
DataRegistryImpl.cloneSubChunk(fromChunk, from, to);
}
@@ -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);
}
}
@@ -21,12 +21,10 @@
*/
/**
* This is an API package covered by the additional permissions in the license.
* <p>
* This package contains the classes that you will use to interact with the ChunkAPI library.
*
* @author FalsePattern
* @version 0.5.0
* @version 0.6.0
* @since 0.5.0
*/
package com.falsepattern.chunk.api;
package com.falsepattern.chunk.api;
@@ -36,17 +36,16 @@ import cpw.mods.fml.common.event.FMLInitializationEvent;
@Mod(modid = Tags.MOD_ID,
version = Tags.MOD_VERSION,
name = Tags.MOD_NAME,
acceptedMinecraftVersions = "[1.7.10]",
dependencies = "required-after:falsepatternlib@[1.5.9,);")
acceptedMinecraftVersions = "[1.7.10]")
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,17 +49,24 @@ 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<CubicPacketManagerInfo> cubicPacketManagers = 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;
private static int maxPacketSizeCubic = 4;
@Data
private static class PacketManagerInfo {
@@ -66,12 +74,18 @@ public class DataRegistryImpl {
public final DataManager.PacketDataManager manager;
}
public static void registerDataManager(DataManager manager) throws IllegalStateException, IllegalArgumentException {
@Data
private static class CubicPacketManagerInfo {
public final int maxPacketSize;
public final DataManager.CubicPacketDataManager manager;
}
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 +94,33 @@ 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.CubicPacketDataManager) {
val cubicPacketManager = (DataManager.CubicPacketDataManager) manager;
val maxSize = cubicPacketManager.maxPacketSizeCubic();
maxPacketSizeCubic += 4 + id.getBytes(StandardCharsets.UTF_8).length + 4 + maxSize;
cubicPacketManagers.put(ord, new CubicPacketManagerInfo(maxSize, cubicPacketManager));
}
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 +132,23 @@ 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);
if (cubicPacketManagers.containsKey(ord)) {
val removed = cubicPacketManagers.remove(ord);
maxPacketSizeCubic -= 4 + id.getBytes(StandardCharsets.UTF_8).length + 4 + removed.maxPacketSize;
}
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.
@@ -130,6 +159,10 @@ public class DataRegistryImpl {
return maxPacketSize;
}
public static int maxPacketSizeCubic() {
return maxPacketSizeCubic;
}
private static void writeString(ByteBuffer buffer, String string) {
val bytes = string.getBytes();
buffer.putInt(bytes.length);
@@ -166,14 +199,37 @@ public class DataRegistryImpl {
}
}
public static void readFromBufferCubic(Chunk chunk, ExtendedBlockStorage blockStorage, byte[] data) {
val buf = ByteBuffer.wrap(data);
buf.order(ByteOrder.LITTLE_ENDIAN);
int count = buf.getInt();
for (int i = 0; i < count; i++) {
val id = readString(buf);
val length = buf.getInt();
val managerInfo = cubicPacketManagers.get(id);
if (managerInfo == null) {
Common.LOG.error("Received data for unknown CubicPacketDataManager " + id + ". Skipping.");
buf.position(buf.position() + length);
continue;
}
if (length > managerInfo.maxPacketSize) {
Common.LOG.error("Received packet larger than max size for CubicPacketDataManager " + id + "! Continuing anyways, things might break!");
}
int start = buf.position();
val slice = createSlice(buf, start, length);
managerInfo.manager.readFromBuffer(chunk, blockStorage, slice);
buf.position(start + length);
}
}
public static int writeToBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, byte[] data) {
val buf = ByteBuffer.wrap(data);
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);
@@ -184,6 +240,24 @@ public class DataRegistryImpl {
return buf.position();
}
public static int writeToBufferCubic(Chunk chunk, ExtendedBlockStorage blockStorage, byte[] data) {
val buf = ByteBuffer.wrap(data);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putInt(cubicPacketManagers.size());
for (val pair : cubicPacketManagers.entrySet()) {
val ord = pair.getKey();
val managerInfo = pair.getValue();
writeString(buf, ord.id);
int start = buf.position() + 4;
val slice = createSlice(buf, start, managerInfo.maxPacketSize);
managerInfo.manager.writeToBuffer(chunk, blockStorage, slice);
int length = slice.position();
buf.putInt(length);
buf.position(start + length);
}
return buf.position();
}
public static void writeBlockToPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet) {
for (val manager : blockPacketManagers.values()) {
manager.writeBlockToPacket(chunk, x, y, z, packet);
@@ -199,9 +273,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 +374,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) {
@@ -335,11 +413,14 @@ public class DataRegistryImpl {
StartupQuery.abort();
}
try {
ZipperUtil.backupWorld();
} catch (IOException e) {
StartupQuery.notify("The world backup couldn't be created.\n\n" + e);
StartupQuery.abort();
String skip = System.getProperty("fml.doNotBackup");
if (skip == null || !"true".equals(skip)) {
try {
ZipperUtil.backupWorld();
} catch (IOException e) {
StartupQuery.notify("The world backup couldn't be created.\n\n" + e);
StartupQuery.abort();
}
}
}
}
@@ -349,7 +430,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 +453,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 +500,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 +518,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();
}
}
@@ -23,13 +23,19 @@
package com.falsepattern.chunk.internal.core;
import com.falsepattern.chunk.internal.Tags;
import com.falsepattern.chunk.internal.mixin.plugin.Mixin;
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@IFMLLoadingPlugin.TransformerExclusions(Tags.ROOT_PKG + ".internal.core")
public class CoreLoadingPlugin implements IFMLLoadingPlugin {
public class CoreLoadingPlugin implements IFMLLoadingPlugin, IEarlyMixinLoader {
@Override
public String[] getASMTransformerClass() {
return new String[0];
@@ -54,4 +60,14 @@ public class CoreLoadingPlugin implements IFMLLoadingPlugin {
public String getAccessTransformerClass() {
return null;
}
@Override
public String getMixinConfig() {
return "mixins.chunkapi.early.json";
}
@Override
public List<String> getMixins(Set<String> loadedCoreMods) {
return IMixins.getEarlyMixins(Mixin.class, loadedCoreMods);
}
}
@@ -0,0 +1,26 @@
/*
* 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/>.
*/
@ApiStatus.Internal
package com.falsepattern.chunk.internal.core;
import org.jetbrains.annotations.ApiStatus;
@@ -0,0 +1,26 @@
/*
* 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/>.
*/
@ApiStatus.Internal
package com.falsepattern.chunk.internal.impl;
import org.jetbrains.annotations.ApiStatus;
@@ -0,0 +1,26 @@
/*
* 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/>.
*/
@ApiStatus.Internal
package com.falsepattern.chunk.internal.mixin.helpers;
import org.jetbrains.annotations.ApiStatus;
@@ -20,7 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
package com.falsepattern.chunk.internal.mixin.mixins.common.base;
import com.falsepattern.chunk.internal.DataRegistryImpl;
import lombok.val;
@@ -20,7 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
package com.falsepattern.chunk.internal.mixin.mixins.common.base;
import com.falsepattern.chunk.internal.impl.CustomPacketMultiBlockChange;
import lombok.val;
@@ -20,7 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
package com.falsepattern.chunk.internal.mixin.mixins.common.base;
import com.falsepattern.chunk.internal.DataRegistryImpl;
import com.falsepattern.chunk.internal.mixin.helpers.LockHelper;
@@ -20,7 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
package com.falsepattern.chunk.internal.mixin.mixins.common.base;
import com.falsepattern.chunk.internal.DataRegistryImpl;
import com.falsepattern.chunk.internal.impl.CustomPacketBlockChange;
@@ -20,7 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
package com.falsepattern.chunk.internal.mixin.mixins.common.base;
import com.falsepattern.chunk.internal.BlockPosUtil;
import com.falsepattern.chunk.internal.DataRegistryImpl;
@@ -0,0 +1,155 @@
/*
* ChunkAPI
*
* Copyright (C) 2023-2025 FalsePattern, The MEGA Team, LegacyModdingMC contributors
* Copyright (C) 2025 Cardinalstar16
* 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.mixin.mixins.common.thermos;
import com.falsepattern.chunk.internal.mixin.helpers.LockHelper;
import lombok.val;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.server.S21PacketChunkData;
import net.minecraft.network.play.server.S26PacketMapChunkBulk;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@Mixin(S26PacketMapChunkBulk.class)
public abstract class S26PacketMapChunkBulkMixin {
@Shadow(aliases = "field_149268_i",
remap = false)
private byte[] inflaterBuffer;
@Shadow(aliases = "field_149263_e",
remap = false)
private byte[] deflatedData;
@Shadow(aliases = "field_149266_a",
remap = false)
private int[] xPositions;
@Shadow(aliases = "field_149264_b",
remap = false)
private int[] zPositions;
@Shadow(aliases = "field_149265_c",
remap = false)
private int[] subChunkMasks;
@Shadow(aliases = "field_149262_d",
remap = false)
private int[] subChunkMSBMasks;
@Shadow(aliases = "field_149261_g",
remap = false)
private int deflatedSize;
@Shadow(aliases = "field_149267_h",
remap = false)
private boolean skylight;
@Shadow(aliases = "field_149260_f",
remap = false)
private byte[][] datas;
@Shadow(remap = false)
protected abstract void compress();
/**
* @author FalsePattern
* @reason Replace functionality
*/
@Overwrite
public void readPacketData(PacketBuffer data) throws IOException {
short chunkCount = data.readShort();
val sizes = new int[chunkCount];
for (int i = 0; i < chunkCount; i++) {
sizes[i] = data.readInt();
}
deflatedSize = data.readInt();
skylight = data.readBoolean();
xPositions = new int[chunkCount];
zPositions = new int[chunkCount];
subChunkMasks = new int[chunkCount];
subChunkMSBMasks = new int[chunkCount];
datas = new byte[chunkCount][];
while (!LockHelper.bufferLockS26PacketMapChunkBulk.tryLock()) {
Thread.yield();
}
byte[] buf;
try {
if (inflaterBuffer.length < deflatedSize) {
inflaterBuffer = new byte[deflatedSize];
}
data.readBytes(inflaterBuffer, 0, deflatedSize);
buf = new byte[S21PacketChunkData.func_149275_c() * chunkCount];
Inflater inflater = new Inflater();
inflater.setInput(inflaterBuffer, 0, deflatedSize);
try {
inflater.inflate(buf);
} catch (DataFormatException dataformatexception) {
throw new IOException("Bad compressed data format");
} finally {
inflater.end();
}
} finally {
LockHelper.bufferLockS26PacketMapChunkBulk.unlock();
}
int pos = 0;
for (int i = 0; i < chunkCount; ++i) {
val size = sizes[i];
xPositions[i] = data.readInt();
zPositions[i] = data.readInt();
subChunkMasks[i] = data.readUnsignedShort();
datas[i] = new byte[size];
System.arraycopy(buf, pos, datas[i], 0, size);
pos += size;
}
}
/**
* @author FalsePattern
* @author Cardinalstar16
* @reason Replace functionality for thermos
*/
@Overwrite
public void writePacketData(PacketBuffer data) {
compress();
data.writeShort(xPositions.length);
for (byte[] bytes : datas) {
data.writeInt(bytes.length);
}
data.writeInt(deflatedSize);
data.writeBoolean(skylight);
data.writeBytes(deflatedData, 0, deflatedSize);
for (int i = 0; i < xPositions.length; ++i) {
data.writeInt(xPositions[i]);
data.writeInt(zPositions[i]);
data.writeShort((short) (subChunkMasks[i] & 65535));
}
}
}
@@ -129,7 +129,7 @@ public abstract class S26PacketMapChunkBulkMixin {
pos += size;
}
}
/**
* @author FalsePattern
* @reason Replace functionality
@@ -22,24 +22,23 @@
package com.falsepattern.chunk.internal.mixin.plugin;
import com.falsepattern.chunk.internal.Tags;
import com.falsepattern.lib.mixin.IMixin;
import com.falsepattern.lib.mixin.IMixinPlugin;
import com.falsepattern.lib.mixin.ITargetedMod;
import lombok.Getter;
import org.apache.logging.log4j.Logger;
import com.gtnewhorizon.gtnhmixins.ILateMixinLoader;
import com.gtnewhorizon.gtnhmixins.LateMixin;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import org.jetbrains.annotations.NotNull;
public class MixinPlugin implements IMixinPlugin {
@Getter
private final Logger logger = IMixinPlugin.createLogger(Tags.MOD_NAME);
import java.util.List;
import java.util.Set;
@LateMixin
public class LateMixins implements ILateMixinLoader {
@Override
public ITargetedMod[] getTargetedModEnumValues() {
return TargetedMod.values();
public String getMixinConfig() {
return "mixins.chunkapi.late.json";
}
@Override
public IMixin[] getMixinEnumValues() {
return Mixin.values();
public @NotNull List<String> getMixins(Set<String> loadedMods) {
return IMixins.getLateMixins(Mixin.class, loadedMods);
}
}
@@ -22,41 +22,111 @@
package com.falsepattern.chunk.internal.mixin.plugin;
import com.falsepattern.lib.mixin.IMixin;
import com.falsepattern.lib.mixin.ITargetedMod;
import com.falsepattern.chunk.internal.Tags;
import com.falsepattern.chunk.internal.mixin.plugin.fplib.MixinHelper;
import com.falsepattern.chunk.internal.mixin.plugin.fplib.SidedMixins;
import com.falsepattern.chunk.internal.mixin.plugin.fplib.TaggedMod;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import com.gtnewhorizon.gtnhmixins.builders.MixinBuilder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.intellij.lang.annotations.Language;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.BooleanSupplier;
import static com.falsepattern.lib.mixin.IMixin.PredicateHelpers.always;
import static com.falsepattern.lib.mixin.IMixin.PredicateHelpers.require;
import static com.falsepattern.chunk.internal.mixin.plugin.TargetMod.LookingGlass;
import static com.falsepattern.chunk.internal.mixin.plugin.TargetMod.Spool;
import static com.falsepattern.chunk.internal.mixin.plugin.fplib.MixinHelper.avoid;
import static com.falsepattern.chunk.internal.mixin.plugin.fplib.MixinHelper.builder;
import static com.falsepattern.chunk.internal.mixin.plugin.fplib.MixinHelper.mods;
import static com.falsepattern.chunk.internal.mixin.plugin.fplib.MixinHelper.require;
@RequiredArgsConstructor
public enum Mixin implements IMixin {
public enum Mixin implements IMixins {
// @formatter:off
AnvilChunkLoaderMixin(Side.COMMON, always(), "vanilla.AnvilChunkLoaderMixin"),
PlayerInstanceMixin(Side.COMMON, always(), "vanilla.PlayerInstanceMixin"),
S21PacketChunkDataMixin(Side.COMMON, always(), "vanilla.S21PacketChunkDataMixin"),
S22PacketMultiBlockChangeMixin(Side.COMMON, always(), "vanilla.S22PacketMultiBlockChangeMixin"),
S23PacketBlockChangeMixin(Side.COMMON, always(), "vanilla.S23PacketBlockChangeMixin"),
S26PacketMapChunkBulkMixin(Side.COMMON, always(), "vanilla.S26PacketMapChunkBulkMixin"),
VanillaCore(Phase.EARLY,
() -> !hasThermos(),
common("vanilla.S26PacketMapChunkBulkMixin")),
ThermosCore(Phase.EARLY,
() -> hasThermos(),
common("thermos.S26PacketMapChunkBulkMixin")),
CommonCore(Phase.EARLY,
common("base.PlayerInstanceMixin",
"base.S21PacketChunkDataMixin",
"base.S22PacketMultiBlockChangeMixin",
"base.S23PacketBlockChangeMixin"),
client("vanilla.NetHandlerPlayClientMixin")),
//from: https://github.com/BallOfEnergy1/ChunkAPI/commit/4f5c0e60e04b6892d206f5f5d93cb20ba6b45608
Core_NoSpool(Phase.EARLY,
avoid(Spool),
common("base.AnvilChunkLoaderMixin"),
client("vanilla.ChunkMixin")),
ChunkMixin(Side.CLIENT, always(), "vanilla.ChunkMixin"),
NetHandlerPlayClientMixin(Side.CLIENT, always(), "vanilla.NetHandlerPlayClientMixin"),
//region Looking Glass
PacketChunkInfoMixin(Side.COMMON, require(TargetedMod.LOOKINGGLASS), "lookingglass.PacketChunkInfoMixin"),
//endregion
;
Compat_LookingGlass(Phase.LATE,
require(LookingGlass),
common("lookingglass.PacketChunkInfoMixin")),
// @formatter:on
//region boilerplate
;
@Getter
private final Side side;
@Getter
private final Predicate<List<ITargetedMod>> filter;
@Getter
private final String mixin;
}
private final MixinBuilder builder;
Mixin(Phase phase, SidedMixins... mixins) {
this(builder(mixins).setPhase(phase));
}
Mixin(Phase phase, BooleanSupplier cond, SidedMixins... mixins) {
this(builder(cond, mixins).setPhase(phase));
}
Mixin(Phase phase, TaggedMod mod, SidedMixins... mixins) {
this(builder(mod, mixins).setPhase(phase));
}
Mixin(Phase phase, TaggedMod[] mods, SidedMixins... mixins) {
this(builder(mods, mixins).setPhase(phase));
}
Mixin(Phase phase, BooleanSupplier cond, TaggedMod mod, SidedMixins... mixins) {
this(builder(cond, mod, mixins).setPhase(phase));
}
Mixin(Phase phase, BooleanSupplier cond, TaggedMod[] mods, SidedMixins... mixins) {
this(builder(cond, mods, mixins).setPhase(phase));
}
private static SidedMixins common(@Language(value = "JAVA",
prefix = "import " + Tags.ROOT_PKG + ".internal.mixin.mixins.common.",
suffix = ";") String... mixins) {
return MixinHelper.common(mixins);
}
private static SidedMixins client(@Language(value = "JAVA",
prefix = "import " + Tags.ROOT_PKG + ".internal.mixin.mixins.client.",
suffix = ";") String... mixins) {
return MixinHelper.client(mixins);
}
private static SidedMixins server(@Language(value = "JAVA",
prefix = "import " + Tags.ROOT_PKG + ".mixin.mixins.server.",
suffix = ";") String... mixins) {
return MixinHelper.server(mixins);
}
//endregion
static boolean hasThermos()
{
try
{
Class.forName("thermos.ThermosClassTransformer");
return true;
}
catch(ClassNotFoundException ignored) {
return false;
}
}
}
@@ -0,0 +1,56 @@
/*
* 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.mixin.plugin;
import com.gtnewhorizon.gtnhmixins.builders.ITargetMod;
import com.gtnewhorizon.gtnhmixins.builders.TargetModBuilder;
import lombok.Getter;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
public enum TargetMod implements ITargetMod {
LookingGlass("com.xcompwiz.lookingglass.LookingGlass"),
Spool("com.gamma.spool.core.Spool"),
;
@Getter
private final TargetModBuilder builder;
TargetMod(@Language(value = "JAVA",
prefix = "import ",
suffix = ";") @NotNull String className) {
this(className, null);
}
TargetMod(@Language(value = "JAVA",
prefix = "import ",
suffix = ";") @NotNull String className, @Nullable Consumer<TargetModBuilder> cfg) {
builder = new TargetModBuilder();
builder.setTargetClass(className);
if (cfg != null) {
cfg.accept(builder);
}
}
}
@@ -0,0 +1,112 @@
/*
* This file is part of FalsePatternLib.
*
* Copyright (C) 2022-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalsePatternLib 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.
*
* FalsePatternLib 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 FalsePatternLib. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.plugin.fplib;
import com.gtnewhorizon.gtnhmixins.builders.IBaseTransformer;
import com.gtnewhorizon.gtnhmixins.builders.ITargetMod;
import com.gtnewhorizon.gtnhmixins.builders.MixinBuilder;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BooleanSupplier;
public class MixinHelper {
public static @NotNull MixinBuilder builder(@NotNull SidedMixins @NotNull ... mixins) {
return builderImpl(null, null, mixins);
}
public static @NotNull MixinBuilder builder(@Nullable BooleanSupplier cond, @NotNull SidedMixins @NotNull ... mixins) {
return builderImpl(cond, null, mixins);
}
public static @NotNull MixinBuilder builder(@NotNull TaggedMod mod, @NotNull SidedMixins @NotNull ... mixins) {
return builderImpl(null, mods(mod), mixins);
}
public static @NotNull MixinBuilder builder(@NotNull TaggedMod @Nullable [] mods, @NotNull SidedMixins @NotNull ... mixins) {
return builderImpl(null, mods, mixins);
}
public static @NotNull MixinBuilder builder(@NotNull BooleanSupplier cond, @NotNull TaggedMod mod, @NotNull SidedMixins @NotNull ... mixins) {
return builderImpl(cond, mods(mod), mixins);
}
public static @NotNull MixinBuilder builder(@NotNull BooleanSupplier cond, @NotNull TaggedMod @NotNull [] mods, @NotNull SidedMixins @NotNull ... mixins) {
return builderImpl(cond, mods, mixins);
}
private static @NotNull MixinBuilder builderImpl(@Nullable BooleanSupplier cond, @NotNull TaggedMod @Nullable [] requiredMods, @NotNull SidedMixins @NotNull ... mixins) {
val builder = new MixinBuilder();
if (requiredMods != null) {
for (val mod : requiredMods) {
if (mod.require) {
builder.addRequiredMod(mod.mod);
} else {
builder.addExcludedMod(mod.mod);
}
}
}
for (val mixin : mixins) {
builder.addSidedMixins(mixin.side, mixin.mixins);
}
if (cond != null) {
builder.setApplyIf(cond::getAsBoolean);
}
return builder;
}
public static @NotNull SidedMixins common(@NotNull String @NotNull ... mixins) {
for (int i = 0; i < mixins.length; i++) {
mixins[i] = "common." + mixins[i];
}
return new SidedMixins(IBaseTransformer.Side.COMMON, mixins);
}
public static @NotNull SidedMixins client(@NotNull String @NotNull ... mixins) {
for (int i = 0; i < mixins.length; i++) {
mixins[i] = "client." + mixins[i];
}
return new SidedMixins(IBaseTransformer.Side.CLIENT, mixins);
}
public static @NotNull SidedMixins server(@NotNull String @NotNull ... mixins) {
for (int i = 0; i < mixins.length; i++) {
mixins[i] = "server." + mixins[i];
}
return new SidedMixins(IBaseTransformer.Side.SERVER, mixins);
}
public static @NotNull TaggedMod require(@NotNull ITargetMod mod) {
return new TaggedMod(true, mod);
}
public static @NotNull TaggedMod avoid(@NotNull ITargetMod mod) {
return new TaggedMod(false, mod);
}
public static @NotNull TaggedMod @NotNull [] mods(@NotNull TaggedMod @NotNull ... t) {
return t;
}
}
@@ -0,0 +1,33 @@
/*
* This file is part of FalsePatternLib.
*
* Copyright (C) 2022-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalsePatternLib 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.
*
* FalsePatternLib 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 FalsePatternLib. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.plugin.fplib;
import com.gtnewhorizon.gtnhmixins.builders.IBaseTransformer;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
@RequiredArgsConstructor
public class SidedMixins {
public final IBaseTransformer.@NotNull Side side;
public final @NotNull String @NotNull [] mixins;
}
@@ -0,0 +1,33 @@
/*
* This file is part of FalsePatternLib.
*
* Copyright (C) 2022-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalsePatternLib 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.
*
* FalsePatternLib 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 FalsePatternLib. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.plugin.fplib;
import com.gtnewhorizon.gtnhmixins.builders.ITargetMod;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
@RequiredArgsConstructor
public class TaggedMod {
public final boolean require;
public final @NotNull ITargetMod mod;
}
@@ -0,0 +1,57 @@
/*
* This file is part of FalsePatternLib.
*
* Copyright (C) 2022-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalsePatternLib 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.
*
* FalsePatternLib 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 FalsePatternLib. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.chunk.internal.mixin.plugin.fplib;
import com.gtnewhorizon.gtnhmixins.builders.ITargetMod;
import com.gtnewhorizon.gtnhmixins.builders.TargetModBuilder;
import lombok.Getter;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
public class TargetMod implements ITargetMod {
@Getter
private final TargetModBuilder builder;
private final String name;
public TargetMod(@NotNull String name, @Language(value = "JAVA", prefix = "import ", suffix = ";") @NotNull String className) {
this(name, className, null);
}
public TargetMod(@NotNull String name, @Language(value = "JAVA", prefix = "import ", suffix = ";") @NotNull String className, @Nullable Consumer<TargetModBuilder> cfg) {
this.name = name;
builder = new TargetModBuilder();
builder.setTargetClass(className);
if (cfg != null) {
cfg.accept(builder);
}
}
@Override
public String toString() {
return name;
}
}
@@ -0,0 +1,26 @@
/*
* This file is part of FalsePatternLib.
*
* Copyright (C) 2022-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalsePatternLib 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.
*
* FalsePatternLib 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 FalsePatternLib. If not, see <https://www.gnu.org/licenses/>.
*/
@ApiStatus.Internal
package com.falsepattern.chunk.internal.mixin.plugin.fplib;
import org.jetbrains.annotations.ApiStatus;
@@ -20,25 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@ApiStatus.Internal
package com.falsepattern.chunk.internal.mixin.plugin;
import com.falsepattern.lib.mixin.ITargetedMod;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.function.Predicate;
import static com.falsepattern.lib.mixin.ITargetedMod.PredicateHelpers.contains;
@RequiredArgsConstructor
public enum TargetedMod implements ITargetedMod {
LOOKINGGLASS("Looking Glass", false, contains("lookingglass-"))
;
@Getter
private final String modName;
@Getter
private final boolean loadInDevelopment;
@Getter
private final Predicate<String> condition;
}
import org.jetbrains.annotations.ApiStatus;
@@ -23,4 +23,7 @@
/**
* This package contains the internal classes of the ChunkAPI library. Do not use these classes directly.
*/
package com.falsepattern.chunk.internal;
@ApiStatus.Internal
package com.falsepattern.chunk.internal;
import org.jetbrains.annotations.ApiStatus;
@@ -40,7 +40,7 @@ import java.nio.ByteBuffer;
import static com.falsepattern.chunk.internal.Common.BLOCKS_PER_SUBCHUNK;
import static com.falsepattern.chunk.internal.Common.SUBCHUNKS_PER_CHUNK;
public class BlockIDManager extends VanillaManager implements DataManager.PacketDataManager, DataManager.BlockPacketDataManager, DataManager.SubChunkDataManager {
public class BlockIDManager extends VanillaManager implements DataManager.PacketDataManager, DataManager.CubicPacketDataManager, DataManager.BlockPacketDataManager, DataManager.SubChunkDataManager {
private static final int LSB_BYTES_PER_SUBCHUNK = BLOCKS_PER_SUBCHUNK;
private static final int MSB_BYTES_PER_SUBCHUNK = BLOCKS_PER_SUBCHUNK / 2;
private static final int HEADER_SIZE = 2;
@@ -100,6 +100,36 @@ public class BlockIDManager extends VanillaManager implements DataManager.Packet
}
}
@Override
public int maxPacketSizeCubic() {
return HEADER_SIZE + LSB_BYTES_PER_SUBCHUNK + MSB_BYTES_PER_SUBCHUNK;
}
@Override
public void writeToBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) {
buffer.put(blockStorage.getBlockLSBArray());
if (blockStorage.getBlockMSBArray() != null) {
buffer.put((byte) 1);
buffer.put(blockStorage.getBlockMSBArray().data);
} else {
buffer.put((byte) 0);
}
}
@Override
public void readFromBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) {
buffer.get(blockStorage.getBlockLSBArray());
if (buffer.get() != 0) {
if (blockStorage.getBlockMSBArray() == null) {
blockStorage.createBlockMSBArray();
}
buffer.get(blockStorage.getBlockMSBArray().data);
}
}
@Override
public boolean subChunkPrivilegedAccess() {
return true;
@@ -32,7 +32,7 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import java.nio.ByteBuffer;
public abstract class NibbleManager extends VanillaManager implements DataManager.PacketDataManager {
public abstract class NibbleManager extends VanillaManager implements DataManager.PacketDataManager, DataManager.CubicPacketDataManager {
public static final int BYTES_PER_SUBCHUNK = Common.BLOCKS_PER_SUBCHUNK / 2;
protected abstract NibbleArray getNibbleArray(ExtendedBlockStorage subChunk);
@@ -67,4 +67,19 @@ public abstract class NibbleManager extends VanillaManager implements DataManage
}
}
}
@Override
public int maxPacketSizeCubic() {
return BYTES_PER_SUBCHUNK;
}
@Override
public void writeToBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) {
buffer.put(getNibbleArray(blockStorage).data, 0, BYTES_PER_SUBCHUNK);
}
@Override
public void readFromBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) {
buffer.get(getNibbleArray(blockStorage).data, 0, BYTES_PER_SUBCHUNK);
}
}
@@ -57,6 +57,20 @@ public class SkylightManager extends NibbleManager implements DataManager.SubChu
}
}
@Override
public void writeToBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) {
if (!chunk.worldObj.provider.hasNoSky) {
super.writeToBuffer(chunk, blockStorage, buffer);
}
}
@Override
public void readFromBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) {
if (!chunk.worldObj.provider.hasNoSky) {
super.readFromBuffer(chunk, blockStorage, buffer);
}
}
@Override
public boolean subChunkPrivilegedAccess() {
return true;
@@ -0,0 +1,26 @@
/*
* 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/>.
*/
@ApiStatus.Internal
package com.falsepattern.chunk.internal.vanilla;
import org.jetbrains.annotations.ApiStatus;
@@ -2,7 +2,6 @@
"required": true,
"minVersion": "0.8.5",
"package": "com.falsepattern.chunk.internal.mixin.mixins",
"plugin": "com.falsepattern.chunk.internal.mixin.plugin.MixinPlugin",
"refmap": "mixins.chunkapi.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
@@ -0,0 +1,9 @@
{
"required": true,
"minVersion": "0.8.5",
"package": "com.falsepattern.chunk.internal.mixin.mixins",
"refmap": "mixins.chunkapi.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
}