mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-29 04:47:39 +00:00
Initial update to 1.21.10
This commit is contained in:
@@ -25,6 +25,7 @@ repositories {
|
|||||||
name = "Fabric"
|
name = "Fabric"
|
||||||
content {
|
content {
|
||||||
includeGroup("net.fabricmc")
|
includeGroup("net.fabricmc")
|
||||||
|
includeGroup("net.fabricmc.unpick")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,4 +15,4 @@ isUnstable=true
|
|||||||
modVersion=1.116.1
|
modVersion=1.116.1
|
||||||
|
|
||||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||||
mcVersion=1.21.8
|
mcVersion=1.21.10
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
# Minecraft
|
# Minecraft
|
||||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||||
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
||||||
fabric-api = "0.129.0+1.21.8"
|
fabric-api = "0.135.0+1.21.10"
|
||||||
fabric-loader = "0.16.14"
|
fabric-loader = "0.17.3"
|
||||||
neoForge = "21.8.0-beta"
|
neoForge = "21.10.6-beta"
|
||||||
neoMergeTool = "2.0.0"
|
neoMergeTool = "2.0.0"
|
||||||
mixin = "0.8.5"
|
mixin = "0.8.5"
|
||||||
parchment = "2025.06.29"
|
parchment = "2025.10.12"
|
||||||
parchmentMc = "1.21.6"
|
parchmentMc = "1.21.10"
|
||||||
yarn = "1.21.7+build.1"
|
yarn = "1.21.10+build.2"
|
||||||
|
|
||||||
# Core dependencies (these versions are tied to the version Minecraft uses)
|
# Core dependencies (these versions are tied to the version Minecraft uses)
|
||||||
fastutil = "8.5.15"
|
fastutil = "8.5.15"
|
||||||
@@ -62,20 +62,20 @@ cctJavadoc = "1.8.5"
|
|||||||
checkstyle = "10.23.1"
|
checkstyle = "10.23.1"
|
||||||
errorProne-core = "2.38.0"
|
errorProne-core = "2.38.0"
|
||||||
errorProne-plugin = "4.1.0"
|
errorProne-plugin = "4.1.0"
|
||||||
fabric-loom = "1.10.4"
|
fabric-loom = "1.11.8"
|
||||||
githubRelease = "2.5.2"
|
githubRelease = "2.5.2"
|
||||||
gradleVersions = "0.50.0"
|
gradleVersions = "0.50.0"
|
||||||
ideaExt = "1.1.7"
|
ideaExt = "1.1.7"
|
||||||
illuaminate = "0.1.0-83-g1131f68"
|
illuaminate = "0.1.0-83-g1131f68"
|
||||||
lwjgl = "3.3.3"
|
lwjgl = "3.3.3"
|
||||||
minotaur = "2.8.7"
|
minotaur = "2.8.7"
|
||||||
modDevGradle = "2.0.99"
|
modDevGradle = "2.0.113"
|
||||||
nullAway = "0.12.7"
|
nullAway = "0.12.7"
|
||||||
shadow = "8.3.1"
|
shadow = "8.3.1"
|
||||||
spotless = "7.0.2"
|
spotless = "7.0.2"
|
||||||
taskTree = "2.1.1"
|
taskTree = "2.1.1"
|
||||||
teavm = "0.13.0-SQUID.1"
|
teavm = "0.13.0-SQUID.1"
|
||||||
vanillaExtract = "0.2.1"
|
vanillaExtract = "0.3.0"
|
||||||
versionCatalogUpdate = "0.8.1"
|
versionCatalogUpdate = "0.8.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
6
gradlew
vendored
6
gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -205,7 +205,7 @@ fi
|
|||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# and any embedded shellness will be escaped.
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-classpath "$CLASSPATH" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
|||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%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" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -6,12 +6,15 @@ package dan200.computercraft.api.client;
|
|||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.Sheets;
|
import net.minecraft.client.renderer.Sheets;
|
||||||
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||||
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||||
import net.minecraft.client.renderer.item.ItemModel;
|
import net.minecraft.client.renderer.item.ItemModel;
|
||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
@@ -19,10 +22,11 @@ import net.minecraft.client.renderer.item.ItemStackRenderState;
|
|||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
import net.minecraft.client.resources.model.BlockModelRotation;
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
import net.minecraft.client.resources.model.ModelBaker;
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.client.resources.model.ModelBakery;
|
||||||
import net.minecraft.client.resources.model.ResolvedModel;
|
import net.minecraft.client.resources.model.ResolvedModel;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.ARGB;
|
import net.minecraft.util.ARGB;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.ItemOwner;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
@@ -113,7 +117,7 @@ public final class StandaloneModel {
|
|||||||
* Set up an {@link ItemStackRenderState.LayerRenderState} to render this model.
|
* Set up an {@link ItemStackRenderState.LayerRenderState} to render this model.
|
||||||
*
|
*
|
||||||
* @param layer The layer to set up.
|
* @param layer The layer to set up.
|
||||||
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, ItemOwner, int)
|
||||||
*/
|
*/
|
||||||
public void setupItemLayer(ItemStackRenderState.LayerRenderState layer) {
|
public void setupItemLayer(ItemStackRenderState.LayerRenderState layer) {
|
||||||
layer.setExtents(extents);
|
layer.setExtents(extents);
|
||||||
@@ -127,26 +131,35 @@ public final class StandaloneModel {
|
|||||||
* Render the model directly.
|
* Render the model directly.
|
||||||
*
|
*
|
||||||
* @param transform The current pose stack transformations.
|
* @param transform The current pose stack transformations.
|
||||||
* @param buffers The buffer source to use for rendering.
|
* @param collector The node collector to render to.
|
||||||
* @param light The current light texture coordinate.
|
* @param light The current light texture coordinate.
|
||||||
* @param overlay The current overlay texture coordinate.
|
* @param overlay The current overlay texture coordinate.
|
||||||
*/
|
*/
|
||||||
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay) {
|
||||||
render(transform, buffers, light, overlay, null);
|
submit(transform, collector, light, overlay, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the model directly.
|
* Render the model directly.
|
||||||
*
|
*
|
||||||
* @param transform The current pose stack transformations.
|
* @param transform The current pose stack transformations.
|
||||||
* @param buffers The buffer source to use for rendering.
|
* @param collector The node collector to render to.
|
||||||
* @param light The current light texture coordinate.
|
* @param light The current light texture coordinate.
|
||||||
* @param overlay The current overlay texture coordinate.
|
* @param overlay The current overlay texture coordinate.
|
||||||
* @param tints The tints for this model.
|
* @param tints The tints for this model.
|
||||||
*/
|
*/
|
||||||
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay, int @Nullable [] tints) {
|
public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay, int @Nullable [] tints, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
|
||||||
var pose = transform.last();
|
collector.submitCustomGeometry(transform, renderType, (pose, buffer) -> render(pose, buffer, tints, light, overlay));
|
||||||
var buffer = buffers.getBuffer(renderType);
|
|
||||||
|
if (crumblingOverlay != null && renderType.affectsCrumbling()) {
|
||||||
|
collector.submitCustomGeometry(transform, ModelBakery.DESTROY_TYPES.get(crumblingOverlay.progress()), (pose, buffer) ->
|
||||||
|
// FIXME: This does not work. Should we have a custom hook for this instead?
|
||||||
|
render(pose, new SheetedDecalTextureGenerator(buffer, crumblingOverlay.cameraPose(), 1.0f), tints, light, overlay)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void render(PoseStack.Pose pose, VertexConsumer buffer, int @Nullable [] tints, int light, int overlay) {
|
||||||
for (var quad : quads) {
|
for (var quad : quads) {
|
||||||
float r, g, b, a;
|
float r, g, b, a;
|
||||||
var idx = quad.tintIndex();
|
var idx = quad.tintIndex();
|
||||||
|
|||||||
@@ -4,16 +4,13 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.client.turtle;
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.client.StandaloneModel;
|
import dan200.computercraft.api.client.StandaloneModel;
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
@@ -70,11 +67,6 @@ public final class BasicUpgradeModel implements TurtleUpgradeModel {
|
|||||||
getModel(side).setupItemLayer(layer);
|
getModel(side).setupItemLayer(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
|
||||||
getModel(side).render(transform, buffers, light, overlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record Unbaked(ResourceLocation left, ResourceLocation right) implements TurtleUpgradeModel.Unbaked {
|
private record Unbaked(ResourceLocation left, ResourceLocation right) implements TurtleUpgradeModel.Unbaked {
|
||||||
@Override
|
@Override
|
||||||
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
||||||
|
|||||||
@@ -9,12 +9,10 @@ import com.mojang.math.Axis;
|
|||||||
import com.mojang.math.Transformation;
|
import com.mojang.math.Transformation;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
@@ -23,7 +21,6 @@ import net.minecraft.client.renderer.special.SpecialModelRenderer;
|
|||||||
import net.minecraft.client.resources.model.ModelBaker;
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.Mth;
|
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
@@ -77,15 +74,6 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
|
||||||
transform.mulPose(getRenderer(side).transform().getMatrix());
|
|
||||||
transform.mulPose(Axis.YP.rotation(Mth.PI));
|
|
||||||
Minecraft.getInstance().getItemRenderer().renderStatic(
|
|
||||||
upgrade.getUpgradeItem(), ItemDisplayContext.FIXED, light, overlay, transform, buffers, turtle.getLevel(), 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class Unbaked implements TurtleUpgradeModel.Unbaked {
|
private static final class Unbaked implements TurtleUpgradeModel.Unbaked {
|
||||||
@Override
|
@Override
|
||||||
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
||||||
@@ -120,14 +108,14 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
|
|||||||
|
|
||||||
private record TransformedRenderer(Transformation transform) implements SpecialModelRenderer<ItemStackRenderState> {
|
private record TransformedRenderer(Transformation transform) implements SpecialModelRenderer<ItemStackRenderState> {
|
||||||
@Override
|
@Override
|
||||||
public void render(
|
public void submit(
|
||||||
@Nullable ItemStackRenderState state, ItemDisplayContext itemDisplayContext, PoseStack poseStack,
|
@Nullable ItemStackRenderState state, ItemDisplayContext context, PoseStack poseStack, SubmitNodeCollector sink,
|
||||||
MultiBufferSource multiBufferSource, int overlay, int light, boolean bl
|
int light, int overlay, boolean foil, int outlineColour
|
||||||
) {
|
) {
|
||||||
if (state == null) return;
|
if (state == null) return;
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
poseStack.mulPose(transform.getMatrix());
|
poseStack.mulPose(transform.getMatrix());
|
||||||
state.render(poseStack, multiBufferSource, overlay, light);
|
state.submit(poseStack, sink, light, overlay, outlineColour);
|
||||||
poseStack.popPose();
|
poseStack.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,20 +6,17 @@ package dan200.computercraft.api.client.turtle;
|
|||||||
|
|
||||||
import com.google.common.collect.HashMultiset;
|
import com.google.common.collect.HashMultiset;
|
||||||
import com.google.common.collect.Multiset;
|
import com.google.common.collect.Multiset;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.DataResult;
|
import com.mojang.serialization.DataResult;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
@@ -71,11 +68,6 @@ public final class SelectUpgradeModel<T> implements TurtleUpgradeModel {
|
|||||||
getModel(upgrade).renderForItem(upgrade, side, renderer, resolver, transform, seed);
|
getModel(upgrade).renderForItem(upgrade, side, renderer, resolver, transform, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
|
||||||
getModel(upgrade).renderForLevel(upgrade, side, turtle, transform, buffers, light, overlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record Unbaked<T>(
|
private record Unbaked<T>(
|
||||||
Cases<T> cases,
|
Cases<T> cases,
|
||||||
Optional<TurtleUpgradeModel.Unbaked> fallback
|
Optional<TurtleUpgradeModel.Unbaked> fallback
|
||||||
|
|||||||
@@ -4,24 +4,21 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.client.turtle;
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
|
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
import net.minecraft.client.renderer.item.ItemModel;
|
import net.minecraft.client.renderer.item.ItemModel;
|
||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
import net.minecraft.client.resources.model.ModelBaker;
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
import net.minecraft.client.resources.model.ResolvableModel;
|
import net.minecraft.client.resources.model.ResolvableModel;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.ItemOwner;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
@@ -67,24 +64,10 @@ public interface TurtleUpgradeModel {
|
|||||||
* @param resolver The model resolver.
|
* @param resolver The model resolver.
|
||||||
* @param transform The root model's transformation.
|
* @param transform The root model's transformation.
|
||||||
* @param seed The current model seed.
|
* @param seed The current model seed.
|
||||||
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, ItemOwner, int)
|
||||||
*/
|
*/
|
||||||
void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed);
|
void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed);
|
||||||
|
|
||||||
/**
|
|
||||||
* Render this upgrade to a {@link MultiBufferSource}. This is used for rendering the block-entity form of the
|
|
||||||
* upgrade.
|
|
||||||
*
|
|
||||||
* @param upgrade The upgrade being rendered.
|
|
||||||
* @param side Which side of the turtle (left or right) the upgrade is equipped on.
|
|
||||||
* @param turtle Access to the turtle that the upgrade resides on.
|
|
||||||
* @param transform The current pose stack.
|
|
||||||
* @param buffers The buffers to render to.
|
|
||||||
* @param light The lightmap coordinate.
|
|
||||||
* @param overlay The overlay coordinate.
|
|
||||||
*/
|
|
||||||
void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unbaked turtle model. Much like other unbaked models (e.g. {@link ItemModel.Unbaked}), this should resolve
|
* An unbaked turtle model. Much like other unbaked models (e.g. {@link ItemModel.Unbaked}), this should resolve
|
||||||
* any dependencies and returned the fully-resolved model.
|
* any dependencies and returned the fully-resolved model.
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import dan200.computercraft.shared.util.WorldUtil;
|
|||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||||
import net.minecraft.client.sounds.AudioStream;
|
import net.minecraft.client.sounds.AudioStream;
|
||||||
import net.minecraft.client.sounds.SoundEngine;
|
import net.minecraft.client.sounds.SoundEngine;
|
||||||
@@ -76,25 +77,25 @@ public final class ClientHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean onRenderHeldItem(
|
public static boolean onRenderHeldItem(
|
||||||
PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand,
|
PoseStack transform, SubmitNodeCollector collector, int lightTexture, InteractionHand hand,
|
||||||
float pitch, float equipProgress, float swingProgress, ItemStack stack
|
float pitch, float equipProgress, float swingProgress, ItemStack stack
|
||||||
) {
|
) {
|
||||||
if (stack.getItem() instanceof PocketComputerItem) {
|
if (stack.getItem() instanceof PocketComputerItem) {
|
||||||
PocketItemRenderer.INSTANCE.renderItemFirstPerson(transform, render, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
PocketItemRenderer.INSTANCE.renderItemFirstPerson(transform, collector, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (stack.getItem() instanceof PrintoutItem) {
|
if (stack.getItem() instanceof PrintoutItem) {
|
||||||
PrintoutItemRenderer.INSTANCE.renderItemFirstPerson(transform, render, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
PrintoutItemRenderer.INSTANCE.renderItemFirstPerson(transform, collector, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean onRenderItemFrame(PoseStack transform, MultiBufferSource render, ItemFrameRenderState frame, ExtendedItemFrameRenderState state, int light) {
|
public static boolean onRenderItemFrame(PoseStack transform, SubmitNodeCollector render, ItemFrameRenderState frame, ExtendedItemFrameRenderState state) {
|
||||||
if (state.printoutData != null) {
|
if (state.printoutData != null) {
|
||||||
transform.mulPose(Axis.ZP.rotationDegrees(frame.rotation * 360.0f / 8.0f));
|
transform.mulPose(Axis.ZP.rotationDegrees(frame.rotation * 360.0f / 8.0f));
|
||||||
PrintoutItemRenderer.onRenderInFrame(transform, render, frame, state.printoutData, state.isBook, light);
|
PrintoutItemRenderer.onRenderInFrame(transform, render, frame, state.printoutData, state.isBook);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +112,7 @@ public final class ClientHooks {
|
|||||||
* @param addText A callback which adds a single line of text.
|
* @param addText A callback which adds a single line of text.
|
||||||
*/
|
*/
|
||||||
public static void addBlockDebugInfo(Consumer<String> addText) {
|
public static void addBlockDebugInfo(Consumer<String> addText) {
|
||||||
|
// TODO(1.21.9): Replacement for this
|
||||||
var minecraft = Minecraft.getInstance();
|
var minecraft = Minecraft.getInstance();
|
||||||
if (!minecraft.getDebugOverlay().showDebugScreen() || minecraft.level == null) return;
|
if (!minecraft.getDebugOverlay().showDebugScreen() || minecraft.level == null) return;
|
||||||
if (minecraft.hitResult == null || minecraft.hitResult.getType() != HitResult.Type.BLOCK) return;
|
if (minecraft.hitResult == null || minecraft.hitResult.getType() != HitResult.Type.BLOCK) return;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import net.minecraft.client.Minecraft;
|
|||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.client.input.KeyEvent;
|
||||||
|
import net.minecraft.client.input.MouseButtonEvent;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@@ -105,24 +107,24 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
public boolean keyPressed(KeyEvent event) {
|
||||||
// Forward the tab key to the terminal, rather than moving between controls.
|
// Forward the tab key to the terminal, rather than moving between controls.
|
||||||
if (key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
if (event.key() == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
||||||
return getFocused().keyPressed(key, scancode, modifiers);
|
return getFocused().keyPressed(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.keyPressed(key, scancode, modifiers);
|
return super.keyPressed(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseReleased(double x, double y, int button) {
|
public boolean mouseReleased(MouseButtonEvent event) {
|
||||||
// Reimplement ContainerEventHandler.mouseReleased, as it's not called in vanilla (it is in Forge, but that
|
// Reimplement ContainerEventHandler.mouseReleased, as it's not called in vanilla (it is in Forge, but that
|
||||||
// shouldn't matter).
|
// shouldn't matter).
|
||||||
setDragging(false);
|
setDragging(false);
|
||||||
var child = getChildAt(x, y);
|
var child = getChildAt(event.x(), event.y());
|
||||||
if (child.isPresent() && child.get().mouseReleased(x, y, button)) return true;
|
if (child.isPresent() && child.get().mouseReleased(event)) return true;
|
||||||
|
|
||||||
return super.mouseReleased(x, y, button);
|
return super.mouseReleased(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -141,8 +143,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseClicked(double x, double y, int button) {
|
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
|
||||||
var changed = super.mouseClicked(x, y, button);
|
var changed = super.mouseClicked(event, doubleClick);
|
||||||
// Clicking the terminate/shutdown button steals focus, which means then pressing "enter" will click the button
|
// Clicking the terminate/shutdown button steals focus, which means then pressing "enter" will click the button
|
||||||
// again. Restore the focus to the terminal in these cases.
|
// again. Restore the focus to the terminal in these cases.
|
||||||
if (getFocused() instanceof DynamicImageButton) setFocused(terminal);
|
if (getFocused() instanceof DynamicImageButton) setFocused(terminal);
|
||||||
@@ -150,9 +152,9 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseDragged(double x, double y, int button, double deltaX, double deltaY) {
|
public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) {
|
||||||
return (getFocused() != null && getFocused().mouseDragged(x, y, button, deltaX, deltaY))
|
return (getFocused() != null && getFocused().mouseDragged(event, deltaX, deltaY))
|
||||||
|| super.mouseDragged(x, y, button, deltaX, deltaY);
|
|| super.mouseDragged(event, deltaX, deltaY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import net.minecraft.client.ScrollWheelHandler;
|
|||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
||||||
|
import net.minecraft.client.input.KeyEvent;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
@@ -91,13 +92,13 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean keyPressed(int key, int scancode, int modifiers) {
|
public final boolean keyPressed(KeyEvent event) {
|
||||||
// Forward the tab key to the terminal, rather than moving between controls.
|
// Forward the tab key to the terminal, rather than moving between controls.
|
||||||
if (key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
if (event.key() == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
||||||
return getFocused().keyPressed(key, scancode, modifiers);
|
return getFocused().keyPressed(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.keyPressed(key, scancode, modifiers);
|
return super.keyPressed(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public final class OptionScreen extends Screen {
|
|||||||
);
|
);
|
||||||
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING, 256, 256);
|
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING, 256, 256);
|
||||||
|
|
||||||
assertNonNull(messageRenderer).renderLeftAlignedNoShadow(graphics, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040);
|
assertNonNull(messageRenderer).render(graphics, MultiLineLabel.Align.LEFT, +PADDING, y + PADDING, FONT_HEIGHT, false, 0x404040);
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(graphics, mouseX, mouseY, partialTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
|
|||||||
import net.minecraft.client.gui.render.state.GuiElementRenderState;
|
import net.minecraft.client.gui.render.state.GuiElementRenderState;
|
||||||
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
|
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.client.input.KeyEvent;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@@ -87,18 +88,18 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
public boolean keyPressed(KeyEvent event) {
|
||||||
if (key == GLFW.GLFW_KEY_RIGHT) {
|
if (event.key() == GLFW.GLFW_KEY_RIGHT) {
|
||||||
nextPage();
|
nextPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == GLFW.GLFW_KEY_LEFT) {
|
if (event.key() == GLFW.GLFW_KEY_LEFT) {
|
||||||
previousPage();
|
previousPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.keyPressed(key, scancode, modifiers);
|
return super.keyPressed(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,7 +186,10 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
|
|||||||
pose.translate(-0.5f * X_SIZE, -(Y_SIZE + COVER_SIZE), 0);
|
pose.translate(-0.5f * X_SIZE, -(Y_SIZE + COVER_SIZE), 0);
|
||||||
pose.scale(1.0f, 1.0f, -1.0f);
|
pose.scale(1.0f, 1.0f, -1.0f);
|
||||||
|
|
||||||
drawBorder(pose, bufferSource, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightTexture.FULL_BRIGHT);
|
var buffer = bufferSource.getBuffer(PrintoutRenderer.BACKGROUND);
|
||||||
|
drawBorder(pose.last().pose(), buffer, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightTexture.FULL_BRIGHT);
|
||||||
|
|
||||||
|
// TODO: This can probably be shifted into a separate one now.
|
||||||
drawText(
|
drawText(
|
||||||
pose, bufferSource, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightTexture.FULL_BRIGHT,
|
pose, bufferSource, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightTexture.FULL_BRIGHT,
|
||||||
state.printout().text(), state.printout().colour()
|
state.printout().text(), state.printout().colour()
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ import net.minecraft.client.gui.narration.NarrationElementOutput;
|
|||||||
import net.minecraft.client.gui.navigation.ScreenRectangle;
|
import net.minecraft.client.gui.navigation.ScreenRectangle;
|
||||||
import net.minecraft.client.gui.render.TextureSetup;
|
import net.minecraft.client.gui.render.TextureSetup;
|
||||||
import net.minecraft.client.gui.render.state.GuiElementRenderState;
|
import net.minecraft.client.gui.render.state.GuiElementRenderState;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.input.CharacterEvent;
|
||||||
|
import net.minecraft.client.input.KeyEvent;
|
||||||
|
import net.minecraft.client.input.MouseButtonEvent;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
import net.minecraft.client.renderer.RenderPipelines;
|
import net.minecraft.client.renderer.RenderPipelines;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@@ -78,22 +80,22 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean charTyped(char ch, int modifiers) {
|
public boolean charTyped(CharacterEvent event) {
|
||||||
var terminalChar = StringUtil.unicodeToTerminal(ch);
|
var terminalChar = StringUtil.unicodeToTerminal(event.codepoint());
|
||||||
if (StringUtil.isTypableChar(terminalChar)) computer.charTyped((byte) terminalChar);
|
if (StringUtil.isTypableChar(terminalChar)) computer.charTyped((byte) terminalChar);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
public boolean keyPressed(KeyEvent event) {
|
||||||
if (key == GLFW.GLFW_KEY_ESCAPE) return false;
|
if (event.key() == GLFW.GLFW_KEY_ESCAPE) return false;
|
||||||
if (Screen.isPaste(key)) {
|
if (event.isPaste()) {
|
||||||
paste();
|
paste();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) {
|
if ((event.modifiers() & GLFW.GLFW_MOD_CONTROL) != 0) {
|
||||||
switch (KeyConverter.physicalToActual(key, scancode)) {
|
switch (KeyConverter.physicalToActual(event.key(), event.scancode())) {
|
||||||
case GLFW.GLFW_KEY_T -> {
|
case GLFW.GLFW_KEY_T -> {
|
||||||
if (terminateTimer < 0) terminateTimer = 0;
|
if (terminateTimer < 0) terminateTimer = 0;
|
||||||
}
|
}
|
||||||
@@ -106,11 +108,11 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key >= 0 && terminateTimer < KEY_SUPPRESS_DELAY && rebootTimer < KEY_SUPPRESS_DELAY && shutdownTimer < KEY_SUPPRESS_DELAY) {
|
if (event.key() >= 0 && terminateTimer < KEY_SUPPRESS_DELAY && rebootTimer < KEY_SUPPRESS_DELAY && shutdownTimer < KEY_SUPPRESS_DELAY) {
|
||||||
// Queue the "key" event and add to the down set
|
// Queue the "key" event and add to the down set
|
||||||
var repeat = keysDown.get(key);
|
var repeat = keysDown.get(event.key());
|
||||||
keysDown.set(key);
|
keysDown.set(event.key());
|
||||||
computer.keyDown(key, repeat);
|
computer.keyDown(event.key(), repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -122,14 +124,14 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyReleased(int key, int scancode, int modifiers) {
|
public boolean keyReleased(KeyEvent event) {
|
||||||
// Queue the "key_up" event and remove from the down set
|
// Queue the "key_up" event and remove from the down set
|
||||||
if (key >= 0 && keysDown.get(key)) {
|
if (event.key() >= 0 && keysDown.get(event.key())) {
|
||||||
keysDown.set(key, false);
|
keysDown.set(event.key(), false);
|
||||||
computer.keyUp(key);
|
computer.keyUp(event.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (KeyConverter.physicalToActual(key, scancode)) {
|
switch (KeyConverter.physicalToActual(event.key(), event.scancode())) {
|
||||||
case GLFW.GLFW_KEY_T -> terminateTimer = -1;
|
case GLFW.GLFW_KEY_T -> terminateTimer = -1;
|
||||||
case GLFW.GLFW_KEY_R -> rebootTimer = -1;
|
case GLFW.GLFW_KEY_R -> rebootTimer = -1;
|
||||||
case GLFW.GLFW_KEY_S -> shutdownTimer = -1;
|
case GLFW.GLFW_KEY_S -> shutdownTimer = -1;
|
||||||
@@ -141,18 +143,18 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
|
||||||
if (!inTermRegion(mouseX, mouseY)) return false;
|
if (!inTermRegion(event.x(), event.y())) return false;
|
||||||
if (!hasMouseSupport() || button < 0 || button > 2) return false;
|
if (!hasMouseSupport() || event.button() < 0 || event.button() > 2) return false;
|
||||||
|
|
||||||
var charX = (int) ((mouseX - innerX) / FONT_WIDTH);
|
var charX = (int) ((event.x() - innerX) / FONT_WIDTH);
|
||||||
var charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
|
var charY = (int) ((event.y() - innerY) / FONT_HEIGHT);
|
||||||
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
||||||
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
||||||
|
|
||||||
computer.mouseClick(button + 1, charX + 1, charY + 1);
|
computer.mouseClick(event.button() + 1, charX + 1, charY + 1);
|
||||||
|
|
||||||
lastMouseButton = button;
|
lastMouseButton = event.button();
|
||||||
lastMouseX = charX;
|
lastMouseX = charX;
|
||||||
lastMouseY = charY;
|
lastMouseY = charY;
|
||||||
|
|
||||||
@@ -160,16 +162,16 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
public boolean mouseReleased(MouseButtonEvent event) {
|
||||||
if (!inTermRegion(mouseX, mouseY)) return false;
|
if (!inTermRegion(event.x(), event.y())) return false;
|
||||||
if (!hasMouseSupport() || button < 0 || button > 2) return false;
|
if (!hasMouseSupport() || event.button() < 0 || event.button() > 2) return false;
|
||||||
|
|
||||||
var charX = (int) ((mouseX - innerX) / FONT_WIDTH);
|
var charX = (int) ((event.x() - innerX) / FONT_WIDTH);
|
||||||
var charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
|
var charY = (int) ((event.y() - innerY) / FONT_HEIGHT);
|
||||||
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
||||||
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
||||||
|
|
||||||
if (lastMouseButton == button) {
|
if (lastMouseButton == event.button()) {
|
||||||
computer.mouseUp(lastMouseButton + 1, charX + 1, charY + 1);
|
computer.mouseUp(lastMouseButton + 1, charX + 1, charY + 1);
|
||||||
lastMouseButton = -1;
|
lastMouseButton = -1;
|
||||||
}
|
}
|
||||||
@@ -181,17 +183,17 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseDragged(double mouseX, double mouseY, int button, double v2, double v3) {
|
public boolean mouseDragged(MouseButtonEvent event, double v2, double v3) {
|
||||||
if (!inTermRegion(mouseX, mouseY)) return false;
|
if (!inTermRegion(event.x(), event.y())) return false;
|
||||||
if (!hasMouseSupport() || button < 0 || button > 2) return false;
|
if (!hasMouseSupport() || event.button() < 0 || event.button() > 2) return false;
|
||||||
|
|
||||||
var charX = (int) ((mouseX - innerX) / FONT_WIDTH);
|
var charX = (int) ((event.x() - innerX) / FONT_WIDTH);
|
||||||
var charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
|
var charY = (int) ((event.y() - innerY) / FONT_HEIGHT);
|
||||||
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
||||||
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
||||||
|
|
||||||
if (button == lastMouseButton && (charX != lastMouseX || charY != lastMouseY)) {
|
if (event.button() == lastMouseButton && (charX != lastMouseX || charY != lastMouseY)) {
|
||||||
computer.mouseDrag(button + 1, charX + 1, charY + 1);
|
computer.mouseDrag(event.button() + 1, charX + 1, charY + 1);
|
||||||
lastMouseX = charX;
|
lastMouseX = charX;
|
||||||
lastMouseY = charY;
|
lastMouseY = charY;
|
||||||
}
|
}
|
||||||
@@ -308,8 +310,8 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
@Nullable ScreenRectangle scissorArea
|
@Nullable ScreenRectangle scissorArea
|
||||||
) implements GuiElementRenderState {
|
) implements GuiElementRenderState {
|
||||||
@Override
|
@Override
|
||||||
public void buildVertices(VertexConsumer vertexConsumer, float z) {
|
public void buildVertices(VertexConsumer vertexConsumer) {
|
||||||
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose).translate(0, 0, z), vertexConsumer);
|
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose), vertexConsumer);
|
||||||
FixedWidthFontRenderer.drawTerminalBackground(quads, x, y, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
FixedWidthFontRenderer.drawTerminalBackground(quads, x, y, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,14 +326,14 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
@Nullable ScreenRectangle bounds, @Nullable ScreenRectangle scissorArea
|
@Nullable ScreenRectangle bounds, @Nullable ScreenRectangle scissorArea
|
||||||
) implements GuiElementRenderState {
|
) implements GuiElementRenderState {
|
||||||
@Override
|
@Override
|
||||||
public void buildVertices(VertexConsumer vertexConsumer, float z) {
|
public void buildVertices(VertexConsumer vertexConsumer) {
|
||||||
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose).translate(0, 0, z), vertexConsumer);
|
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose), vertexConsumer);
|
||||||
FixedWidthFontRenderer.drawTerminalForeground(quads, x, y, terminal);
|
FixedWidthFontRenderer.drawTerminalForeground(quads, x, y, terminal);
|
||||||
FixedWidthFontRenderer.drawCursor(quads, x, y, terminal);
|
FixedWidthFontRenderer.drawCursor(quads, x, y, terminal);
|
||||||
|
|
||||||
// The GUI renderer requires that the buffer is non-empty. Add a zero-size vertex so we always have something.
|
// The GUI renderer requires that the buffer is non-empty. Add a zero-size vertex so we always have something.
|
||||||
for (var i = 0; i < 4; i++) {
|
for (var i = 0; i < 4; i++) {
|
||||||
vertexConsumer.addVertex(0, 0, z).setColor(0x00ffffff).setUv(0, 0).setLight(LightTexture.FULL_BRIGHT);
|
vertexConsumer.addVertex(0, 0, 0).setColor(0x00ffffff).setUv(0, 0).setLight(LightTexture.FULL_BRIGHT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import net.minecraft.client.renderer.item.ItemModel;
|
|||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.ItemOwner;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
@@ -35,7 +35,7 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
|
|||||||
).apply(instance, Unbaked::new));
|
).apply(instance, Unbaked::new));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable LivingEntity holder, int light) {
|
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable ItemOwner holder, int light) {
|
||||||
var overlay = TurtleItem.getOverlay(stack);
|
var overlay = TurtleItem.getOverlay(stack);
|
||||||
if (overlay == null) return;
|
if (overlay == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import net.minecraft.client.renderer.item.ItemModel;
|
|||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.ItemOwner;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
@@ -36,7 +36,7 @@ public record TurtleUpgradeModel(TurtleSide side, ItemTransforms base) implement
|
|||||||
).apply(instance, Unbaked::new));
|
).apply(instance, Unbaked::new));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable LivingEntity holder, int seed) {
|
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable ItemOwner holder, int seed) {
|
||||||
var upgrade = TurtleItem.getUpgradeWithData(stack, side);
|
var upgrade = TurtleItem.getUpgradeWithData(stack, side);
|
||||||
if (upgrade == null) return;
|
if (upgrade == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -4,23 +4,16 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.model;
|
package dan200.computercraft.client.model;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.client.pocket.PocketComputerData;
|
|
||||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import net.minecraft.client.model.geom.ModelPart;
|
import net.minecraft.client.model.geom.ModelPart;
|
||||||
import net.minecraft.client.model.geom.PartPose;
|
import net.minecraft.client.model.geom.PartPose;
|
||||||
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||||
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||||
import net.minecraft.client.resources.model.Material;
|
import net.minecraft.client.resources.model.Material;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A model for {@linkplain PocketComputerItem pocket computers} placed on a lectern.
|
* A model for {@linkplain PocketComputerItem pocket computers} placed on a lectern.
|
||||||
@@ -76,7 +69,7 @@ public class LecternPocketModel {
|
|||||||
* @param frameColour The pocket computer's {@linkplain DyedItemColor colour}.
|
* @param frameColour The pocket computer's {@linkplain DyedItemColor colour}.
|
||||||
* @param lightColour The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}.
|
* @param lightColour The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}.
|
||||||
*/
|
*/
|
||||||
public void render(PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, ComputerFamily family, int frameColour, int lightColour) {
|
/* public void render(PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, ComputerFamily family, int frameColour, int lightColour) {
|
||||||
if (frameColour != -1) {
|
if (frameColour != -1) {
|
||||||
root.render(poseStack, MATERIAL_FRAME.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay);
|
root.render(poseStack, MATERIAL_FRAME.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay);
|
||||||
root.render(poseStack, MATERIAL_COLOUR.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay, frameColour);
|
root.render(poseStack, MATERIAL_COLOUR.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay, frameColour);
|
||||||
@@ -86,5 +79,5 @@ public class LecternPocketModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
root.render(poseStack, MATERIAL_LIGHT.buffer(bufferSource, RenderType::entityCutout), LightTexture.FULL_BRIGHT, packedOverlay, lightColour);
|
root.render(poseStack, MATERIAL_LIGHT.buffer(bufferSource, RenderType::entityCutout), LightTexture.FULL_BRIGHT, packedOverlay, lightColour);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import net.minecraft.client.model.geom.ModelPart;
|
|||||||
import net.minecraft.client.model.geom.PartPose;
|
import net.minecraft.client.model.geom.PartPose;
|
||||||
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||||
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||||
import net.minecraft.client.resources.model.Material;
|
import net.minecraft.client.resources.model.Material;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -102,8 +104,8 @@ public class LecternPrintoutModel {
|
|||||||
return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderBook(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay) {
|
public void submitBook(PoseStack poseStack, SubmitNodeCollector collector, int packedLight, int packedOverlay) {
|
||||||
bookRoot.render(poseStack, buffer, packedLight, packedOverlay);
|
collector.submitModelPart(bookRoot, poseStack, RenderType.entitySolid(LecternPrintoutModel.MATERIAL.texture()), packedLight, packedOverlay, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderPages(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int pageCount) {
|
public void renderPages(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int pageCount) {
|
||||||
|
|||||||
@@ -11,21 +11,24 @@ import dan200.computercraft.client.model.LecternPrintoutModel;
|
|||||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.core.util.Colour;
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
|
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.client.renderer.blockentity.LecternRenderer;
|
import net.minecraft.client.renderer.blockentity.LecternRenderer;
|
||||||
import net.minecraft.util.ARGB;
|
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||||
|
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||||
|
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
import net.minecraft.world.level.block.LecternBlock;
|
import net.minecraft.world.level.block.LecternBlock;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
||||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||||
@@ -36,7 +39,7 @@ import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FON
|
|||||||
* <p>
|
* <p>
|
||||||
* This largely follows {@link LecternRenderer}, but with support for multiple types of item.
|
* This largely follows {@link LecternRenderer}, but with support for multiple types of item.
|
||||||
*/
|
*/
|
||||||
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity> {
|
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity, CustomLecternRenderer.State> {
|
||||||
private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
|
private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
|
||||||
|
|
||||||
private final LecternPrintoutModel printoutModel;
|
private final LecternPrintoutModel printoutModel;
|
||||||
@@ -48,25 +51,47 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(CustomLecternBlockEntity lectern, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay, Vec3 camera) {
|
public State createRenderState() {
|
||||||
poseStack.pushPose();
|
return new State();
|
||||||
poseStack.translate(0.5f, 1.0625f, 0.5f);
|
}
|
||||||
poseStack.mulPose(Axis.YP.rotationDegrees(-lectern.getBlockState().getValue(LecternBlock.FACING).getClockWise().toYRot()));
|
|
||||||
poseStack.mulPose(Axis.ZP.rotationDegrees(67.5f));
|
@Override
|
||||||
poseStack.translate(0, -0.125f, 0);
|
public void extractRenderState(CustomLecternBlockEntity lectern, State state, float f, Vec3 camera, ModelFeatureRenderer.@Nullable CrumblingOverlay overlay) {
|
||||||
|
BlockEntityRenderer.super.extractRenderState(lectern, state, f, camera, overlay);
|
||||||
|
|
||||||
var item = lectern.getItem();
|
var item = lectern.getItem();
|
||||||
if (item.getItem() instanceof PrintoutItem) {
|
if (item.getItem() instanceof PrintoutItem) {
|
||||||
var vertexConsumer = LecternPrintoutModel.MATERIAL.buffer(buffer, RenderType::entitySolid);
|
state.setPrintout(item.is(ModRegistry.Items.PRINTED_BOOK.get()), PrintoutData.getOrEmpty(item).pages());
|
||||||
if (item.is(ModRegistry.Items.PRINTED_BOOK.get())) {
|
|
||||||
printoutModel.renderBook(poseStack, vertexConsumer, packedLight, packedOverlay);
|
|
||||||
} else {
|
|
||||||
printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutData.getOrEmpty(item).pages());
|
|
||||||
}
|
|
||||||
} else if (item.getItem() instanceof PocketComputerItem pocket) {
|
} else if (item.getItem() instanceof PocketComputerItem pocket) {
|
||||||
var computer = ClientPocketComputers.get(item);
|
var computer = ClientPocketComputers.get(item);
|
||||||
|
state.setPocket(
|
||||||
|
pocket.getFamily(), DyedItemColor.getOrDefault(item, -1),
|
||||||
|
computer == null ? -1 : computer.getLightState(),
|
||||||
|
computer == null || !Vec3.atCenterOf(lectern.getBlockPos()).closerThan(camera, POCKET_TERMINAL_RENDER_DISTANCE)
|
||||||
|
? null : computer.getTerminal()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
state.setUnknown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pocketModel.render(
|
@Override
|
||||||
|
public void submit(State state, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraRenderState) {
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.translate(0.5f, 1.0625f, 0.5f);
|
||||||
|
poseStack.mulPose(Axis.YP.rotationDegrees(-state.blockState.getValue(LecternBlock.FACING).getClockWise().toYRot()));
|
||||||
|
poseStack.mulPose(Axis.ZP.rotationDegrees(67.5f));
|
||||||
|
poseStack.translate(0, -0.125f, 0);
|
||||||
|
|
||||||
|
if (state.type == Type.PRINTOUT) {
|
||||||
|
if (state.isBook) {
|
||||||
|
printoutModel.submitBook(poseStack, collector, state.lightCoords, OverlayTexture.NO_OVERLAY);
|
||||||
|
} else {
|
||||||
|
// TODO: printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutData.getOrEmpty(item).pages());
|
||||||
|
}
|
||||||
|
} else if (state.type == Type.POCKET_COMPUTER) {
|
||||||
|
// TODO: Pocket model rendering
|
||||||
|
/*pocketModel.render(
|
||||||
poseStack, buffer, packedLight, packedOverlay, pocket.getFamily(), DyedItemColor.getOrDefault(item, -1),
|
poseStack, buffer, packedLight, packedOverlay, pocket.getFamily(), DyedItemColor.getOrDefault(item, -1),
|
||||||
ARGB.opaque(computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState())
|
ARGB.opaque(computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState())
|
||||||
);
|
);
|
||||||
@@ -77,13 +102,12 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
|
|||||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||||
|
|
||||||
// Either render the terminal or a black screen, depending on how close we are.
|
// Either render the terminal or a black screen, depending on how close we are.
|
||||||
var terminal = computer == null ? null : computer.getTerminal();
|
|
||||||
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(poseStack, buffer.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
|
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(poseStack, buffer.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
|
||||||
if (terminal != null && Vec3.atCenterOf(lectern.getBlockPos()).closerThan(camera, POCKET_TERMINAL_RENDER_DISTANCE)) {
|
if (state.pocketTerminal != null) {
|
||||||
renderPocketTerminal(poseStack, quadEmitter, terminal);
|
renderPocketTerminal(poseStack, quadEmitter, state.pocketTerminal);
|
||||||
} else {
|
} else {
|
||||||
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, LecternPocketModel.TERM_WIDTH, LecternPocketModel.TERM_HEIGHT);
|
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, LecternPocketModel.TERM_WIDTH, LecternPocketModel.TERM_HEIGHT);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
poseStack.popPose();
|
poseStack.popPose();
|
||||||
@@ -105,4 +129,45 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
|
|||||||
|
|
||||||
FixedWidthFontRenderer.drawTerminal(quadEmitter, marginX, marginY, terminal, marginY, marginY, marginX, marginX);
|
FixedWidthFontRenderer.drawTerminal(quadEmitter, marginX, marginY, terminal, marginY, marginY, marginX, marginX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum Type {
|
||||||
|
PRINTOUT,
|
||||||
|
POCKET_COMPUTER,
|
||||||
|
UNKNOWN,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class State extends BlockEntityRenderState {
|
||||||
|
private Type type = Type.PRINTOUT;
|
||||||
|
private boolean isBook;
|
||||||
|
private int pages;
|
||||||
|
|
||||||
|
private ComputerFamily pocketFamily = ComputerFamily.NORMAL;
|
||||||
|
private int pocketColour;
|
||||||
|
private int pocketLight;
|
||||||
|
private @Nullable Terminal pocketTerminal; // TODO: Make this immutable
|
||||||
|
|
||||||
|
private State() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUnknown() {
|
||||||
|
this.type = Type.UNKNOWN;
|
||||||
|
this.pocketTerminal = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPrintout(boolean isBook, int pages) {
|
||||||
|
this.type = Type.PRINTOUT;
|
||||||
|
this.isBook = isBook;
|
||||||
|
this.pages = pages;
|
||||||
|
|
||||||
|
this.pocketTerminal = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPocket(ComputerFamily family, int colour, int light, @Nullable Terminal terminal) {
|
||||||
|
this.type = Type.POCKET_COMPUTER;
|
||||||
|
this.pocketFamily = family;
|
||||||
|
this.pocketColour = colour;
|
||||||
|
this.pocketLight = light;
|
||||||
|
this.pocketTerminal = terminal;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.entity.HumanoidArm;
|
import net.minecraft.world.entity.HumanoidArm;
|
||||||
@@ -22,29 +22,29 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* A base class for items which have map-like rendering when held in the hand.
|
* A base class for items which have map-like rendering when held in the hand.
|
||||||
*
|
*
|
||||||
* @see dan200.computercraft.client.ClientHooks#onRenderHeldItem(PoseStack, MultiBufferSource, int, InteractionHand, float, float, float, ItemStack)
|
* @see dan200.computercraft.client.ClientHooks#onRenderHeldItem(PoseStack, SubmitNodeCollector, int, InteractionHand, float, float, float, ItemStack)
|
||||||
*/
|
*/
|
||||||
public abstract class ItemMapLikeRenderer {
|
public abstract class ItemMapLikeRenderer {
|
||||||
/**
|
/**
|
||||||
* The main rendering method for the item.
|
* The main rendering method for the item.
|
||||||
*
|
*
|
||||||
* @param transform The matrix transformation stack
|
* @param transform The matrix transformation stack
|
||||||
* @param render The buffer to render to
|
* @param collector The buffer to render to
|
||||||
* @param stack The stack to render
|
* @param stack The stack to render
|
||||||
* @param light The packed lightmap coordinates.
|
* @param light The packed lightmap coordinates.
|
||||||
* @see ItemInHandRenderer#renderItem(LivingEntity, ItemStack, ItemDisplayContext, boolean, PoseStack, MultiBufferSource, int)
|
* @see ItemInHandRenderer#renderItem(LivingEntity, ItemStack, ItemDisplayContext, PoseStack, SubmitNodeCollector, int)
|
||||||
*/
|
*/
|
||||||
protected abstract void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light);
|
protected abstract void renderItem(PoseStack transform, SubmitNodeCollector collector, ItemStack stack, int light);
|
||||||
|
|
||||||
public void renderItemFirstPerson(PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
public void renderItemFirstPerson(PoseStack transform, SubmitNodeCollector collector, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||||
Player player = Objects.requireNonNull(Minecraft.getInstance().player);
|
Player player = Objects.requireNonNull(Minecraft.getInstance().player);
|
||||||
|
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
if (hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty()) {
|
if (hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty()) {
|
||||||
renderItemFirstPersonCenter(transform, render, lightTexture, pitch, equipProgress, swingProgress, stack);
|
renderItemFirstPersonCenter(transform, collector, lightTexture, pitch, equipProgress, swingProgress, stack);
|
||||||
} else {
|
} else {
|
||||||
renderItemFirstPersonSide(
|
renderItemFirstPersonSide(
|
||||||
transform, render, lightTexture,
|
transform, collector, lightTexture,
|
||||||
hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(),
|
hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(),
|
||||||
equipProgress, swingProgress, stack
|
equipProgress, swingProgress, stack
|
||||||
);
|
);
|
||||||
@@ -56,15 +56,15 @@ public abstract class ItemMapLikeRenderer {
|
|||||||
* Renders the item to one side of the player.
|
* Renders the item to one side of the player.
|
||||||
*
|
*
|
||||||
* @param transform The matrix transformation stack
|
* @param transform The matrix transformation stack
|
||||||
* @param render The buffer to render to
|
* @param collector The buffer to render to
|
||||||
* @param combinedLight The current light level
|
* @param combinedLight The current light level
|
||||||
* @param side The side to render on
|
* @param side The side to render on
|
||||||
* @param equipProgress The equip progress of this item
|
* @param equipProgress The equip progress of this item
|
||||||
* @param swingProgress The swing progress of this item
|
* @param swingProgress The swing progress of this item
|
||||||
* @param stack The stack to render
|
* @param stack The stack to render
|
||||||
* @see ItemInHandRenderer#renderOneHandedMap(PoseStack, MultiBufferSource, int, float, HumanoidArm, float, ItemStack)
|
* @see ItemInHandRenderer#renderOneHandedMap(PoseStack, SubmitNodeCollector, int, float, HumanoidArm, float, ItemStack)
|
||||||
*/
|
*/
|
||||||
private void renderItemFirstPersonSide(PoseStack transform, MultiBufferSource render, int combinedLight, HumanoidArm side, float equipProgress, float swingProgress, ItemStack stack) {
|
private void renderItemFirstPersonSide(PoseStack transform, SubmitNodeCollector collector, int combinedLight, HumanoidArm side, float equipProgress, float swingProgress, ItemStack stack) {
|
||||||
var minecraft = Minecraft.getInstance();
|
var minecraft = Minecraft.getInstance();
|
||||||
var offset = side == HumanoidArm.RIGHT ? 1f : -1f;
|
var offset = side == HumanoidArm.RIGHT ? 1f : -1f;
|
||||||
transform.translate(offset * 0.125f, -0.125f, 0f);
|
transform.translate(offset * 0.125f, -0.125f, 0f);
|
||||||
@@ -73,7 +73,7 @@ public abstract class ItemMapLikeRenderer {
|
|||||||
if (!minecraft.player.isInvisible()) {
|
if (!minecraft.player.isInvisible()) {
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
transform.mulPose(Axis.ZP.rotationDegrees(offset * 10f));
|
transform.mulPose(Axis.ZP.rotationDegrees(offset * 10f));
|
||||||
minecraft.getEntityRenderDispatcher().getItemInHandRenderer().renderPlayerArm(transform, render, combinedLight, equipProgress, swingProgress, side);
|
minecraft.getEntityRenderDispatcher().getItemInHandRenderer().renderPlayerArm(transform, collector, combinedLight, equipProgress, swingProgress, side);
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ public abstract class ItemMapLikeRenderer {
|
|||||||
transform.mulPose(Axis.XP.rotationDegrees(f2 * -45f));
|
transform.mulPose(Axis.XP.rotationDegrees(f2 * -45f));
|
||||||
transform.mulPose(Axis.YP.rotationDegrees(offset * f2 * -30f));
|
transform.mulPose(Axis.YP.rotationDegrees(offset * f2 * -30f));
|
||||||
|
|
||||||
renderItem(transform, render, stack, combinedLight);
|
renderItem(transform, collector, stack, combinedLight);
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
@@ -99,15 +99,15 @@ public abstract class ItemMapLikeRenderer {
|
|||||||
* Render an item in the middle of the screen.
|
* Render an item in the middle of the screen.
|
||||||
*
|
*
|
||||||
* @param transform The matrix transformation stack
|
* @param transform The matrix transformation stack
|
||||||
* @param render The buffer to render to
|
* @param collector The buffer to render to
|
||||||
* @param combinedLight The current light level
|
* @param combinedLight The current light level
|
||||||
* @param pitch The pitch of the player
|
* @param pitch The pitch of the player
|
||||||
* @param equipProgress The equip progress of this item
|
* @param equipProgress The equip progress of this item
|
||||||
* @param swingProgress The swing progress of this item
|
* @param swingProgress The swing progress of this item
|
||||||
* @param stack The stack to render
|
* @param stack The stack to render
|
||||||
* @see ItemInHandRenderer#renderTwoHandedMap(PoseStack, MultiBufferSource, int, float, float, float)
|
* @see ItemInHandRenderer#renderTwoHandedMap(PoseStack, SubmitNodeCollector, int, float, float, float)
|
||||||
*/
|
*/
|
||||||
private void renderItemFirstPersonCenter(PoseStack transform, MultiBufferSource render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
private void renderItemFirstPersonCenter(PoseStack transform, SubmitNodeCollector collector, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||||
var minecraft = Minecraft.getInstance();
|
var minecraft = Minecraft.getInstance();
|
||||||
var renderer = minecraft.getEntityRenderDispatcher().getItemInHandRenderer();
|
var renderer = minecraft.getEntityRenderDispatcher().getItemInHandRenderer();
|
||||||
|
|
||||||
@@ -124,8 +124,8 @@ public abstract class ItemMapLikeRenderer {
|
|||||||
if (!minecraft.player.isInvisible()) {
|
if (!minecraft.player.isInvisible()) {
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
transform.mulPose(Axis.YP.rotationDegrees(90.0F));
|
transform.mulPose(Axis.YP.rotationDegrees(90.0F));
|
||||||
renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.RIGHT);
|
renderer.renderMapHand(transform, collector, combinedLight, HumanoidArm.RIGHT);
|
||||||
renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.LEFT);
|
renderer.renderMapHand(transform, collector, combinedLight, HumanoidArm.LEFT);
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +133,6 @@ public abstract class ItemMapLikeRenderer {
|
|||||||
transform.mulPose(Axis.XP.rotationDegrees(rX * 20.0F));
|
transform.mulPose(Axis.XP.rotationDegrees(rX * 20.0F));
|
||||||
transform.scale(2.0F, 2.0F, 2.0F);
|
transform.scale(2.0F, 2.0F, 2.0F);
|
||||||
|
|
||||||
renderItem(transform, render, stack, combinedLight);
|
renderItem(transform, collector, stack, combinedLight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ import dan200.computercraft.shared.config.Config;
|
|||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
|
import net.minecraft.client.resources.metadata.gui.GuiMetadataSection;
|
||||||
import net.minecraft.client.resources.metadata.gui.GuiSpriteScaling;
|
import net.minecraft.client.resources.metadata.gui.GuiSpriteScaling;
|
||||||
|
import net.minecraft.data.AtlasIds;
|
||||||
import net.minecraft.util.ARGB;
|
import net.minecraft.util.ARGB;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
import org.joml.Matrix4f;
|
|
||||||
|
|
||||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
|
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
|
||||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
||||||
@@ -42,7 +44,7 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderItem(PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light) {
|
protected void renderItem(PoseStack transform, SubmitNodeCollector submit, ItemStack stack, int light) {
|
||||||
var computer = ClientPocketComputers.get(stack);
|
var computer = ClientPocketComputers.get(stack);
|
||||||
var terminal = computer == null ? null : computer.getTerminal();
|
var terminal = computer == null ? null : computer.getTerminal();
|
||||||
|
|
||||||
@@ -75,41 +77,43 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
|||||||
var frameColour = DyedItemColor.getOrDefault(stack, -1);
|
var frameColour = DyedItemColor.getOrDefault(stack, -1);
|
||||||
|
|
||||||
var matrix = transform.last().pose();
|
var matrix = transform.last().pose();
|
||||||
renderFrame(matrix, bufferSource, family, frameColour, light, width, height);
|
renderFrame(transform, submit, family, frameColour, light, width, height);
|
||||||
|
|
||||||
// Render the light
|
// Render the light
|
||||||
var lightColour = computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState();
|
var lightColour = computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState();
|
||||||
renderLight(transform, bufferSource, lightColour, width, height);
|
renderLight(transform, submit, lightColour, width, height);
|
||||||
|
|
||||||
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
|
submit.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> {
|
||||||
if (terminal == null) {
|
var quadEmitter = new FixedWidthFontRenderer.QuadEmitter(pose.pose(), buffer);
|
||||||
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, width, height);
|
if (terminal == null) {
|
||||||
} else {
|
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, width, height);
|
||||||
FixedWidthFontRenderer.drawTerminal(quadEmitter, MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
} else {
|
||||||
}
|
FixedWidthFontRenderer.drawTerminal(quadEmitter, MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderFrame(Matrix4f transform, MultiBufferSource render, ComputerFamily family, int colour, int light, int width, int height) {
|
private static void renderFrame(PoseStack transform, SubmitNodeCollector submit, ComputerFamily family, int colour, int light, int width, int height) {
|
||||||
var textures = colour != -1 ? GuiSprites.COMPUTER_COLOUR : GuiSprites.getComputerTextures(family);
|
var textures = colour != -1 ? GuiSprites.COMPUTER_COLOUR : GuiSprites.getComputerTextures(family);
|
||||||
var spriteRenderer = new SpriteRenderer(transform, render, 0, light, colour);
|
var spriteRenderer = new SpriteRenderer(transform, submit, 0, light, colour);
|
||||||
renderBorder(spriteRenderer, textures, width, height);
|
renderBorder(spriteRenderer, textures, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderBorder(SpriteRenderer renderer, GuiSprites.ComputerTextures textures, int width, int height) {
|
private static void renderBorder(SpriteRenderer renderer, GuiSprites.ComputerTextures textures, int width, int height) {
|
||||||
var sprites = Minecraft.getInstance().getGuiSprites();
|
var sprites = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.GUI);
|
||||||
|
|
||||||
// Find our border, forcing it to be a nine-sliced texture.
|
// Find our border, forcing it to be a nine-sliced texture.
|
||||||
var borderSprite = sprites.getSprite(textures.border());
|
var borderSprite = sprites.getSprite(textures.border());
|
||||||
var borderSlice = getSlice(sprites.getSpriteScaling(borderSprite), DEFAULT_BORDER);
|
var borderSlice = getSlice(borderSprite, DEFAULT_BORDER);
|
||||||
var borderBounds = borderSlice.border();
|
var borderBounds = borderSlice.border();
|
||||||
|
|
||||||
// And take the separate bottom bit of the pocket computer.
|
// And take the separate bottom bit of the pocket computer.
|
||||||
var bottomTexture = textures.pocketBottom();
|
var bottomTexture = textures.pocketBottom();
|
||||||
if (bottomTexture == null) throw new NullPointerException(textures + " has no pocket texture");
|
if (bottomTexture == null) throw new NullPointerException(textures + " has no pocket texture");
|
||||||
var bottomSprite = sprites.getSprite(bottomTexture);
|
var bottomSprite = sprites.getSprite(bottomTexture);
|
||||||
var bottomSlice = getSlice(sprites.getSpriteScaling(bottomSprite), DEFAULT_BOTTOM);
|
var bottomSlice = getSlice(bottomSprite, DEFAULT_BOTTOM);
|
||||||
var bottomBounds = bottomSlice.border();
|
var bottomBounds = bottomSlice.border();
|
||||||
|
|
||||||
// Now draw a nine-sliced texture, by stitching together the top parts of the border with the pocket bottom.
|
// Now draw a nine-sliced texture, by stitching together the top parts of the border with the pocket bottom.
|
||||||
@@ -157,13 +161,12 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderLight(PoseStack transform, MultiBufferSource render, int colour, int width, int height) {
|
private static void renderLight(PoseStack transform, SubmitNodeCollector render, int colour, int width, int height) {
|
||||||
var buffer = render.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
|
render.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> FixedWidthFontRenderer.drawQuad(
|
||||||
FixedWidthFontRenderer.drawQuad(
|
new FixedWidthFontRenderer.QuadEmitter(pose.pose(), buffer),
|
||||||
FixedWidthFontRenderer.toVertexConsumer(transform, buffer),
|
|
||||||
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
|
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
|
||||||
ARGB.opaque(colour), LightTexture.FULL_BRIGHT
|
ARGB.opaque(colour), LightTexture.FULL_BRIGHT
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final GuiSpriteScaling.NineSlice DEFAULT_BORDER = new GuiSpriteScaling.NineSlice(
|
private static final GuiSpriteScaling.NineSlice DEFAULT_BORDER = new GuiSpriteScaling.NineSlice(
|
||||||
@@ -177,4 +180,8 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
|||||||
private static GuiSpriteScaling.NineSlice getSlice(GuiSpriteScaling scaling, GuiSpriteScaling.NineSlice fallback) {
|
private static GuiSpriteScaling.NineSlice getSlice(GuiSpriteScaling scaling, GuiSpriteScaling.NineSlice fallback) {
|
||||||
return scaling instanceof GuiSpriteScaling.NineSlice slice ? slice : fallback;
|
return scaling instanceof GuiSpriteScaling.NineSlice slice ? slice : fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static GuiSpriteScaling.NineSlice getSlice(TextureAtlasSprite sprite, GuiSpriteScaling.NineSlice fallback) {
|
||||||
|
return getSlice(sprite.contents().getAdditionalMetadata(GuiMetadataSection.TYPE).orElse(GuiMetadataSection.DEFAULT).scaling(), fallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ package dan200.computercraft.client.render;
|
|||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
|
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
@@ -28,26 +29,26 @@ public final class PrintoutItemRenderer extends ItemMapLikeRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) {
|
protected void renderItem(PoseStack transform, SubmitNodeCollector collector, ItemStack stack, int light) {
|
||||||
transform.mulPose(Axis.XP.rotationDegrees(180f));
|
transform.mulPose(Axis.XP.rotationDegrees(180f));
|
||||||
transform.scale(0.42f, 0.42f, -0.42f);
|
transform.scale(0.42f, 0.42f, -0.42f);
|
||||||
transform.translate(-0.5f, -0.48f, 0.0f);
|
transform.translate(-0.5f, -0.48f, 0.0f);
|
||||||
|
|
||||||
drawPrintout(transform, render, PrintoutData.getOrEmpty(stack), stack.getItem() == ModRegistry.Items.PRINTED_BOOK.get(), light);
|
drawPrintout(transform, collector, PrintoutData.getOrEmpty(stack), stack.getItem() == ModRegistry.Items.PRINTED_BOOK.get(), light);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onRenderInFrame(PoseStack transform, MultiBufferSource render, ItemFrameRenderState frame, PrintoutData data, boolean isBook, int packedLight) {
|
public static void onRenderInFrame(PoseStack transform, SubmitNodeCollector collector, ItemFrameRenderState frame, PrintoutData data, boolean isBook) {
|
||||||
// Move a little bit forward to ensure we're not clipping with the frame
|
// Move a little bit forward to ensure we're not clipping with the frame
|
||||||
transform.translate(0.0f, 0.0f, -0.001f);
|
transform.translate(0.0f, 0.0f, -0.001f);
|
||||||
transform.mulPose(Axis.ZP.rotationDegrees(180f));
|
transform.mulPose(Axis.ZP.rotationDegrees(180f));
|
||||||
transform.scale(0.95f, 0.95f, -0.95f);
|
transform.scale(0.95f, 0.95f, -0.95f);
|
||||||
transform.translate(-0.5f, -0.5f, 0.0f);
|
transform.translate(-0.5f, -0.5f, 0.0f);
|
||||||
|
|
||||||
var light = frame.isGlowFrame ? 0xf000d2 : packedLight; // See getLightCoords.
|
var light = frame.isGlowFrame ? 0xf000d2 : frame.lightCoords; // See getLightCoords.
|
||||||
drawPrintout(transform, render, data, isBook, light);
|
drawPrintout(transform, collector, data, isBook, light);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawPrintout(PoseStack transform, MultiBufferSource render, PrintoutData pageData, boolean book, int light) {
|
private static void drawPrintout(PoseStack transform, SubmitNodeCollector collector, PrintoutData pageData, boolean book, int light) {
|
||||||
var pages = pageData.pages();
|
var pages = pageData.pages();
|
||||||
|
|
||||||
double width = LINE_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
|
double width = LINE_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
|
||||||
@@ -71,7 +72,7 @@ public final class PrintoutItemRenderer extends ItemMapLikeRenderer {
|
|||||||
transform.scale(scale, scale, scale);
|
transform.scale(scale, scale, scale);
|
||||||
transform.translate((max - width) / 2.0, (max - height) / 2.0, 0.0);
|
transform.translate((max - width) / 2.0, (max - height) / 2.0, 0.0);
|
||||||
|
|
||||||
drawBorder(transform, render, 0, 0, -0.01f, 0, pages, book, light);
|
collector.submitCustomGeometry(transform, BACKGROUND, (matrix, buffer) -> drawBorder(matrix.pose(), buffer, 0, 0, -0.01f, 0, pages, book, light));
|
||||||
drawText(transform, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, pageData.lines());
|
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (matrix, buffer) -> drawText(matrix.pose(), buffer, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, pageData.lines()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public final class PrintoutRenderer {
|
|||||||
* Printout's background texture. {@link RenderType#text(ResourceLocation)} is a <em>little</em> questionable, but
|
* Printout's background texture. {@link RenderType#text(ResourceLocation)} is a <em>little</em> questionable, but
|
||||||
* it is what maps use, so should behave the same as vanilla in both item frames and in-hand.
|
* it is what maps use, so should behave the same as vanilla in both item frames and in-hand.
|
||||||
*/
|
*/
|
||||||
private static final RenderType BACKGROUND = RenderType.text(ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/printout.png"));
|
public static final RenderType BACKGROUND = RenderType.text(ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/printout.png"));
|
||||||
|
|
||||||
private static final float BG_SIZE = 256.0f;
|
private static final float BG_SIZE = 256.0f;
|
||||||
|
|
||||||
@@ -83,9 +83,8 @@ public final class PrintoutRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, List<PrintoutData.Line> lines) {
|
public static void drawText(Matrix4f matrix4f, VertexConsumer buffer, int x, int y, int start, int light, List<PrintoutData.Line> lines) {
|
||||||
var buffer = bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
|
var emitter = new FixedWidthFontRenderer.QuadEmitter(matrix4f, buffer);
|
||||||
var emitter = FixedWidthFontRenderer.toVertexConsumer(transform, buffer);
|
|
||||||
for (var line = 0; line < LINES_PER_PAGE && line < lines.size(); line++) {
|
for (var line = 0; line < LINES_PER_PAGE && line < lines.size(); line++) {
|
||||||
var lineContents = lines.get(start + line);
|
var lineContents = lines.get(start + line);
|
||||||
FixedWidthFontRenderer.drawString(emitter,
|
FixedWidthFontRenderer.drawString(emitter,
|
||||||
@@ -96,13 +95,10 @@ public final class PrintoutRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawBorder(PoseStack transform, MultiBufferSource bufferSource, float x, float y, float z, int page, int pages, boolean isBook, int light) {
|
public static void drawBorder(Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, int page, int pages, boolean isBook, int light) {
|
||||||
var matrix = transform.last().pose();
|
|
||||||
var leftPages = page;
|
var leftPages = page;
|
||||||
var rightPages = pages - page - 1;
|
var rightPages = pages - page - 1;
|
||||||
|
|
||||||
var buffer = bufferSource.getBuffer(BACKGROUND);
|
|
||||||
|
|
||||||
if (isBook) {
|
if (isBook) {
|
||||||
// Border
|
// Border
|
||||||
var offset = offsetAt(pages);
|
var offset = offsetAt(pages);
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.render;
|
package dan200.computercraft.client.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import org.joml.Matrix4f;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,15 +23,15 @@ import org.joml.Matrix4f;
|
|||||||
public class SpriteRenderer {
|
public class SpriteRenderer {
|
||||||
public static final ResourceLocation TEXTURE = ResourceLocation.withDefaultNamespace("textures/atlas/gui.png");
|
public static final ResourceLocation TEXTURE = ResourceLocation.withDefaultNamespace("textures/atlas/gui.png");
|
||||||
|
|
||||||
private final Matrix4f transform;
|
private final PoseStack transform;
|
||||||
private final MultiBufferSource buffers;
|
private final SubmitNodeCollector submit;
|
||||||
private final int light;
|
private final int light;
|
||||||
private final int z;
|
private final int z;
|
||||||
private final int colour;
|
private final int colour;
|
||||||
|
|
||||||
public SpriteRenderer(Matrix4f transform, MultiBufferSource buffers, int z, int light, int colour) {
|
public SpriteRenderer(PoseStack transform, SubmitNodeCollector submit, int z, int light, int colour) {
|
||||||
this.transform = transform;
|
this.transform = transform;
|
||||||
this.buffers = buffers;
|
this.submit = submit;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
this.light = light;
|
this.light = light;
|
||||||
this.colour = colour;
|
this.colour = colour;
|
||||||
@@ -47,11 +47,12 @@ public class SpriteRenderer {
|
|||||||
var v0 = sprite.getV((float) spriteY / spriteHeight);
|
var v0 = sprite.getV((float) spriteY / spriteHeight);
|
||||||
var v1 = sprite.getV((float) (spriteY + height) / spriteHeight);
|
var v1 = sprite.getV((float) (spriteY + height) / spriteHeight);
|
||||||
|
|
||||||
var vertices = buffers.getBuffer(RenderType.text(sprite.atlasLocation()));
|
submit.submitCustomGeometry(transform, RenderType.text(sprite.atlasLocation()), (t, vertices) -> {
|
||||||
vertices.addVertex(transform, x0, y1, z).setColor(colour).setUv(u0, v1).setLight(light);
|
vertices.addVertex(t, x0, y1, z).setColor(colour).setUv(u0, v1).setLight(light);
|
||||||
vertices.addVertex(transform, x1, y1, z).setColor(colour).setUv(u1, v1).setLight(light);
|
vertices.addVertex(t, x1, y1, z).setColor(colour).setUv(u1, v1).setLight(light);
|
||||||
vertices.addVertex(transform, x1, y0, z).setColor(colour).setUv(u1, v0).setLight(light);
|
vertices.addVertex(t, x1, y0, z).setColor(colour).setUv(u1, v0).setLight(light);
|
||||||
vertices.addVertex(transform, x0, y0, z).setColor(colour).setUv(u0, v0).setLight(light);
|
vertices.addVertex(t, x0, y0, z).setColor(colour).setUv(u0, v0).setLight(light);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void blitTiled(
|
public void blitTiled(
|
||||||
|
|||||||
@@ -4,9 +4,12 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.render;
|
package dan200.computercraft.client.render;
|
||||||
|
|
||||||
|
import com.google.errorprone.annotations.concurrent.LazyInit;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.client.StandaloneModel;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.client.ClientRegistry;
|
import dan200.computercraft.client.ClientRegistry;
|
||||||
import dan200.computercraft.client.turtle.TurtleOverlay;
|
import dan200.computercraft.client.turtle.TurtleOverlay;
|
||||||
@@ -17,110 +20,152 @@ import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
|||||||
import dan200.computercraft.shared.util.Holiday;
|
import dan200.computercraft.shared.util.Holiday;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.Font;
|
import net.minecraft.client.gui.Font;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
|
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||||
|
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
|
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.ARGB;
|
import net.minecraft.util.ARGB;
|
||||||
import net.minecraft.util.CommonColors;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity, TurtleBlockEntityRenderer.State> {
|
||||||
public static final ResourceLocation NORMAL_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_normal");
|
public static final ResourceLocation NORMAL_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_normal");
|
||||||
public static final ResourceLocation ADVANCED_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_advanced");
|
public static final ResourceLocation ADVANCED_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_advanced");
|
||||||
public static final ResourceLocation COLOUR_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
|
public static final ResourceLocation COLOUR_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
|
||||||
|
|
||||||
private final BlockEntityRenderDispatcher renderer;
|
private final BlockEntityRenderDispatcher renderer;
|
||||||
|
private final ItemModelResolver itemModelResolver;
|
||||||
private final Font font;
|
private final Font font;
|
||||||
|
|
||||||
public TurtleBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
|
public TurtleBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
|
||||||
renderer = context.getBlockEntityRenderDispatcher();
|
renderer = context.blockEntityRenderDispatcher();
|
||||||
font = context.getFont();
|
itemModelResolver = context.itemModelResolver();
|
||||||
|
font = context.font();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class State extends BlockEntityRenderState {
|
||||||
|
private @Nullable String label;
|
||||||
|
private Vec3 offset = Vec3.ZERO;
|
||||||
|
private int colour;
|
||||||
|
private float yaw;
|
||||||
|
private @LazyInit StandaloneModel model;
|
||||||
|
private @Nullable StandaloneModel overlay;
|
||||||
|
private @Nullable StandaloneModel elfOverlay;
|
||||||
|
|
||||||
|
private float leftAngle;
|
||||||
|
private ItemStackRenderState leftUpgrade = new ItemStackRenderState();
|
||||||
|
|
||||||
|
private float rightAngle;
|
||||||
|
private ItemStackRenderState rightUpgrade = new ItemStackRenderState();
|
||||||
|
|
||||||
|
private State() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, Vec3 camera) {
|
public State createRenderState() {
|
||||||
|
return new State();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void extractRenderState(TurtleBlockEntity turtle, State state, float partialTicks, Vec3 camera, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
|
||||||
|
BlockEntityRenderer.super.extractRenderState(turtle, state, partialTicks, camera, crumblingOverlay);
|
||||||
|
|
||||||
|
var modelManager = Minecraft.getInstance().getModelManager();
|
||||||
|
|
||||||
|
var hit = Minecraft.getInstance().hitResult;
|
||||||
|
state.label = hit != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())
|
||||||
|
? turtle.getLabel() : null;
|
||||||
|
state.colour = turtle.getColour();
|
||||||
|
state.offset = turtle.getRenderOffset(partialTicks);
|
||||||
|
state.yaw = turtle.getRenderYaw(partialTicks);
|
||||||
|
|
||||||
|
var modelLocation = state.colour == -1
|
||||||
|
? (turtle.getFamily() == ComputerFamily.NORMAL ? NORMAL_TURTLE_MODEL : ADVANCED_TURTLE_MODEL)
|
||||||
|
: COLOUR_TURTLE_MODEL;
|
||||||
|
state.model = ClientRegistry.getModel(modelManager, modelLocation);
|
||||||
|
|
||||||
|
var overlay = TurtleOverlayManager.get(modelManager, turtle.getOverlay());
|
||||||
|
state.overlay = overlay == null ? null : overlay.model();
|
||||||
|
state.elfOverlay = Holiday.getCurrent() == Holiday.CHRISTMAS && (overlay == null || overlay.showElfOverlay())
|
||||||
|
? ClientRegistry.getModel(modelManager, TurtleOverlay.ELF_MODEL)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
state.leftAngle = turtle.getToolRenderAngle(TurtleSide.LEFT, partialTicks);
|
||||||
|
extractUpgrade(turtle.getAccess(), TurtleSide.LEFT, state.leftUpgrade);
|
||||||
|
|
||||||
|
state.rightAngle = turtle.getToolRenderAngle(TurtleSide.RIGHT, partialTicks);
|
||||||
|
extractUpgrade(turtle.getAccess(), TurtleSide.RIGHT, state.rightUpgrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extractUpgrade(ITurtleAccess turtle, TurtleSide side, ItemStackRenderState state) {
|
||||||
|
state.clear();
|
||||||
|
var upgrade = turtle.getUpgradeWithData(side);
|
||||||
|
if (upgrade == null) return;
|
||||||
|
|
||||||
|
TurtleUpgradeModelManager.get(Minecraft.getInstance().getModelManager(), upgrade.holder())
|
||||||
|
.renderForItem(upgrade, side, state, itemModelResolver, ItemTransform.NO_TRANSFORM, 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void submit(State state, PoseStack transform, SubmitNodeCollector collector, CameraRenderState camera) {
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
|
|
||||||
// Translate the turtle first, so the label moves with it.
|
// Translate the turtle first, so the label moves with it.
|
||||||
var offset = turtle.getRenderOffset(partialTicks);
|
transform.translate(state.offset);
|
||||||
transform.translate(offset.x, offset.y, offset.z);
|
|
||||||
|
|
||||||
// Render the label
|
if (state.label != null) {
|
||||||
var label = turtle.getLabel();
|
collector.submitNameTag(
|
||||||
var hit = renderer.cameraHitResult;
|
transform, new Vec3(0.5, 1.2, 0.5), 0, Component.literal(state.label), false, state.lightCoords,
|
||||||
if (label != null && hit != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())) {
|
camera.pos.distanceToSqr(Vec3.atCenterOf(state.blockPos)), // TODO: Should we read camera from the render state instead?
|
||||||
var mc = Minecraft.getInstance();
|
camera
|
||||||
var font = this.font;
|
);
|
||||||
|
|
||||||
transform.pushPose();
|
|
||||||
transform.translate(0.5, 1.2, 0.5);
|
|
||||||
transform.mulPose(mc.getEntityRenderDispatcher().cameraOrientation());
|
|
||||||
transform.scale(0.025f, -0.025f, 0.025f);
|
|
||||||
|
|
||||||
var matrix = transform.last().pose();
|
|
||||||
var opacity = (int) (mc.options.getBackgroundOpacity(0.25f) * 255) << 24;
|
|
||||||
var width = -font.width(label) / 2.0f;
|
|
||||||
font.drawInBatch(label, width, 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
|
|
||||||
font.drawInBatch(label, width, 0, CommonColors.WHITE, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
|
||||||
|
|
||||||
transform.popPose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then apply rotation and flip if needed.
|
// Then apply rotation and flip if needed.
|
||||||
transform.translate(0.5f, 0.5f, 0.5f);
|
transform.translate(0.5f, 0.5f, 0.5f);
|
||||||
var yaw = turtle.getRenderYaw(partialTicks);
|
transform.mulPose(Axis.YP.rotationDegrees(180.0f - state.yaw));
|
||||||
transform.mulPose(Axis.YP.rotationDegrees(180.0f - yaw));
|
|
||||||
transform.translate(-0.5f, -0.5f, -0.5f);
|
transform.translate(-0.5f, -0.5f, -0.5f);
|
||||||
|
|
||||||
// Render the turtle
|
state.model.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY, state.colour == -1 ? null : new int[]{ ARGB.opaque(state.colour) }, state.breakProgress);
|
||||||
var colour = turtle.getColour();
|
|
||||||
var overlay = TurtleOverlayManager.get(Minecraft.getInstance().getModelManager(), turtle.getOverlay());
|
|
||||||
|
|
||||||
if (colour == -1) {
|
if (state.overlay != null) {
|
||||||
renderModel(transform, buffers, lightmapCoord, overlayLight, turtle.getFamily() == ComputerFamily.NORMAL ? NORMAL_TURTLE_MODEL : ADVANCED_TURTLE_MODEL, null);
|
state.overlay.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY);
|
||||||
} else {
|
}
|
||||||
// Otherwise render it using the colour item.
|
if (state.elfOverlay != null) {
|
||||||
renderModel(transform, buffers, lightmapCoord, overlayLight, COLOUR_TURTLE_MODEL, new int[]{ ARGB.opaque(colour) });
|
state.elfOverlay.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the overlay
|
submitUpgrade(transform, collector, state.lightCoords, state.leftAngle, state.leftUpgrade);
|
||||||
if (overlay != null) overlay.model().render(transform, buffers, lightmapCoord, overlayLight);
|
submitUpgrade(transform, collector, state.lightCoords, state.rightAngle, state.rightUpgrade);
|
||||||
|
|
||||||
// And the Christmas overlay.
|
|
||||||
var showChristmas = Holiday.getCurrent() == Holiday.CHRISTMAS && (overlay == null || overlay.showElfOverlay());
|
|
||||||
if (showChristmas) renderModel(transform, buffers, lightmapCoord, overlayLight, TurtleOverlay.ELF_MODEL, null);
|
|
||||||
|
|
||||||
// Render the upgrades
|
|
||||||
renderUpgrade(transform, buffers, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks);
|
|
||||||
renderUpgrade(transform, buffers, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks);
|
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderUpgrade(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, TurtleBlockEntity turtle, TurtleSide side, float f) {
|
private void submitUpgrade(PoseStack transform, SubmitNodeCollector collector, int lightmapCoord, float angle, ItemStackRenderState state) {
|
||||||
var upgrade = turtle.getAccess().getUpgradeWithData(side);
|
if (state.isEmpty()) return;
|
||||||
if (upgrade == null) return;
|
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
|
|
||||||
var toolAngle = turtle.getToolRenderAngle(side, f);
|
// Swing the tool
|
||||||
transform.translate(0.0f, 0.5f, 0.5f);
|
transform.translate(0.0f, 0.5f, 0.5f);
|
||||||
transform.mulPose(Axis.XN.rotationDegrees(toolAngle));
|
transform.mulPose(Axis.XN.rotationDegrees(angle));
|
||||||
transform.translate(0.0f, -0.5f, -0.5f);
|
transform.translate(0.0f, -0.5f, -0.5f);
|
||||||
|
|
||||||
TurtleUpgradeModelManager.get(Minecraft.getInstance().getModelManager(), upgrade.holder())
|
// Then reposition for rendering the item
|
||||||
.renderForLevel(upgrade, side, turtle.getAccess(), transform, buffers, lightmapCoord, overlayLight);
|
transform.translate(0.5f, 0.5f, 0.5f);
|
||||||
|
state.submit(transform, collector, lightmapCoord, OverlayTexture.NO_OVERLAY, 0);
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderModel(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, int @Nullable [] tints) {
|
|
||||||
var modelManager = Minecraft.getInstance().getModelManager();
|
|
||||||
ClientRegistry.getModel(modelManager, modelLocation).render(transform, buffers, lightmapCoord, overlayLight, tints);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,104 +4,81 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.render.monitor;
|
package dan200.computercraft.client.render.monitor;
|
||||||
|
|
||||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
|
||||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import dan200.computercraft.annotations.ForgeOverride;
|
import dan200.computercraft.annotations.ForgeOverride;
|
||||||
import dan200.computercraft.client.FrameInfo;
|
|
||||||
import dan200.computercraft.client.integration.ShaderMod;
|
|
||||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
|
||||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
|
||||||
import dan200.computercraft.shared.config.Config;
|
import dan200.computercraft.shared.config.Config;
|
||||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||||
import dan200.computercraft.shared.util.DirectionUtil;
|
import dan200.computercraft.shared.util.DirectionUtil;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.RenderPipelines;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.client.renderer.fog.FogRenderer;
|
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||||
|
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||||
|
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector4f;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.OptionalDouble;
|
|
||||||
import java.util.OptionalInt;
|
|
||||||
|
|
||||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||||
|
|
||||||
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity> {
|
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity, MonitorBlockEntityRenderer.State> {
|
||||||
/**
|
/**
|
||||||
* {@link MonitorBlockEntity#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between
|
* {@link MonitorBlockEntity#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between
|
||||||
* the monitor frame and contents.
|
* the monitor frame and contents.
|
||||||
*/
|
*/
|
||||||
private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1);
|
private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1);
|
||||||
|
|
||||||
private static @Nullable ByteBuffer backingBuffer;
|
|
||||||
|
|
||||||
public MonitorBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
|
public MonitorBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MonitorBlockEntity monitor, float partialTicks, PoseStack transform, MultiBufferSource bufferSource, int lightmapCoord, int overlayLight, Vec3 camera) {
|
public State createRenderState() {
|
||||||
// Render from the origin monitor
|
return new State();
|
||||||
var originTerminal = monitor.getOriginClientMonitor();
|
}
|
||||||
if (originTerminal == null) return;
|
|
||||||
|
|
||||||
var origin = originTerminal.getOrigin();
|
@Override
|
||||||
var renderState = originTerminal.getRenderState(MonitorRenderState::new);
|
public void extractRenderState(MonitorBlockEntity monitor, State state, float f, Vec3 camera, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
|
||||||
var monitorPos = monitor.getBlockPos();
|
BlockEntityRenderer.super.extractRenderState(monitor, state, f, camera, crumblingOverlay);
|
||||||
|
|
||||||
// Ensure each monitor terminal is rendered only once. We allow rendering a specific tile
|
state.direction = monitor.getDirection();
|
||||||
// multiple times in a single frame to ensure compatibility with shaders which may run a
|
state.front = monitor.getFront();
|
||||||
// pass multiple times.
|
state.width = monitor.getWidth();
|
||||||
var renderFrame = FrameInfo.getRenderFrame();
|
state.height = monitor.getHeight();
|
||||||
if (renderState.lastRenderFrame == renderFrame && !monitorPos.equals(renderState.lastRenderPos)) {
|
state.terminal = monitor.getOriginClientMonitor();
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
renderState.lastRenderFrame = renderFrame;
|
@Override
|
||||||
renderState.lastRenderPos = monitorPos;
|
public void submit(State state, PoseStack transform, SubmitNodeCollector collector, CameraRenderState camera) {
|
||||||
|
if (state.terminal == null) return;
|
||||||
var originPos = origin.getBlockPos();
|
|
||||||
|
|
||||||
// Determine orientation
|
// Determine orientation
|
||||||
var dir = origin.getDirection();
|
var dir = state.direction;
|
||||||
var front = origin.getFront();
|
var front = state.front;
|
||||||
var yaw = dir.toYRot();
|
var yaw = dir.toYRot();
|
||||||
var pitch = DirectionUtil.toPitchAngle(front);
|
var pitch = DirectionUtil.toPitchAngle(front);
|
||||||
|
|
||||||
// Setup initial transform
|
// Setup initial transform
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
transform.translate(
|
transform.translate(0.5, 0.5, 0.5);
|
||||||
originPos.getX() - monitorPos.getX() + 0.5,
|
|
||||||
originPos.getY() - monitorPos.getY() + 0.5,
|
|
||||||
originPos.getZ() - monitorPos.getZ() + 0.5
|
|
||||||
);
|
|
||||||
|
|
||||||
transform.mulPose(Axis.YN.rotationDegrees(yaw));
|
transform.mulPose(Axis.YN.rotationDegrees(yaw));
|
||||||
transform.mulPose(Axis.XP.rotationDegrees(pitch));
|
transform.mulPose(Axis.XP.rotationDegrees(pitch));
|
||||||
transform.translate(
|
transform.translate(
|
||||||
-0.5 + MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN,
|
-0.5 + MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN,
|
||||||
origin.getHeight() - 0.5 - (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN) + 0,
|
state.height - 0.5 - (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN) + 0,
|
||||||
0.5
|
0.5
|
||||||
);
|
);
|
||||||
var xSize = origin.getWidth() - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
var xSize = state.width - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
||||||
var ySize = origin.getHeight() - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
var ySize = state.height - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
||||||
|
|
||||||
// Draw the contents
|
// Draw the contents
|
||||||
var terminal = originTerminal.getTerminal();
|
var terminal = state.terminal.getTerminal();
|
||||||
if (terminal != null && !ShaderMod.get().isRenderingShadowPass()) {
|
if (terminal != null) {
|
||||||
// Draw a terminal
|
// Draw a terminal
|
||||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||||
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
||||||
@@ -110,158 +87,34 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
transform.scale((float) xScale, (float) -yScale, 1.0f);
|
transform.scale((float) xScale, (float) -yScale, 1.0f);
|
||||||
|
|
||||||
var matrix = transform.last().pose();
|
var xMargin = (float) (MARGIN / xScale);
|
||||||
|
var yMagin = (float) (MARGIN / yScale);
|
||||||
|
|
||||||
renderTerminal(matrix, originTerminal, renderState, terminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale));
|
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, consumer) -> {
|
||||||
|
FixedWidthFontRenderer.drawTerminalBackground(
|
||||||
|
new FixedWidthFontRenderer.QuadEmitter(pose.pose(), consumer),
|
||||||
|
0, 0, terminal, yMagin, yMagin, xMargin, xMargin
|
||||||
|
);
|
||||||
|
});
|
||||||
|
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, (pose, consumer) -> {
|
||||||
|
var sink = new FixedWidthFontRenderer.QuadEmitter(pose.pose(), consumer);
|
||||||
|
FixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
|
||||||
|
FixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
|
||||||
|
});
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
} else {
|
} else {
|
||||||
FixedWidthFontRenderer.drawEmptyTerminal(
|
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, consumer) -> {
|
||||||
FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT)),
|
FixedWidthFontRenderer.drawEmptyTerminal(
|
||||||
-MARGIN, MARGIN,
|
new FixedWidthFontRenderer.QuadEmitter(pose.pose(), consumer),
|
||||||
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
-MARGIN, MARGIN, (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderTerminal(
|
|
||||||
Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
|
|
||||||
) {
|
|
||||||
var redraw = monitor.pollTerminalChanged();
|
|
||||||
if (renderState.vertexBuffer == null) redraw = true;
|
|
||||||
|
|
||||||
if (redraw) {
|
|
||||||
// Cursor, Foreground, Background+Margin
|
|
||||||
var maxQuadCount = 1 + (terminal.getWidth() * terminal.getHeight()) + ((terminal.getWidth() + 2) * (terminal.getHeight() + 2));
|
|
||||||
var maxVertexCount = 4 * maxQuadCount;
|
|
||||||
var sink = ShaderMod.get().getQuadEmitter(maxQuadCount, MonitorBlockEntityRenderer::getBuffer);
|
|
||||||
|
|
||||||
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin);
|
|
||||||
var vertexCountAfterBackground = sink.vertexCount();
|
|
||||||
|
|
||||||
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
|
|
||||||
var vertexCountAfterForeground = sink.vertexCount();
|
|
||||||
|
|
||||||
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
|
|
||||||
var vertexCountAfterCursor = sink.vertexCount();
|
|
||||||
|
|
||||||
if (vertexCountAfterCursor > maxVertexCount) {
|
|
||||||
throw new IllegalStateException("Drew too many vertices. Expected " + maxVertexCount + ", drew " + vertexCountAfterCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vertexCountAfterCursor != 0) {
|
|
||||||
renderState.register();
|
|
||||||
|
|
||||||
var commandEncoder = RenderSystem.getDevice().createCommandEncoder();
|
|
||||||
|
|
||||||
var resultBuffer = sink.byteBuffer().flip();
|
|
||||||
|
|
||||||
// Ensure our buffer contains the correct number of vertices.
|
|
||||||
if (resultBuffer.remaining() != sink.format().getVertexSize() * vertexCountAfterCursor) {
|
|
||||||
throw new IllegalStateException(String.format(
|
|
||||||
"Mismatched vertex count. Buffer is %d bytes long, but was expected to be %d (vertex size) * %d (vertex count) = %d bytes.",
|
|
||||||
resultBuffer.limit(), sink.format().getVertexSize(), vertexCountAfterCursor, sink.format().getVertexSize() * vertexCountAfterCursor
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload the buffer, reallocating if required.
|
|
||||||
if (renderState.vertexBuffer == null || resultBuffer.remaining() > renderState.vertexBuffer.size()) {
|
|
||||||
if (renderState.vertexBuffer != null) {
|
|
||||||
renderState.vertexBuffer.close();
|
|
||||||
renderState.vertexBuffer = null;
|
|
||||||
}
|
|
||||||
renderState.vertexBuffer = RenderSystem.getDevice().createBuffer(
|
|
||||||
() -> "Monitor at " + monitor.getOrigin().getBlockPos(), GpuBuffer.USAGE_VERTEX | GpuBuffer.USAGE_COPY_DST, resultBuffer
|
|
||||||
);
|
|
||||||
} else if (!renderState.vertexBuffer.isClosed()) {
|
|
||||||
commandEncoder.writeToBuffer(renderState.vertexBuffer.slice(), resultBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderState.vertexCountAfterBackground = vertexCountAfterBackground;
|
|
||||||
renderState.vertexCountAfterForeground = vertexCountAfterForeground;
|
|
||||||
renderState.vertexCountAfterCursor = vertexCountAfterCursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderState.vertexCountAfterCursor == 0) return;
|
|
||||||
|
|
||||||
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
|
|
||||||
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
|
|
||||||
// normal render distance (~200), and the edges of the monitor fade out due to fog.
|
|
||||||
// There's not really a good way around this, at least without using a custom render type (which the VBO
|
|
||||||
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
|
|
||||||
// absurdly high value.
|
|
||||||
var oldFog = RenderSystem.getShaderFog();
|
|
||||||
RenderSystem.setShaderFog(Minecraft.getInstance().gameRenderer.fogRenderer.getBuffer(FogRenderer.FogMode.NONE));
|
|
||||||
|
|
||||||
// Compose the existing model view matrix with our transformation matrix.
|
|
||||||
RenderSystem.getModelViewStack().pushMatrix();
|
|
||||||
RenderSystem.getModelViewStack().mul(matrix);
|
|
||||||
|
|
||||||
// Render background geometry
|
|
||||||
drawWithShader(renderState, FixedWidthFontRenderer.TERMINAL_TEXT, RenderPipelines.TEXT, 0, renderState.vertexCountAfterBackground);
|
|
||||||
drawWithShader(
|
|
||||||
renderState, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, RenderPipelines.TEXT_POLYGON_OFFSET, renderState.vertexCountAfterBackground,
|
|
||||||
(
|
|
||||||
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
|
|
||||||
? renderState.vertexCountAfterCursor : renderState.vertexCountAfterForeground
|
|
||||||
) - renderState.vertexCountAfterBackground
|
|
||||||
);
|
|
||||||
|
|
||||||
// Clear state
|
|
||||||
RenderSystem.getModelViewStack().popMatrix();
|
|
||||||
RenderSystem.setShaderFog(oldFog);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void drawWithShader(MonitorRenderState renderState, RenderType renderType, RenderPipeline pipeline, int vertexOffset, int vertexCount) {
|
|
||||||
if (renderState.vertexBuffer == null) {
|
|
||||||
throw new IllegalStateException("MonitorRenderState has not been initialised");
|
|
||||||
}
|
|
||||||
if (vertexCount == 0) return;
|
|
||||||
|
|
||||||
var transforms = RenderSystem.getDynamicUniforms().writeTransform(
|
|
||||||
RenderSystem.getModelViewMatrix(),
|
|
||||||
new Vector4f(1.0F, 1.0F, 1.0F, 1.0F),
|
|
||||||
RenderSystem.getModelOffset(),
|
|
||||||
RenderSystem.getTextureMatrix(),
|
|
||||||
RenderSystem.getShaderLineWidth()
|
|
||||||
);
|
|
||||||
|
|
||||||
renderType.setupRenderState();
|
|
||||||
|
|
||||||
var autoStorageBuffer = RenderSystem.getSequentialBuffer(renderType.mode());
|
|
||||||
var indexCount = FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(vertexCount);
|
|
||||||
var indexBuffer = autoStorageBuffer.getBuffer(indexCount);
|
|
||||||
|
|
||||||
var target = Minecraft.getInstance().getMainRenderTarget();
|
|
||||||
var colourTarget = RenderSystem.outputColorTextureOverride != null ? RenderSystem.outputColorTextureOverride : target.getColorTextureView();
|
|
||||||
var depthTarget = target.useDepth
|
|
||||||
? (RenderSystem.outputDepthTextureOverride != null ? RenderSystem.outputDepthTextureOverride : target.getDepthTextureView())
|
|
||||||
: null;
|
|
||||||
|
|
||||||
try (var renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
|
|
||||||
() -> "Monitor", colourTarget, OptionalInt.empty(), depthTarget, OptionalDouble.empty()
|
|
||||||
)) {
|
|
||||||
renderPass.setPipeline(pipeline);
|
|
||||||
|
|
||||||
RenderSystem.bindDefaultUniforms(renderPass);
|
|
||||||
renderPass.setUniform("DynamicTransforms", transforms);
|
|
||||||
renderPass.setVertexBuffer(0, renderState.vertexBuffer);
|
|
||||||
renderPass.setIndexBuffer(indexBuffer, autoStorageBuffer.type());
|
|
||||||
|
|
||||||
for (var j = 0; j < 12; j++) {
|
|
||||||
var gpuTexture = RenderSystem.getShaderTexture(j);
|
|
||||||
if (gpuTexture != null) renderPass.bindSampler("Sampler" + j, gpuTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderPass.drawIndexed(vertexOffset, 0, indexCount, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderType.clearRenderState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getViewDistance() {
|
public int getViewDistance() {
|
||||||
return Config.monitorDistance;
|
return Config.monitorDistance;
|
||||||
@@ -272,13 +125,19 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
return monitor.getRenderBoundingBox();
|
return monitor.getRenderBoundingBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ByteBuffer getBuffer(int capacity) {
|
@Override
|
||||||
var buffer = backingBuffer;
|
public boolean shouldRender(MonitorBlockEntity monitor, Vec3 camera) {
|
||||||
if (buffer == null || buffer.capacity() < capacity) {
|
return BlockEntityRenderer.super.shouldRender(monitor, camera) && monitor.getXIndex() == 0 && monitor.getYIndex() == 0;
|
||||||
buffer = backingBuffer = buffer == null ? MemoryUtil.memAlloc(capacity) : MemoryUtil.memRealloc(buffer, capacity);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
buffer.clear();
|
public static final class State extends BlockEntityRenderState {
|
||||||
return buffer;
|
private Direction direction = Direction.NORTH;
|
||||||
|
private Direction front = Direction.NORTH;
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private @Nullable ClientMonitor terminal;
|
||||||
|
|
||||||
|
private State() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ public enum UserLevel implements Predicate<CommandSourceStack> {
|
|||||||
var player = source.getPlayer();
|
var player = source.getPlayer();
|
||||||
return server.isDedicatedServer()
|
return server.isDedicatedServer()
|
||||||
? source.getEntity() == null && source.hasPermission(4) && source.getTextName().equals("Server")
|
? source.getEntity() == null && source.hasPermission(4) && source.getTextName().equals("Server")
|
||||||
: player != null && server.isSingleplayerOwner(player.getGameProfile());
|
: player != null && server.isSingleplayerOwner(player.nameAndId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isOwner(ServerPlayer player) {
|
public static boolean isOwner(ServerPlayer player) {
|
||||||
var server = player.getServer();
|
var server = player.level().getServer();
|
||||||
return server != null && server.isSingleplayerOwner(player.getGameProfile());
|
return server != null && server.isSingleplayerOwner(player.nameAndId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public abstract class HorizontalContainerBlock extends BaseEntityBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
||||||
if (level.isClientSide) return InteractionResult.SUCCESS;
|
if (level.isClientSide()) return InteractionResult.SUCCESS;
|
||||||
|
|
||||||
if (level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) {
|
if (level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) {
|
||||||
player.openMenu(container);
|
player.openMenu(container);
|
||||||
@@ -65,7 +65,7 @@ public abstract class HorizontalContainerBlock extends BaseEntityBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos pPos) {
|
protected final int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos pPos, Direction direction) {
|
||||||
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(pLevel.getBlockEntity(pPos));
|
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(pLevel.getBlockEntity(pPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
|||||||
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
||||||
if (!player.isCrouching() && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
if (!player.isCrouching() && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
||||||
// Regular right click to activate computer
|
// Regular right click to activate computer
|
||||||
if (!level.isClientSide && computer.isUsable(player)) {
|
if (!level.isClientSide() && computer.isUsable(player)) {
|
||||||
var serverComputer = computer.createServerComputer();
|
var serverComputer = computer.createServerComputer();
|
||||||
serverComputer.turnOn();
|
serverComputer.turnOn();
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
|||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, this.type.get(), serverTicker);
|
return level.isClientSide() ? null : BlockEntityHelpers.createTickerHelper(type, this.type.get(), serverTicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void unload() {
|
protected void unload() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide()) return;
|
||||||
|
|
||||||
var computer = getServerComputer();
|
var computer = getServerComputer();
|
||||||
if (computer != null) computer.close();
|
if (computer != null) computer.close();
|
||||||
@@ -91,7 +91,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void serverTick() {
|
protected void serverTick() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide()) return;
|
||||||
if (computerID < 0 && !startOn) return; // Don't tick if we don't need a computer!
|
if (computerID < 0 && !startOn) return; // Don't tick if we don't need a computer!
|
||||||
|
|
||||||
var computer = createServerComputer();
|
var computer = createServerComputer();
|
||||||
@@ -157,7 +157,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
@Override
|
@Override
|
||||||
public final void loadAdditional(ValueInput nbt) {
|
public final void loadAdditional(ValueInput nbt) {
|
||||||
super.loadAdditional(nbt);
|
super.loadAdditional(nbt);
|
||||||
if (level != null && level.isClientSide) {
|
if (level != null && level.isClientSide()) {
|
||||||
loadClient(nbt);
|
loadClient(nbt);
|
||||||
} else {
|
} else {
|
||||||
loadServer(nbt);
|
loadServer(nbt);
|
||||||
@@ -340,14 +340,14 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void setComputerID(int id) {
|
public final void setComputerID(int id) {
|
||||||
if (getLevel().isClientSide || computerID == id) return;
|
if (getLevel().isClientSide() || computerID == id) return;
|
||||||
|
|
||||||
computerID = id;
|
computerID = id;
|
||||||
BlockEntityHelpers.updateBlock(this);
|
BlockEntityHelpers.updateBlock(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setLabel(@Nullable String label) {
|
public final void setLabel(@Nullable String label) {
|
||||||
if (getLevel().isClientSide || Objects.equals(this.label, label)) return;
|
if (getLevel().isClientSide() || Objects.equals(this.label, label)) return;
|
||||||
|
|
||||||
this.label = label;
|
this.label = label;
|
||||||
var computer = getServerComputer();
|
var computer = getServerComputer();
|
||||||
@@ -386,7 +386,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public ServerComputer getServerComputer() {
|
public ServerComputer getServerComputer() {
|
||||||
return getLevel().isClientSide || getLevel().getServer() == null ? null : ServerContext.get(getLevel().getServer()).registry().get(instanceID);
|
return getLevel().isClientSide() || getLevel().getServer() == null ? null : ServerContext.get(getLevel().getServer()).registry().get(instanceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Networking stuff
|
// Networking stuff
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public enum ComputerFamily {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkCommandUsable(Player player) {
|
private static boolean checkCommandUsable(Player player) {
|
||||||
var server = player.getServer();
|
var server = player.level().getServer();
|
||||||
if (server == null || !server.isCommandBlockEnabled()) {
|
if (server == null || !server.isCommandBlockEnabled()) {
|
||||||
player.displayClientMessage(Component.translatable("advMode.notEnabled"), true);
|
player.displayClientMessage(Component.translatable("advMode.notEnabled"), true);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -5,11 +5,14 @@
|
|||||||
package dan200.computercraft.shared.container;
|
package dan200.computercraft.shared.container;
|
||||||
|
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.entity.ContainerUser;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@@ -69,12 +72,12 @@ public interface InventoryDelegate extends Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void startOpen(Player player) {
|
default void startOpen(ContainerUser player) {
|
||||||
getInventory().startOpen(player);
|
getInventory().startOpen(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void stopOpen(Player player) {
|
default void stopOpen(ContainerUser player) {
|
||||||
getInventory().stopOpen(player);
|
getInventory().stopOpen(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,4 +105,24 @@ public interface InventoryDelegate extends Container {
|
|||||||
default boolean hasAnyMatching(Predicate<ItemStack> predicate) {
|
default boolean hasAnyMatching(Predicate<ItemStack> predicate) {
|
||||||
return getInventory().hasAnyMatching(predicate);
|
return getInventory().hasAnyMatching(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default int getMaxStackSize(ItemStack stack) {
|
||||||
|
return getInventory().getMaxStackSize(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default List<ContainerUser> getEntitiesWithContainerOpen() {
|
||||||
|
return getInventory().getEntitiesWithContainerOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean canTakeItem(Container target, int slot, ItemStack stack) {
|
||||||
|
return getInventory().canTakeItem(target, slot, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Iterator<ItemStack> iterator() {
|
||||||
|
return getInventory().iterator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import dan200.computercraft.shared.media.items.PrintoutItem;
|
|||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.stats.Stats;
|
import net.minecraft.stats.Stats;
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
@@ -55,7 +56,7 @@ public class CustomLecternBlock extends LecternBlock {
|
|||||||
*/
|
*/
|
||||||
public static InteractionResult tryPlaceItem(Player player, Level level, BlockPos pos, BlockState blockState, ItemStack item) {
|
public static InteractionResult tryPlaceItem(Player player, Level level, BlockPos pos, BlockState blockState, ItemStack item) {
|
||||||
if (item.getItem() instanceof PrintoutItem || item.getItem() instanceof PocketComputerItem) {
|
if (item.getItem() instanceof PrintoutItem || item.getItem() instanceof PocketComputerItem) {
|
||||||
if (!level.isClientSide) replaceLectern(player, level, pos, blockState, item);
|
if (!level.isClientSide()) replaceLectern(player, level, pos, blockState, item);
|
||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,13 +130,13 @@ public class CustomLecternBlock extends LecternBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos pos) {
|
protected int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos pos, Direction direction) {
|
||||||
return level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern ? lectern.getRedstoneSignal() : 0;
|
return level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern ? lectern.getRedstoneSignal() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
||||||
if (!level.isClientSide && level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern) {
|
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern) {
|
||||||
if (player.isSecondaryUseActive()) {
|
if (player.isSecondaryUseActive()) {
|
||||||
// When shift+clicked with an empty hand, drop the item and replace with the normal lectern.
|
// When shift+clicked with an empty hand, drop the item and replace with the normal lectern.
|
||||||
clearLectern(level, pos, state);
|
clearLectern(level, pos, state);
|
||||||
@@ -152,7 +153,7 @@ public class CustomLecternBlock extends LecternBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
|
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
|
||||||
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.LECTERN.get(), serverTicker);
|
return level.isClientSide() ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.LECTERN.get(), serverTicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final BlockEntityTicker<CustomLecternBlockEntity> serverTicker = (level, pos, state, lectern) -> lectern.tick();
|
private static final BlockEntityTicker<CustomLecternBlockEntity> serverTicker = (level, pos, state, lectern) -> lectern.tick();
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class PrintoutItem extends Item {
|
|||||||
@Override
|
@Override
|
||||||
public InteractionResult use(Level world, Player player, InteractionHand hand) {
|
public InteractionResult use(Level world, Player player, InteractionHand hand) {
|
||||||
var stack = player.getItemInHand(hand);
|
var stack = player.getItemInHand(hand);
|
||||||
if (!world.isClientSide) {
|
if (!world.isClientSide()) {
|
||||||
var title = PrintoutData.getOrEmpty(stack).title();
|
var title = PrintoutData.getOrEmpty(stack).title();
|
||||||
var displayTitle = Strings.isNullOrEmpty(title) ? stack.getDisplayName() : Component.literal(title);
|
var displayTitle = Strings.isNullOrEmpty(title) ? stack.getDisplayName() : Component.literal(title);
|
||||||
player.openMenu(new SimpleMenuProvider((id, playerInventory, p) -> PrintoutMenu.createInHand(id, p, hand), displayTitle));
|
player.openMenu(new SimpleMenuProvider((id, playerInventory, p) -> PrintoutMenu.createInHand(id, p, hand), displayTitle));
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class DiskDriveBlock extends HorizontalContainerBlock {
|
|||||||
var blockPos = context.getClickedPos();
|
var blockPos = context.getClickedPos();
|
||||||
var blockState = level.getBlockState(blockPos);
|
var blockState = level.getBlockState(blockPos);
|
||||||
if (blockState.is(ModRegistry.Blocks.DISK_DRIVE.get()) && blockState.getValue(STATE) == DiskDriveState.EMPTY) {
|
if (blockState.is(ModRegistry.Blocks.DISK_DRIVE.get()) && blockState.getValue(STATE) == DiskDriveState.EMPTY) {
|
||||||
if (!level.isClientSide && level.getBlockEntity(blockPos) instanceof DiskDriveBlockEntity drive && drive.getDiskStack().isEmpty()) {
|
if (!level.isClientSide() && level.getBlockEntity(blockPos) instanceof DiskDriveBlockEntity drive && drive.getDiskStack().isEmpty()) {
|
||||||
drive.setDiskStack(context.getItemInHand().split(1));
|
drive.setDiskStack(context.getItemInHand().split(1));
|
||||||
}
|
}
|
||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS;
|
||||||
@@ -76,6 +76,6 @@ public class DiskDriveBlock extends HorizontalContainerBlock {
|
|||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
return level.isClientSide ? null : BaseEntityBlock.createTickerHelper(type, ModRegistry.BlockEntities.DISK_DRIVE.get(), serverTicker);
|
return level.isClientSide() ? null : BaseEntityBlock.createTickerHelper(type, ModRegistry.BlockEntities.DISK_DRIVE.get(), serverTicker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity imp
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setChanged() {
|
public void setChanged() {
|
||||||
if (level != null && !level.isClientSide) updateMedia();
|
if (level != null && !level.isClientSide()) updateMedia();
|
||||||
super.setChanged();
|
super.setChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +357,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity imp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ejectContents() {
|
private void ejectContents() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide()) return;
|
||||||
|
|
||||||
var stack = getDiskStack();
|
var stack = getDiskStack();
|
||||||
if (stack.isEmpty()) return;
|
if (stack.isEmpty()) return;
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityB
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return world.setBlock(pos, fluid.createLegacyBlock(), world.isClientSide ? UPDATE_ALL_IMMEDIATE : UPDATE_ALL);
|
return world.setBlock(pos, fluid.createLegacyBlock(), world.isClientSide() ? UPDATE_ALL_IMMEDIATE : UPDATE_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onCustomDestroyBlock(BlockState state, Level world, BlockPos pos, Player player) {
|
public boolean onCustomDestroyBlock(BlockState state, Level world, BlockPos pos, Player player) {
|
||||||
@@ -130,7 +130,7 @@ public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityB
|
|||||||
world.setBlockAndUpdate(pos, correctConnections(world, pos, newState));
|
world.setBlockAndUpdate(pos, correctConnections(world, pos, newState));
|
||||||
|
|
||||||
cable.connectionsChanged();
|
cable.connectionsChanged();
|
||||||
if (!world.isClientSide && !player.getAbilities().instabuild) {
|
if (!world.isClientSide() && !player.getAbilities().instabuild) {
|
||||||
Block.popResource(world, pos, item);
|
Block.popResource(world, pos, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class CableBlockEntity extends BlockEntity {
|
|||||||
public void setRemoved() {
|
public void setRemoved() {
|
||||||
super.setRemoved();
|
super.setRemoved();
|
||||||
modem.removed();
|
modem.removed();
|
||||||
if (level == null || !level.isClientSide) node.remove();
|
if (level == null || !level.isClientSide()) node.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -108,7 +108,7 @@ public class CableBlockEntity extends BlockEntity {
|
|||||||
|
|
||||||
void neighborChanged() {
|
void neighborChanged() {
|
||||||
var dir = getModemDirection();
|
var dir = getModemDirection();
|
||||||
if (!getLevel().isClientSide && dir != null && isPeripheralOn()) queueRefreshPeripheral();
|
if (!getLevel().isClientSide() && dir != null && isPeripheralOn()) queueRefreshPeripheral();
|
||||||
}
|
}
|
||||||
|
|
||||||
void queueRefreshPeripheral() {
|
void queueRefreshPeripheral() {
|
||||||
@@ -119,7 +119,7 @@ public class CableBlockEntity extends BlockEntity {
|
|||||||
InteractionResult use(Player player) {
|
InteractionResult use(Player player) {
|
||||||
if (!canAttachPeripheral()) return InteractionResult.FAIL;
|
if (!canAttachPeripheral()) return InteractionResult.FAIL;
|
||||||
|
|
||||||
if (getLevel().isClientSide) return InteractionResult.SUCCESS;
|
if (getLevel().isClientSide()) return InteractionResult.SUCCESS;
|
||||||
|
|
||||||
var oldName = peripheral.getConnectedName();
|
var oldName = peripheral.getConnectedName();
|
||||||
if (isPeripheralOn()) {
|
if (isPeripheralOn()) {
|
||||||
@@ -167,7 +167,7 @@ public class CableBlockEntity extends BlockEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void blockTick() {
|
void blockTick() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide()) return;
|
||||||
|
|
||||||
if (refreshPeripheral) {
|
if (refreshPeripheral) {
|
||||||
refreshPeripheral = false;
|
refreshPeripheral = false;
|
||||||
@@ -185,7 +185,7 @@ public class CableBlockEntity extends BlockEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void connectionsChanged() {
|
void connectionsChanged() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide()) return;
|
||||||
refreshConnections = false;
|
refreshConnections = false;
|
||||||
|
|
||||||
var state = getBlockState();
|
var state = getBlockState();
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
|||||||
for (var modem : modems) {
|
for (var modem : modems) {
|
||||||
if (modem != null) modem.removed();
|
if (modem != null) modem.removed();
|
||||||
}
|
}
|
||||||
if (level == null || !level.isClientSide) node.remove();
|
if (level == null || !level.isClientSide()) node.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -120,7 +120,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
|||||||
|
|
||||||
public InteractionResult use(Player player) {
|
public InteractionResult use(Player player) {
|
||||||
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
||||||
if (getLevel().isClientSide) return InteractionResult.SUCCESS;
|
if (getLevel().isClientSide()) return InteractionResult.SUCCESS;
|
||||||
|
|
||||||
// On server, we interacted if a peripheral was found
|
// On server, we interacted if a peripheral was found
|
||||||
var oldPeriphNames = getConnectedPeripheralNames();
|
var oldPeriphNames = getConnectedPeripheralNames();
|
||||||
@@ -167,7 +167,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void blockTick() {
|
void blockTick() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide()) return;
|
||||||
|
|
||||||
if (invalidSides != 0) {
|
if (invalidSides != 0) {
|
||||||
var oldInvalidSides = invalidSides;
|
var oldInvalidSides = invalidSides;
|
||||||
@@ -194,7 +194,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void connectionsChanged() {
|
private void connectionsChanged() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide()) return;
|
||||||
refreshConnections = false;
|
refreshConnections = false;
|
||||||
|
|
||||||
var world = getLevel();
|
var world = getLevel();
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBl
|
|||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!level.isClientSide) {
|
if (!level.isClientSide()) {
|
||||||
monitor.monitorTouched(
|
monitor.monitorTouched(
|
||||||
(float) (hit.getLocation().x - hit.getBlockPos().getX()),
|
(float) (hit.getLocation().x - hit.getBlockPos().getX()),
|
||||||
(float) (hit.getLocation().y - hit.getBlockPos().getY()),
|
(float) (hit.getLocation().y - hit.getBlockPos().getY()),
|
||||||
@@ -111,7 +111,7 @@ public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBl
|
|||||||
super.setPlacedBy(world, pos, blockState, livingEntity, itemStack);
|
super.setPlacedBy(world, pos, blockState, livingEntity, itemStack);
|
||||||
|
|
||||||
var entity = world.getBlockEntity(pos);
|
var entity = world.getBlockEntity(pos);
|
||||||
if (entity instanceof MonitorBlockEntity monitor && !world.isClientSide) {
|
if (entity instanceof MonitorBlockEntity monitor && !world.isClientSide()) {
|
||||||
// Defer the block update if we're being placed by another TE. See #691
|
// Defer the block update if we're being placed by another TE. See #691
|
||||||
if (livingEntity == null || (livingEntity instanceof ServerPlayer player && PlatformHelper.get().isFakePlayer(player))) {
|
if (livingEntity == null || (livingEntity instanceof ServerPlayer player && PlatformHelper.get().isFakePlayer(player))) {
|
||||||
monitor.updateNeighborsDeferred();
|
monitor.updateNeighborsDeferred();
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
public void preRemoveSideEffects(BlockPos blockPos, BlockState blockState) {
|
public void preRemoveSideEffects(BlockPos blockPos, BlockState blockState) {
|
||||||
super.preRemoveSideEffects(blockPos, blockState);
|
super.preRemoveSideEffects(blockPos, blockState);
|
||||||
isRemoving = true;
|
isRemoving = true;
|
||||||
if (level != null && !getLevel().isClientSide) contractNeighbours();
|
if (level != null && !getLevel().isClientSide()) contractNeighbours();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -129,7 +129,7 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
width = nbt.getIntOr(NBT_WIDTH, 1);
|
width = nbt.getIntOr(NBT_WIDTH, 1);
|
||||||
height = nbt.getIntOr(NBT_HEIGHT, 1);
|
height = nbt.getIntOr(NBT_HEIGHT, 1);
|
||||||
|
|
||||||
if (level != null && level.isClientSide) onClientLoad(oldXIndex, oldYIndex);
|
if (level != null && level.isClientSide()) onClientLoad(oldXIndex, oldYIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockTick() {
|
void blockTick() {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class SpeakerBlock extends HorizontalDirectionalBlock implements EntityBl
|
|||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.SPEAKER.get(), serverTicker);
|
return level.isClientSide() ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.SPEAKER.get(), serverTicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class SpeakerBlockEntity extends BlockEntity {
|
|||||||
@Override
|
@Override
|
||||||
public void setRemoved() {
|
public void setRemoved() {
|
||||||
super.setRemoved();
|
super.setRemoved();
|
||||||
if (level != null && !level.isClientSide) {
|
if (level != null && !level.isClientSide()) {
|
||||||
ServerNetworking.sendToAllPlayers(new SpeakerStopClientMessage(peripheral.getSource()), Nullability.assertNonNull(getLevel().getServer()));
|
ServerNetworking.sendToAllPlayers(new SpeakerStopClientMessage(peripheral.getSource()), Nullability.assertNonNull(getLevel().getServer()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public class PocketComputerItem extends Item {
|
|||||||
@ForgeOverride
|
@ForgeOverride
|
||||||
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
|
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
|
||||||
var level = entity.level();
|
var level = entity.level();
|
||||||
if (level.isClientSide || level.getServer() == null) return false;
|
if (level.isClientSide() || level.getServer() == null) return false;
|
||||||
|
|
||||||
// If we're an item entity, tick an already existing computer (as to update the position), but do not keep the
|
// If we're an item entity, tick an already existing computer (as to update the position), but do not keep the
|
||||||
// computer alive.
|
// computer alive.
|
||||||
@@ -123,7 +123,7 @@ public class PocketComputerItem extends Item {
|
|||||||
@Override
|
@Override
|
||||||
public InteractionResult use(Level world, Player player, InteractionHand hand) {
|
public InteractionResult use(Level world, Player player, InteractionHand hand) {
|
||||||
var stack = player.getItemInHand(hand);
|
var stack = player.getItemInHand(hand);
|
||||||
if (!world.isClientSide) {
|
if (!world.isClientSide()) {
|
||||||
var holder = new PocketHolder.PlayerHolder((ServerPlayer) player, InventoryUtil.getHandSlot(player, hand));
|
var holder = new PocketHolder.PlayerHolder((ServerPlayer) player, InventoryUtil.getHandSlot(player, hand));
|
||||||
var brain = getOrCreateBrain((ServerLevel) world, holder, stack);
|
var brain = getOrCreateBrain((ServerLevel) world, holder, stack);
|
||||||
var computer = brain.computer();
|
var computer = brain.computer();
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
|||||||
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
||||||
super.setPlacedBy(level, pos, state, entity, stack);
|
super.setPlacedBy(level, pos, state, entity, stack);
|
||||||
|
|
||||||
if (!level.isClientSide && level.getBlockEntity(pos) instanceof TurtleBlockEntity turtle && entity instanceof Player player) {
|
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof TurtleBlockEntity turtle && entity instanceof Player player) {
|
||||||
turtle.setOwningPlayer(player.getGameProfile());
|
turtle.setOwningPlayer(player.getGameProfile());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
|||||||
protected InteractionResult useItemOn(ItemStack currentItem, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
protected InteractionResult useItemOn(ItemStack currentItem, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
if (currentItem.getItem() == Items.NAME_TAG && currentItem.has(DataComponents.CUSTOM_NAME) && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
if (currentItem.getItem() == Items.NAME_TAG && currentItem.has(DataComponents.CUSTOM_NAME) && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
||||||
// Label to rename computer
|
// Label to rename computer
|
||||||
if (!level.isClientSide) {
|
if (!level.isClientSide()) {
|
||||||
computer.setLabel(currentItem.getHoverName().getString());
|
computer.setLabel(currentItem.getHoverName().getString());
|
||||||
currentItem.shrink(1);
|
currentItem.shrink(1);
|
||||||
}
|
}
|
||||||
@@ -157,6 +157,6 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
|||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
return level.isClientSide ? BlockEntityHelpers.createTickerHelper(type, this.type.get(), clientTicker) : super.getTicker(level, state, type);
|
return level.isClientSide() ? BlockEntityHelpers.createTickerHelper(type, this.type.get(), clientTicker) : super.getTicker(level, state, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package dan200.computercraft.shared.turtle.core;
|
|||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
|
||||||
import dan200.computercraft.api.lua.ILuaCallback;
|
import dan200.computercraft.api.lua.ILuaCallback;
|
||||||
import dan200.computercraft.api.lua.MethodResult;
|
import dan200.computercraft.api.lua.MethodResult;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
@@ -28,7 +27,6 @@ import dan200.computercraft.shared.util.Holiday;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.UUIDUtil;
|
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -65,15 +63,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
private static final String NBT_SLOT = "Slot";
|
private static final String NBT_SLOT = "Slot";
|
||||||
|
|
||||||
/**
|
private static final Codec<GameProfile> GAME_PROFILE_CODEC = ExtraCodecs.STORED_GAME_PROFILE.codec();
|
||||||
* {@link net.minecraft.world.item.component.ResolvableProfile#CODEC}, but resolving to a {@link GameProfile}
|
|
||||||
* directly. We don't use {@link ExtraCodecs#GAME_PROFILE}, as that encodes the UUID as a string, not an int array.
|
|
||||||
*/
|
|
||||||
private static final Codec<GameProfile> GAME_PROFILE_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
|
||||||
UUIDUtil.CODEC.fieldOf("id").forGetter(GameProfile::getId),
|
|
||||||
ExtraCodecs.PLAYER_NAME.fieldOf("name").forGetter(GameProfile::getName)
|
|
||||||
)
|
|
||||||
.apply(instance, GameProfile::new));
|
|
||||||
|
|
||||||
private static final int ANIM_DURATION = 8;
|
private static final int ANIM_DURATION = 8;
|
||||||
|
|
||||||
@@ -121,7 +111,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
var world = getLevel();
|
var world = getLevel();
|
||||||
if (!world.isClientSide) {
|
if (!world.isClientSide()) {
|
||||||
// Advance movement
|
// Advance movement
|
||||||
updateCommands();
|
updateCommands();
|
||||||
|
|
||||||
@@ -221,7 +211,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean teleportTo(Level world, BlockPos pos) {
|
public boolean teleportTo(Level world, BlockPos pos) {
|
||||||
if (world.isClientSide || getLevel().isClientSide) {
|
if (world.isClientSide() || getLevel().isClientSide()) {
|
||||||
throw new UnsupportedOperationException("Cannot teleport on the client");
|
throw new UnsupportedOperationException("Cannot teleport on the client");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +325,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSelectedSlot(int slot) {
|
public void setSelectedSlot(int slot) {
|
||||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot set the slot on the client");
|
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot set the slot on the client");
|
||||||
|
|
||||||
if (slot >= 0 && slot < owner.getContainerSize()) {
|
if (slot >= 0 && slot < owner.getContainerSize()) {
|
||||||
selectedSlot = slot;
|
selectedSlot = slot;
|
||||||
@@ -371,7 +361,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean consumeFuel(int fuel) {
|
public boolean consumeFuel(int fuel) {
|
||||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot consume fuel on the client");
|
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot consume fuel on the client");
|
||||||
|
|
||||||
if (!isFuelNeeded()) return true;
|
if (!isFuelNeeded()) return true;
|
||||||
|
|
||||||
@@ -385,7 +375,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addFuel(int fuel) {
|
public void addFuel(int fuel) {
|
||||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot add fuel on the client");
|
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot add fuel on the client");
|
||||||
|
|
||||||
var addition = Math.max(fuel, 0);
|
var addition = Math.max(fuel, 0);
|
||||||
setFuelLevel(getFuelLevel() + addition);
|
setFuelLevel(getFuelLevel() + addition);
|
||||||
@@ -393,7 +383,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodResult executeCommand(TurtleCommand command) {
|
public MethodResult executeCommand(TurtleCommand command) {
|
||||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot run commands on the client");
|
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot run commands on the client");
|
||||||
if (commandQueue.size() > 16) return MethodResult.of(false, "Too many ongoing turtle commands");
|
if (commandQueue.size() > 16) return MethodResult.of(false, "Too many ongoing turtle commands");
|
||||||
|
|
||||||
commandQueue.offer(new TurtleCommandQueueEntry(++commandsIssued, command));
|
commandQueue.offer(new TurtleCommandQueueEntry(++commandsIssued, command));
|
||||||
@@ -403,7 +393,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playAnimation(TurtleAnimation animation) {
|
public void playAnimation(TurtleAnimation animation) {
|
||||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot play animations on the client");
|
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot play animations on the client");
|
||||||
|
|
||||||
this.animation = animation;
|
this.animation = animation;
|
||||||
if (this.animation == TurtleAnimation.SHORT_WAIT) {
|
if (this.animation == TurtleAnimation.SHORT_WAIT) {
|
||||||
@@ -489,7 +479,9 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
instance.setUpgrade(upgrade);
|
instance.setUpgrade(upgrade);
|
||||||
|
|
||||||
// Create peripherals
|
// Create peripherals
|
||||||
if (owner.getLevel() != null && !owner.getLevel().isClientSide) updatePeripherals(owner.createServerComputer());
|
if (owner.getLevel() != null && !owner.getLevel().isClientSide()) {
|
||||||
|
updatePeripherals(owner.createServerComputer());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -681,7 +673,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Advance valentines day easter egg
|
// Advance valentines day easter egg
|
||||||
if (world.isClientSide && animation == TurtleAnimation.MOVE_FORWARD && animationProgress == 4) {
|
if (world.isClientSide() && animation == TurtleAnimation.MOVE_FORWARD && animationProgress == 4) {
|
||||||
// Spawn love pfx if valentines day
|
// Spawn love pfx if valentines day
|
||||||
var currentHoliday = Holiday.getCurrent();
|
var currentHoliday = Holiday.getCurrent();
|
||||||
if (currentHoliday == Holiday.VALENTINES) {
|
if (currentHoliday == Holiday.VALENTINES) {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class TurtleItem extends BlockItem {
|
|||||||
|
|
||||||
public static final CauldronInteraction CAULDRON_INTERACTION = (blockState, level, pos, player, hand, stack) -> {
|
public static final CauldronInteraction CAULDRON_INTERACTION = (blockState, level, pos, player, hand, stack) -> {
|
||||||
if (!stack.has(DataComponents.DYED_COLOR)) return InteractionResult.TRY_WITH_EMPTY_HAND;
|
if (!stack.has(DataComponents.DYED_COLOR)) return InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||||
if (!level.isClientSide) {
|
if (!level.isClientSide()) {
|
||||||
stack.remove(DataComponents.DYED_COLOR);
|
stack.remove(DataComponents.DYED_COLOR);
|
||||||
LayeredCauldronBlock.lowerFillLevel(blockState, level, pos);
|
LayeredCauldronBlock.lowerFillLevel(blockState, level, pos);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class TurtleModem extends AbstractTurtleUpgrade {
|
|||||||
@Override
|
@Override
|
||||||
public void update(ITurtleAccess turtle, TurtleSide side) {
|
public void update(ITurtleAccess turtle, TurtleSide side) {
|
||||||
// Advance the modem
|
// Advance the modem
|
||||||
if (!turtle.getLevel().isClientSide) {
|
if (!turtle.getLevel().isClientSide()) {
|
||||||
var peripheral = turtle.getPeripheral(side);
|
var peripheral = turtle.getPeripheral(side);
|
||||||
if (peripheral instanceof Peripheral modem) {
|
if (peripheral instanceof Peripheral modem) {
|
||||||
var state = modem.getModemState();
|
var state = modem.getModemState();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import net.minecraft.tags.TagKey;
|
|||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityReference;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||||
@@ -218,7 +219,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
|||||||
|
|
||||||
// If this is a projectile, attempt to deflect it instead.
|
// If this is a projectile, attempt to deflect it instead.
|
||||||
if (entity.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && entity instanceof Projectile projectile &&
|
if (entity.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && entity instanceof Projectile projectile &&
|
||||||
projectile.deflect(ProjectileDeflection.AIM_DEFLECT, player, player, true)
|
projectile.deflect(ProjectileDeflection.AIM_DEFLECT, player, EntityReference.of(player), true)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public final class TickScheduler {
|
|||||||
*/
|
*/
|
||||||
public static void schedule(Token token) {
|
public static void schedule(Token token) {
|
||||||
var world = token.owner.getLevel();
|
var world = token.owner.getLevel();
|
||||||
if (world != null && !world.isClientSide && Token.STATE.compareAndSet(token, State.IDLE, State.SCHEDULED)) {
|
if (world != null && !world.isClientSide() && Token.STATE.compareAndSet(token, State.IDLE, State.SCHEDULED)) {
|
||||||
toTick.add(token);
|
toTick.add(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ accessible field net/minecraft/client/gui/components/ChatComponent allMessages L
|
|||||||
|
|
||||||
# ItemPocketRenderer/ItemPrintoutRenderer
|
# ItemPocketRenderer/ItemPrintoutRenderer
|
||||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer calculateMapTilt (F)F
|
accessible method net/minecraft/client/renderer/ItemInHandRenderer calculateMapTilt (F)F
|
||||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderMapHand (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/entity/HumanoidArm;)V
|
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderMapHand (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/world/entity/HumanoidArm;)V
|
||||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderPlayerArm (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IFFLnet/minecraft/world/entity/HumanoidArm;)V
|
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderPlayerArm (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IFFLnet/minecraft/world/entity/HumanoidArm;)V
|
||||||
|
|
||||||
# SpeakerInstance/SpeakerManager
|
# SpeakerInstance/SpeakerManager
|
||||||
accessible method com/mojang/blaze3d/audio/Channel pumpBuffers (I)V
|
accessible method com/mojang/blaze3d/audio/Channel pumpBuffers (I)V
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import dan200.computercraft.api.client.FabricComputerCraftAPIClient;
|
|||||||
import dan200.computercraft.client.platform.ClientNetworkContextImpl;
|
import dan200.computercraft.client.platform.ClientNetworkContextImpl;
|
||||||
import dan200.computercraft.client.platform.FabricModelKey;
|
import dan200.computercraft.client.platform.FabricModelKey;
|
||||||
import dan200.computercraft.client.platform.ModelKey;
|
import dan200.computercraft.client.platform.ModelKey;
|
||||||
import dan200.computercraft.core.util.Nullability;
|
|
||||||
import dan200.computercraft.shared.ComputerCraft;
|
import dan200.computercraft.shared.ComputerCraft;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.config.ConfigSpec;
|
import dan200.computercraft.shared.config.ConfigSpec;
|
||||||
@@ -26,7 +25,6 @@ import net.fabricmc.fabric.api.client.model.loading.v1.UnbakedExtraModel;
|
|||||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.BlockRenderLayerMap;
|
import net.fabricmc.fabric.api.client.rendering.v1.BlockRenderLayerMap;
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.SpecialGuiElementRegistry;
|
import net.fabricmc.fabric.api.client.rendering.v1.SpecialGuiElementRegistry;
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
@@ -41,7 +39,6 @@ import net.minecraft.client.renderer.item.properties.conditional.ConditionalItem
|
|||||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperties;
|
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperties;
|
||||||
import net.minecraft.client.resources.model.ModelBaker;
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
import net.minecraft.client.resources.model.ResolvableModel;
|
import net.minecraft.client.resources.model.ResolvableModel;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -49,8 +46,6 @@ import java.util.function.BiConsumer;
|
|||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
|
||||||
|
|
||||||
public class ComputerCraftClient {
|
public class ComputerCraftClient {
|
||||||
public static void init() {
|
public static void init() {
|
||||||
var clientNetwork = new ClientNetworkContextImpl();
|
var clientNetwork = new ClientNetworkContextImpl();
|
||||||
@@ -69,7 +64,7 @@ public class ComputerCraftClient {
|
|||||||
ClientRegistry.registerConditionalItemProperties(ConditionalItemModelProperties.ID_MAPPER::put);
|
ClientRegistry.registerConditionalItemProperties(ConditionalItemModelProperties.ID_MAPPER::put);
|
||||||
|
|
||||||
PreparableModelLoadingPlugin.register(
|
PreparableModelLoadingPlugin.register(
|
||||||
ClientRegistry::gatherExtraModels,
|
(state, executor) -> ClientRegistry.gatherExtraModels(state.resourceManager(), executor),
|
||||||
(state, context) -> ClientRegistry.registerExtraModels(new ClientRegistry.RegisterExtraModels() {
|
(state, context) -> ClientRegistry.registerExtraModels(new ClientRegistry.RegisterExtraModels() {
|
||||||
@Override
|
@Override
|
||||||
public <U, T> void register(ModelKey<T> key, U unbaked, BiConsumer<U, ResolvableModel.Resolver> resolve, BiFunction<U, ModelBaker, T> bake) {
|
public <U, T> void register(ModelKey<T> key, U unbaked, BiConsumer<U, ResolvableModel.Resolver> resolve, BiFunction<U, ModelBaker, T> bake) {
|
||||||
@@ -93,6 +88,7 @@ public class ComputerCraftClient {
|
|||||||
|
|
||||||
ClientTickEvents.START_CLIENT_TICK.register(client -> ClientHooks.onTick());
|
ClientTickEvents.START_CLIENT_TICK.register(client -> ClientHooks.onTick());
|
||||||
// This isn't 100% consistent with Forge, but not worth a mixin.
|
// This isn't 100% consistent with Forge, but not worth a mixin.
|
||||||
|
/*
|
||||||
WorldRenderEvents.START.register(context -> ClientHooks.onRenderTick());
|
WorldRenderEvents.START.register(context -> ClientHooks.onRenderTick());
|
||||||
WorldRenderEvents.BLOCK_OUTLINE.register((context, hitResult) -> {
|
WorldRenderEvents.BLOCK_OUTLINE.register((context, hitResult) -> {
|
||||||
var hit = Minecraft.getInstance().hitResult;
|
var hit = Minecraft.getInstance().hitResult;
|
||||||
@@ -102,6 +98,7 @@ public class ComputerCraftClient {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
// Register our open folder command
|
// Register our open folder command
|
||||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
|
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.mixin.client;
|
|
||||||
|
|
||||||
import dan200.computercraft.client.ClientHooks;
|
|
||||||
import net.minecraft.client.gui.components.DebugScreenOverlay;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(DebugScreenOverlay.class)
|
|
||||||
class DebugScreenOverlayMixin {
|
|
||||||
@Inject(method = "getSystemInformation", at = @At("RETURN"))
|
|
||||||
@SuppressWarnings("UnusedMethod")
|
|
||||||
private void appendBlockDebugInfo(CallbackInfoReturnable<List<String>> cir) {
|
|
||||||
ClientHooks.addBlockDebugInfo(cir.getReturnValue()::add);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,9 +7,10 @@ package dan200.computercraft.mixin.client;
|
|||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dan200.computercraft.client.ClientHooks;
|
import dan200.computercraft.client.ClientHooks;
|
||||||
import dan200.computercraft.client.ExtendedItemFrameRenderStateHolder;
|
import dan200.computercraft.client.ExtendedItemFrameRenderStateHolder;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.client.renderer.entity.ItemFrameRenderer;
|
import net.minecraft.client.renderer.entity.ItemFrameRenderer;
|
||||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||||
|
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -21,14 +22,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
@SuppressWarnings("UnusedMethod")
|
@SuppressWarnings("UnusedMethod")
|
||||||
class ItemFrameRendererMixin {
|
class ItemFrameRendererMixin {
|
||||||
@Inject(
|
@Inject(
|
||||||
method = "render(Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",
|
method = "submit(Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V",
|
||||||
at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;mapId:Lnet/minecraft/world/level/saveddata/maps/MapId;", opcode = Opcodes.GETFIELD, ordinal = 1),
|
at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;mapId:Lnet/minecraft/world/level/saveddata/maps/MapId;", opcode = Opcodes.GETFIELD, ordinal = 1),
|
||||||
cancellable = true
|
cancellable = true
|
||||||
)
|
)
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private void render(ItemFrameRenderState frame, PoseStack pose, MultiBufferSource buffers, int light, CallbackInfo ci) {
|
private void submit(ItemFrameRenderState frame, PoseStack pose, SubmitNodeCollector buffers, CameraRenderState camera, CallbackInfo ci) {
|
||||||
var state = ((ExtendedItemFrameRenderStateHolder) frame).computercraft$state();
|
var state = ((ExtendedItemFrameRenderStateHolder) frame).computercraft$state();
|
||||||
if (ClientHooks.onRenderItemFrame(pose, buffers, frame, state, light)) {
|
if (ClientHooks.onRenderItemFrame(pose, buffers, frame, state)) {
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
pose.popPose();
|
pose.popPose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||||||
import dan200.computercraft.client.ClientHooks;
|
import dan200.computercraft.client.ClientHooks;
|
||||||
import net.minecraft.client.player.AbstractClientPlayer;
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -22,9 +22,9 @@ class ItemInHandRendererMixin {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private void onRenderItem(
|
private void onRenderItem(
|
||||||
AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float swingProgress, ItemStack stack,
|
AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float swingProgress, ItemStack stack,
|
||||||
float equippedProgress, PoseStack transform, MultiBufferSource buffer, int combinedLight, CallbackInfo ci
|
float equippedProgress, PoseStack transform, SubmitNodeCollector collector, int combinedLight, CallbackInfo ci
|
||||||
) {
|
) {
|
||||||
if (ClientHooks.onRenderHeldItem(transform, buffer, combinedLight, hand, pitch, equippedProgress, swingProgress, stack)) {
|
if (ClientHooks.onRenderHeldItem(transform, collector, combinedLight, hand, pitch, equippedProgress, swingProgress, stack)) {
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
},
|
},
|
||||||
"client": [
|
"client": [
|
||||||
"DebugScreenOverlayMixin",
|
|
||||||
"ItemFrameRendererMixin",
|
"ItemFrameRendererMixin",
|
||||||
"ItemFrameRenderStateMixin",
|
"ItemFrameRenderStateMixin",
|
||||||
"ItemInHandRendererMixin",
|
"ItemInHandRendererMixin",
|
||||||
|
|||||||
@@ -40,18 +40,14 @@ import net.fabricmc.fabric.api.lookup.v1.item.ItemApiLookup;
|
|||||||
import net.fabricmc.fabric.api.loot.v3.LootTableEvents;
|
import net.fabricmc.fabric.api.loot.v3.LootTableEvents;
|
||||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
|
import net.fabricmc.fabric.api.resource.v1.ResourceLoader;
|
||||||
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ChunkLevel;
|
import net.minecraft.server.level.ChunkLevel;
|
||||||
import net.minecraft.server.packs.PackType;
|
import net.minecraft.server.packs.PackType;
|
||||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.ItemLike;
|
import net.minecraft.world.level.ItemLike;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
@@ -59,8 +55,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
|
|||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
public class ComputerCraft {
|
public class ComputerCraft {
|
||||||
@@ -137,7 +131,7 @@ public class ComputerCraft {
|
|||||||
entries.getContext(), entries
|
entries.getContext(), entries
|
||||||
));
|
));
|
||||||
|
|
||||||
CommonHooks.onDatapackReload((name, listener) -> ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new ReloadListener(name, listener)));
|
CommonHooks.onDatapackReload(ResourceLoader.get(PackType.SERVER_DATA)::registerReloader);
|
||||||
|
|
||||||
FabricDetailRegistries.FLUID_VARIANT.addProvider(FluidDetails::fill);
|
FabricDetailRegistries.FLUID_VARIANT.addProvider(FluidDetails::fill);
|
||||||
|
|
||||||
@@ -152,20 +146,6 @@ public class ComputerCraft {
|
|||||||
registry.register(type.type(), type.codec());
|
registry.register(type.type(), type.codec());
|
||||||
}
|
}
|
||||||
|
|
||||||
private record ReloadListener(ResourceLocation name, PreparableReloadListener listener)
|
|
||||||
implements IdentifiableResourceReloadListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResourceLocation getFabricId() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<Void> reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, Executor backgroundExecutor, Executor gameExecutor) {
|
|
||||||
return listener.reload(preparationBarrier, resourceManager, backgroundExecutor, gameExecutor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private record BlockComponentImpl<T, C extends @Nullable Object>(
|
private record BlockComponentImpl<T, C extends @Nullable Object>(
|
||||||
BlockApiLookup<T, C> lookup
|
BlockApiLookup<T, C> lookup
|
||||||
) implements ModRegistry.BlockComponent<T, C> {
|
) implements ModRegistry.BlockComponent<T, C> {
|
||||||
|
|||||||
@@ -49,9 +49,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.16.14",
|
"fabricloader": ">=0.17.3",
|
||||||
"fabric-api": ">=0.128.0",
|
"fabric-api": ">=0.135.0",
|
||||||
"minecraft": "=1.21.8"
|
"minecraft": "=1.21.10"
|
||||||
},
|
},
|
||||||
"accessWidener": "computercraft.accesswidener"
|
"accessWidener": "computercraft.accesswidener"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,19 +124,6 @@ neoForge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
additionalRuntimeClasspath { extendsFrom(jarJar.get()) }
|
|
||||||
|
|
||||||
val testAdditionalRuntimeClasspath by registering {
|
|
||||||
isCanBeResolved = true
|
|
||||||
isCanBeConsumed = false
|
|
||||||
// Prevent ending up with multiple versions of libraries on the classpath.
|
|
||||||
shouldResolveConsistentlyWith(additionalRuntimeClasspath.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
for (testConfig in listOf("testClientAdditionalRuntimeClasspath", "gametestAdditionalRuntimeClasspath")) {
|
|
||||||
named(testConfig) { extendsFrom(testAdditionalRuntimeClasspath.get()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
register("testWithIris") {
|
register("testWithIris") {
|
||||||
isCanBeConsumed = false
|
isCanBeConsumed = false
|
||||||
isCanBeResolved = true
|
isCanBeResolved = true
|
||||||
@@ -169,11 +156,6 @@ dependencies {
|
|||||||
|
|
||||||
jarJar(libs.cobalt)
|
jarJar(libs.cobalt)
|
||||||
jarJar(libs.jzlib)
|
jarJar(libs.jzlib)
|
||||||
// We don't jar-in-jar our additional netty dependencies (see the tasks.jarJar configuration), but still want them
|
|
||||||
// on the legacy classpath.
|
|
||||||
additionalRuntimeClasspath(libs.netty.http) { isTransitive = false }
|
|
||||||
additionalRuntimeClasspath(libs.netty.socks) { isTransitive = false }
|
|
||||||
additionalRuntimeClasspath(libs.netty.proxy) { isTransitive = false }
|
|
||||||
|
|
||||||
testFixturesApi(libs.bundles.test)
|
testFixturesApi(libs.bundles.test)
|
||||||
testFixturesApi(libs.bundles.kotlin)
|
testFixturesApi(libs.bundles.kotlin)
|
||||||
@@ -186,10 +168,6 @@ dependencies {
|
|||||||
testModImplementation(testFixtures(project(":core")))
|
testModImplementation(testFixtures(project(":core")))
|
||||||
testModImplementation(testFixtures(project(":forge")))
|
testModImplementation(testFixtures(project(":forge")))
|
||||||
|
|
||||||
// Ensure our test fixture dependencies are on the classpath
|
|
||||||
"testAdditionalRuntimeClasspath"(libs.bundles.kotlin)
|
|
||||||
"testAdditionalRuntimeClasspath"(libs.bundles.test)
|
|
||||||
|
|
||||||
testFixturesImplementation(testFixtures(project(":core")))
|
testFixturesImplementation(testFixtures(project(":core")))
|
||||||
|
|
||||||
"testWithIris"(libs.iris.forge)
|
"testWithIris"(libs.iris.forge)
|
||||||
|
|||||||
@@ -51,13 +51,13 @@ import net.neoforged.neoforge.capabilities.Capabilities;
|
|||||||
import net.neoforged.neoforge.capabilities.ItemCapability;
|
import net.neoforged.neoforge.capabilities.ItemCapability;
|
||||||
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
|
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
|
||||||
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
|
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
|
||||||
import net.neoforged.neoforge.items.wrapper.InvWrapper;
|
|
||||||
import net.neoforged.neoforge.items.wrapper.SidedInvWrapper;
|
|
||||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
|
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
|
||||||
import net.neoforged.neoforge.registries.DataPackRegistryEvent;
|
import net.neoforged.neoforge.registries.DataPackRegistryEvent;
|
||||||
import net.neoforged.neoforge.registries.NewRegistryEvent;
|
import net.neoforged.neoforge.registries.NewRegistryEvent;
|
||||||
import net.neoforged.neoforge.registries.RegistryBuilder;
|
import net.neoforged.neoforge.registries.RegistryBuilder;
|
||||||
|
import net.neoforged.neoforge.transfer.item.VanillaContainerWrapper;
|
||||||
|
import net.neoforged.neoforge.transfer.item.WorldlyContainerWrapper;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -112,9 +112,9 @@ public final class ComputerCraft {
|
|||||||
ComputerCraftAPI.registerGenericSource(new FluidMethods());
|
ComputerCraftAPI.registerGenericSource(new FluidMethods());
|
||||||
ComputerCraftAPI.registerGenericSource(new EnergyMethods());
|
ComputerCraftAPI.registerGenericSource(new EnergyMethods());
|
||||||
|
|
||||||
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.ItemHandler.BLOCK);
|
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.Item.BLOCK);
|
||||||
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.FluidHandler.BLOCK);
|
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.Fluid.BLOCK);
|
||||||
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.EnergyStorage.BLOCK);
|
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.Energy.BLOCK);
|
||||||
|
|
||||||
ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill);
|
ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill);
|
||||||
|
|
||||||
@@ -155,12 +155,12 @@ public final class ComputerCraft {
|
|||||||
ModRegistry.BlockEntities.DISK_DRIVE
|
ModRegistry.BlockEntities.DISK_DRIVE
|
||||||
);
|
);
|
||||||
for (var inv : unsidedContainers) {
|
for (var inv : unsidedContainers) {
|
||||||
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, inv.get(), (be, side) -> new InvWrapper(be));
|
event.registerBlockEntity(Capabilities.Item.BLOCK, inv.get(), (be, side) -> VanillaContainerWrapper.of(be));
|
||||||
}
|
}
|
||||||
|
|
||||||
event.registerBlockEntity(
|
event.registerBlockEntity(
|
||||||
Capabilities.ItemHandler.BLOCK, ModRegistry.BlockEntities.PRINTER.get(),
|
Capabilities.Item.BLOCK, ModRegistry.BlockEntities.PRINTER.get(),
|
||||||
(be, side) -> side == null ? new InvWrapper(be) : new SidedInvWrapper(be, side)
|
(be, side) -> side == null ? VanillaContainerWrapper.of(be) : new WorldlyContainerWrapper(be, side)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ public final class InventoryMethods extends AbstractInventoryMethods<IItemHandle
|
|||||||
var level = blockEntity.getLevel();
|
var level = blockEntity.getLevel();
|
||||||
if (!(level instanceof ServerLevel serverLevel)) return null;
|
if (!(level instanceof ServerLevel serverLevel)) return null;
|
||||||
|
|
||||||
var result = CapabilityUtil.getCapability(serverLevel, Capabilities.ItemHandler.BLOCK, blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity, direction);
|
var result = CapabilityUtil.getCapability(serverLevel, Capabilities.Item.BLOCK, blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity, direction);
|
||||||
if (result != null) return result;
|
if (result != null) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user