NeoForge 1.20.2 Port

This commit is contained in:
shedaniel
2023-11-15 03:56:31 +08:00
parent cc2b8c7489
commit d309d26bff
55 changed files with 1348 additions and 227 deletions

View File

@@ -29,6 +29,10 @@ subprojects {
minecraft "com.mojang:minecraft:${rootProject.architectury.minecraft}"
mappings loom.officialMojangMappings()
}
repositories {
maven { url "https://maven.neoforged.net/releases/" }
}
}
allprojects {

View File

@@ -9,7 +9,9 @@ dependencies {
}
architectury {
common(rootProject.platforms.split(","))
common(rootProject.platforms.split(",")) {
it.platformPackage "neoforge", "forge"
}
}
/**

View File

@@ -41,11 +41,25 @@ public final class Platform {
return simpleLoaderCache == 0;
}
@Deprecated(forRemoval = true)
public static boolean isForge() {
return isForgeLike();
}
public static boolean isForgeLike() {
return isMinecraftForge() || isNeoForge();
}
public static boolean isMinecraftForge() {
updateLoaderCache();
return simpleLoaderCache == 1;
}
public static boolean isNeoForge() {
updateLoaderCache();
return simpleLoaderCache == 2;
}
private static void updateLoaderCache() {
if (simpleLoaderCache != -1) {
return;
@@ -54,6 +68,7 @@ public final class Platform {
switch (ArchitecturyTarget.getCurrentTarget()) {
case "fabric" -> simpleLoaderCache = 0;
case "forge" -> simpleLoaderCache = 1;
case "neoforge" -> simpleLoaderCache = 2;
}
}

View File

@@ -0,0 +1,24 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.utils;
public class ArchitecturyConstants {
public static final String MOD_ID = "architectury";
}

View File

@@ -1,109 +1,28 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
id "me.shedaniel.unified-publishing"
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
forge {
mixinConfig "architectury.mixins.json"
mixinConfig "architectury-common.mixins.json"
convertAccessWideners = true
extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
}
}
architectury {
platformSetupLoomIde()
forge()
}
configurations {
common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentForge.extendsFrom common
forgeLike(["forge", "neoforge"]) {
it.platformPackage "neoforge", "forge"
it.remapForgeLike "net/minecraftforge/common/extensions/IForgeItem", "net/neoforged/neoforge/common/extensions/IItemExtension"
it.remapForgeLike "net/minecraftforge/client/event/TextureStitchEvent\$Post", "net/neoforged/neoforge/client/event/TextureAtlasStitchedEvent"
it.remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid", "net/neoforged/neoforge/fluids/BaseFlowingFluid"
it.remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid\$Properties", "net/neoforged/neoforge/fluids/BaseFlowingFluid\$Properties"
it.remapForgeLike "net/minecraftforge/common/ForgeHooks", "net/neoforged/neoforge/common/CommonHooks"
}
}
dependencies {
forge "net.minecraftforge:forge:${rootProject.architectury.minecraft}-${rootProject.forge_version}"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive false }
}
processResources {
filesMatching("META-INF/mods.toml") {
expand "version": project.version
}
inputs.property "META-INF/mods.toml", project.version
}
shadowJar {
exclude "fabric.mod.json"
exclude "architectury-common.accessWidener"
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
archiveClassifier = "dev-shadow"
// Replace classes with forge's version
exclude "dev/architectury/core/block/ArchitecturyLiquidBlock.class"
exclude "dev/architectury/core/fluid/ArchitecturyFlowingFluid.class"
exclude 'dev/architectury/core/fluid/ArchitecturyFlowingFluid$Source.class'
exclude 'dev/architectury/core/fluid/ArchitecturyFlowingFluid$Flowing.class'
exclude 'dev/architectury/core/item/ArchitecturyBucketItem.class'
exclude 'dev/architectury/core/item/ArchitecturyMobBucketItem.class'
relocate "dev.architectury.core.block.forge.imitator", "dev.architectury.core.block"
relocate "dev.architectury.core.fluid.forge.imitator", "dev.architectury.core.fluid"
relocate "dev.architectury.core.item.forge.imitator", "dev.architectury.core.item"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
archiveClassifier = null
}
task renameJarForPublication(type: Zip, dependsOn: remapJar) {
from remapJar.archiveFile.map { zipTree(it) }
archiveExtension = "jar"
metadataCharset "UTF-8"
destinationDirectory = base.libsDirectory
archiveClassifier = project.name
}
assemble.dependsOn renameJarForPublication
jar {
archiveClassifier = "dev"
}
sourcesJar {
afterEvaluate {
[":common"].forEach {
def depSources = project(it).sourcesJar
dependsOn depSources
from(depSources.archiveFile.map { zipTree(it) }) {
exclude "architectury.accessWidener"
}
}
}
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
compileOnly(project(path: ":common", configuration: "namedElements")) { transitive false }
}
publishing {
publications {
mavenForge(MavenPublication) {
artifactId = rootProject.archivesBaseName + "-forge"
artifactId = rootProject.archivesBaseName + "-forge-like"
from components.java
}
}
@@ -120,33 +39,3 @@ publishing {
}
}
}
unifiedPublishing {
project {
displayName = "[MinecraftForge $rootProject.supported_version] v$project.version"
releaseType = "$rootProject.artifact_type"
changelog = releaseChangelog()
gameVersions = ["1.20.2"]
gameLoaders = ["forge"]
mainPublication renameJarForPublication
var CURSE_API_KEY = project.findProperty("CURSE_API_KEY") ?: System.getenv("CURSE_API_KEY")
if (CURSE_API_KEY != null) {
curseforge {
token = CURSE_API_KEY
id = rootProject.curseforge_id
gameVersions.addAll "Java 17"
}
}
var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN")
if (MODRINTH_TOKEN != null) {
modrinth {
token = MODRINTH_TOKEN
id = rootProject.modrinth_id
version = "$project.version+$project.name"
}
}
}
}

View File

@@ -19,8 +19,8 @@
package dev.architectury.event.forge;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
@@ -29,23 +29,23 @@ public class EventHandlerImpl {
@OnlyIn(Dist.CLIENT)
public static void registerClient() {
MinecraftForge.EVENT_BUS.register(EventHandlerImplClient.class);
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.register(EventHandlerImplClient.ModBasedEventHandler.class);
});
}
public static void registerCommon() {
MinecraftForge.EVENT_BUS.register(EventHandlerImplCommon.class);
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.register(EventHandlerImplCommon.ModBasedEventHandler.class);
});
}
@OnlyIn(Dist.DEDICATED_SERVER)
public static void registerServer() {
MinecraftForge.EVENT_BUS.register(EventHandlerImplServer.class);
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
bus.register(EventHandlerImplServer.ModBasedEventHandler.class);
});
// MinecraftForge.EVENT_BUS.register(EventHandlerImplServer.class);
// EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
// bus.register(EventHandlerImplServer.ModBasedEventHandler.class);
// });
}
}

View File

@@ -27,6 +27,7 @@ import dev.architectury.event.events.common.InteractionEvent;
import dev.architectury.impl.ScreenAccessImpl;
import dev.architectury.impl.TooltipEventColorContextImpl;
import dev.architectury.impl.TooltipEventPositionContextImpl;
import dev.architectury.platform.Platform;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.Screen;
@@ -42,6 +43,8 @@ import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import java.lang.reflect.InvocationTargetException;
@OnlyIn(Dist.CLIENT)
public class EventHandlerImplClient {
@SubscribeEvent(priority = EventPriority.HIGH)
@@ -217,14 +220,40 @@ public class EventHandlerImplClient {
@SubscribeEvent(priority = EventPriority.HIGH)
public static void eventMouseScrollEvent(ScreenEvent.MouseScrolled.Pre event) {
if (ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getDeltaX(), event.getDeltaY()).isFalse()) {
double deltaX, deltaY;
if (Platform.isNeoForge()) {
try {
deltaX = (double) event.getClass().getMethod("getScrollDeltaX").invoke(event);
deltaY = (double) event.getClass().getMethod("getScrollDeltaY").invoke(event);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
deltaX = event.getDeltaX();
deltaY = event.getDeltaY();
}
if (ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), deltaX, deltaY).isFalse()) {
event.setCanceled(true);
}
}
@SubscribeEvent(priority = EventPriority.HIGH)
public static void eventMouseScrollEvent(ScreenEvent.MouseScrolled.Post event) {
ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getDeltaX(), event.getDeltaY());
double deltaX, deltaY;
if (Platform.isNeoForge()) {
try {
deltaX = (double) event.getClass().getMethod("getScrollDeltaX").invoke(event);
deltaY = (double) event.getClass().getMethod("getScrollDeltaY").invoke(event);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
deltaX = event.getDeltaX();
deltaY = event.getDeltaY();
}
ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), deltaX, deltaY);
}
@SubscribeEvent(priority = EventPriority.HIGH)

View File

@@ -57,20 +57,30 @@ final class LootTableModificationContextImpl implements LootEvent.LootTableModif
throw new RuntimeException(e);
}
} catch (NoSuchFieldException ignored2) {
for (Field field : LootTable.class.getDeclaredFields()) {
if (field.getType().equals(List.class)) {
// This is probably the field
field.setAccessible(true);
try {
pools = (List<LootPool>) field.get(table);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
try {
Field field = LootTable.class.getDeclaredField("pools");
field.setAccessible(true);
try {
pools = (List<LootPool>) field.get(table);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
} catch (NoSuchFieldException ignored3) {
for (Field field : LootTable.class.getDeclaredFields()) {
if (field.getType().equals(List.class)) {
// This is probably the field
field.setAccessible(true);
try {
pools = (List<LootPool>) field.get(table);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
if (pools == null) {
throw new RuntimeException("Unable to find pools field in LootTable!");
if (pools == null) {
throw new RuntimeException("Unable to find pools field in LootTable!");
}
}
}
}

View File

@@ -19,14 +19,13 @@
package dev.architectury.hooks.client.screen.forge;
import dev.architectury.mixin.forge.ScreenAccessor;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Renderable;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.Screen;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class ScreenHooksImpl {
@@ -39,26 +38,14 @@ public class ScreenHooksImpl {
}
public static <T extends AbstractWidget & Renderable & NarratableEntry> T addRenderableWidget(Screen screen, T widget) {
try {
return (T) ObfuscationReflectionHelper.findMethod(Screen.class, "m_142416_", GuiEventListener.class).invoke(screen, widget);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return ((ScreenAccessor) screen).invokeAddRenderableWidget(widget);
}
public static <T extends Renderable> T addRenderableOnly(Screen screen, T listener) {
try {
return (T) ObfuscationReflectionHelper.findMethod(Screen.class, "m_169394_", Renderable.class).invoke(screen, listener);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return ((ScreenAccessor) screen).invokeAddRenderableOnly(listener);
}
public static <T extends GuiEventListener & NarratableEntry> T addWidget(Screen screen, T listener) {
try {
return (T) ObfuscationReflectionHelper.findMethod(Screen.class, "m_7787_", GuiEventListener.class).invoke(screen, listener);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return ((ScreenAccessor) screen).invokeAddWidget(listener);
}
}

View File

@@ -0,0 +1,39 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.mixin.forge;
import net.minecraft.client.gui.components.Renderable;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.Screen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Screen.class)
public interface ScreenAccessor {
@Invoker("addRenderableWidget")
<T extends GuiEventListener & Renderable & NarratableEntry> T invokeAddRenderableWidget(T arg);
@Invoker("addRenderableOnly")
<T extends Renderable> T invokeAddRenderableOnly(T arg);
@Invoker("addWidget")
<T extends GuiEventListener & NarratableEntry> T invokeAddWidget(T arg);
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.platform.hooks;
import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraftforge.eventbus.api.IEventBus;
import java.util.Optional;
import java.util.function.Consumer;
public final class EventBusesHooks {
private EventBusesHooks() {
}
@ExpectPlatform
public static void whenAvailable(String modId, Consumer<IEventBus> busConsumer) {
throw new AssertionError();
}
@ExpectPlatform
public static Optional<IEventBus> getModEventBus(String modId) {
throw new AssertionError();
}
}

View File

@@ -19,6 +19,7 @@
package dev.architectury.plugin.forge;
import dev.architectury.injectables.targets.ArchitecturyTarget;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
@@ -29,7 +30,7 @@ import java.util.Set;
public class ArchitecturyMixinPlugin implements IMixinConfigPlugin {
@Override
public void onLoad(String mixinPackage) {
}
@Override
@@ -44,21 +45,23 @@ public class ArchitecturyMixinPlugin implements IMixinConfigPlugin {
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> getMixins() {
return null;
return ArchitecturyTarget.getCurrentTarget().equals("forge")
? List.of("minecraftforge.MixinChunkSerializer")
: List.of("neoforge.MixinChunkSerializer");
}
@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
}

View File

@@ -19,14 +19,12 @@
package dev.architectury.registry.client.keymappings.forge;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -34,12 +32,17 @@ import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public class KeyMappingRegistryImpl {
private static final Logger LOGGER = LogManager.getLogger(KeyMappingRegistryImpl.class);
private static final List<KeyMapping> MAPPINGS = new ArrayList<>();
private static boolean eventCalled = false;
static {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.addListener(KeyMappingRegistryImpl::event);
});
}
public static void register(KeyMapping mapping) {
if (eventCalled) {
Options options = Minecraft.getInstance().options;
@@ -50,7 +53,6 @@ public class KeyMappingRegistryImpl {
}
}
@SubscribeEvent
public static void event(RegisterKeyMappingsEvent event) {
MAPPINGS.forEach(event::register);
eventCalled = true;

View File

@@ -19,8 +19,8 @@
package dev.architectury.registry.client.level.entity.forge;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraftforge.client.event.EntityRenderersEvent;
@@ -34,7 +34,7 @@ public class EntityModelLayerRegistryImpl {
private static final Map<ModelLayerLocation, Supplier<LayerDefinition>> DEFINITIONS = new ConcurrentHashMap<>();
static {
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.register(EntityModelLayerRegistryImpl.class);
});
}

View File

@@ -19,8 +19,8 @@
package dev.architectury.registry.client.level.entity.forge;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
@@ -39,7 +39,7 @@ public class EntityRendererRegistryImpl {
}
static {
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.register(EntityRendererRegistryImpl.class);
});
}

View File

@@ -20,8 +20,9 @@
package dev.architectury.registry.client.particle.forge;
import com.mojang.logging.LogUtils;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.registry.client.particle.ParticleProviderRegistry;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.ParticleEngine;
import net.minecraft.client.particle.ParticleProvider;
@@ -31,21 +32,22 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.util.RandomSource;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterParticleProvidersEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ParticleProviderRegistryImpl {
public static final Logger LOGGER = LogUtils.getLogger();
static {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.addListener(ParticleProviderRegistryImpl::onParticleFactoryRegister);
});
}
private static final class ExtendedSpriteSetImpl implements ParticleProviderRegistry.ExtendedSpriteSet {
private final ParticleEngine engine;
private final SpriteSet delegate;
@@ -105,7 +107,6 @@ public class ParticleProviderRegistryImpl {
}
}
@SubscribeEvent
public static void onParticleFactoryRegister(RegisterParticleProvidersEvent event) {
if (deferred != null) {
ParticleProviderRegistrar registrar = ParticleProviderRegistrar.ofForge(event);

View File

@@ -20,8 +20,8 @@
package dev.architectury.registry.client.rendering.forge;
import com.google.common.collect.Lists;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockColor;
import net.minecraft.client.color.item.ItemColor;
@@ -40,7 +40,7 @@ public class ColorHandlerRegistryImpl {
private static final List<Pair<BlockColor, Supplier<? extends Block>[]>> BLOCK_COLORS = Lists.newArrayList();
static {
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.register(ColorHandlerRegistryImpl.class);
});
}

View File

@@ -22,21 +22,19 @@ package dev.architectury.registry.forge;
import com.google.common.base.Suppliers;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.registry.CreativeTabOutput;
import dev.architectury.registry.CreativeTabRegistry;
import dev.architectury.registry.registries.DeferredSupplier;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.CreativeModeTabRegistry;
import net.minecraftforge.common.util.MutableHashedLinkedMap;
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.ApiStatus;
@@ -46,7 +44,6 @@ import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public class CreativeTabRegistryImpl {
private static final Logger LOGGER = LogManager.getLogger(CreativeTabRegistryImpl.class);
@@ -54,6 +51,10 @@ public class CreativeTabRegistryImpl {
private static final Multimap<TabKey, Supplier<ItemStack>> APPENDS = MultimapBuilder.hashKeys().arrayListValues().build();
static {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.addListener(CreativeTabRegistryImpl::event);
});
BUILD_CONTENTS_LISTENERS.add(event -> {
for (Map.Entry<TabKey, Collection<Supplier<ItemStack>>> keyEntry : APPENDS.asMap().entrySet()) {
Supplier<List<ItemStack>> stacks = Suppliers.memoize(() -> keyEntry.getValue().stream()
@@ -76,7 +77,6 @@ public class CreativeTabRegistryImpl {
});
}
@SubscribeEvent
public static void event(BuildCreativeModeTabContentsEvent event) {
for (Consumer<BuildCreativeModeTabContentsEvent> listener : BUILD_CONTENTS_LISTENERS) {
listener.accept(event);

View File

@@ -20,7 +20,8 @@
package dev.architectury.registry.forge;
import com.google.common.collect.Lists;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
@@ -28,18 +29,20 @@ import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AddReloadListenerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID)
public class ReloadListenerRegistryImpl {
private static List<PreparableReloadListener> serverDataReloadListeners = Lists.newArrayList();
static {
MinecraftForge.EVENT_BUS.addListener(ReloadListenerRegistryImpl::addReloadListeners);
}
public static void register(PackType type, PreparableReloadListener listener, @Nullable ResourceLocation listenerId, Collection<ResourceLocation> dependencies) {
if (type == PackType.SERVER_DATA) {
serverDataReloadListeners.add(listener);
@@ -53,7 +56,6 @@ public class ReloadListenerRegistryImpl {
((ReloadableResourceManager) Minecraft.getInstance().getResourceManager()).registerReloadListener(listener);
}
@SubscribeEvent
public static void addReloadListeners(AddReloadListenerEvent event) {
for (PreparableReloadListener listener : serverDataReloadListeners) {
event.addListener(listener);

View File

@@ -21,10 +21,10 @@ package dev.architectury.registry.level.biome.forge;
import com.google.common.collect.Lists;
import com.mojang.serialization.Codec;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.hooks.level.biome.*;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.registry.level.biome.BiomeModifications.BiomeContext;
import dev.architectury.utils.ArchitecturyConstants;
import dev.architectury.utils.GameInstance;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
@@ -64,10 +64,10 @@ public class BiomeModificationsImpl {
private static Codec<BiomeModifierImpl> noneBiomeModCodec = null;
public static void init() {
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID,bus -> {
bus.<RegisterEvent>addListener(event -> {
event.register(ForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, registry -> {
registry.register(new ResourceLocation(ArchitecturyForge.MOD_ID, "none_biome_mod_codec"),
registry.register(new ResourceLocation(ArchitecturyConstants.MOD_ID, "none_biome_mod_codec"),
noneBiomeModCodec = Codec.unit(BiomeModifierImpl.INSTANCE));
});
});

View File

@@ -19,8 +19,8 @@
package dev.architectury.registry.level.entity.forge;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
@@ -39,7 +39,7 @@ public class EntityAttributeRegistryImpl {
}
static {
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
bus.register(EntityAttributeRegistryImpl.class);
});
}

View File

@@ -21,23 +21,25 @@ package dev.architectury.registry.level.entity.trade.forge;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import dev.architectury.forge.ArchitecturyForge;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerTrades;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.village.VillagerTradesEvent;
import net.minecraftforge.event.village.WandererTradesEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.*;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID)
public class TradeRegistryImpl {
private static final Map<VillagerProfession, Int2ObjectMap<List<VillagerTrades.ItemListing>>> TRADES_TO_ADD = new HashMap<>();
private static final List<VillagerTrades.ItemListing> WANDERER_TRADER_TRADES_GENERIC = new ArrayList<>();
private static final List<VillagerTrades.ItemListing> WANDERER_TRADER_TRADES_RARE = new ArrayList<>();
static {
MinecraftForge.EVENT_BUS.addListener(TradeRegistryImpl::onTradeRegistering);
MinecraftForge.EVENT_BUS.addListener(TradeRegistryImpl::onWanderingTradeRegistering);
}
public static void registerVillagerTrade0(VillagerProfession profession, int level, VillagerTrades.ItemListing... trades) {
Int2ObjectMap<List<VillagerTrades.ItemListing>> tradesForProfession = TRADES_TO_ADD.computeIfAbsent(profession, $ -> new Int2ObjectOpenHashMap<>());
List<VillagerTrades.ItemListing> tradesForLevel = tradesForProfession.computeIfAbsent(level, $ -> new ArrayList<>());
@@ -52,7 +54,6 @@ public class TradeRegistryImpl {
}
}
@SubscribeEvent
public static void onTradeRegistering(VillagerTradesEvent event) {
Int2ObjectMap<List<VillagerTrades.ItemListing>> trades = TRADES_TO_ADD.get(event.getType());
@@ -63,7 +64,6 @@ public class TradeRegistryImpl {
}
}
@SubscribeEvent
public static void onWanderingTradeRegistering(WandererTradesEvent event) {
if (!WANDERER_TRADER_TRADES_GENERIC.isEmpty()) {
event.getGenericTrades().addAll(WANDERER_TRADER_TRADES_GENERIC);

View File

@@ -23,7 +23,7 @@ import com.google.common.base.Objects;
import com.google.common.base.Suppliers;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.platform.hooks.EventBusesHooks;
import dev.architectury.registry.registries.Registrar;
import dev.architectury.registry.registries.RegistrarBuilder;
import dev.architectury.registry.registries.RegistrarManager;
@@ -123,7 +123,7 @@ public class RegistrarManagerImpl {
public RegistryProviderImpl(String modId) {
this.modId = modId;
this.eventBus = Suppliers.memoize(() -> {
IEventBus eventBus = EventBuses.getModEventBus(modId).orElseThrow(() -> new IllegalStateException("Can't get event bus for mod '" + modId + "' because it was not registered!"));
IEventBus eventBus = EventBusesHooks.getModEventBus(modId).orElseThrow(() -> new IllegalStateException("Can't get event bus for mod '" + modId + "' because it was not registered!"));
eventBus.register(new EventListener());
return eventBus;
});

View File

@@ -6,10 +6,10 @@
"minVersion": "0.8",
"client": [
"MixinClientLevel",
"MixinMinecraft"
"MixinMinecraft",
"ScreenAccessor"
],
"mixins": [
"MixinChunkSerializer",
"MixinEntitySpawnExtension",
"MixinFallingBlockEntity",
"MixinItemExtension",

View File

@@ -1,7 +1,7 @@
org.gradle.jvmargs=-Xmx6G
org.gradle.daemon=false
platforms=fabric,forge
platforms=fabric,forge,neoforge
minecraft_version=1.20.2
supported_version=1.20.2
@@ -18,6 +18,7 @@ fabric_api_version=0.89.1+1.20.2
mod_menu_version=7.0.0
forge_version=48.0.38
neoforge_version=20.2.52-beta
curseforge_id=419699
modrinth_id=lhGA9TYQ

154
minecraftforge/build.gradle Normal file
View File

@@ -0,0 +1,154 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
id "me.shedaniel.unified-publishing"
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
forge {
mixinConfig "architectury.mixins.json"
mixinConfig "architectury-common.mixins.json"
convertAccessWideners = true
extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
}
}
architectury {
platformSetupLoomIde()
forge()
}
configurations {
common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentForge.extendsFrom common
}
dependencies {
forge "net.minecraftforge:forge:${rootProject.architectury.minecraft}-${rootProject.forge_version}"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
common(project(path: ":forge", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive false }
shadowCommon(project(path: ":forge", configuration: "transformProductionForge")) { transitive false }
}
processResources {
filesMatching("META-INF/mods.toml") {
expand "version": project.version
}
inputs.property "META-INF/mods.toml", project.version
}
shadowJar {
exclude "fabric.mod.json"
exclude "architectury-common.accessWidener"
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
archiveClassifier = "dev-shadow"
// Replace classes with forge's version
exclude "dev/architectury/core/block/ArchitecturyLiquidBlock.class"
exclude "dev/architectury/core/fluid/ArchitecturyFlowingFluid.class"
exclude 'dev/architectury/core/fluid/ArchitecturyFlowingFluid$Source.class'
exclude 'dev/architectury/core/fluid/ArchitecturyFlowingFluid$Flowing.class'
exclude 'dev/architectury/core/item/ArchitecturyBucketItem.class'
exclude 'dev/architectury/core/item/ArchitecturyMobBucketItem.class'
relocate "dev.architectury.core.block.forge.imitator", "dev.architectury.core.block"
relocate "dev.architectury.core.fluid.forge.imitator", "dev.architectury.core.fluid"
relocate "dev.architectury.core.item.forge.imitator", "dev.architectury.core.item"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
archiveClassifier = null
}
task renameJarForPublication(type: Zip, dependsOn: remapJar) {
from remapJar.archiveFile.map { zipTree(it) }
archiveExtension = "jar"
metadataCharset "UTF-8"
destinationDirectory = base.libsDirectory
archiveClassifier = project.name
}
assemble.dependsOn renameJarForPublication
jar {
archiveClassifier = "dev"
}
sourcesJar {
afterEvaluate {
[":common"].forEach {
def depSources = project(it).sourcesJar
dependsOn depSources
from(depSources.archiveFile.map { zipTree(it) }) {
exclude "architectury.accessWidener"
}
}
}
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
publishing {
publications {
mavenMinecraftForge(MavenPublication) {
artifactId = rootProject.archivesBaseName + "-forge"
from components.java
}
}
repositories {
if (System.getenv("MAVEN_PASS") != null) {
maven {
url = "https://deploy.shedaniel.me/"
credentials {
username = "shedaniel"
password = System.getenv("MAVEN_PASS")
}
}
}
}
}
unifiedPublishing {
project {
displayName = "[MinecraftForge $rootProject.supported_version] v$project.version"
releaseType = "$rootProject.artifact_type"
changelog = releaseChangelog()
gameVersions = ["1.20.2"]
gameLoaders = ["forge"]
mainPublication renameJarForPublication
var CURSE_API_KEY = project.findProperty("CURSE_API_KEY") ?: System.getenv("CURSE_API_KEY")
if (CURSE_API_KEY != null) {
curseforge {
token = CURSE_API_KEY
id = rootProject.curseforge_id
gameVersions.addAll "Java 17"
}
}
var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN")
if (MODRINTH_TOKEN != null) {
modrinth {
token = MODRINTH_TOKEN
id = rootProject.modrinth_id
version = "$project.version+$project.name"
}
}
}
}

View File

@@ -0,0 +1 @@
loom.platform=forge

View File

@@ -19,18 +19,17 @@
package dev.architectury.forge;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.event.EventHandler;
import dev.architectury.platform.forge.EventBuses;
import dev.architectury.registry.level.biome.forge.BiomeModificationsImpl;
import dev.architectury.utils.ArchitecturyConstants;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@Mod(ArchitecturyForge.MOD_ID)
@Mod(ArchitecturyConstants.MOD_ID)
public class ArchitecturyForge {
public static final String MOD_ID = "architectury";
public ArchitecturyForge() {
EventBuses.registerModEventBus(ArchitecturyForge.MOD_ID, FMLJavaModLoadingContext.get().getModEventBus());
EventBuses.registerModEventBus(ArchitecturyConstants.MOD_ID, FMLJavaModLoadingContext.get().getModEventBus());
EventHandler.init();
BiomeModificationsImpl.init();
}

View File

@@ -17,7 +17,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.mixin.forge;
package dev.architectury.mixin.forge.minecraftforge;
import dev.architectury.event.forge.EventHandlerImplCommon;
import net.minecraft.nbt.CompoundTag;

View File

@@ -22,7 +22,6 @@ package dev.architectury.networking.forge;
import com.google.common.collect.*;
import com.mojang.logging.LogUtils;
import dev.architectury.forge.ArchitecturyForge;
import dev.architectury.networking.NetworkManager;
import dev.architectury.networking.NetworkManager.NetworkReceiver;
import dev.architectury.networking.transformers.PacketSink;
@@ -52,7 +51,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.function.Consumer;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID)
@Mod.EventBusSubscriber(modid = "architectury")
public class NetworkManagerImpl {
public static void registerReceiver(NetworkManager.Side side, ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
Objects.requireNonNull(id, "Cannot register receiver with a null ID!");

View File

@@ -0,0 +1,36 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.platform.hooks.forge;
import dev.architectury.platform.forge.EventBuses;
import net.minecraftforge.eventbus.api.IEventBus;
import java.util.Optional;
import java.util.function.Consumer;
public class EventBusesHooksImpl {
public static void whenAvailable(String modId, Consumer<IEventBus> busConsumer) {
EventBuses.onRegistered(modId, busConsumer);
}
public static Optional<IEventBus> getModEventBus(String modId) {
return EventBuses.getModEventBus(modId);
}
}

View File

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

155
neoforge/build.gradle Normal file
View File

@@ -0,0 +1,155 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
id "me.shedaniel.unified-publishing"
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
}
architectury {
platformSetupLoomIde()
neoForge {
platformPackage = "forge"
remapForgeLike "net/minecraftforge/common/extensions/IForgeItem", "net/neoforged/neoforge/common/extensions/IItemExtension"
remapForgeLike "net/minecraftforge/client/event/TextureStitchEvent\$Post", "net/neoforged/neoforge/client/event/TextureAtlasStitchedEvent"
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid", "net/neoforged/neoforge/fluids/BaseFlowingFluid"
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid\$Properties", "net/neoforged/neoforge/fluids/BaseFlowingFluid\$Properties"
remapForgeLike "net/minecraftforge/common/ForgeHooks", "net/neoforged/neoforge/common/CommonHooks"
}
}
configurations {
common
forgeLike
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common, forgeLike
runtimeClasspath.extendsFrom common, forgeLike
developmentNeoForge.extendsFrom common
developmentForgeLike.extendsFrom forgeLike
}
dependencies {
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
forgeLike(project(path: ":forge", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive false }
shadowCommon(project(path: ":forge", configuration: "transformProductionNeoForge")) { transitive false }
}
processResources {
filesMatching("META-INF/mods.toml") {
expand "version": project.version
}
inputs.property "META-INF/mods.toml", project.version
}
shadowJar {
exclude "fabric.mod.json"
exclude "architectury-common.accessWidener"
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
archiveClassifier = "dev-shadow"
// Replace classes with forge's version
exclude "dev/architectury/core/block/ArchitecturyLiquidBlock.class"
exclude "dev/architectury/core/fluid/ArchitecturyFlowingFluid.class"
exclude 'dev/architectury/core/fluid/ArchitecturyFlowingFluid$Source.class'
exclude 'dev/architectury/core/fluid/ArchitecturyFlowingFluid$Flowing.class'
exclude 'dev/architectury/core/item/ArchitecturyBucketItem.class'
exclude 'dev/architectury/core/item/ArchitecturyMobBucketItem.class'
relocate "dev.architectury.core.block.forge.imitator", "dev.architectury.core.block"
relocate "dev.architectury.core.fluid.forge.imitator", "dev.architectury.core.fluid"
relocate "dev.architectury.core.item.forge.imitator", "dev.architectury.core.item"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
archiveClassifier = null
}
task renameJarForPublication(type: Zip, dependsOn: remapJar) {
from remapJar.archiveFile.map { zipTree(it) }
archiveExtension = "jar"
metadataCharset "UTF-8"
destinationDirectory = base.libsDirectory
archiveClassifier = project.name
}
assemble.dependsOn renameJarForPublication
jar {
archiveClassifier = "dev"
}
sourcesJar {
afterEvaluate {
[":common"].forEach {
def depSources = project(it).sourcesJar
dependsOn depSources
from(depSources.archiveFile.map { zipTree(it) }) {
exclude "architectury.accessWidener"
}
}
}
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
publishing {
publications {
mavenNeoForge(MavenPublication) {
artifactId = rootProject.archivesBaseName + "-neoforge"
from components.java
}
}
repositories {
if (System.getenv("MAVEN_PASS") != null) {
maven {
url = "https://deploy.shedaniel.me/"
credentials {
username = "shedaniel"
password = System.getenv("MAVEN_PASS")
}
}
}
}
}
unifiedPublishing {
project {
displayName = "[NeoForge $rootProject.supported_version] v$project.version"
releaseType = "$rootProject.artifact_type"
changelog = releaseChangelog()
gameVersions = ["1.20.2"]
gameLoaders = ["neoforge"]
mainPublication renameJarForPublication
var CURSE_API_KEY = project.findProperty("CURSE_API_KEY") ?: System.getenv("CURSE_API_KEY")
if (CURSE_API_KEY != null) {
curseforge {
token = CURSE_API_KEY
id = rootProject.curseforge_id
gameVersions.addAll "Java 17"
}
}
var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN")
if (MODRINTH_TOKEN != null) {
modrinth {
token = MODRINTH_TOKEN
id = rootProject.modrinth_id
version = "$project.version+$project.name"
}
}
}
}

View File

@@ -0,0 +1 @@
loom.platform=neoforge

View File

@@ -0,0 +1,64 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.mixin.forge.neoforge;
import dev.architectury.event.forge.EventHandlerImplCommon;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
import net.neoforged.bus.api.Event;
import net.neoforged.neoforge.event.level.ChunkDataEvent;
import org.spongepowered.asm.mixin.Mixin;
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.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.lang.ref.WeakReference;
@Mixin(ChunkSerializer.class)
public class MixinChunkSerializer {
@Unique
private static ThreadLocal<WeakReference<ServerLevel>> level = new ThreadLocal<>();
@Inject(method = "read", at = @At("HEAD"))
private static void read(ServerLevel worldIn, PoiManager arg2, ChunkPos arg3, CompoundTag arg4, CallbackInfoReturnable<ProtoChunk> cir) {
level.set(new WeakReference<>(worldIn));
}
@ModifyArg(method = "read", at = @At(value = "INVOKE",
ordinal = 1,
target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;"),
index = 0)
private static Event modifyProtoChunkLevel(Event event) {
// We should get this PRed to Forge
WeakReference<ServerLevel> levelRef = level.get();
if (levelRef != null && event instanceof ChunkDataEvent.Load) {
ChunkDataEvent.Load load = (ChunkDataEvent.Load) event;
((EventHandlerImplCommon.LevelEventAttachment) load).architectury$attachLevel(levelRef.get());
}
level.remove();
return event;
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.neoforge;
import dev.architectury.event.EventHandler;
import dev.architectury.registry.level.biome.forge.BiomeModificationsImpl;
import dev.architectury.utils.ArchitecturyConstants;
import net.neoforged.fml.common.Mod;
@Mod(ArchitecturyConstants.MOD_ID)
public class ArchitecturyNeoForge {
public ArchitecturyNeoForge() {
EventHandler.init();
BiomeModificationsImpl.init();
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.networking.forge;
import dev.architectury.networking.NetworkManager;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.network.PlayNetworkDirection;
import java.util.Collections;
import java.util.Set;
@OnlyIn(Dist.CLIENT)
public class ClientNetworkingManager {
public static void initClient() {
NetworkManagerImpl.CHANNEL.addListener(NetworkManagerImpl.createPacketHandler(PlayNetworkDirection.PLAY_TO_CLIENT, NetworkManagerImpl.S2C_TRANSFORMERS));
NeoForge.EVENT_BUS.register(ClientNetworkingManager.class);
NetworkManagerImpl.registerS2CReceiver(NetworkManagerImpl.SYNC_IDS, Collections.emptyList(), (buffer, context) -> {
Set<ResourceLocation> receivables = NetworkManagerImpl.serverReceivables;
int size = buffer.readInt();
receivables.clear();
for (int i = 0; i < size; i++) {
receivables.add(buffer.readResourceLocation());
}
context.queue(() -> {
NetworkManager.sendToServer(NetworkManagerImpl.SYNC_IDS, NetworkManagerImpl.sendSyncPacket(NetworkManagerImpl.C2S));
});
});
}
public static Player getClientPlayer() {
return Minecraft.getInstance().player;
}
@SubscribeEvent
public static void loggedOut(ClientPlayerNetworkEvent.LoggingOut event) {
NetworkManagerImpl.serverReceivables.clear();
}
}

View File

@@ -0,0 +1,203 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.networking.forge;
import com.google.common.collect.*;
import com.mojang.logging.LogUtils;
import dev.architectury.networking.NetworkManager;
import dev.architectury.networking.NetworkManager.NetworkReceiver;
import dev.architectury.networking.transformers.PacketSink;
import dev.architectury.networking.transformers.PacketTransformer;
import dev.architectury.utils.ArchitecturyConstants;
import dev.architectury.utils.Env;
import io.netty.buffer.Unpooled;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.DistExecutor;
import net.neoforged.fml.LogicalSide;
import net.neoforged.fml.common.Mod;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.network.*;
import net.neoforged.neoforge.network.event.EventNetworkChannel;
import org.slf4j.Logger;
import java.util.*;
import java.util.function.Consumer;
@Mod.EventBusSubscriber(modid = ArchitecturyConstants.MOD_ID)
public class NetworkManagerImpl {
public static void registerReceiver(NetworkManager.Side side, ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
Objects.requireNonNull(id, "Cannot register receiver with a null ID!");
packetTransformers = Objects.requireNonNullElse(packetTransformers, List.of());
Objects.requireNonNull(receiver, "Cannot register a null receiver!");
if (side == NetworkManager.Side.C2S) {
registerC2SReceiver(id, packetTransformers, receiver);
} else if (side == NetworkManager.Side.S2C) {
registerS2CReceiver(id, packetTransformers, receiver);
}
}
public static Packet<?> toPacket(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buffer) {
FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
packetBuffer.writeResourceLocation(id);
packetBuffer.writeBytes(buffer);
return (side == NetworkManager.Side.C2S ? PlayNetworkDirection.PLAY_TO_SERVER : PlayNetworkDirection.PLAY_TO_CLIENT).buildPacket(new INetworkDirection.PacketData(packetBuffer, 0), CHANNEL_ID);
}
public static void collectPackets(PacketSink sink, NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf) {
PacketTransformer transformer = side == NetworkManager.Side.C2S ? C2S_TRANSFORMERS.get(id) : S2C_TRANSFORMERS.get(id);
if (transformer != null) {
transformer.outbound(side, id, buf, (side1, id1, buf1) -> {
sink.accept(toPacket(side1, id1, buf1));
});
} else {
sink.accept(toPacket(side, id, buf));
}
}
private static final Logger LOGGER = LogUtils.getLogger();
private static final ResourceLocation CHANNEL_ID = new ResourceLocation("architectury:network");
static final ResourceLocation SYNC_IDS = new ResourceLocation("architectury:sync_ids");
static final EventNetworkChannel CHANNEL = NetworkRegistry.ChannelBuilder.named(CHANNEL_ID).networkProtocolVersion(() -> "").clientAcceptedVersions(version -> true).serverAcceptedVersions(version -> true).eventNetworkChannel();
static final Map<ResourceLocation, NetworkReceiver> S2C = Maps.newHashMap();
static final Map<ResourceLocation, NetworkReceiver> C2S = Maps.newHashMap();
static final Map<ResourceLocation, PacketTransformer> S2C_TRANSFORMERS = Maps.newHashMap();
static final Map<ResourceLocation, PacketTransformer> C2S_TRANSFORMERS = Maps.newHashMap();
static final Set<ResourceLocation> serverReceivables = Sets.newHashSet();
private static final Multimap<Player, ResourceLocation> clientReceivables = Multimaps.newMultimap(Maps.newHashMap(), Sets::newHashSet);
static {
CHANNEL.addListener(createPacketHandler(PlayNetworkDirection.PLAY_TO_SERVER, C2S_TRANSFORMERS));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::initClient);
registerC2SReceiver(SYNC_IDS, Collections.emptyList(), (buffer, context) -> {
Set<ResourceLocation> receivables = (Set<ResourceLocation>) clientReceivables.get(context.getPlayer());
int size = buffer.readInt();
receivables.clear();
for (int i = 0; i < size; i++) {
receivables.add(buffer.readResourceLocation());
}
});
}
static <T extends NetworkEvent> Consumer<T> createPacketHandler(INetworkDirection<?> direction, Map<ResourceLocation, PacketTransformer> map) {
return event -> {
NetworkEvent.Context context = event.getSource();
if (context.getDirection() != direction) return;
if (context.getPacketHandled()) return;
FriendlyByteBuf buffer = event.getPayload();
if (buffer == null) return;
ResourceLocation type = buffer.readResourceLocation();
PacketTransformer transformer = map.get(type);
if (transformer != null) {
NetworkManager.Side side = context.getDirection().getReceptionSide() == LogicalSide.CLIENT ? NetworkManager.Side.S2C : NetworkManager.Side.C2S;
NetworkManager.PacketContext packetContext = new NetworkManager.PacketContext() {
@Override
public Player getPlayer() {
return getEnvironment() == Env.CLIENT ? getClientPlayer() : context.getSender();
}
@Override
public void queue(Runnable runnable) {
context.enqueueWork(runnable);
}
@Override
public Env getEnvironment() {
return context.getDirection().getReceptionSide() == LogicalSide.CLIENT ? Env.CLIENT : Env.SERVER;
}
private Player getClientPlayer() {
return DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::getClientPlayer);
}
};
transformer.inbound(side, type, buffer, packetContext, (side1, id1, buf1) -> {
NetworkReceiver networkReceiver = side == NetworkManager.Side.C2S ? C2S.get(id1) : S2C.get(id1);
if (networkReceiver == null) {
throw new IllegalArgumentException("Network Receiver not found! " + id1);
}
networkReceiver.receive(buf1, packetContext);
});
} else {
LOGGER.error("Unknown message ID: " + type);
}
context.setPacketHandled(true);
};
}
@OnlyIn(Dist.CLIENT)
public static void registerS2CReceiver(ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
LOGGER.info("Registering S2C receiver with id {}", id);
S2C.put(id, receiver);
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
S2C_TRANSFORMERS.put(id, transformer);
}
public static void registerC2SReceiver(ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
LOGGER.info("Registering C2S receiver with id {}", id);
C2S.put(id, receiver);
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
C2S_TRANSFORMERS.put(id, transformer);
}
public static boolean canServerReceive(ResourceLocation id) {
return serverReceivables.contains(id);
}
public static boolean canPlayerReceive(ServerPlayer player, ResourceLocation id) {
return clientReceivables.get(player).contains(id);
}
public static Packet<ClientGamePacketListener> createAddEntityPacket(Entity entity) {
return NetworkHooks.getEntitySpawningPacket(entity);
}
static FriendlyByteBuf sendSyncPacket(Map<ResourceLocation, NetworkReceiver> map) {
List<ResourceLocation> availableIds = Lists.newArrayList(map.keySet());
FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
packetBuffer.writeInt(availableIds.size());
for (ResourceLocation availableId : availableIds) {
packetBuffer.writeResourceLocation(availableId);
}
return packetBuffer;
}
@SubscribeEvent
public static void loggedIn(PlayerEvent.PlayerLoggedInEvent event) {
NetworkManager.sendToPlayer((ServerPlayer) event.getEntity(), SYNC_IDS, sendSyncPacket(C2S));
}
@SubscribeEvent
public static void loggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
clientReceivables.removeAll(event.getEntity());
}
}

View File

@@ -0,0 +1,185 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.platform.forge;
import dev.architectury.platform.Mod;
import dev.architectury.utils.Env;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.ModList;
import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.fml.loading.FMLLoader;
import net.neoforged.fml.loading.FMLPaths;
import net.neoforged.fml.loading.moddiscovery.ModFileInfo;
import net.neoforged.neoforge.client.ConfigScreenHandler;
import net.neoforged.neoforgespi.language.IModFileInfo;
import net.neoforged.neoforgespi.language.IModInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class PlatformImpl {
private static final Map<String, Mod> mods = new ConcurrentHashMap<>();
public static Path getGameFolder() {
return FMLPaths.GAMEDIR.get();
}
public static Path getConfigFolder() {
return FMLPaths.CONFIGDIR.get();
}
public static Path getModsFolder() {
return FMLPaths.MODSDIR.get();
}
public static Env getEnvironment() {
return Env.fromPlatform(getEnv());
}
public static Dist getEnv() {
return FMLEnvironment.dist;
}
public static boolean isModLoaded(String id) {
return ModList.get().isLoaded(id);
}
public static Mod getMod(String id) {
return mods.computeIfAbsent(id, ModImpl::new);
}
public static Collection<Mod> getMods() {
for (IModInfo mod : ModList.get().getMods()) {
getMod(mod.getModId());
}
return mods.values();
}
public static Collection<String> getModIds() {
return ModList.get().getMods().stream().map(IModInfo::getModId).collect(Collectors.toList());
}
public static boolean isDevelopmentEnvironment() {
return !FMLLoader.isProduction();
}
private static class ModImpl implements Mod {
private final ModContainer container;
private final IModInfo info;
public ModImpl(String id) {
this.container = ModList.get().getModContainerById(id).orElseThrow();
this.info = ModList.get().getMods().stream()
.filter(modInfo -> Objects.equals(modInfo.getModId(), id))
.findAny()
.orElseThrow();
}
@Override
@NotNull
public String getModId() {
return info.getModId();
}
@Override
@NotNull
public String getVersion() {
return info.getVersion().toString();
}
@Override
@NotNull
public String getName() {
return info.getDisplayName();
}
@Override
@NotNull
public String getDescription() {
return info.getDescription();
}
@Override
public Optional<String> getLogoFile(int i) {
return this.info.getLogoFile();
}
@Override
public List<Path> getFilePaths() {
return List.of(getFilePath());
}
@Override
public Path getFilePath() {
return this.info.getOwningFile().getFile().getSecureJar().getRootPath();
}
@Override
public Optional<Path> findResource(String... path) {
return Optional.of(this.info.getOwningFile().getFile().findResource(path)).filter(Files::exists);
}
@Override
public Collection<String> getAuthors() {
Optional<String> optional = this.info.getConfig().getConfigElement("authors")
.map(String::valueOf);
return optional.isPresent() ? Collections.singleton(optional.get()) : Collections.emptyList();
}
@Override
public @Nullable Collection<String> getLicense() {
return Collections.singleton(this.info.getOwningFile().getLicense());
}
@Override
public Optional<String> getHomepage() {
return this.info.getConfig().getConfigElement("displayURL")
.map(String::valueOf);
}
@Override
public Optional<String> getSources() {
return Optional.empty();
}
@Override
public Optional<String> getIssueTracker() {
IModFileInfo owningFile = this.info.getOwningFile();
if (owningFile instanceof ModFileInfo info) {
return Optional.ofNullable(info.getIssueURL())
.map(URL::toString);
}
return Optional.empty();
}
@Override
public void registerConfigurationScreen(ConfigurationScreenProvider configurationScreenProvider) {
container.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () ->
new ConfigScreenHandler.ConfigScreenFactory((minecraft, screen) -> configurationScreenProvider.provide(screen)));
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.platform.hooks.forge;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.ModList;
import java.util.Optional;
import java.util.function.Consumer;
public class EventBusesHooksImpl {
public static void whenAvailable(String modId, Consumer<IEventBus> busConsumer) {
IEventBus bus = getModEventBus(modId).orElseThrow(() -> new IllegalStateException("Mod '" + modId + "' is not available!"));
busConsumer.accept(bus);
}
public static Optional<IEventBus> getModEventBus(String modId) {
return ModList.get().getModContainerById(modId)
.map(ModContainer::getEventBus);
}
}

View File

@@ -0,0 +1,35 @@
modLoader = "javafml"
loaderVersion = "[1,)"
issueTrackerURL = "https://github.com/shedaniel/architectury/issues"
license = "GNU LGPLv3"
[[mods]]
modId = "architectury"
version = "${version}"
displayName = "Architectury"
authors = "shedaniel"
description = '''
A intermediary api aimed to ease developing multiplatform mods.
'''
logoFile = "icon.png"
license = "LGPL-3"
[[dependencies.architectury]]
modId = "minecraft"
mandatory = true
versionRange = "[1.20.2,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.architectury]]
modId = "neoforge"
mandatory = true
versionRange = "[20.2,)"
ordering = "NONE"
side = "BOTH"
[[mixins]]
config = "architectury.mixins.json"
[[mixins]]
config = "architectury-common.mixins.json"

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@@ -0,0 +1,6 @@
{
"pack": {
"description": "Architectury",
"pack_format": 6
}
}

View File

@@ -14,8 +14,11 @@ if (JavaVersion.current().ordinal() + 1 < 17) {
include("common")
include("fabric")
include("forge")
include("minecraftforge")
include("neoforge")
include("testmod-common")
include("testmod-fabric")
include("testmod-forge")
include("testmod-neoforge")
rootProject.name = "architectury"

View File

@@ -8,7 +8,7 @@ loom {
mods {
forge {
sourceSet project(":forge").sourceSets.main
sourceSet project(":minecraftforge").sourceSets.main
}
}
@@ -32,7 +32,8 @@ configurations {
dependencies {
forge "net.minecraftforge:forge:${gradle.rootProject.architectury.minecraft}-${rootProject.forge_version}"
implementation project(path: ":forge", configuration: "namedElements")
implementation project(path: ":minecraftforge", configuration: "namedElements")
common(project(path: ":common", configuration: "namedElements")) { transitive false }
common(project(path: ":testmod-common", configuration: "namedElements")) { transitive false }
common(project(path: ":forge", configuration: "namedElements")) { transitive false }
}

View File

@@ -0,0 +1,44 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.0.0"
id "com.matthewprenger.cursegradle"
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
mods {
forge {
sourceSet project(":neoforge").sourceSets.main
}
}
}
architectury {
platformSetupLoomIde()
neoForge {
platformPackage = "forge"
remapForgeLike "net/minecraftforge/common/extensions/IForgeItem", "net/neoforged/neoforge/common/extensions/IItemExtension"
remapForgeLike "net/minecraftforge/client/event/TextureStitchEvent\$Post", "net/neoforged/neoforge/client/event/TextureAtlasStitchedEvent"
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid", "net/neoforged/neoforge/fluids/BaseFlowingFluid"
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid\$Properties", "net/neoforged/neoforge/fluids/BaseFlowingFluid\$Properties"
remapForgeLike "net/minecraftforge/common/ForgeHooks", "net/neoforged/neoforge/common/CommonHooks"
}
}
configurations {
common
forgeLike
compileClasspath.extendsFrom common, forgeLike
runtimeClasspath.extendsFrom common, forgeLike
developmentNeoForge.extendsFrom common
developmentForgeLike.extendsFrom forgeLike
}
dependencies {
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
implementation(project(path: ":neoforge", configuration: "namedElements")) { transitive false }
common(project(path: ":common", configuration: "namedElements")) { transitive false }
common(project(path: ":testmod-common", configuration: "namedElements")) { transitive false }
forgeLike(project(path: ":forge", configuration: "namedElements")) { transitive false }
}

View File

@@ -0,0 +1 @@
loom.platform=neoforge

View File

@@ -0,0 +1,30 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* 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; either
* version 3 of the License, or (at your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.architectury.test.forge;
import dev.architectury.test.TestMod;
import net.neoforged.fml.common.Mod;
@Mod(TestMod.MOD_ID)
public class TestModForge {
public TestModForge() {
TestMod.initialize();
}
}

View File

@@ -0,0 +1,14 @@
modLoader = "javafml"
loaderVersion = "[1,)"
issueTrackerURL = "https://github.com/shedaniel/architectury/issues"
license = "LGPL-3"
[[mods]]
modId = "architectury_test"
version = "${file.jarVersion}"
displayName = "Architectury Test"
authors = "shedaniel"
description = '''
A intermediary api aimed to ease developing multiplatform mods.
'''
license = "LGPL-3"

View File

@@ -0,0 +1,6 @@
{
"pack": {
"description": "Architectury Test",
"pack_format": 6
}
}