diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f12e409
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/MinetestChatBridgeBot/.gradle/
+/MinetestChatBridgeBot/build/
+/MinetestChatBridgeIRCBot/.gradle/
+/MinetestChatBridgeIRCBot/build/
\ No newline at end of file
diff --git a/MinetestChatBridgeBot/.classpath b/MinetestChatBridgeBot/.classpath
new file mode 100644
index 0000000..9f9cc9f
--- /dev/null
+++ b/MinetestChatBridgeBot/.classpath
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MinetestChatBridgeBot/.project b/MinetestChatBridgeBot/.project
new file mode 100644
index 0000000..e04c6b6
--- /dev/null
+++ b/MinetestChatBridgeBot/.project
@@ -0,0 +1,23 @@
+
+
+ MinetestChatBridgeBot
+ Project MinetestChatBridgeBot created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/MinetestChatBridgeBot/.settings/org.eclipse.buildship.core.prefs b/MinetestChatBridgeBot/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..7a23d11
--- /dev/null
+++ b/MinetestChatBridgeBot/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(5.6.1))
+connection.project.dir=
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/MinetestChatBridgeBot/bin/main/appguru/Main.class b/MinetestChatBridgeBot/bin/main/appguru/Main.class
new file mode 100644
index 0000000..3250d08
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/appguru/Main.class differ
diff --git a/MinetestChatBridgeBot/bin/main/bridge/FileBridge$1.class b/MinetestChatBridgeBot/bin/main/bridge/FileBridge$1.class
new file mode 100644
index 0000000..5fe5e20
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/bridge/FileBridge$1.class differ
diff --git a/MinetestChatBridgeBot/bin/main/bridge/FileBridge.class b/MinetestChatBridgeBot/bin/main/bridge/FileBridge.class
new file mode 100644
index 0000000..23b2d79
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/bridge/FileBridge.class differ
diff --git a/MinetestChatBridgeBot/bin/main/bridge/ProcessBridge.class b/MinetestChatBridgeBot/bin/main/bridge/ProcessBridge.class
new file mode 100644
index 0000000..13c0ce8
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/bridge/ProcessBridge.class differ
diff --git a/MinetestChatBridgeBot/bin/main/bridge/SocketBridge.class b/MinetestChatBridgeBot/bin/main/bridge/SocketBridge.class
new file mode 100644
index 0000000..b41e7df
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/bridge/SocketBridge.class differ
diff --git a/MinetestChatBridgeBot/bin/main/chat/Bot.class b/MinetestChatBridgeBot/bin/main/chat/Bot.class
new file mode 100644
index 0000000..0fbac22
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/chat/Bot.class differ
diff --git a/MinetestChatBridgeBot/bin/main/commands/Command.class b/MinetestChatBridgeBot/bin/main/commands/Command.class
new file mode 100644
index 0000000..25dd751
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/commands/Command.class differ
diff --git a/MinetestChatBridgeBot/bin/main/commands/StatusCommand.class b/MinetestChatBridgeBot/bin/main/commands/StatusCommand.class
new file mode 100644
index 0000000..2651dd7
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/commands/StatusCommand.class differ
diff --git a/MinetestChatBridgeBot/bin/main/misc/GarbageCollector.class b/MinetestChatBridgeBot/bin/main/misc/GarbageCollector.class
new file mode 100644
index 0000000..cf045ad
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/misc/GarbageCollector.class differ
diff --git a/MinetestChatBridgeBot/bin/main/misc/Utils.class b/MinetestChatBridgeBot/bin/main/misc/Utils.class
new file mode 100644
index 0000000..7fabb06
Binary files /dev/null and b/MinetestChatBridgeBot/bin/main/misc/Utils.class differ
diff --git a/MinetestChatBridgeBot/build.gradle b/MinetestChatBridgeBot/build.gradle
new file mode 100644
index 0000000..90bd796
--- /dev/null
+++ b/MinetestChatBridgeBot/build.gradle
@@ -0,0 +1,37 @@
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'com.github.johnrengelman.shadow'
+apply plugin: 'jacoco'
+apply plugin: 'application'
+
+
+description = 'Minetest Chat Bridge Discord Bot'
+mainClassName = 'appguru.Main'
+
+repositories {
+ mavenCentral()
+ jcenter()
+}
+
+dependencies {
+ compile "net.dv8tion:JDA:4.0.0_39", 'ch.qos.logback:logback-classic:1.3.0-alpha4'
+ compile group: 'com.google.guava', name: 'guava', version: '23.5-jre'
+ testCompile group: 'junit', name: 'junit', version: '4.12'
+}
+
+jar {
+ manifest {
+ attributes(
+ 'Created-By': "Gradle ${gradle.gradleVersion}",
+ 'Main-Class': "appguru.Main"
+ )
+ }
+}
\ No newline at end of file
diff --git a/MinetestChatBridgeBot/gradle.properties b/MinetestChatBridgeBot/gradle.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/MinetestChatBridgeBot/gradle.properties
@@ -0,0 +1 @@
+
diff --git a/MinetestChatBridgeBot/settings.gradle b/MinetestChatBridgeBot/settings.gradle
new file mode 100644
index 0000000..a9edce5
--- /dev/null
+++ b/MinetestChatBridgeBot/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'MinetestChatBridgeBot'
diff --git a/minetest-chat-bridge-bot/src/main/java/appguru/Main.java b/MinetestChatBridgeBot/src/main/java/appguru/Main.java
similarity index 79%
rename from minetest-chat-bridge-bot/src/main/java/appguru/Main.java
rename to MinetestChatBridgeBot/src/main/java/appguru/Main.java
index f88fccc..4c2cadd 100644
--- a/minetest-chat-bridge-bot/src/main/java/appguru/Main.java
+++ b/MinetestChatBridgeBot/src/main/java/appguru/Main.java
@@ -1,6 +1,8 @@
package appguru;
+import bridge.FileBridge;
import bridge.ProcessBridge;
+import bridge.SocketBridge;
import chat.Bot;
import commands.StatusCommand;
import misc.GarbageCollector;
@@ -15,12 +17,15 @@ import java.util.Date;
public class Main {
public static long STARTED_AT;
public static int GARBAGE_COLLECTION=5000; //5s
- public static long PING_WAIT=20000; //20s
+ public static long PING_WAIT=5000; //5s
public static String PREFIX="!";
public static String DISCORD_PREFIX="?";
public static String GUILD_ID=null;
public static PrintStream OUT=System.out;
+
+ public static ProcessBridge PROCESS_BRIDGE;
+
public static void main(String[] args) throws IOException {
if (args.length > 4) {
@@ -60,16 +65,22 @@ public class Main {
OUT.println("INFO: Starting Minetest chat bridge");
String token=args[0];
String channelname=args[1];
- File in=new File(args[2]);
- File out=new File(args[3]);
- if (!in.isFile() || !out.isFile() || !in.canWrite() || !in.canRead() || !out.canWrite() || !out.canRead()) {
- OUT.println("ERR: Input or output files do not exist or can't be read/written.");
- OUT.close();
- System.exit(0);
+
+ if (args[2].length() == 0) {
+ int socket_port=Integer.parseInt(args[3]);
+ PROCESS_BRIDGE=new SocketBridge("localhost", socket_port);
+ } else {
+ File in=new File(args[2]);
+ File out=new File(args[3]);
+ if (!in.isFile() || !out.isFile() || !in.canWrite() || !in.canRead() || !out.canWrite() || !out.canRead()) {
+ OUT.println("ERR: Input or output files do not exist or can't be read/written.");
+ System.exit(0);
+ }
+ PROCESS_BRIDGE=new FileBridge(in, out);
}
- ProcessBridge pb=new ProcessBridge(in, out);
+
try {
- Bot i=new Bot(token, pb, channelname);
+ Bot i=new Bot(token, PROCESS_BRIDGE, channelname);
i.registerInfo("status", "Status", "", Color.CYAN, null);
i.registerCommand("status", new StatusCommand());
diff --git a/minetest-chat-bridge-bot/src/main/java/bridge/ProcessBridge.java b/MinetestChatBridgeBot/src/main/java/bridge/FileBridge.java
similarity index 77%
rename from minetest-chat-bridge-bot/src/main/java/bridge/ProcessBridge.java
rename to MinetestChatBridgeBot/src/main/java/bridge/FileBridge.java
index d24ad4d..42ea77e 100644
--- a/minetest-chat-bridge-bot/src/main/java/bridge/ProcessBridge.java
+++ b/MinetestChatBridgeBot/src/main/java/bridge/FileBridge.java
@@ -5,21 +5,18 @@ import appguru.Main;
import java.io.*;
import java.util.function.Consumer;
-public class ProcessBridge {
- public static long PING_WAIT=20000; //20s
+public class FileBridge extends ProcessBridge {
- public long last_ping;
- public void ping() {
- last_ping=System.currentTimeMillis();
- }
public File out_file;
public File in;
public PrintWriter out;
+ private long last_ping_sent;
- public ProcessBridge(File in, File out) throws IOException {
+ public FileBridge(File in, File out) throws IOException {
this.out = new PrintWriter(new BufferedWriter(new FileWriter(out, true)));
this.out_file=out;
this.in=in;
+ this.last_ping_sent=System.currentTimeMillis();
}
public void kill(String reason) {
@@ -30,9 +27,11 @@ public class ProcessBridge {
fw.write("");
fw.close();
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
Main.OUT.close();
+ out.write("[KIL]"+reason);
+ out.close();
System.exit(0);
}
@@ -47,15 +46,18 @@ public class ProcessBridge {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
- Main.OUT.flush();
+ if (System.currentTimeMillis()-last_ping_sent >= 1000) {
+ out.write("[PIN]");
+ }
+ // Main.OUT.flush();
out.flush();
out.close();
try {
out = new PrintWriter(new BufferedWriter(new FileWriter(out_file, true)));
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
}
}
@@ -71,19 +73,19 @@ public class ProcessBridge {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
BufferedReader r = null;
try {
r = new BufferedReader(new FileReader(in));
} catch (FileNotFoundException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
String line = null;
try {
line = r.readLine();
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
boolean one_line = line != null;
while (line != null) {
@@ -99,7 +101,7 @@ public class ProcessBridge {
try {
line = r.readLine();
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
}
if (System.currentTimeMillis()-last_ping > Main.PING_WAIT) {
@@ -109,7 +111,7 @@ public class ProcessBridge {
try {
FileWriter fw = new FileWriter(in);fw.write("");fw.close();
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
}
}
diff --git a/MinetestChatBridgeBot/src/main/java/bridge/ProcessBridge.java b/MinetestChatBridgeBot/src/main/java/bridge/ProcessBridge.java
new file mode 100644
index 0000000..48e4a88
--- /dev/null
+++ b/MinetestChatBridgeBot/src/main/java/bridge/ProcessBridge.java
@@ -0,0 +1,18 @@
+package bridge;
+
+import java.util.function.Consumer;
+
+public abstract class ProcessBridge {
+ public long last_ping;
+ public void ping() {
+ last_ping=System.currentTimeMillis();
+ }
+
+ public abstract void kill(String reason);
+
+ public abstract void write(String out);
+
+ public abstract void serve();
+
+ public abstract void listen(Consumer line_consumer);
+}
\ No newline at end of file
diff --git a/MinetestChatBridgeBot/src/main/java/bridge/SocketBridge.java b/MinetestChatBridgeBot/src/main/java/bridge/SocketBridge.java
new file mode 100644
index 0000000..602d9b1
--- /dev/null
+++ b/MinetestChatBridgeBot/src/main/java/bridge/SocketBridge.java
@@ -0,0 +1,112 @@
+package bridge;
+
+import appguru.Main;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.function.Consumer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author lars
+ */
+public class SocketBridge extends ProcessBridge {
+ private Socket socket;
+ private final BufferedWriter writer;
+ private BufferedReader reader;
+
+ public SocketBridge(String host, int port) throws IOException {
+ socket = new Socket();
+ socket.connect(new InetSocketAddress(host, port));
+ writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
+ reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ }
+
+ @Override
+ public void kill(String reason) {
+ Main.OUT.println("INFO: "+reason);
+ if (socket.isConnected()) {
+ try {
+ writer.write("[KIL]"+reason);
+ } catch (IOException ex) {
+ ex.printStackTrace(Main.OUT);
+ }
+ }
+ try {
+ writer.close();
+ reader.close();
+ socket.close();
+ } catch (IOException ex) {
+ ex.printStackTrace(Main.OUT);
+ } finally {
+ Main.OUT.close();
+ System.exit(1);
+ }
+ }
+
+ @Override
+ public void write(String out) {
+ synchronized (writer) {
+ try {
+ writer.write(out+"\n");
+ writer.flush();
+ } catch (IOException ex) {
+ ex.printStackTrace(Main.OUT);
+ }
+ }
+ }
+
+ @Override
+ public void serve() {
+ }
+
+ @Override
+ public void listen(Consumer line_consumer) {
+ ping();
+ new Thread(() -> {
+ while(true) {
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace(Main.OUT);
+ }
+ String line = null;
+ try {
+ line = reader.readLine();
+ } catch (IOException e) {
+ e.printStackTrace(Main.OUT);
+ if (socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) {
+ kill("Socket connection lost");
+ }
+ }
+ boolean one_line = line != null;
+ while (line != null) {
+
+ if (line.startsWith("[PIN]")) { // A PING YAY
+ ping();
+ } else if (line.startsWith("[KIL]")) {
+ kill("Minetest server shutting down; shutting down as well.");
+ } else {
+ line_consumer.accept(line);
+ }
+
+ try {
+ line = reader.readLine();
+ } catch (IOException e) {
+ e.printStackTrace(Main.OUT);
+ }
+ }
+ if (System.currentTimeMillis()-last_ping > Main.PING_WAIT) {
+ kill("No ping during the last "+(Main.PING_WAIT/1000)+"s; shutting down.");
+ }
+ }
+ }).start();
+ }
+
+}
diff --git a/minetest-chat-bridge-bot/src/main/java/chat/Bot.java b/MinetestChatBridgeBot/src/main/java/chat/Bot.java
similarity index 87%
rename from minetest-chat-bridge-bot/src/main/java/chat/Bot.java
rename to MinetestChatBridgeBot/src/main/java/chat/Bot.java
index bfda5f4..a5b0c6a 100644
--- a/minetest-chat-bridge-bot/src/main/java/chat/Bot.java
+++ b/MinetestChatBridgeBot/src/main/java/chat/Bot.java
@@ -5,44 +5,32 @@ import bridge.ProcessBridge;
import com.google.common.collect.HashBiMap;
import commands.Command;
import misc.Utils;
-import net.dv8tion.jda.core.*;
-import net.dv8tion.jda.core.entities.*;
-import net.dv8tion.jda.core.events.ReadyEvent;
-import net.dv8tion.jda.core.events.channel.text.TextChannelCreateEvent;
-import net.dv8tion.jda.core.events.channel.text.TextChannelDeleteEvent;
-import net.dv8tion.jda.core.events.channel.text.update.*;
-import net.dv8tion.jda.core.events.guild.GuildJoinEvent;
-import net.dv8tion.jda.core.events.guild.member.*;
-import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
-import net.dv8tion.jda.core.events.message.priv.PrivateMessageReceivedEvent;
-import net.dv8tion.jda.core.events.message.priv.react.PrivateMessageReactionAddEvent;
-import net.dv8tion.jda.core.events.role.RoleCreateEvent;
-import net.dv8tion.jda.core.events.role.RoleDeleteEvent;
-import net.dv8tion.jda.core.events.role.update.RoleUpdateColorEvent;
-import net.dv8tion.jda.core.events.role.update.RoleUpdateNameEvent;
-import net.dv8tion.jda.core.events.user.update.UserUpdateNameEvent;
-import net.dv8tion.jda.core.hooks.ListenerAdapter;
-import net.dv8tion.jda.core.utils.cache.MemberCacheView;
+import net.dv8tion.jda.api.*;
+import net.dv8tion.jda.api.entities.*;
+import net.dv8tion.jda.api.events.ReadyEvent;
+import net.dv8tion.jda.api.events.channel.text.TextChannelCreateEvent;
+import net.dv8tion.jda.api.events.channel.text.TextChannelDeleteEvent;
+import net.dv8tion.jda.api.events.channel.text.update.*;
+import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
+import net.dv8tion.jda.api.events.guild.member.*;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.role.RoleCreateEvent;
+import net.dv8tion.jda.api.events.role.RoleDeleteEvent;
+import net.dv8tion.jda.api.events.role.update.RoleUpdateColorEvent;
+import net.dv8tion.jda.api.events.role.update.RoleUpdateNameEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
import javax.security.auth.login.LoginException;
-import java.io.*;
import java.time.Instant;
import java.time.OffsetDateTime;
-import java.time.temporal.TemporalAccessor;
import java.util.*;
import java.awt.Color;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
+import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent;
public class Bot extends ListenerAdapter {
public static int DEFAULT_COLOR=Integer.parseInt("7289DA",16); // Discord color
- public long last_ping;
- public void ping() {
- last_ping=System.currentTimeMillis();
- }
-
public String text_channel;
public ProcessBridge bridge;
public JDA jda;
@@ -88,20 +76,27 @@ public class Bot extends ListenerAdapter {
return this.jda.getGuildById(Main.GUILD_ID);
}
+ @Override
public void onTextChannelDelete(TextChannelDeleteEvent event) {
if (event.getChannel().getIdLong() == global_channel) {
System.err.println("Error ! Global channel was deleted !");
System.exit(1);
}
}
+
+ @Override
public void onTextChannelUpdatePermissions(TextChannelUpdatePermissionsEvent event) {
if (event.getChannel().getIdLong() == global_channel && !event.getChannel().canTalk()) {
System.err.println("Error ! Cannot talk in global channel !");
System.exit(1);
}
}
+
+ @Override
public void onTextChannelUpdateNSFW(TextChannelUpdateNSFWEvent event) {}
+ @Override
public void onTextChannelUpdateParent(TextChannelUpdateParentEvent event) {}
+ @Override
public void onTextChannelCreate(TextChannelCreateEvent event) {}
@Override
@@ -112,11 +107,15 @@ public class Bot extends ListenerAdapter {
}*/
// IDEA: leave
}
+
+ public String escapeName(String name) {
+ return name.replace(" ", "_").replace(",", "_");
+ }
@Override
public void onGuildMemberJoin(GuildMemberJoinEvent e) {
Member m=e.getMember();
- String name=m.getEffectiveName().replace(" ", "_");
+ String name=escapeName(m.getEffectiveName());
members.put(Utils.getFreeKey(name, members), m.getUser().getIdLong());
bridge.write("[JOI]"+name+" #"+ Utils.getColorString(m.getColorRaw()));
}
@@ -169,10 +168,10 @@ public class Bot extends ListenerAdapter {
if (chosen == null) {
List guilds=event.getJDA().getGuilds();
String guild_id=guilds.get(0).getId();
- OffsetDateTime min_join_time=guilds.get(0).getMember(event.getJDA().getSelfUser()).getJoinDate();
+ OffsetDateTime min_join_time=guilds.get(0).getMember(event.getJDA().getSelfUser()).getTimeJoined();
for (int i=1; i < guilds.size(); i++) {
Guild g=guilds.get(i);
- OffsetDateTime join_time=guilds.get(i).getMember(event.getJDA().getSelfUser()).getJoinDate();
+ OffsetDateTime join_time=guilds.get(i).getMember(event.getJDA().getSelfUser()).getTimeJoined();
if (join_time.isBefore(min_join_time)) {
min_join_time=join_time;
guild_id=g.getId();
@@ -182,16 +181,16 @@ public class Bot extends ListenerAdapter {
Main.GUILD_ID=guild_id;
}
setGlobalChannel(getGuild().getTextChannelsByName(text_channel, true).get(0).getIdLong());
- event.getJDA().getPresence().setGame(net.dv8tion.jda.core.entities.Game.playing("Minetest"));
+ event.getJDA().getPresence().setActivity(Activity.playing("Minetest"));
for (Member m:getGuild().getMemberCache()) {
- String name=m.getEffectiveName().replace(" ", "_");
+ String name=escapeName(m.getEffectiveName());
String finalname=Utils.getFreeKey(name, members);
members.put(finalname, m.getUser().getIdLong());
int color=m.getColor() == null ? DEFAULT_COLOR:m.getColorRaw();
bridge.write("[LIS]"+finalname+" #"+ Utils.getColorString(color));
}
for (Role r:getGuild().getRoles()) {
- String name=r.getName().replace(" ", "_");
+ String name=escapeName(r.getName());
String finalname=Utils.getFreeKey(name, roles);
String output="[ROL]"+finalname+" #"+Utils.getColorString(r.getColorRaw());
for (Member m:getGuild().getMembersWithRoles(r)) {
@@ -229,7 +228,7 @@ public class Bot extends ListenerAdapter {
@Override
public void onRoleCreate(RoleCreateEvent event) {
- String name=event.getRole().getName().replace(" ", "_");
+ String name=escapeName(event.getRole().getName());
String output="[ROL]"+Utils.getFreeKey(name, roles)+" #"+Utils.getColorString(event.getRole().getColorRaw());
bridge.write(output);
}
@@ -238,7 +237,7 @@ public class Bot extends ListenerAdapter {
@Override
public void onRoleUpdateName(RoleUpdateNameEvent event) {
String oldname=roles.inverse().get(event.getRole().getIdLong());
- String name=Utils.getFreeKey(event.getNewName().replace(" ", "_"), roles);
+ String name=Utils.getFreeKey(escapeName(event.getNewName()), roles);
roles.inverse().remove(event.getRole().getIdLong());
roles.put(name, event.getRole().getIdLong());
String output="[NAM]"+oldname+" "+name;
@@ -270,21 +269,18 @@ public class Bot extends ListenerAdapter {
}
}
- public void onGuildMemberNickChange(GuildMemberNickChangeEvent event) {
- String newnick=(event.getNewNick() != null ? event.getNewNick():event.getUser().getName()).replace(" ", "_");
+ @Override
+ public void onGuildMemberUpdateNickname(GuildMemberUpdateNicknameEvent event) {
+ String newnick=escapeName((event.getNewNickname() != null ? event.getNewNickname():event.getUser().getName()));
if (members.containsKey(newnick)) {
- getGuild().getController().setNickname(event.getMember(), event.getPrevNick()).queue();
- event.getMember().getUser().openPrivateChannel().queue(pc -> pc.sendMessage("Your nickname could not be changed to `"+event.getNewNick()+"` as there already is another guild member with a similar nickname.").queue());
+ getGuild().modifyNickname(event.getMember(), event.getOldNickname()).queue();
+ event.getMember().getUser().openPrivateChannel().queue(pc -> pc.sendMessage("Your nickname could not be changed to `"+event.getNewNickname()+"` as there already is another guild member with a similar nickname.").queue());
} else {
members.inverse().remove(event.getMember().getUser().getIdLong());
members.put(newnick, event.getMember().getUser().getIdLong());
}
}
- public String getIdentifier(Member m) {
- return null; // TODO replace spaces by underscores, check for duplicates, if yes use actual username or even discriminator
- }
-
public static String getName(Member m) {
return m.getEffectiveName()+(m.getNickname() == null ? "":" aka "+m.getUser().getName())+" #"+m.getUser().getDiscriminator();
}
diff --git a/minetest-chat-bridge-bot/src/main/java/commands/Command.java b/MinetestChatBridgeBot/src/main/java/commands/Command.java
similarity index 83%
rename from minetest-chat-bridge-bot/src/main/java/commands/Command.java
rename to MinetestChatBridgeBot/src/main/java/commands/Command.java
index 935fb2f..5718d0f 100644
--- a/minetest-chat-bridge-bot/src/main/java/commands/Command.java
+++ b/MinetestChatBridgeBot/src/main/java/commands/Command.java
@@ -1,7 +1,7 @@
package commands;
import chat.Bot;
-import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public abstract class Command {
diff --git a/minetest-chat-bridge-bot/src/main/java/commands/StatusCommand.java b/MinetestChatBridgeBot/src/main/java/commands/StatusCommand.java
similarity index 93%
rename from minetest-chat-bridge-bot/src/main/java/commands/StatusCommand.java
rename to MinetestChatBridgeBot/src/main/java/commands/StatusCommand.java
index 9e937f9..b9ffac7 100644
--- a/minetest-chat-bridge-bot/src/main/java/commands/StatusCommand.java
+++ b/MinetestChatBridgeBot/src/main/java/commands/StatusCommand.java
@@ -2,17 +2,20 @@ package commands;
import appguru.Main;
import chat.Bot;
-import net.dv8tion.jda.core.EmbedBuilder;
-import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.EmbedBuilder;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
public class StatusCommand extends Command {
+
+ @Override
public int getMinArgs() {
return 0;
}
+ @Override
public int getMaxArgs() {
return 0;
}
diff --git a/minetest-chat-bridge-bot/src/main/java/misc/GarbageCollector.java b/MinetestChatBridgeBot/src/main/java/misc/GarbageCollector.java
similarity index 100%
rename from minetest-chat-bridge-bot/src/main/java/misc/GarbageCollector.java
rename to MinetestChatBridgeBot/src/main/java/misc/GarbageCollector.java
diff --git a/minetest-chat-bridge-bot/src/main/java/misc/Utils.java b/MinetestChatBridgeBot/src/main/java/misc/Utils.java
similarity index 100%
rename from minetest-chat-bridge-bot/src/main/java/misc/Utils.java
rename to MinetestChatBridgeBot/src/main/java/misc/Utils.java
diff --git a/MinetestChatBridgeIRCBot/.classpath b/MinetestChatBridgeIRCBot/.classpath
new file mode 100644
index 0000000..9f9cc9f
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/.classpath
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MinetestChatBridgeIRCBot/.project b/MinetestChatBridgeIRCBot/.project
new file mode 100644
index 0000000..df93e45
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/.project
@@ -0,0 +1,23 @@
+
+
+ MinetestChatBridgeIRCBot
+ Project MinetestChatBridgeIRCBot created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/MinetestChatBridgeIRCBot/.settings/org.eclipse.buildship.core.prefs b/MinetestChatBridgeIRCBot/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..7a23d11
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(5.6.1))
+connection.project.dir=
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/MinetestChatBridgeIRCBot/bin/main/appguru/Main$1.class b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$1.class
new file mode 100644
index 0000000..5fb14c4
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$1.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/appguru/Main$2.class b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$2.class
new file mode 100644
index 0000000..7c55050
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$2.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/appguru/Main$3.class b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$3.class
new file mode 100644
index 0000000..8444d8d
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$3.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/appguru/Main$4.class b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$4.class
new file mode 100644
index 0000000..34c22ef
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/appguru/Main$4.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/appguru/Main.class b/MinetestChatBridgeIRCBot/bin/main/appguru/Main.class
new file mode 100644
index 0000000..c97d341
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/appguru/Main.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/bridge/FileBridge$1.class b/MinetestChatBridgeIRCBot/bin/main/bridge/FileBridge$1.class
new file mode 100644
index 0000000..5fe5e20
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/bridge/FileBridge$1.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/bridge/FileBridge.class b/MinetestChatBridgeIRCBot/bin/main/bridge/FileBridge.class
new file mode 100644
index 0000000..23b2d79
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/bridge/FileBridge.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/bridge/IRCFileBridge.class b/MinetestChatBridgeIRCBot/bin/main/bridge/IRCFileBridge.class
new file mode 100644
index 0000000..c8843cc
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/bridge/IRCFileBridge.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/bridge/IRCSocketBridge.class b/MinetestChatBridgeIRCBot/bin/main/bridge/IRCSocketBridge.class
new file mode 100644
index 0000000..543be69
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/bridge/IRCSocketBridge.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/bridge/ProcessBridge.class b/MinetestChatBridgeIRCBot/bin/main/bridge/ProcessBridge.class
new file mode 100644
index 0000000..13c0ce8
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/bridge/ProcessBridge.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/bridge/SocketBridge.class b/MinetestChatBridgeIRCBot/bin/main/bridge/SocketBridge.class
new file mode 100644
index 0000000..b41e7df
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/bridge/SocketBridge.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/commands/Command.class b/MinetestChatBridgeIRCBot/bin/main/commands/Command.class
new file mode 100644
index 0000000..d3185a0
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/commands/Command.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/commands/InfoCommand.class b/MinetestChatBridgeIRCBot/bin/main/commands/InfoCommand.class
new file mode 100644
index 0000000..7610255
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/commands/InfoCommand.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/handlers/NumericHandler.class b/MinetestChatBridgeIRCBot/bin/main/handlers/NumericHandler.class
new file mode 100644
index 0000000..bab48b8
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/handlers/NumericHandler.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/handlers/NumericResponseHandler.class b/MinetestChatBridgeIRCBot/bin/main/handlers/NumericResponseHandler.class
new file mode 100644
index 0000000..5cc5208
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/handlers/NumericResponseHandler.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/handlers/NumericTimeoutResponseHandler.class b/MinetestChatBridgeIRCBot/bin/main/handlers/NumericTimeoutResponseHandler.class
new file mode 100644
index 0000000..681fac3
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/handlers/NumericTimeoutResponseHandler.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/handlers/ResponseHandler.class b/MinetestChatBridgeIRCBot/bin/main/handlers/ResponseHandler.class
new file mode 100644
index 0000000..8c1939f
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/handlers/ResponseHandler.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/handlers/TimeoutResponseHandler.class b/MinetestChatBridgeIRCBot/bin/main/handlers/TimeoutResponseHandler.class
new file mode 100644
index 0000000..5228ffb
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/handlers/TimeoutResponseHandler.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/handlers/TopicResponseHandler.class b/MinetestChatBridgeIRCBot/bin/main/handlers/TopicResponseHandler.class
new file mode 100644
index 0000000..ddccc9e
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/handlers/TopicResponseHandler.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/handlers/TryAgainHandler.class b/MinetestChatBridgeIRCBot/bin/main/handlers/TryAgainHandler.class
new file mode 100644
index 0000000..c499652
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/handlers/TryAgainHandler.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/irc/Command.class b/MinetestChatBridgeIRCBot/bin/main/irc/Command.class
new file mode 100644
index 0000000..094f07e
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/irc/Command.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/irc/Default.class b/MinetestChatBridgeIRCBot/bin/main/irc/Default.class
new file mode 100644
index 0000000..87c63a4
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/irc/Default.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/irc/HandledResponse.class b/MinetestChatBridgeIRCBot/bin/main/irc/HandledResponse.class
new file mode 100644
index 0000000..dee62d4
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/irc/HandledResponse.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/irc/IRCBot.class b/MinetestChatBridgeIRCBot/bin/main/irc/IRCBot.class
new file mode 100644
index 0000000..71fc4fd
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/irc/IRCBot.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/irc/InvalidMessageException.class b/MinetestChatBridgeIRCBot/bin/main/irc/InvalidMessageException.class
new file mode 100644
index 0000000..5c6b7c2
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/irc/InvalidMessageException.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/irc/PongCommand.class b/MinetestChatBridgeIRCBot/bin/main/irc/PongCommand.class
new file mode 100644
index 0000000..b79ddab
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/irc/PongCommand.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/misc/GarbageCollector.class b/MinetestChatBridgeIRCBot/bin/main/misc/GarbageCollector.class
new file mode 100644
index 0000000..7b6c716
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/misc/GarbageCollector.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/numeric/Numeric.class b/MinetestChatBridgeIRCBot/bin/main/numeric/Numeric.class
new file mode 100644
index 0000000..628bb3c
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/numeric/Numeric.class differ
diff --git a/MinetestChatBridgeIRCBot/bin/main/numeric/NumericLookup.class b/MinetestChatBridgeIRCBot/bin/main/numeric/NumericLookup.class
new file mode 100644
index 0000000..2346c2d
Binary files /dev/null and b/MinetestChatBridgeIRCBot/bin/main/numeric/NumericLookup.class differ
diff --git a/MinetestChatBridgeIRCBot/build.gradle b/MinetestChatBridgeIRCBot/build.gradle
new file mode 100644
index 0000000..3957464
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'java'
+apply plugin: 'jacoco'
+apply plugin: 'application'
+
+
+description = 'Minetest Chat Bridge IRC Bot'
+
+mainClassName = 'appguru.Main'
+
+repositories {
+ jcenter()
+}
+
+dependencies {
+ testCompile 'junit:junit:4.12'
+}
+
+jar {
+ manifest {
+ attributes(
+ 'Created-By': "Gradle ${gradle.gradleVersion}",
+ 'Main-Class': "appguru.Main"
+ )
+ }
+}
\ No newline at end of file
diff --git a/MinetestChatBridgeIRCBot/gradle.properties b/MinetestChatBridgeIRCBot/gradle.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/gradle.properties
@@ -0,0 +1 @@
+
diff --git a/MinetestChatBridgeIRCBot/settings.gradle b/MinetestChatBridgeIRCBot/settings.gradle
new file mode 100644
index 0000000..bd9ebeb
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'MinetestChatBridgeIRCBot'
diff --git a/minetest-chat-bridge-irc-bot/src/appguru/Main.java b/MinetestChatBridgeIRCBot/src/main/java/appguru/Main.java
similarity index 81%
rename from minetest-chat-bridge-irc-bot/src/appguru/Main.java
rename to MinetestChatBridgeIRCBot/src/main/java/appguru/Main.java
index 7ae8d57..5092e69 100644
--- a/minetest-chat-bridge-irc-bot/src/appguru/Main.java
+++ b/MinetestChatBridgeIRCBot/src/main/java/appguru/Main.java
@@ -1,6 +1,8 @@
package appguru;
+import bridge.FileBridge;
import bridge.ProcessBridge;
+import bridge.SocketBridge;
import commands.Command;
import commands.InfoCommand;
import handlers.NumericTimeoutResponseHandler;
@@ -24,11 +26,13 @@ public class Main {
public static String IRC_PREFIX="?";
public static String PREFIX="!";
- public static long PING_WAIT=20000; //20s
+ public static long PING_WAIT=5000; //5s
public static PrintStream OUT = System.out;
- public static IRCBot chat_bridge;
+ public static IRCBot CHAT_BRIDGE;
+
+ public static ProcessBridge PROCESS_BRIDGE;
public static void main(String[] args) throws IOException {
String project_url="https://github.com/appgurueu/adv_chat";
@@ -72,20 +76,23 @@ public class Main {
String nickname=args[3];
String channelname=args[4];
- File in=new File(args[5]);
- File out=new File(args[6]);
- if (!in.isFile() || !out.isFile() || !in.canWrite() || !in.canRead() || !out.canWrite() || !out.canRead()) {
- OUT.println("ERR: Input or output files do not exist or can't be read/written.");
- System.exit(0);
+ if (args[5].length() == 0) {
+ int socket_port=Integer.parseInt(args[6]);
+ PROCESS_BRIDGE=new SocketBridge("localhost", socket_port);
+ } else {
+ File in=new File(args[5]);
+ File out=new File(args[6]);
+ if (!in.isFile() || !out.isFile() || !in.canWrite() || !in.canRead() || !out.canWrite() || !out.canRead()) {
+ OUT.println("ERR: Input or output files do not exist or can't be read/written.");
+ System.exit(0);
+ }
+ PROCESS_BRIDGE=new FileBridge(in, out);
}
- /* Open Process Bridge */
- ProcessBridge pb=new ProcessBridge(in, out);
-
/* Create IRC Bot */
- chat_bridge=new IRCBot(port, network, ssl.equals("true"));
+ CHAT_BRIDGE=new IRCBot(port, network, ssl.equals("true"));
- chat_bridge.commands.put("PRIVMSG", (bot, tags, source, params) -> {
+ CHAT_BRIDGE.commands.put("PRIVMSG", (bot, tags, source, params) -> {
if (source == null || params.size() < 2) {
return;
}
@@ -130,13 +137,13 @@ public class Main {
mentionstring+=",irc";
}
}
- pb.write((params.get(0).startsWith("#") ? "[CGM]":"[GMS]")+nick+" "+mentionstring+" "+msg_content);
+ PROCESS_BRIDGE.write((params.get(0).startsWith("#") ? "[CGM]":"[GMS]")+nick+" "+mentionstring+" "+msg_content);
} else {
String command="PRIVMSG "+nick+" :No message given. Use '@mentions message'.";
try {
- chat_bridge.send(command, new TryAgainHandler(command));
+ CHAT_BRIDGE.send(command, new TryAgainHandler(command));
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
}
return;
@@ -146,12 +153,12 @@ public class Main {
if (commandname_and_params[0].length() == 0) {
String reply="PRIVMSG "+nick+" :No commandname given !";
try {
- chat_bridge.send(reply, new TryAgainHandler(command));
+ CHAT_BRIDGE.send(reply, new TryAgainHandler(command));
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
} else {
- pb.write("[CMD]"+nick+" "+String.join(" ", commandname_and_params)+(commandname_and_params.length == 1 ? " ":""));
+ PROCESS_BRIDGE.write("[CMD]"+nick+" "+String.join(" ", commandname_and_params)+(commandname_and_params.length == 1 ? " ":""));
}
return;
} else if (params.get(1).startsWith(Main.IRC_PREFIX)) {
@@ -180,13 +187,13 @@ public class Main {
return;
}
if (params.get(0).startsWith("#")) {
- pb.write("[MSG]"+nick+" "+params.get(1));
+ PROCESS_BRIDGE.write("[MSG]"+nick+" "+params.get(1));
} else {
bot.sendTryAgain("PRIVMSG "+nick+" :I can only deliver your message if you use '@mentions'.");
}
});
- chat_bridge.commands.put("JOIN", (bot, tags, source, params) -> {
+ CHAT_BRIDGE.commands.put("JOIN", (bot, tags, source, params) -> {
if (source == null || params.isEmpty()) {
return;
}
@@ -200,42 +207,42 @@ public class Main {
for (byte b=0; b < colorstring.length()-6; b++) {
colorstring="0"+colorstring;
}
- pb.write("[JOI]"+nick+" #"+colorstring+" "+channelname);
+ PROCESS_BRIDGE.write("[JOI]"+nick+" #"+colorstring+" "+channelname);
});
- chat_bridge.commands.put("NICK", (bot, tags, source, params) -> {
+ CHAT_BRIDGE.commands.put("NICK", (bot, tags, source, params) -> {
if (source == null || params.isEmpty()) {
return;
}
int indexOf=source.indexOf('!');
String nick=indexOf >= 0 ? source.substring(0, indexOf):source;
- pb.write("[NCK]"+nick+" "+params.get(0));
+ PROCESS_BRIDGE.write("[NCK]"+nick+" "+params.get(0));
});
- chat_bridge.commands.put("QUIT", (bot, tags, source, params) -> {
+ CHAT_BRIDGE.commands.put("QUIT", (bot, tags, source, params) -> {
if (source == null || params.isEmpty()) {
return;
}
int indexOf=source.indexOf('!');
String nick=indexOf >= 0 ? source.substring(0, indexOf):source;
- pb.write("[EXT]"+nick+" "+(params.size() >= 2 ? params.get(1):"no reason"));
+ PROCESS_BRIDGE.write("[EXT]"+nick+" "+(params.size() >= 2 ? params.get(1):"no reason"));
});
- chat_bridge.commands.put("PART", (bot, tags, source, params) -> {
+ CHAT_BRIDGE.commands.put("PART", (bot, tags, source, params) -> {
if (source == null || params.isEmpty()) {
return;
}
int indexOf=source.indexOf('!');
String nick=indexOf >= 0 ? source.substring(0, indexOf):source;
- pb.write("[BYE]"+nick+" "+(params.size() >= 2 ? params.get(1):"no reason"));
+ PROCESS_BRIDGE.write("[BYE]"+nick+" "+(params.size() >= 2 ? params.get(1):"no reason"));
});
// TODO Probably Ident & SASL negotiation ?
//chat_bridge.send("CAP LS 302");
- chat_bridge.send("NICK "+nickname);
- chat_bridge.send("USER Minetest null null :Minetest Chat Bridge"); // 0 *
+ CHAT_BRIDGE.send("NICK "+nickname);
+ CHAT_BRIDGE.send("USER Minetest null null :Minetest Chat Bridge"); // 0 *
- chat_bridge.send("JOIN "+channelname, new NumericTimeoutResponseHandler(20000) {
+ CHAT_BRIDGE.send("JOIN "+channelname, new NumericTimeoutResponseHandler(20000) {
@Override
public HandledResponse handleNumeric(IRCBot bot, Numeric num, List params) {
switch (num) {
@@ -256,7 +263,7 @@ public class Main {
for (byte b=0; b < colorstring.length()-6; b++) {
colorstring="0"+colorstring;
}
- pb.write("[JOI]"+nick+" #"+colorstring+" "+channelname);
+ PROCESS_BRIDGE.write("[JOI]"+nick+" #"+colorstring+" "+channelname);
}
return HandledResponse.BREAK;
case RPL_ENDOFNAMES:
@@ -282,7 +289,7 @@ public class Main {
};
}
};
- chat_bridge.chatcommands.put("help", help_command);
+ CHAT_BRIDGE.chatcommands.put("help", help_command);
InfoCommand about_command=new InfoCommand() {
@Override
@@ -292,7 +299,7 @@ public class Main {
};
}
};
- chat_bridge.chatcommands.put("about", about_command);
+ CHAT_BRIDGE.chatcommands.put("about", about_command);
InfoCommand status_command=new InfoCommand() {
@Override
@@ -308,31 +315,31 @@ public class Main {
};
}
};
- chat_bridge.chatcommands.put("status", status_command);
+ CHAT_BRIDGE.chatcommands.put("status", status_command);
OUT.println("INFO: Starting client");
Main.STARTED_AT=System.currentTimeMillis();
- chat_bridge.listen();
+ CHAT_BRIDGE.listen();
OUT.println("INFO: Starting server");
- pb.serve();
+ PROCESS_BRIDGE.serve();
OUT.println("INFO: Starting listener");
- pb.listen(line -> {
+ PROCESS_BRIDGE.listen(line -> {
if (line.startsWith("[MSG]")) {
try {
String command="PRIVMSG #mtchatbridgetest :"+line.substring(5);
- chat_bridge.send(command, new TryAgainHandler(command));
+ CHAT_BRIDGE.send(command, new TryAgainHandler(command));
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
} else if (line.startsWith("[PMS]")) { // GMS = PMS with comma separated list of targets
String line_content=line.substring(5);
String[] parts=line_content.split(" ", 2);
String command="PRIVMSG "+parts[0]+" :"+parts[1];
try {
- chat_bridge.send(command, new TryAgainHandler(command));
+ CHAT_BRIDGE.send(command, new TryAgainHandler(command));
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
}
});
diff --git a/MinetestChatBridgeIRCBot/src/main/java/bridge/FileBridge.java b/MinetestChatBridgeIRCBot/src/main/java/bridge/FileBridge.java
new file mode 120000
index 0000000..eb955df
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/src/main/java/bridge/FileBridge.java
@@ -0,0 +1 @@
+/home/lars/.minetest/mods/adv_chat/MinetestChatBridgeBot/src/main/java/bridge/FileBridge.java
\ No newline at end of file
diff --git a/MinetestChatBridgeIRCBot/src/main/java/bridge/IRCFileBridge.java b/MinetestChatBridgeIRCBot/src/main/java/bridge/IRCFileBridge.java
new file mode 100644
index 0000000..98e330f
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/src/main/java/bridge/IRCFileBridge.java
@@ -0,0 +1,25 @@
+package bridge;
+
+import appguru.Main;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ *
+ * @author lars
+ */
+public class IRCFileBridge extends FileBridge {
+
+ public IRCFileBridge(File in, File out) throws IOException {
+ super(in, out);
+ }
+
+ @Override
+ public void kill(String reason) {
+ super.kill(reason);
+
+ Main.CHAT_BRIDGE.shutdown(reason);
+
+ System.exit(0);
+ }
+}
diff --git a/MinetestChatBridgeIRCBot/src/main/java/bridge/IRCSocketBridge.java b/MinetestChatBridgeIRCBot/src/main/java/bridge/IRCSocketBridge.java
new file mode 100644
index 0000000..bf4c144
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/src/main/java/bridge/IRCSocketBridge.java
@@ -0,0 +1,23 @@
+package bridge;
+
+import appguru.Main;
+import java.io.IOException;
+
+/**
+ *
+ * @author lars
+ */
+public class IRCSocketBridge extends SocketBridge {
+ public IRCSocketBridge(String host, int port) throws IOException {
+ super(host, port);
+ }
+
+ @Override
+ public void kill(String reason) {
+ super.kill(reason);
+
+ Main.CHAT_BRIDGE.shutdown(reason);
+
+ System.exit(0);
+ }
+}
diff --git a/MinetestChatBridgeIRCBot/src/main/java/bridge/ProcessBridge.java b/MinetestChatBridgeIRCBot/src/main/java/bridge/ProcessBridge.java
new file mode 120000
index 0000000..4eee6a0
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/src/main/java/bridge/ProcessBridge.java
@@ -0,0 +1 @@
+/home/lars/.minetest/mods/adv_chat/MinetestChatBridgeBot/src/main/java/bridge/ProcessBridge.java
\ No newline at end of file
diff --git a/MinetestChatBridgeIRCBot/src/main/java/bridge/SocketBridge.java b/MinetestChatBridgeIRCBot/src/main/java/bridge/SocketBridge.java
new file mode 120000
index 0000000..a463d43
--- /dev/null
+++ b/MinetestChatBridgeIRCBot/src/main/java/bridge/SocketBridge.java
@@ -0,0 +1 @@
+/home/lars/.minetest/mods/adv_chat/MinetestChatBridgeBot/src/main/java/bridge/SocketBridge.java
\ No newline at end of file
diff --git a/minetest-chat-bridge-irc-bot/src/commands/Command.java b/MinetestChatBridgeIRCBot/src/main/java/commands/Command.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/commands/Command.java
rename to MinetestChatBridgeIRCBot/src/main/java/commands/Command.java
diff --git a/minetest-chat-bridge-irc-bot/src/commands/InfoCommand.java b/MinetestChatBridgeIRCBot/src/main/java/commands/InfoCommand.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/commands/InfoCommand.java
rename to MinetestChatBridgeIRCBot/src/main/java/commands/InfoCommand.java
diff --git a/minetest-chat-bridge-irc-bot/src/handlers/NumericHandler.java b/MinetestChatBridgeIRCBot/src/main/java/handlers/NumericHandler.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/handlers/NumericHandler.java
rename to MinetestChatBridgeIRCBot/src/main/java/handlers/NumericHandler.java
diff --git a/minetest-chat-bridge-irc-bot/src/handlers/NumericResponseHandler.java b/MinetestChatBridgeIRCBot/src/main/java/handlers/NumericResponseHandler.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/handlers/NumericResponseHandler.java
rename to MinetestChatBridgeIRCBot/src/main/java/handlers/NumericResponseHandler.java
diff --git a/minetest-chat-bridge-irc-bot/src/handlers/NumericTimeoutResponseHandler.java b/MinetestChatBridgeIRCBot/src/main/java/handlers/NumericTimeoutResponseHandler.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/handlers/NumericTimeoutResponseHandler.java
rename to MinetestChatBridgeIRCBot/src/main/java/handlers/NumericTimeoutResponseHandler.java
diff --git a/minetest-chat-bridge-irc-bot/src/handlers/ResponseHandler.java b/MinetestChatBridgeIRCBot/src/main/java/handlers/ResponseHandler.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/handlers/ResponseHandler.java
rename to MinetestChatBridgeIRCBot/src/main/java/handlers/ResponseHandler.java
diff --git a/minetest-chat-bridge-irc-bot/src/handlers/TimeoutResponseHandler.java b/MinetestChatBridgeIRCBot/src/main/java/handlers/TimeoutResponseHandler.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/handlers/TimeoutResponseHandler.java
rename to MinetestChatBridgeIRCBot/src/main/java/handlers/TimeoutResponseHandler.java
diff --git a/minetest-chat-bridge-irc-bot/src/handlers/TopicResponseHandler.java b/MinetestChatBridgeIRCBot/src/main/java/handlers/TopicResponseHandler.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/handlers/TopicResponseHandler.java
rename to MinetestChatBridgeIRCBot/src/main/java/handlers/TopicResponseHandler.java
diff --git a/minetest-chat-bridge-irc-bot/src/handlers/TryAgainHandler.java b/MinetestChatBridgeIRCBot/src/main/java/handlers/TryAgainHandler.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/handlers/TryAgainHandler.java
rename to MinetestChatBridgeIRCBot/src/main/java/handlers/TryAgainHandler.java
diff --git a/minetest-chat-bridge-irc-bot/src/irc/Command.java b/MinetestChatBridgeIRCBot/src/main/java/irc/Command.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/irc/Command.java
rename to MinetestChatBridgeIRCBot/src/main/java/irc/Command.java
diff --git a/minetest-chat-bridge-irc-bot/src/irc/Default.java b/MinetestChatBridgeIRCBot/src/main/java/irc/Default.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/irc/Default.java
rename to MinetestChatBridgeIRCBot/src/main/java/irc/Default.java
diff --git a/minetest-chat-bridge-irc-bot/src/irc/HandledResponse.java b/MinetestChatBridgeIRCBot/src/main/java/irc/HandledResponse.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/irc/HandledResponse.java
rename to MinetestChatBridgeIRCBot/src/main/java/irc/HandledResponse.java
diff --git a/minetest-chat-bridge-irc-bot/src/irc/IRCBot.java b/MinetestChatBridgeIRCBot/src/main/java/irc/IRCBot.java
similarity index 79%
rename from minetest-chat-bridge-irc-bot/src/irc/IRCBot.java
rename to MinetestChatBridgeIRCBot/src/main/java/irc/IRCBot.java
index 4df0825..0e7073b 100644
--- a/minetest-chat-bridge-irc-bot/src/irc/IRCBot.java
+++ b/MinetestChatBridgeIRCBot/src/main/java/irc/IRCBot.java
@@ -10,6 +10,8 @@ import java.net.Socket;
import java.util.*;
import static irc.HandledResponse.*;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
public class IRCBot {
public Map chatcommands;
@@ -39,7 +41,7 @@ public class IRCBot {
try {
socket.close();
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
}
}
}));
@@ -158,6 +160,16 @@ public class IRCBot {
}
public void listen() {
Thread listenerThread = new Thread(() -> {
+ BufferedReader reader=null;
+ try {
+ reader=new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
+ } catch (IOException e) {
+ e.printStackTrace(Main.OUT);
+ if (socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) {
+ Main.PROCESS_BRIDGE.kill("Socket connection lost");
+ }
+ System.exit(1);
+ }
while (true) {
try {
Thread.sleep(20);
@@ -165,34 +177,29 @@ public class IRCBot {
return;
}
try {
- String message = "";
- int c = socket.getInputStream().read();
- while (c >= 0) {
- if (c == '\n' && message.charAt(message.length() - 1) == '\r') {
- // message completed !
- message = message.substring(0, message.length() - 1);
- try {
- processMessage(message);
- } catch (InvalidMessageException e) {
- e.printStackTrace();
- }
- message = "";
- } else {
- message += (char) c;
+ String message;
+ while ((message = reader.readLine()) != null) {
+ try {
+ processMessage(message);
+ } catch (InvalidMessageException e) {
+ e.printStackTrace(Main.OUT);
}
- c = socket.getInputStream().read();
}
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
+ if (socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) {
+ Main.PROCESS_BRIDGE.kill("Socket connection lost");
+ }
}
}
});
listenerThread.start();
}
public void send(String message) throws IOException {
- for (int i = 0; i < message.length(); i++) {
- socket.getOutputStream().write(message.charAt(i));
+ if (socket.isClosed() || socket.isOutputShutdown()) {
+ Main.PROCESS_BRIDGE.kill("Socket connection lost");
}
+ socket.getOutputStream().write(message.getBytes("UTF-8"));
socket.getOutputStream().write('\r');
socket.getOutputStream().write('\n');
}
@@ -204,7 +211,21 @@ public class IRCBot {
try {
send(command, new TryAgainHandler(command));
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace(Main.OUT);
+ }
+ }
+ public void shutdown(String reason) {
+ try {
+ this.send("QUIT :" + reason);
+ } catch (IOException e) {
+ e.printStackTrace(Main.OUT);
+ }
+ if (!this.socket.isClosed()) {
+ try {
+ this.socket.close();
+ } catch (IOException e) {
+ e.printStackTrace(Main.OUT);
+ }
}
}
}
diff --git a/minetest-chat-bridge-irc-bot/src/irc/InvalidMessageException.java b/MinetestChatBridgeIRCBot/src/main/java/irc/InvalidMessageException.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/irc/InvalidMessageException.java
rename to MinetestChatBridgeIRCBot/src/main/java/irc/InvalidMessageException.java
diff --git a/minetest-chat-bridge-irc-bot/src/irc/PongCommand.java b/MinetestChatBridgeIRCBot/src/main/java/irc/PongCommand.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/irc/PongCommand.java
rename to MinetestChatBridgeIRCBot/src/main/java/irc/PongCommand.java
diff --git a/minetest-chat-bridge-irc-bot/src/misc/GarbageCollector.java b/MinetestChatBridgeIRCBot/src/main/java/misc/GarbageCollector.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/misc/GarbageCollector.java
rename to MinetestChatBridgeIRCBot/src/main/java/misc/GarbageCollector.java
diff --git a/minetest-chat-bridge-irc-bot/src/numeric/Numeric.java b/MinetestChatBridgeIRCBot/src/main/java/numeric/Numeric.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/numeric/Numeric.java
rename to MinetestChatBridgeIRCBot/src/main/java/numeric/Numeric.java
diff --git a/minetest-chat-bridge-irc-bot/src/numeric/NumericLookup.java b/MinetestChatBridgeIRCBot/src/main/java/numeric/NumericLookup.java
similarity index 100%
rename from minetest-chat-bridge-irc-bot/src/numeric/NumericLookup.java
rename to MinetestChatBridgeIRCBot/src/main/java/numeric/NumericLookup.java
diff --git a/Readme.md b/Readme.md
index 1859871..5dd1db0 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,9 +1,9 @@
-# Advanced Chat(`adv_chat`)
+# Advanced Chat (`adv_chat`)
+
> One Mod to rule them all, One Mod to find them,
> One Mod to bring them all, and in the darkness bind them
\- adapted quote from "Lord of the Rings"
-With "all" other chat mods are meant.
Adds roles, colors, unicode, hud notifications, and chat bridges (IRC & discord).
@@ -15,26 +15,56 @@ Depends on [`modlib`](https://github.com/appgurueu/modlib). Modlib has been upda
Code licensed under the GPLv3 (GNU Public License Version 3). Written by Lars Mueller alias LMD or appguru(eu).
-## Terminology
+## Links
-Chatter : Participant in chat, be it a Minetest player, IRC user, or Discord member
-Role : "Group" of chatters
-Targets/Mentions : Roles or chatters mentioned using `@`
+* [GitHub](https://github.com/appgurueu/voxelizer) - sources, issue tracking, contributing
+* [Discord](https://discord.gg/ysP74by) - discussion, chatting
+* [Minetest Forum](https://forum.minetest.net/viewtopic.php?f=9&t=22845) - (more organized) discussion
+* [ContentDB](https://content.minetest.net/packages/LMD/voxelizer/) - releases (downloading from GitHub is recommended)
+
+## Setup
+
+In order to properly use `adv_chat`, you'll have to meet the following prerequisites:
+
+* `modlib` Minetest mod installed and enabled as hard dependency and additionally also `cmdlib` (recommended)
+* `adv_chat` needs to be installed, enabled and added to the trusted mods in settings/`minetest.conf`
+* [LuaSocket](https://luarocks.org/modules/luasocket/luasocket) should be installed (`sudo luarocks install luasocket` on Ubuntu)
+* Complete [Java](https://www.java.com/de/) 8 or ideally newer installation under your system path (accessible from terminal via `java`)
+
+Then just install it like any other mod and enjoy your greatly improved chat experience!
+
+## Terminology
+
+Chatter: Participant in chat, be it a Minetest player, IRC user, or Discord member
+Role: "Group" of chatters
+Targets/Mentions: Roles or chatters mentioned using `@`
## Features
-* Discord & IRC chat bridges
+* Discord & IRC chat bridges, login & commands
+* Blocking
* Colorization
+* Style preservation
* Unicode
* Mentions
* HUD channels/notifications
* Scheduled messages for offline players
+## Changes
+
+### 🎃 Halloween Update
+
+* Proper formatting support
+* More configuration options
+* Remote login for chatcommand execution
+* Many under-the-hood changes cleaning up stuff & fixing bugs (improving the code & architecture)
+* See `config_help.md` and the sources for all details
+
## API
### HUD notifications
-See the `hud_channels.lua` for how it works and `test.lua` for a score change demo running with random values.
+See `hud_channels.lua` for how it works and `test.lua` for a score change demo running with random values.
### Votes
@@ -58,14 +88,14 @@ See the code and `config_help.md`. Feel free to contact me.
### Unicode support
-This mod adds unicode support. Simply use the unicode codepoint in hexadecimal format prefixed by `U+`. To get a "slight smile" (🙂), you'd use `U+1F643`. Note that not all fonts fully support Unicode.
+This mod adds unicode support. Simply use the unicode codepoint in hexadecimal format prefixed by `U+`. To get a "slight smile" (🙂), you'd use `U+1F642`. Note that not all fonts fully support Unicode.
Use the `/chat say` command to open a text entry field to paste text.
### Real-time chat
Use `@` at the beginning to message players or roles before your message.
There are 3 special mentions : `minetest`, `irc` and `discord`.
-Can be separated by comma **&** whitespace. Examples :
+Can be separated by comma **&** whitespace. Examples:
* `@singleplayer hi, singleplayer !` - message `hi, singleplayer !` is sent to singleplayer
* `lol(or whitespaces) @singleplayer hi` - message is just sent in global chat
@@ -103,7 +133,7 @@ Summarized, the Discord Chat Bridge works quite similar to the IRC one, with som
Making Minetest & IRC chat compatible with Discord required the introduction of restrictions to simplify and reduce confusion.
* No double nicknames on Discord. If there are double nicknames, one of them gets an appendix, which is not guaranteed to be the same each time. So better make sure this doesn't happen.
-* Spaces (` `) in Discord nicknames are replaced by underscores (`_`)
+* Spaces (` `) and commata (`,`) in Discord nicknames are replaced by underscores (`_`)
### Internal process bridge protocol
diff --git a/chatcommands.lua b/chatcommands.lua
new file mode 100644
index 0000000..07b4cc8
--- /dev/null
+++ b/chatcommands.lua
@@ -0,0 +1,73 @@
+minetest.original_get_player_privs = minetest.get_player_privs
+function minetest.get_player_privs(playername)
+ if chatters[playername] then
+ return {chatter=true}
+ end
+ return minetest.original_get_player_privs(playername)
+end
+
+if cmd_ext then
+ function call_chatcommand(chatter, call)
+ local last_space, next_space = 1, call:find(" ")
+ local command_trie, command_name = cmd_ext.chatcommands
+ local cmd, suggestion
+ local total_command_name = {}
+ repeat
+ next_space = next_space or call:len()+1
+ command_name = call:sub(last_space, next_space-1)
+ table.insert(total_command_name, command_name)
+ local concat = table.concat(total_command_name, " ")
+ if bridges.command_blacklist[total_command_name] then
+ return false, "Command only available from Minetest."
+ end
+ total_command_name = {concat}
+ if command_name == "" and cmd and not cmd.params then break end
+ cmd, suggestion, _ = trie.search(command_trie, command_name)
+ if not cmd then
+ return false, "No such chatcommand."..((suggestion and " Did you mean \""..call:sub(0, last_space-1)..suggestion.."\" ?") or "")
+ elseif cmd.subcommands and not cmd.implicit_call then
+ command_trie = cmd.subcommands
+ last_space, next_space = next_space + 1, call:find(" ", next_space+1)
+ else
+ last_space = next_space + 1
+ break
+ end
+ until next_space == call:len()
+ local params = call:sub(last_space)
+ if cmd.privs and cmd.privs.chatter then
+ return cmd.func(chatter, params)
+ end
+ return cmd.func((chatters[chatter] and chatters[chatter].login) or chatter, params)
+ end
+else
+ function call_chatcommand(chatter, call)
+ local name, params = unpack(string_ext.split(call, " ", 2))
+ if bridges.command_blacklist[name] then
+ return false, "Command only available from Minetest."
+ end
+ local command = minetest.registered_chatcommands[name]
+ if not command then
+ return false, "No such chatcommand."
+ end
+ local privs = minetest.get_player_privs(chatter)
+ local to_lose, to_gain = {}, {}
+ for priv, val in pairs(command.privs) do
+ if val ~= privs[val] then
+ table.insert((val and to_gain) or to_lose, priv)
+ end
+ end
+ if #to_lose ~= 0 or #to_gain ~= 0 then
+ if #to_lose == 0 then
+ return false, "Missing privileges : "..table.concat(to_gain, ", ")
+ end
+ if #to_gain == 0 then
+ return false, "Privileges to be lost : "..table.concat(to_lose, ", ")
+ end
+ return false, "Missing privileges : "..table.concat(to_gain, ", ")..", privileges to be lost : "..table.concat(to_lose, ", ")
+ end
+ if cmd.privs.chatter then
+ return cmd.func(chatter, params)
+ end
+ return command.func((chatters[chatter] and chatters[chatter].login) or chatter, params)
+ end
+end
\ No newline at end of file
diff --git a/closest_color.lua b/closest_color.lua
new file mode 120000
index 0000000..ebf0867
--- /dev/null
+++ b/closest_color.lua
@@ -0,0 +1 @@
+/home/lars/.minetest/mods/voxelizer/closest_color.lua
\ No newline at end of file
diff --git a/colorize_message.lua b/colorize_message.lua
index aa5bdad..266279c 100644
--- a/colorize_message.lua
+++ b/colorize_message.lua
@@ -1,35 +1,39 @@
+-- Converts "#XXXXXX" color codes to colors
function colorize_message(message)
local rope={}
- --IFNDEF bridge
+ --IFNDEF discord
local otherrope={}
--ENDIF
- local last_index=1
- for i=1, string.len(message) do
- local c=string.byte(message:sub(i,i))
- if c == hashtag then
+ local i=1
+ while i <= message:len() do
+ local c=message:sub(i,i)
+ if c == string.char(0x1b) and message:sub(i+1, i+4) == "(c@#" and message:sub(i+11, i+11) == ")" then
+ table.insert(rope, message:sub(i, i+11))
+ i=i+11
+ goto continue
+ elseif c == "#" then
for j=i+1, i+6 do
- local c2=string.byte(string.upper(message:sub(j,j)))
- if c2:len() == 0 or not string_ext.is_hexadecimal(c2) then
- i=j
+ local c2=message:sub(j,j):upper()
+ if c2=="" or not ((c2 >= "0" and c2 <= "9") or (c2 >= "A" and c2 <= "F")) then
goto nocolor
end
end
- local colorstring=minetest.get_color_escape_sequence(string.sub(message, i, i+6))
- table.insert(rope, message:sub(last_index, i-1))
- --IFNDEF bridge
- table.insert(otherrope, message:sub(last_index, i-1))
- --ENDIF
- table.insert(rope, colorstring)
- last_index=i+7
- ::nocolor::
+ table.insert(rope, minetest.get_color_escape_sequence(message:sub(i, i+6)))
+ i=i+6
+ goto continue
end
+ ::nocolor::
+ table.insert(rope, c)
+ --IFNDEF discord
+ table.insert(otherrope, c)
+ --ENDIF
+ ::continue::
+ i=i+1
end
- table.insert(rope, message:sub(last_index))
- --IFNDEF bridge
- table.insert(otherrope, message:sub(last_index))
+ return table.concat(rope)
+ --IFNDEF discord
+ , table.concat(otherrope)
--ENDIF
- return table.concat(rope, "")
- --IFNDEF bridge
- , table.concat(otherrope, "")
- --ENDIF
-end
\ No newline at end of file
+end
+
+load_schemes()
\ No newline at end of file
diff --git a/conf.lua b/conf.lua
index 67933ce..f72a4b9 100644
--- a/conf.lua
+++ b/conf.lua
@@ -1,25 +1,36 @@
-local schemedef={mention_prefix={type="string"},
-mention_delim={type="string"},
-delim={type="string"}}
+local schemedef={
+ message_prefix={type="string"},
+ mention_prefix={type="string"},
+ mention_delim={type="string"},
+ content_prefix={type="string"},
+ message_suffix={type="string"},
+}
local conf_spec={type="table", children={
- scheme={type="table", required_children={
+ schemes={type="table", required_children={
minetest=schemedef
}, possible_children={
- other=schemedef
+ irc=schemedef,
+ discord=schemedef
}},
bridges={
type="table",
possible_children={
- irc={type="table", children={
- port={type="number", range={0, 65535}},
- network={type="string"},
- nickname={type="string"},
- channelname={type="string"},
- ssl={type="boolean"},
- prefix={type="string"},
- minetest_prefix={type="string"}
- }},
+ irc={type="table", required_children={
+ port={type="number", range={0, 65535}},
+ network={type="string"},
+ nickname={type="string"},
+ channelname={type="string"},
+ ssl={type="boolean"},
+ prefix={type="string"},
+ minetest_prefix={type="string"}
+ },
+ possible_children={
+ bridge={type="string", possible_values={"files", "sockets"}},
+ convert_minetest_colors={type="string", possible_values={"disabled", "hex", "safer", "safest"}},
+ handle_discord_markdown={type="boolean"},
+ handle_minetest_markdown={type="boolean"}
+ }},
discord={type="table", required_children={
token={type="string"},
channelname={type="string"},
@@ -29,9 +40,15 @@ local conf_spec={type="table", children={
possible_children={
blacklist={type="table", keys={type="string"}},
whitelist={type="table", keys={type="string"}},
- guild_id={type="string"}
+ guild_id={type="string"},
+ bridge={type="string", possible_values={"files", "sockets"}},
+ convert_internal_markdown={type="boolean"},
+ convert_minetest_markdown={type="boolean"},
+ handle_irc_styles={type="string", possible_values={"escape_markdown", "convert", "disabled"}}
}
- }
+ },
+ command_blacklist={type="table", keys={type="number"}, values={type="string"}},
+ command_whitelist={type="table", keys={type="number"}, values={type="string"}}
}
}
}}
@@ -39,6 +56,30 @@ local conf_spec={type="table", children={
local config=conf.import("adv_chat", conf_spec)
table_ext.add_all(getfenv(1), config)
+function load_schemes()
+ for k, v in pairs(schemes.minetest) do
+ schemes.minetest[k] = colorize_message(v)
+ end
+
+ for _,s in pairs({"irc", "discord"}) do
+ if not schemes[s] then
+ schemes[s] = {}
+ for k, v in pairs(schemes.minetest) do
+ schemes[s][k] = minetest.strip_colors(v)
+ end
+ end
+ end
+
+ load_schemes = nil
+end
+
+if not bridges.irc.style_conversion then
+ bridges.irc.style_conversion={}
+ if not bridges.irc.style_conversion.colors then
+ bridges.irc.style_conversion.colors="disabled"
+ end
+end
+
if bridges.discord then
local blacklist_empty=table_ext.is_empty(bridges.discord.blacklist or {})
@@ -58,4 +99,23 @@ if bridges.discord then
end
end
+end
+
+if bridges.discord or bridges.irc then
+
+ bridges.command_blacklist = table_ext.set(bridges.command_blacklist or {})
+ bridges.command_whitelist = table_ext.set(bridges.command_whitelist or {})
+ local blacklist_empty=table_ext.is_empty(bridges.command_blacklist)
+ local whitelist_empty=table_ext.is_empty(bridges.command_whitelist or {})
+ if blacklist_empty then
+ if not whitelist_empty then
+ bridges.command_blacklist=setmetatable(bridges.command_blacklist, {__index=function(value)
+ if bridges.command_whitelist[value] then
+ return nil
+ end
+ return true
+ end})
+ end
+ end
+
end
\ No newline at end of file
diff --git a/config_help.md b/config_help.md
index 911a4f4..ad14386 100644
--- a/config_help.md
+++ b/config_help.md
@@ -11,14 +11,15 @@ Explaining document(this, Markdown) : `/adv_chat/config_help.m
Readme : `/adv_chat/Readme.md`
## Default Configuration
+
Located under `/adv_chat/default_config.json`
+
```json
{
- "scheme" : {
- "minetest" : {"mention_prefix":"#FFFF00@", "mention_delim":"#FFFF00, ", "delim":"#FFFF00 : "},
+ "schemes" : {
+ "minetest" : {"message_prefix": "", "mention_prefix": "#FFFF00@", "mention_delim": "#FFFF00, ", "content_prefix": "#FFFF00: #FFFFFF"},
"other" : null
},
-
"bridges" : {
"discord" : null,
"irc" : null
@@ -27,13 +28,13 @@ Located under `/adv_chat/default_config.json`
```
## Example Configuration
+
```json
{
- "scheme" : {
- "minetest" : {"mention_prefix":"#FFFF00@", "mention_delim":"#FFFF00, ", "delim":"#FFFF00 : "},
+ "schemes" : {
+ "minetest" : {"message_prefix": "Somebody - namely ", "mention_prefix": "#FFFF00 - wrote to ", "mention_delim": "#FFFF00 and ", "content_prefix": "#FFFF00: #FFFFFF", "message_suffix": " :D"},
"other" : null
},
-
"bridges" : {
"discord" : {"channelname":"allgemein", "prefix": "?", "minetest_prefix": "!","token":"S.U.Pxxs.E.R.T.9998OKEN", "blacklist":{"~~new_role~~":true}, "guild_id": 580416319703351296},
"irc" : {"channelname":"#mtchatbridgetest", "prefix": "?", "minetest_prefix": "!", "nickname": "MT_Chat_Bridge", "network": "irc.freenode.net", "port": 7000, "ssl": true}
@@ -44,28 +45,40 @@ Located under `/adv_chat/default_config.json`
## Usage
-### `scheme`
+### `schemes`
-Specifies the chat message format, `minetest` is for the one used on the Minetest chat, and `other` is for Discord/IRC.
+Specifies the chat message format, `minetest` is for the one used on the Minetest chat, `irc` is IRC, and `discord` for Discord.
+
+* `message_prefix` - Prefix for the message
* `mention_prefix` - Prefix for mentionpart.
* `mention_delim` - Mention delimiter.
-* `delim` - Message/sendername delimiter.
-If you want to use color escape sequences, type `\x1B(c@#66FF00)`, and replace `#66FF00` with your color of choice in hex format.
+* `content_prefix` - Message/sendername delimiter.
+* `message_suffix` - Suffix for the message
-Messages are formatted as `sendername + mention_prefix + {mentions, mention_delim} + delim + message`
+If you want to use color escape sequences, type something like `#66FF00 colorized text here`, and replace `#66FF00` with your color of choice in hex format.
+
+Messages are formatted as `message_prefix + sendername + mention_prefix + {mentions, mention_delim} + delim + message + message_suffix`
### `bridges`
+
Configuration for IRC/Discord chat bridges. If `irc` or `discord` are set to `false` or `null`, the corresponding chat bridges aren't created.
#### `discord`
-Table with the following entries :
-* `token` : Discord bot token, required
-* `channelname` : Name of bridge channel, required as well
-* `prefix`, `minetest_prefix` : Prefixes for Discord/Minetest commands, required
-* `role_blacklist`/`role_whitelist` : Blacklist/whitelist of Discord roles. If both or none are set, Discord roles are ignored.
-* `guild_id` : Guild ID, string. If swines add your bot to other servers, force it to use the server with the specified Guild ID. Optional. If unset, bot will use the guild it joined first.
-Example :
+Table with the following entries :
+
+* `token`: Discord bot token, required
+* `channelname`: Name of bridge channel, required as well
+* `prefix`, `minetest_prefix`: Prefixes for Discord/Minetest commands, required
+* `role_blacklist`/`role_whitelist`: Blacklist/whitelist of Discord roles. If both or none are set, Discord roles are ignored.
+* `guild_id`: Guild ID, string. If swines add your bot to other servers, force it to use the server with the specified Guild ID. Optional. If unset, bot will use the guild it joined first.
+* `bridge`: Optional. Forces type of process bridge to use. Choices are `"file"` and `"socket"`. Sockets are recommended but require `luasocket`.
+* `convert_internal_markdown`/`convert_minetest_markdown`: Optional boolean. Whether Markdown sent from Minetest/internal chat messages should be left untouched as if it was Discord Markdown
+* `handle_irc_styles`: Optional string. How IRC styles should be converted to Discord Markdown. Possible values: `"disabled"`, `"escape_markdown"` and `"convert"`
+* `strip_discord_markdown_in_minetest`: Optional boolean. Whether Discord Markdown should be stripped from Minetest chat.
+
+Example :
+
```json
{
"discord": {
@@ -80,22 +93,33 @@ Example :
```
#### `irc`
-Table with fields (all required) :
-* `network` : IRC network, for example `irc.freenode.net`
-* `port` : Port, on [Freenode](https://freenode.net/kb/answer/chat) it would be `7000` if SSL is used, or else `6667`. Just google "connecting to network" for your IRC network of choice to get detailed information.
-* `ssl` : Whether to use encryption (SSL) to communicate with the IRC network. Setting this to `true` is recommended.
-* `nickname` : Bot nickname
-* `channelname` : IRC channel name, for example `#minetest-server`
-* `prefix`, `minetest_prefix` : Prefixes for IRC/Minetest commands, required
-Example :
+Table with fields. Required are:
+
+* `network`: IRC network, for example `irc.freenode.net`
+* `port`: Port, on [Freenode](https://freenode.net/kb/answer/chat) it would be `7000` if SSL is used, or else `6667`. Just google "connecting to network" for your IRC network of choice to get detailed information.
+* `ssl`: Whether to use encryption (SSL) to communicate with the IRC network. Setting this to `true` is recommended.
+* `nickname`: Bot nickname
+* `channelname`: IRC channel name, for example `#minetest-server`
+* `prefix`, `minetest_prefix`: Prefixes for IRC bot/Minetest chatcommands, required
+
+Optional fields are:
+
+* `bridge`: Type of process bridge to use can be forced here. Choices are `"file"` and `"socket"`. Sockets are recommended but require `luasocket`.
+* `convert_minetest_colors`: How colors from Minetest chat messages should be converted to IRC. Possible values are `"disabled"`, `"safest"`, `"safe"` and `"hex_safe"` and `"hex"`
+* `handle_internal_markdown`: How Markdown sent from internal MT should be converted to IRC text styles. Possible values are `"disabled"`, `"strip"` and `"convert"`
+* `handle_minetest_markdown`: How Markdown sent from Minetest should be converted to IRC text styles. Possible values are `"disabled"`, `"strip"` and `"convert"`
+* `handle_discord_markdown`: How Markdown sent from Discord should be converted to IRC text styles. Possible values are `"disabled"`, `"strip"` and `"convert"`
+
+Example:
+
```json
{
"irc": {
"prefix": "?",
"minetest_prefix": "!",
- "channelname": "#minetest-server",
- "nickname": "SERVERNAME_Chat",
+ "channelname": "#minetest-server",
+ "nickname": "SERVERNAME_Chat",
"port": 7000,
"ssl": true,
"network": "irc.freenode.net"
@@ -103,21 +127,29 @@ Example :
}
```
+#### `chatcommand_whitelist`/`chatcommand_blacklist`
+
+Whitelist/blacklist of chatcommands which are not available from Discord or IRC. If both or none are set, all chatcommands are blacklisted.
+
## Recommendations
### Consistency
+
It is recommended to **keep consistency**. To do so, channel & chat bot names could be similar across Discord and IRC. The same goes for prefixes.
### Prefixes
+
You should try to keep prefixes similar and memorable, while ensuring that there are no collisions. I recommend the combination of `?` for Discord/IRC commands and `!` for Minetest commands.
Other neat combinations I have thought of are `+` and `-`, or `;` and `:`. Keep in mind that prefixes should be easy to type as well, and that others might have a different keyboard layout.
### Discord Avatar
+
Pixel-art Minetest skin heads always work well as avatars. For an example look you could look at my [Robby-Head](https://github.com/appgurueu/artwork/blob/master/robbyhead.png).
There are tons of skins out there and it's fairly easy to extract the faces (but make sure you don't violate the licenses when using the images).
A good starting point is [Addis Open MT-Skin Database](http://minetest.fensta.bplaced.net/). You can, however, of course also design it yourself. Just grab your favorite pixel-art program and draw a 8x8 head.
You should also make sure to scale the small image up (to at least 256x256), because else Discord scales it up "for you" which makes it lose it's sharp edges.
### Security
-Only two basic hints : Always enable SSL, and don't give your bot token to anyone.
-And of course make sure your server isn't hacked. Messages are sent as plain text over the file bridges.
\ No newline at end of file
+
+Only two basic hints : Always enable SSL, and don't give your bot token to anyone.
+And of course make sure your server isn't hacked. Messages are sent as plain text over the sockets or file bridges.
diff --git a/default_config.json b/default_config.json
index 0d98eca..0837519 100644
--- a/default_config.json
+++ b/default_config.json
@@ -1,6 +1,6 @@
{
- "scheme" : {
- "minetest" : {"mention_prefix":"#FFFF00@", "mention_delim":"#FFFF00, ", "delim":"#FFFF00 : "},
+ "schemes" : {
+ "minetest" : {"message_prefix": "", "mention_prefix": "#FFFF00@", "mention_delim": "#FFFF00, ", "content_prefix": "#FFFF00: #FFFFFF"},
"other" : null
},
diff --git a/discord.lua b/discord.lua
index 5353f14..d876ba9 100644
--- a/discord.lua
+++ b/discord.lua
@@ -17,20 +17,29 @@ function delete_discord_role(linecontent)
end
end
-file_ext.process_bridge_build("discord")
+local bridge
+if bridges.discord.bridge == "files" then
+ bridge = build_file_bridge("discord")
+else
+ bridge = build_bridge("discord")
+end
-file_ext.process_bridge_listen("discord", function(line)
+discord_bridge = bridge
+
+bridge.listen(function(line)
local linecontent=line:sub(6)
if string_ext.starts_with(line, "[MSG]") then
local parts=string_ext.split(linecontent, " ", 2)
local src=parts[1].."[discord]"
- send_to_all(src, src..scheme.other.delim..parts[2], minetest.get_color_escape_sequence(get_color(src))..src..scheme.minetest.delim..parts[2], "discord")
+ local adv_msg=message.new(chatters[src], nil, parts[2])
+ adv_msg.sent_to="discord"
+ send_to_all(adv_msg)
elseif string_ext.starts_with(line, "[GMS]") or string_ext.starts_with(line, "[CGM]") then -- GMS = group message or CGM = channel group message
local parts=string_ext.split(linecontent, " ",3)
local source=parts[1]
local targets=string_ext.split_without_limit(parts[2], ",")
local msg=parts[3]
- local sent_to="nobody"
+ local sent_to
if string_ext.starts_with(line, "[CGM]") then
sent_to="discord"
end
@@ -38,39 +47,29 @@ file_ext.process_bridge_listen("discord", function(line)
for _, target in ipairs(targets) do
targetset[target]=true
end
- local invalid_targets, msg, mt_msg=build_message(source.."[discord]", targets, msg)
- send_to_targets(source.."[discord]", table_ext.set(targets), msg, mt_msg, sent_to)
- if (#invalid_targets) == 1 then
- file_ext.process_bridge_write("discord", "[PMS]"..source.." The target "..invalid_targets[1].." is inexistant.")
- elseif (#invalid_targets) > 1 then
- file_ext.process_bridge_write("discord", "[PMS]"..source.." The targets "..table.concat(invalid_targets, ", ").." are inexistant.")
+ local adv_msg=message.new(chatters[source.."[discord]"], targets, msg)
+ adv_msg.sent_to=sent_to
+ message.mentionpart(adv_msg) --force check mentions
+ send_to_targets(adv_msg)
+ if (#adv_msg.invalid_mentions) == 1 then
+ discord_bridge.write("[PMS]#FFFFFF "..source.." The target "..adv_msg.invalid_mentions[1].." is inexistant.")
+ elseif (#adv_msg.invalid_mentions) > 1 then
+ discord_bridge.write("[PMS]#FFFFFF "..source.." The targets "..table.concat(adv_msg.invalid_mentions, ", ").." are inexistant.")
end
elseif string_ext.starts_with(line, "[CMD]") then
- local parts=string_ext.split(linecontent, " ", 3)
+ local parts=string_ext.split(linecontent, " ", 2)
local source=parts[1]
- local commandname=parts[2]
- local params=parts[3]
- local command=minetest.registered_chatcommands[commandname]
- if command then
- if not table_ext.is_empty(command.privs) then
- file_ext.process_bridge_write("discord", "[ERR]"..source.." Command requires privs.")
- else
- local success, retval = command.func(source.."[discord]", params or "")
- if success then
- file_ext.process_bridge_write("discord", "[SUC]"..source.." "..(retval or "No return value."))
- else
- file_ext.process_bridge_write("discord", "[ERR]"..source.." "..(retval or "No return value."))
- end
- end
- else
- file_ext.process_bridge_write("discord", "[ERR]"..source.."`"+commandname+"` : No such command.")
- end
+ local call=parts[2]
+ local success, retval = call_chatcommand(source.."[discord]", call)
+ local prefix = "[PMS]#FFFFFF "
+ if success then prefix = "[SUC]" elseif success == false then prefix = "[ERR]" end
+ discord_bridge.write(prefix..source.." "..(retval or "No return value."))
elseif string_ext.starts_with(line, "[JOI]") or string_ext.starts_with(line, "[LIS]") then
local parts=string_ext.split(linecontent, " ", 2) --nick & roles
local chatter=parts[1].."[discord]"
join(chatter, {color=parts[2], roles={}, discord=true})
if string_ext.starts_with(line, "[JOI]") then
- send_to_all("", get_color(chatter)..chatter..minetest.get_color_escape_sequence("#FFFFFF").." joined.")
+ minetest.chat_send_all(get_color(chatter)..chatter..minetest.get_color_escape_sequence("#FFFFFF").." joined.")
end
elseif string_ext.starts_with(line, "[EXT]") then
chatters[linecontent.."[discord]"]=nil
@@ -134,24 +133,24 @@ end)
-- Pinging
mt_ext.register_globalstep(1, function()
- file_ext.process_bridge_write("discord", "[PIN]")
+ bridge.write("[PIN]")
end)
-- Killing on_shutdown
minetest.register_on_shutdown(function()
- file_ext.process_bridge_write("discord", "[KIL]")
+ bridge.write("[KIL]")
end)
-file_ext.process_bridge_serve("discord")
+bridge.serve()
-- Start AFTER mods are loaded, so that the player sees chat messages
minetest.register_on_mods_loaded(function()
local java="java"
- local classpath=minetest.get_modpath("adv_chat").."/minetest-chat-bridge-bot/out/production/classes:/home/lars/.gradle/caches/modules-2/files-2.1/net.dv8tion/JDA/3.7.1_388/f534ab5132d8df986e603a404120492d4cdf815e/JDA-3.7.1_388.jar:/home/lars/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/23.5-jre/e9ce4989adf6092a3dab6152860e93d989e8cf88/guava-23.5-jre.jar:/home/lars/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar:/home/lars/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.25/da76ca59f6a57ee3102f8f9bd9cee742973efa8a/slf4j-api-1.7.25.jar:/home/lars/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-collections4/4.1/a4cf4688fe1c7e3a63aa636cc96d013af537768e/commons-collections4-4.1.jar:/home/lars/.gradle/caches/modules-2/files-2.1/org.json/json/20160810/aca5eb39e2a12fddd6c472b240afe9ebea3a6733/json-20160810.jar:/home/lars/.gradle/caches/modules-2/files-2.1/net.sf.trove4j/trove4j/3.0.3/42ccaf4761f0dfdfa805c9e340d99a755907e2dd/trove4j-3.0.3.jar:/home/lars/.gradle/caches/modules-2/files-2.1/club.minnced/opus-java/1.0.2/c2e69f8d9aab5eab7476df8f5558e001657009bd/opus-java-1.0.2.jar:/home/lars/.gradle/caches/modules-2/files-2.1/com.neovisionaries/nv-websocket-client/2.4/da95dda351dba317468b08f8e5575216c05102/nv-websocket-client-2.4.jar:/home/lars/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/3.8.1/4d060ca3190df0eda4dc13415532a12e15ca5f11/okhttp-3.8.1.jar:/home/lars/.gradle/caches/modules-2/files-2.1/org.checkerframework/checker-qual/2.0.0/518929596ee3249127502a8573b2e008e2d51ed3/checker-qual-2.0.0.jar:/home/lars/.gradle/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.0.18/5f65affce1684999e2f4024983835efc3504012e/error_prone_annotations-2.0.18.jar:/home/lars/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/ed28ded51a8b1c6b112568def5f4b455e6809019/j2objc-annotations-1.1.jar:/home/lars/.gradle/caches/modules-2/files-2.1/org.codehaus.mojo/animal-sniffer-annotations/1.14/775b7e22fb10026eed3f86e8dc556dfafe35f2d5/animal-sniffer-annotations-1.14.jar:/home/lars/.gradle/caches/modules-2/files-2.1/club.minnced/opus-java-api/1.0.2/e6e5afd72b5305356ef6d3aa95e84790cd340828/opus-java-api-1.0.2.jar:/home/lars/.gradle/caches/modules-2/files-2.1/club.minnced/opus-java-natives/1.0.2/b62c0be7a49c9bf0933d003cc0418e90518db728/opus-java-natives-1.0.2.jar:/home/lars/.gradle/caches/modules-2/files-2.1/com.squareup.okio/okio/1.13.0/a9283170b7305c8d92d25aff02a6ab7e45d06cbe/okio-1.13.0.jar:/home/lars/.gradle/caches/modules-2/files-2.1/net.java.dev.jna/jna/4.4.0/cb208278274bf12ebdb56c61bd7407e6f774d65a/jna-4.4.0.jar"
+ local jarpath=minetest.get_modpath("adv_chat").."/MinetestChatBridgeBot/build/libs/MinetestChatBridgeBot-all.jar"
local token=bridges.discord.token or "NTc4MjM0NjM5NTc2MDcyMjEx.XPgWKA.ilzmvz-I7XTIML6Emj1jBx4ejLw"
local text_channel=bridges.discord.channelname
local prefixes='"'..bridges.discord.minetest_prefix..'" "'..bridges.discord.prefix..'"'
local guild_id=bridges.discord.guild_id.." " or ""
- file_ext.process_bridge_start("discord", java..' -Dfile.encoding=UTF-8 -classpath "'..classpath..'" appguru.Main "'..token..'" "'..text_channel..'" "%s" "%s" "%s" '..prefixes.." "..guild_id.."&")
+ bridge.start(java..' -jar "'..jarpath..'" "'..token..'" "'..text_channel..'" "%s" "%s" "%s" '..prefixes.." "..guild_id.." &")
end)
\ No newline at end of file
diff --git a/init.lua b/init.lua
index bcf0a7f..3ac8c05 100644
--- a/init.lua
+++ b/init.lua
@@ -8,41 +8,38 @@ local bridge_ifndefs={
irc=adv_chat.bridges.irc
}
-if not bridge_ifndefs.bridge then
- error("OOF")
-end
-
extend_mod_string("adv_chat", string_ext.handle_ifndefs(file_ext.read(get_resource("adv_chat", "colorize_message.lua")), bridge_ifndefs))
-if bridge_ifndefs.bridge then
- adv_chat.scheme.other=adv_chat.scheme.other or {}
- for k, v in pairs(adv_chat.scheme.minetest) do
- local mt_msg, msg=adv_chat.colorize_message(v)
- adv_chat.scheme.minetest[k]=mt_msg
- if not adv_chat.scheme.other[k] then
- adv_chat.scheme.other[k]=msg
- end
- end
-else
- for k, v in pairs(adv_chat.scheme.minetest) do
- local mt_msg=adv_chat.colorize_message(v)
- adv_chat.scheme.minetest[k]=mt_msg
- end
-end
-
extend_mod_string("adv_chat", string_ext.handle_ifndefs(file_ext.read(get_resource("adv_chat", "main.lua")), bridge_ifndefs))
-- Basic API stuff
extend_mod("adv_chat", "unicode")
+extend_mod("adv_chat", "closest_color")
+extend_mod("adv_chat", "trie")
+extend_mod("adv_chat", "text_styles")
+extend_mod("adv_chat", "message")
extend_mod("adv_chat", "hud_channels")
-- Chat bridges
-if adv_chat.bridges.irc then
- extend_mod("adv_chat", "irc")
-end
+if bridge_ifndefs.bridge then
+ extend_mod("adv_chat", "chatcommands")
+ extend_mod("adv_chat", "process_bridges")
+
+ local env = minetest.request_insecure_environment() or error("Error: adv_chat needs to be added to the trusted mods for chat bridges to work. See the Readme for more info.")
+ adv_chat.set_os_execute(env.os.execute)
+ adv_chat.set_socket(env.require("socket"))
-if adv_chat.bridges.discord then
- extend_mod("adv_chat", "discord")
+ if adv_chat.bridges.irc then
+ extend_mod("adv_chat", "irc")
+ end
+
+ if adv_chat.bridges.discord then
+ extend_mod("adv_chat", "discord")
+ end
+
+ adv_chat.build_socket_bridge = nil
+ adv_chat.build_file_bridge = nil
+ adv_chat.build_bridge = nil
end
-- Tests - don't uncomment unless you actually want to test something
diff --git a/irc.lua b/irc.lua
index a4339ee..68abffc 100644
--- a/irc.lua
+++ b/irc.lua
@@ -1,102 +1,112 @@
register_role("irc",{color="#FFFF66"})
-file_ext.process_bridge_build("irc")
+local bridge
+if bridges.discord.bridge == "files" then
+ bridge = build_file_bridge("irc")
+else
+ bridge = build_bridge("irc")
+end
-file_ext.process_bridge_listen("irc", function(line)
+irc_bridge = bridge
+
+local color = function(chattername) return minetest.get_color_escape_sequence((chatters[chattername] and chatters[chattername].color) or "#FFFFFF") end
+
+bridge.listen(function(line)
local linecontent=line:sub(6)
if string_ext.starts_with(line, "[MSG]") then
local parts=string_ext.split(linecontent, " ", 2)
local src=parts[1].."[irc]"
- send_to_all(src, src..scheme.other.delim..parts[2], minetest.get_color_escape_sequence(get_color(src))..src..scheme.minetest.delim..parts[2], "irc")
+ local adv_msg=message.new(chatters[src], nil, parts[2])
+ adv_msg.sent_to="irc"
+ send_to_all(adv_msg)
+ --send_to_all(src, src..scheme.other.delim..parts[2], minetest.get_color_escape_sequence(get_color(src))..src..scheme.minetest.delim..parts[2], "irc")
elseif string_ext.starts_with(line, "[PMS]") then
local parts=string_ext.split(linecontent, " ", 1)
local source=parts[1]
local target=parts[2]
local msg=parts[3]
if string_ext.ends_with(target, "[discord]") then
- file_ext.process_bridge_write("discord", "[PMS]"..source.." "..target.."@you : "..msg)
+ discord_bridge.write("[PMS]"..source.." "..target.."@you : "..msg)
else
if minetest.get_player_by_name(target_and_msg[1]) then
minetest.chat_send_player(target_and_msg[2])
end
end
elseif string_ext.starts_with(line, "[CMD]") then
- local parts=string_ext.split(linecontent, " ", 3)
+ local parts=string_ext.split(linecontent, " ", 2)
local source=parts[1]
- local commandname=parts[2]
- local params=parts[3]
- local command=minetest.registered_chatcommands[commandname]
- if command then
- if not table_ext.is_empty(command.privs) then
- file_ext.process_bridge_write("irc", "[PMS]"..source.." ".."Error: Command requires privs.")
- else
- local success, retval = command.func(source, params)
- local prefix="Unknown"
- if success then prefix="Success" elseif success ~= nil then prefix="Error" end
- file_ext.process_bridge_write("irc", "[PMS]"..source.." "..prefix.." : "..(retval or "No return value."))
- end
- else
- file_ext.process_bridge_write("irc", "[PMS]"..source.." ".."Error: No such command.")
- end
+ local call=parts[2]
+ local success, retval = call_chatcommand(source.."[irc]", call)
+ local prefix="Unknown"
+ if success then prefix="Success" elseif success ~= nil then prefix="Error" end
+ irc_bridge.write("[PMS]"..source.." "..prefix.." : "..(retval or "No return value."))
elseif string_ext.starts_with(line, "[GMS]") or string_ext.starts_with(line, "[CGM]") then -- GMS = group message or CGM = channel group message
local parts=string_ext.split(linecontent, " ",3)
local source=parts[1]
local targets=string_ext.split_without_limit(parts[2], ",")
local msg=parts[3]
- local sent_to="nobody"
+ local sent_to
if string_ext.starts_with(line, "[CGM]") then
sent_to="irc"
end
- targetset={}
- for _, target in ipairs(targets) do
- targetset[target]=true
- end
- local invalid_targets, msg, mt_msg=build_message(source.."[irc]", targets, msg)
- send_to_targets(source.."[irc]", table_ext.set(targets), msg, mt_msg, sent_to)
- if (#invalid_targets) == 1 then
- file_ext.process_bridge_write("irc", "[PMS]"..source.." The target "..invalid_targets[1].." is inexistant.")
- elseif (#invalid_targets) > 1 then
- file_ext.process_bridge_write("irc", "[PMS]"..source.." The targets "..table.concat(invalid_targets, ", ").." are inexistant.")
+ --targetset={}
+ --for _, target in ipairs(targets) do
+ -- targetset[target]=true
+ --end
+ --local invalid_targets, msg, mt_msg=build_message(source.."[irc]", targets, msg)
+ --send_to_targets(source.."[irc]", table_ext.set(targets), msg, mt_msg, sent_to)
+ local adv_msg=message.new(chatters[source.."[discord]"], targets, msg)
+ adv_msg.sent_to=sent_to
+ message.mentionpart(adv_msg) --force check mentions
+ send_to_targets(adv_msg)
+ if (#adv_msg.invalid_mentions) == 1 then
+ irc_bridge.write("[PMS]"..source.." The target "..adv_msg.invalid_mentions[1].." is inexistant.")
+ elseif (#adv_msg.invalid_mentions) > 1 then
+ irc_bridge.write("[PMS]"..source.." The targets "..table.concat(adv_msg.invalid_mentions, ", ").." are inexistant.")
end
elseif string_ext.starts_with(line, "[JOI]") then
local parts=string_ext.split(linecontent, " ", 3) --nick & color & channel
join(parts[1].."[irc]", {color=parts[2], roles={}, irc=true})
- send_to_all("", parts[1].."[irc]".." joined.", minetest.get_color_escape_sequence(parts[2])..
- parts[1].."[irc]"..
- minetest.get_color_escape_sequence("#FFFFFF").." joined.")
+ local chattername=parts[1].."[irc]"
+ minetest.chat_send_all(color(chattername)..
+ chattername..minetest.get_color_escape_sequence("#FFFFFF").." joined.",
+ minetest.get_color_escape_sequence(parts[2])..parts[1].."[irc]"..
+ minetest.get_color_escape_sequence("#FFFFFF").." joined.")
--parts[3])
elseif string_ext.starts_with(line, "[EXT]") then
local parts=string_ext.split(linecontent, " ", 2) --nick & reason
local chattername=parts[1].."[irc]"
- send_to_all("", chattername.." quitted ("..parts[2]..").", minetest.get_color_escape_sequence(get_color(chattername))..
- chattername..minetest.get_color_escape_sequence("#FFFFFF").." quitted ("..parts[2]..").")
+ minetest.chat_send_all(color(chattername)..
+ chattername..minetest.get_color_escape_sequence("#FFFFFF").." quitted ("..parts[2]..").", minetest.get_color_escape_sequence(get_color(chattername))..
+ chattername..minetest.get_color_escape_sequence("#FFFFFF").." quitted ("..parts[2]..").")
chatters[chattername]=nil
elseif string_ext.starts_with(line, "[BYE]") then
local parts=string_ext.split(linecontent, " ", 2) --nick & reason
local chattername=parts[1].."[irc]"
- send_to_all("", chattername.." left ("..parts[2]..").", minetest.get_color_escape_sequence(get_color(chattername))..
+ minetest.chat_send_all(color(chattername)..chattername..minetest.get_color_escape_sequence("#FFFFFF").." left ("..parts[2]..").", minetest.get_color_escape_sequence(get_color(chattername))..
chattername..minetest.get_color_escape_sequence("#FFFFFF").." left ("..parts[2]..").")
chatters[chattername]=nil
elseif string_ext.starts_with(line, "[NCK]") then
local parts=string_ext.split(linecontent, " ", 2) --nick & newnick
irc_users[parts[1]]=nil
irc_users[parts[2]]=true
- minetest.chat_send_all(parts[1].."[irc] is now known as "..parts[2].."[irc]")
+ local chattername=parts[1].."[irc]"
+ minetest.chat_send_all(color(chattername)..chattername..minetest.get_color_escape_sequence("#FFFFFF").." is now known as "..parts[2].."[irc]")
end
end)
-- Pinging
mt_ext.register_globalstep(1, function()
- file_ext.process_bridge_write("irc", "[PIN]")
+ bridge.write("[PIN]")
end)
-file_ext.process_bridge_serve("irc")
+bridge.serve()
--"/usr/lib/jvm/jdk-11.0.1/bin/java -classpath /home/lars/IdeaProjects/minetest-chat-bridge-irc-bot/out/production/minetest-chat-bridge-irc-bot Main 7000 irc.freenode.net true MT_Chat_Bridge #mtchatbridgetest /home/lars/.minetest/worlds/world/bridges/irc/output.txt /home/lars/.minetest/worlds/world/bridges/irc/input.txt"
-- Start AFTER mods are loaded, so that the player sees chat messages
minetest.register_on_mods_loaded(function()
local java="java"
- local classpath=minetest.get_modpath("adv_chat").."/minetest-chat-bridge-irc-bot/out/production/minetest-chat-bridge-irc-bot"
+ local classpath=minetest.get_modpath("adv_chat").."/MinetestChatBridgeIRCBot/build/classes/java/main"
local port=bridges.irc.port
local network=bridges.irc.network
local ssl=tostring(bridges.irc.ssl)
@@ -104,5 +114,5 @@ minetest.register_on_mods_loaded(function()
local textchannel=bridges.irc.channelname
local prefixes='"'..bridges.discord.minetest_prefix..'" "'..bridges.discord.prefix..'"'
- file_ext.process_bridge_start("irc", java..' -Dfile.encoding=UTF-8 -classpath "'..classpath..'" appguru.Main '..port..' "'..network..'" '..ssl..' "'..nick..'" "'..textchannel..'" "%s" "%s" "%s" '..prefixes..' &')
+ bridge.start(java..' -Dfile.encoding=UTF-8 -classpath "'..classpath..'" appguru.Main '..port..' "'..network..'" '..ssl..' "'..nick..'" "'..textchannel..'" "%s" "%s" "%s" '..prefixes..' &')
end)
\ No newline at end of file
diff --git a/main.lua b/main.lua
index 5623dea..772e0af 100644
--- a/main.lua
+++ b/main.lua
@@ -1,8 +1,3 @@
----
---- Generated by EmmyLua(https://github.com/EmmyLua)
---- Created by lars.
----
-
--- THIS FILE USES CUSTOM STUFF (IFNDEFS) IMPLEMENTED USING MODLIB - DON'T CHANGE THE WAY IT IS EXECUTED IN init.lua
-- TODO (planned features)
@@ -17,7 +12,6 @@ player_ext.set_property_default("adv_chat.blocked",{chatters={}, roles={}})
channels={} --channelname -> definition : {hud_pos, mode, autoremove, max_messages, max_lines, wrap_chars, smartwrap}
roles={} -- Role -> players -> true
chatters={} -- Chatter -> stuff
---blocked={} -- Receiver -> what he blocks : roles and playernames, true
to_be_sent={} --Receiver -> { {sender, message, date, time} }
scheme={minetest={mention_prefix=minetest.get_color_escape_sequence("#FFFF66").."@", mention_delim=minetest.get_color_escape_sequence("#FFFF66")..", ",
delim=minetest.get_color_escape_sequence("#FFFF66").." : "..minetest.get_color_escape_sequence("#FFFFFF")},
@@ -55,36 +49,36 @@ function send_to_chatter(sendername, chattername, message)
else
--IFNDEF discord
if chatters[chattername].discord then
- file_ext.process_bridge_write("discord", "[PMS]"..get_color(chattername).." "..chattername.." "..message)
+ discord_bridge.write("[PMS]"..get_color(chattername).." "..chattername.." "..message)
end
--ENDIF
--IFNDEF irc
if chatters[chattername].irc then
- file_ext.process_bridge_write("irc", "[PMS]"..chattername.." "..message)
+ irc_bridge.write("[PMS]"..chattername.." "..message)
end
--ENDIF
end
end
-function send_to_targets(sendername, targets, message, mt_message, sent_to)
+function send_to_targets(msg)
+ message.mentionpart(msg)
--IFNDEF bridge
- local discord_mentioned, irc_mentioned=targets.discord, targets.irc
+ local discord_mentioned, irc_mentioned=msg.targets.discord, msg.targets.irc
--ENDIF
- for target, _ in pairs(targets) do
+ for target, _ in pairs(msg.targets) do
if not chatters[target] then
if roles[target] then
- table_ext.add_all(targets, roles[target].affected)
+ table_ext.add_all(msg.targets, roles[target].affected)
end
- targets[target]=nil
+ msg.targets[target]=nil
end
end
- local mt_message=mt_message or message
local discord_chatters={}
local irc_chatters={}
- for chatter, _ in pairs(targets) do
+ for chatter, _ in pairs(msg.targets) do
if not is_blocked(chatter, sendername) then
if chatters[chatter].minetest then
- minetest.chat_send_player(chatter, mt_message)
+ minetest.chat_send_player(chatter, message.build(msg, "minetest"))
else
--IFNDEF discord
if chatters[chatter].discord then
@@ -101,25 +95,21 @@ function send_to_targets(sendername, targets, message, mt_message, sent_to)
end
--IFNDEF discord
- if sent_to ~= "discord" then
+ if msg.sent_to ~= "discord" then
if discord_mentioned then
- file_ext.process_bridge_write("discord", "[MSG]"..get_color(sendername).." "..message)
- else
- if #discord_chatters > 0 then
- file_ext.process_bridge_write("discord", "[PMS]"..get_color(sendername).." "..table.concat(discord_chatters, ",").." "..message)
- end
+ discord_bridge.write("[MSG]"..(msg.chatter.color).." "..message.build(msg, "discord"))
+ elseif #discord_chatters > 0 then
+ discord_bridge.write("[PMS]"..(msg.chatter.color).." "..table.concat(discord_chatters, ",").." "..message.build(msg, "discord"))
end
end
--ENDIF
--IFNDEF irc
- if sent_to ~= "irc" then
+ if msg.sent_to ~= "irc" then
if irc_mentioned then
- file_ext.process_bridge_write("irc", "[MSG]"..message)
- else
- if #irc_chatters > 0 then
- file_ext.process_bridge_write("irc", "[PMS]"..table.concat(irc_chatters, ",").." "..message)
- end
+ irc_bridge.write("[MSG]"..message.build(msg, "irc"))
+ elseif #irc_chatters > 0 then
+ irc_bridge.write("[PMS]"..table.concat(irc_chatters, ",").." "..message.build(msg, "irc"))
end
end
--ENDIF
@@ -129,6 +119,10 @@ function join(name, def)
if not def.roles then
def.roles={}
end
+ if not def.name then
+ def.name=name
+ end
+ def.service = ((def.minetest and "minetest") or (def.irc and "irc")) or "discord"
chatters[name]=def
local to_be_received=to_be_sent[name]
if to_be_received then
@@ -172,7 +166,33 @@ end
--IFNDEF bridge
minetest.original_chat_send_all=minetest.chat_send_all
minetest.chat_send_all=function(msg)
- send_to_all("", minetest.strip_colors(msg), msg)
+ local adv_message=message.new(nil, nil, msg)
+ adv_message.internal=true
+ send_to_all(adv_message)
+end
+
+minetest.original_chat_send_player=minetest.chat_send_player
+minetest.chat_send_player=function(name, msg)
+ local chatter=chatters[name]
+ if not chatter then
+ return
+ end
+ if chatter.minetest then
+ return minetest.original_chat_send_player(name, msg)
+ end
+ local adv_message=message.new(nil, nil, msg)
+ adv_message.internal=true
+ local to_be_sent=message.build(adv_message, chatter.service)
+ --IFNDEF irc
+ if chatter.irc then
+ irc_bridge.write("[PMS]"..chatter.name.." "..to_be_sent)
+ end
+ --ENDIF
+ --IFNDEF discord
+ if chatter.discord then
+ discord_bridge.write("[PMS]#FFFFFF "..chatter.name.." "..to_be_sent)
+ end
+ --ENDIF
end
--ENDIF
@@ -201,6 +221,7 @@ function remove_role(player, role, expected_value)
end
end
+-- deprecated, minetest-only
function get_color(chatter)
if chatters[chatter] then
return chatters[chatter].color or "#FFFFFF"
@@ -208,22 +229,23 @@ function get_color(chatter)
return "#FFFFFF"
end
-function send_to_all(sender, msg, mt_msg, sent_to)
+function send_to_all(msg)
--IFNDEF irc
- if sent_to ~= "irc" then
- file_ext.process_bridge_write("irc", "[MSG]"..msg)
+ if msg.sent_to ~= "irc" then
+ irc_bridge.write("[MSG]"..message.build(msg, "irc"))
end
--ENDIF
--IFNDEF discord
- if sent_to ~= "discord" then
- file_ext.process_bridge_write("discord", "[MSG]"..get_color(sender).." "..msg)
+ if msg.sent_to ~= "discord" then
+ discord_bridge.write("[MSG]"..((msg.chatter and msg.chatter.color) or "#FFFFFF").." "..message.build(msg, "discord"))
end
--ENDIF
- if sent_to ~= "minetest" then
- local mt_msg=mt_msg or msg
+ if msg.sent_to ~= "minetest" then
+ local mt_msg
for _,player in pairs(minetest.get_connected_players()) do
local playername=player:get_player_name()
- if not is_blocked(playername, sender) then
+ if not msg.chatter or not is_blocked(playername, msg.chatter) then
+ mt_msg=mt_msg or message.build(msg, "minetest")
minetest.chat_send_player(playername, mt_msg)
end
end
@@ -327,13 +349,14 @@ on_chat_message=function(sender, msg)
for _, part in pairs(parts) do
table.insert(mentions, string_ext.trim(part, " "))
end
- local invalid_targets, msg, mt_msg=build_message(sender, mentions, msg_content)
+ local adv_msg=message.new(chatters[sender], mentions, msg_content)
+ message.mentionpart(adv_msg)
table.insert(mentions, sender)
- send_to_targets(sender, table_ext.set(mentions), msg, mt_msg, "nobody")
- if (#invalid_targets) == 1 then
- minetest.chat_send_player(sender, "The target "..invalid_targets[1].." is inexistant.")
- elseif (#invalid_targets) > 1 then
- minetest.chat_send_player(sender, "The targets "..table.concat(invalid_targets, ", ").." are inexistant.")
+ send_to_targets(adv_msg)--sender, table_ext.set(mentions), msg, mt_msg, "nobody")
+ if #adv_msg.invalid_mentions == 1 then
+ minetest.chat_send_player(sender, "The target "..adv_msg.invalid_mentions[1].." is inexistant.")
+ elseif #adv_msg.invalid_mentions > 1 then
+ minetest.chat_send_player(sender, "The targets "..table.concat(adv_msg.invalid_mentions, ", ").." are inexistant.")
end
else
local sender_color=get_color(sender)
@@ -341,16 +364,16 @@ on_chat_message=function(sender, msg)
for _,player in pairs(minetest.get_connected_players()) do
players[player:get_player_name()]=true
end
- local msg, mt_msg=parse_message(msg)
- mt_msg=minetest.get_color_escape_sequence(sender_color)..sender..scheme.minetest.delim..msg
- msg=sender..scheme.other.delim..msg
- send_to_all(sender, msg, mt_msg)
+ local adv_msg=message.new(chatters[sender], mentions, msg_content)
+ send_to_all(adv_msg)
end
return true
end
minetest.register_on_chat_message(on_chat_message)
-minetest.register_chatcommand("msg",{
+local prefix = (cmd_ext and "chat ") or "chat_"
+
+minetest.register_chatcommand(prefix.."msg",{
params = "",
description = "Send a message to a chatter as soon as they join",
privs={},
@@ -380,7 +403,7 @@ button_exit[7,0;2,0.75;send;Send]
no_prepend[]
]]
-minetest.register_chatcommand("say", {
+minetest.register_chatcommand(prefix.."say", {
params="",
description="Send chat message using entry field.",
privs={discord_user=false, irc_user=false},
@@ -395,7 +418,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end)
-minetest.register_chatcommand("block", {
+minetest.register_chatcommand(prefix.."block", {
params = " | ",
description = "Block messages from chatter or role",
privs={},
@@ -419,7 +442,7 @@ minetest.register_chatcommand("block", {
end
})
-minetest.register_chatcommand("unblock", {
+minetest.register_chatcommand(prefix.."unblock", {
params = " | ",
description = "Unblock messages from chatter or role",
privs={},
@@ -441,4 +464,38 @@ minetest.register_chatcommand("unblock", {
blocked[param]=nil
return true, type..param.." was unblocked"
end
+})
+
+minetest.register_chatcommand(prefix.."login", {
+ params = "",
+ description = "Log in as (fake) player to execute chatcommands as them",
+ privs = {chatter=true},
+ func = function(sendername, param)
+ param=string_ext.trim(param)
+ if param:len() == 0 then
+ return false, "No arguments given - missing name and password."
+ end
+ local name, password = unpack(string_ext.split(param, " ", 2))
+ password = password or ""
+ local auth = minetest.get_auth_handler().get_auth(name)
+ if auth and minetest.check_password_entry(name, auth.password, password) then
+ chatters[sendername].login = name
+ return true, 'Logged in as "'..name..'"'
+ end
+ return false, "Wrong playername/password. : "..name..", "..password.."!="..auth.password
+ end
+})
+
+minetest.register_chatcommand(prefix.."logout", {
+ params = "",
+ description = "Log out from your (fake) player account",
+ privs = {chatter=true},
+ func = function(sendername, param)
+ if not chatters[sendername].login then
+ return false, "Not logged in."
+ end
+ local login = chatters[sendername].login
+ chatters[sendername].login = nil
+ return true, 'Logged out from "'..login..'"'
+ end
})
\ No newline at end of file
diff --git a/message.lua b/message.lua
new file mode 100644
index 0000000..b5ca9c3
--- /dev/null
+++ b/message.lua
@@ -0,0 +1,227 @@
+-- TODO handle and mentions like @ or @ (modification of Discord bot needed)
+
+message={}
+
+function message.new(chatter, mentions, content)
+ return {chatter=chatter, mentions=mentions, content=content}
+end
+
+local function unicode(message)
+ message.unicode_content = message.unicode_content or parse_unicode(message.content)
+ return message.unicode_content
+end
+
+local function colorized(message)
+ if not message.colorized_content then
+ message.colorized_content, message.uncolorized_content=colorize_message(unicode(message))
+ end
+ return message.colorized_content
+end
+
+local function uncolorized(message)
+ if not message.uncolorized_content then
+ message.colorized_content, message.uncolorized_content=colorize_message(unicode(message))
+ end
+ message.uncolorized_content=minetest.strip_colors(message.uncolorized_content)
+ return message.uncolorized_content
+end
+
+local to = {
+ minetest = {
+ from={
+ internal=function(message)
+ return message.content
+ end,
+ minetest = colorized,
+ irc = function(message)
+ message.colorized_content = irc_to_minetest(colorized(message))
+ return message.colorized_content
+ end,
+ discord = uncolorized
+ }
+ },
+
+ irc = {
+ from={
+ internal=function(message)
+ return message.content
+ end,
+ minetest = function(message)
+ return colorized(message)
+ end,
+ irc = function(message)
+ return colorized(message)
+ end,
+ discord = function(message)
+ return minetest_to_irc(colorized(message))
+ end
+ }
+ },
+
+ discord = {
+ from={
+ internal=function(message)
+ return minetest.strip_colors(message.content)
+ end,
+ minetest = uncolorized,
+ irc = function(message)
+ return uncolorized(message)
+ end,
+ discord = uncolorized
+ }
+ }
+}
+
+local builders = to
+
+builders.minetest.scheme = schemes.minetest
+builders.irc.scheme = schemes.irc
+builders.discord.scheme = schemes.discord
+
+function message.mentionpart(msg)
+ if not msg.mentionpart then
+ msg.invalid_mentions={}
+ msg.targets={}
+ msg.mentionpart={}
+ for _, mention in ipairs(msg.mentions or {}) do
+ if not msg.targets[mention] then
+ msg.targets[mention]=true
+ if roles[mention] then
+ table.insert(msg.mentionpart,roles[mention].color)
+ table.insert(msg.mentionpart, mention)
+ elseif chatters[mention] then
+ table.insert(msg.mentionpart, chatters[mention].color)
+ table.insert(msg.mentionpart, mention)
+ else
+ table.insert(msg.invalid_mentions,mention)
+ end
+ end
+ end
+ end
+end
+
+local mentionpart_builders = {
+ irc=nil,
+ discord=function(msg)
+ if not msg.uncolorized_mentionpart then
+ msg.uncolorized_mentionpart={}
+ for i=2, #msg.mentionpart, 2 do
+ table.insert(msg.uncolorized_mentionpart,msg.mentionpart[i])
+ end
+ end
+ return "uncolorized_mentionpart"
+ end,
+ minetest=function(msg)
+ if not msg.mt_mentionpart then
+ msg.mt_mentionpart={}
+ for index, item in ipairs(msg.mentionpart) do
+ table.insert(msg.mt_mentionpart, ((index % 2 == 0) and item) or minetest.get_color_escape_sequence(item))
+ end
+ end
+ return "mt_mentionpart"
+ end
+}
+
+local function wrap_builder(source, goal, wrapper)
+ local old_builder = builders[source].from[goal]
+ builders[source].from[goal] = function(msg) return wrapper(old_builder(msg)) end
+end
+
+if bridges.discord then
+ if not bridges.discord.convert_internal_markdown then
+ wrap_builder("discord", "internal", escape_markdown)
+ end
+ if not bridges.discord.convert_minetest_markdown then
+ wrap_builder("discord", "minetest", escape_markdown)
+ end
+ if bridges.discord.handle_irc_styles == "escape_markdown" then
+ wrap_builder("discord", "irc", escape_markdown)
+ elseif bridges.discord.handle_irc_styles ~= "disabled" then
+ wrap_builder("discord", "irc", irc_to_markdown)
+ end
+end
+
+if bridges.irc then
+
+ if bridges.irc.handle_discord_markdown == "strip" then
+ wrap_builder("irc", "discord", strip_markdown)
+ elseif bridges.irc.handle_discord_markdown ~= "disabled" then
+ wrap_builder("irc", "discord", markdown_to_irc)
+ end
+
+ if bridges.irc.handle_minetest_markdown == "strip" then
+ wrap_builder("irc", "minetest", strip_markdown)
+ elseif bridges.irc.handle_discord_markdown ~= "disabled" then
+ wrap_builder("irc", "minetest", markdown_to_irc)
+ end
+
+ if bridges.irc.handle_internal_markdown == "strip" then
+ wrap_builder("irc", "internal", strip_markdown)
+ elseif bridges.irc.handle_discord_markdown ~= "disabled" then
+ wrap_builder("irc", "internal", markdown_to_irc)
+ end
+
+ if bridges.irc.convert_minetest_colors=="disabled" then
+ mentionpart_builders.irc=mentionpart_builders.discord
+ else
+ local old_from_minetest = builders.irc.from.minetest
+ builders.irc.from.minetest=function(msg) return minetest_to_irc(old_from_minetest(msg)) end
+ local old_from_internal = builders.irc.from.internal
+ builders.irc.from.internal=function(msg) return minetest_to_irc(old_from_internal(msg)) end
+ mentionpart_builders.irc=function(msg)
+ if not msg.irc_mentionpart then
+ msg.irc_mentionpart={}
+ for index, item in ipairs(msg.mentionpart) do
+ if index % 2 == 0 then
+ table.insert(msg.irc_mentionpart, item)
+ elseif item ~= "#FFFFFF" then
+ table.insert(msg.irc_mentionpart, convert_color_to_irc(item:sub(2)))
+ end
+ table.insert(msg.irc_mentionpart, ((index % 2 == 0) and item) or (item ~= "#FFFFFF" and convert_color_to_irc(item:sub(2))))
+ end
+ end
+ return "irc_mentionpart"
+ end
+ end
+end
+
+function message.mentionpart_target(msg, target)
+ local builder=mentionpart_builders[target]
+ message.mentionpart(msg)
+ local name=builder(msg)
+ local text = name.."_text"
+ if not msg[text] then
+ msg[text]=table.concat(msg[name], builders[target].mention_delim)
+ end
+ return msg[text]
+end
+
+
+function message.build(msg, target)
+ local build=target.."_build"
+ if not msg[build] then
+ local builder = builders[target]
+ if msg.internal then
+ msg[build]=builder.from.internal(msg)
+ return msg[build]
+ end
+ local conversion = builder.from[msg.chatter.service]
+ local content = conversion(msg)
+ local source = (msg.chatter.name and msg.chatter.name)
+ if source and msg.chatter.color then
+ if target=="minetest" then
+ source=minetest.get_color_escape_sequence(msg.chatter.color)..source
+ elseif target=="irc" and bridges.irc.style_conversion.color~="disabled" then
+ local to_escape, color=convert_color_to_irc(msg.chatter.color:sub(2))
+ if source:sub(1,1)==to_escape then
+ source=string.char(0x02)..string.char(0x02)..source
+ end
+ source=color..source
+ end
+ end
+ local mentions = (msg.mentions and next(msg.mentions) and builder.scheme.mention_prefix..message.mentionpart_target(msg, target)..builder.scheme.content_prefix)
+ if not mentions and source then source=source..builder.scheme.content_prefix end
+ msg[build]=builder.scheme.message_prefix..(source or "")..(mentions or "")..content..builder.scheme.message_suffix
+ end
+ return msg[build]
+end
\ No newline at end of file
diff --git a/minetest-chat-bridge-bot/.attach_pid29291 b/minetest-chat-bridge-bot/.attach_pid29291
deleted file mode 100644
index e69de29..0000000
diff --git a/minetest-chat-bridge-bot/.attach_pid31402 b/minetest-chat-bridge-bot/.attach_pid31402
deleted file mode 100644
index e69de29..0000000
diff --git a/minetest-chat-bridge-bot/.attach_pid31496 b/minetest-chat-bridge-bot/.attach_pid31496
deleted file mode 100644
index e69de29..0000000
diff --git a/minetest-chat-bridge-bot/.attach_pid32551 b/minetest-chat-bridge-bot/.attach_pid32551
deleted file mode 100644
index e69de29..0000000
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/fileChanges/last-build.bin b/minetest-chat-bridge-bot/.gradle/4.10/fileChanges/last-build.bin
deleted file mode 100644
index f76dd23..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/fileChanges/last-build.bin and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/fileContent/fileContent.lock b/minetest-chat-bridge-bot/.gradle/4.10/fileContent/fileContent.lock
deleted file mode 100644
index 6a1b176..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/fileContent/fileContent.lock and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/fileHashes/fileHashes.bin b/minetest-chat-bridge-bot/.gradle/4.10/fileHashes/fileHashes.bin
deleted file mode 100644
index 2425e23..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/fileHashes/fileHashes.bin and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/fileHashes/fileHashes.lock b/minetest-chat-bridge-bot/.gradle/4.10/fileHashes/fileHashes.lock
deleted file mode 100644
index 10b6d60..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/fileHashes/fileHashes.lock and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/gc.properties b/minetest-chat-bridge-bot/.gradle/4.10/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/classAnalysis.bin b/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/classAnalysis.bin
deleted file mode 100644
index 0f50b0b..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/classAnalysis.bin and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/javaCompile.lock b/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/javaCompile.lock
deleted file mode 100644
index 8a5c3f9..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/javaCompile.lock and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/taskHistory.bin b/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/taskHistory.bin
deleted file mode 100644
index a85838d..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/javaCompile/taskHistory.bin and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/taskHistory/taskHistory.bin b/minetest-chat-bridge-bot/.gradle/4.10/taskHistory/taskHistory.bin
deleted file mode 100644
index 20366be..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/taskHistory/taskHistory.bin and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/4.10/taskHistory/taskHistory.lock b/minetest-chat-bridge-bot/.gradle/4.10/taskHistory/taskHistory.lock
deleted file mode 100644
index 932977a..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/4.10/taskHistory/taskHistory.lock and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/buildOutputCleanup.lock
deleted file mode 100644
index f6edcf0..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/cache.properties b/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/cache.properties
deleted file mode 100644
index 5e6dd2c..0000000
--- a/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/cache.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-#Fri Dec 14 15:02:12 CET 2018
-gradle.version=4.10
diff --git a/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/outputFiles.bin b/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/outputFiles.bin
deleted file mode 100644
index 3c2db96..0000000
Binary files a/minetest-chat-bridge-bot/.gradle/buildOutputCleanup/outputFiles.bin and /dev/null differ
diff --git a/minetest-chat-bridge-bot/.gradle/vcs-1/gc.properties b/minetest-chat-bridge-bot/.gradle/vcs-1/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/minetest-chat-bridge-bot/.idea/compiler.xml b/minetest-chat-bridge-bot/.idea/compiler.xml
deleted file mode 100644
index 77821e9..0000000
--- a/minetest-chat-bridge-bot/.idea/compiler.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/minetest-chat-bridge-bot/.idea/encodings.xml b/minetest-chat-bridge-bot/.idea/encodings.xml
deleted file mode 100644
index 15a15b2..0000000
--- a/minetest-chat-bridge-bot/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/minetest-chat-bridge-bot/.idea/gradle.xml b/minetest-chat-bridge-bot/.idea/gradle.xml
deleted file mode 100644
index 3163861..0000000
--- a/minetest-chat-bridge-bot/.idea/gradle.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/minetest-chat-bridge-bot/.idea/misc.xml b/minetest-chat-bridge-bot/.idea/misc.xml
deleted file mode 100644
index 402f058..0000000
--- a/minetest-chat-bridge-bot/.idea/misc.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-