Skip to content

Commit 03da26e

Browse files
committed
Implement event system
Added the event system in accordance to #12. The events are not yet implemented in that way that they get dispatched as soon as the according action is executed. The following event classes where added: - User related: - Creation - Deletion - Loading - Punishment related (which are also user-related since a punishment is always bound to an user): - Persecution/actual punishing - cancellation - change - Necrify state - pre-initialization (first API action) - initialized - disabling - disabled (last API action)
1 parent 08cb0dc commit 03da26e

25 files changed

+1025
-25
lines changed

api/build.gradle.kts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
plugins {
22
java
3+
`java-library`
34
}
45

56
version = rootProject.version
@@ -10,7 +11,12 @@ repositories {
1011
}
1112

1213
dependencies {
13-
compileOnly(libs.velocity.api)
14+
api(libs.jetbrains.annotations)
15+
api(libs.eventbus)
16+
compileOnly(libs.slf4j.api)
17+
compileOnly(libs.bundles.adventure)
18+
testImplementation(libs.slf4j.api)
19+
testImplementation("ch.qos.logback:logback-classic:1.5.6")
1420
testImplementation(libs.junit.jupiter.api)
1521
testRuntimeOnly(libs.junit.jupiter.engine)
1622
}

api/src/main/java/de/jvstvshd/necrify/api/Necrify.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
package de.jvstvshd.necrify.api;
2626

27-
import com.velocitypowered.api.proxy.ProxyServer;
2827
import de.jvstvshd.necrify.api.message.MessageProvider;
2928
import de.jvstvshd.necrify.api.punishment.Punishment;
3029
import de.jvstvshd.necrify.api.punishment.PunishmentManager;
@@ -69,37 +68,30 @@ public interface Necrify {
6968
* @deprecated Will be removed with {@link PunishmentManager}.
7069
*/
7170
@Deprecated(since = "1.2.0", forRemoval = true)
72-
@ApiStatus.ScheduledForRemoval(inVersion = "2.0.0")
71+
@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0")
7372
PunishmentManager getPunishmentManager();
7473

7574
/**
7675
* @deprecated Will be removed with {@link PunishmentManager}.
7776
*/
7877
@Deprecated(since = "1.2.0", forRemoval = true)
79-
@ApiStatus.ScheduledForRemoval(inVersion = "2.0.0")
78+
@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0")
8079
void setPunishmentManager(PunishmentManager punishmentManager);
8180

8281
/**
8382
* @deprecated Will be removed with {@link PunishmentManager}.
8483
*/
8584
@Deprecated(since = "1.2.0", forRemoval = true)
86-
@ApiStatus.ScheduledForRemoval(inVersion = "2.0.0")
85+
@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0")
8786
PlayerResolver getPlayerResolver();
8887

8988
/**
9089
* @deprecated Will be removed with {@link PunishmentManager}.
9190
*/
9291
@Deprecated(since = "1.2.0", forRemoval = true)
93-
@ApiStatus.ScheduledForRemoval(inVersion = "2.0.0")
92+
@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0")
9493
void setPlayerResolver(PlayerResolver playerResolver);
9594

96-
/**
97-
* @deprecated Will be removed with multi-platform support.
98-
*/
99-
@Deprecated(since = "1.2.0", forRemoval = true)
100-
@ApiStatus.ScheduledForRemoval(inVersion = "2.0.0")
101-
ProxyServer getServer();
102-
10395
@NotNull
10496
ExecutorService getService();
10597

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* This file is part of Necrify (formerly Velocity Punishment), which is licensed under the MIT license.
3+
*
4+
* Copyright (c) 2022-2024 JvstvsHD
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package de.jvstvshd.necrify.api.event;
26+
27+
import org.greenrobot.eventbus.EventBus;
28+
import org.greenrobot.eventbus.Logger;
29+
import org.greenrobot.eventbus.Subscribe;
30+
import org.greenrobot.eventbus.ThreadMode;
31+
import org.jetbrains.annotations.NotNull;
32+
33+
import java.util.Objects;
34+
import java.util.concurrent.CompletableFuture;
35+
import java.util.concurrent.ExecutorService;
36+
37+
/**
38+
* The event dispatcher is used to dispatch events to the event bus. Events may be cancelled or dispatched synchronously or asynchronously.
39+
* Moreover, listeners can be registered and unregistered; or you may directly listen to events.
40+
*
41+
* @see NecrifyEvent
42+
* @see EventBus
43+
* @since 1.2.0
44+
*/
45+
public class EventDispatcher {
46+
47+
private final EventBus eventbus;
48+
private final ExecutorService executorService;
49+
50+
/**
51+
* Creates a new event dispatcher that can be customized completely.
52+
*
53+
* @param eventbus The event bus to use. See the <a href="https://greenrobot.org/eventbus/documentation/configuration/">
54+
* GreenRobot EventBus documentation</a> for more information.
55+
* @param executorService The executor service to use for asynchronous event dispatching. Note: this service must not
56+
* correspond with the {@link org.greenrobot.eventbus.EventBusBuilder#executorService(ExecutorService) event bus' executor service}.
57+
*/
58+
public EventDispatcher(@NotNull EventBus eventbus, ExecutorService executorService) {
59+
this.eventbus = eventbus;
60+
this.executorService = executorService;
61+
}
62+
63+
/**
64+
* Creates a new event dispatcher with the given executor service and logger. This event bus does not log messages
65+
* if an dispatched event has no subscriber and does not send an event if no subscriber is registered.
66+
*
67+
* @param executorService The executor service to use for asynchronous event dispatching and for asynchronous event
68+
* handling execution (only for {@link org.greenrobot.eventbus.ThreadMode thread modes}
69+
* {@link org.greenrobot.eventbus.ThreadMode#ASYNC} and {@link org.greenrobot.eventbus.ThreadMode#BACKGROUND}).
70+
* @param logger The logger to use for logging messages. If null, sysout will be used for logging. It may be better
71+
* to delegate messages to the platform's logger, for example with the {@link Slf4jLogger}.
72+
*/
73+
public EventDispatcher(ExecutorService executorService, Logger logger) {
74+
this.executorService = executorService;
75+
this.eventbus = EventBus
76+
.builder()
77+
.logNoSubscriberMessages(false)
78+
.sendNoSubscriberEvent(false)
79+
.logger(logger)
80+
.executorService(executorService)
81+
.build();
82+
}
83+
84+
/**
85+
* Dispatches the given event synchronously. This method will block until all listeners have been executed. Listener
86+
* methods registered with {@link org.greenrobot.eventbus.ThreadMode#ASYNC} or {@link ThreadMode#BACKGROUND} will be executed
87+
* asynchronously through the given {@link org.greenrobot.eventbus.EventBusBuilder#executorService(ExecutorService) eventbus executor}; thus the method will not block until these listeners have been executed.
88+
*
89+
* @param event The event to dispatch.
90+
*/
91+
public void dispatch(NecrifyEvent event) {
92+
eventbus.post(event.setExecutingDispatcher(this));
93+
}
94+
95+
/**
96+
* Dispatches the given event asynchronously. This method will not block until all listeners have been executed.
97+
* Listener methods registered with {@link org.greenrobot.eventbus.ThreadMode#ASYNC} or {@link ThreadMode#BACKGROUND} will be executed
98+
* asynchronously; thus the method will not block until these listeners have been executed.
99+
*
100+
* @param event The event to dispatch.
101+
* @return A future that will be completed when the event has been dispatched.
102+
*/
103+
public CompletableFuture<Void> dispatchAsync(NecrifyEvent event) {
104+
var future = new CompletableFuture<Void>();
105+
executorService.execute(() -> {
106+
dispatch(event);
107+
future.complete(null);
108+
});
109+
return future;
110+
}
111+
112+
/**
113+
* Registers the given listener to the event bus. The listener will be able to listen to events via subscribed methods.
114+
* These methods must be annotated with {@link Subscribe} and must have a single parameter of the event type.
115+
*
116+
* @param listener the listener instance to register.
117+
*/
118+
public void register(@NotNull Object listener) {
119+
eventbus.register(Objects.requireNonNull(listener, "listener must not be null in order to get registered"));
120+
}
121+
122+
/**
123+
* Unregisters the given listener from the event bus. The listener will no longer be able to listen to events.
124+
*
125+
* @param listener the listener instance to unregister.
126+
*/
127+
public void unregister(@NotNull Object listener) {
128+
eventbus.unregister(Objects.requireNonNull(listener, "listener must not be null in order to get unregistered"));
129+
}
130+
131+
/**
132+
* Cancels the given event. This method will prevent the event from being delivered to any new listeners, though it
133+
* may already have been delivered to some listeners.
134+
* <p>This method is implicitly called though {@link NecrifyEvent#cancel()}</p>
135+
*
136+
* @param event the event to cancel.
137+
*/
138+
public void cancelEvent(@NotNull NecrifyEvent event) {
139+
eventbus.cancelEventDelivery(Objects.requireNonNull(event, "event must not be null in order to get cancelled"));
140+
}
141+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* This file is part of Necrify (formerly Velocity Punishment), which is licensed under the MIT license.
3+
*
4+
* Copyright (c) 2022-2024 JvstvsHD
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package de.jvstvshd.necrify.api.event;
26+
27+
/**
28+
* Represents an event that can be dispatched by the {@link EventDispatcher}.
29+
* All events must extend this class.
30+
*
31+
* @since 1.2.0
32+
*/
33+
public abstract class NecrifyEvent {
34+
35+
private final String name;
36+
private EventDispatcher executingDispatcher = null;
37+
38+
public NecrifyEvent(String name) {
39+
this.name = name;
40+
}
41+
42+
public String getName() {
43+
return name;
44+
}
45+
46+
/**
47+
* Cancels the event. This will prevent the event from being executed further.
48+
*/
49+
public final void cancel() {
50+
if (executingDispatcher != null) {
51+
executingDispatcher.cancelEvent(this);
52+
}
53+
}
54+
55+
/**
56+
* Sets the dispatcher that is currently executing this event.
57+
*
58+
* @param executingDispatcher the dispatcher that is currently executing this event.
59+
* @return this event.
60+
*/
61+
NecrifyEvent setExecutingDispatcher(EventDispatcher executingDispatcher) {
62+
this.executingDispatcher = executingDispatcher;
63+
return this;
64+
}
65+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* This file is part of Necrify (formerly Velocity Punishment), which is licensed under the MIT license.
3+
*
4+
* Copyright (c) 2022-2024 JvstvsHD
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package de.jvstvshd.necrify.api.event;
26+
27+
import org.greenrobot.eventbus.Logger;
28+
29+
import java.util.logging.Level;
30+
31+
/**
32+
* An adapter for the SLF4J logger to the GreenRobot EventBus logger.
33+
* This logger will delegate all messages to the SLF4J logger.
34+
* The level conversion is as follows:
35+
* <table border="1">
36+
* <tr>
37+
* <th>Java Util Logging Level</th>
38+
* <th>SLF4J Level</th>
39+
* </tr>
40+
* <tr>
41+
* <td>SEVERE</td>
42+
* <td>ERROR</td>
43+
* </tr>
44+
* <tr>
45+
* <td>WARNING</td>
46+
* <td>WARN</td>
47+
* </tr>
48+
* <tr>
49+
* <td>INFO, CONFIG</td>
50+
* <td>INFO</td>
51+
* </tr>
52+
* <tr>
53+
* <td>FINER, FINEST, ALL</td>
54+
* <td>TRACE</td>
55+
* </tr>
56+
* <tr>
57+
* <td>Other</td>
58+
* <td>DEBUG</td>
59+
* </tr>
60+
* <tr>
61+
* <td>OFF</td>
62+
* <td>No logging</td>
63+
* </tr>
64+
* </table>
65+
*
66+
* @see Logger
67+
* @see org.slf4j.Logger
68+
* @since 1.2.0
69+
*/
70+
public class Slf4jLogger implements Logger {
71+
72+
private final org.slf4j.Logger logger;
73+
74+
public Slf4jLogger(org.slf4j.Logger logger) {
75+
this.logger = logger;
76+
}
77+
78+
@Override
79+
public void log(Level level, String msg) {
80+
if (level == Level.OFF)
81+
return;
82+
logger.atLevel(convertLevel(level)).log(msg);
83+
}
84+
85+
@Override
86+
public void log(Level level, String msg, Throwable th) {
87+
if (level == Level.OFF)
88+
return;
89+
logger.atLevel(convertLevel(level)).setCause(th).log(msg);
90+
}
91+
92+
private org.slf4j.event.Level convertLevel(Level level) {
93+
return switch (level.getName()) {
94+
case "SEVERE" -> org.slf4j.event.Level.ERROR;
95+
case "WARNING" -> org.slf4j.event.Level.WARN;
96+
case "INFO", "CONFIG" -> org.slf4j.event.Level.INFO;
97+
case "FINER", "FINEST", "ALL" -> org.slf4j.event.Level.TRACE;
98+
default -> org.slf4j.event.Level.DEBUG;
99+
};
100+
}
101+
}

0 commit comments

Comments
 (0)