55import net .minecraft .server .level .ChunkHolder ;
66import net .minecraft .world .level .chunk .LevelChunk ;
77import net .minecraft .world .level .chunk .LevelChunkSection ;
8- import net .minecraft .world .level .block .entity .BlockEntity ;
9- import net .minecraft .core .BlockPos ;
10- import java .util .Map ;
11- import java .lang .reflect .Field ;
12- import java .lang .reflect .Constructor ;
13- import net .minecraft .core .registries .Registries ;
148import net .minecraft .world .level .ChunkPos ;
159import net .minecraft .world .level .chunk .EmptyLevelChunk ;
1610import net .minecraft .world .level .chunk .status .ChunkStatus ;
17- import net .minecraft .world .level .chunk .PalettedContainer ;
1811import net .minecraft .world .level .block .Block ;
1912import net .minecraft .world .level .block .Blocks ;
2013import net .minecraft .world .level .block .state .BlockState ;
@@ -38,7 +31,7 @@ public Object getChunkIfLoaded(World world, int x, int z) {
3831
3932 if (chunkHolder != null ) {
4033 LevelChunk chunk = chunkHolder .getFullChunkNow ();
41- if (chunk != null && !(chunk instanceof EmptyLevelChunk )) {
34+ if (!(chunk instanceof EmptyLevelChunk )) {
4235 return chunk ;
4336 }
4437 }
@@ -63,93 +56,21 @@ public Object getNMSChunk(Chunk chunk) {
6356
6457 @ Override
6558 public Object cloneChunk (Object chunk ) {
66- if (!(chunk instanceof LevelChunk ))
59+ if (!(chunk instanceof LevelChunk original )) {
6760 return null ;
68- LevelChunk original = (LevelChunk ) chunk ;
69-
70- final LevelChunkSection [] originalSections = original .getSections ();
71- final LevelChunkSection [] newSections = new LevelChunkSection [originalSections .length ];
72-
73- LevelChunk newChunk = new LevelChunk (original .getLevel (), original .getPos ()) {
74- @ Override
75- public Map <BlockPos , BlockEntity > getBlockEntities () {
76- return original .getBlockEntities ();
77- }
78-
79- @ Override
80- public LevelChunkSection [] getSections () {
81- return newSections ;
82- }
83- };
61+ }
8462
85- // Copy critical data
63+ LevelChunk newChunk = new LevelChunk ( original . getLevel (), original . getPos ());
8664 newChunk .setInhabitedTime (original .getInhabitedTime ());
8765
88- for (int i = 0 ; i < originalSections .length ; i ++) {
89- LevelChunkSection oldSection = originalSections [i ];
90- if (oldSection != null && !oldSection .hasOnlyAir ()) {
91- try {
92- // get section Y using reflection if method is missing
93- Field bottomYField = LevelChunkSection .class .getDeclaredField ("bottomBlockY" );
94- bottomYField .setAccessible (true );
95- int bottomY = bottomYField .getInt (oldSection );
96- int sectionY = bottomY >> 4 ;
97- LevelChunkSection newSection = null ;
98- Object biomeRegistryOrContainer = null ;
99-
100- for (Constructor <?> c : LevelChunkSection .class .getDeclaredConstructors ()) {
101- if (c .getParameterCount () == 2 && c .getParameterTypes ()[0 ] == int .class ) {
102- c .setAccessible (true );
103- Class <?> argType = c .getParameterTypes ()[1 ];
104-
105- if (net .minecraft .core .Registry .class .isAssignableFrom (argType )) {
106- biomeRegistryOrContainer = original .getLevel ().registryAccess ()
107- .lookupOrThrow (Registries .BIOME );
108- newSection = (LevelChunkSection ) c .newInstance (sectionY , biomeRegistryOrContainer );
109- break ;
110- } else if (PalettedContainer .class .isAssignableFrom (argType )) {
111- biomeRegistryOrContainer = oldSection .getBiomes (); // already a container
112- newSection = (LevelChunkSection ) c .newInstance (sectionY , biomeRegistryOrContainer );
113- break ;
114- }
115- }
116- }
117-
118- if (newSection == null ) {
119- throw new RuntimeException ("Could not find suitable LevelChunkSection constructor" );
120- }
121-
122- // Reflective copy fields
123-
124- // 1. Biomes
125- Field biomesField = LevelChunkSection .class .getDeclaredField ("biomes" );
126- biomesField .setAccessible (true );
127- biomesField .set (newSection , oldSection .getBiomes ().copy ());
128-
129- // 2. States (BlockStates)
130- Field statesField = LevelChunkSection .class .getDeclaredField ("states" );
131- statesField .setAccessible (true );
132- statesField .set (newSection , oldSection .getStates ().copy ());
133-
134- // 3. Non-empty block count
135- Field nonEmptyCountField = LevelChunkSection .class
136- .getDeclaredField ("nonEmptyBlockCount" );
137- nonEmptyCountField .setAccessible (true );
138- short count = (short ) nonEmptyCountField .getShort (oldSection );
139- nonEmptyCountField .setShort (newSection , count );
140-
141- // 4. Ticking block count
142- Field tickingCountField = LevelChunkSection .class
143- .getDeclaredField ("tickingBlockCount" );
144- tickingCountField .setAccessible (true );
145- tickingCountField .setShort (newSection , (short ) tickingCountField .getShort (oldSection ));
66+ final LevelChunkSection [] originalSections = original .getSections ();
67+ final LevelChunkSection [] newSections = newChunk .getSections ();
14668
147- newSections [i ] = newSection ;
69+ for (int i = 0 ; i < originalSections .length && i < newSections .length ; i ++) {
70+ LevelChunkSection oldSection = originalSections [i ];
14871
149- } catch (Exception e ) {
150- e .printStackTrace ();
151- newSections [i ] = oldSection ;
152- }
72+ if (oldSection != null && !oldSection .hasOnlyAir ()) {
73+ newSections [i ] = oldSection .copy ();
15374 }
15475 }
15576
@@ -158,26 +79,53 @@ public LevelChunkSection[] getSections() {
15879
15980 @ Override
16081 public void obfuscateChunk (Object chunkObj , boolean hideOres , boolean addFakeOres , double density ) {
161- if (!(chunkObj instanceof LevelChunk ))
82+ if (!(chunkObj instanceof LevelChunk chunk ))
16283 return ;
163- LevelChunk chunk = (LevelChunk ) chunkObj ;
84+
85+ if (!hideOres && !addFakeOres )
86+ return ;
87+
16488 Random random = new Random ();
16589
16690 for (LevelChunkSection section : chunk .getSections ()) {
167- if (section == null || section .hasOnlyAir ())
91+ if (section .hasOnlyAir ())
16892 continue ;
16993
94+ BlockState stone = null ;
95+ BlockState deepslate = null ;
96+ BlockState netherrack = null ;
97+
17098 for (int x = 0 ; x < 16 ; x ++) {
17199 for (int y = 0 ; y < 16 ; y ++) {
172100 for (int z = 0 ; z < 16 ; z ++) {
173101 BlockState state = section .getBlockState (x , y , z );
174102 Block block = state .getBlock ();
175103
176- if (hideOres && isValuableOre (block )) {
177- section .setBlockState (x , y , z , getReplacement (block ).defaultBlockState (), false );
178- } else if (addFakeOres && shouldFakeOre (block )) {
179- if (random .nextDouble () < density ) {
180- section .setBlockState (x , y , z , getRandomOre (block , random ).defaultBlockState (), false );
104+ if (hideOres ) {
105+ if (isValuableOre (block )) {
106+ Block replacement = getReplacement (block );
107+ BlockState replacementState ;
108+
109+ if (replacement == Blocks .STONE ) {
110+ if (stone == null ) stone = Blocks .STONE .defaultBlockState ();
111+ replacementState = stone ;
112+ } else if (replacement == Blocks .DEEPSLATE ) {
113+ if (deepslate == null ) deepslate = Blocks .DEEPSLATE .defaultBlockState ();
114+ replacementState = deepslate ;
115+ } else {
116+ if (netherrack == null ) netherrack = Blocks .NETHERRACK .defaultBlockState ();
117+ replacementState = netherrack ;
118+ }
119+
120+ section .setBlockState (x , y , z , replacementState , false );
121+ continue ;
122+ }
123+ }
124+
125+ if (addFakeOres ) {
126+ if (shouldFakeOre (block ) && random .nextDouble () < density ) {
127+ Block fakeOre = getRandomOre (block , random );
128+ section .setBlockState (x , y , z , fakeOre .defaultBlockState (), false );
181129 }
182130 }
183131 }
0 commit comments