Compare commits

..

26 Commits

Author SHA1 Message Date
James Seibel 89b959d3f5 Up version number 2.1.3-dev -> 2.2.0 2024-08-20 17:45:42 -05:00
James Seibel d62e50d6f4 Fix Legacy GL causing fog to smear 2024-08-20 17:45:31 -05:00
James Seibel 16836a2b49 Move MixinChunkMap shared code to common 2024-08-18 14:46:49 -05:00
James Seibel f5651f26a5 Merge !65 (fix neo/forge chunk update events) 2024-08-18 14:31:24 -05:00
James Seibel 82ff59c857 Fix fog and SSAO being broken by some mods 2024-08-17 22:29:42 -05:00
James Seibel 8af61041f0 Remove 1.21 from CI build script
1.21.1 also covers 1.21
2024-08-16 17:28:36 -05:00
James Seibel 2a9136b56f Merge 1.21.1 and 1.21 2024-08-15 07:21:19 -05:00
James Seibel 64da6c811d revert temporary 1.17.1 breakage 2024-08-13 17:24:18 -05:00
James Seibel e6b93e0d92 forgot to close test preprocessor 2024-08-13 07:46:49 -05:00
James Seibel f874219a64 Wrong 1.17.1 perpreocessor used 2024-08-13 07:33:39 -05:00
James Seibel b4822740f4 temporarily break 1.17 compiling to test gitlab bages 2024-08-13 07:33:04 -05:00
James Seibel af205a50b4 Deprecate IDhApiWorldGenerator.isBusy(), task queuing is now handled internally 2024-08-12 22:20:14 -05:00
James Seibel 2f6eaf79bd Add optional DhApiChunk validation for world gen 2024-08-12 21:47:58 -05:00
James Seibel 625f1e700f Fix MC 1.21 / 1.21.1 2024-08-12 21:05:15 -05:00
James Seibel 897d5b0b11 Change MC 1.21 -> 1.21.1 in CI version 2024-08-12 19:53:48 -05:00
James Seibel 95641e2f4e Allow adding empty lists to DhApiChunk 2024-08-11 22:01:29 -05:00
James Seibel cd856b86c7 Fix DhApiChunk setDataPoints failing for empty lists 2024-08-11 21:55:19 -05:00
James Seibel c00aa6d627 Add MC 1.21.1 2024-08-11 20:05:24 -05:00
James Seibel 398a3fb0bc Add alex's cave warning message 2024-08-11 09:55:12 -05:00
James Seibel e0fa638ad9 Fix beacons not enabling/disabling correctly 2024-08-09 07:26:20 -05:00
James Seibel 4e42cbd4ce Fix frustum culling when the screen is warped 2024-08-07 18:55:09 -05:00
James Seibel b6c6be77cd Fix beacons not being updated 2024-08-07 07:47:30 -05:00
James Seibel 0964293a72 Fix direct memory leak and remove config for GpuUpload 2024-08-07 07:30:01 -05:00
James Seibel c8b6141ce0 Improve LOD detail level detection and hole filling 2024-08-04 08:31:03 -05:00
James Seibel 948540369f Attempt to improve LOD building speed and reduce broken lighting on servers 2024-08-03 17:11:22 -05:00
James Seibel 363df0ad6f Fix MC 1.16/1.17 compiling 2024-08-03 11:38:02 -05:00
58 changed files with 846 additions and 289 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ build:
stage: build
parallel:
matrix:
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21"]
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21.1"]
script:
# this both runs the unit tests and assembles the code
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
@@ -0,0 +1,85 @@
package com.seibel.distanthorizons.common.commonMixins;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class MixinChunkMapCommon
{
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
{
// is this position already being updated?
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(chunk.getPos().x, chunk.getPos().z))
{
return;
}
// is this chunk being saved to disk?
boolean savingChunkToDisk = ci.getReturnValue();
// true means a chunk was saved to disk
if (!savingChunkToDisk)
{
return;
}
// TODO are the following validations necessary since we are checking above if
// the callback return value should state if the chunk was actually saved or not?
// Do we trust it to always be correct?
// corrupt/incomplete chunk validation //
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
// this logic should prevent that from happening
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
{
return;
}
#else
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
{
return;
}
#endif
// biome validation //
// some chunks may be missing their biomes, which cause issues when attempting to save them
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
if (chunk.getBiomes() == null)
{
return;
}
#else
try
{
// this will throw an exception if the biomes aren't set up
chunk.getNoiseBiome(0,0,0);
}
catch (Exception e)
{
return;
}
#endif
// submit the update event
ServerApi.INSTANCE.serverChunkSaveEvent(
new ChunkWrapper(chunk, level, ServerLevelWrapper.getWrapper(level)),
ServerLevelWrapper.getWrapper(level)
);
}
}
@@ -155,7 +155,7 @@ public class WrapperFactory implements IWrapperFactory
}
}
#if MC_VER <= MC_1_21
//#if MC_VER <= MC_1_XX_X
else if (objectArray.length == 2)
{
// correct number of parameters from the API
@@ -201,16 +201,7 @@ public class WrapperFactory implements IWrapperFactory
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
#else
// Intentional compiler error to bring attention to the missing wrapper function.
// If you need to work on an unimplemented version but don't have the ability to implement this yet
// you can comment it out, but please don't commit it. Someone will have to implement it.
// After implementing the new version please read this method's javadocs for instructions
// on what other locations also need to be updated, the DhAPI specifically needs to
// be updated to state which objects this method accepts.
not implemented for this version of Minecraft!
#endif
//#endif
}
/**
* Note: when this is updated for different MC versions,
@@ -220,16 +211,13 @@ public class WrapperFactory implements IWrapperFactory
{
String[] expectedClassNames;
#if MC_VER <= MC_1_21
//#if MC_VER <= MC_1_XX_X
expectedClassNames = new String[]
{
ChunkAccess.class.getName(),
ServerLevel.class.getName() + "] or [" + ClientLevel.class.getName()
};
#else
// See preprocessor comment in createChunkWrapper() for full documentation
not implemented for this version of Minecraft!
#endif
//#endif
return createWrapperErrorMessage("Chunk wrapper", expectedClassNames, objectArray);
}
@@ -268,7 +256,7 @@ public class WrapperFactory implements IWrapperFactory
Biome biome = (Biome) objectArray[0];
return BiomeWrapper.getBiomeWrapper(biome, coreLevelWrapper);
#elif MC_VER <= MC_1_21
#else
if (!(objectArray[0] instanceof Holder) || !(((Holder<?>) objectArray[0]).value() instanceof Biome))
{
throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
@@ -276,9 +264,6 @@ public class WrapperFactory implements IWrapperFactory
Holder<Biome> biomeHolder = (Holder<Biome>) objectArray[0];
return BiomeWrapper.getBiomeWrapper(biomeHolder, coreLevelWrapper);
#else
// See preprocessor comment in createChunkWrapper() for full documentation (not a typo, check createChunkWrapper()'s else statement for full documentation)
not implemented for this version of Minecraft!
#endif
}
/**
@@ -291,11 +276,8 @@ public class WrapperFactory implements IWrapperFactory
#if MC_VER < MC_1_18_2
expectedClassNames = new String[] { Biome.class.getName() };
#elif MC_VER <= MC_1_21
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
#else
// See preprocessor comment in createChunkWrapper() for full documentation
not implemented for this version of Minecraft!
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
#endif
return createWrapperErrorMessage("Biome wrapper", expectedClassNames, objectArray);
@@ -312,7 +294,7 @@ public class WrapperFactory implements IWrapperFactory
#if MC_VER <= MC_1_21
//#if MC_VER <= MC_1_XX_X
if (objectArray.length != 1)
{
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
@@ -324,10 +306,7 @@ public class WrapperFactory implements IWrapperFactory
BlockState blockState = (BlockState) objectArray[0];
return BlockStateWrapper.fromBlockState(blockState, coreLevelWrapper);
#else
// See preprocessor comment in createChunkWrapper() for full documentation (not a typo, check createChunkWrapper()'s else statement for full documentation)
not implemented for this version of Minecraft!
#endif
//#endif
}
/**
* Note: when this is updated for different MC versions,
@@ -339,11 +318,8 @@ public class WrapperFactory implements IWrapperFactory
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
expectedClassNames = new String[] { Biome.class.getName() };
#elif MC_VER <= MC_1_21
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
#else
// See preprocessor comment in createChunkWrapper() for full documentation
not implemented for this version of Minecraft!
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
#endif
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
@@ -293,7 +293,7 @@ public class BiomeWrapper implements IBiomeWrapper
ResourceLocation resourceLocation;
try
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
@@ -498,7 +498,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
ResourceLocation resourceLocation;
try
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
@@ -305,7 +305,7 @@ public class ChunkWrapper implements IChunkWrapper
public ChunkStatus getStatus() { return getStatus(this.getChunk()); }
public static ChunkStatus getStatus(ChunkAccess chunk)
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
return chunk.getStatus();
#else
return chunk.getPersistedStatus();
@@ -390,6 +390,8 @@ public class ChunkWrapper implements IChunkWrapper
return this.blockLightStorage;
}
public void setBlockLightStorage(ChunkLightStorage lightStorage) { this.blockLightStorage = lightStorage; }
@Override
public void clearDhBlockLighting() { this.getBlockLightStorage().clear(); }
@Override
@@ -404,6 +406,8 @@ public class ChunkWrapper implements IChunkWrapper
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
this.getSkyLightStorage().set(relX, y, relZ, lightValue);
}
@Override
public void clearDhSkyLighting() { this.getSkyLightStorage().clear(); }
private ChunkLightStorage getSkyLightStorage()
{
@@ -259,7 +259,7 @@ public class ClassicConfigGUI
0, 0,
// Some textuary stuff
0,
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
@@ -76,7 +76,7 @@ public class UpdateModScreen extends DhScreen
0, 0,
// Some textuary stuff
0,
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "logo.png"),
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
@@ -107,7 +107,7 @@ public class UpdateModScreen extends DhScreen
0, 0,
// Some textuary stuff
0,
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
@@ -21,7 +21,7 @@ public class MinecraftDedicatedServerWrapper implements IMinecraftSharedWrapper
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
}
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
return this.dedicatedServer.getServerDirectory();
#else
return this.dedicatedServer.getServerDirectory().toFile();
@@ -165,7 +165,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
if (MC.level.dimensionType().hasSkyLight())
{
float frameTime;
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
frameTime = MC.getFrameTime();
#else
frameTime = MC.getTimer().getRealtimeDeltaTicks();
@@ -85,7 +85,7 @@ import net.minecraft.world.level.material.Fluids;
#if MC_VER == MC_1_20_6
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkType;
#elif MC_VER == MC_1_21
#elif MC_VER >= MC_1_21_1
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkType;
#endif
@@ -325,7 +325,7 @@ public class ChunkLoader
}
private static
#if MC_VER < MC_1_20_6 ChunkStatus.ChunkType
#elif MC_VER < MC_1_21 ChunkType
#elif MC_VER < MC_1_21_1 ChunkType
#else ChunkType #endif
readChunkType(CompoundTag tagLevel)
{
@@ -1,6 +1,6 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
#if MC_VER >= MC_1_21
#if MC_VER >= MC_1_21_1
import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.world.level.ChunkPos;
@@ -63,7 +63,7 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.*;
#endif
#if MC_VER == MC_1_21
#if MC_VER >= MC_1_21_1
import net.minecraft.util.StaticCache2D;
import com.google.common.collect.ImmutableList;
import net.minecraft.server.level.GenerationChunkHolder;
@@ -127,7 +127,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
{
#if MC_VER == MC_1_16_5
super(serverLevel, chunkList);
#elif MC_VER < MC_1_21
#elif MC_VER < MC_1_21_1
super(serverLevel, chunkList, chunkStatus, writeRadius);
#else
super(serverLevel,
@@ -68,7 +68,7 @@ public final class StepBiomes
}
else if (chunk instanceof ProtoChunk)
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
@@ -89,7 +89,7 @@ public final class StepBiomes
#elif MC_VER < MC_1_19_4
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#elif MC_VER < MC_1_21
#elif MC_VER < MC_1_21_1
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else
@@ -66,7 +66,7 @@ public final class StepFeatures
}
else if (chunk instanceof ProtoChunk)
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
@@ -68,7 +68,7 @@ public final class StepNoise
continue;
}
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
@@ -87,7 +87,7 @@ public final class StepNoise
#elif MC_VER < MC_1_19_2
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#elif MC_VER < MC_1_21
#elif MC_VER < MC_1_21_1
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), this.environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else
@@ -66,7 +66,7 @@ public final class StepStructureReference
}
else if (chunk instanceof ProtoChunk)
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
@@ -83,7 +83,7 @@ public final class StepStructureStart
}
else if (chunk instanceof ProtoChunk)
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
@@ -65,7 +65,7 @@ public final class StepSurface
}
else if (chunk instanceof ProtoChunk)
{
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
@@ -1,14 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "com.seibel.distanthorizons.common.mixins",
"mixins": [
],
"client": [
"client.MixinDebugScreenOverlay",
"client.MixinFogRenderer",
"client.MixinGameRenderer",
"client.MixinLightTexture"
],
"server": []
}
@@ -117,8 +117,11 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
// ClientChunkLoadEvent
ClientChunkEvents.CHUNK_LOAD.register((level, chunk) ->
{
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
if (MC.clientConnectedToDedicatedServer())
{
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
}
});
// (kinda) block break event
@@ -200,14 +203,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
});
// Client Chunk Save
ClientChunkEvents.CHUNK_UNLOAD.register((level, chunk) ->
{
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
SharedApi.INSTANCE.chunkUnloadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
});
//==============//
// render event //
@@ -227,14 +222,14 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
modelViewMatrix,
projectionMatrix,
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
renderContext.tickDelta()
#else
renderContext.tickCounter().getGameTimeDeltaTicks()
#endif
);
});
// Debug keyboard event
// FIXME: Use better hooks so it doesn't trigger key press events in text boxes
ClientTickEvents.END_CLIENT_TICK.register(client ->
@@ -1,4 +1,4 @@
package com.seibel.distanthorizons.common.mixins.client;
package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.client.gui.components.DebugScreenOverlay;
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.mixins.client;
package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -1,4 +1,4 @@
package com.seibel.distanthorizons.common.mixins.client;
package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
@@ -116,7 +116,7 @@ public class MixinLevelRenderer
ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level),
mcModelViewMatrix,
mcProjectionMatrix,
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
Minecraft.getInstance().getFrameTime()
#else
Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.mixins.client;
package com.seibel.distanthorizons.fabric.mixins.client;
import com.mojang.blaze3d.platform.NativeImage;
@@ -45,7 +45,7 @@ import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Shadow;
#endif
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
import net.minecraft.client.gui.screens.OptionsScreen;
#else
import net.minecraft.client.gui.screens.options.OptionsScreen;
@@ -64,7 +64,7 @@ public class MixinOptionsScreen extends Screen
/** Texture used for the config opening button */
@Unique
private static final ResourceLocation ICON_TEXTURE =
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
@@ -1,8 +1,6 @@
package com.seibel.distanthorizons.fabric.mixins.server;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
@@ -32,62 +30,6 @@ public class MixinChunkMap
// don't need the chunk(s) before MC has finished saving them
@Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
{
// true means a chunk was saved to disk
if (ci.getReturnValue())
{
// TODO is this validation necessary since we are checking above if
// the callback return value should state if the chunk was actually saved or not?
// Do we trust it to always be correct?
//=====================================//
// corrupt/incomplete chunk validation //
//=====================================//
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
// this logic should prevent that from happening
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
{
return;
}
#else
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
{
return;
}
#endif
//==================//
// biome validation //
//==================//
// some chunks may be missing their biomes, which cause issues when attempting to save them
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
if (chunk.getBiomes() == null)
{
return;
}
#else
try
{
// this will throw an exception if the biomes aren't set up
chunk.getNoiseBiome(0,0,0);
}
catch (Exception e)
{
return;
}
#endif
ServerApi.INSTANCE.serverChunkSaveEvent(
new ChunkWrapper(chunk, this.level, ServerLevelWrapper.getWrapper(this.level)),
ServerLevelWrapper.getWrapper(this.level)
);
}
}
{ MixinChunkMapCommon.onChunkSave(this.level, chunk, ci); }
}
@@ -1,16 +1,16 @@
package com.seibel.distanthorizons.fabric.testing;
import com.mojang.logging.LogUtils;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.fabric.FabricServerProxy;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.server.level.ServerLevel;
import org.apache.logging.log4j.Logger;
public class TestWorldGenBindingEvent extends DhApiLevelLoadEvent
{
private static final org.slf4j.Logger LOGGER = LogUtils.getLogger();
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
@Override
public void onLevelLoad(DhApiEventParam<DhApiLevelLoadEvent.EventParam> event)
@@ -9,18 +9,27 @@ import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.Abstrac
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.objects.data.DhApiChunk;
import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.config.Config;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator
{
private final ServerLevel level;
private final IDhApiLevelWrapper levelWrapper;
//=============//
// constructor //
//=============//
public TestWorldGenerator(ServerLevel level)
{
this.level = level;
@@ -28,13 +37,23 @@ public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator
}
//============//
// properties //
//============//
@Override
public EDhApiWorldGeneratorReturnType getReturnType() { return EDhApiWorldGeneratorReturnType.API_CHUNKS; }
@Override
public boolean isBusy() { return false; }
@Override
public boolean runApiChunkValidation() { return true; }
//==================//
// chunk generation //
//==================//
@Override
public Object[] generateChunk(int chunkX, int chunkZ, EDhApiDistantGeneratorMode eDhApiDistantGeneratorMode)
{
@@ -45,10 +64,14 @@ public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator
@Override
public DhApiChunk generateApiChunk(int chunkPosX, int chunkPosZ, EDhApiDistantGeneratorMode generatorMode)
{
// this test is only validated for 1.18.2 and up
// (and it is only needed when testing world gen overrides/API chunks, so it isn't normally needed)
#if MC_VER >= MC_1_18_2
ChunkAccess chunk = this.level.getChunk(chunkPosX, chunkPosZ);
int minBuildHeight = chunk.getMinBuildHeight();
int maxBuildHeight = chunk.getMaxBuildHeight();
int minBuildHeight = this.level.getMinBuildHeight();
int maxBuildHeight = this.level.getMaxBuildHeight();
DhApiChunk apiChunk = DhApiChunk.create(chunkPosX, chunkPosZ, minBuildHeight, maxBuildHeight);
for (int x = 0; x < 16; x++)
@@ -71,11 +94,20 @@ public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator
}
}
return apiChunk;
#else
return null;
#endif
}
@Override
public void preGeneratorTaskStart() { /* do nothing */ }
//=========//
// cleanup //
//=========//
@Override
public void close() { /* do nothing */ }
@@ -5,7 +5,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAcces
#elif MC_VER == MC_1_18_2
import ru.bclib.config.ClientConfig;
import ru.bclib.config.Configs;
#elif MC_VER < MC_1_21
#elif MC_VER < MC_1_21_1
import org.betterx.bclib.config.ClientConfig;
import org.betterx.bclib.config.Configs;
#endif
@@ -10,7 +10,11 @@
"client": [
"client.MixinClientLevel",
"client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay",
"client.MixinFogRenderer",
"client.MixinGameRenderer",
"client.MixinLevelRenderer",
"client.MixinLightTexture",
"client.MixinOptionsScreen",
"client.MixinMinecraft",
"client.MixinTextureUtil"
@@ -35,7 +35,6 @@
},
"mixins": [
"DistantHorizons.common.mixins.json",
"DistantHorizons.fabric.mixins.json"
],
-1
View File
@@ -28,7 +28,6 @@ loom {
extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
mixinConfigs = [
"DistantHorizons.common.mixins.json",
"DistantHorizons.forge.mixins.json"
]
}
@@ -176,53 +176,59 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
@SubscribeEvent
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
{
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
if (MC.clientConnectedToDedicatedServer())
{
return;
}
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
#if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
#endif
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
{
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
return;
}
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
#if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
#endif
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
}
}
}
@SubscribeEvent
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
{
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
if (MC.clientConnectedToDedicatedServer())
{
return;
}
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
#if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
#endif
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
{
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
return;
}
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
#if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
#endif
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
}
}
}
private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
@@ -230,21 +236,16 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
SharedApi.INSTANCE.chunkBlockChangedEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
}
@SubscribeEvent
public void clientChunkLoadEvent(ChunkEvent.Load event)
{
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
SharedApi.INSTANCE.chunkLoadEvent(chunk, wrappedLevel);
}
@SubscribeEvent
public void clientChunkUnloadEvent(ChunkEvent.Unload event)
{
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
SharedApi.INSTANCE.chunkUnloadEvent(chunk, wrappedLevel);
if (MC.clientConnectedToDedicatedServer())
{
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
SharedApi.INSTANCE.chunkLoadEvent(chunk, wrappedLevel);
}
}
@@ -22,6 +22,8 @@ package com.seibel.distanthorizons.forge;
import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.ModInfo;
@@ -104,6 +106,20 @@ public class ForgeMain extends AbstractModInitializer
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
() -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> GetConfigScreen.getScreen(parent)));
#endif
if (Config.Client.Advanced.Logging.showModCompatibilityWarningsOnStartup.get())
{
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
if (modChecker.isModLoaded("alexscaves"))
{
String message =
// orange text
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
"You may have to change Alex's config for DH to render. ";
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
}
}
@Override
@@ -137,14 +137,6 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
}
@SubscribeEvent
public void serverChunkSaveEvent(ChunkEvent.Unload event)
{
ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
this.serverApi.serverChunkSaveEvent(chunk, levelWrapper);
}
@@ -0,0 +1,23 @@
package com.seibel.distanthorizons.forge.mixins.client;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.client.gui.components.DebugScreenOverlay;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@Mixin(DebugScreenOverlay.class)
public class MixinDebugScreenOverlay
{
@Inject(method = "getSystemInformation", at = @At("RETURN"))
private void addCustomF3(CallbackInfoReturnable<List<String>> cir)
{
List<String> messages = cir.getReturnValue();
F3Screen.addStringToDisplay(messages);
}
}
@@ -0,0 +1,84 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.forge.mixins.client;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
#if MC_VER < MC_1_17_1
import net.minecraft.world.level.material.FluidState;
#else
import net.minecraft.world.level.material.FogType;
#endif
@Mixin(FogRenderer.class)
public class MixinFogRenderer
{
// Using this instead of Float.MAX_VALUE because Sodium don't like it.
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
@Inject(at = @At("RETURN"),
method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V",
remap = #if MC_VER == MC_1_17_1 || MC_VER == MC_1_18_2 false #else true #endif ) // Remap messiness due to this being weird in forge
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
{
#if MC_VER < MC_1_17_1
FluidState fluidState = camera.getFluidInCamera();
boolean cameraNotInFluid = fluidState.isEmpty();
#else
FogType fogTypes = camera.getFluidInCamera();
boolean cameraNotInFluid = fogTypes == FogType.NONE;
#endif
Entity entity = camera.getEntity();
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
if (!isSpecialFog && cameraNotInFluid && fogMode == FogMode.FOG_TERRAIN
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
&& Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get())
{
#if MC_VER < MC_1_17_1
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
RenderSystem.fogEnd(A_EVEN_LARGER_VALUE);
#else
RenderSystem.setShaderFogStart(A_REALLY_REALLY_BIG_VALUE);
RenderSystem.setShaderFogEnd(A_EVEN_LARGER_VALUE);
#endif
}
}
}
@@ -0,0 +1,58 @@
package com.seibel.distanthorizons.forge.mixins.client;
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.renderer.GameRenderer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
// TODO: Check if this port from fabric works
@Mixin(GameRenderer.class)
public class MixinGameRenderer
{
private static final Logger LOGGER = LogManager.getLogger(MixinGameRenderer.class.getSimpleName());
#if MC_VER >= MC_1_17_1
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci)
{
LOGGER.info("Starting up renderer (forge)");
if (!DependencySetupDoneCheck.isDone)
{
LOGGER.warn("Dependency setup is not done yet, skipping renderer this startup event!");
return;
}
ClientApi.INSTANCE.rendererStartupEvent();
}
@Inject(method = "shutdownShaders", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci)
{
LOGGER.info("Shutting down renderer (forge)");
if (!DependencySetupDoneCheck.isDone)
{
LOGGER.warn("Dependency setup is not done yet, skipping renderer this shutdown event!");
return;
}
ClientApi.INSTANCE.rendererShutdownEvent();
}
#else
@Inject(method = {"loadEffect"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci) {
ClientApi.INSTANCE.rendererStartupEvent();
}
@Inject(method = "shutdownEffect", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
ClientApi.INSTANCE.rendererShutdownEvent();
}
#endif
}
@@ -0,0 +1,59 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.forge.mixins.client;
import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.renderer.LightTexture;
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;
@Mixin(LightTexture.class)
public class MixinLightTexture
{
@Shadow //# if MC_VER >= MC_1_20_4 (remap = false) # endif
@Final
private NativeImage lightPixels;
@Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
public void updateLightTexture(float partialTicks, CallbackInfo ci)
{
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (mc == null || mc.getWrappedClientLevel() == null)
{
return;
}
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
}
}
@@ -0,0 +1,35 @@
package com.seibel.distanthorizons.forge.mixins.server;
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ChunkMap.class)
public class MixinChunkMap
{
@Unique
private static final String CHUNK_SERIALIZER_WRITE
= "Lnet/minecraft/world/level/chunk/storage/ChunkSerializer;write(" +
"Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;)" +
"Lnet/minecraft/nbt/CompoundTag;";
@Shadow
@Final
ServerLevel level;
// firing at INVOKE causes issues with C2ME and is probably unnecessary since we
// don't need the chunk(s) before MC has finished saving them
@Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
{ MixinChunkMapCommon.onChunkSave(this.level, chunk, ci); }
}
@@ -5,11 +5,16 @@
"mixins": [
"server.MixinUtilBackgroundThread",
"server.MixinChunkGenerator",
"server.MixinTFChunkGenerator"
"server.MixinTFChunkGenerator",
"server.MixinChunkMap"
],
"client": [
"client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay",
"client.MixinFogRenderer",
"client.MixinGameRenderer",
"client.MixinLevelRenderer",
"client.MixinLightTexture",
"client.MixinOptionsScreen",
"client.MixinTextureUtil"
],
+2 -2
View File
@@ -5,7 +5,7 @@ org.gradle.caching=true
# Mod Info
mod_name=DistantHorizons
mod_version=2.1.3-a-dev
mod_version=2.2.0-a
api_version=3.0.0
maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons
@@ -49,7 +49,7 @@ versionStr=
# This defines what MC version Intellij will use for the preprocessor
# and what version is used automatically by build and run commands
mcVer=1.21
mcVer=1.21.1
# Defines the maximum amount of memory Minecraft is allowed when run in a development environment
#minecraftMemoryJavaArg="-Xmx4G"
@@ -63,6 +63,8 @@ import org.lwjgl.opengl.GL32;
import net.neoforged.neoforge.event.TickEvent;
#else
import net.neoforged.neoforge.client.event.ClientTickEvent;
import java.util.concurrent.ThreadPoolExecutor;
#endif
@@ -164,49 +166,55 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
@SubscribeEvent
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
{
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
if (MC.clientConnectedToDedicatedServer())
{
return;
}
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
var executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
{
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
LevelAccessor level = event.getLevel();
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
return;
}
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
LevelAccessor level = event.getLevel();
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
}
}
}
@SubscribeEvent
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
{
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
if (MC.clientConnectedToDedicatedServer())
{
return;
}
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
var executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
{
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
LevelAccessor level = event.getLevel();
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
return;
}
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
LevelAccessor level = event.getLevel();
ChunkAccess chunk = level.getChunk(event.getPos());
this.onBlockChangeEvent(level, chunk);
});
}
}
}
private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
@@ -216,22 +224,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
}
@SubscribeEvent
public void clientChunkLoadEvent(ChunkEvent.Load event)
{
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
SharedApi.INSTANCE.chunkLoadEvent(chunk, wrappedLevel);
}
@SubscribeEvent
public void clientChunkUnloadEvent(ChunkEvent.Unload event)
{
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
SharedApi.INSTANCE.chunkUnloadEvent(chunk, wrappedLevel);
}
//==============//
// key bindings //
@@ -22,6 +22,8 @@ package com.seibel.distanthorizons.neoforge;
import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
@@ -83,6 +85,20 @@ public class NeoforgeMain extends AbstractModInitializer
// TODO fix potential null pointer
() -> (client, parent) -> GetConfigScreen.getScreen(parent));
#endif
if (Config.Client.Advanced.Logging.showModCompatibilityWarningsOnStartup.get())
{
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
if (modChecker.isModLoaded("alexscaves"))
{
String message =
// orange text
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
"You may have to change Alex's config for DH to render. ";
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
}
}
@Override
@@ -122,14 +122,6 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
}
@SubscribeEvent
public void serverChunkSaveEvent(ChunkEvent.Unload event)
{
ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
this.serverApi.serverChunkSaveEvent(chunk, levelWrapper);
}
@@ -0,0 +1,23 @@
package com.seibel.distanthorizons.neoforge.mixins.client;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.client.gui.components.DebugScreenOverlay;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@Mixin(DebugScreenOverlay.class)
public class MixinDebugScreenOverlay
{
@Inject(method = "getSystemInformation", at = @At("RETURN"))
private void addCustomF3(CallbackInfoReturnable<List<String>> cir)
{
List<String> messages = cir.getReturnValue();
F3Screen.addStringToDisplay(messages);
}
}
@@ -0,0 +1,84 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.neoforge.mixins.client;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
#if MC_VER < MC_1_17_1
import net.minecraft.world.level.material.FluidState;
#else
import net.minecraft.world.level.material.FogType;
#endif
@Mixin(FogRenderer.class)
public class MixinFogRenderer
{
// Using this instead of Float.MAX_VALUE because Sodium don't like it.
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
@Inject(at = @At("RETURN"),
method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V",
remap = #if MC_VER == MC_1_17_1 || MC_VER == MC_1_18_2 false #else true #endif ) // Remap messiness due to this being weird in forge
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
{
#if MC_VER < MC_1_17_1
FluidState fluidState = camera.getFluidInCamera();
boolean cameraNotInFluid = fluidState.isEmpty();
#else
FogType fogTypes = camera.getFluidInCamera();
boolean cameraNotInFluid = fogTypes == FogType.NONE;
#endif
Entity entity = camera.getEntity();
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
if (!isSpecialFog && cameraNotInFluid && fogMode == FogMode.FOG_TERRAIN
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
&& Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get())
{
#if MC_VER < MC_1_17_1
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
RenderSystem.fogEnd(A_EVEN_LARGER_VALUE);
#else
RenderSystem.setShaderFogStart(A_REALLY_REALLY_BIG_VALUE);
RenderSystem.setShaderFogEnd(A_EVEN_LARGER_VALUE);
#endif
}
}
}
@@ -0,0 +1,58 @@
package com.seibel.distanthorizons.neoforge.mixins.client;
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.renderer.GameRenderer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
// TODO: Check if this port from fabric works
@Mixin(GameRenderer.class)
public class MixinGameRenderer
{
private static final Logger LOGGER = LogManager.getLogger(MixinGameRenderer.class.getSimpleName());
#if MC_VER >= MC_1_17_1
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci)
{
LOGGER.info("Starting up renderer (forge)");
if (!DependencySetupDoneCheck.isDone)
{
LOGGER.warn("Dependency setup is not done yet, skipping renderer this startup event!");
return;
}
ClientApi.INSTANCE.rendererStartupEvent();
}
@Inject(method = "shutdownShaders", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci)
{
LOGGER.info("Shutting down renderer (forge)");
if (!DependencySetupDoneCheck.isDone)
{
LOGGER.warn("Dependency setup is not done yet, skipping renderer this shutdown event!");
return;
}
ClientApi.INSTANCE.rendererShutdownEvent();
}
#else
@Inject(method = {"loadEffect"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci) {
ClientApi.INSTANCE.rendererStartupEvent();
}
@Inject(method = "shutdownEffect", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
ClientApi.INSTANCE.rendererShutdownEvent();
}
#endif
}
@@ -120,7 +120,7 @@ public class MixinLevelRenderer
float frameTime;
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
frameTime = Minecraft.getInstance().getFrameTime();
#else
frameTime = Minecraft.getInstance().getTimer().getRealtimeDeltaTicks();
@@ -0,0 +1,59 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.neoforge.mixins.client;
import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.renderer.LightTexture;
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;
@Mixin(LightTexture.class)
public class MixinLightTexture
{
@Shadow
@Final
private NativeImage lightPixels;
@Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
public void updateLightTexture(float partialTicks, CallbackInfo ci)
{
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (mc == null || mc.getWrappedClientLevel() == null)
{
return;
}
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
}
}
@@ -45,7 +45,7 @@ import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Shadow;
#endif
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
import net.minecraft.client.gui.screens.OptionsScreen;
#else
import net.minecraft.client.gui.screens.options.OptionsScreen;
@@ -64,7 +64,7 @@ public class MixinOptionsScreen extends Screen
/** Texture used for the config opening button */
@Unique
private static final ResourceLocation ICON_TEXTURE =
#if MC_VER < MC_1_21
#if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
@@ -0,0 +1,35 @@
package com.seibel.distanthorizons.neoforge.mixins.server;
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ChunkMap.class)
public class MixinChunkMap
{
@Unique
private static final String CHUNK_SERIALIZER_WRITE
= "Lnet/minecraft/world/level/chunk/storage/ChunkSerializer;write(" +
"Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;)" +
"Lnet/minecraft/nbt/CompoundTag;";
@Shadow
@Final
ServerLevel level;
// firing at INVOKE causes issues with C2ME and is probably unnecessary since we
// don't need the chunk(s) before MC has finished saving them
@Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
{ MixinChunkMapCommon.onChunkSave(this.level, chunk, ci); }
}
@@ -5,11 +5,16 @@
"mixins": [
"server.MixinUtilBackgroundThread",
"server.MixinChunkGenerator",
"server.MixinTFChunkGenerator"
"server.MixinTFChunkGenerator",
"server.MixinChunkMap"
],
"client": [
"client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay",
"client.MixinFogRenderer",
"client.MixinGameRenderer",
"client.MixinLevelRenderer",
"client.MixinLightTexture",
"client.MixinOptionsScreen",
"client.MixinTextureUtil"
],
@@ -24,8 +24,6 @@ issueTrackerURL = "${issues}"
acceptableRemoteVersions = "*"
# We may need this to make forge (lexforge) & neoforge work together
[[mixins]]
config = "DistantHorizons.common.mixins.json"
[[mixins]]
config = "DistantHorizons.neoforge.mixins.json"
@@ -1,8 +1,8 @@
# 1.21 version
# 1.21.1 version
java_version=21
minecraft_version=1.21
minecraft_version=1.21.1
parchment_version=1.20.6:2024.05.01
compatible_minecraft_versions=["1.21.0"]
compatible_minecraft_versions=["1.21", "1.21.1"]
accessWidenerVersion=1_20_6
builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues
@@ -38,8 +38,8 @@ fabric_api_version=0.100.1+1.21
enable_canvas=0
# (Neo)Forge loader
forge_version=50.0.19
neoforge_version=21.0.4-beta
forge_version=
neoforge_version=21.1.6
# (Neo)Forge mod versions
starlight_version_forge=
terraforged_version=