Skip to content

Commit d64fb01

Browse files
[~] Fixed console colors could not be correctly displayed in Windows terminal.
[+] Added @eventhandler annotation. [+] Added bukkit-like event system and its dispatcher [+] Added EntityEmergedEvent [+] Added PlayerMoveEvent [~] Improved code structure. [-] Removed useless classes. [+] Added Win32ColorSerializer for windows style color rendering. [~] Added Player interfaces for plugin development [~] Improved Logging system.
1 parent d03743e commit d64fb01

33 files changed

+598
-138
lines changed

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PluginDocs.md

Lines changed: 144 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,138 @@ In this section, you will learn:
4040
````java
4141
package org.angellock.impl.extensions;
4242

43-
import org.angellock.impl.AbstractRobot;
44-
import org.angellock.impl.events.handlers.LoginHandler;
43+
import org.angellock.impl.AbstractRobot;
44+
import org.angellock.impl.events.handlers.LoginHandler;
45+
import org.angellock.impl.providers.AbstractPlugin;
46+
47+
public class ExamplePlugin extends AbstractPlugin {
48+
@Override
49+
public String getPluginName() {
50+
return "My First Plugin";
51+
}
52+
53+
@Override
54+
public String getVersion() {
55+
return "1.0.0";
56+
}
57+
58+
@Override
59+
public String getDescription() {
60+
return "Hello DolphinBot";
61+
}
62+
63+
@Override
64+
public void onDisable() {
65+
getLogger().info("Disabling {} - {}", this.getName(), getVersion());
66+
//Disable Message
67+
}
68+
69+
@Override
70+
public void onLoad() {
71+
getLogger().info("Loading {} - {}", this.getName(), getVersion());
72+
// Loading Plugin Message
73+
}
74+
75+
@Override
76+
public void onEnable(AbstractRobot entityBot) {
77+
getListeners().add(
78+
new LoginHandler().addExtraAction((loginPacket) -> {
79+
getLogger().info(loginPacket.getCommonPlayerSpawnInfo().getGameMode().name());
80+
})
81+
);
82+
}
83+
}
84+
85+
````
86+
- You can also refer to the example plugin in folder `/example-plugin/example_plugin` for help, or you can base on this demo plugin as your template to develop your own plugin.
87+
- After you package your plugin, put the packaged plugin in folder `/plugins` (Global plugin directory).
88+
- If you only want to apply a plugin to a specified bot, put plugin into `/plugin/<Bot Profile Name>` (Automatically
89+
generated by DolphinBot.)
90+
91+
## 3. Register Event Handlers:
92+
93+
In order to make DolphinAPI more easy-used and scalable, DolphinBot also provides a Bukkit-like Event APIs.
94+
95+
### `@EventHandler` Annotation:
96+
97+
- The `@EventHandler` is aimed mark methods as handleable actions. Whenever `@EventHandler` is declared on methods,
98+
it will inject the inner method code into `EventDispatcher` by using reflects.
99+
`@EventHandler` has an optional parameter, namely handling priority, which is classified by `EventPriority` enum.
100+
Absent for `EventPriority.NORMAL`.
101+
102+
There are 6 different priority level:
103+
104+
| Event Priority | Description |
105+
|----------------|-------------------------------------------------|
106+
| LOWEST | Lowest priority, might be ignored by dispatcher |
107+
| LOW | Low but above lowest |
108+
| NORMAL | Default level, meets normal tasks |
109+
| HIGH | Above NORMAL |
110+
| HIGHEST | Above the HIGH level |
111+
| MONITOR | More than HIGHEST level, may consume more CPU |
112+
113+
**Examples:**
114+
Create a class named `MyListener`
115+
by Implementing `IListener` interface, and annotate `@EventHandler` on methods you want to handle.
116+
117+
```java
118+
import org.angellock.impl.events.EventPriority;
119+
import org.angellock.impl.events.IListener;
120+
import org.angellock.impl.events.annotations.EventHandler;
121+
import org.angellock.impl.events.types.PlayerMoveEvent;
122+
import org.angellock.impl.ingame.Player;
123+
import org.angellock.impl.util.math.Position;
124+
125+
public class MyListener implements IListener {
126+
@EventHandler(EventPriority.HIGHEST)
127+
public void onPlayerMove(PlayerMoveEvent event) {
128+
Player player = event.getPlayer();
129+
System.out.println("Warning! the player " + player.getName() + " is moving!");
130+
}
131+
132+
@EventHandler(EventPriority.LOW)
133+
public void onPlayerChat(PlayerChatEvent event){
134+
Player sender = event.getSender();
135+
String msg = event.getMessage();
136+
System.out.println("In-Game message: "+sender.getName()+ " has sent "+msg);
137+
}
138+
}
139+
```
140+
141+
After that, you need to register the listener class `MyListener` you just create.
142+
Added below code to `onEnable()` method in `ExamplePlugin`:
143+
144+
```java
145+
...
146+
@Override
147+
public void onEnable(AbstractRobot entityBot) {
148+
registerEvent(new MyListener());
149+
}
150+
```
151+
152+
Alternately you can put `@EventHandler` methods into `ExamplePlugin` class instead of creating new listener class,
153+
The only thing you need to do is make `ExamplePlugin` to also implement the `IListener` interface:
154+
**Here is Example:**
155+
156+
```java
157+
import org.angellock.impl.events.IListener;
158+
import org.angellock.impl.events.annotations.EventHandler;
159+
import org.angellock.impl.events.types.EntityEmergedEvent;
45160
import org.angellock.impl.providers.AbstractPlugin;
161+
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
162+
163+
public class ExamplePlugin extends AbstractPlugin implements IListener {
164+
@Override
165+
public void onEnable(AbstractRobot entityBot) {
166+
registerEvent(this); // Because plugin class implemented IListener, so it is also a Listener Type.
167+
}
168+
169+
@EventHandler // None Parameter for default event priority.
170+
public onTestEvent(EntityEmergedEvent event) {
171+
EntityType entityType = event.getEntity();
172+
System.out.println("An Entity emerges: " + entityType.name());
173+
}
46174

47-
public class ExamplePlugin extends AbstractPlugin {
48175
@Override
49176
public String getPluginName() {
50177
return "My First Plugin";
@@ -71,20 +198,22 @@ public class ExamplePlugin extends AbstractPlugin {
71198
getLogger().info("Loading {} - {}", this.getName(), getVersion());
72199
// Loading Plugin Message
73200
}
74-
75-
@Override
76-
public void onEnable(AbstractRobot entityBot) {
77-
getListeners().add(
78-
new LoginHandler().addExtraAction((loginPacket) -> {
79-
getLogger().info(loginPacket.getCommonPlayerSpawnInfo().getGameMode().name());
80-
})
81-
);
82-
}
83201
}
202+
```
84203

85-
````
86-
- You can also refer to the example plugin in folder `/example-plugin/example_plugin` for help, or you can base on this demo plugin as your template to develop your own plugin.
87-
- After you package your plugin, put the packaged plugin in folder `/plugins`.
204+
### Dolphin's Event Listeners
205+
206+
- Available Event Listeners:
207+
208+
| Event Listener | Only Triggered When |
209+
|--------------------|----------------------------------------------------------|
210+
| PlayerMoveEvent | Triggered when a nearby player moves |
211+
| EntityEmergedEvent | A entity generates, player emerged, or projectile thrown |
212+
| PlayerChatEvent | When a player send a in-game message. |
213+
- Note That:
214+
- Every single handling method should annotate with `@EventHandler`.
215+
- All handling method should be public.
216+
- Remember to register the all listener classes.
88217

89218
## 3. Deep Understand DolphinAPIs:
90219
- ### 1. Listeners and PacketEvents:

README.md

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@
4747
- [`Hot-Reloading Plugin`](#hot-swapping-plugins-in-game)
4848

4949
**Implemented Event APIs:**
50-
- [`Command Systems`](PluginDocs.md#2-commands-system)
51-
- [`Packet Handlers`](PluginDocs.md#3-deep-understand-dolphinapis-)
50+
51+
- [`Event Handler System`](PluginDocs.md#3-register-event-handlers)
52+
- [`Command System`](PluginDocs.md#2-commands-system)
53+
- [`Packet Handlers`](PluginDocs.md#3-deep-understand-dolphinapis-)
5254
- [`Player Events`](PluginDocs.md#player-events)
5355
- [`Force Unicode Chat`](PluginDocs.md#unicode-string-helper)
5456

@@ -111,7 +113,7 @@ In this section, you will understand below how-tos:
111113
"bot#1": {
112114
"name": "Player494",
113115
"password": "123example",
114-
"owner": "player_name",
116+
"owner": ["player_name"],
115117
116118
"enabled_plugins": [
117119
"QuestionAnswerer",
@@ -122,7 +124,7 @@ In this section, you will understand below how-tos:
122124
"bot#2": {
123125
"name": "Player495",
124126
"password": "password",
125-
"owner": "player_name",
127+
"owner": ["player_name", "other_owner"],
126128
127129
"enabled_plugins": [
128130
"HumanVerify"
@@ -142,15 +144,48 @@ In this section, you will understand below how-tos:
142144
java -jar "DolphinBot-[version].jar" -profiles="bot#1"
143145
```
144146
If you want to start multiple bot simultaneously, specify multiple profile name as a list in option `-profiles`, for
145-
each profile name, should be split with ";".
147+
each profile name, should be split with ";".
148+
146149
**Examples:**
147150
```bash
148151
java -jar "DolphinBot-[version].jar" -profiles="bot#1;bot#2"
149152
```
150153
```bash
151154
java -jar "DolphinBot-[version].jar" -profiles="bot#1;bot#2;bot#3;..."
152155
```
153-
- **Warning**: If the `--profiles` option is absented, it will load all bots in profile config by default.
156+
- **Warning**: If the `--profiles` option is absented, it will load all bots in profile config by default.
157+
158+
**Owners:**
159+
If you want to limit a bot can be only use by specified player(s) you can put player names into `owner` as list.
160+
**Example:**
161+
```json
162+
{
163+
"profiles": {
164+
"bot#1": {
165+
"name": "Player494",
166+
"password": "123example",
167+
"owner": [
168+
"owner1",
169+
"owner2",
170+
"owner3"
171+
],
172+
173+
"enabled_plugins": [
174+
"QuestionAnswerer",
175+
"MessageDisplay",
176+
"HumanVerify"
177+
]
178+
}
179+
}
180+
}
181+
```
182+
183+
Or you can directly define it by command line.
184+
**Example:**
185+
`--owner=Melibertan`, of course, you also can define multiple names:
186+
For each owner name, should be split with ";".
187+
**Example:**
188+
`--owner=owner1;owner2;owner3;...`
154189
2. **Advanced Configurations (optional)**
155190
If you want to access more advanced configs, you can edit `mc.bot.config.json`.
156191
Every single config option is equilibrium to option that defined by command line, and all config value including

pom.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.angellock.impl</groupId>
88
<artifactId>DolphinBot</artifactId>
9-
<version>1.1.14-RELEASE-full</version>
9+
<version>1.1.17-RELEASE-full</version>
1010
<packaging>
1111
jar
1212
</packaging>
@@ -35,6 +35,16 @@
3535
<artifactId>adventure-text-serializer-json</artifactId>
3636
<version>4.15.0</version>
3737
</dependency>
38+
<dependency>
39+
<groupId>net.java.dev.jna</groupId>
40+
<artifactId>jna-platform</artifactId>
41+
<version>5.17.0</version>
42+
</dependency>
43+
<dependency>
44+
<groupId>net.java.dev.jna</groupId>
45+
<artifactId>jna</artifactId>
46+
<version>5.17.0</version>
47+
</dependency>
3848
<dependency>
3949
<groupId>org.jline</groupId>
4050
<artifactId>jline</artifactId>

src/main/java/org/angellock/impl/AbstractRobot.java

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package org.angellock.impl;
22

33

4-
import org.angellock.impl.commands.*;
4+
import com.google.gson.JsonElement;
5+
import org.angellock.impl.commands.Command;
6+
import org.angellock.impl.commands.CommandResponse;
7+
import org.angellock.impl.commands.CommandSerializer;
8+
import org.angellock.impl.commands.CommandSpec;
59
import org.angellock.impl.events.IConnectListener;
610
import org.angellock.impl.events.IDisconnectListener;
711
import org.angellock.impl.events.handlers.SystemChatHandler;
@@ -18,12 +22,12 @@
1822
import org.angellock.impl.util.ConsoleTokens;
1923
import org.angellock.impl.util.PlainTextSerializer;
2024
import org.angellock.impl.util.math.Position;
21-
import org.cloudburstmc.math.vector.Vector3d;
2225
import org.geysermc.mcprotocollib.network.Session;
2326
import org.geysermc.mcprotocollib.network.tcp.TcpClientSession;
2427
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
2528
import org.geysermc.mcprotocollib.protocol.codec.MinecraftPacket;
2629
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
30+
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
2731
import org.slf4j.Logger;
2832
import org.slf4j.LoggerFactory;
2933

@@ -53,8 +57,9 @@ public abstract class AbstractRobot implements ISendable, SessionProvider, IOpti
5357
protected short port;
5458
protected String name;
5559
private String profileName;
60+
protected List<String> owners = new ArrayList<>();
5661
protected String password;
57-
private final CommandSpec commands = new CommandSpec();
62+
protected final CommandSpec commands = new CommandSpec();
5863

5964
public AbstractRobot(ConfigManager configManager, PluginManager pluginManager){
6065
this.config = configManager;
@@ -71,17 +76,27 @@ public AbstractRobot(ConfigManager configManager, PluginManager pluginManager){
7176
this.TIME_OUT = Integer.parseInt((String) this.config.getConfigValue("connect-timing-out"));
7277
this.ReconnectionDelay = Integer.parseInt((String) this.config.getConfigValue("reconnect-delay"));
7378

74-
this.commands.register(new CommandBuilder().withName("reload").allowedUsers(config.getConfigValue("owner")).build((act)->{
75-
this.pluginManager.reloadPlugin(this, act.getCommandList()[1].toLowerCase());
76-
}));
77-
7879
}
7980

8081
public AbstractRobot withName(String userName){
8182
this.name = userName;
8283
return this;
8384
}
8485

86+
public AbstractRobot withOwners(String... owners) {
87+
this.owners = List.of(owners);
88+
return this;
89+
}
90+
91+
public AbstractRobot withOwners(List<JsonElement> owners) {
92+
List<String> stringOwners = new ArrayList<>();
93+
for (JsonElement obj : owners) {
94+
stringOwners.add(obj.getAsString());
95+
}
96+
this.owners = stringOwners;
97+
return this;
98+
}
99+
85100
public AbstractRobot withPassword(String password){
86101
this.password = password;
87102
return this;
@@ -147,12 +162,15 @@ public void connect(){
147162
})));
148163

149164
this.serverSession.addListener(new AddEntityPacket().addExtraAction((entityPacket -> {
150-
if (this.onlinePlayers.get(entityPacket.getEntityId()) == null) {
151-
this.onlinePlayers.put(entityPacket.getEntityId(), new Player(entityPacket.getEntityId(), new Position(entityPacket.getX(), entityPacket.getY(), entityPacket.getZ())));
165+
if (entityPacket.getType() == EntityType.PLAYER) {
166+
if (this.onlinePlayers.get(entityPacket.getEntityId()) == null) {
167+
this.onlinePlayers.put(entityPacket.getEntityId(), new Player(entityPacket.getEntityId(), new Position(entityPacket.getX(), entityPacket.getY(), entityPacket.getZ())));
168+
}
152169
}
153170
})));
154171
this.serverSession.addListener(new TeleportEntityPacket().addExtraAction((teleportEntityPacket -> {
155172
this.onlinePlayers.get(teleportEntityPacket.getId()).setPosition(teleportEntityPacket.getPosition().getX(), teleportEntityPacket.getPosition().getX(), teleportEntityPacket.getPosition().getZ());
173+
156174
})));
157175
this.serverSession.addListener(new PlayerPositionPacket().addExtraAction((packet->{
158176
log.info(ConsoleTokens.colorizeText("&7Login At Position &b{}"), packet.getPosition());

0 commit comments

Comments
 (0)