var sessionIdToFollow = null;
let socket = null;
let paused = false;
let usernamesAndProfileIds = new Map();
let userSessions = new Map();
let positionsTracking = new Map(); // To track the positions of users
let repeatingUsers = new Set(); // To keep track of whose messages are being repeated
let repeatedMessages = new Set(); // To keep track of already repeated messages
let logWindow = window.open("", "LogWindow", "width=600,height=400");
logWindow.document.write("
Log Outputbody { margin-top: 50px; margin-bottom: 50px; padding-bottom: 60px; }");
init();
const header = logWindow.document.createElement('div');
header.style.position = 'fixed';
header.style.top = '0';
header.style.width = '100%';
header.style.backgroundColor = '#f1f1f1';
header.style.zIndex = '1000';
header.style.padding = '10px';
header.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
logWindow.document.body.appendChild(header);
// Status Indicator
const statusIndicator = logWindow.document.createElement('span');
statusIndicator.innerText = 'Status: Running';
statusIndicator.style.color = 'green';
statusIndicator.style.marginLeft = '10px';
header.appendChild(statusIndicator);
// Existing buttons
const pauseButton = logWindow.document.createElement('button');
pauseButton.innerText = 'Pause';
pauseButton.style.marginRight = '10px';
pauseButton.addEventListener('click', pause);
header.appendChild(pauseButton);
const resumeButton = logWindow.document.createElement('button');
resumeButton.innerText = 'Resume';
resumeButton.style.marginRight = '10px';
resumeButton.addEventListener('click', resume);
header.appendChild(resumeButton);
const initButton = logWindow.document.createElement('button');
initButton.innerText = 'Init';
initButton.addEventListener('click', init);
header.appendChild(initButton);
// Clear Log button
const clearLogButton = logWindow.document.createElement('button');
clearLogButton.innerText = 'Clear Log';
clearLogButton.style.marginRight = '10px';
clearLogButton.addEventListener('click', function() {
logWindow.document.getElementById('log').innerText = ''; // Clear the log display
});
header.appendChild(clearLogButton);
// Follow dropdown and button
const followDropdown = logWindow.document.createElement('select');
followDropdown.style.marginRight = '10px';
header.appendChild(followDropdown);
const followButton = logWindow.document.createElement('button');
followButton.innerText = 'Follow';
followButton.style.marginRight = '10px';
followButton.addEventListener('click', function() {
const usernameToFollow = followDropdown.value;
const profileId = getProfileId(usernameToFollow);
if (profileId) {
sessionIdToFollow = userSessions.get(profileId);
printAlert(`🟡 Now following ${usernameToFollow}`);
} else {
printAlert(`🔴 Cannot follow ${usernameToFollow}. User not found.`);
}
});
header.appendChild(followButton);
// Stop Following button
const stopFollowButton = logWindow.document.createElement('button');
stopFollowButton.innerText = 'Stop Following';
stopFollowButton.addEventListener('click', function() {
sessionIdToFollow = null; // Clear the session ID to stop following
printAlert(`🔴 Stopped following.`);
});
header.appendChild(stopFollowButton);
// Repeat dropdown and button
const repeatDropdown = logWindow.document.createElement('select');
repeatDropdown.style.marginRight = '10px';
header.appendChild(repeatDropdown);
const repeatButton = logWindow.document.createElement('button');
repeatButton.innerText = 'Repeat';
repeatButton.style.marginRight = '10px';
repeatButton.addEventListener('click', function() {
const usernameToRepeat = repeatDropdown.value;
const profileId = getProfileId(usernameToRepeat);
if (profileId) {
if (repeatingUsers.has(profileId)) {
repeatingUsers.delete(profileId);
printAlert(`🔴 Stopped repeating messages from ${usernameToRepeat}`);
repeatedMessages.clear(); // Clear repeated messages on toggling off
} else {
repeatingUsers.add(profileId);
printAlert(`🟢 Now repeating messages from ${usernameToRepeat}`);
}
} else {
printAlert(`🔴 Cannot repeat from ${usernameToRepeat}. User not found.`);
}
});
header.appendChild(repeatButton);
// To display the chat input
const inputBar = logWindow.document.createElement('div');
inputBar.style.position = 'fixed';
inputBar.style.bottom = '0';
inputBar.style.width = '100%';
inputBar.style.backgroundColor = '#f1f1f1';
inputBar.style.zIndex = '1000';
inputBar.style.padding = '10px';
inputBar.style.boxShadow = '0 -2px 4px rgba(0,0,0,0.1)';
logWindow.document.body.appendChild(inputBar);
const inputField = logWindow.document.createElement('input');
inputField.type = 'text';
inputField.style.width = '80%';
inputField.style.marginRight = '10px';
inputBar.appendChild(inputField);
inputField.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
say(inputField.value);
inputField.value = '';
}
});
function updateStatus() {
statusIndicator.innerText = paused ? 'Status: Paused' : 'Status: Running';
statusIndicator.style.color = paused ? 'red' : 'green';
}
function init() {
socket = null;
printAlert("Initializing...");
const nativeWebSocket = window.WebSocket;
window.WebSocket = function (...args) {
socket = new nativeWebSocket(...args);
return socket;
};
printAlert(`🟡 Searching for websockets. You can now join the Chatroom.`);
usernamesAndProfileIds.clear();
userSessions.clear();
positionsTracking.clear(); // Clear previous positions
sessionIdToFollow = null; // Reset follow state
repeatingUsers.clear(); // Clear any currently repeating users
repeatedMessages.clear(); // Clear previously repeated messages
checkSockets();
}
function checkSockets() {
if (socket === null) {
window.setTimeout(checkSockets, 100);
printAlert("🟡 No socket found. Retrying...");
} else {
printAlert("🟡 Room found. Starting to listen...");
storeUsernameOnNewJoin(socket);
runChat(socket);
setTimeout(() => {
socket.send(`42["7004",{"position":{"x":-5.86839676,"y":0.03366667,"z":8.124479}}]`);
}, 5000);
}
}
function runChat(ws) {
ws.addEventListener('message', function(event) {
// Handle PING Interval
if (/"pingInterval":15000/.test(event.data)) {
printAlert("🟡 Wrong socket. Looking for a new socket...");
init();
return;
}
storeUsernameOnSpawn(ws);
deleteUserOnLeave(ws);
const messageMatch = /42\["message",\{"messageType":"2001","messageContent":\{"sessionId":(\d+),"profileId":"([^"]+)","message":"([^"]+)"/.exec(event.data);
const positionMatch = /42\["message",\{"messageType":"7103","messageContent":\{"position":\{"x":(-?\d+\.\d+),"y":(-?\d+\.\d+),"z":(-?\d+\.\d+)\},"sessionId":(\d+)\}\}\]/.exec(event.data);
// Handling Messages
if (messageMatch) {
const messageSessionId = messageMatch[1];
const profileId = messageMatch[2];
const message = messageMatch[3];
const username = usernamesAndProfileIds.get(profileId) || "Unknown";
printAlert(`${username}: ${message}`);
// Check if the message is from a user that is in the repeatingUsers set
if (!paused && repeatingUsers.has(profileId) && message && !repeatedMessages.has(message)) {
// Send message once without username
const formattedMessage = message.replace(/^.*?:\s*/, ''); // Remove username part
ws.send(`42["chatv2:send",{"message":"${formattedMessage}"}]`);
printAlert(`🔵🗣️ ${username}: ${formattedMessage}`);
repeatedMessages.add(message); // Mark this message as repeated
}
// If following this user, send movement commands to the server
if (!paused && sessionIdToFollow === messageSessionId) {
printAlert(`🔵 Following message from ${username}: ${message}`);
}
}
// Handling Position Updates
if (positionMatch) {
const x = positionMatch[1];
const y = positionMatch[2];
const z = positionMatch[3];
const followedSessionId = positionMatch[4];
positionsTracking.set(followedSessionId, { x, y, z });
// If following this user, send movement commands to the server
if (sessionIdToFollow === followedSessionId) {
printAlert(`🔵 Moving to position (${x}, ${y}, ${z}) for following.`);
ws.send(`42["7003",{"position":{"x":${x},"y":${y},"z":${z}}}]`);
ws.send(`42["7004",{"position":{"x":${x},"y":${y},"z":${z}}}]`);
}
}
});
}
function printAlert(str) {
logWindow.document.getElementById('log').innerText += `${new Date().toLocaleTimeString()} - ${str}\n`;
}
function storeUsernameOnSpawn(ws) {
ws.addEventListener('message', function(event) {
const match = /42\["message",\{"messageType":"2000","messageContent":\{"success":true,"roomId":"[^"]+","profileId":"[^"]+","sessionId":\d+,"otherUsers":\[(.*?)\]\}\}\]/.exec(event.data);
if (match) {
let otherUsers = match[1];
const userRegex = /\{"profileId":"([^"]+)","sessionId":(\d+),"profileData":\{"name":"([^"]+)"/g;
let userMatch;
while ((userMatch = userRegex.exec(otherUsers)) !== null) {
const profileId = userMatch[1];
const sessionId = userMatch[2];
const username = userMatch[3];
usernamesAndProfileIds.set(profileId, username);
userSessions.set(profileId, sessionId);
printAlert(`🟡 Profile ID: ${profileId}, Username: ${username}, Session ID: ${sessionId}`);
updateFollowDropdown();
updateRepeatDropdown(); // Update the repeat dropdown as well
}
}
});
}
function storeUsernameOnNewJoin(ws) {
ws.addEventListener('message', function(event) {
const match = /42\["message",\{"messageType":"20000","messageContent":\{"profileId":"([^"]+)","sessionId":(\d+),"profileData":\{"name":"([^"]+)"/.exec(event.data);
if (match) {
const profileId = match[1];
const sessionId = match[2];
const username = match[3];
if (!usernamesAndProfileIds.has(profileId) || userSessions.get(profileId) !== sessionId) {
usernamesAndProfileIds.set(profileId, username);
userSessions.set(profileId, sessionId);
printAlert(`🟡 New Join - Profile ID: ${profileId}, Username: ${username}, Session ID: ${sessionId}`);
updateFollowDropdown();
updateRepeatDropdown(); // Update the repeat dropdown as well
}
}
});
}
function deleteUserOnLeave(ws) {
ws.addEventListener('message', function(event) {
const match = /42\["message",\{"messageType":"20090","messageContent":\{"sessionId":(\d+),"profileId":"([^"]+)"\}\}\]/.exec(event.data);
if (match) {
const sessionId = match[1];
const profileId = match[2];
if (usernamesAndProfileIds.has(profileId)) {
const username = usernamesAndProfileIds.get(profileId);
usernamesAndProfileIds.delete(profileId);
userSessions.delete(profileId);
printAlert(`🟡 User Left - Profile ID: ${profileId}, Username: ${username}, Session ID: ${sessionId}`);
updateFollowDropdown();
updateRepeatDropdown(); // Update the repeat dropdown as well
}
}
});
}
function getProfileId(username) {
for (let [profileId, name] of usernamesAndProfileIds.entries()) {
if (name === username) {
return profileId;
}
}
return null;
}
function getSocket() {
return socket;
}
function say(message) {
if (!paused) {
socket.send(`42["chatv2:send",{"message":"${message}"}]`);
printAlert(`🔵🗣️ SYSTEM: ${message}`);
}
}
function pause() {
paused = true;
printAlert("🟡 Chat Bot paused");
updateStatus();
}
function resume() {
paused = false;
printAlert("🟡 Chat Bot resumed");
updateStatus();
}
function updateFollowDropdown() {
followDropdown.innerHTML = '';
usernamesAndProfileIds.forEach((username, profileId) => {
const option = document.createElement('option');
option.value = username;
option.innerText = username;
followDropdown.appendChild(option);
});
}
function updateRepeatDropdown() {
repeatDropdown.innerHTML = '';
usernamesAndProfileIds.forEach((username, profileId) => {
const option = document.createElement('option');
option.value = username;
option.innerText = username;
repeatDropdown.appendChild(option);
});
}
setInterval(() => {
const options = Array.from(followDropdown.options);
options.forEach(option => {
if (!usernamesAndProfileIds.has(getProfileId(option.value))) {
followDropdown.removeChild(option);
}
});
const repeatOptions = Array.from(repeatDropdown.options);
repeatOptions.forEach(option => {
if (!usernamesAndProfileIds.has(getProfileId(option.value))) {
repeatDropdown.removeChild(option);
}
});
}, 5000);