-
Notifications
You must be signed in to change notification settings - Fork 71
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
Completely fixed trigger() #488
base: master
Are you sure you want to change the base?
Conversation
These three events did not have an interface extending from BindableEvent causing a NPE on classloading of EventBuilder. Which blocked all usage of that class. Fix: adding MCPalyerEvent like in all other player events.
ManualTrigger was only able to trigger an event if there was a bind() which used that event in MS. If one intends to send an only serverwide message. it was not possible. General rewrite as cleanup. Features stay the same.
This PR has been created in collaboration with @Pieter12345 |
Additional things which will break if not fixed:
These would trigger the, in this PR prevented debug message, warning that no _instantiate method exists. |
09111fc
to
b98b1a4
Compare
Has issue with one wrong import, issue resolved, lets ask travis for more issues. |
Given that the code works, I like the following changes:
The one thing I do not like is:
Having the _instantiate method as it is ensures that some Bukkit Event object was instantiated and passed to the corresponding BukkitMCEvent class (and therefore indirectly ensures that some event can be broadcasted server-wide, as it has to have a Bukkit event object). It also disallows some _instantiate method to instantiate events from a different type, even though that would be very poor programming from the developer that writes that (or a copy-paste error perhaps). An argument against, on the other hand, is that making the _instantiate method return a BukkitMCEvent does not require reflection to pass the Bukkit Event to the BukkitMCEvent constructor, which is more efficient. @LadyCailin and @PseudoKnight , this _instantiate design choice is something I'd like to hear your opinions about. If we can all agree on something, @Ecconia and I can figure out how to make our PR's compatible for merging. |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<ramble>
So, before diving into the solution, it's useful to think about what the actual problem is, so let's step back and think this though.
The trigger() method is designed to trigger a synthesized event. In order to do this, we need to ultimately instantiate a new instance of the underlying event. The problem is, that we must of course instantiate a concrete instance of a class, (i.e. org.bukkit.event.player.PlayerJoinEvent), not a MCPlayerJoinEvent (or a BukkitMCPlayerJoinEvent for that matter). But in the core code, we actually only have an instance of MCPlayerJoinEvent, and we need to abstractly get ahold of the PlayerJoinEvent. We can rely on BukkitMCPlayerJoinEvent to do the conversion from CH abstraction layer to Bukkit terms, that's ok, so actually we just need a concrete reference to BukkitMCPlayerJoinEvent. But even still we need to have access to a static method in BukkitMCPlayerJoinEvent, which will return the new instance, or at least it needs to be able to return a builder for it. If we return a builder, that moves the problem one layer up, which might be useful anyways, but we still need to solve the original problem: We need to construct a new instance of an object, for which the abstract code does not know the signature required to construct it (or even what class it should instantiate), and we do not have concrete instances, we only have static methods. And: We would like to construct the code in such a way that if we screw it up, we get a compile error.
</ramble>
So, in general, this problem can probably be solved by modeling after the dependency injection pattern. In DI, you are able to have singleton instances. Unlike a traditional DI framework, we have class discovery, which makes instantiating instances way easier. So if we have a builder in BukkitMCPlayerJoinEvent, which is instantiated with a no-arg constructor, then we have a list of concrete builders for each abstract event subtype. These build method in these builders should extend a common build method which accepts a CArray, and converts that to a new PlayerJoinEvent (no need for MCPlayerJoinEvent to get involved here, I think) The methods for obtaining the builder in the first place will all have the same signature (just a different return type) so this can easily be checked as a unit test or compile error, to ensure that all event subtypes have this static method defined.
interface ConcreteEventBuilder<T extends ...Object Maybe?> {
T build(CArray input);
}
interface BukkitConcreteEventBuilder<T extends Event> extends ConcreteEventBuilder<T>{ ... }
public static class BukkitMCPlayerJoinEvent ... {
public static ConcreteEventBuilder<PlayerJoinEvent> () {
return new BukkitConcreteEventBuilder<PlayerJoinEvent>() {
PlayerJoinEvent build(CArray array) {
return new PlayerJoinEvent(array, values, here);
}
}
}
}
Then, in the BukkitAbstractEventMixin, you get the Event.
I think this will work. Any thoughts?
+ " Defaults to false, which means that only CommandHelper code will receive the event." | ||
+ " Throws a CastException when eventObject is not an array and not null." | ||
+ " Throws a BindException when " + getName() + "() is not yet supported by the given event." | ||
+ " Throws a CREIllegalArgumentException exception, if the event does not exist."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
End users do not know what a CREIllegalArgumentException is, it is an IllegalArgumentException.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
New exceptions are now thrown. Old ones had been ignored. Formatting the docs to the 120 character limit.
-> Using EventBuilder resulted in spam in console on proper usage. EventBuilder is checking in static code if each Event has a _instantiate method to create it. Some events don't need to be created since convert() returns null or throws an exception. By removing the "warmup" for all events on classloading, the loads is distributed and the actual checks if _instantiate exists will only be done, when a convert() method actually needs to create an event. -> instantiate() expects _instantiate() to return a Bukkit event, but all except one event return a BukkitMC*Event from CH. There is no need for EventBuilder to insert the Bukkit event into the BukkitMC*Event with reflection and overhead.
This is the only event which does not return a BukkitMC*Event instead it returned a Bukkit event. Which is no longer accepted.
b98b1a4
to
d57d093
Compare
Updating Style to get rid of merge conflicts.
Did anyone ever use trigger?
Following PR fixes almost everything not event-specific in the whole trigger system.
It allows the usage of trigger again.
Fixes done:
Fixing 4 inconsistent events (one causing a NPE).
Fixing EventBuilder which was also incompatible with all events except one.
-> Preventing not useful spamy developer debug on proper usage.
Rewriting ManualTrigger to support sending serverwide events without binding them first.