diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a03cd339a..f8864693a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,17 +42,20 @@ build: name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}" paths: - Merged/*.jar + - quilt/build/libs/*.jar - fabric/build/libs/*.jar - forge/build/libs/*.jar - - quilt/build/libs/*.jar + - neoforged/build/libs/*.jar exclude: # TODO: There is a lot of duplicate stuff here, try to maybe make it smaller - fabric/build/libs/*-all.jar - fabric/build/libs/*-sources.jar - - forge/build/libs/*-all.jar - - forge/build/libs/*-sources.jar - quilt/build/libs/*-all.jar - quilt/build/libs/*-sources.jar + - forge/build/libs/*-all.jar + - forge/build/libs/*-sources.jar + - neoforged/build/libs/*-all.jar + - neoforged/build/libs/*-sources.jar expire_in: 14 days when: always extends: .build_java diff --git a/build.gradle b/build.gradle index ef06dab95..cb022673b 100644 --- a/build.gradle +++ b/build.gradle @@ -75,6 +75,12 @@ forgix { forge { jarLocation = "build/libs/DistantHorizons-forge-${rootProject.versionStr}.jar" } + + if (findProject(":neoforged")) + custom { + projectName = "neoforged" + jarLocation = "build/libs/DistantHorizons-neoforged-${rootProject.versionStr}.jar" + } if (findProject(":fabric")) fabric { @@ -105,7 +111,10 @@ subprojects { p -> // apply plugin: "org.spongepowered.gradle.vanilla" // Provides minecraft libraries // Apply forge's loom - if (findProject(":forge") && p == project(":forge")) + if ( + (findProject(":forge") && p == project(":forge")) || + (findProject(":neoforged") && p == project(":neoforged")) + ) apply plugin: "dev.architectury.loom" @@ -318,7 +327,7 @@ subprojects { p -> def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder // Fix forge version numbering system as it is weird - // For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"] which make more sense + // For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"] def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)") // println compatible_forgemc_versions @@ -400,7 +409,7 @@ subprojects { p -> //// include "${accessWidenerVersion}.distanthorizons.accesswidener" // Jank solution to remove all unused accesswideners - // The line above would work..., except forge requires the original accesswidener file, meaning we require this jank solution to keep it + // The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it exclude { file -> if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") { return true @@ -446,7 +455,7 @@ subprojects { p -> } allprojects { p -> - // Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge")" + // Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")" // Useful later on so we dont have duplicated code def isMinecraftSubProject = p != project(":core") && p != project(":api") @@ -461,8 +470,21 @@ allprojects { p -> // this is the text that appears at the top of the overview (home) page // and is used when bookmarking a page javadoc.title = rootProject.mod_name + "-" + project.name - - + + // Some annotations arent "technically" part of the official java standard, + // so we define it ourself here + javadoc { + configure( options ) { + tags( + 'todo:X"', + 'apiNote:a:API Note:', + 'implSpec:a:Implementation Requirements:', + 'implNote:a:Implementation Note:' + ) + } + } + + repositories { // The central repo mavenCentral() @@ -527,6 +549,7 @@ allprojects { p -> includeGroup "forge-mod" } } + // TODO: If neoforged is ever needed, should we use that, or call it a forge mod? } // Adds some dependencies that are in vanilla but not in core diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java index 4b3d5b7ec..202120b35 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java @@ -39,7 +39,9 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper; import net.minecraft.client.multiplayer.ClientLevel; +#if MC_VER > MC_1_17_1 import net.minecraft.core.Holder; +#endif import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; @@ -288,11 +290,13 @@ public class WrapperFactory implements IWrapperFactory { String[] expectedClassNames; - #if MC_VER <= MC_1_20_4 + #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 + expectedClassNames = new String[] { Biome.class.getName() }; + #elif MC_VER <= MC_1_20_4 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! + // See preprocessor comment in createChunkWrapper() for full documentation + not implemented for this version of Minecraft! #endif return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray); diff --git a/coreSubProjects b/coreSubProjects index da60ca756..5c644fbf5 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit da60ca756055cc15ef57e94f81ac29d702b67b4d +Subproject commit 5c644fbf5b4293d5418d91dac59a6d234ec40dcb diff --git a/forge/build.gradle b/forge/build.gradle index 0e34fa028..9c159a519 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -28,7 +28,7 @@ loom { extraAccessWideners.add loom.accessWidenerPath.get().asFile.name mixinConfigs = [ - "DistantHorizons.mixins.json" + "DistantHorizons.forge.mixins.json" ] } diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java index 78f4fd7e5..9d2d7aa3c 100644 --- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java @@ -1,5 +1,6 @@ package com.seibel.distanthorizons.forge.mixins; +import net.minecraft.client.ClientBrandRetriever; import net.minecraftforge.fml.ModList; import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; @@ -18,6 +19,9 @@ public class ForgeMixinPlugin implements IMixinConfigPlugin @Override public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + if (!ClientBrandRetriever.getClientModName().equals("forge")) + return false; + if (mixinClassName.contains(".mods.")) { // If the mixin wants to go into a mod then we check if that mod is loaded or not return ModList.get().isLoaded( diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinDynamicTexture.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinDynamicTexture.java index 3f02eb37d..7117e7063 100644 --- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinDynamicTexture.java +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinDynamicTexture.java @@ -38,8 +38,10 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import javax.annotation.Nullable; + @Mixin(DynamicTexture.class) -public class MixinDynamicTexture implements ILightTextureMarker +public abstract class MixinDynamicTexture implements ILightTextureMarker { /** Used to prevent accidentally using other dynamic textures as a lightmap */ @Unique diff --git a/forge/src/main/resources/DistantHorizons.mixins.json b/forge/src/main/resources/DistantHorizons.forge.mixins.json similarity index 100% rename from forge/src/main/resources/DistantHorizons.mixins.json rename to forge/src/main/resources/DistantHorizons.forge.mixins.json diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index 43a8eb78d..2a984312e 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -26,7 +26,8 @@ issueTrackerURL = "${issues}" [[dependencies.distanthorizons]] modId = "minecraft" - mandatory = true + mandatory = true # Forge syntax + type = "required" # Neoforged syntax versionRange = "${compatible_forgemc_versions}" # Where we set what version of mc it is avalible for ordering = "NONE" side = "BOTH" \ No newline at end of file diff --git a/neoforged/build.gradle b/neoforged/build.gradle new file mode 100644 index 000000000..eb49e83bb --- /dev/null +++ b/neoforged/build.gradle @@ -0,0 +1,149 @@ +plugins { + // Note: This is only needed for multi-loader projects + // The main architectury loom version is set at the start of the root build.gradle + id "architectury-plugin" version "3.4-SNAPSHOT" +} + +sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17 + +architectury { + platformSetupLoomIde() + forge() +} + +repositories { + maven { + name "Neoforged" + url "https://maven.neoforged.net/releases/" + } +} + +//loom { +// forge { +// convertAccessWideners.set(true) +// extraAccessWideners.add("lod.accesswidener") +// mixinConfigs("DistantHorizons.mixins.json") +// } +//} + +loom { + silentMojangMappingsLicense() // Shut the licencing warning + accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener") + + neoForge { + // Access wideners are now defined in the `remapJar.atAccessWideners` +// convertAccessWideners = true +// extraAccessWideners.add loom.accessWidenerPath.get().asFile.name + + // Mixins are now defined in the `mods.toml` +// mixinConfigs = [ +// "DistantHorizons.mixins.json" +// ] + } + mixin { + useLegacyMixinAp = true + + // Mixins are now defined in the `mods.toml` +// mixinConfigs = [ +// "DistantHorizons.mixins.json" +// ] + } + + // "runs" isn't required, but when we do need it then it can be useful + runs { + client { + client() + setConfigName("Neoforged Client") + ideConfigGenerated(true) + runDir("../run") +// vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg) + } + server { + server() + setConfigName("Neoforged Server") + ideConfigGenerated(true) + runDir("../run") + } + } +} + +remapJar { + inputFile = shadowJar.archiveFile + dependsOn shadowJar +// classifier null + + atAccessWideners.add("distanthorizons.accesswidener") +} + + +def addMod(path, enabled) { + if (enabled == "2") + dependencies { implementation(path) } + else if (enabled == "1") + dependencies { modCompileOnly(path) } +} +dependencies { + minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" + mappings loom.layered() { + // Mojmap mappings + officialMojangMappings() + // Parchment mappings (it adds parameter mappings & javadoc) + parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip") + + // Architectury hackishness +// it.mappings "dev.architectury:yarn-mappings-patch-forge:${rootProject.mappings_patch}" + } + + // Neoforged + neoForge "net.neoforged:neoforge:${rootProject.neoforged_version}" + + // Architectury API +// if (minecraft_version == "1.16.5") { +// implementation("me.shedaniel:architectury-forge:${rootProject.architectury_version}") +// } else { +// implementation("dev.architectury:architectury-forge:${rootProject.architectury_version}") +// } + + // Starlight + addMod("curse.maven:starlight-forge-526854:${rootProject.starlight_version_forge}", rootProject.enable_starlight_forge) +// annotationProcessor "org.spongepowered:mixin:0.8.4:processor" + + addMod("curse.maven:TerraForged-363820:${rootProject.terraforged_version}", rootProject.enable_terraforged) + + addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft) + +// if (System.getProperty("idea.sync.active") != "true") { +// annotationProcessor "org.spongepowered:mixin:0.8.4:processor" +// } +} + +task deleteResources(type: Delete) { + delete file("build/resources/main") +} + +tasks.register('copyAllResources') { + dependsOn(copyCoreResources) + dependsOn(copyCommonLoaderResources) +} + +processResources { + dependsOn(tasks.named('copyAllResources')) +} + +tasks.named('runClient') { + dependsOn(tasks.named('copyAllResources')) + finalizedBy(deleteResources) +} + + +sourcesJar { + def commonSources = project(":common").sourcesJar + dependsOn commonSources + from commonSources.archiveFile.map { zipTree(it) } +} + +//components.java { +// withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { +// skip() +// } +//} \ No newline at end of file diff --git a/neoforged/gradle.properties b/neoforged/gradle.properties new file mode 100644 index 000000000..85e1db4b7 --- /dev/null +++ b/neoforged/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoForge \ No newline at end of file diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeClientProxy.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeClientProxy.java new file mode 100644 index 000000000..449714877 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeClientProxy.java @@ -0,0 +1,285 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged; + +import com.seibel.distanthorizons.common.util.ProxyUtil; +import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.core.api.internal.ClientApi; +import com.seibel.distanthorizons.core.api.internal.SharedApi; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; + +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import com.seibel.distanthorizons.coreapi.ModInfo; +//import io.netty.buffer.ByteBuf; +import net.minecraft.world.level.LevelAccessor; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.neoforged.neoforge.client.event.RenderLevelStageEvent; +import net.neoforged.neoforge.event.level.ChunkEvent; +import net.neoforged.neoforge.event.level.LevelEvent; + +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; +import net.minecraft.world.level.chunk.ChunkAccess; + +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +//import net.neoforged.network.NetworkRegistry; +//import net.neoforged.network.simple.SimpleChannel; +import org.apache.logging.log4j.Logger; +import org.lwjgl.glfw.GLFW; + +import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; + +import net.minecraft.client.Minecraft; +import net.neoforged.neoforge.client.event.InputEvent; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.SubscribeEvent; +import org.lwjgl.opengl.GL32; + +/** + * This handles all events sent to the client, + * and is the starting point for most of the mod. + * + * @author James_Seibel + * @version 2023-7-27 + */ +public class ForgeClientProxy +{ + private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + +// private static SimpleChannel multiversePluginChannel; + + + private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); } + + + + //=============// + // tick events // + //=============// + + @SubscribeEvent + public void clientTickEvent(TickEvent.ClientTickEvent event) + { + if (event.phase == TickEvent.Phase.START) + { + ClientApi.INSTANCE.clientTickEvent(); + } + } + + + + //==============// + // world events // + //==============// + + @SubscribeEvent + public void clientLevelLoadEvent(LevelEvent.Load event) + { + LOGGER.info("level load"); + + LevelAccessor level = event.getLevel(); + if (!(level instanceof ClientLevel)) + { + return; + } + + ClientLevel clientLevel = (ClientLevel) level; + IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel); + // TODO this causes a crash due to level being set to null somewhere + ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper); + } + @SubscribeEvent + public void clientLevelUnloadEvent(LevelEvent.Load event) + { + LOGGER.info("level unload"); + + LevelAccessor level = event.getLevel(); + if (!(level instanceof ClientLevel)) + { + return; + } + + ClientLevel clientLevel = (ClientLevel) level; + IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel); + ClientApi.INSTANCE.clientLevelUnloadEvent(clientLevelWrapper); + } + + + + //==============// + // chunk events // + //==============// + + @SubscribeEvent + public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event) + { + 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) + { + 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) + { + 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); + } + + + + //==============// + // key bindings // + //==============// + + @SubscribeEvent + public void registerKeyBindings(InputEvent.Key event) + { + if (Minecraft.getInstance().player == null) + { + return; + } + if (event.getAction() != GLFW.GLFW_PRESS) + { + return; + } + + ClientApi.INSTANCE.keyPressedEvent(event.getKey()); + } + + + + //============// + // networking // + //============// + + /** @param event this is just to ensure the event is called at the right time, if it is called outside the {@link FMLClientSetupEvent} event, the binding may fail */ + public static void setupNetworkingListeners(FMLClientSetupEvent event) + { +// multiversePluginChannel = NetworkRegistry.newSimpleChannel( +// new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE), +// // network protocol version +// () -> ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION +"", +// // client accepted versions +// ForgeClientProxy::isReceivedProtocolVersionAcceptable, +// // server accepted versions +// ForgeClientProxy::isReceivedProtocolVersionAcceptable +// ); +// +// multiversePluginChannel.registerMessage(0/*should be incremented for each simple channel we listen to*/, ByteBuf.class, +// // encoder +// (pack, friendlyByteBuf) -> { }, +// // decoder +// (friendlyByteBuf) -> friendlyByteBuf.asByteBuf(), +// // message consumer +// (nettyByteBuf, contextRef) -> +// { +// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf); +// contextRef.get().setPacketHandled(true); +// } +// ); + } + + public static boolean isReceivedProtocolVersionAcceptable(String versionString) + { + if (versionString.toLowerCase().contains("allowvanilla")) + { + // allow using networking on vanilla servers + return true; + } + else if (versionString.toLowerCase().contains("absent")) + { + // allow using networking even if DH isn't installed on the server + return true; + } + else + { + // DH is installed on the server, check if the version is valid to use + try + { + int version = Integer.parseInt(versionString); + return ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION == version; + } + catch (NumberFormatException ignored) + { + return false; + } + } + } + + + + //===========// + // rendering // + //===========// + + @SubscribeEvent + public void afterLevelRenderEvent(RenderLevelStageEvent event) + { + if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_LEVEL) + { + try + { + // should generally only need to be set once per game session + // allows DH to render directly to Optifine's level frame buffer, + // allowing better shader support + MinecraftRenderWrapper.INSTANCE.finalLevelFrameBufferId = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING); + } + catch (Exception | Error e) + { + LOGGER.error("Unexpected error in afterLevelRenderEvent: "+e.getMessage(), e); + } + } + } + + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeMain.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeMain.java new file mode 100644 index 000000000..c60f364e8 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeMain.java @@ -0,0 +1,161 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged; + +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent; +import com.seibel.distanthorizons.common.LodCommonMain; +import com.seibel.distanthorizons.common.forge.LodForgeMethodCaller; +import com.seibel.distanthorizons.common.wrappers.DependencySetup; +import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen; +import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper; +import com.seibel.distanthorizons.core.jar.ModJarInfo; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor; +import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; +import com.seibel.distanthorizons.coreapi.ModInfo; +import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; +import com.seibel.distanthorizons.neoforged.wrappers.ForgeDependencySetup; + +import com.seibel.distanthorizons.neoforged.wrappers.modAccessor.OptifineAccessor; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ColorResolver; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.*; +import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.neoforge.client.ConfigScreenHandler; + +import net.neoforged.neoforge.common.NeoForge; +import org.apache.logging.log4j.Logger; + +import net.minecraft.client.renderer.RenderType; +import net.neoforged.neoforge.client.model.data.ModelData; + +import java.lang.invoke.MethodHandles; +import java.util.List; + +/** + * Initialize and setup the Mod.
+ * If you are looking for the real start of the mod + * check out the ClientProxy. + * + * @author coolGi + * @author Ran + * @author James Seibel + * @version 8-15-2022 + */ +@Mod(ModInfo.ID) +public class ForgeMain implements LodForgeMethodCaller +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); + public static ForgeClientProxy client_proxy = null; + public static ForgeServerProxy server_proxy = null; + + public ForgeMain() + { + DependencySetup.createClientBindings(); + +// initDedicated(null); +// initDedicated(null); + // Register the mod initializer (Actual event registration is done in the different proxies) + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::initClient); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::initDedicated); + } + + private void initClient(final FMLClientSetupEvent event) + { + ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null); + + LOGGER.info("Initializing Mod"); + LodCommonMain.startup(this); + ForgeDependencySetup.createInitialBindings(); + LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION); + + // Print git info (Useful for dev builds) + LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch); + LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit); + LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source); + + client_proxy = new ForgeClientProxy(); + NeoForge.EVENT_BUS.register(client_proxy); + server_proxy = new ForgeServerProxy(false); + NeoForge.EVENT_BUS.register(server_proxy); + + if (AbstractOptifineAccessor.optifinePresent()) + { + ModAccessorInjector.INSTANCE.bind(IOptifineAccessor.class, new OptifineAccessor()); + } + + ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, + () -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> GetConfigScreen.getScreen(parent))); + + ForgeClientProxy.setupNetworkingListeners(event); + + LOGGER.info(ModInfo.READABLE_NAME + " Initialized"); + + ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null); + + // Init config + // The reason im initialising in this rather than the post init process is cus im using this for the auto updater + LodCommonMain.initConfig(); + } + + private void initDedicated(final FMLDedicatedServerSetupEvent event) + { +// DependencySetup.createServerBindings(); +// initCommon(); + +// server_proxy = new ForgeServerProxy(true); +// MinecraftForge.EVENT_BUS.register(server_proxy); +// + postInitCommon(); + } + + private void postInitCommon() + { + LOGGER.info("Post-Initializing Mod"); + ForgeDependencySetup.runDelayedSetup(); + + LOGGER.info("Mod Post-Initialized"); + } + + private final ModelData modelData = ModelData.EMPTY; + + @Override + public List getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, RandomSource random) + { + return mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, modelData, RenderType.solid() ); + } + + @Override //TODO: Check this if its still needed + public int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z) + { + return resolver.getColor(biome, x, z); + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeServerProxy.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeServerProxy.java new file mode 100644 index 000000000..83f6d644e --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/ForgeServerProxy.java @@ -0,0 +1,125 @@ +package com.seibel.distanthorizons.neoforged; + +import com.seibel.distanthorizons.common.util.ProxyUtil; +import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; +import com.seibel.distanthorizons.core.api.internal.ServerApi; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.neoforge.event.level.ChunkEvent; +import net.neoforged.neoforge.event.level.LevelEvent; +import net.neoforged.bus.api.SubscribeEvent; + +import net.neoforged.neoforge.event.server.ServerAboutToStartEvent; +import net.neoforged.neoforge.event.server.ServerStoppingEvent; + + +import org.apache.logging.log4j.Logger; + +import java.util.function.Supplier; + +public class ForgeServerProxy +{ + private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); } + + private final ServerApi serverApi = ServerApi.INSTANCE; + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + private final boolean isDedicated; + public static Supplier isGenerationThreadChecker = null; + + + //=============// + // constructor // + //=============// + + public ForgeServerProxy(boolean isDedicated) + { + this.isDedicated = isDedicated; + isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; + } + + + + //========// + // events // + //========// + + // ServerTickEvent (at end) + @SubscribeEvent + public void serverTickEvent(TickEvent.ServerTickEvent event) + { + if (event.phase == TickEvent.Phase.END) + { + this.serverApi.serverTickEvent(); + } + } + + // ServerWorldLoadEvent + @SubscribeEvent + public void dedicatedWorldLoadEvent(ServerAboutToStartEvent event) + { + this.serverApi.serverLoadEvent(this.isDedicated); + } + + // ServerWorldUnloadEvent + @SubscribeEvent + public void serverWorldUnloadEvent(ServerStoppingEvent event) + { + this.serverApi.serverUnloadEvent(); + } + + // ServerLevelLoadEvent + @SubscribeEvent + public void serverLevelLoadEvent(LevelEvent.Load event) + { + if (GetEventLevel(event) instanceof ServerLevel) + { + this.serverApi.serverLevelLoadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event))); + } + } + + // ServerLevelUnloadEvent + @SubscribeEvent + public void serverLevelUnloadEvent(LevelEvent.Unload event) + { + if (GetEventLevel(event) instanceof ServerLevel) + { + this.serverApi.serverLevelUnloadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event))); + } + } + + @SubscribeEvent + public void serverChunkLoadEvent(ChunkEvent.Load event) + { + ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event)); + + 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); + } + + + + //================// + // helper methods // + //================// + + private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); } + + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/NeoforgedMixinPlugin.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/NeoforgedMixinPlugin.java new file mode 100644 index 000000000..68566e4f3 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/NeoforgedMixinPlugin.java @@ -0,0 +1,75 @@ +package com.seibel.distanthorizons.neoforged.mixins; + +import net.minecraft.client.ClientBrandRetriever; +import net.neoforged.fml.ModList; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +/** + * @author coolGi + * @author cortex + */ +public class NeoforgedMixinPlugin implements IMixinConfigPlugin +{ + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) + { + if (!ClientBrandRetriever.getClientModName().equals("neoforge")) + return false; + + if (mixinClassName.contains(".mods.")) + { // If the mixin wants to go into a mod then we check if that mod is loaded or not + return ModList.get().isLoaded( + mixinClassName + // What these 2 regex's do is get the mod name that we are checking out of the mixinClassName + // Eg. "com.seibel.distanthorizons.mixins.mods.sodium.MixinSodiumChunkRenderer" turns into "sodium" + .replaceAll("^.*mods.", "") // Replaces everything before the mods + .replaceAll("\\..*$", "") // Replaces everything after the mod name + ); + } + return true; + } + + + @Override + public void onLoad(String mixinPackage) + { + + } + + @Override + public String getRefMapperConfig() + { + return null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) + { + + } + + @Override + public List getMixins() + { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) + { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) + { + + } + +} \ No newline at end of file diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinClientPacketListener.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinClientPacketListener.java new file mode 100644 index 000000000..07f7b65d1 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinClientPacketListener.java @@ -0,0 +1,29 @@ +package com.seibel.distanthorizons.neoforged.mixins.client; + +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.core.api.internal.ClientApi; +import net.minecraft.client.multiplayer.ClientPacketListener; +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; + +@Mixin(ClientPacketListener.class) +public class MixinClientPacketListener +{ + // TODO update fabric version as well + + @Inject(method = "handleLogin", at = @At("RETURN")) + void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); } + + #if MC_VER < MC_1_19_4 + @Inject(method = "cleanup", at = @At("HEAD")) + #else + @Inject(method = "close", at = @At("HEAD")) + #endif + void onCleanupStart(CallbackInfo ci) + { + ClientApi.INSTANCE.onClientOnlyDisconnected(); + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinDebugScreenOverlay.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinDebugScreenOverlay.java new file mode 100644 index 000000000..b9f0d1ce6 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinDebugScreenOverlay.java @@ -0,0 +1,23 @@ +package com.seibel.distanthorizons.neoforged.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> cir) + { + List messages = cir.getReturnValue(); + F3Screen.addStringToDisplay(messages); + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinDynamicTexture.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinDynamicTexture.java new file mode 100644 index 000000000..f58783e6b --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinDynamicTexture.java @@ -0,0 +1,77 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.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 com.seibel.distanthorizons.common.util.ILightTextureMarker; + +import net.minecraft.client.renderer.texture.DynamicTexture; + +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.CallbackInfo; + +import javax.annotation.Nullable; + +@Mixin(DynamicTexture.class) +public abstract class MixinDynamicTexture implements ILightTextureMarker +{ + /** Used to prevent accidentally using other dynamic textures as a lightmap */ + @Unique + private boolean isLightTexture = false; + + @Shadow + #if MC_VER >= MC_1_20_4 + (remap = false) + #endif + @Final + private NativeImage pixels; + + @Inject(method = "upload()V", at = @At("HEAD")) + public void updateLightTexture(CallbackInfo ci) + { + // since the light map is always updated on the client render thread we should be able to access the client level at the same time + IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + if (!this.isLightTexture + || mc == null + || mc.getWrappedClientLevel() == null + ) + { + return; + } + + //ApiShared.LOGGER.info("Lightmap update"); + IClientLevelWrapper clientLevel = mc.getWrappedClientLevel(); + MinecraftRenderWrapper.INSTANCE.updateLightmap(this.pixels, clientLevel); + } + + public void markLightTexture() { this.isLightTexture = true; } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinFogRenderer.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinFogRenderer.java new file mode 100644 index 000000000..480fad3e8 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinFogRenderer.java @@ -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 . + */ + +package com.seibel.distanthorizons.neoforged.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 + } + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinGameRenderer.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinGameRenderer.java new file mode 100644 index 000000000..56b2e4698 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinGameRenderer.java @@ -0,0 +1,58 @@ +package com.seibel.distanthorizons.neoforged.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 + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinLevelRenderer.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinLevelRenderer.java new file mode 100644 index 000000000..0054ab483 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinLevelRenderer.java @@ -0,0 +1,185 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.mixins.client; + +import com.mojang.blaze3d.vertex.PoseStack; +#if MC_VER < MC_1_19_4 +import com.mojang.math.Matrix4f; +#else +import net.minecraft.client.Camera; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LightTexture; +import org.joml.Matrix4f; +#endif +import com.seibel.distanthorizons.common.rendering.SeamlessOverdraw; +import com.seibel.distanthorizons.common.wrappers.McObjectConverter; +import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.api.internal.ClientApi; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.level.lighting.LevelLightEngine; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.nio.FloatBuffer; + +#if MC_VER < MC_1_17_1 +import org.lwjgl.opengl.GL15; +#endif + + +/** + * This class is used to mix in my rendering code + * before Minecraft starts rendering blocks. + * If this wasn't done, and we used Forge's + * render last event, the LODs would render on top + * of the normal terrain.

+ * + * This is also the mixin for rendering the clouds + * + * @author coolGi + * @author James Seibel + * @version 12-31-2021 + */ +@Mixin(LevelRenderer.class) +public class MixinLevelRenderer +{ + @Shadow + #if MC_VER >= MC_1_20_4 + (remap = false) + #endif + private ClientLevel level; + @Unique + private static float previousPartialTicks = 0; + + // TODO: Is there any reason why this is here? Can it be deleted? + public MixinLevelRenderer() + { + throw new NullPointerException("Null cannot be cast to non-null type."); + } + + #if MC_VER < MC_1_17_1 + @Inject(at = @At("RETURN"), method = "renderSky(Lcom/mojang/blaze3d/vertex/PoseStack;F)V") + private void renderSky(PoseStack matrixStackIn, float partialTicks, CallbackInfo callback) + #else + @Inject(method = "renderClouds", at = @At("HEAD"), cancellable = true) + public void renderClouds(PoseStack poseStack, Matrix4f projectionMatrix, float partialTicks, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) + #endif + { + // get the partial ticks since renderBlockLayer doesn't + // have access to them + previousPartialTicks = partialTicks; + } + + + // TODO: Can we move this to forge's client proxy similarly to how fabric does it + #if MC_VER < MC_1_17_1 + @Inject(at = @At("HEAD"), + method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDD)V", + cancellable = true) + private void renderChunkLayer(RenderType renderType, PoseStack matrixStackIn, double xIn, double yIn, double zIn, CallbackInfo callback) + #elif MC_VER < MC_1_19_4 + @Inject(at = @At("HEAD"), + method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V", + cancellable = true) + private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback) + #elif MC_VER < MC_1_20_2 + @Inject(at = @At("HEAD"), + method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V", + cancellable = true) + private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback) + #else + @Inject(at = @At("HEAD"), + method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V", + cancellable = true) + private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback) + #endif + { + // get MC's model view and projection matrices + #if MC_VER == MC_1_16_5 + // get the matrices from the OpenGL fixed pipeline + float[] mcProjMatrixRaw = new float[16]; + GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw); + Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw); + mcProjectionMatrix.transpose(); + + Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose()); + + #else + // get the matrices directly from MC + Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose()); + Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix); + #endif + + + + // only render before solid blocks + if (renderType.equals(RenderType.solid())) + { + ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(level), mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks); + + // experimental proof-of-concept option + if (Config.Client.Advanced.Graphics.AdvancedGraphics.seamlessOverdraw.get()) + { + float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(mcProjectionMatrix, previousPartialTicks); + + #if MC_VER == MC_1_16_5 + SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray); + #elif MC_VER < MC_1_19_4 + projectionMatrix.load(FloatBuffer.wrap(matrixFloatArray)); + #else + projectionMatrix.set(matrixFloatArray); + #endif + } + } + + if (Config.Client.Advanced.Debugging.lodOnlyMode.get()) + { + callback.cancel(); + } + } + + #if MC_VER < MC_1_19_4 + @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel") + public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) + #elif MC_VER < MC_1_20_1 + @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel") + public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) + #else + @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel") + private void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) + #endif + { + ChunkWrapper.syncedUpdateClientLightStatus(); + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinLightTexture.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinLightTexture.java new file mode 100644 index 000000000..6cea85ebd --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinLightTexture.java @@ -0,0 +1,48 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.mixins.client; + + +import com.seibel.distanthorizons.common.util.ILightTextureMarker; + +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.texture.DynamicTexture; + +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 DynamicTexture lightTexture; + + @Inject(method = "", at = @At("RETURN")) + public void markLightTexture(CallbackInfo ci) { ((ILightTextureMarker) this.lightTexture).markLightTexture(); } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinMinecraft.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinMinecraft.java new file mode 100644 index 000000000..4b5b174c8 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinMinecraft.java @@ -0,0 +1,95 @@ +package com.seibel.distanthorizons.neoforged.mixins.client; + +import com.seibel.distanthorizons.api.enums.config.EUpdateBranch; +import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen; +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.jar.installer.GitlabGetter; +import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter; +import com.seibel.distanthorizons.core.jar.updater.SelfUpdater; +import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * At the moment this is only used for the auto updater + * + * @author coolGi + */ +@Mixin(Minecraft.class) +public class MixinMinecraft +{ + #if MC_VER < MC_1_20_2 + #if MC_VER == MC_1_20_1 + @Redirect( + method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V") + ) + public void onOpenScreen(Minecraft instance, Screen guiScreen) + { + #else + @Redirect( + method = "(Lnet/minecraft/client/main/GameConfig;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V") + ) + public void onOpenScreen(Minecraft instance, Screen guiScreen) + { + #endif + if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()) // Don't do anything if the user doesn't want it + { + instance.setScreen(guiScreen); // Sets the screen back to the vanilla screen as if nothing ever happened + return; + } + + if (SelfUpdater.onStart()) + { + instance.setScreen(new UpdateModScreen( + new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons + (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha")) + )); + } + else + { + instance.setScreen(guiScreen); // Sets the screen back to the vanilla screen as if nothing ever happened + } + } + #endif + + #if MC_VER >= MC_1_20_2 + @Redirect( + method = "Lnet/minecraft/client/Minecraft;onGameLoadFinished(Lnet/minecraft/client/Minecraft$GameLoadCookie;)V", + at = @At(value = "INVOKE", target = "Ljava/lang/Runnable;run()V") + ) + private void buildInitialScreens(Runnable runnable) + { + if ( + Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() // Don't do anything if the user doesn't want it + && SelfUpdater.onStart() + ) + { + runnable = () -> { + Minecraft.getInstance().setScreen(new UpdateModScreen( + // TODO: Change to runnable, instead of tittle screen + new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons + (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha")) + )); + }; + } + + runnable.run(); + } + #endif + + @Inject(at = @At("HEAD"), method = "close()V", remap = false) + public void close(CallbackInfo ci) + { + SelfUpdater.onClose(); + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinOptionsScreen.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinOptionsScreen.java new file mode 100644 index 000000000..1049d0559 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinOptionsScreen.java @@ -0,0 +1,81 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.mixins.client; + +import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen; +import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget; +import com.seibel.distanthorizons.coreapi.ModInfo; +import com.seibel.distanthorizons.core.config.Config; +import net.minecraft.client.gui.screens.OptionsScreen; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +#if MC_VER < MC_1_19_2 +import net.minecraft.network.chat.TranslatableComponent; +#endif +import net.minecraft.resources.ResourceLocation; +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 java.util.Objects; + +/** + * Adds a button to the menu to goto the config + * + * @author coolGi + * @version 12-02-2021 + */ +@Mixin(OptionsScreen.class) +public class MixinOptionsScreen extends Screen +{ + // Get the texture for the button + private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png"); + protected MixinOptionsScreen(Component title) + { + super(title); + } + + @Inject(at = @At("HEAD"), method = "init") + private void lodconfig$init(CallbackInfo ci) + { + if (Config.Client.optionsButton.get()) + this. #if MC_VER < MC_1_17_1 addButton #else addRenderableWidget #endif + (new TexturedButtonWidget( + // Where the button is on the screen + this.width / 2 - 180, this.height / 6 - 12, + // Width and height of the button + 20, 20, + // Offset + 0, 0, + // Some textuary stuff + 20, ICON_TEXTURE, 20, 40, + // Create the button and tell it where to go + // For now it goes to the client option by default + (buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)), + // Add a title to the button + #if MC_VER < MC_1_19_2 + new TranslatableComponent(ModInfo.ID + ".title"))); + #else + Component.translatable(ModInfo.ID + ".title"))); + #endif + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinTextureUtil.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinTextureUtil.java new file mode 100644 index 000000000..2502b116c --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinTextureUtil.java @@ -0,0 +1,31 @@ +package com.seibel.distanthorizons.neoforged.mixins.client; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.TextureUtil; +import com.seibel.distanthorizons.core.config.Config; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +/** + * Sets Minecraft's LOD Bias (looks similar to mipmaps) + * + * @author coolGi + */ +@Mixin(TextureUtil.class) +public class MixinTextureUtil +{ + @Redirect(method = "prepareImage(Lcom/mojang/blaze3d/platform/NativeImage$InternalGlFormat;IIII)V", + at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_texParameter(IIF)V"), remap = false) + private static void setLodBias(int target, int pname, float param) + { + float biasValue = Config.Client.Advanced.Graphics.AdvancedGraphics.lodBias.get().floatValue(); + if (biasValue != 0) + { + // The target is GL11.GL_TEXTURE_2D + // And the pname is GL14.GL_TEXTURE_LOD_BIAS + GlStateManager._texParameter(target, pname, biasValue); + } + } + +} \ No newline at end of file diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinWorldUpgrader.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinWorldUpgrader.java new file mode 100644 index 000000000..5b46ae32e --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/client/MixinWorldUpgrader.java @@ -0,0 +1,156 @@ +package com.seibel.distanthorizons.neoforged.mixins.client; + +import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; +import com.seibel.distanthorizons.api.interfaces.world.IDhApiDimensionTypeWrapper; +import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; +import com.seibel.distanthorizons.common.wrappers.world.DimensionTypeWrapper; +import com.seibel.distanthorizons.core.file.structure.LocalSaveStructure; +import com.seibel.distanthorizons.core.level.DhServerLevel; +import com.seibel.distanthorizons.core.pos.DhBlockPos; +import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.worldupdate.WorldUpgrader; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.storage.DimensionDataStorage; +import net.minecraft.world.level.storage.LevelStorageSource; +import org.jetbrains.annotations.Nullable; +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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.io.File; +import java.nio.file.Path; + +#if FALSE +@Mixin(WorldUpgrader.class) +public class MixinWorldUpgrader { + static class FakeLevelWrapper implements IServerLevelWrapper { + private Path saveFolder; + private LevelStem stem; + private DimensionType dimension; + private DimensionTypeWrapper dimensionTypeWrapper; + + public FakeLevelWrapper(LevelStorageSource.LevelStorageAccess storage, WorldGenSettings gen, ResourceKey dim) { + saveFolder = storage.getDimensionPath(dim); + stem = gen.dimensions().getOrThrow(WorldGenSettings.levelToLevelStem(dim)); + dimension = stem.typeHolder().value(); + dimensionTypeWrapper = DimensionTypeWrapper.getDimensionTypeWrapper(dimension); + } + + @Override + public EDhApiLevelType getLevelType() { + return EDhApiLevelType.SERVER_LEVEL; + } + + @Override + public IDhApiDimensionTypeWrapper getDimensionType() { + return dimensionTypeWrapper; + } + + @Override + public int getBlockLight(int x, int y, int z) { + return 0; + } + + @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public boolean hasCeiling() { + return dimension.hasCeiling(); + } + + @Override + public boolean hasSkyLight() { + return dimension.hasSkyLight(); + } + + @Override + public int getHeight() { + return dimension.height(); + } + + @Override + public int getMinHeight() { + return dimension.minY(); + } + + @Override + public boolean hasChunkLoaded(int chunkX, int chunkZ) { + return false; + } + + @Override + public IBlockStateWrapper getBlockState(DhBlockPos pos) { + return BlockStateWrapper.AIR; + } + + @Override + public IBiomeWrapper getBiome(DhBlockPos pos) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Override + public Object getWrappedMcObject() { + return null; + } + + @Nullable + @Override + public IClientLevelWrapper tryGetClientLevelWrapper() { + return null; + } + + @Override + public File getSaveFolder() { + return saveFolder.toFile(); + } + } + + @Unique + private DhServerLevel dhServerLevel; + @Unique + private FakeLevelWrapper fakeLevelWrapper; + @Unique + public LocalSaveStructure saveStructure; + + @Shadow @Final + private DimensionDataStorage overworldDataStorage; + @Shadow @Final + private LevelStorageSource.LevelStorageAccess levelStorage; + @Shadow @Final + private WorldGenSettings worldGenSettings; + + @Inject(method = "Lnet/minecraft/util/worldupdate/WorldUpgrader;work()V", + at = @At(value = "INVOKE") + ) + private void initWorldUpgrade() { + saveStructure = new LocalSaveStructure(); + } + + @Inject(method = "Lnet/minecraft/util/worldupdate/WorldUpgrader;work()V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/worldupdate/WorldUpgrader;getAllChunkPos(Lnet/minecraft/resources/ResourceKey;)Ljava/util/List;", shift = At.Shift.AFTER), + locals = LocalCapture.CAPTURE_FAILSOFT + ) + private void startWorldUpgrade(CallbackInfo info, ResourceKey resourceKey) { + ResourceKey key = resourceKey; + fakeLevelWrapper = new FakeLevelWrapper(levelStorage, worldGenSettings, key); + dhServerLevel = new DhServerLevel(saveStructure, fakeLevelWrapper); + } + + +} +#endif \ No newline at end of file diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinChunkGenerator.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinChunkGenerator.java new file mode 100644 index 000000000..1b492c5d3 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinChunkGenerator.java @@ -0,0 +1,62 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.mixins.server; + +import org.spongepowered.asm.mixin.Mixin; +import net.minecraft.world.level.chunk.ChunkGenerator; + +#if MC_VER < MC_1_18_2 +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.level.StructureFeatureManager; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.WorldgenRandom; + +@Mixin(ChunkGenerator.class) +public class MixinChunkGenerator +{ + @Redirect(method = "applyBiomeDecoration", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/biome/Biome;generate(Lnet/minecraft/world/level/StructureFeatureManager;" + + "Lnet/minecraft/world/level/chunk/ChunkGenerator;Lnet/minecraft/server/level/WorldGenRegion;J" + + "Lnet/minecraft/world/level/levelgen/WorldgenRandom;Lnet/minecraft/core/BlockPos;)V" + + )) + private void wrapBiomeGenerateCall( + Biome biome, StructureFeatureManager structFeatManager, ChunkGenerator generator, + WorldGenRegion genRegion, long l, WorldgenRandom random, BlockPos pos) + { + synchronized (ChunkGenerator.class) + { + //ApiShared.LOGGER.info("Generating Biome {} and acquired lock.", biome.getRegistryName()); + biome.generate(structFeatManager, (ChunkGenerator) (Object) this, genRegion, l, random, pos); + } + //ApiShared.LOGGER.info("Released lock. Biome {} generated.", biome.getRegistryName()); + } + +} + +#else +@Mixin(ChunkGenerator.class) +public class MixinChunkGenerator { } +#endif \ No newline at end of file diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinTFChunkGenerator.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinTFChunkGenerator.java new file mode 100644 index 000000000..d1cdc6a5d --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinTFChunkGenerator.java @@ -0,0 +1,61 @@ +package com.seibel.distanthorizons.neoforged.mixins.server; + +import net.minecraft.world.level.chunk.ChunkGenerator; +import org.spongepowered.asm.mixin.Mixin; + +#if MC_VER == MC_1_16_5 +@Mixin(ChunkGenerator.class) +class MixinTFChunkGenerator +{ + // not currently implemented, attempting to run with the mod enabled in the IDE causes the game to lock up +} +#elif MC_VER < MC_1_17_1 + +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import com.terraforged.mod.chunk.generator.FeatureGenerator; + +import java.util.Random; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; + +@Mixin(FeatureGenerator.class) +public class MixinTFChunkGenerator +{ + + @Redirect(method = "decorate(" + + "Lnet/minecraft/world/level/StructureFeatureManager;" + + "Lnet/minecraft/world/level/WorldGenLevel;" + + "Lnet/minecraft/world/level/chunk/ChunkAccess;" + + "Lnet/minecraft/world/level/biome/Biome;" + + "Lnet/minecraft/core/BlockPos;" + + "Lcom/terraforged/mod/profiler/watchdog/WatchdogContext;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/levelgen/feature/ConfiguredFeature;place(" + + "Lnet/minecraft/world/level/WorldGenLevel;" + + "Lnet/minecraft/world/level/chunk/ChunkGenerator;" + + "Ljava/util/Random;Lnet/minecraft/core/BlockPos;)Z" + )) + private boolean wrapDecorate$FeaturePlace(ConfiguredFeature feature, WorldGenLevel arg, + ChunkGenerator arg2, Random random, BlockPos arg3) { + synchronized(FeatureGenerator.class) { + //ClientApi.LOGGER.info("wrapDecorate FeaturePlace triggered"); + return feature.place(arg, arg2, random, arg3); + } + } + + //METHOD: com.terraforged.mod.chunk.generator.FeatureGenerator.decorate(StructureFeatureManager manager, + // WorldGenLevel region, ChunkAccess chunk, Biome biome, BlockPos pos, WatchdogContext context) + + //TARGET: boolean net.minecraft.world.level.levelgen.feature.ConfiguredFeature.place + // (WorldGenLevel arg, ChunkGenerator arg2, Random random, BlockPos arg3) +} + +#else +@Mixin(ChunkGenerator.class) +class MixinTFChunkGenerator { } +#endif \ No newline at end of file diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinUtilBackgroundThread.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinUtilBackgroundThread.java new file mode 100644 index 000000000..fdb9742d8 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/MixinUtilBackgroundThread.java @@ -0,0 +1,78 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.mixins.server; + +import java.util.concurrent.ExecutorService; +import java.util.function.Supplier; + +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 com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.core.util.objects.DummyRunExecutorService; + +import net.minecraft.Util; + +@Mixin(Util.class) +public class MixinUtilBackgroundThread +{ + private static boolean shouldApplyOverride() + { + return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); + } + + @Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true) + private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable ci) + { + if (shouldApplyOverride()) + { + //ApiShared.LOGGER.info("util backgroundExecutor triggered"); + ci.setReturnValue(new DummyRunExecutorService()); + } + } + + #if MC_VER >= MC_1_17_1 + @Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Runnable;", + at = @At("HEAD"), cancellable = true) + private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable ci) + { + if (shouldApplyOverride()) + { + //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered"); + ci.setReturnValue(r); + } + } + #endif + #if MC_VER >= MC_1_18_2 + @Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;", + at = @At("HEAD"), cancellable = true) + private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier r, CallbackInfoReturnable> ci) + { + if (shouldApplyOverride()) + { + //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered"); + ci.setReturnValue(r); + } + } + #endif + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/unsafe/MixinThreadingDetector.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/unsafe/MixinThreadingDetector.java new file mode 100644 index 000000000..1d62f4785 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/mixins/server/unsafe/MixinThreadingDetector.java @@ -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 . + */ + +package com.seibel.distanthorizons.neoforged.mixins.server.unsafe; + +import org.spongepowered.asm.mixin.Mixin; +#if MC_VER >= MC_1_18_2 + +import net.minecraft.util.ThreadingDetector; +import org.spongepowered.asm.mixin.Mutable; +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 java.util.concurrent.Semaphore; + +/** + * Why does this exist? But okay! (Will be probably removed when the experimental generator is done) + * FIXME: Recheck this // STILL check this + */ +@Mixin(ThreadingDetector.class) +public class MixinThreadingDetector +{ + @Mutable + @Shadow + private Semaphore lock; + + @Inject(method = "", at = @At("RETURN")) + private void setSemaphore(CallbackInfo ci) + { + this.lock = new Semaphore(2); + } + +} + +#else + +import net.minecraft.world.level.chunk.ChunkGenerator; + +@Mixin(ChunkGenerator.class) +public class MixinThreadingDetector { } +#endif \ No newline at end of file diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/ForgeDependencySetup.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/ForgeDependencySetup.java new file mode 100644 index 000000000..b1e73a77d --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/ForgeDependencySetup.java @@ -0,0 +1,48 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.wrappers; + +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; +import com.seibel.distanthorizons.neoforged.wrappers.modAccessor.ModChecker; + +/** + * Binds all necessary dependencies so we + * can access them in Core.
+ * This needs to be called before any Core classes + * are loaded. + * + * @author James Seibel + * @author Ran + * @version 12-1-2021 + */ +public class ForgeDependencySetup +{ + public static void createInitialBindings() + { + SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); + } + + public static void runDelayedSetup() + { + SingletonInjector.INSTANCE.runDelayedSetup(); + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/modAccessor/ModChecker.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/modAccessor/ModChecker.java new file mode 100644 index 000000000..8dfff8710 --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/modAccessor/ModChecker.java @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.wrappers.modAccessor; + +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; +import net.neoforged.fml.ModList; + +public class ModChecker implements IModChecker +{ + public static final ModChecker INSTANCE = new ModChecker(); + + @Override + public boolean isModLoaded(String modid) + { + return ModList.get().isLoaded(modid); + } + +} diff --git a/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/modAccessor/OptifineAccessor.java b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/modAccessor/OptifineAccessor.java new file mode 100644 index 000000000..6e157485d --- /dev/null +++ b/neoforged/src/main/java/com/seibel/distanthorizons/neoforged/wrappers/modAccessor/OptifineAccessor.java @@ -0,0 +1,43 @@ +/* + * 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 . + */ + +package com.seibel.distanthorizons.neoforged.wrappers.modAccessor; + +import java.util.HashSet; + +import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor; + +public class OptifineAccessor extends AbstractOptifineAccessor +{ + + @Override + public String getModName() + { + return "Optifine-Forge-1.18.X"; + } + + @Override + public HashSet getNormalRenderedChunks() + { + // TODO: Impl proper methods here + return null; + } + +} diff --git a/neoforged/src/main/resources/DistantHorizons.neoforged.mixins.json b/neoforged/src/main/resources/DistantHorizons.neoforged.mixins.json new file mode 100644 index 000000000..c8d168b6c --- /dev/null +++ b/neoforged/src/main/resources/DistantHorizons.neoforged.mixins.json @@ -0,0 +1,24 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.seibel.distanthorizons.neoforged.mixins", + "mixins": [ + "server.unsafe.MixinThreadingDetector", + "server.MixinUtilBackgroundThread", + "server.MixinChunkGenerator", + "server.MixinTFChunkGenerator" + ], + "client": [ + "client.MixinClientPacketListener", + "client.MixinDebugScreenOverlay", + "client.MixinFogRenderer", + "client.MixinGameRenderer", + "client.MixinLevelRenderer", + "client.MixinDynamicTexture", + "client.MixinLightTexture", + "client.MixinOptionsScreen", + "client.MixinTextureUtil" + ], + "server": [], + "plugin": "com.seibel.distanthorizons.neoforged.mixins.NeoforgedMixinPlugin" +} diff --git a/neoforged/src/main/resources/META-INF/mods.toml b/neoforged/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..2904583d0 --- /dev/null +++ b/neoforged/src/main/resources/META-INF/mods.toml @@ -0,0 +1,37 @@ +modLoader = "javafml" #//mandatory +loaderVersion = "*" # // mandatory. Allow all forge versions as we are definding what Minecraft versions we requre later on +license = "LGPL" +issueTrackerURL = "${issues}" + + +[[mods]] #//mandatory + modId = "distanthorizons" #//mandatory + version = "${version}" #//mandatory, gets the version number from jar populated by the build.gradle script + displayName = "${mod_name}" #//mandatory + authors = ["James Seibel", "Leonardo Amato", "Cola", "coolGi", "Ran", "Leetom"] # Should be done with `$authors`, but architectury complains + #//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ + displayURL = "${homepage}" + description = "${description}" #//mandatory. The description text for the mod + logoFile = "logo.png" + catalogueImageIcon = "icon.png" + credits = "Massive thanks to: Leonardo, Cola, Ran, CoolGi, and Leetom. For their hard work to bring Distant Horizons to where it is today. - James" + #// if not set defaults to "false" + clientSideOnly = "true" + #// if not set side defaults to "BOTH" + #// TODO change to "BOTH" when we add server support + side = "CLIENT" + #// Allow any version to be present (or not) on the server + acceptableRemoteVersions = "*" + +# TODO: Once there is a way to move this to the `META-INF/MANIFEST.MF` with architectury, DO SO! +# (currently, this only works cus neoforge's mods.toml is added to the jar after forge's mods.toml, so this can work +[[mixins]] + config = "DistantHorizons.neoforged.mixins.json" + +[[dependencies.distanthorizons]] + modId = "minecraft" + mandatory = true # Forge syntax + type = "required" # Neoforged syntax + versionRange = "${compatible_forgemc_versions}" # Where we set what version of mc it is avalible for + ordering = "NONE" + side = "BOTH" \ No newline at end of file diff --git a/neoforged/src/main/resources/pack.mcmeta b/neoforged/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..37621f6f9 --- /dev/null +++ b/neoforged/src/main/resources/pack.mcmeta @@ -0,0 +1,10 @@ +{ + "pack": { + "pack_format": 7, + "supported_formats": { + "min_inclusive": 16, + "max_inclusive": 90000 + }, + "description": "Distant Horizons" + } +} diff --git a/settings.gradle b/settings.gradle index 7a873a6bb..69a4656fc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,11 +4,15 @@ pluginManagement { name "Fabric" url "https://maven.fabricmc.net/" } - // TODO: Stop using Forge for versions with NeoForge + // TODO: Stop using Forge for versions with NeoForged maven { name "Forge" url "https://maven.minecraftforge.net/" } + maven { + name "Neoforged" + url "https://maven.neoforged.net/releases/" + } maven { name "Architectury (Better Forge because regular Forge is annoying)" // TODO: Once we switch to NeoForge, would it's gradle work better? or will it have Forge's problems in it url "https://maven.architectury.dev/" @@ -84,7 +88,9 @@ project(":api").projectDir = file('coreSubProjects/api') include("common") // Enables or disables the subprojects depending on whats in the versionProperties/mcVer.properties for (loader in ((String) gradle.builds_for).split(",")) { - include(loader.strip()) // Strip it in case a space is added before or after the comma + def l = loader.strip() // Strip it in case a space is added before or after the comma + println "Adding loader " + l + include(l) } //if (gradle.builds_for.contains("fabric") || gradle.builds_for.contains("quilt")) // include("fabricLike") diff --git a/versionProperties/1.20.4.properties b/versionProperties/1.20.4.properties index 5cec6abec..479aaa056 100644 --- a/versionProperties/1.20.4.properties +++ b/versionProperties/1.20.4.properties @@ -1,10 +1,10 @@ # 1.20.4 version java_version=17 minecraft_version=1.20.4 -parchment_version=1.20.1:2023.09.03 +parchment_version=1.20.2:2023.12.10 compatible_minecraft_versions=["1.20.3", "1.20.4"] accessWidenerVersion=1_20_2 -builds_for=fabric,forge +builds_for=fabric,forge,neoforged # Fabric loader fabric_loader_version=0.15.1 @@ -36,13 +36,14 @@ fabric_api_version=0.91.2+1.20.4 enable_immersive_portals=0 enable_canvas=0 -# Forge loader +# (Neo)Forge loader forge_version=49.0.3 - # Forge mod versions +neoforged_version=20.4.49-beta + # (Neo)Forge mod versions starlight_version_forge= terraforged_version= - # Forge mod run + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client