Skip to content

Commit bb2f4a7

Browse files
committed
fix anti-xray issues & minor changes
1 parent 359d6aa commit bb2f4a7

File tree

2 files changed

+64
-100
lines changed

2 files changed

+64
-100
lines changed

src/main/java/me/mapacheee/extendedhorizons/viewdistance/service/FakeChunkService.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,7 @@ public CompletableFuture<Integer> sendFakeChunks(Player player, Set<Long> chunkK
572572
* Attempts to get a chunk from the servers memory cache or our own cache
573573
*/
574574
private Object getChunkFromMemoryCache(World world, int chunkX, int chunkZ) {
575-
boolean antiXrayEnabled = configService.get().performance().fakeChunks().antiXray().enabled();
576-
if (!configService.get().performance().fakeChunks().enableMemoryCache() || antiXrayEnabled) {
575+
if (!configService.get().performance().fakeChunks().enableMemoryCache()) {
577576
return null;
578577
}
579578

@@ -670,7 +669,24 @@ private void sendChunkPacket(Player player, Object chunk, long key, Set<Long> se
670669
if (!player.isOnline())
671670
return null;
672671

673-
return nmsPacketAccess.createChunkPacket(chunk);
672+
Object chunkToSend = chunk;
673+
MainConfig.PerformanceConfig.FakeChunksConfig.AntiXrayConfig antiXray = configService.get().performance().fakeChunks().antiXray();
674+
675+
if (antiXray != null && antiXray.enabled()) {
676+
// Clone chunk to avoid modifying original server chunk
677+
chunkToSend = nmsChunkAccess.cloneChunk(chunk);
678+
if (chunkToSend != null) {
679+
nmsChunkAccess.obfuscateChunk(
680+
chunkToSend,
681+
antiXray.hideOres(),
682+
antiXray.addFakeOres(),
683+
antiXray.fakeOreDensity());
684+
} else {
685+
chunkToSend = chunk; // Fallback to original if clone fails
686+
}
687+
}
688+
689+
return nmsPacketAccess.createChunkPacket(chunkToSend);
674690
} catch (Exception e) {
675691
if (DEBUG)
676692
logger.warn("[EH] Failed to create packet: {}", e.getMessage());

src/main/java/me/mapacheee/extendedhorizons/viewdistance/service/nms/v1_21_R1/NMSChunkAccess_v1_21_R1.java

Lines changed: 45 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,9 @@
55
import net.minecraft.server.level.ChunkHolder;
66
import net.minecraft.world.level.chunk.LevelChunk;
77
import 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;
148
import net.minecraft.world.level.ChunkPos;
159
import net.minecraft.world.level.chunk.EmptyLevelChunk;
1610
import net.minecraft.world.level.chunk.status.ChunkStatus;
17-
import net.minecraft.world.level.chunk.PalettedContainer;
1811
import net.minecraft.world.level.block.Block;
1912
import net.minecraft.world.level.block.Blocks;
2013
import 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

Comments
 (0)