From 30cbabe1c87e6d5dfbf18279b4d714aceb377a01 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sun, 27 Sep 2020 19:26:42 +0200 Subject: [PATCH] wip modding (4): event api, logger, example in Modding.md --- doc/Modding.md | 55 ++++++++++- .../java/de/bixilon/minosoft/logging/Log.java | 6 +- .../de/bixilon/minosoft/modding/Logger.java | 93 +++++++++++++++++++ .../bixilon/minosoft/modding/MinosoftMod.java | 32 +++++++ .../minosoft/modding/event/EventListener.java | 22 +++++ .../events/ChatMessageReceivingEvent.java | 47 ++++++++++ .../minosoft/modding/event/events/Event.java | 29 ++++++ .../event/events/MaximumProtocolVersion.java | 18 ++++ .../event/events/MinimumProtocolVersion.java | 18 ++++ .../minosoft/modding/loading/ModLoader.java | 3 +- .../play/PacketChatMessageReceiving.java | 13 +-- .../bixilon/minosoft/util/ServerAddress.java | 14 +++ 12 files changed, 335 insertions(+), 15 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/modding/Logger.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/EventListener.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/events/ChatMessageReceivingEvent.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/events/Event.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/events/MaximumProtocolVersion.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/events/MinimumProtocolVersion.java diff --git a/doc/Modding.md b/doc/Modding.md index 83d3740e3..41b25d020 100644 --- a/doc/Modding.md +++ b/doc/Modding.md @@ -68,4 +68,57 @@ There are different phases (states) for the loading. There are the following pha The most important thing is performance. To archive fast loading times, etc, all mods (if they don't on each other) are getting loaded async. One phase is completed (= Next phase starts), once all mods have completed the previous phase. Everything is async. -If your start function needs much time, you can set the loading priority in the `mod.json` to start at the beginning. The `start` method returns a success boolean. \ No newline at end of file +If your start function needs much time, you can set the loading priority in the `mod.json` to start at the beginning. The `start` method returns a success boolean. + +## Getting started +Add Minosoft to your maven dependencies with +Repository: +```xml + + + jitpack.io + https://jitpack.io + + +``` +Dependency: +```xml + + de.bixilon.gitlab.bixilon + minosoft + master-SNAPSHOT + + +``` +Create a Main class, here is an example +```java +package de.bixilon.example.mod.main; + +import de.bixilon.minosoft.modding.MinosoftMod; +import de.bixilon.minosoft.modding.loading.ModPhases; + +public class TestMod extends MinosoftMod { + public boolean start(ModPhases phase) { + if (phase == ModPhases.BOOTING) { + getLogger().info("Hello world!"); + } + return true; + } +} +``` +Your `mod.json` can look like this +```json +{ + "uuid": "1f37a8e0-9ec7-45db-ad2f-40afd2eb5a07", + "versionId": 1, + "versionName": "1.0", + "authors": ["Bixilon"], + "name": "Example Mod", + "identifier": "example", + "mainClass": "de.bixilon.example.mod.main.TestMod" +} +``` + +## Events +There are global events (which works on all connections) and connections events (server specific). + diff --git a/src/main/java/de/bixilon/minosoft/logging/Log.java b/src/main/java/de/bixilon/minosoft/logging/Log.java index 77ce4a227..ccd91f600 100644 --- a/src/main/java/de/bixilon/minosoft/logging/Log.java +++ b/src/main/java/de/bixilon/minosoft/logging/Log.java @@ -25,8 +25,8 @@ public class Log { static LogLevels level = LogLevels.PROTOCOL; static Thread logThread; - public static void log(LogLevels l, String message, TextComponent.ChatAttributes color) { - if (l.ordinal() > level.ordinal()) { + public static void log(LogLevels level, String message, TextComponent.ChatAttributes color) { + if (level.ordinal() > Log.level.ordinal()) { // log level too low return; } @@ -36,7 +36,7 @@ public class Log { builder.append("] ["); builder.append(Thread.currentThread().getName()); builder.append("] ["); - builder.append(l.name()); + builder.append(level.name()); builder.append("] "); if (color != null && Config.colorLog) { builder.append(color); diff --git a/src/main/java/de/bixilon/minosoft/modding/Logger.java b/src/main/java/de/bixilon/minosoft/modding/Logger.java new file mode 100644 index 000000000..50f2979a8 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/Logger.java @@ -0,0 +1,93 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding; + +import de.bixilon.minosoft.game.datatypes.TextComponent; +import de.bixilon.minosoft.logging.Log; +import de.bixilon.minosoft.logging.LogLevels; + +public class Logger { + private final String modName; + + public Logger(String modName) { + this.modName = modName; + } + + public void log(LogLevels level, String message, TextComponent.ChatAttributes color) { + Log.log(level, String.format("[%s] %s", modName, message), color); + } + + /** + * Logs all game related things (chunk loading, rendering, ...) + * + * @param message Raw message to log + */ + public void game(String message) { + log(LogLevels.GAME, message, TextComponent.ChatAttributes.GREEN); + } + + /** + * Logs all fatal errors (critical exceptions, etc) + * + * @param message Raw message to log + */ + public void fatal(String message) { + log(LogLevels.FATAL, message, TextComponent.ChatAttributes.DARK_RED); + } + + /** + * Logs all general infos (connecting to server, ...) + * + * @param message Raw message to log + */ + public void info(String message) { + log(LogLevels.INFO, message, TextComponent.ChatAttributes.WHITE); + } + + /** + * Logs all warnings (connection to server failed, ...) + * + * @param message Raw message to log + */ + public void warn(String message) { + log(LogLevels.WARNING, message, TextComponent.ChatAttributes.RED); + } + + /** + * Logs all debug relevant infos (...) + * + * @param message Raw message to log + */ + public void debug(String message) { + log(LogLevels.DEBUG, message, TextComponent.ChatAttributes.GRAY); + } + + /** + * Logs all debug relevant infos (even higher level!) (connection status, ...) + * + * @param message Raw message to log + */ + public void verbose(String message) { + log(LogLevels.VERBOSE, message, TextComponent.ChatAttributes.YELLOW); + } + + /** + * Logs all protocol data (received protocol with length and command x,...) + * + * @param message Raw message to log + */ + public void protocol(String message) { + log(LogLevels.PROTOCOL, message, TextComponent.ChatAttributes.BLUE); + } +} diff --git a/src/main/java/de/bixilon/minosoft/modding/MinosoftMod.java b/src/main/java/de/bixilon/minosoft/modding/MinosoftMod.java index 5ba2bb1d7..eda193113 100644 --- a/src/main/java/de/bixilon/minosoft/modding/MinosoftMod.java +++ b/src/main/java/de/bixilon/minosoft/modding/MinosoftMod.java @@ -13,11 +13,43 @@ package de.bixilon.minosoft.modding; +import de.bixilon.minosoft.modding.loading.ModInfo; import de.bixilon.minosoft.modding.loading.ModPhases; interface MinosoftModInterface { + /** + * @param phase The current loading phase + * @return If the loading was successful. If not, the mod is getting disabled. + */ boolean start(ModPhases phase); } public abstract class MinosoftMod implements MinosoftModInterface { + protected boolean enabled = false; + private ModInfo info; + private Logger logger; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public ModInfo getInfo() { + return info; + } + + public void setInfo(ModInfo info) { + if (this.info != null) { + throw new RuntimeException(String.format("Mod info already set %s vs %s", this.info, info)); + } + this.info = info; + this.logger = new Logger(info.getName()); + } + + public Logger getLogger() { + return logger; + } } \ No newline at end of file diff --git a/src/main/java/de/bixilon/minosoft/modding/event/EventListener.java b/src/main/java/de/bixilon/minosoft/modding/event/EventListener.java new file mode 100644 index 000000000..4b730036d --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/EventListener.java @@ -0,0 +1,22 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event; + +import de.bixilon.minosoft.modding.event.events.ChatMessageReceivingEvent; + +public class EventListener { + public void onChatMessageReceiving(ChatMessageReceivingEvent event) { + } + +} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/ChatMessageReceivingEvent.java b/src/main/java/de/bixilon/minosoft/modding/event/events/ChatMessageReceivingEvent.java new file mode 100644 index 000000000..4967d7f3f --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/ChatMessageReceivingEvent.java @@ -0,0 +1,47 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event.events; + +import de.bixilon.minosoft.game.datatypes.ChatTextPositions; +import de.bixilon.minosoft.game.datatypes.TextComponent; + +import java.util.UUID; + +public class ChatMessageReceivingEvent extends Event { + private final TextComponent message; + private final ChatTextPositions position; + private final UUID sender; + + public ChatMessageReceivingEvent(TextComponent message, ChatTextPositions position, UUID sender) { + this.message = message; + this.position = position; + this.sender = sender; + } + + public TextComponent getMessage() { + return message; + } + + public ChatTextPositions getPosition() { + return position; + } + + /** + * @return The uuid of the sender + */ + @MinimumProtocolVersion(protocolId = 718) + public UUID getSender() { + return this.sender; + } +} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/Event.java b/src/main/java/de/bixilon/minosoft/modding/event/events/Event.java new file mode 100644 index 000000000..fe9c8dc42 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/Event.java @@ -0,0 +1,29 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event.events; + +public class Event { + boolean cancelled = false; + + protected Event() { + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } +} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/MaximumProtocolVersion.java b/src/main/java/de/bixilon/minosoft/modding/event/events/MaximumProtocolVersion.java new file mode 100644 index 000000000..492a4375e --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/MaximumProtocolVersion.java @@ -0,0 +1,18 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event.events; + +public @interface MaximumProtocolVersion { + int protocolId() default Integer.MAX_VALUE; +} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/MinimumProtocolVersion.java b/src/main/java/de/bixilon/minosoft/modding/event/events/MinimumProtocolVersion.java new file mode 100644 index 000000000..8547443bb --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/MinimumProtocolVersion.java @@ -0,0 +1,18 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event.events; + +public @interface MinimumProtocolVersion { + int protocolId() default 0; +} diff --git a/src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java b/src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java index 2464b9063..7bf391ea9 100644 --- a/src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java +++ b/src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java @@ -28,8 +28,6 @@ import java.util.zip.ZipFile; public class ModLoader { static TreeMap modMap; - ModPhases currentPhase; - public static void loadMods() { modMap = new TreeMap<>((a, b) -> { LoadingPriorities priorityA = getLoadingPriorityOrDefault(a); @@ -61,6 +59,7 @@ public class ModLoader { JclObjectFactory factory = JclObjectFactory.getInstance(); MinosoftMod instance = (MinosoftMod) factory.create(jcl, modInfo.getMainClass()); + instance.setInfo(modInfo); Log.verbose(String.format("[MOD] Mod file loaded (%s)", modInfo)); modMap.put(modInfo, instance); zipFile.close(); diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChatMessageReceiving.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChatMessageReceiving.java index a1898683a..554b5c319 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChatMessageReceiving.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChatMessageReceiving.java @@ -29,20 +29,15 @@ public class PacketChatMessageReceiving implements ClientboundPacket { @Override public boolean read(InByteBuffer buffer) { + message = buffer.readTextComponent(); if (buffer.getProtocolId() < 7) { - message = buffer.readTextComponent(); position = ChatTextPositions.CHAT_BOX; return true; } - if (buffer.getProtocolId() < 718) { - message = buffer.readTextComponent(); - position = ChatTextPositions.byId(buffer.readByte()); - return true; - } - - message = buffer.readTextComponent(); position = ChatTextPositions.byId(buffer.readByte()); - sender = buffer.readUUID(); + if (buffer.getProtocolId() >= 718) { + sender = buffer.readUUID(); + } return true; } diff --git a/src/main/java/de/bixilon/minosoft/util/ServerAddress.java b/src/main/java/de/bixilon/minosoft/util/ServerAddress.java index 5e7968c2a..d6e69db46 100644 --- a/src/main/java/de/bixilon/minosoft/util/ServerAddress.java +++ b/src/main/java/de/bixilon/minosoft/util/ServerAddress.java @@ -34,4 +34,18 @@ public class ServerAddress { public String toString() { return getHostname() + ":" + getPort(); } + + @Override + public int hashCode() { + return hostname.hashCode() * port; + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + return true; + } + ServerAddress their = (ServerAddress) obj; + return hostname.equals(their.getHostname()) && port == their.getPort(); + } }