mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-28 07:56:26 +01:00
F3+A
- Reloading chunks correctly reloads block entity instances
This commit is contained in:
parent
0c6a75ade5
commit
ca554f5993
5 changed files with 98 additions and 3 deletions
|
@ -8,6 +8,7 @@ import com.jozufozu.flywheel.core.Contexts;
|
||||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||||
|
import com.jozufozu.flywheel.util.ChunkIter;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -58,8 +59,9 @@ public class InstanceWorld {
|
||||||
* Instantiate all the necessary instances to render the given world.
|
* Instantiate all the necessary instances to render the given world.
|
||||||
*/
|
*/
|
||||||
public void loadAll(ClientLevel world) {
|
public void loadAll(ClientLevel world) {
|
||||||
// FIXME: no more global blockEntity list
|
ChunkIter.forEachChunk(world, chunk -> {
|
||||||
// world.blockEntityList.forEach(tileEntityInstanceManager::add);
|
chunk.getBlockEntities().values().forEach(tileEntityInstanceManager::add);
|
||||||
|
});
|
||||||
world.entitiesForRendering()
|
world.entitiesForRendering()
|
||||||
.forEach(entityInstanceManager::add);
|
.forEach(entityInstanceManager::add);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.util.ArrayList;
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||||
import com.jozufozu.flywheel.light.LightUpdater;
|
import com.jozufozu.flywheel.light.LightUpdater;
|
||||||
|
import com.jozufozu.flywheel.util.ChunkIter;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
@ -47,6 +48,12 @@ public class ForgeEvents {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void unloadWorld(WorldEvent.Unload event) {
|
||||||
|
LevelAccessor world = event.getWorld();
|
||||||
|
ChunkIter._unload(world);
|
||||||
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void tickLight(TickEvent.ClientTickEvent e) {
|
public static void tickLight(TickEvent.ClientTickEvent e) {
|
||||||
if (e.phase == TickEvent.Phase.END && Backend.isGameActive())
|
if (e.phase == TickEvent.Phase.END && Backend.isGameActive())
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.jozufozu.flywheel.mixin;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
|
|
||||||
|
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 com.jozufozu.flywheel.util.ChunkIter;
|
||||||
|
|
||||||
|
import net.minecraft.client.multiplayer.ClientChunkCache;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In order to iterate over all loaded chunks, we do something absolutely foul.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* By stealing the reference to the backing array of the chunk storage when it is constructed, we gain 0 maintenance
|
||||||
|
* access to the full array of loaded chunks.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
@Mixin(targets = "net.minecraft.client.multiplayer.ClientChunkCache$Storage")
|
||||||
|
public class LeakChunkStorageArrayMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
AtomicReferenceArray<LevelChunk> chunks;
|
||||||
|
|
||||||
|
@Inject(method = "<init>", at = @At("TAIL"))
|
||||||
|
private void leakBackingArray(ClientChunkCache outer, int chunkRadius, CallbackInfo ci) {
|
||||||
|
ChunkIter._putStorageReference(outer.getLevel(), chunks);
|
||||||
|
}
|
||||||
|
}
|
46
src/main/java/com/jozufozu/flywheel/util/ChunkIter.java
Normal file
46
src/main/java/com/jozufozu/flywheel/util/ChunkIter.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package com.jozufozu.flywheel.util;
|
||||||
|
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for iterating over all loaded chunks.
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class ChunkIter {
|
||||||
|
|
||||||
|
private static final WeakHashMap<BlockGetter, AtomicReferenceArray<LevelChunk>> storages = new WeakHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over all loaded chunks in a level.
|
||||||
|
*/
|
||||||
|
public static void forEachChunk(BlockGetter level, Consumer<LevelChunk> consumer) {
|
||||||
|
AtomicReferenceArray<LevelChunk> storage = storages.get(level);
|
||||||
|
|
||||||
|
if (storage == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < storage.length(); i++) {
|
||||||
|
LevelChunk chunk = storage.get(i);
|
||||||
|
if (chunk != null) {
|
||||||
|
consumer.accept(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// INTERNAL MAINTENENCE METHODS BELOW
|
||||||
|
|
||||||
|
public static void _putStorageReference(BlockGetter level, AtomicReferenceArray<LevelChunk> storage) {
|
||||||
|
storages.put(level, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void _unload(BlockGetter world) {
|
||||||
|
storages.remove(world);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,8 @@
|
||||||
"light.NetworkLightUpdateMixin",
|
"light.NetworkLightUpdateMixin",
|
||||||
"LevelRendererAccessor",
|
"LevelRendererAccessor",
|
||||||
"InstanceAddMixin",
|
"InstanceAddMixin",
|
||||||
"InstanceRemoveMixin"
|
"InstanceRemoveMixin",
|
||||||
|
"LeakChunkStorageArrayMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|
Loading…
Reference in a new issue