This commit is contained in:
Louis Mazin 2026-02-01 13:13:22 +01:00
parent 4a4771c60b
commit be3cfeb081
6 changed files with 227 additions and 0 deletions

View File

@ -68,6 +68,19 @@ module.exports = {
// Supprimer la liaison
await deleteUserLink(interaction.user.id);
// Retirer le rôle de joueur lié
try {
const guild = interaction.guild;
const member = await guild.members.fetch(interaction.user.id);
const linkedRole = guild.roles.cache.get('1467491093649035475');
if (linkedRole && member.roles.cache.has(linkedRole.id)) {
await member.roles.remove(linkedRole);
console.log(`✅ Rôle retiré de ${interaction.user.tag}`);
}
} catch (roleError) {
console.error('Erreur lors du retrait du rôle:', roleError);
}
const successEmbed = new EmbedBuilder()
.setColor(0x00FF00)
.setTitle('✅ Déliaison réussie')

View File

@ -68,6 +68,19 @@ module.exports = {
if (confirmation.customId === 'admin_confirm_unlink') {
await deleteUserLink(discordUser.id);
// Retirer le rôle de joueur lié
try {
const guild = interaction.guild;
const member = await guild.members.fetch(discordUser.id);
const linkedRole = guild.roles.cache.get('1467491093649035475');
if (linkedRole && member.roles.cache.has(linkedRole.id)) {
await member.roles.remove(linkedRole);
console.log(`✅ Rôle retiré de ${discordUser.tag}`);
}
} catch (roleError) {
console.error('Erreur lors du retrait du rôle:', roleError);
}
const successEmbed = new EmbedBuilder()
.setColor(0x00FF00)
.setTitle('✅ Liaison supprimée')

View File

@ -65,6 +65,19 @@ module.exports = {
if (result.success) {
await updateUserLinkWithUsername(discordUser.id, discordUser.tag);
// Ajouter le rôle de joueur lié
try {
const guild = interaction.guild;
const member = await guild.members.fetch(discordUser.id);
const linkedRole = guild.roles.cache.get('1467491093649035475');
if (linkedRole && !member.roles.cache.has(linkedRole.id)) {
await member.roles.add(linkedRole);
console.log(`✅ Rôle ajouté à ${discordUser.tag}`);
}
} catch (roleError) {
console.error('Erreur lors de l\'ajout du rôle:', roleError);
}
const embed = new EmbedBuilder()
.setColor(0x00FF00)
.setTitle('✅ Liaison manuelle réussie')

View File

@ -1,6 +1,7 @@
const axios = require('axios');
const WebSocket = require('ws');
const { verifyLinkCode, updateUserLinkWithUsername, updateLastConnection } = require('./database.js');
const { handlePalworldChat } = require('./palworld-bridge.js');
let ws = null;
let reconnectTimeout = null;
@ -102,6 +103,22 @@ const handleLinkCommand = async (playerName, playerData, code) => {
const user = await client.users.fetch(result.discordId).catch(() => null);
if (user) {
await updateUserLinkWithUsername(result.discordId, user.tag);
// Ajouter le rôle de joueur lié
try {
const guild = client.guilds.cache.get(process.env.GUILD_ID);
if (guild) {
const member = await guild.members.fetch(result.discordId);
const linkedRole = guild.roles.cache.get('1467491093649035475');
if (linkedRole && !member.roles.cache.has(linkedRole.id)) {
await member.roles.add(linkedRole);
console.log(`✅ Rôle ajouté à ${user.tag}`);
}
}
} catch (roleError) {
console.error('Erreur lors de l\'ajout du rôle:', roleError);
}
await user.send(
`✅ **Liaison réussie !**\n\n` +
`Votre compte Discord a été lié avec succès à votre compte Palworld:\n` +
@ -321,6 +338,9 @@ const connectWebSocket = async (pterodactylToken, serverId) => {
}
}
// Transférer le message de chat vers Discord via le bridge
await handlePalworldChat(log);
const linkData = parseLogMessage(log);
if (linkData) {

View File

@ -8,6 +8,7 @@ const clean = require('./cleaner.js');
const { Client, GatewayIntentBits, Collection, Events, Partials } = require('discord.js');
const { initDatabase, createTables, cleanExpiredCodes } = require('./database.js');
const { startConsoleMonitoring } = require('./consoleMonitor.js');
const { initPalworldBridge } = require('./palworld-bridge.js');
const client = new Client({ intents:
[
@ -62,6 +63,10 @@ client.once('ready', async () => {
console.log('📦 Système de liaison activé');
// Initialiser le pont Palworld-Discord
const bridgeChannelId = '1467491354924814411';
initPalworldBridge(client, bridgeChannelId);
startConsoleMonitoring(client, process.env.PTERODACTYL_API_TOKEN);
} catch (error) {
console.error('⚠️ Erreur lors de l\'initialisation de la base de données');

163
palworld-bridge.js Normal file
View File

@ -0,0 +1,163 @@
const axios = require('axios');
const { getUserLink, getAllLinks } = require('./database.js');
let bridgeClient = null;
let bridgeChannelId = null;
let wsInstance = null;
// Initialiser le bridge
const initPalworldBridge = (client, channelId, ws) => {
bridgeClient = client;
bridgeChannelId = channelId;
wsInstance = ws;
console.log('🌉 Pont Palworld-Discord initialisé');
// Écouter les messages du salon Discord
client.on('messageCreate', async (message) => {
// Ignorer les messages du bot lui-même
if (message.author.bot) return;
// Vérifier que c'est bien le salon du pont
if (message.channelId !== bridgeChannelId) return;
try {
// Récupérer le pseudo Palworld lié
const userLink = await getUserLink(message.author.id);
if (!userLink) {
// L'utilisateur n'est pas lié
await message.reply('❌ Vous devez lier votre compte Palworld pour envoyer des messages. Utilisez `/lier-rygainland`');
return;
}
// Envoyer le message vers Palworld via broadcast
await sendToPalworld(userLink.palworld_username, message.content);
} catch (error) {
console.error('Erreur lors de l\'envoi du message vers Palworld:', error);
await message.reply('❌ Erreur lors de l\'envoi du message vers Palworld').catch(() => {});
}
});
};
// Envoyer un message vers Palworld via RCON broadcast
const sendToPalworld = async (palworldUsername, content) => {
try {
// Nettoyer le message (enlever les mentions, emojis personnalisés, etc.)
let cleanContent = content
.replace(/<@!?\d+>/g, '@utilisateur') // Remplacer les mentions
.replace(/<#\d+>/g, '#salon') // Remplacer les mentions de salons
.replace(/<:.+?:\d+>/g, '') // Enlever les emojis personnalisés
.replace(/\n/g, ' ') // Remplacer les sauts de ligne
.trim();
// Limiter la longueur du message
if (cleanContent.length > 200) {
cleanContent = cleanContent.substring(0, 197) + '...';
}
// Format du message pour Palworld
const broadcastMessage = `[Discord] ${palworldUsername}: ${cleanContent}`;
// Envoyer via l'API Palworld
await axios({
method: 'post',
url: 'http://play.louismazin.ovh:8212/v1/api/announce',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Basic ${process.env.PALWORLD_API_TOKEN}`
},
data: {
message: broadcastMessage
}
});
console.log(`✅ Message envoyé à Palworld: ${broadcastMessage}`);
} catch (error) {
console.error('Erreur lors de l\'envoi vers Palworld:', error.message);
throw error;
}
};
// Parser les messages de chat Palworld et les envoyer sur Discord
const parsePalworldChatAndSend = async (log) => {
if (!bridgeClient || !bridgeChannelId) return;
// Format: [2026-02-01 13:08:02] [CHAT] <Lili Asuna> coucou
const chatRegex = /\[.*?\]\s*\[CHAT\]\s*<(.+?)>\s*(.+)/i;
const match = log.match(chatRegex);
if (!match) return;
const palworldUsername = match[1].trim();
const messageContent = match[2].trim();
// Ignorer les messages de commande !lier
if (messageContent.toLowerCase().startsWith('!lier')) return;
try {
// Récupérer le salon
const channel = await bridgeClient.channels.fetch(bridgeChannelId).catch(() => null);
if (!channel) {
console.error('❌ Impossible de trouver le salon du pont');
return;
}
// Chercher si le joueur a un compte Discord lié
const allLinks = await getAllLinks();
const linkedUser = allLinks.find(link => link.palworld_username === palworldUsername);
if (linkedUser) {
// Utilisateur lié : utiliser webhook pour afficher sa PP et son pseudo Discord
try {
const discordUser = await bridgeClient.users.fetch(linkedUser.discord_id).catch(() => null);
if (discordUser) {
// Créer ou récupérer un webhook pour ce salon
const webhooks = await channel.fetchWebhooks();
let webhook = webhooks.find(wh => wh.name === 'Palworld Bridge');
if (!webhook) {
webhook = await channel.createWebhook({
name: 'Palworld Bridge',
avatar: 'https://i.imgur.com/AfFp7pu.png' // Logo Palworld
});
}
// Envoyer via webhook avec le pseudo et l'avatar Discord
await webhook.send({
content: messageContent,
username: discordUser.username,
avatarURL: discordUser.displayAvatarURL({ dynamic: true, size: 256 })
});
console.log(`✅ Message Palworld envoyé sur Discord (via webhook): ${discordUser.username}: ${messageContent}`);
return;
}
} catch (error) {
console.error('Erreur lors de l\'envoi via webhook:', error);
// Fallback vers message normal
}
}
// Utilisateur non lié ou erreur webhook : envoyer un message normal
await channel.send(`**${palworldUsername}**: ${messageContent}`);
console.log(`✅ Message Palworld envoyé sur Discord: ${palworldUsername}: ${messageContent}`);
} catch (error) {
console.error('Erreur lors de l\'envoi du message Palworld vers Discord:', error);
}
};
// Fonction appelée par consoleMonitor pour traiter les messages de chat
const handlePalworldChat = async (log) => {
await parsePalworldChatAndSend(log);
};
module.exports = {
initPalworldBridge,
handlePalworldChat
};