Little things.

- Quark magnets don't crash (already fixed).
 - Fix quark magnet leaving behind ghost instances.
 - Fix crash with belt lighting after being placed by contraptions.
 - Simplify tile add/remove mixins and avoid conflict with Performant.
 - Avoid FloatBuffer detour when uploading matrix uniforms.
 - InstancedTileRenderer no longer has to clean up.
 - Properly let go of tickable instances.
This commit is contained in:
JozsefA 2021-03-24 15:48:15 -07:00
parent 7eafbe5757
commit b18993ed26
13 changed files with 300 additions and 290 deletions

View file

@ -548,18 +548,20 @@ public class BeltTileEntity extends KineticTileEntity implements LightUpdateList
}
private void initializeLight() {
light = new byte[beltLength * 2];
if (beltLength > 0) {
light = new byte[beltLength * 2];
Vec3i vec = getBeltFacing().getDirectionVec();
BeltSlope slope = getBlockState().get(BeltBlock.SLOPE);
int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0;
Vec3i vec = getBeltFacing().getDirectionVec();
BeltSlope slope = getBlockState().get(BeltBlock.SLOPE);
int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0;
BlockPos.Mutable pos = new BlockPos.Mutable(controller);
for (int i = 0; i < beltLength * 2; i += 2) {
light[i] = (byte) world.getLightLevel(LightType.BLOCK, pos);
light[i + 1] = (byte) world.getLightLevel(LightType.SKY, pos);
BlockPos.Mutable pos = new BlockPos.Mutable(controller);
for (int i = 0; i < beltLength * 2; i += 2) {
light[i] = (byte) world.getLightLevel(LightType.BLOCK, pos);
light[i + 1] = (byte) world.getLightLevel(LightType.SKY, pos);
pos.move(vec.getX(), verticality, vec.getZ());
pos.move(vec.getX(), verticality, vec.getZ());
}
}
}

View file

@ -1,72 +0,0 @@
package com.simibubi.create.foundation.mixin;
import com.simibubi.create.foundation.render.KineticRenderer;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import com.simibubi.create.CreateClient;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import java.util.Set;
@OnlyIn(Dist.CLIENT)
@Mixin(value = World.class, priority = 1042)
public class AddRemoveTileMixin {
@Shadow @Final public boolean isRemote;
@Shadow @Final protected Set<TileEntity> tileEntitiesToBeRemoved;
/**
* JUSTIFICATION: This method is called whenever a tile entity is removed due
* to a change in block state, even on the client. By hooking into this method,
* we gain easy access to the information while having no impact on performance.
*/
@Inject(at = @At(
value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/World;getTileEntity(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/tileentity/TileEntity;"
),
method = "removeTileEntity",
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onRemoveTile(BlockPos pos, CallbackInfo ci, TileEntity te) {
if (isRemote) {
World thi = (World)(Object) this;
CreateClient.kineticRenderer.get(thi).remove(te);
}
}
@Inject(at = @At("TAIL"), method = "addTileEntity")
private void onAddTile(TileEntity te, CallbackInfoReturnable<Boolean> cir) {
if (isRemote) {
World thi = (World)(Object) this;
CreateClient.kineticRenderer.get(thi).queueAdd(te);
}
}
@Inject(at = @At(
value = "INVOKE",
target = "Ljava/util/Set;clear()V", ordinal = 0
),
method = "tickBlockEntities")
private void onChunkUnload(CallbackInfo ci) {
if (isRemote) {
World thi = (World)(Object) this;
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(thi);
for (TileEntity tile : tileEntitiesToBeRemoved) {
kineticRenderer.remove(tile);
}
}
}
}

View file

@ -0,0 +1,29 @@
package com.simibubi.create.foundation.mixin;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.simibubi.create.CreateClient;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@Mixin(World.class)
public class TileAddMixin {
@Shadow @Final public boolean isRemote;
@Inject(at = @At("TAIL"), method = "addTileEntity")
private void onAddTile(TileEntity te, CallbackInfoReturnable<Boolean> cir) {
if (isRemote) {
CreateClient.kineticRenderer.get((World)(Object) this).queueAdd(te);
}
}
}

View file

@ -0,0 +1,25 @@
package com.simibubi.create.foundation.mixin;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.simibubi.create.CreateClient;
@Mixin(TileEntity.class)
public class TileRemoveMixin {
@Shadow @Nullable protected World world;
@Inject(at = @At("TAIL"), method = "remove")
private void onRemove(CallbackInfo ci) {
if (world instanceof ClientWorld)
CreateClient.kineticRenderer.get(this.world).remove((TileEntity) (Object) this);
}
}

View file

@ -11,6 +11,7 @@ import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld;
import net.minecraft.world.World;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryUtil;
@ -23,82 +24,85 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
public class Backend {
public static final Boolean SHADER_DEBUG_OUTPUT = true;
public static final Boolean SHADER_DEBUG_OUTPUT = true;
public static final Logger log = LogManager.getLogger(Backend.class);
public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16);
public static final Logger log = LogManager.getLogger(Backend.class);
public static GLCapabilities capabilities;
public static GlFeatureCompat compat;
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
private static boolean instancingAvailable;
private static boolean enabled;
private static boolean enabled;
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
public static GLCapabilities capabilities;
public static GlFeatureCompat compat;
public Backend() {
throw new IllegalStateException();
}
public Backend() {
throw new IllegalStateException();
}
/**
* Register a shader program. TODO: replace with forge registry?
*/
public static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
ResourceLocation name = spec.name;
if (registry.containsKey(name)) {
throw new IllegalStateException("Program spec '" + name + "' already registered.");
}
registry.put(name, spec);
return spec;
}
/**
* Register a shader program. TODO: replace with forge registry?
*/
public static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
ResourceLocation name = spec.name;
if (registry.containsKey(name)) {
throw new IllegalStateException("Program spec '" + name + "' already registered.");
}
registry.put(name, spec);
return spec;
}
@SuppressWarnings("unchecked")
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
return (P) programs.get(spec).get(GlFog.getFogMode());
}
@SuppressWarnings("unchecked")
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
return (P) programs.get(spec).get(GlFog.getFogMode());
}
public static boolean isFlywheelWorld(World world) {
return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel());
}
public static boolean isFlywheelWorld(World world) {
return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel());
}
public static boolean available() {
return canUseVBOs();
}
public static boolean available() {
return canUseVBOs();
}
public static boolean canUseInstancing() {
return enabled && instancingAvailable;
}
public static boolean canUseInstancing() {
return enabled &&
compat.vertexArrayObjectsSupported() &&
compat.drawInstancedSupported() &&
compat.instancedArraysSupported();
}
public static boolean canUseVBOs() {
return enabled && gl20();
}
public static boolean canUseVBOs() {
return enabled && gl20();
}
public static boolean gl33() {
return capabilities.OpenGL33;
}
public static boolean gl33() {
return capabilities.OpenGL33;
}
public static boolean gl20() {
return capabilities.OpenGL20;
}
public static boolean gl20() {
return capabilities.OpenGL20;
}
public static void init() {
// Can be null when running datagenerators due to the unfortunate time we call this
Minecraft mc = Minecraft.getInstance();
if (mc == null) return;
public static void init() {
// Can be null when running datagenerators due to the unfortunate time we call this
Minecraft mc = Minecraft.getInstance();
if (mc == null) return;
IResourceManager manager = mc.getResourceManager();
IResourceManager manager = mc.getResourceManager();
if (manager instanceof IReloadableResourceManager) {
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
((IReloadableResourceManager) manager).addReloadListener(listener);
}
}
if (manager instanceof IReloadableResourceManager) {
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
((IReloadableResourceManager) manager).addReloadListener(listener);
}
}
public static void refresh() {
capabilities = GL.createCapabilities();
public static void refresh() {
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
}
compat = new GlFeatureCompat(capabilities);
instancingAvailable = compat.vertexArrayObjectsSupported() &&
compat.drawInstancedSupported() &&
compat.instancedArraysSupported();
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
}
}

View file

@ -3,8 +3,7 @@ package com.simibubi.create.foundation.render.backend;
import net.minecraft.client.renderer.Matrix3f;
import net.minecraft.client.renderer.Matrix4f;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import com.mojang.blaze3d.matrix.MatrixStack;
public class RenderUtil {
public static int nextPowerOf2(int a) {
@ -17,9 +16,12 @@ public class RenderUtil {
return b == 0 && n != 0;
}
// GPUs want matrices in column major order.
public static float[] writeMatrixStack(MatrixStack stack) {
return writeMatrixStack(stack.peek().getModel(), stack.peek().getNormal());
}
public static float[] bufferMatrices(Matrix4f model, Matrix3f normal) {
// GPUs want matrices in column major order.
public static float[] writeMatrixStack(Matrix4f model, Matrix3f normal) {
return new float[] {
model.a00,
model.a10,
@ -48,4 +50,25 @@ public class RenderUtil {
normal.a22,
};
}
public static float[] writeMatrix(Matrix4f model) {
return new float[]{
model.a00,
model.a10,
model.a20,
model.a30,
model.a01,
model.a11,
model.a21,
model.a31,
model.a02,
model.a12,
model.a22,
model.a32,
model.a03,
model.a13,
model.a23,
model.a33,
};
}
}

View file

@ -28,175 +28,172 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ShaderLoader {
public static final String SHADER_DIR = "flywheel/shaders/";
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
public static final String SHADER_DIR = "flywheel/shaders/";
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
static final Map<ResourceLocation, String> shaderSource = new HashMap<>();
static final Map<ResourceLocation, String> shaderSource = new HashMap<>();
static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
if (predicate.test(VanillaResourceType.SHADERS)) {
Backend.capabilities = GL.createCapabilities();
Backend.compat = new GlFeatureCompat(Backend.capabilities);
static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
if (predicate.test(VanillaResourceType.SHADERS)) {
OptifineHandler.refresh();
Backend.refresh();
OptifineHandler.refresh();
Backend.refresh();
if (Backend.gl20()) {
shaderSource.clear();
loadShaderSources(manager);
if (Backend.gl20()) {
shaderSource.clear();
loadShaderSources(manager);
Backend.programs.values().forEach(ProgramGroup::delete);
Backend.programs.clear();
Backend.registry.values().forEach(ShaderLoader::loadProgram);
Backend.programs.values().forEach(ProgramGroup::delete);
Backend.programs.clear();
Backend.registry.values().forEach(ShaderLoader::loadProgram);
Backend.log.info("Loaded all shader programs.");
}
}
}
Backend.log.info("Loaded all shader programs.");
}
}
}
private static void loadShaderSources(IResourceManager manager){
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
for (String ext : EXTENSIONS) {
if (s.endsWith(ext)) return true;
}
return false;
});
private static void loadShaderSources(IResourceManager manager){
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
for (String ext : EXTENSIONS) {
if (s.endsWith(ext)) return true;
}
return false;
});
for (ResourceLocation location : allShaders) {
try {
IResource resource = manager.getResource(location);
for (ResourceLocation location : allShaders) {
try {
IResource resource = manager.getResource(location);
String file = readToString(resource.getInputStream());
String file = readToString(resource.getInputStream());
ResourceLocation name = new ResourceLocation(location.getNamespace(),
location.getPath().substring(SHADER_DIR.length()));
ResourceLocation name = new ResourceLocation(location.getNamespace(),
location.getPath().substring(SHADER_DIR.length()));
shaderSource.put(name, file);
} catch (IOException e) {
shaderSource.put(name, file);
} catch (IOException e) {
}
}
}
}
}
}
static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(S programSpec) {
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(S programSpec) {
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
for (GlFogMode fogMode : GlFogMode.values()) {
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
}
for (GlFogMode fogMode : GlFogMode.values()) {
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
}
Backend.programs.put(programSpec, new ProgramGroup<>(programGroup));
Backend.programs.put(programSpec, new ProgramGroup<>(programGroup));
Backend.log.debug("Loaded program {}", programSpec.name);
}
Backend.log.debug("Loaded program {}", programSpec.name);
}
private static <P extends GlProgram, S extends ProgramSpec<P>> P loadProgram(S programSpec, GlFogMode fogMode) {
GlShader vert = null;
GlShader frag = null;
try {
ShaderConstants defines = new ShaderConstants(programSpec.defines);
private static <P extends GlProgram, S extends ProgramSpec<P>> P loadProgram(S programSpec, GlFogMode fogMode) {
GlShader vert = null;
GlShader frag = null;
try {
ShaderConstants defines = new ShaderConstants(programSpec.defines);
defines.defineAll(fogMode.getDefines());
defines.defineAll(fogMode.getDefines());
vert = loadShader(programSpec.getVert(), ShaderType.VERTEX, defines);
frag = loadShader(programSpec.getFrag(), ShaderType.FRAGMENT, defines);
vert = loadShader(programSpec.getVert(), ShaderType.VERTEX, defines);
frag = loadShader(programSpec.getFrag(), ShaderType.FRAGMENT, defines);
GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag);
GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag);
programSpec.attributes.forEach(builder::addAttribute);
programSpec.attributes.forEach(builder::addAttribute);
return builder.build(programSpec.factory);
return builder.build(programSpec.factory);
} finally {
if (vert != null) vert.delete();
if (frag != null) frag.delete();
}
}
} finally {
if (vert != null) vert.delete();
if (frag != null) frag.delete();
}
}
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
private static String processIncludes(ResourceLocation baseName, String source) {
HashSet<ResourceLocation> seen = new HashSet<>();
seen.add(baseName);
private static String processIncludes(ResourceLocation baseName, String source) {
HashSet<ResourceLocation> seen = new HashSet<>();
seen.add(baseName);
return includeRecursive(source, seen).collect(Collectors.joining("\n"));
}
return includeRecursive(source, seen).collect(Collectors.joining("\n"));
}
private static Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
private static Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
Matcher matcher = includePattern.matcher(line);
Matcher matcher = includePattern.matcher(line);
if (matcher.find()) {
String includeName = matcher.group(1);
if (matcher.find()) {
String includeName = matcher.group(1);
ResourceLocation include = new ResourceLocation(includeName);
ResourceLocation include = new ResourceLocation(includeName);
if (seen.add(include)) {
String includeSource = shaderSource.get(include);
if (seen.add(include)) {
String includeSource = shaderSource.get(include);
if (includeSource != null) {
return includeRecursive(includeSource, seen);
}
}
}
if (includeSource != null) {
return includeRecursive(includeSource, seen);
}
}
}
return Stream.of(line);
});
}
return Stream.of(line);
});
}
private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
String source = shaderSource.get(name);
private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
String source = shaderSource.get(name);
source = processIncludes(name, source);
source = processIncludes(name, source);
if (defines != null)
source = defines.process(source);
if (defines != null)
source = defines.process(source);
return new GlShader(type, name, source);
}
return new GlShader(type, name, source);
}
public static String readToString(InputStream is) {
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
ByteBuffer bytebuffer = null;
public static String readToString(InputStream is) {
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
ByteBuffer bytebuffer = null;
try {
bytebuffer = readToBuffer(is);
int i = bytebuffer.position();
((Buffer)bytebuffer).rewind();
return MemoryUtil.memASCII(bytebuffer, i);
} catch (IOException e) {
try {
bytebuffer = readToBuffer(is);
int i = bytebuffer.position();
((Buffer)bytebuffer).rewind();
return MemoryUtil.memASCII(bytebuffer, i);
} catch (IOException e) {
} finally {
if (bytebuffer != null) {
MemoryUtil.memFree(bytebuffer);
}
} finally {
if (bytebuffer != null) {
MemoryUtil.memFree(bytebuffer);
}
}
}
return null;
}
return null;
}
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
ByteBuffer bytebuffer;
if (is instanceof FileInputStream) {
FileInputStream fileinputstream = (FileInputStream)is;
FileChannel filechannel = fileinputstream.getChannel();
bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1);
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
ByteBuffer bytebuffer;
if (is instanceof FileInputStream) {
FileInputStream fileinputstream = (FileInputStream)is;
FileChannel filechannel = fileinputstream.getChannel();
bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1);
while (filechannel.read(bytebuffer) != -1) { }
} else {
bytebuffer = MemoryUtil.memAlloc(8192);
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
while (filechannel.read(bytebuffer) != -1) { }
} else {
bytebuffer = MemoryUtil.memAlloc(8192);
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
while (readablebytechannel.read(bytebuffer) != -1) {
if (bytebuffer.remaining() == 0) {
bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
}
}
}
while (readablebytechannel.read(bytebuffer) != -1) {
if (bytebuffer.remaining() == 0) {
bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
}
}
}
return bytebuffer;
}
return bytebuffer;
}
}

View file

@ -1,5 +1,6 @@
package com.simibubi.create.foundation.render.backend.gl;
import com.simibubi.create.foundation.render.backend.RenderUtil;
import com.simibubi.create.foundation.render.backend.gl.shader.ProgramFogMode;
import org.lwjgl.opengl.GL20;
@ -53,9 +54,6 @@ public class BasicProgram extends GlProgram {
}
protected static void uploadMatrixUniform(int uniform, Matrix4f mat) {
Backend.MATRIX_BUFFER.position(0);
mat.write(Backend.MATRIX_BUFFER);
Backend.MATRIX_BUFFER.rewind();
GL20.glUniformMatrix4fv(uniform, false, Backend.MATRIX_BUFFER);
GL20.glUniformMatrix4fv(uniform, false, RenderUtil.writeMatrix(mat));
}
}

View file

@ -2,7 +2,8 @@ package com.simibubi.create.foundation.render.backend.instancing;
public interface IDynamicInstance {
/**
* Called every frame, this can be used to make more dynamic animations.
* Called every frame. This can be used to smoothly change instance data
* to allow for fancy animations that could not be achieved on the GPU alone.
*/
void beginFrame();
}

View file

@ -2,5 +2,9 @@ package com.simibubi.create.foundation.render.backend.instancing;
public interface ITickableInstance {
/**
* Called every tick. This is useful for things that don't have to be smooth,
* or to recalculate something that would only change after a game tick.
*/
void tick();
}

View file

@ -39,14 +39,6 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
public abstract void registerMaterials();
public void tick() {
int ticks = AnimationTickHolder.getTicks();
// Clean up twice a second. This doesn't have to happen every tick,
// but this does need to be run to ensure we don't miss anything.
if (ticks % 10 == 0) {
clean();
}
if (tickableInstances.size() > 0)
tickableInstances.values().forEach(ITickableInstance::tick);
}
@ -187,16 +179,13 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
return renderer;
}
private void clean() {
instances.keySet().removeIf(TileEntity::isRemoved);
}
public void invalidate() {
for (RenderMaterial<?, ?> material : materials.values()) {
material.delete();
}
instances.clear();
dynamicInstances.clear();
tickableInstances.clear();
}
public boolean canCreateInstance(TileEntity tile) {

View file

@ -16,7 +16,7 @@ public class ModelData extends BasicData {
}
public ModelData setTransform(MatrixStack stack) {
matrices = RenderUtil.bufferMatrices(stack.peek().getModel(), stack.peek().getNormal());
matrices = RenderUtil.writeMatrixStack(stack);
return this;
}

View file

@ -3,9 +3,19 @@
"package": "com.simibubi.create.foundation.mixin",
"compatibilityLevel": "JAVA_8",
"refmap": "create.refmap.json",
"client": ["AddRemoveTileMixin", "CancelTileEntityRenderMixin", "FogColorTrackerMixin", "LightUpdateMixin", "NetworkLightUpdateMixin", "RenderHooksMixin", "ShaderCloseMixin"],
"mixins": ["StepSoundMixin"],
"client": [
"TileAddMixin",
"CancelTileEntityRenderMixin",
"FogColorTrackerMixin",
"LightUpdateMixin",
"NetworkLightUpdateMixin",
"RenderHooksMixin",
"ShaderCloseMixin",
"TileRemoveMixin"
],
"injectors": {
"defaultRequire": 1
},
"minVersion": "0.8", "mixins": ["StepSoundMixin"]
"minVersion": "0.8"
}