Skip to content

Commit fa79ef9

Browse files
authored
Implemented final Forge features (#199)
* Cache world instead of creating a new instance every time on Forge * Implemented regenerateChunk * Implemented ForgeBlockData.getCopy, made ILeaves extend IBlockData (same as the other subclasses) * Implemented Forge Leaves and Waterlogged - Leaves are also watterlogged since 1.19 - not yet 100% sure what to do with that on spigot * remove substring from getWorld
1 parent 39267fe commit fa79ef9

File tree

8 files changed

+125
-9
lines changed

8 files changed

+125
-9
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.github.kevindagame.voxelsniper.blockdata.leaves
22

3-
interface ILeaves {
3+
import com.github.kevindagame.voxelsniper.blockdata.IBlockData
4+
5+
interface ILeaves : IBlockData {
46
fun isPersistent(): Boolean
57
fun setPersistent(persistent: Boolean)
68
}

VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/ForgeVoxelSniperListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private BlockFace getBlockFace(PlayerInteractEvent event) {
8181
private @Nullable
8282
IBlock getClickedBlock(PlayerInteractEvent event) {
8383
if (event instanceof PlayerInteractEvent.LeftClickBlock || event instanceof PlayerInteractEvent.RightClickBlock) {
84-
var world = new ForgeWorld(((ServerLevel) event.getLevel()));
84+
var world = VoxelSniperForge.getInstance().getWorld(((ServerLevel) event.getLevel()));
8585
var pos = ForgeLocation.fromForgeBlockPos(world, event.getPos());
8686
return world.getBlock(pos);
8787

VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/VoxelSniperForge.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
import com.github.kevindagame.voxelsniperforge.material.BlockMaterial;
1919
import com.github.kevindagame.voxelsniperforge.material.ItemMaterial;
2020
import com.github.kevindagame.voxelsniperforge.permissions.ForgePermissionManager;
21+
import com.github.kevindagame.voxelsniperforge.world.ForgeWorld;
2122

22-
import net.minecraft.core.Holder;
2323
import net.minecraft.core.Registry;
2424
import net.minecraft.core.registries.Registries;
25-
import net.minecraft.resources.ResourceKey;
2625
import net.minecraft.resources.ResourceLocation;
26+
import net.minecraft.server.level.ServerLevel;
2727
import net.minecraft.server.level.ServerPlayer;
2828
import net.minecraft.world.level.biome.Biome;
2929
import net.minecraft.world.level.levelgen.feature.ChorusPlantFeature;
@@ -65,6 +65,7 @@ public class VoxelSniperForge implements IVoxelsniper {
6565
private static VoxelSniperForge instance;
6666

6767
private final Map<UUID, ForgePlayer> players = new HashMap<>();
68+
private final Map<String, ForgeWorld> worlds = new HashMap<>();
6869
public static VoxelSniperForge getInstance() {
6970
return instance;
7071
}
@@ -243,4 +244,13 @@ public static boolean isTreeType(@NotNull ConfiguredFeature<?, ?> feature) {
243244
feature.config() instanceof HugeFungusConfiguration ||
244245
feature.feature() instanceof ChorusPlantFeature;
245246
}
247+
248+
@NotNull
249+
public ForgeWorld getWorld(@NotNull ServerLevel level) {
250+
var name = level.toString();
251+
if (this.worlds.get(name) != null) return this.worlds.get(name);
252+
ForgeWorld res = new ForgeWorld(level);
253+
this.worlds.put(name, res);
254+
return res;
255+
}
246256
}

VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/blockdata/ForgeBlockData.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.github.kevindagame.voxelsniper.blockdata.IBlockData;
44
import com.github.kevindagame.voxelsniper.material.VoxelMaterial;
5+
import com.github.kevindagame.voxelsniperforge.blockdata.leaves.ForgeLeaves;
56
import com.github.kevindagame.voxelsniperforge.blockdata.redstoneWire.ForgeRedstoneWire;
7+
import com.github.kevindagame.voxelsniperforge.blockdata.waterlogged.ForgeWaterlogged;
68
import com.github.kevindagame.voxelsniperforge.material.BlockMaterial;
79
import com.google.common.base.Preconditions;
810
import com.mojang.brigadier.StringReader;
@@ -13,7 +15,9 @@
1315
import net.minecraft.commands.arguments.blocks.BlockStateParser;
1416
import net.minecraft.core.registries.BuiltInRegistries;
1517
import net.minecraft.world.level.block.Block;
18+
import net.minecraft.world.level.block.LeavesBlock;
1619
import net.minecraft.world.level.block.RedStoneWireBlock;
20+
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
1721
import net.minecraft.world.level.block.state.BlockState;
1822
import net.minecraft.world.level.block.state.properties.Property;
1923
import net.minecraftforge.registries.ForgeRegistries;
@@ -89,7 +93,7 @@ public IBlockData merge(IBlockData newData) {
8993

9094
@Override
9195
public IBlockData getCopy() {
92-
throw new UnsupportedOperationException("Not implemented yet");
96+
return this.clone();
9397
}
9498

9599
@Override
@@ -150,6 +154,10 @@ public static ForgeBlockData fromData(BlockState blockData) {
150154
Block b = blockData.getBlock();
151155
if (b instanceof RedStoneWireBlock)
152156
return new ForgeRedstoneWire(blockData);
157+
if (b instanceof LeavesBlock)
158+
return new ForgeLeaves(blockData);
159+
if (b instanceof SimpleWaterloggedBlock)
160+
return new ForgeWaterlogged(blockData);
153161
return new ForgeBlockData(blockData);
154162
}
155163
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.github.kevindagame.voxelsniperforge.blockdata.leaves
2+
3+
import com.github.kevindagame.voxelsniper.blockdata.leaves.ILeaves
4+
import com.github.kevindagame.voxelsniperforge.blockdata.waterlogged.ForgeWaterlogged
5+
import net.minecraft.world.level.block.LeavesBlock
6+
import net.minecraft.world.level.block.state.BlockState
7+
8+
class ForgeLeaves(state: BlockState?) : ForgeWaterlogged(state), ILeaves {
9+
override fun isPersistent(): Boolean {
10+
return get(LeavesBlock.PERSISTENT)
11+
}
12+
13+
override fun setPersistent(persistent: Boolean) {
14+
set(LeavesBlock.PERSISTENT, persistent)
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.github.kevindagame.voxelsniperforge.blockdata.waterlogged
2+
3+
import com.github.kevindagame.voxelsniper.blockdata.waterlogged.IWaterlogged
4+
import com.github.kevindagame.voxelsniperforge.blockdata.ForgeBlockData
5+
import net.minecraft.world.level.block.state.BlockState
6+
import net.minecraft.world.level.block.state.properties.BlockStateProperties
7+
8+
open class ForgeWaterlogged(state: BlockState?) : ForgeBlockData(state), IWaterlogged {
9+
override fun isWaterlogged(): Boolean {
10+
return get(BlockStateProperties.WATERLOGGED)
11+
}
12+
13+
override fun setWaterlogged(waterlogged: Boolean) {
14+
set(BlockStateProperties.WATERLOGGED, waterlogged)
15+
}
16+
}

VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/entity/ForgeEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public BaseLocation getLocation() {
5858

5959
@Override
6060
public IWorld getWorld() {
61-
return new ForgeWorld((ServerLevel) this.entity.level());
61+
return VoxelSniperForge.getInstance().getWorld((ServerLevel) this.entity.level());
6262
}
6363

6464
@Override

VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/world/ForgeWorld.java

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,34 @@
1616
import com.github.kevindagame.voxelsniperforge.chunk.ForgeChunk;
1717
import com.github.kevindagame.voxelsniperforge.entity.ForgeEntity;
1818
import com.github.kevindagame.voxelsniperforge.location.ForgeLocation;
19+
import com.google.common.collect.ImmutableList;
20+
import com.google.common.collect.Lists;
21+
import com.mojang.datafixers.util.Unit;
1922

23+
import net.minecraft.Util;
2024
import net.minecraft.core.BlockPos;
2125
import net.minecraft.core.Holder;
2226
import net.minecraft.core.QuartPos;
2327
import net.minecraft.core.registries.Registries;
2428
import net.minecraft.resources.ResourceKey;
2529
import net.minecraft.resources.ResourceLocation;
30+
import net.minecraft.server.level.ServerChunkCache;
2631
import net.minecraft.server.level.ServerLevel;
2732
import net.minecraft.util.RandomSource;
33+
import net.minecraft.util.thread.ProcessorMailbox;
2834
import net.minecraft.world.entity.Entity;
2935
import net.minecraft.world.entity.EntityType;
3036
import net.minecraft.world.entity.LightningBolt;
37+
import net.minecraft.world.level.ChunkPos;
3138
import net.minecraft.world.level.WorldGenLevel;
3239
import net.minecraft.world.level.biome.Biome;
3340
import net.minecraft.world.level.biome.BiomeResolver;
41+
import net.minecraft.world.level.block.Blocks;
3442
import net.minecraft.world.level.chunk.ChunkAccess;
3543
import net.minecraft.world.level.chunk.ChunkGenerator;
3644
import net.minecraft.world.level.chunk.ChunkStatus;
45+
import net.minecraft.world.level.chunk.ImposterProtoChunk;
46+
import net.minecraft.world.level.chunk.LevelChunk;
3747
import net.minecraft.world.level.levelgen.Heightmap;
3848
import net.minecraft.world.level.levelgen.LegacyRandomSource;
3949
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
@@ -46,6 +56,7 @@
4656
import java.util.ArrayList;
4757
import java.util.List;
4858
import java.util.Random;
59+
import java.util.concurrent.CompletableFuture;
4960
import java.util.function.Predicate;
5061

5162
public record ForgeWorld(@NotNull ServerLevel level) implements IWorld {
@@ -109,7 +120,6 @@ public String getName() {
109120

110121
@Override
111122
public void spawn(BaseLocation location, VoxelEntityType entity) {
112-
//TODO test this
113123
var tag = EntityType.byString(entity.getKey());
114124
if (tag.isPresent()) {
115125
Entity created = tag.get().create(level);
@@ -149,13 +159,67 @@ public void setBiome(int x, int y, int z, VoxelBiome selectedBiome) {
149159

150160
@Override
151161
public int getHighestBlockYAt(int x, int z) {
152-
//TODO test this
153162
return level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, new BlockPos(x, 0, z)).getY();
154163
}
155164

156165
@Override
157166
public void regenerateChunk(int x, int z) {
158-
throw new UnsupportedOperationException("Not implemented yet");
167+
// copied from net.minecraft.server.commands.ResetChunksCommand, seems to work
168+
ServerChunkCache serverchunkcache = this.level.getChunkSource();
169+
serverchunkcache.chunkMap.debugReloadGenerator();
170+
171+
// clear all blocks
172+
final ChunkPos chunkPos = new ChunkPos(x, z);
173+
if (serverchunkcache.getChunk(x, z, false) != null) {
174+
for(BlockPos blockpos : BlockPos.betweenClosed(chunkPos.getMinBlockX(), this.level.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), this.level.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ())) {
175+
this.level.setBlock(blockpos, Blocks.AIR.defaultBlockState(), 16);
176+
}
177+
}
178+
179+
ProcessorMailbox<Runnable> processormailbox = ProcessorMailbox.create(Util.backgroundExecutor(), "worldgen-resetchunks");
180+
181+
// Generate chunk
182+
for(ChunkStatus chunkstatus : ImmutableList.of(ChunkStatus.BIOMES, ChunkStatus.NOISE, ChunkStatus.SURFACE, ChunkStatus.CARVERS, ChunkStatus.FEATURES, ChunkStatus.INITIALIZE_LIGHT)) {
183+
CompletableFuture<Unit> completablefuture = CompletableFuture.supplyAsync(() -> Unit.INSTANCE, processormailbox::tell);
184+
185+
if (serverchunkcache.getChunk(x, z, false) != null) {
186+
List<ChunkAccess> list = Lists.newArrayList();
187+
int range = Math.max(1, chunkstatus.getRange());
188+
189+
for(int z1 = z - range; z1 <= z + range; ++z1) {
190+
for(int x1 = x - range; x1 <= x + range; ++x1) {
191+
ChunkAccess chunkaccess = serverchunkcache.getChunk(x1, z1, chunkstatus.getParent(), true);
192+
ChunkAccess newChunkaccess;
193+
if (chunkaccess instanceof ImposterProtoChunk) {
194+
newChunkaccess = new ImposterProtoChunk(((ImposterProtoChunk)chunkaccess).getWrapped(), true);
195+
} else if (chunkaccess instanceof LevelChunk) {
196+
newChunkaccess = new ImposterProtoChunk((LevelChunk)chunkaccess, true);
197+
} else {
198+
newChunkaccess = chunkaccess;
199+
}
200+
list.add(newChunkaccess);
201+
}
202+
}
203+
204+
completablefuture = completablefuture.thenComposeAsync((unit) -> chunkstatus.generate(processormailbox::tell, this.level, serverchunkcache.getGenerator(), this.level.getStructureManager(), serverchunkcache.getLightEngine(), (access) -> {
205+
throw new UnsupportedOperationException("Not creating full chunks here");
206+
}, list).thenApply((either) -> {
207+
if (chunkstatus == ChunkStatus.NOISE) {
208+
either.left().ifPresent((access) -> Heightmap.primeHeightmaps(access, ChunkStatus.POST_FEATURES));
209+
}
210+
return Unit.INSTANCE;
211+
}), processormailbox::tell);
212+
}
213+
214+
this.level.getServer().managedBlock(completablefuture::isDone);
215+
}
216+
217+
// fire blockChanged events
218+
if (serverchunkcache.getChunk(x, z, false) != null) {
219+
for(BlockPos blockpos1 : BlockPos.betweenClosed(chunkPos.getMinBlockX(), this.level.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), this.level.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ())) {
220+
serverchunkcache.blockChanged(blockpos1);
221+
}
222+
}
159223
}
160224

161225
@Override

0 commit comments

Comments
 (0)