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

Overhaul project setup #7

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Combine examples into singular plugin, with Java and Kotlin
zt64 committed Jul 6, 2024
commit f3c86920f5674cfb700cae3fd72db15f6a7f70dd

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version = "1.0.0" // Plugin version. Increment this to trigger the updater
description = "My first commands!" // Plugin description that will be shown to user
description = "My first Java plugin!" // Plugin description that will be shown to user

aliucord {
// Changelog of your plugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.github.yournamehere;

import android.content.Context;

import com.aliucord.Utils;
import com.aliucord.annotations.AliucordPlugin;
import com.aliucord.api.CommandsAPI;
import com.aliucord.entities.MessageEmbedBuilder;
import com.aliucord.entities.Plugin;
import com.aliucord.patcher.Hook;
import com.aliucord.patcher.InsteadHook;
import com.aliucord.patcher.PreHook;
import com.aliucord.wrappers.embeds.MessageEmbedWrapper;
import com.discord.api.commands.ApplicationCommandType;
import com.discord.models.user.CoreUser;
import com.discord.stores.StoreUserTyping;
import com.discord.widgets.chat.list.adapter.WidgetChatListAdapterItemMessage;
import com.discord.widgets.chat.list.entries.ChatListEntry;
import com.discord.widgets.chat.list.entries.MessageEntry;

import java.util.Arrays;
import java.util.Objects;

// Aliucord Plugin annotation. Must be present on the main class of your plugin
// Plugin class. Must extend Plugin and override start and stop
// Learn more: https://github.com/Aliucord/documentation/blob/main/plugin-dev/1_introduction.md#basic-plugin-structure
@AliucordPlugin(
requiresRestart = false // Whether your plugin requires a restart after being installed/updated
)
class MyFirstJavaPlugin extends Plugin {
@Override
public void start(Context context) throws Throwable {
// Register a command with the name hello and description "My first command!" and no arguments.
// Learn more: https://github.com/Aliucord/documentation/blob/main/plugin-dev/2_commands.md
commands.registerCommand("hello", "My first command!", ctx -> {
// Just return a command result with hello world as the content
return new CommandsAPI.CommandResult(
"Hello World!",
null, // List of embeds
false // Whether to send visible for everyone
);
});

// A bit more advanced command with arguments
commands.registerCommand(
"hellowitharguments",
"Hello World but with arguments!",
Arrays.asList(
Utils.createCommandOption(ApplicationCommandType.STRING, "name", "Person to say hello to"),
Utils.createCommandOption(ApplicationCommandType.USER, "user", "User to say hello to")
),
ctx -> {
String username;

// Check if a user argument was passed
if (ctx.containsArg("user")) {
username = ctx.getRequiredUser("user").getUsername();
} else {
// Returns either the argument value if present, or the defaultValue ("World" in this case)
username = ctx.getStringOrDefault("name", "World");
}

// Return the final result that will be displayed in chat as a response to the command
return new CommandsAPI.CommandResult("Hello " + username + "!");
}
);

// Patch that adds an embed with message statistics to each message
// Patched method is WidgetChatListAdapterItemMessage.onConfigure(int type, ChatListEntry entry)
patcher.patch(WidgetChatListAdapterItemMessage.class.getDeclaredMethod("onConfigure", int.class, ChatListEntry.class), new Hook(param -> {
// see https://api.xposed.info/reference/de/robv/android/xposed/XC_MethodHook.MethodHookParam.html
// Obtain the second argument passed to the method, so the ChatListEntry
// Because this is a Message item, it will always be a MessageEntry, so cast it to that
var entry = (MessageEntry) param.args[1];
var message = entry.getMessage();

// You need to be careful when messing with messages, because they may be loading
// (user sent a message, and it is currently sending)
if (message.isLoading()) return;

// Now add an embed with the statistics

// This method may be called multiple times per message, e.g. if it is edited,
// so first remove existing embeds
message.getEmbeds().removeIf(it -> Objects.equals(new MessageEmbedWrapper(it).getTitle(), "Message Statistics"));

// Creating embeds is a pain, so Aliucord provides a convenient builder
var embed = new MessageEmbedBuilder()
.setTitle("Message Statistics")
.addField("Length", message.getContent() != null ? Integer.toString(message.getContent().length()) : "0", false)
.addField("ID", Long.toString(message.getId()), false).build();

message.getEmbeds().add(embed);
}));

// Patch that renames Juby to JoobJoob
patcher.patch(
CoreUser.class.getDeclaredMethod("getUsername"),
new PreHook(param -> { // see https://api.xposed.info/reference/de/robv/android/xposed/XC_MethodHook.MethodHookParam.html
if (((CoreUser) param.thisObject).getId() == 925141667688878090L) {
// setResult() in before patches skips original method invocation
param.setResult("JoobJoob");
}
})
);

// Patch that hides your typing status by replacing the method and simply doing nothing
// This patches the method StoreUserTyping.setUserTyping(long channelId)
patcher.patch(StoreUserTyping.class.getDeclaredMethod("setUserTyping", long.class), InsteadHook.DO_NOTHING);
}

@Override
public void stop(Context context) {
// Remove all patches
patcher.unpatchAll();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version = "1.0.0" // Plugin version. Increment this to trigger the updater
description = "My first patch!" // Plugin description that will be shown to user
description = "My first Kotlin plugin!" // Plugin description that will be shown to user

aliucord {
// Changelog of your plugin
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.github.yournamehere

import android.content.Context
import com.aliucord.Utils
import com.aliucord.annotations.AliucordPlugin
import com.aliucord.api.CommandsAPI
import com.aliucord.entities.MessageEmbedBuilder
import com.aliucord.entities.Plugin
import com.aliucord.patcher.*
import com.aliucord.wrappers.embeds.MessageEmbedWrapper.Companion.title
import com.discord.api.commands.ApplicationCommandType
import com.discord.models.user.CoreUser
import com.discord.stores.StoreUserTyping
import com.discord.widgets.chat.list.adapter.WidgetChatListAdapterItemMessage
@@ -18,11 +21,51 @@ import com.discord.widgets.chat.list.entries.MessageEntry
@AliucordPlugin(
requiresRestart = false // Whether your plugin requires a restart after being installed/updated
)
class MyFirstPatch : Plugin() {
class MyFirstKotlinPlugin : Plugin() {
override fun start(context: Context) {
// Register a command with the name hello and description "My first command!" and no arguments.
// Learn more: https://github.com/Aliucord/documentation/blob/main/plugin-dev/2_commands.md
commands.registerCommand("hello", "My first command!") {
// Just return a command result with hello world as the content
CommandsAPI.CommandResult(
"Hello World!",
null, // List of embeds
false // Whether to send visible for everyone
)
}

// A bit more advanced command with arguments
commands.registerCommand(
"hellowitharguments",
"Hello World but with arguments!",
listOf(
Utils.createCommandOption(
ApplicationCommandType.STRING,
"name",
"Person to say hello to"
),
Utils.createCommandOption(
ApplicationCommandType.USER,
"user",
"User to say hello to"
)
)
) { ctx ->
// Check if a user argument was passed
val username = if (ctx.containsArg("user")) {
ctx.getRequiredUser("user").username
} else {
// Returns either the argument value if present, or the defaultValue ("World" in this case)
ctx.getStringOrDefault("name", "World")
}

// Return the final result that will be displayed in chat as a response to the command
CommandsAPI.CommandResult("Hello $username!")
}

// Patch that adds an embed with message statistics to each message
// Patched method is WidgetChatListAdapterItemMessage.onConfigure(int type, ChatListEntry entry)
patcher.after<WidgetChatListAdapterItemMessage> /* Class whose method to patch */(
patcher.after<WidgetChatListAdapterItemMessage>(
"onConfigure", // Method name
// Refer to https://kotlinlang.org/docs/reflection.html#class-references
// and https://docs.oracle.com/javase/tutorial/reflect/class/classNew.html
@@ -33,16 +76,17 @@ class MyFirstPatch : Plugin() {
// Obtain the second argument passed to the method, so the ChatListEntry
// Because this is a Message item, it will always be a MessageEntry, so cast it to that
val entry = param.args[1] as MessageEntry
val message = entry.message

// You need to be careful when messing with messages, because they may be loading
// (user sent a message, and it is currently sending)
if (entry.message.isLoading) return@after
if (message.isLoading) return@after

// Now add an embed with the statistics

// This method may be called multiple times per message, e.g. if it is edited,
// so first remove existing embeds
entry.message.embeds.removeIf {
message.embeds.removeIf {
// MessageEmbed.getTitle() is actually obfuscated, but Aliucord provides extensions for commonly used
// obfuscated Discord classes, so just import the MessageEmbed.title extension and boom goodbye obfuscation!
it.title == "Message Statistics"
@@ -51,10 +95,10 @@ class MyFirstPatch : Plugin() {
// Creating embeds is a pain, so Aliucord provides a convenient builder
MessageEmbedBuilder().run {
setTitle("Message Statistics")
addField("Length", (entry.message.content?.length ?: 0).toString(), false)
addField("ID", entry.message.id.toString(), false)
addField("Length", "${message.content?.length ?: 0}", false)
addField("ID", message.id.toString(), false)

entry.message.embeds.add(build())
message.embeds.add(build())
}
}

1 change: 1 addition & 0 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ subprojects {
}

configure<LibraryExtension> {
// TODO: Change to your package name
namespace = "com.github.yournamehere"

compileSdk = 34