diff --git a/Fabric/build.gradle b/Fabric/build.gradle new file mode 100644 index 0000000..2fd0663 --- /dev/null +++ b/Fabric/build.gradle @@ -0,0 +1,137 @@ +plugins { + alias quilt.plugins.quilt.loom +} + +project.configurations.runtimeClasspath { + exclude(group: "loom_mappings_1_20_4_layered_hash_919249853_v2.net.fabricmc", module: "fabric-loader") +} + +dependencies { + minecraft libs.minecraft + mappings(loom.layered { + it.parchment("${libs.parchment.mappings.get()}@zip") + it.officialMojangMappings() + }) + + modImplementation fabric.fabric.loader + modImplementation (fabric.fabric.api) { + exclude group: "net.fabricmc", module: "fabric-loader" + } + + compileOnly project(":Common") + + testmodImplementation sourceSets.main.output + testmodCompileOnly project(path: ":Common", configuration: "testmod") + + modImplementation (libs.resourcefulconfig.fabric) { + transitive = false + } + + implementation libs.appdirs + include libs.appdirs + + modCompileOnly ("${libs.emi.fabric.get()}:api") { + transitive = false + } + modLocalRuntime (libs.emi.fabric) { + transitive = false + } + + modCompileOnly (fabric.modmenu) { + transitive = false + } + modLocalRuntime (fabric.modmenu) { + transitive = false + } +} + +loom { + mods { + "${mod_id}" { + // Tell Loom about each source set used by your mod here. This ensures that your mod's classes are properly transformed by Loader. + sourceSet("main") + } + + "${mod_id}_testmod" { + sourceSet("testmod") + } + } + if (project(":Common").file("src/main/resources/${mod_id}.accesswidener").exists()) { + accessWidenerPath.set(project(":Common").file("src/main/resources/${mod_id}.accesswidener")) + } + mixin { + defaultRefmapName.set("${mod_id}.refmap.json") + } + + runs { + client { + client() + setConfigName("Fabric Client") + ideConfigGenerated(true) + runDir("run") + + if (project.hasProperty('mc_uuid')) { + programArg("--uuid=${project.findProperty('mc_uuid')}") + } + + if (project.hasProperty('mc_username')) { + programArg("--username=${project.findProperty('mc_username')}") + } + + if (project.hasProperty('mc_java_agent_path')) { + vmArg("-javaagent:${project.findProperty('mc_java_agent_path')}") + } + } + + testmodClient { + client() + setConfigName("Fabric Testmod Client") + ideConfigGenerated(true) + runDir("run/testmod") + source(sourceSets.testmod) + + if (project.hasProperty('mc_uuid')) { + programArg("--uuid=${project.findProperty('mc_uuid')}") + } + + if (project.hasProperty('mc_username')) { + programArg("--username=${project.findProperty('mc_username')}") + } + + if (project.hasProperty('mc_java_agent_path')) { + vmArg("-javaagent:${project.findProperty('mc_java_agent_path')}") + } + } + + server { + server() + setConfigName("Fabric Server") + ideConfigGenerated(true) + runDir("run/server") + } + } +} + +tasks.withType(JavaCompile).configureEach { + source(project(":Common").sourceSets.main.allJava) +} + +tasks.named("compileTestmodJava", JavaCompile).configure { + source(project(":Common").sourceSets.testmod.allJava) +} + +tasks.named("javadoc", Javadoc).configure { + source(project(":Common").sourceSets.main.allJava) +} + +tasks.named("sourcesJar", Jar) { + from(project(":Common").sourceSets.main.allSource) +} + +processResources { + from project(":Common").sourceSets.main.resources +} + +processTestmodResources { + from project(":Common").sourceSets.testmod.resources +} diff --git a/Fabric/libs.versions.toml b/Fabric/libs.versions.toml new file mode 100644 index 0000000..35be72b --- /dev/null +++ b/Fabric/libs.versions.toml @@ -0,0 +1,17 @@ +[versions] +# The latest versions are available at https://fabricmc.net/develop + +fabric_loader = "0.15.11" +fabric_api = "0.97.0+1.20.4" + +modmenu = "9.2.0-beta.2" + +[libraries] +fabric_loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric_loader" } + +fabric_api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric_api" } + +modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } + +# If you have multiple similar dependencies, you can declare a dependency bundle and reference it on the build script with "libs.bundles.example". +#[bundles] diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/command/ClientRootCommand.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/command/ClientRootCommand.java new file mode 100644 index 0000000..920b2ec --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/command/ClientRootCommand.java @@ -0,0 +1,40 @@ +package dev.upcraft.sparkweave.fabric.client.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.context.CommandContext; +import dev.upcraft.sparkweave.fabric.client.consent.ConsentScreen; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.resources.ResourceLocation; + +import java.util.List; + +public class ClientRootCommand { + + public static void register(CommandDispatcher dispatcher) { + var root = ClientCommandManager.literal("sparkweave"); + DebugMonitorCommand.register(root); + + //TODO remove debug + root.then(ClientCommandManager.literal("test") + .executes(ClientRootCommand::openConsentScreen)); + + dispatcher.register(root); + } + + private static int openConsentScreen(CommandContext ctx) { + List permissions = List.of( + new ResourceLocation("sparkweave", "test1"), + new ResourceLocation("sparkweave", "test2"), + new ResourceLocation("sparkweave", "test3"), + new ResourceLocation("sparkweave", "test4"), + new ResourceLocation("sparkweave", "test5") + ); + System.out.println("opening screen"); + ctx.getSource().getClient().setScreen(new ConsentScreen(permissions, true)); + + return Command.SINGLE_SUCCESS; + } + +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/command/DebugMonitorCommand.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/command/DebugMonitorCommand.java new file mode 100644 index 0000000..b2d23e9 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/command/DebugMonitorCommand.java @@ -0,0 +1,14 @@ +package dev.upcraft.sparkweave.fabric.client.command; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; + +public class DebugMonitorCommand { + + public static void register(LiteralArgumentBuilder root) { + root.then(ClientCommandManager.literal("debug").then(ClientCommandManager.literal("monitor").executes(context -> { + return 0; + }))); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/consent/ConsentScreen.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/consent/ConsentScreen.java new file mode 100644 index 0000000..0c61d5c --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/client/consent/ConsentScreen.java @@ -0,0 +1,40 @@ +package dev.upcraft.sparkweave.fabric.client.consent; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.List; + +public class ConsentScreen extends Screen { + + private static final Component TITLE = Component.translatable("screen.sparkweave.consent.title"); + private final List permissions; + private final boolean explicit; + + public ConsentScreen(List permissions, boolean explicit) { + super(TITLE); + this.permissions = permissions; + this.explicit = explicit; + System.out.println("screen constructor"); + } + + @Override + protected void init() { + super.init(); + System.out.println("initializing screen"); + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float delta) { + this.renderBackground(guiGraphics, mouseX, mouseY, delta); + super.render(guiGraphics, mouseX, mouseY, delta); + System.out.println("rendering screen"); + } + + @Override + public boolean shouldCloseOnEsc() { + return false; + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/Client.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/Client.java new file mode 100644 index 0000000..3140e70 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/Client.java @@ -0,0 +1,70 @@ +package dev.upcraft.sparkweave.fabric.entrypoint; + +import dev.upcraft.sparkweave.SparkweaveMod; +import dev.upcraft.sparkweave.api.annotation.CalledByReflection; +import dev.upcraft.sparkweave.api.client.event.*; +import dev.upcraft.sparkweave.api.client.render.DebugRenderer; +import dev.upcraft.sparkweave.api.entrypoint.ClientEntryPoint; +import dev.upcraft.sparkweave.client.event.RegisterItemPropertiesEventImpl; +import dev.upcraft.sparkweave.entrypoint.EntrypointHelper; +import dev.upcraft.sparkweave.fabric.client.command.ClientRootCommand; +import dev.upcraft.sparkweave.fabric.impl.registry.RegisterBlockEntityRenderersEventImpl; +import dev.upcraft.sparkweave.fabric.impl.registry.RegisterEntityRenderersEventImpl; +import dev.upcraft.sparkweave.fabric.impl.registry.RegisterMenuScreensEventImpl; +import dev.upcraft.sparkweave.fabric.impl.registry.RegisterParticleFactoriesEventImpl; +import dev.upcraft.sparkweave.validation.TranslationChecker; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.ResourceReloadListenerKeys; +import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.resources.ResourceManager; + +import java.util.Collection; +import java.util.Set; + +@Environment(EnvType.CLIENT) +@CalledByReflection +public class Client implements ClientModInitializer { + @Override + public void onInitializeClient() { + WorldRenderEvents.AFTER_ENTITIES.register((context) -> DebugRenderer.render(context.matrixStack(), context.consumers(), context.camera())); + ClientCommandRegistrationCallback.EVENT.register((dispatcher, buildContext) -> { + if(Minecraft.getInstance().hasSingleplayerServer()) { + ClientRootCommand.register(dispatcher); + } + }); + + ResourceManagerHelper.get(PackType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { + private final ResourceLocation ID = new ResourceLocation(SparkweaveMod.MODID, "translation_checker"); + @Override + public ResourceLocation getFabricId() { + return ID; + } + + @Override + public void onResourceManagerReload(ResourceManager resourceManager) { + TranslationChecker.validate(); + } + + @Override + public Collection getFabricDependencies() { + return Set.of(ResourceReloadListenerKeys.LANGUAGES); + } + }); + + EntrypointHelper.fireEntrypoints(ClientEntryPoint.class, ClientEntryPoint::onInitializeClient); + + RegisterBlockEntityRenderersEvent.EVENT.invoker().registerBlockEntityRenderers(new RegisterBlockEntityRenderersEventImpl()); + RegisterEntityRenderersEvent.EVENT.invoker().registerEntityRenderers(new RegisterEntityRenderersEventImpl()); + RegisterItemPropertiesEvent.EVENT.invoker().registerItemProperties(new RegisterItemPropertiesEventImpl()); + RegisterMenuScreensEvent.EVENT.invoker().registerMenuScreens(new RegisterMenuScreensEventImpl()); + RegisterParticleFactoriesEvent.EVENT.invoker().registerParticleFactories(new RegisterParticleFactoriesEventImpl()); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/DedicatedServer.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/DedicatedServer.java new file mode 100644 index 0000000..b0bc8c9 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/DedicatedServer.java @@ -0,0 +1,15 @@ +package dev.upcraft.sparkweave.fabric.entrypoint; + +import dev.upcraft.sparkweave.api.annotation.CalledByReflection; +import dev.upcraft.sparkweave.api.entrypoint.DedicatedServerEntryPoint; +import dev.upcraft.sparkweave.entrypoint.EntrypointHelper; +import net.fabricmc.api.DedicatedServerModInitializer; + +@CalledByReflection +public class DedicatedServer implements DedicatedServerModInitializer { + + @Override + public void onInitializeServer() { + EntrypointHelper.fireEntrypoints(DedicatedServerEntryPoint.class, DedicatedServerEntryPoint::onInitializeServer); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/Main.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/Main.java new file mode 100644 index 0000000..0d1dfb1 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/entrypoint/Main.java @@ -0,0 +1,43 @@ +package dev.upcraft.sparkweave.fabric.entrypoint; + +import dev.upcraft.sparkweave.api.annotation.CalledByReflection; +import dev.upcraft.sparkweave.api.entrypoint.MainEntryPoint; +import dev.upcraft.sparkweave.api.event.CommandEvents; +import dev.upcraft.sparkweave.api.platform.services.RegistryService; +import dev.upcraft.sparkweave.api.registry.block.BlockItemProvider; +import dev.upcraft.sparkweave.entrypoint.EntrypointHelper; +import dev.upcraft.sparkweave.logging.SparkweaveLogging; +import dev.upcraft.sparkweave.registry.SparkweaveCommandArgumentTypes; +import dev.upcraft.sparkweave.scheduler.ScheduledTaskQueue; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; + +@CalledByReflection +public class Main implements ModInitializer { + + @Override + public void onInitialize() { + RegistryService.get().visitRegistry(BuiltInRegistries.BLOCK, (id, block) -> { + if (block instanceof BlockItemProvider provider) { + Registry.register(BuiltInRegistries.ITEM, id, provider.createItem()); + } + }); + + ServerLifecycleEvents.SERVER_STARTING.register(ScheduledTaskQueue::onServerStarting); + ServerLifecycleEvents.SERVER_STOPPED.register(server -> ScheduledTaskQueue.onServerStopped()); + ServerTickEvents.START_SERVER_TICK.register(server -> ScheduledTaskQueue.onServerTick()); + + CommandRegistrationCallback.EVENT.register((dispatcher, buildContext, environment) -> CommandEvents.REGISTER.invoker().registerCommands(dispatcher, buildContext, environment)); + + var service = RegistryService.get(); + SparkweaveCommandArgumentTypes.ARGUMENT_TYPES.accept(service); + + EntrypointHelper.fireEntrypoints(MainEntryPoint.class, MainEntryPoint::onInitialize); + + SparkweaveLogging.getLogger().debug("System initialized!"); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/mod/FabricModContainer.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/mod/FabricModContainer.java new file mode 100644 index 0000000..561f27f --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/mod/FabricModContainer.java @@ -0,0 +1,30 @@ +package dev.upcraft.sparkweave.fabric.impl.mod; + +import dev.upcraft.sparkweave.api.platform.ModContainer; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +public record FabricModContainer(net.fabricmc.loader.api.ModContainer delegate, FabricModMetadata metadata) implements ModContainer { + + public static FabricModContainer of(net.fabricmc.loader.api.ModContainer delegate) { + return new FabricModContainer(delegate, new FabricModMetadata(delegate)); + } + + @Deprecated(forRemoval = true) + @Override + public Path rootPath() { + return delegate().getRootPath(); + } + + @Override + public List rootPaths() { + return delegate().getRootPaths(); + } + + @Override + public Optional findPath(String file) { + return delegate().findPath(file); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/mod/FabricModMetadata.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/mod/FabricModMetadata.java new file mode 100644 index 0000000..683629c --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/mod/FabricModMetadata.java @@ -0,0 +1,44 @@ +package dev.upcraft.sparkweave.fabric.impl.mod; + +import dev.upcraft.sparkweave.api.platform.ModMetadata; +import net.fabricmc.loader.api.ModContainer; +import org.jetbrains.annotations.Nullable; + +public class FabricModMetadata implements ModMetadata { + + private final net.fabricmc.loader.api.metadata.ModMetadata delegate; + + public FabricModMetadata(ModContainer modContainer) { + delegate = modContainer.getMetadata(); + } + + @Override + public String id() { + return delegate.getId(); + } + + @Override + public @Nullable String issuesUrl() { + return delegate.getContact().get("issues").orElse(null); + } + + @Override + public @Nullable String sourcesUrl() { + return delegate.getContact().get("sources").orElse(null); + } + + @Override + public @Nullable String getHomepageUrl() { + return delegate.getContact().get("homepage").orElse(null); + } + + @Override + public String displayName() { + return delegate.getName(); + } + + @Override + public String version() { + return delegate.getVersion().getFriendlyString(); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/FabricRegistryHandler.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/FabricRegistryHandler.java new file mode 100644 index 0000000..5773db9 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/FabricRegistryHandler.java @@ -0,0 +1,82 @@ +package dev.upcraft.sparkweave.fabric.impl.registry; + +import com.google.common.base.Suppliers; +import dev.upcraft.sparkweave.api.registry.RegistryHandler; +import dev.upcraft.sparkweave.api.registry.RegistryHelper; +import dev.upcraft.sparkweave.api.registry.RegistrySupplier; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; +import net.fabricmc.fabric.api.event.registry.RegistryAttribute; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class FabricRegistryHandler implements RegistryHandler { + + private final ResourceKey> registryKey; + private final String namespace; + private final Supplier> registry; + + private final Map> values = new Object2ObjectOpenHashMap<>(); + private final List> orderedEntries = new LinkedList<>(); + + private FabricRegistryHandler(ResourceKey> registryKey, String namespace) { + this.registryKey = registryKey; + this.namespace = namespace; + this.registry = Suppliers.memoize(() -> RegistryHelper.getBuiltinRegistry(registryKey)); + } + + public static FabricRegistryHandler create(ResourceKey> registryKey, String modid) { + return new FabricRegistryHandler<>(registryKey, modid); + } + + @Override + public QuiltRegistrySupplier register(String name, Supplier factory) { + var id = new ResourceLocation(namespace, name); + var supplier = new QuiltRegistrySupplier<>(ResourceKey.create(registryKey, id), factory); + + // immediately register entry + supplier.register(registry.get()); + + values.put(id, supplier); + orderedEntries.add(supplier); + return supplier; + } + + @Override + public Map> values() { + return Collections.unmodifiableMap(values); + } + + @Override + public List> getEntriesOrdered() { + return Collections.unmodifiableList(orderedEntries); + } + + @Override + public Stream> stream() { + return orderedEntries.stream(); + } + + @Override + public ResourceKey> registry() { + return registryKey; + } + + @Override + public Registry createNewRegistry(boolean sync, @Nullable ResourceLocation defaultEntry) { + var builder = defaultEntry != null ? FabricRegistryBuilder.createDefaulted(this.registryKey, defaultEntry) : FabricRegistryBuilder.createSimple(this.registryKey); + if(sync) { + builder.attribute(RegistryAttribute.SYNCED); + } + return builder.buildAndRegister(); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/QuiltRegistrySupplier.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/QuiltRegistrySupplier.java new file mode 100644 index 0000000..f27d07e --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/QuiltRegistrySupplier.java @@ -0,0 +1,85 @@ +package dev.upcraft.sparkweave.fabric.impl.registry; + +import dev.upcraft.sparkweave.api.registry.RegistryHelper; +import dev.upcraft.sparkweave.api.registry.RegistrySupplier; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Supplier; + +public class QuiltRegistrySupplier implements RegistrySupplier { + + private final ResourceKey id; + private final Supplier factory; + @Nullable + private T value; + private Registry registry; + + public QuiltRegistrySupplier(ResourceKey id, Supplier factory) { + this.id = id; + this.factory = factory; + } + + public void register(Registry registry) { + this.registry = registry; + this.value = Registry.register(registry, this.getId(), Objects.requireNonNull(this.factory.get(), "factory returned null for " + this.id)); + } + + @SuppressWarnings("unchecked") + @Override + public T get() { + if (value == null) { + Registry reg = (Registry) getRegistry(); + value = (T) Objects.requireNonNull(reg.get(this.id.location()), "Registry supplier called too early: " + this.getId()); + } + return value; + } + + @Override + public boolean is(T other) { + return this.get() == other; + } + + @SuppressWarnings("unchecked") + @Override + public boolean matches(TagKey tag) { + Registry reg = (Registry) getRegistry(); + return reg.getHolderOrThrow((ResourceKey) getRegistryKey()).is((TagKey) tag); + } + + @Override + public ResourceLocation getId() { + return this.id.location(); + } + + @Override + public ResourceKey getRegistryKey() { + return this.id; + } + + @Override + public Registry getRegistry() { + if(registry == null) { + registry = RegistryHelper.getBuiltinRegistry(ResourceKey.createRegistryKey(id.registry())); + } + return registry; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof QuiltRegistrySupplier other) { + return this.getRegistryKey() == other.getRegistryKey(); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.id.registry(), this.id.location()); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterBlockEntityRenderersEventImpl.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterBlockEntityRenderersEventImpl.java new file mode 100644 index 0000000..00f75a6 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterBlockEntityRenderersEventImpl.java @@ -0,0 +1,17 @@ +package dev.upcraft.sparkweave.fabric.impl.registry; + +import dev.upcraft.sparkweave.api.client.event.RegisterBlockEntityRenderersEvent; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; + +import java.util.function.Supplier; + +public class RegisterBlockEntityRenderersEventImpl implements RegisterBlockEntityRenderersEvent { + + @Override + public void registerRenderer(Supplier> blockEntityType, BlockEntityRendererProvider blockEntityRendererProvider) { + BlockEntityRenderers.register(blockEntityType.get(), blockEntityRendererProvider); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterEntityRenderersEventImpl.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterEntityRenderersEventImpl.java new file mode 100644 index 0000000..bd5af9a --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterEntityRenderersEventImpl.java @@ -0,0 +1,17 @@ +package dev.upcraft.sparkweave.fabric.impl.registry; + +import dev.upcraft.sparkweave.api.client.event.RegisterEntityRenderersEvent; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; + +import java.util.function.Supplier; + +public class RegisterEntityRenderersEventImpl implements RegisterEntityRenderersEvent { + + @Override + public void registerRenderer(Supplier> entityType, EntityRendererProvider entityRendererProvider) { + EntityRendererRegistry.register(entityType.get(), entityRendererProvider); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterMenuScreensEventImpl.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterMenuScreensEventImpl.java new file mode 100644 index 0000000..0cf856c --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterMenuScreensEventImpl.java @@ -0,0 +1,18 @@ +package dev.upcraft.sparkweave.fabric.impl.registry; + +import dev.upcraft.sparkweave.api.client.event.RegisterMenuScreensEvent; +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.MenuAccess; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; + +import java.util.function.Supplier; + +public class RegisterMenuScreensEventImpl implements RegisterMenuScreensEvent { + + @Override + public > void register(Supplier> menuType, ScreenConstructor screenFactory) { + MenuScreens.register(menuType.get(), screenFactory); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterParticleFactoriesEventImpl.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterParticleFactoriesEventImpl.java new file mode 100644 index 0000000..e64ce58 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/impl/registry/RegisterParticleFactoriesEventImpl.java @@ -0,0 +1,22 @@ +package dev.upcraft.sparkweave.fabric.impl.registry; + +import dev.upcraft.sparkweave.api.client.event.RegisterParticleFactoriesEvent; +import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; + +import java.util.function.Supplier; + +public class RegisterParticleFactoriesEventImpl implements RegisterParticleFactoriesEvent { + + @Override + public > void registerSpecial(Supplier type, ParticleProvider provider) { + ParticleFactoryRegistry.getInstance().register(type.get(), provider); + } + + @Override + public > void registerSpriteSet(Supplier type, SpriteParticleRegistration registration) { + ParticleFactoryRegistry.getInstance().register(type.get(), registration::create); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/mixin/impl/ArgumentTypeInfosAccessor.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/mixin/impl/ArgumentTypeInfosAccessor.java new file mode 100644 index 0000000..19ee716 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/mixin/impl/ArgumentTypeInfosAccessor.java @@ -0,0 +1,17 @@ +package dev.upcraft.sparkweave.fabric.mixin.impl; + +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(ArgumentTypeInfos.class) +public interface ArgumentTypeInfosAccessor { + + @Accessor("BY_CLASS") + static Map, ArgumentTypeInfo> sparkweave$getByClass() { + throw new UnsupportedOperationException("Mixin not transformed"); + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/package-info.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/package-info.java new file mode 100644 index 0000000..b8f3ae6 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/package-info.java @@ -0,0 +1,5 @@ +@Mod.Context(SparkweaveMod.MODID) +package dev.upcraft.sparkweave.fabric; + +import dev.upcraft.sparkweave.SparkweaveMod; +import dev.upcraft.sparkweave.api.annotation.Mod; diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricHelperService.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricHelperService.java new file mode 100644 index 0000000..ba7fa45 --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricHelperService.java @@ -0,0 +1,28 @@ +package dev.upcraft.sparkweave.fabric.service; + +import com.mojang.brigadier.arguments.ArgumentType; +import dev.upcraft.sparkweave.api.annotation.CalledByReflection; +import dev.upcraft.sparkweave.api.platform.services.SparkweaveHelperService; +import dev.upcraft.sparkweave.fabric.mixin.impl.ArgumentTypeInfosAccessor; +import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.world.item.CreativeModeTab; + +public class FabricHelperService implements SparkweaveHelperService { + + @CalledByReflection + public FabricHelperService() { + // need an explicit default constructor for the service loader to work + } + + @Override + public CreativeModeTab.Builder newCreativeTabBuilder() { + return FabricItemGroup.builder(); + } + + @Override + public synchronized , T extends ArgumentTypeInfo.Template> ArgumentTypeInfo create(Class clazz, ArgumentTypeInfo info) { + ArgumentTypeInfosAccessor.sparkweave$getByClass().put(clazz, info); + return info; + } +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricPlatformService.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricPlatformService.java new file mode 100644 index 0000000..bdb84ae --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricPlatformService.java @@ -0,0 +1,112 @@ +package dev.upcraft.sparkweave.fabric.service; + +import com.google.common.base.Suppliers; +import dev.upcraft.sparkweave.api.annotation.CalledByReflection; +import dev.upcraft.sparkweave.api.platform.ModContainer; +import dev.upcraft.sparkweave.api.platform.RuntimeEnvironmentType; +import dev.upcraft.sparkweave.api.platform.services.PlatformService; +import dev.upcraft.sparkweave.fabric.impl.mod.FabricModContainer; +import dev.upcraft.sparkweave.platform.BasePlatformService; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.impl.FabricLoaderImpl; +import org.spongepowered.asm.util.JavaVersion; +import oshi.SystemInfo; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class FabricPlatformService extends BasePlatformService implements PlatformService { + + private static final String QUILT_LOADER_MODID = "quilt_loader"; + + private final Map> MOD_CONTAINERS = new Object2ObjectOpenHashMap<>(); + private final RuntimeEnvironmentType environmentType = switch (FabricLoader.getInstance().getEnvironmentType()) { + case CLIENT -> RuntimeEnvironmentType.CLIENT; + case SERVER -> RuntimeEnvironmentType.SERVER; + }; + private final Supplier userAgent = Suppliers.memoize(() -> { + var info = new SystemInfo(); + var os = info.getOperatingSystem(); + + var platformName = getPlatformName(); + var platformVersion = getModContainer(QUILT_LOADER_MODID).orElseThrow(() -> new IllegalStateException("Unable to find quilt loader!")).metadata().version(); + + var mcVersion = FabricLoaderImpl.INSTANCE.getGameProvider().getRawGameVersion(); + + var jvmVendor = System.getProperty("java.vm.vendor"); + var jvmVersion = Runtime.version().toString(); + + var osName = os.getFamily(); + var osVersion = os.getVersionInfo().getVersion(); + + var bitness = "x" + os.getBitness(); + if (os.getBitness() == 32) { + bitness = "x86"; + } + + return String.format("%s/%s Minecraft/%s Java/%.1f (%s/%s) (%s %s; %s)", platformName, platformVersion, mcVersion, JavaVersion.current(), jvmVendor, jvmVersion, osName, osVersion, bitness); + }); + + @CalledByReflection + public FabricPlatformService() { + // need an explicit default constructor for the service loader to work + super(); + } + + @Override + public boolean isModLoaded(String modid) { + return FabricLoader.getInstance().isModLoaded(modid); + } + + @Override + public boolean isDevelopmentEnvironment() { + return FabricLoader.getInstance().isDevelopmentEnvironment(); + } + + @Override + public Path getGameDir() { + return FabricLoader.getInstance().getGameDir(); + } + + @Override + public Path getConfigDir() { + return FabricLoader.getInstance().getConfigDir(); + } + + @Override + public Optional getModContainer(String modid) { + return MOD_CONTAINERS.computeIfAbsent(modid, key -> FabricLoader.getInstance().getModContainer(key).map(FabricModContainer::of)); + } + + @Override + public List getActiveMods() { + // can't use Stream#toList() because java compiler is dumb :( + return FabricLoader.getInstance().getAllMods().stream().map(FabricModContainer::of).collect(Collectors.toList()); + } + + @Override + public RuntimeEnvironmentType getEnvironmentType() { + return environmentType; + } + + @Override + public List getLaunchArguments(boolean hideSensitive) { + return List.of(FabricLoader.getInstance().getLaunchArguments(hideSensitive)); + } + + @Override + public String getUserAgent() { + return userAgent.get(); + } + + @Override + public String getPlatformName() { + return "Fabric"; + } + +} diff --git a/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricRegistryService.java b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricRegistryService.java new file mode 100644 index 0000000..ad066de --- /dev/null +++ b/Fabric/src/main/java/dev/upcraft/sparkweave/fabric/service/FabricRegistryService.java @@ -0,0 +1,39 @@ +package dev.upcraft.sparkweave.fabric.service; + +import dev.upcraft.sparkweave.api.annotation.CalledByReflection; +import dev.upcraft.sparkweave.api.platform.services.RegistryService; +import dev.upcraft.sparkweave.api.registry.RegistryHandler; +import dev.upcraft.sparkweave.api.registry.RegistryVisitor; +import dev.upcraft.sparkweave.fabric.impl.registry.FabricRegistryHandler; +import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; + +import java.util.Map; +import java.util.stream.Collectors; + +public class FabricRegistryService implements RegistryService { + + @CalledByReflection + public FabricRegistryService() { + // need an explicit default constructor for the service loader to work + } + + @Override + public RegistryHandler createRegistryHandler(ResourceKey> registryKey, String namespace) { + return FabricRegistryHandler.create(registryKey, namespace); + } + + @Override + public void visitRegistry(Registry registry, RegistryVisitor callback) { + RegistryEntryAddedCallback.event(registry).register((rawId, id, object) -> callback.accept(id, object)); + // need to create a copy because the callback itself may add entries to the registry while we are iterating it + var copy = registry.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().location(), Map.Entry::getValue)); + copy.forEach(callback); + } + + @Override + public void handleRegister(RegistryHandler handler) { + // NO-OP because registration happens anyway, we just need to load the class + } +} diff --git a/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.PlatformService b/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.PlatformService new file mode 100644 index 0000000..368e9bf --- /dev/null +++ b/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.PlatformService @@ -0,0 +1 @@ +dev.upcraft.sparkweave.fabric.service.FabricPlatformService diff --git a/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.RegistryService b/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.RegistryService new file mode 100644 index 0000000..38175f5 --- /dev/null +++ b/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.RegistryService @@ -0,0 +1 @@ +dev.upcraft.sparkweave.fabric.service.FabricRegistryService diff --git a/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.SparkweaveHelperService b/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.SparkweaveHelperService new file mode 100644 index 0000000..841c59a --- /dev/null +++ b/Fabric/src/main/resources/META-INF/services/dev.upcraft.sparkweave.api.platform.services.SparkweaveHelperService @@ -0,0 +1 @@ +dev.upcraft.sparkweave.fabric.service.FabricHelperService diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..76c2a08 --- /dev/null +++ b/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,50 @@ +{ + "schemaVersion": 1, + "id": "${mod_id}", + "version": "${version}", + "name": "${mod_display_name}", + "description": "${mod_description}", + "authors": [ + "Up" + ], + "contact": { + "homepage": "${homepage_url}", + "sources": "${sources_url}", + "issues": "${issues_url}" + }, + "license": "${license_url}", + "icon": "icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "dev.upcraft.sparkweave.fabric.entrypoint.Main" + ], + "client": [ + "dev.upcraft.sparkweave.fabric.entrypoint.Client" + ], + "server": [ + "dev.upcraft.sparkweave.fabric.entrypoint.DedicatedServer" + ] + }, + "mixins": [ + "${mod_id}.mixins.json", + "${mod_id}.fabric.mixins.json" + ], + "depends": { + "fabricloader": ">=${fabric_loader_version}", + "minecraft": "=${minecraft_version}", + "java": ">=${java_version}", + "fabric-api": "*", + "resourcefulconfig": "*" + }, + "custom": { + "mc-publish": { + "curseforge": "911456", + "modrinth": "nf68xfAw", + "dependencies": [ + "fabric-api(required)#{curseforge:306612}{modrinth:P7dR8mSH}", + "resourcefulconfig(required)#{curseforge:714059}{modrinth:M1953qlQ}" + ] + } + } +} diff --git a/Fabric/src/main/resources/sparkweave.fabric.mixins.json b/Fabric/src/main/resources/sparkweave.fabric.mixins.json new file mode 100644 index 0000000..02fa807 --- /dev/null +++ b/Fabric/src/main/resources/sparkweave.fabric.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "dev.upcraft.sparkweave.fabric.mixin", + "plugin": "dev.upcraft.sparkweave.SparkweaveMixinConfigPlugin", + "refmap": "${mod_id}.refmap.json", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "impl.ArgumentTypeInfosAccessor" + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/Quilt/build.gradle b/Quilt/build.gradle index ede859f..eeb5819 100644 --- a/Quilt/build.gradle +++ b/Quilt/build.gradle @@ -34,8 +34,8 @@ dependencies { modCompileOnly "${libs.emi.fabric.get()}:api" modLocalRuntime libs.emi.fabric - modCompileOnly quilt.modmenu - modLocalRuntime quilt.modmenu + modCompileOnly fabric.modmenu + modLocalRuntime fabric.modmenu } loom { diff --git a/Quilt/libs.versions.toml b/Quilt/libs.versions.toml index ac2948e..cd1fb5b 100644 --- a/Quilt/libs.versions.toml +++ b/Quilt/libs.versions.toml @@ -5,16 +5,12 @@ quilt_loom = "1.6.+" quilt_loader = "0.26.0" quilted_fabric_api = "9.0.0-alpha.8+0.97.0-1.20.4" -modmenu = "9.2.0-beta.2" - [libraries] quilt_loader = { module = "org.quiltmc:quilt-loader", version.ref = "quilt_loader" } quilted_fabric_api = { module = "org.quiltmc.quilted-fabric-api:quilted-fabric-api", version.ref = "quilted_fabric_api" } quilted_fabric_api_deprecated = { module = "org.quiltmc.quilted-fabric-api:quilted-fabric-api-deprecated", version.ref = "quilted_fabric_api" } -modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } - # If you have multiple similar dependencies, you can declare a dependency bundle and reference it on the build script with "libs.bundles.example". [bundles] quilted_fabric_api = ["quilted_fabric_api", "quilted_fabric_api_deprecated"] diff --git a/build.gradle b/build.gradle index 9ed9f6c..72bc0ef 100644 --- a/build.gradle +++ b/build.gradle @@ -168,6 +168,8 @@ subprojects { "neoforge_version" : neoforge.versions.neoforge.get(), "quilt_loader_version": quilt.versions.quilt.loader.get(), + + "fabric_loader_version": fabric.versions.fabric.loader.get(), ] filesMatching(['pack.mcmeta', '*.mod.json', 'META-INF/mods.toml', '*.mixins.json']) { diff --git a/settings.gradle b/settings.gradle index a8792ad..0b1d9c2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,15 +30,18 @@ dependencyResolutionManagement { libs { from(files("./Common/libs.versions.toml")) } - quilt { - from(files("./Quilt/libs.versions.toml")) + fabric { + from(files("./Fabric/libs.versions.toml")) } neoforge { from(files("./NeoForge/libs.versions.toml")) } + quilt { + from(files("./Quilt/libs.versions.toml")) + } } } rootProject.name = 'Sparkweave' -include 'Common', 'NeoForge', 'Quilt' +include 'Common', 'Fabric', 'NeoForge', 'Quilt'