mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-10-27 06:43:52 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31d26db5b4 | ||
|
|
2077a8da86 | ||
|
|
ba757e4237 | ||
|
|
b738e8e073 | ||
|
|
a385d29ab3 |
No files matched your search
@@ -28,3 +28,5 @@ whitelist.json
|
||||
src/main/resources/mixins.*.json
|
||||
*.bat
|
||||
.DS_Store
|
||||
|
||||
*.sh
|
||||
@@ -6,3 +6,10 @@ minecraft {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
// Add your dependencies here
|
||||
|
||||
dependencies {
|
||||
testImplementation(platform('org.junit:junit-bom:5.14.1'))
|
||||
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
|
||||
}
|
||||
@@ -180,6 +180,11 @@ modrinthRelations =
|
||||
# Leave this empty if you don't want to publish on CurseForge.
|
||||
curseForgeProjectId = 746279
|
||||
|
||||
# Comma-separated supported CurseForge environments: client, server (case-insensitive).
|
||||
# Use client or server for mods that only support one environment. Defaults to client,server.
|
||||
# These tags describe where the mod can run, not whether installation is required on both sides.
|
||||
curseForgeEnvironments = client,server
|
||||
|
||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||
# Syntax: type1:name1;type2:name2;...
|
||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1630f7ebef05444cb27a2709ea0249b3/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/d4fd992c9557644e637ebe98263e0ae7/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/59a9771cad43219260d9aac9a8ec4d6a/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a4c09dd2e2d7079373d30e524bbc2829/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/8e1d9ee5d0f13e442218f6884a306da1/redirect
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9064f22734b42ac03e85df04b632e167/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/4d0277c49991306ac78048580fe34bcf/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a9fa3b809e484a1e1ac4308a5dda661a/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/aa99913fa6d767d899ffc96082da01ca/redirect
|
||||
toolchainVersion=25
|
||||
Vendored
BIN
Binary file not shown.
+3
-1
@@ -1,7 +1,9 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
|
||||
networkTimeout=10000
|
||||
retries=0
|
||||
retryBackOffMs=500
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -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/b631911858264c0b6e4d6603d677ff5218766cee/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/.
|
||||
|
||||
Vendored
+12
-23
@@ -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,29 +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
|
||||
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -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%
|
||||
+1
-1
@@ -17,7 +17,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.24'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.30'
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,12 @@ import codechicken.lib.vec.BlockCoord;
|
||||
public class SimpleBrightnessModel implements CCRenderState.IVertexOperation {
|
||||
|
||||
public static final int operationIndex = CCRenderState.registerOperation();
|
||||
public static SimpleBrightnessModel instance = new SimpleBrightnessModel();
|
||||
private static final ThreadLocal<SimpleBrightnessModel> instances = ThreadLocal
|
||||
.withInitial(SimpleBrightnessModel::new);
|
||||
|
||||
public static SimpleBrightnessModel instance() {
|
||||
return instances.get();
|
||||
}
|
||||
|
||||
public IBlockAccess access;
|
||||
public BlockCoord pos = new BlockCoord();
|
||||
|
||||
@@ -466,7 +466,7 @@ public final class PacketCustom implements MCDataInput, MCDataOutput {
|
||||
|
||||
public FluidStack readFluidStack() {
|
||||
Fluid fluid = FluidRegistry.getFluid(readShort());
|
||||
if (fluid == null) fluid = FluidRegistry.WATER;
|
||||
if (fluid == null) return null;
|
||||
|
||||
return new FluidStack(fluid, readVarInt(), readNBTTagCompound());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
@@ -38,9 +39,9 @@ public class CCRenderState {
|
||||
return instances.get();
|
||||
}
|
||||
|
||||
private static int nextOperationIndex;
|
||||
private static volatile int nextOperationIndex;
|
||||
|
||||
public static int registerOperation() {
|
||||
public static synchronized int registerOperation() {
|
||||
return nextOperationIndex++;
|
||||
}
|
||||
|
||||
@@ -87,15 +88,52 @@ public class CCRenderState {
|
||||
int operationID();
|
||||
}
|
||||
|
||||
private static ArrayList<VertexAttribute<?>> vertexAttributes = new ArrayList<>();
|
||||
public static final class AttributeKey<T> {
|
||||
|
||||
private static int registerVertexAttribute(VertexAttribute<?> attr) {
|
||||
vertexAttributes.add(attr);
|
||||
return vertexAttributes.size() - 1;
|
||||
private static final HashMap<String, AttributeKey<?>> nameMap = new HashMap<>();
|
||||
private static final ArrayList<AttributeKey<?>> attributeKeys = new ArrayList<>();
|
||||
private static int nextLegacyId;
|
||||
|
||||
public final String name;
|
||||
public final int attributeKeyIndex;
|
||||
public final int operationIndex;
|
||||
private VertexAttribute<T> canonical;
|
||||
|
||||
private AttributeKey(String name) {
|
||||
this.name = name;
|
||||
this.attributeKeyIndex = attributeKeys.size();
|
||||
this.operationIndex = registerOperation();
|
||||
attributeKeys.add(this);
|
||||
nameMap.put(name, this);
|
||||
}
|
||||
|
||||
public static synchronized <T> AttributeKey<T> create(String name) {
|
||||
if (nameMap.containsKey(name))
|
||||
throw new IllegalArgumentException("Duplicate registration of attribute with name: " + name);
|
||||
return new AttributeKey<>(name);
|
||||
}
|
||||
|
||||
static synchronized <T> AttributeKey<T> createLegacy() {
|
||||
return new AttributeKey<>("legacy#" + nextLegacyId++);
|
||||
}
|
||||
|
||||
synchronized void setCanonical(VertexAttribute<T> attr) {
|
||||
if (canonical == null) canonical = attr;
|
||||
}
|
||||
|
||||
static synchronized AttributeKey<?> get(int index) {
|
||||
return attributeKeys.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static final AttributeKey<Vector3[]> NORMAL_KEY = AttributeKey.create("normal");
|
||||
private static final AttributeKey<int[]> COLOUR_KEY = AttributeKey.create("colour");
|
||||
private static final AttributeKey<int[]> LIGHTING_KEY = AttributeKey.create("lighting");
|
||||
private static final AttributeKey<int[]> SIDE_KEY = AttributeKey.create("side");
|
||||
private static final AttributeKey<LC[]> LC_KEY = AttributeKey.create("lc");
|
||||
|
||||
public static VertexAttribute<?> getAttribute(int index) {
|
||||
return vertexAttributes.get(index);
|
||||
return AttributeKey.get(index).canonical;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,14 +144,26 @@ public class CCRenderState {
|
||||
*/
|
||||
public abstract static class VertexAttribute<T> implements IVertexOperation {
|
||||
|
||||
public final int attributeIndex = registerVertexAttribute(this);
|
||||
private final int operationIndex = registerOperation();
|
||||
public final int attributeIndex;
|
||||
private final int operationIndex;
|
||||
/**
|
||||
* Set to true when the attrute is part of the pipeline. Should only be managed by CCRenderState when
|
||||
* constructing the pipeline
|
||||
*/
|
||||
public boolean active = false;
|
||||
|
||||
protected VertexAttribute(AttributeKey<T> key) {
|
||||
attributeIndex = key.attributeKeyIndex;
|
||||
operationIndex = key.operationIndex;
|
||||
key.setCanonical(this);
|
||||
}
|
||||
|
||||
/** @deprecated keyless attributes get a per-construction index that is threadsafe */
|
||||
@Deprecated
|
||||
protected VertexAttribute() {
|
||||
this(AttributeKey.createLegacy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new array for storage of vertex attrutes in a model
|
||||
*/
|
||||
@@ -189,7 +239,7 @@ public class CCRenderState {
|
||||
return instances.get().lightingAttrib;
|
||||
}
|
||||
|
||||
public VertexAttribute<Vector3[]> normalAttrib = new VertexAttribute<>() {
|
||||
public VertexAttribute<Vector3[]> normalAttrib = new VertexAttribute<>(NORMAL_KEY) {
|
||||
|
||||
private Vector3[] normalRef;
|
||||
|
||||
@@ -217,7 +267,7 @@ public class CCRenderState {
|
||||
else state.setNormalInstance(Rotation.axes[state.side]);
|
||||
}
|
||||
};
|
||||
public VertexAttribute<int[]> colourAttrib = new VertexAttribute<>() {
|
||||
public VertexAttribute<int[]> colourAttrib = new VertexAttribute<>(COLOUR_KEY) {
|
||||
|
||||
private int[] colourRef;
|
||||
|
||||
@@ -239,7 +289,7 @@ public class CCRenderState {
|
||||
else state.setColourInstance(state.baseColour);
|
||||
}
|
||||
};
|
||||
public VertexAttribute<int[]> lightingAttrib = new VertexAttribute<>() {
|
||||
public VertexAttribute<int[]> lightingAttrib = new VertexAttribute<>(LIGHTING_KEY) {
|
||||
|
||||
private int[] colourRef;
|
||||
|
||||
@@ -265,7 +315,7 @@ public class CCRenderState {
|
||||
state.setColourInstance(ColourRGBA.multiply(state.colour, colourRef[state.vertexIndex]));
|
||||
}
|
||||
};
|
||||
public VertexAttribute<int[]> sideAttrib = new VertexAttribute<>() {
|
||||
public VertexAttribute<int[]> sideAttrib = new VertexAttribute<>(SIDE_KEY) {
|
||||
|
||||
private int[] sideRef;
|
||||
|
||||
@@ -292,7 +342,7 @@ public class CCRenderState {
|
||||
/**
|
||||
* Uses the position of the lightmatrix to compute LC if not provided
|
||||
*/
|
||||
public VertexAttribute<LC[]> lightCoordAttrib = new VertexAttribute<>() {
|
||||
public VertexAttribute<LC[]> lightCoordAttrib = new VertexAttribute<>(LC_KEY) {
|
||||
|
||||
private LC[] lcRef;
|
||||
private final Vector3 vec = new Vector3(); // for computation
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
@@ -11,6 +13,9 @@ import codechicken.lib.vec.Vector3;
|
||||
|
||||
public class EntityDigIconFX extends EntityFX {
|
||||
|
||||
/** Tint that leaves the particle colour untouched, for materials that don't colour their texture. */
|
||||
public static final int NO_TINT = 0xFFFFFF;
|
||||
|
||||
public EntityDigIconFX(World world, double x, double y, double z, double dx, double dy, double dz, IIcon icon) {
|
||||
super(world, x, y, z, dx, dy, dz);
|
||||
particleIcon = icon;
|
||||
@@ -19,6 +24,18 @@ public class EntityDigIconFX extends EntityFX {
|
||||
particleScale /= 2.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the particle colour by an 0xRRGGBB tint, the equivalent of vanilla
|
||||
* EntityDiggingFX.applyColourMultiplier. Materials that draw a greyscale texture and colour it at render time
|
||||
* (leaves, grass tops) need this, or their particles come out flat grey.
|
||||
*/
|
||||
public EntityDigIconFX applyColourMultiplier(int colour) {
|
||||
particleRed *= (colour >> 16 & 255) / 255F;
|
||||
particleGreen *= (colour >> 8 & 255) / 255F;
|
||||
particleBlue *= (colour & 255) / 255F;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFXLayer() {
|
||||
return 1;
|
||||
@@ -90,8 +107,24 @@ public class EntityDigIconFX extends EntityFX {
|
||||
f9);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the particle is never tinted, so a material that colours a greyscale texture at render time (leaves,
|
||||
* grass tops) breaks into grey particles. Use
|
||||
* {@link #addBlockHitEffects(World, Cuboid6, int, IIcon, int, EffectRenderer)}, passing
|
||||
* {@link #NO_TINT} for materials whose texture is already coloured.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addBlockHitEffects(World world, Cuboid6 bounds, int side, IIcon icon,
|
||||
EffectRenderer effectRenderer) {
|
||||
addBlockHitEffects(world, bounds, side, icon, NO_TINT, effectRenderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a hit particle on side of bounds, tinted by colour (0xRRGGBB, {@link #NO_TINT} for none). The caller
|
||||
* resolves the tint for the side it hit, so per-face materials like grass can tint only the faces that need it.
|
||||
*/
|
||||
public static void addBlockHitEffects(World world, Cuboid6 bounds, int side, IIcon icon, int colour,
|
||||
EffectRenderer effectRenderer) {
|
||||
float border = 0.1F;
|
||||
Vector3 diff = bounds.max.copy().subtract(bounds.min).add(-2 * border);
|
||||
diff.x *= world.rand.nextDouble();
|
||||
@@ -106,13 +139,34 @@ public class EntityDigIconFX extends EntityFX {
|
||||
if (side == 4) diff.x = bounds.min.x - border;
|
||||
if (side == 5) diff.x = bounds.max.x + border;
|
||||
|
||||
effectRenderer.addEffect(
|
||||
new EntityDigIconFX(world, pos.x, pos.y, pos.z, 0, 0, 0, icon).multiplyVelocity(0.2F)
|
||||
.multipleParticleScaleBy(0.6F));
|
||||
EntityDigIconFX fx = new EntityDigIconFX(world, pos.x, pos.y, pos.z, 0, 0, 0, icon);
|
||||
effectRenderer.addEffect(fx.applyColourMultiplier(colour).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the particles are never tinted, so a material that colours a greyscale texture at render time
|
||||
* (leaves, grass tops) breaks into grey particles. Use
|
||||
* {@link #addBlockDestroyEffects(World, Cuboid6, IIcon[], int[], EffectRenderer)}, passing
|
||||
* {@link #NO_TINT} for the faces whose texture is already coloured.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addBlockDestroyEffects(World world, Cuboid6 bounds, IIcon[] icons,
|
||||
EffectRenderer effectRenderer) {
|
||||
int[] colours = new int[icons.length];
|
||||
Arrays.fill(colours, NO_TINT);
|
||||
addBlockDestroyEffects(world, bounds, icons, colours, effectRenderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns break particles filling bounds, each drawn from a random face. colours holds the 0xRRGGBB tint for the
|
||||
* matching entry of icons ({@link #NO_TINT} for none) and must be the same length, so a particle is tinted by the
|
||||
* face it was taken from.
|
||||
*/
|
||||
public static void addBlockDestroyEffects(World world, Cuboid6 bounds, IIcon[] icons, int[] colours,
|
||||
EffectRenderer effectRenderer) {
|
||||
if (icons.length != colours.length)
|
||||
throw new IllegalArgumentException("icons and colours must have the same length");
|
||||
|
||||
Vector3 diff = bounds.max.copy().subtract(bounds.min);
|
||||
Vector3 center = bounds.min.copy().add(bounds.max).multiply(0.5);
|
||||
Vector3 density = diff.copy().multiply(4);
|
||||
@@ -121,19 +175,20 @@ public class EntityDigIconFX extends EntityFX {
|
||||
density.z = Math.ceil(density.z);
|
||||
|
||||
for (int i = 0; i < density.x; ++i) for (int j = 0; j < density.y; ++j) for (int k = 0; k < density.z; ++k) {
|
||||
double x = bounds.min.x + (i + 0.5) * diff.x / density.x;
|
||||
double y = bounds.min.y + (j + 0.5) * diff.y / density.y;
|
||||
double z = bounds.min.z + (k + 0.5) * diff.z / density.z;
|
||||
effectRenderer.addEffect(
|
||||
new EntityDigIconFX(
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
x - center.x,
|
||||
y - center.y,
|
||||
z - center.z,
|
||||
icons[world.rand.nextInt(icons.length)]));
|
||||
double px = bounds.min.x + (i + 0.5) * diff.x / density.x;
|
||||
double py = bounds.min.y + (j + 0.5) * diff.y / density.y;
|
||||
double pz = bounds.min.z + (k + 0.5) * diff.z / density.z;
|
||||
int iconSide = world.rand.nextInt(icons.length);
|
||||
EntityDigIconFX fx = new EntityDigIconFX(
|
||||
world,
|
||||
px,
|
||||
py,
|
||||
pz,
|
||||
px - center.x,
|
||||
py - center.y,
|
||||
pz - center.z,
|
||||
icons[iconSide]);
|
||||
effectRenderer.addEffect(fx.applyColourMultiplier(colours[iconSide]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,10 @@ public class WorldExtensionManager {
|
||||
public void onChunkUnLoad(ChunkEvent.Unload event) {
|
||||
if (event.getChunk() instanceof EmptyChunk) return;
|
||||
|
||||
for (WorldExtension extension : worldMap.get(event.world)) extension.unloadChunk(event.getChunk());
|
||||
WorldExtension[] extensions = worldMap.get(event.world);
|
||||
if (extensions == null) return;
|
||||
|
||||
for (WorldExtension extension : extensions) extension.unloadChunk(event.getChunk());
|
||||
|
||||
if (event.world.isRemote) removeChunk(event.world, event.getChunk());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
public class CCRenderStateThreadingTest {
|
||||
|
||||
private static int[] attribIndices() {
|
||||
return new int[] { CCRenderState.normalAttrib().attributeIndex, CCRenderState.colourAttrib().attributeIndex,
|
||||
CCRenderState.lightingAttrib().attributeIndex, CCRenderState.sideAttrib().attributeIndex,
|
||||
CCRenderState.lightCoordAttrib().attributeIndex };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attributeIndicesStableAcrossThreads() throws Exception {
|
||||
int[] main = attribIndices();
|
||||
assertEquals(5, Arrays.stream(main).distinct().count());
|
||||
|
||||
ExecutorService pool = Executors.newFixedThreadPool(8);
|
||||
try {
|
||||
List<Future<int[]>> futures = new ArrayList<>();
|
||||
for (int i = 0; i < 8; i++) futures.add(pool.submit(CCRenderStateThreadingTest::attribIndices));
|
||||
for (Future<int[]> f : futures) assertArrayEquals(main, f.get(10, TimeUnit.SECONDS));
|
||||
} finally {
|
||||
pool.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modelBakedOnOneThreadIsReadableOnAnother() throws Exception {
|
||||
ExecutorService bakeThread = Executors.newSingleThreadExecutor();
|
||||
ExecutorService renderThread = Executors.newSingleThreadExecutor();
|
||||
try {
|
||||
CCModel model = bakeThread.submit(() -> {
|
||||
CCModel m = CCModel.quadModel(4);
|
||||
m.verts[0] = new Vertex5(0, 1, 0, 0, 0);
|
||||
m.verts[1] = new Vertex5(0, 1, 1, 0, 1);
|
||||
m.verts[2] = new Vertex5(1, 1, 1, 1, 1);
|
||||
m.verts[3] = new Vertex5(1, 1, 0, 1, 0);
|
||||
return m.computeNormals();
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
|
||||
int side = renderThread.submit(() -> {
|
||||
assertTrue(
|
||||
model.hasAttribute(CCRenderState.normalAttrib()),
|
||||
"normals baked on another thread not visible under this thread's attributeIndex");
|
||||
Vector3[] normals = model.getAttributes(CCRenderState.normalAttrib());
|
||||
assertNotNull(normals);
|
||||
return CCModel.findSide(normals[0]);
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(1, side);
|
||||
assertEquals(1, CCModel.findSide(model.getAttributes(CCRenderState.normalAttrib())[0]));
|
||||
} finally {
|
||||
bakeThread.shutdownNow();
|
||||
renderThread.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void concurrentFirstUseKeepsIndicesConsistent() throws Exception {
|
||||
int threads = 16;
|
||||
CyclicBarrier barrier = new CyclicBarrier(threads);
|
||||
ExecutorService pool = Executors.newFixedThreadPool(threads);
|
||||
try {
|
||||
List<Future<int[]>> futures = new ArrayList<>();
|
||||
for (int i = 0; i < threads; i++) futures.add(pool.submit(() -> {
|
||||
barrier.await(10, TimeUnit.SECONDS);
|
||||
return attribIndices();
|
||||
}));
|
||||
int[] expected = attribIndices();
|
||||
for (Future<int[]> f : futures) assertArrayEquals(expected, f.get(10, TimeUnit.SECONDS));
|
||||
} finally {
|
||||
pool.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeReturnsCanonicalForIndex() {
|
||||
int normalIndex = CCRenderState.normalAttrib().attributeIndex;
|
||||
CCRenderState.VertexAttribute<?> canonical = CCRenderState.getAttribute(normalIndex);
|
||||
assertNotNull(canonical);
|
||||
assertEquals(normalIndex, canonical.attributeIndex);
|
||||
assertSame(canonical, CCRenderState.getAttribute(normalIndex));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EntityDigIconFXTest {
|
||||
|
||||
@Test
|
||||
public void rejectsMismatchedIconAndColourCountsBeforeSpawning() {
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> EntityDigIconFX.addBlockDestroyEffects(null, null, new IIcon[1], new int[0], null));
|
||||
|
||||
assertEquals("icons and colours must have the same length", exception.getMessage());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user