Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component API Implementation #146

Closed
wants to merge 77 commits into from
Closed

Component API Implementation #146

wants to merge 77 commits into from

Conversation

0xJoeMama
Copy link

@0xJoeMama 0xJoeMama commented Jun 29, 2022

After 2 weeks of unhealthy head-banging I have finally finished this!

This API adds:

  • A new module to the data library, called 'component'.
  • A new class on the qsl_base module, called Maybe. It represents a monad that either holds a value or doesn't.

A bit of an explanation:

This module allows you attach data, functions, ticking functions to game objects.
Right now the following objects are implemented:

  • Block Entities
  • Entities
  • Chunks
  • ItemStacks(Removed from the Initial Release)
  • LevelProperties

The data can be serialized using NBT and can also be network synced(although that feature is a bit unstable at the moment).

Component Injection

During the mod loading stage, mods are able to inject into difference game objects, provided those objects implement the ComponentProvider interface. Those injections are cached using the target class/classes and are then able to be quickly looked up.

But what about the case where cached injections don't suffice? one may ask.
Well that's also covered using dynamic injection.
Along with the class that you are targeting, you can also provide a predicate that will match the type of the class.
That predicate is then used when a provider is initialized to make sure it matches and/or can be injected into the target.
Proceed with caution: The predicate is checked, at the end of the constructor of the highest class in the hierarchy. This means that only the properties initialized up to that point will be available for querying!.

While that may not seem like a problem for things like ItemStacks, which generally aren't extended, Entities for example have a wide variety of classes with different fields. However, when injecting dynamically, one will only have access to the Entity class fields as well as the type information of the object.

Custom implementations

I have made the API really flexible, so that anyone can just create custom implementations of most provided objects.
Component containers, component providers, components, sync headers, all of those can be extended and tweaked as per need.

Network sync and data saving

Data is currently saved using NBT and a save call that is provided from the provider to its container.
Data is currently synced using a system I have implemented. Needless to say, this system needs some tweaking as well as a lot of testing to make sure that:

  1. No data is lost through the network.
  2. There are no runtime crashes caused by the system.
  3. Components are properly synced even in edge cases.
  4. Components are synced when the object is first loaded.

I think that after all that is done, this will be able to be released.

Finally

Feel free to ask any questions about the implementation and provide feedback wherever possible.
This project was a massive undertaking for one person and that is why I decided to PR it now that it's reaching its final stages.
The codebase is big and documentation is needed, I understand that. However I still think I needed to share it with everyone.
Thank you for your time!

0xJoeMama and others added 30 commits June 14, 2022 00:03
0xJoeMama and others added 5 commits July 16, 2022 16:05
* Implemented initial sync.
* Implemented sync requests.

This is the last feature commit. From now on only improvements, until
the initial release.
@0xJoeMama
Copy link
Author

0xJoeMama commented Jul 21, 2022

Consider the initial feature-set done! Feel free to start breaking this!

* needs to implement this interface.<br/>
*
* <p>
* Currectly it consists of the {@link ComponentProvider#getComponentContainer()} method, which is the abstract one,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, instead of Currectly

* @see ComponentContainer
* @see Components
*/
@InjectedInterface({ // We inject this inteface, so that modders don't need to use the methods in Components directly with our default implementations.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interface instead of inteface

public interface ComponentProvider {
/**
* Every {@linkplain ComponentProvider provider} must provide a {@link ComponentContainer},
* so that it can store the components targetting or that are manually added to it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targeting instead of targetting

@TheGlitch76 TheGlitch76 removed the test label Aug 28, 2022
@0xJoeMama 0xJoeMama marked this pull request as draft September 8, 2022 19:44
@0xJoeMama 0xJoeMama closed this May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
library: data Related to the data library. new: module A pull request which adds a new module s: waiting for test This pull request is waiting to be tested, the PR cannot be put in FCP until it has been tested. t: new api This adds a new API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet