Code Monkey home page Code Monkey logo

flintmc's Introduction

Flint

A modern Minecraft modding framework helping You to create maintainable Mods easily

License MC Version MC Version Discord

Flint is a Minecraft modding framework created by LabyMedia GmbH. It is developed with a focus on responsibility-driven design, interface segregation and dependency injection. This allows for easy encapsulation of version-specific code. Flint makes heavy use of bytecode manipulation - Minecraft isn't patched directly - resulting in better compatibility between Mods and a simpler update process.

Warning: Flint is still in development and not stable yet. We are currently working with Minecraft 1.15.2 and 1.16.5, but will soon start to implement other versions (including 1.8.9).

Contributions are welcome, just make sure to take a look at our contribution guidelines first. We would also love to chat with you about Flint on our Discord Server. We always appreciate feedback.

Table of Contents

  1. Motivation
  2. Examples
    2.1. Listen on Events
    2.2. Use Javassist to transform a Class
    2.3. Access private fields
    2.4. Hook into Methods
  3. Architecture
    3.1. Dependency Injection
    3.2. Binding Implementations
    3.3. Separating version-specific Code
  4. Building Flint
  5. Creating a simple Mod
    5.1. Project Setup
    5.2. Create an Installer
  6. Roadmap
  7. Further Resources

Motivation

Creating Minecraft modifications is often not as easy as it could be due to several challenges.

  • Version Independence is difficult to achieve.
  • Modding APIs are not stable and do not provide enough features to implement the mod.
  • Patching Minecraft directly leads to incompatibilities with other mods and is often not EULA compliant.
  • Bytecode manipulation is difficult and results in code strongly coupled with the Minecraft version it was developed against, meaning it is tedious to port to other Minecraft versions.
  • Distributing a mod with all its dependencies quickly results in a non-trivial installation process and tends to brick when the wrong version of the used modding framework is installed or dependency conflicts appear.

We learned from older projects and tried to approach these issues to make your life as a mod creator as easy as possible.

  • Flint helps you to encapsulate version-specific code properly and is able to bundle multiple implementations for different Minecraft versions into a single JAR file. Flint will then automatically load the correct implementation at runtime.
  • Flint does not patch Minecraft directly and doesn't provide a way for you to do that. Instead, it is completely build using byte code manipulation at runtime.
  • Bytecode manipulation with flint is easy. The annotation based class transformers help you to use your favourite manipulation library while eradicating the need to worry about obfuscation. At the same time, Flint's architecture encourages you to properly encapsulate those class transformations and reimplement them for each supported version.
  • Flint's installer helps you to automatically resolve and install dependencies. Flint also makes sure your mod and all its dependencies are actually compatible with the given environment. As third-party maven dependencies aren't shaded into your JAR file, issues with libraries loaded more than once won't appear.

Examples

Many things can already be accomplished using Flint's version independent Minecraft API. There are however many tools provided to modify Minecraft even further. A few examples are listed below.

Listen on Events provided by the Framework

For event listener, Flint uses the @Subscribe annotation. The event type will be inferred from the method's parameter type.

@Subscribe
public void onTick(TickEvent tickEvent) {
  if (tickEvent.getType() == TickEvent.Type.GENERAL)
    System.out.println("Tick!");
}

Use Javassist to transform a Minecraft class

Flint provides several ways for bytecode manipulation, including the popular Javassist library as well as objectweb ASM. Class transformations can easily be performed by annotating an appropriate Method with @ClassTransform.

@ClassTransform("net.minecraft.client.Minecraft")
public void transformMinecraft(ClassTransformContext ctx) throws CannotCompileException {
  CtClass mcClass = ctx.getCtClass();
  mcClass.addMethod(CtMethod.make(
      "public void helloWorld() { System.out.println(\"Hello World!\"); }", mcClass));
}

Access private Fields

With the help of the @Shadow annotation, interfaces can be used to easily access private fields or methods in Minecraft's classes.

@Shadow("net.minecraft.client.Minecraft")
public interface MinecraftAccessor {
  
  @FieldGetter("gameDir")
  File getGameDir();
}

Instances of that class can then be casted to the interface type to access fields and methods:

File gameDir = ((MinecraftAccessor) Minecraft.getInstance()).getGameDir();

Hook into arbitrary Methods

Should the included events not suffice, a Mod can hook into arbitrary Minecraft methods using the @Hook annotation.

@Hook(
    className = "net.minecraft.client.Minecraft",
    methodName = "displayInGameMenu",
    parameters = {@Type(reference = boolean.class)},
    executionTime = Hook.ExecutionTime.BEFORE)
public void beforeInGameMenu(@Named("args") Object[] args) {
  System.out.println("Opening the in-game Menu...");
}

Architecture

Flint is build using a responsibility driven approach and dependency injection. For the latter, we currently use Google's Guice (the assisted factory extensions is not compatible though, however, a custom alternative is available).

Dependency Injection

To access the tools of the framework you won't call static getter methods but instead use constructor injection to retrieve the instance you need.

@Singleton
public class ChatHandler {
  
  private final TaskExecutor executor;  

  @Inject
  private ChatHandler(TaskExecutor executor) {
    this.executor = executor;
  }

  @Subscribe
  public void onChat(ChatSendEvent event) {
    if (event.getMessage().equals("Remind me!")) {
      this.executor.scheduleSync(60 * 20, () -> {
        System.out.println("Reminder!");
      });
    }
  }
}

There is no need to manually register the event listener. An instance of the class will be constructed automatically using Guice, an appropriate instance of the TaskExecutor interface will be injected. For further explanations, see the very comprehensive Guice documentation.

Binding Implementations

When creating own interfaces and implementations, there is no need to manually bind them together using a Guice module. Instead, the implementation should be marked with the @Implement annotation, which also allows for version-specific implementations.

Assume a simple interface whose implementation performs an action that requires different implementations for different Minecraft versions.

public interface StuffDoer {
  void doStuff();
}

Flint will then automatically bind the correct implementation for the running version.

// Class in 1.15.2 source set
@Implement(StuffDoer.class)
public class VersionedStuffDoer implements StuffDoer {

  @Override
  public void doStuff() {
    // Since the class is in the 1.15.2 source set, this
    // implementation will only be used for 1.15.2
  }
}

Abstracting your version-specific code like this results in a strong encapsulation and helps you to write big parts of your Mod version independently.

Separating version specific code

Each Flint module (as well as Mods build using our Gradle plugin) is split up into multiple source sets.

The main source set should contain interfaces and classes that make up the public API of the module. This API must always be completely version independent. Minecraft classes can't be accessed directly.

The internal source set should contain version-independent implementations of interfaces located in the main source set.

you can add a source set for every supported Minecraft version. These source sets should contain version-specific implementations. Minecraft classes can be accessed directly. The resulting symbolic references will be remapped automatically at runtime to assure compatibility with both obfuscated and de-obfuscated Minecraft installations. Class transformations and alike should also go into these source sets.

Building Flint

Building Flint is fairly easy. The project is set up using Gradle and a custom Gradle plugin that manages source sets and dependencies. The Gradle plugin also downloads, decompiles and de-obfuscates Minecraft when building for the first time.

After cloning the repository, just run the build task:

# Linux
$ ./gradlew build

# Windows
C:\...\FlintMC> gradlew.bat :build

There is also a task to start a de-obfuscated Minecraft directly out of your development environment.

# Linux
$ ./gradlew runClient1.16.5

# Windows
C:\...\FlintMC> gradlew.bat :runClient1.16.5

If you want to login into your Minecraft account, just set the following property in your global Gradle property file (~/.gradle/gradle.properties):

net.flintmc.enable-minecraft-login=true

When running the client, a login prompt will appear.

Creating a simple Mod

Getting started with Flint is not difficult. The project setup doesn't require deep Gradle knowledge and IDE support should be available without any extra steps.

Project Setup

To create a simple Mod, the first step is to set up a new Gradle project. We will use the following build.gradle.kts:

plugins {
    id("java-library")
    id("net.flintmc.flint-gradle")
}

repositories {
    mavenCentral()
}

group = "your.group"
version = "1.0.0"

flint {
    // Enter the newest Flint version here
    flintVersion = "2.0.23"
    minecraftVersions("1.15.2", "1.16.5")
    authors = arrayOf("Your Name")
    runs {
        overrideMainClass("net.flintmc.launcher.FlintLauncher")    
    }
}

dependencies {
    annotationProcessor(flintApi("annotation-processing-autoload"))
    internalAnnotationProcessor(flintApi("annotation-processing-autoload"))

    api(flintApi("framework-eventbus"))
    api(flintApi("framework-inject"))
    api(flintApi("mcapi"))
    api(flintApi("util-task-executor"))

    minecraft("1.15.2", "1.16.5") {
        annotationProcessor(flintApi("annotation-processing-autoload"))
    }
}

You will also need the following in your settings.gradle.kts, otherwise Gradle won't find our custom Gradle plugin.

pluginManagement {
    plugins {
        // make sure to use the newest version
        id("net.flintmc.flint-gradle") version "2.8.1"
    }
    buildscript {
        dependencies {
            classpath("net.flintmc", "flint-gradle", "2.8.1")         
        }
        repositories {
            maven {
                setUrl("https://dist.labymod.net/api/v1/maven/release")
                name = "Flint"   
            }
            mavenCentral()
        } 
    }
}

You can then set up the source sets. The Gradle plugin expects the following structure:

.
└── src
    ├── internal/java/your/group/internal
    ├── main/java/your/group
    └── v1_16_5/java/your/group/v1_16_5

If you now add the ChatHandler class from the Dependency Injection section, you will see that Reminder! is printed to the log output one minute after you wrote Remind me! into the chat.

Create an Installer

The Flint gradle plugin can automatically generate a simple JAR installer. It will contain all the files needed by your mod and will also download and install dependencies (including Flint itself) if not already installed.

To generate the installer, just run following task:

$ ./gradlew bundledInstallerJar

For more comprehensive examples and tutorials, go to our developer documentation. There you will also find tutorials on how to publish your Mod to our distribution service.

Roadmap

This project is not yet finished, there are many things we still want to do.

  • Improve dependency resolution in package loading.
  • Implement Minecraft 1.8.9 and other versions.
  • Make it possible to create server mods.
  • Write more documentation and create further resources on getting started.
  • Improve Minecraft API.
  • Move to yarn mappings.
  • Make the gradle plugin not depend on MCP.
  • Remove Guice and create an own injection framework for better performance and more control over class loading.
  • Improve startup performance.

Further Resources

  • If you would like to contribute to Flint (or any of the related repositories) make sure to take a look at our contribution guidelines. There you will find information on coding and formatting standards we require as well as the process of code review.
  • On flintmc.net, you will find a comprehensive documentation as well as many examples and tutorials.
  • JavaDocs should automatically be available in your IDE of choice if you're including Flint as a Gradle/maven dependency. However, a hosted version can be found here.
  • For more explanations regarding dependency injection, also refer to the Guice documentation.
  • If you have any questions or feedback, feel free to join our Discord Server and talk to us directly.
  • Should you notice any bugs or missing features, you can create an issue right here on GitHub.

NOT OFFICIAL MINECRAFT PRODUCT. NOT APPROVED BY OR ASSOCIATED WITH MOJANG.

flintmc's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

flintmc's Issues

MethodProxy for static methods

The MethodProxy annotation of the shadow module should be able to proxy static methods that are private, but this requires #15 because the name of a static and non-static cannot be the same.

Useless ConfigValueUpdateEvent

Is your feature request related to a problem? Please describe.
The ConfigValueUpdateEvent is currently only fired when updating a value via ConfigObjectReference#setValue, not via the generated setter in the config. This is pretty useless as mostly the setter is used instead of the method in ConfigObjectReference.

Describe the solution you'd like
The event should also be fired in the generated method. For already implemented configs the code to fire this event should be added to the already present setter.

Weird Inventory Click NullPointerException crash

Happened when @zortax was clicking around in a Furnace inventory

// I blame Janrupf.

Time: 12/10/20 9:36 PM
Description: mouseClicked event handler

java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at net.flintmc.framework.inject.internal.DefaultInjectedInvocationHelper.invokeMethod(DefaultInjectedInvocationHelper.java:78)
	at net.flintmc.transform.hook.internal.HookService.notify(HookService.java:76)
	at net.minecraft.inventory.container.Container.slotClick(Container.java)
	at net.minecraft.client.multiplayer.PlayerController.windowClick(PlayerController.java:342)
	at net.minecraft.client.gui.screen.inventory.ContainerScreen.handleMouseClick(ContainerScreen.java:491)
	at net.minecraft.client.gui.screen.inventory.AbstractFurnaceScreen.handleMouseClick(AbstractFurnaceScreen.java:91)
	at net.minecraft.client.gui.screen.inventory.ContainerScreen.mouseClicked(ContainerScreen.java:307)
	at net.minecraft.client.gui.screen.inventory.AbstractFurnaceScreen.mouseClicked(AbstractFurnaceScreen.java:86)
	at net.minecraft.client.MouseHelper.lambda$mouseButtonCallback$0(MouseHelper.java:78)
	at net.minecraft.client.gui.screen.Screen.wrapScreenError(Screen.java:426)
	at net.minecraft.client.MouseHelper.mouseButtonCallback(MouseHelper.java:77)
	at net.minecraft.client.MouseHelper.lambda$null$4(MouseHelper.java:153)
	at net.minecraft.util.concurrent.ThreadTaskExecutor.execute(ThreadTaskExecutor.java:84)
	at net.minecraft.client.MouseHelper.lambda$registerCallbacks$5(MouseHelper.java:152)
	at net.flintmc.render.gui.v1_15_2.VersionedInputInterceptor.lambda$interceptMouseCallbacks$3(VersionedInputInterceptor.java:87)
	at org.lwjgl.glfw.GLFWMouseButtonCallbackI.callback(GLFWMouseButtonCallbackI.java:36)
	at org.lwjgl.system.JNI.invokeV(Native Method)
	at org.lwjgl.glfw.GLFW.glfwPollEvents(GLFW.java:3101)
	at com.mojang.blaze3d.systems.RenderSystem.flipFrame(RenderSystem.java:83)
	at net.minecraft.client.MainWindow.flipFrame(MainWindow.java:292)
	at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:914)
	at net.minecraft.client.Minecraft.run(Minecraft.java:528)
	at net.minecraft.client.main.Main.main(Main.java:174)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at net.flintmc.launcher.LaunchController.run(LaunchController.java:183)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at net.flintmc.launcher.FlintLauncher.main(FlintLauncher.java:36)
	at net.flintmc.launcher.FlintLauncher.main(FlintLauncher.java:16)
Caused by: java.lang.NullPointerException
	at net.flintmc.mcapi.v1_15_2.items.inventory.event.InventoryClickEventInjector.slotClick(InventoryClickEventInjector.java:59)
	... 38 more

Hooked methods obfuscated

The name of the method with a Hook annotation will be obfuscated with the mappings if it is available and therefore we will get a NotFoundException because the method with the obfuscated name doesn't exist.

This is actually a problem in the annotation processor because in MethodIdentifier#getLocation the method will automatically be obfuscated which it shouldn't.

Move self transforms to compile time transformation

Whats going on?

A lot of the transformers transform classes in a way which could be done at compile time as well. This should reduce startup time and also time joining a server (and more cases, which are not known yet).

Proposed solution

Move transformation of classes to compile time when possible. This means for example add methods, changing visibility modifiers and generating factories at compile time.

Then they only need to be registered using the already existing mechanism.

Implement 1.8.9

  • Full testing of everything
  • Flint gradle plugin supports yarn / older mappings (thanks Christian)
  • mcapi package
  • render/gui package
  • render/shader package
  • render/vbo-rendering package
  • util/il8n package
  • util/mapping package
  • util/session-service package
  • bootstrap package

Invalid mouse callbacks interceptor in 1.16.4

Description
Mouse callbacks have an invalid intercept target causing a NPE and crashes.

To Reproduce the Bug

  1. Start the 1.16.4 client

Expected behavior
The callbacks should target the proper methods.

Configs as a value in a map/collection

Is your feature request related to a problem? Please describe.
There is no way to create dynamic configs with for example an enum as a key.

Describe the solution you'd like
When a config is used as a value for a collection or map, it should be serialized as it would be done if it was a simple string or an object that has a registered serializer.

Add license

  • Add LGPLv3 license file
  • Apply license header to all source files

Minecraft TextFormatting not properly converted to Flint ChatColor

Description
When translating the Minecraft TextFormatting to Flint ChatColors when parsing a PlayerTeam, it just uses the name to get the Flint ChatColor.

playerTeam.setColor(ChatColor.getByName(packet.getColor().getFriendlyName().toUpperCase()));

But the TextFormatting can be "ITALIC" for example too, which is not included in the Flint ChatColor. This leads to a NullPointerException and the PlayerTeam parsing fails.

To Reproduce the Bug
Join on GommeHD.net for example

Expected behavior
The colors should be translated correctly or there should be decent error handling

Log Output

java.lang.NullPointerException: null
	at net.flintmc.mcapi.v1_15_2.world.scoreboard.listener.VersionedPlayerTeamChangeListener.lambda$changeColor$3(VersionedPlayerTeamChangeListener.java:90) ~[VersionedPlayerTeamChangeListener.class:?]
	at java.util.Optional.ifPresent(Optional.java:159) ~[?:1.8.0_144]
	at net.flintmc.mcapi.v1_15_2.world.scoreboard.listener.VersionedPlayerTeamChangeListener.changeColor(VersionedPlayerTeamChangeListener.java:88) ~[VersionedPlayerTeamChangeListener.class:?]
	at net.flintmc.mcapi.internal.world.scoreboard.score.DefaultPlayerTeam.setColor(DefaultPlayerTeam.java:137) ~[DefaultPlayerTeam.class:?]
	at net.flintmc.mcapi.v1_15_2.world.scoreboard.VersionedScoreboardInterceptor.hookHandleTeams(VersionedScoreboardInterceptor.java:141) ~[VersionedScoreboardInterceptor.class:?]
	at GeneratedMethodInjector_125_1f1ae294b45945eba506ea211023e950.notifyHook(GeneratedMethodInjector_125_1f1ae294b45945eba506ea211023e950.java) ~[?:?]
	at net.minecraft.client.network.play.ClientPlayNetHandler.handleTeams(ClientPlayNetHandler.java:1948) ~[ClientPlayNetHandler.class:?]

Create MethodInjector implementation with Reflections

Is your feature request related to a problem? Please describe.
Currently there are the MethodInjectors that are generated with Javassist, but that takes some time to generate. If a MethodInjector should only be used once (for example to invoke a getter which won't be reused anymore), this is unnecessary and reflections can be used.

Describe the solution you'd like
The given interface in MethodInjector.Factory.generate should be implemented with a Proxy and the target method should be invoked via Reflections. This solution will be faster when executed once, but for multiple invocations Javassist should still be used.

Describe alternatives you've considered
The InjectedInvocationHelper that has been removed in this commit could be implemented again to simply invoke a method with a Map of Keys (from Guice) and their values and without creating an interface.

Enforce line endings in project

Description
I noticed in my #7 pr, my Linux line endings will be shown in the diff.

To Reproduce the Bug

  1. Switch operating systems on some file
  2. Edit in vim or similar editor
  3. Commit
  4. View commit diff

Expected behavior
The .git/config or similar enforces one line ending and fixes this when committing.

System Information:

  • Operating System: Arch Linux
  • Flint Version: 2087173

Clean exit on failure

Is your feature request related to a problem? Please describe.
Currently there is no clean way to exit the process when a fatal error occurs. Exceptions either bubble up and cause a crash, or worse, get eaten somewhere in the framework and cause the process to hang without exiting.

Describe the solution you'd like
A method to exit the process in case of a failure. Minecraft crash reports should be reused, as there are tools out there which can parse information out of such logs.

This could be extended with an error screen displayed to the user.

Describe alternatives you've considered
System.exit - However, that would kill the process without a clear indication why.
Throwing the exception - Mentioned above, gets swallowed a lot of times

Add target to MethodProxy

The MethodProxy annotation can only proxy a method with the same name, but it may be useful to also proxy methods with other names and specify the original name inside of the MethodProxy annotation.

Add EventPhase annotation to events

This annotation should contain an array of all phases in which the annotated event can be fired.
When firing the event, the phase should be checked and if the event is not marked to be fired in the given phase, throw an exception.

Useless error message for invalid event subscribers

Description
The stacktrace and message for invalid event subscribers is more or less useless:
Example:

net.flintmc.framework.stereotype.service.ServiceNotFoundException: One parameter of a @Subscribe Method must be a subtype of Event
	at net.flintmc.framework.eventbus.internal.EventBusService.discover(EventBusService.java:62)
	at net.flintmc.framework.stereotype.service.ServiceRepository.flushServices(ServiceRepository.java:102)
	at net.flintmc.transform.launchplugin.FlintFrameworkInitializer.initialize(FlintFrameworkInitializer.java:66)
	at net.flintmc.transform.launchplugin.FlintLauncherPlugin.preLaunch(FlintLauncherPlugin.java:106)
	at net.flintmc.launcher.LaunchController.run(LaunchController.java:177)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at net.flintmc.launcher.FlintLauncher.main(FlintLauncher.java:36)
	at net.flintmc.launcher.FlintLauncher.main(FlintLauncher.java:16)

To Reproduce the Bug

  1. Create an event subscriber which has no parameter which is a valid event

Expected behavior
A better error message containing which method failed to validate. The stacktrace is ok as is, but the message needs to get better.

Vector3D#distanceSq calculation is wrong

public double distanceSq(double x, double y, double z, boolean useCenter) {
double center = useCenter ? 0.5D : 0.0D;
double distanceX = this.getX() + center - x;
double distanceY = this.getX() + center - y;
double distanceZ = this.getX() + center - z;
return distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ;
}

Every distance is calculated with x, not the correct coordinate, which leads to a wrong distance result.

Issues in the Chat module

Description

  • The ChatSendEvent cannot be cancelled because the message will be null in the POST phase
  • The displayChatMessage is not implemented yet

To Reproduce the Bug

  • Subscribe to the ChatSendEvent in the PRE phase and cancel it
  • Try to send a message in the chat via ChatController.displayChatMessage

Fix injection of PotionRegister

The constructor of the DefaultPotionRegister is private and is missing an Inject annotation and therefore cannot be injected by Guice.

Track package origin in AnnotationMeta

Make the Annotation preprocessor encode the name of the package/root gradle module into the DetectableAnnotationProvider, so that it can be accesssed via the AnnotationMeta when the ServiceHandler's discover method get called.

Proposed API:

// returns the name of the root gradle project (which should always equal the package name)
AnnotationMeta#getOrigin(): String

This should also work in a debug IDE environment when the package's classes are loaded directly into the RootClassLoader instead of using the PackageLoader.
This however means that the PackageLoader cannot handle this, the information can only be obtained at compile time.

Create ModelRenderer API

To make it possible to manipulate body parts of single entities easily, it is necessary to write an API for the "ModelRenderer" of Minecraft

Exclude non Minecraft classes from transformation

Description
All classes are passed through class transformers implicitly using the DefaultClassTransformService. This causes injection dependency cycles.

Expected behavior
Only classes starting with net.minecraft and com.mojang are passed through the transformers implicitly using the `DefaultClassTransformService.

Add WorldJoinEvent

Is your feature request related to a problem? Please describe.
Currently there is no way to detect when joining a world, only for the multiplayer.

Describe the solution you'd like
The event should be fired when joining a world and in multiplayer, but contain an enum to decide whether it is singleplayer or multiplayer.

Proper entity mapping

Description
The big problem with entity mapping from Flint to Minecraft and from Minecraft to Flint currently is, that the types do not always match. For example, when wanting the map the Minecraft.getInstance().player to a Flint object, the result will never be instanceof ClientPlayer. This can lead to problems when wanting to store something in an entity, for example the potion effects. ClientPlayer#getActivePotions will never return a non-empty list because the potion effects are applied to another instance of PlayerEntity representing the player.
Another issue of the current mapping system is, that there has to be a mapping method for every single entity, which will get too much when all entities are implemented. A single method like fromMinecraftEntity(Object handle) would be good.
Furthermore, the toMinecraft mapping method is not really needed. As all entities currently are wrappers around the minecraft object, a getHandle() method should be fine.

Fix javadocs

Description
The javadocs are completely broken.

To Reproduce the Bug

  1. Try to generate javaodocs for the entire project

Expected behavior
The javadocs build cleanly.

Log Output
Not going to post over 200 errors and warnings...

Add FieldIdentifier

The DetectableAnnotations should also work on Fields if for example someone wants a getter with an annotation, the annotation could also be located directly on the field.

Add WorldGenerator

Is your feature request related to a problem? Please describe.
Currently there is no way to create a new world with custom properties without directly accessing Minecraft code.

Describe the solution you'd like
There should be a builder where you can set every property that can be set in the world creation screen of vanilla Minecraft.

RGB chat colors

Is your feature request related to a problem? Please describe.

Minecraft 1.16 has RGB chat colors, we might want to backport that to older versions if desirable.

Slow EventBus

Is your feature request related to a problem? Please describe.
Currently the EventBus discovers all SubscribeMethods when an event is being fired, obviously this process is pretty time-consuming and should be moved to the startup.

Describe the solution you'd like
Maybe we could generate a class that holds a collection with all SubscribeMethods per event.
#11 could help discovering all events.

Implement 1.16.4

As a developer, I would like to use my modifications on the newer versions.

Convert the bootstrap module to a proper launcher plugin

Description
The bootstrap module is a hack which should not exist in first place. The functionality of it should go into a launcher plugin, as it currently makes the launcher not standalone anymore by preloading jars.

Expected behavior
The bootstrap module is a launcher plugin instead of the hacky bootstrap.

Proposal

  1. The launcher starts up and begins its plugin loading cycle
  2. Bootstrap is the only launcher plugin which is initially on the path
  3. Bootstrap detects (or does not detect) an install of FlintMC
    4.1 FlintMC is not detected -> Bootstrap sets up a FlintMC install
    4.2 FlintMC is dectected -> Bootstrap verifies the integrity of the install and possibly checks for updates
  4. Bootstrap performs additional checks regarding installed mod compatibility
  5. Boostrap loads FlintMC launcher plugin and injects it using the provided mechanism
  6. The launcher finishes the first loading cycle and begins the second one
  7. The launch process continues as known

Improve Package Loader

There are some things that need to be done:

  • Refactor package loading (into a more responsibility driven approach)
  • Fix bugs in package loading
  • implement a better algorithm for dependency resolution (find best loadable dep. graph)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.