mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-07-26 09:55:26 +02:00
Merge 3ee54b3cf0
into 7348ddd458
This commit is contained in:
commit
482b79ded9
6 changed files with 565 additions and 69 deletions
47
config.json
Normal file
47
config.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"minecraft_version": "1.21.1", // supports up to 1.21.1
|
||||
"host": "127.0.0.1", // or "localhost", "your.ip.address.here"
|
||||
"port": 55916,
|
||||
"auth": "offline", // or "microsoft"
|
||||
|
||||
// the mindserver manages all agents and hosts the UI
|
||||
"host_mindserver": true, // if true, the mindserver will be hosted on this machine. otherwise, specify a public IP address
|
||||
"mindserver_host": "localhost",
|
||||
"mindserver_port": 8080,
|
||||
|
||||
// the base profile is shared by all bots for default prompts/examples/modes
|
||||
"base_profile": "./profiles/defaults/survival.json", // also see creative.json, god_mode.json
|
||||
"profiles": [
|
||||
"./andy.json",
|
||||
// "./profiles/gpt.json",
|
||||
// "./profiles/claude.json",
|
||||
// "./profiles/gemini.json",
|
||||
// "./profiles/llama.json",
|
||||
// "./profiles/qwen.json",
|
||||
// "./profiles/grok.json",
|
||||
// "./profiles/mistral.json",
|
||||
// "./profiles/deepseek.json",
|
||||
|
||||
// using more than 1 profile requires you to /msg each bot indivually
|
||||
// individual profiles override values from the base profile
|
||||
],
|
||||
"load_memory": false, // load memory from previous session
|
||||
"init_message": "Respond with hello world and your name", // sends to all on spawn
|
||||
"only_chat_with": [], // users that the bots listen to and send general messages to. if empty it will chat publicly
|
||||
"speak": false, // allows all bots to speak through system text-to-speech. works on windows, mac, on linux you need to `apt install espeak`
|
||||
"language": "en", // translate to/from this language. Supports these language names: https://cloud.google.com/translate/docs/languages
|
||||
"show_bot_views": false, // show bot's view in browser at localhost:3000, 3001...
|
||||
|
||||
"allow_insecure_coding": false, // allows newAction command and model can write/run code on your computer. enable at own risk
|
||||
"allow_vision": false, // allows vision model to interpret screenshots as inputs
|
||||
"blocked_actions" : [], // commands to disable and remove from docs. Ex: ["!setMode"]
|
||||
"code_timeout_mins": -1, // minutes code is allowed to run. -1 for no timeout
|
||||
"relevant_docs_count": 5, // number of relevant code function docs to select for prompting. -1 for all
|
||||
|
||||
"max_messages": 15, // max number of messages to keep in context
|
||||
"num_examples": 2, // number of examples to give to the model
|
||||
"max_commands": -1, // max number of commands that can be used in consecutive responses. -1 for no limit
|
||||
"verbose_commands": true, // show full command syntax
|
||||
"narrate_behavior": true, // chat simple automatic actions ('Picking up item!')
|
||||
"chat_bot_messages": true, // publicly chat messages to other bots
|
||||
}
|
21
settings.js
21
settings.js
|
@ -1,3 +1,6 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const settings = {
|
||||
"minecraft_version": "1.21.1", // supports up to 1.21.1
|
||||
"host": "127.0.0.1", // or "localhost", "your.ip.address.here"
|
||||
|
@ -47,6 +50,24 @@ const settings = {
|
|||
"log_all_prompts": false, // log ALL prompts to file
|
||||
}
|
||||
|
||||
const configPath = path.resolve('./src/server/saved_settings.json'); // This is to save user-modified settings edited via the Mindserver.
|
||||
if(fs.existsSync(configPath)) {
|
||||
try {
|
||||
const newSettings = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
Object.assign(settings, newSettings);
|
||||
} catch (error) {
|
||||
console.error("Error reading config.json. Using default settings.", error);
|
||||
}
|
||||
} else {
|
||||
fs.writeFileSync(configPath, JSON.stringify(settings, null, 4))
|
||||
}
|
||||
|
||||
// Function to update settings
|
||||
export function updateSettings(newSettings) {
|
||||
Object.assign(settings, newSettings);
|
||||
fs.writeFileSync(configPath, JSON.stringify(settings, null, 4));
|
||||
}
|
||||
|
||||
// these environment variables override certain settings
|
||||
if (process.env.MINECRAFT_PORT) {
|
||||
settings.port = process.env.MINECRAFT_PORT;
|
||||
|
|
|
@ -3,6 +3,8 @@ import express from 'express';
|
|||
import http from 'http';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import settings, { updateSettings } from '../../settings.js';
|
||||
import fs from 'fs';
|
||||
|
||||
// Module-level variables
|
||||
let io;
|
||||
|
@ -128,6 +130,27 @@ export function createMindServer(port = 8080) {
|
|||
console.error('Error: ', error);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('get-settings', (callback) => {
|
||||
callback(settings);
|
||||
});
|
||||
|
||||
socket.on('update-settings', (newSettings) => {
|
||||
updateSettings(newSettings);
|
||||
});
|
||||
|
||||
socket.on('get-profile-dir', (callback) => {
|
||||
const profileDir = path.join(__dirname, '../../profiles/');
|
||||
fs.readdir(profileDir, (err, files) => {
|
||||
if (err) {
|
||||
console.error("Could not list the profiles.", err);
|
||||
callback([]);
|
||||
}
|
||||
|
||||
const fileNames = files.filter(file => file.endsWith('.json')).map(file => './profiles/' + file);
|
||||
callback(fileNames);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(port, 'localhost', () => {
|
||||
|
|
|
@ -1,68 +1,135 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Mindcraft</title>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background: #1a1a1a;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
#agents {
|
||||
background: #2d2d2d;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
h1 {
|
||||
color: #ffffff;
|
||||
}
|
||||
.agent {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
background: #363636;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.restart-btn, .start-btn, .stop-btn {
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.restart-btn {
|
||||
background: #4CAF50;
|
||||
}
|
||||
.start-btn {
|
||||
background: #2196F3;
|
||||
}
|
||||
.stop-btn {
|
||||
background: #f44336;
|
||||
}
|
||||
.restart-btn:hover { background: #45a049; }
|
||||
.start-btn:hover { background: #1976D2; }
|
||||
.stop-btn:hover { background: #d32f2f; }
|
||||
.status-icon {
|
||||
font-size: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.status-icon.online {
|
||||
color: #4CAF50;
|
||||
}
|
||||
.status-icon.offline {
|
||||
color: #f44336;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="/styles.css">
|
||||
<meta viewport="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Mindcraft</h1>
|
||||
<div id="agents"></div>
|
||||
<div id="agents" class="container"></div>
|
||||
<div id="settings" class="container">
|
||||
<h3>Edit Settings</h3>
|
||||
<button onclick="toggleSettings()" id="settingsToggler">Show Settings</button>
|
||||
<div id="settingsContainer" class="miniContainer" style="display:none;">
|
||||
<br>
|
||||
<em>Edits won't take effect until restarting Mindcraft.</em>
|
||||
<br>
|
||||
<div class="formOption">
|
||||
<label for="mcVersion">Minecraft Version: </label>
|
||||
<input id="mcVersion" type="text" placeholder="Up to 1.21.1">
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcHostSelector">Host: </label>
|
||||
<input id="mcHostSelector" type="text" placeholder="localhost">
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcPort">Port: </label>
|
||||
<input id="mcPort" type="number" placeholder="55916">
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcAuth">Authentication Method: </label>
|
||||
<select id="mcAuth">
|
||||
<option value="offline">Offline (requires cracked server)</option>
|
||||
<option value="microsoft">Microsoft Account</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcBaseProfile">Base Profile: </label>
|
||||
<select id="mcBaseProfile">
|
||||
<option value="./profiles/defaults/survival.json">Survival</option>
|
||||
<option value="./profiles/defaults/creative.json">Creative</option>
|
||||
<option value="./profiles/defaults/god_mode.json">God Mode</option>
|
||||
</select>
|
||||
<h5>The base profile is shared by all bots for default prompts/examples/modes</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcProfileList">Profiles: </label>
|
||||
<div id="mcProfileList"></div>
|
||||
<button onclick="addProfileItem(`mcProfileList`, `./andy.json`)" class="blue-btn add-btn"><svg width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="white"><rect x="10" y="2" width="4" height="20"/><rect x="2" y="10" width="20" height="4"/></g></svg>Add Item</button>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcLoadMemory">Load Memory?</label>
|
||||
<input type="radio" name="mcLoadMemory" value="true">Yes</input>
|
||||
<input type="radio" name="mcLoadMemory" value="false" checked>No</input>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcInitMessage">Initial Message</label>
|
||||
<input id="mcInitMessage" type="text" placeholder="Respond with hello world and your name" style="min-width:40%;">
|
||||
<h5>This message gets sent to all bots on spawn.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcOnlyChatWith">Only chat with: (leave empty to chat publicly)</label>
|
||||
<div id="mcOnlyChatWith"></div>
|
||||
<button onclick="addProfileItem(`mcOnlyChatWith`, `Bob123`)" class="blue-btn add-btn"><svg width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="white"><rect x="10" y="2" width="4" height="20"/><rect x="2" y="10" width="20" height="4"/></g></svg>Add Item</button>
|
||||
<h5>Users that the bots listen to and send general messages to. If empty, it will chat publicly.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcSpeak">Speak?</label>
|
||||
<input type="radio" name="mcSpeak" value="true">Yes</input>
|
||||
<input type="radio" name="mcSpeak" value="false" checked>No</input>
|
||||
<h5>Allows all bots to speak through system text-to-speech.<br>This works on Windows and Mac, but on Linux you may need to run <code>sudo apt install espeak</code> first.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcLanguage">Language: </label>
|
||||
<input id="mcLanguage" type="text" placeholder="en">
|
||||
<h5>Translates chat into specified language. <a href="https://cloud.google.com/translate/docs/languages">Supported languages</a></h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcShowBotViews">Show bot views in browser?</label>
|
||||
<input type="radio" name="mcShowBotViews" value="true">Yes</input>
|
||||
<input type="radio" name="mcShowBotViews" value="false" checked>No</input>
|
||||
<h5>Only supports 1.20.4 and previous versions.<br>These can be accessed at http://localhost:3000, 3001, 3002, etc. depending on which bot you want to view.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcAllowInsecureCoding">Allow Insecure Coding?</label>
|
||||
<input type="radio" name="mcAllowInsecureCoding" value="true">Yes</input>
|
||||
<input type="radio" name="mcAllowInsecureCoding" value="false" checked>No</input>
|
||||
<h5>Allows newAction command and model can write/run code on your computer. Enable at your own risk (it's fine if nobody <b>untrustworthy</b> is playing with your bot).</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcAllowVision">Allow Vision?</label>
|
||||
<input type="radio" name="mcAllowVision" value="true">Yes</input>
|
||||
<input type="radio" name="mcAllowVision" value="false" checked>No</input>
|
||||
<h5>Allows the vision model to interpret screenshots as inputs. Requires version 1.20.4 or less.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcBlockedActions">Blocked Actions: </label>
|
||||
<div id="mcBlockedActions"></div>
|
||||
<button onclick="addProfileItem(`mcBlockedActions`, `!setMode`)" class="blue-btn add-btn"><svg width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="white"><rect x="10" y="2" width="4" height="20"/><rect x="2" y="10" width="20" height="4"/></g></svg>Add Item</button>
|
||||
<h5>Commands to disable and remove from the docs.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcMessageHistory">Maxmimum Message History Length: </label>
|
||||
<input id="mcMessageHistory" type="number" placeholder="15">
|
||||
<h5>Maximum number of previous messages to keep in context. Increasing it may produce longer response times and higher cost if using a paid API, but with the benefit of increasing memory.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcVerboseCommands">Verbose Commands?</label>
|
||||
<input type="radio" name="mcVerboseCommands" value="true" checked>Yes</input>
|
||||
<input type="radio" name="mcVerboseCommands" value="false">No</input>
|
||||
<h5>Show full command syntax.</h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcNarrateBehavior">Narrate Behavior?</label>
|
||||
<input type="radio" name="mcNarrateBehavior" value="true" checked>Yes</input>
|
||||
<input type="radio" name="mcNarrateBehavior" value="false">No</input>
|
||||
<h5>Chat simple, automatic actions for example <code>Picking up item!</code></h5>
|
||||
</div>
|
||||
<div class="formOption">
|
||||
<label for="mcChatBotMessages">Chat to other bots?</label>
|
||||
<input type="radio" name="mcChatBotMessages" value="true" checked>Yes</input>
|
||||
<input type="radio" name="mcChatBotMessages" value="false">No</input>
|
||||
<h5>Publicly chat messages to other bots.</h5>
|
||||
</div>
|
||||
<div class="formOption" style="display:flex;">
|
||||
<button class="green-btn add-btn" onclick="saveSettings()"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="24" fill="currentColor" class="bi bi-floppy" viewBox="0 0 16 16"><path d="M11 2H9v3h2z"/><path d="M1.5 0h11.586a1.5 1.5 0 0 1 1.06.44l1.415 1.414A1.5 1.5 0 0 1 16 2.914V14.5a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 0 14.5v-13A1.5 1.5 0 0 1 1.5 0M1 1.5v13a.5.5 0 0 0 .5.5H2v-4.5A1.5 1.5 0 0 1 3.5 9h9a1.5 1.5 0 0 1 1.5 1.5V15h.5a.5.5 0 0 0 .5-.5V2.914a.5.5 0 0 0-.146-.353l-1.415-1.415A.5.5 0 0 0 13.086 1H13v4.5A1.5 1.5 0 0 1 11.5 7h-7A1.5 1.5 0 0 1 3 5.5V1H1.5a.5.5 0 0 0-.5.5m3 4a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 .5-.5V1H4zM3 15h10v-4.5a.5.5 0 0 0-.5-.5h-9a.5.5 0 0 0-.5.5z"/></svg>Save</button>
|
||||
<button class="red-btn add-btn" onclick="getSettings()"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16"><path fill="white" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/></svg>Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const socket = io();
|
||||
|
@ -78,17 +145,17 @@
|
|||
</span>
|
||||
<div>
|
||||
${agent.in_game ? `
|
||||
<button class="stop-btn" onclick="stopAgent('${agent.name}')">Stop</button>
|
||||
<button class="restart-btn" onclick="restartAgent('${agent.name}')">Restart</button>
|
||||
<input type="text" id="messageInput" placeholder="Enter a message or command..."></input><button class="start-btn" onclick="sendMessage('${agent.name}', document.getElementById('messageInput').value)">Send</button>
|
||||
<button class="red-btn" onclick="stopAgent('${agent.name}')">Stop</button>
|
||||
<button class="green-btn" onclick="restartAgent('${agent.name}')">Restart</button>
|
||||
<input type="text" id="messageInput" placeholder="Enter a message or command..."></input><button class="blue-btn" onclick="sendMessage('${agent.name}', document.getElementById('messageInput').value)">Send</button>
|
||||
` : `
|
||||
<button class="start-btn" onclick="startAgent('${agent.name}')">Start</button>
|
||||
<button class="blue-btn" onclick="startAgent('${agent.name}')">Start</button>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
`).join('') +
|
||||
`<button class="stop-btn" onclick="killAllAgents()">Stop All</button>
|
||||
<button class="stop-btn" onclick="shutdown()">Shutdown</button>` :
|
||||
`<button class="red-btn" onclick="killAllAgents()">Stop All</button>
|
||||
<button class="red-btn" onclick="shutdown()">Shutdown</button>` :
|
||||
'<div class="agent">No agents connected</div>';
|
||||
});
|
||||
|
||||
|
@ -111,10 +178,208 @@
|
|||
function shutdown() {
|
||||
socket.emit('shutdown');
|
||||
}
|
||||
|
||||
function sendMessage(agentName, message) {
|
||||
socket.emit('send-message', agentName, message)
|
||||
}
|
||||
|
||||
function sendMessage(agentName, message) {
|
||||
socket.emit('send-message', agentName, message)
|
||||
}
|
||||
|
||||
let pathProfiles;
|
||||
function getProfilesFromPath() {
|
||||
socket.emit('get-profile-dir', (response) => {
|
||||
pathProfiles = response;
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
document.getElementById("settingsContainer").style.display = document.getElementById("settingsContainer").style.display === "none" ? "block" : "none";
|
||||
document.getElementById("settingsToggler").innerText = document.getElementById("settingsToggler").innerText === "Show Settings" ? "Hide Settings" : "Show Settings";
|
||||
if (document.getElementById("settingsContainer").style.display = "block") {
|
||||
getSettings();
|
||||
}
|
||||
}
|
||||
|
||||
let settings;
|
||||
function getSettings() {
|
||||
socket.emit('get-settings', (response) => {
|
||||
settings = response;
|
||||
console.log(settings);
|
||||
updateSettings(settings);
|
||||
})
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
const newSettings = getNewSettings();
|
||||
socket.emit('update-settings', newSettings);
|
||||
}
|
||||
|
||||
function updateListItem(listId, listContent, enabled = true, clear = true) {
|
||||
if (clear) {
|
||||
document.getElementById(listId).innerHTML = "";
|
||||
listContent.forEach(element => {
|
||||
addProfileItem(listId, element, enabled);
|
||||
});
|
||||
} else {
|
||||
const list = document.getElementById(listId);
|
||||
const existingItemsDivs = document.querySelectorAll(`#${listId} .list-item`);
|
||||
let existingItems = Array.from(existingItemsDivs)
|
||||
.map(item => item.querySelector('input[type="text"]').value);
|
||||
listContent.forEach(element => {
|
||||
if (existingItems.includes(element)) {
|
||||
const item = Array.from(list.querySelectorAll('.list-item'))
|
||||
.find(item => item.querySelector('input[type="text"]').value === element);
|
||||
if (item) {
|
||||
const checkbox = item.querySelector('input[type="checkbox"]');
|
||||
console.log(`Setting this to ${enabled}: `, checkbox);
|
||||
console.log("Checkbox in DOM?", document.body.contains(checkbox));
|
||||
console.log("Before: ", checkbox.checked);
|
||||
checkbox.checked = enabled;
|
||||
console.log("After: ", checkbox.checked);
|
||||
const itemName = item.querySelector('.name');
|
||||
if (checkbox.checked) {
|
||||
itemName.classList.remove('not-selected');
|
||||
} else {
|
||||
itemName.classList.add('not-selected');
|
||||
}
|
||||
} else {
|
||||
addProfileItem(listId, element, enabled);
|
||||
}
|
||||
} else {
|
||||
addProfileItem(listId, element, enabled);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function updateBooleanRadio(radioName, value) {
|
||||
const trueRadio = document.querySelector(`input[name="${radioName}"][value="true"]`);
|
||||
const falseRadio = document.querySelector(`input[name="${radioName}"][value="false"]`);
|
||||
trueRadio.checked = value;
|
||||
falseRadio.checked = !value;
|
||||
}
|
||||
|
||||
function getBooleanRadio(radioName) {
|
||||
return document.querySelector(`input[name="${radioName}"][value="true"]`).checked;
|
||||
}
|
||||
|
||||
function updateSettings(settings) {
|
||||
// string/integer fields
|
||||
document.getElementById("mcVersion").value = settings["minecraft_version"];
|
||||
document.getElementById("mcHostSelector").value = settings["host"];
|
||||
document.getElementById("mcPort").value = settings["port"];
|
||||
document.getElementById("mcAuth").value = settings["auth"];
|
||||
document.getElementById("mcBaseProfile").value = settings["base_profile"];
|
||||
document.getElementById("mcInitMessage").value = settings["init_message"];
|
||||
document.getElementById("mcLanguage").value = settings["language"];
|
||||
document.getElementById("mcMessageHistory").value = settings["max_messages"];
|
||||
|
||||
// boolean fields
|
||||
updateBooleanRadio("mcLoadMemory", settings["load_memory"]);
|
||||
updateBooleanRadio("mcSpeak", settings["speak"]);
|
||||
updateBooleanRadio("mcShowBotViews", settings["show_bot_views"]);
|
||||
updateBooleanRadio("mcAllowInsecureCoding", settings["allow_insecure_coding"]);
|
||||
updateBooleanRadio("mcAllowVision", settings["allow_vision"]);
|
||||
updateBooleanRadio("mcVerboseCommands", settings["verbose_commands"]);
|
||||
updateBooleanRadio("mcNarrateBehavior", settings["narrate_behavior"]);
|
||||
updateBooleanRadio("mcChatBotMessages", settings["chat_bot_messages"]);
|
||||
|
||||
// array/list fields
|
||||
updateListItem("mcBlockedActions", settings["blocked_actions"]);
|
||||
updateListItem("mcOnlyChatWith", settings["only_chat_with"]);
|
||||
|
||||
// handling profiles is special
|
||||
updateListItem("mcProfileList", settings["profiles"]);
|
||||
pathProfiles = undefined;
|
||||
getProfilesFromPath();
|
||||
const intervalId = setInterval(() => {
|
||||
if (pathProfiles !== undefined) {
|
||||
clearInterval(intervalId);
|
||||
updateListItem("mcProfileList", pathProfiles, enabled=false);
|
||||
updateListItem("mcProfileList", settings["profiles"], enabled=true, clear = false);
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function getNewSettings() {
|
||||
let settings = {};
|
||||
|
||||
// string/integer fields
|
||||
settings["minecraft_version"] = document.getElementById("mcVersion").value;
|
||||
settings["host"] = document.getElementById("mcHostSelector").value;
|
||||
settings["port"] = parseInt(document.getElementById("mcPort").value, 10); // Convert to integer using base 10
|
||||
settings["auth"] = document.getElementById("mcAuth").value;
|
||||
settings["base_profile"] = document.getElementById("mcBaseProfile").value;
|
||||
settings["init_message"] = document.getElementById("mcInitMessage").value;
|
||||
settings["language"] = document.getElementById("mcLanguage").value;
|
||||
settings["max_messages"] = parseInt(document.getElementById("mcMessageHistory").value, 10); // Convert to integer using base 10
|
||||
|
||||
// boolean fields
|
||||
settings["load_memory"] = getBooleanRadio("mcLoadMemory");
|
||||
settings["speak"] = getBooleanRadio("mcSpeak");
|
||||
settings["show_bot_views"] = getBooleanRadio("mcShowBotViews");
|
||||
settings["allow_insecure_coding"] = getBooleanRadio("mcAllowInsecureCoding");
|
||||
settings["allow_vision"] = getBooleanRadio("mcAllowVision");
|
||||
settings["verbose_commands"] = getBooleanRadio("mcVerboseCommands");
|
||||
settings["narrate_behavior"] = getBooleanRadio("mcNarrateBehavior");
|
||||
settings["chat_bot_messages"] = getBooleanRadio("mcChatBotMessages");
|
||||
|
||||
// array/list fields
|
||||
settings["profiles"] = getItemNames("mcProfileList");
|
||||
settings["blocked_actions"] = getItemNames("mcBlockedActions");
|
||||
settings["only_chat_with"] = getItemNames("mcOnlyChatWith");
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
function addProfileItem(listName, itemNameArg, enabled) {
|
||||
const itemDiv = document.createElement('div');
|
||||
itemDiv.className = 'list-item';
|
||||
|
||||
const itemName = document.createElement('input');
|
||||
itemName.type = 'text';
|
||||
itemName.className = 'name';
|
||||
itemName.value = itemNameArg;
|
||||
|
||||
const itemCheckbox = document.createElement('input');
|
||||
itemCheckbox.type = 'checkbox';
|
||||
itemCheckbox.checked = enabled;
|
||||
if (itemCheckbox.checked) {
|
||||
itemName.classList.remove('not-selected');
|
||||
} else {
|
||||
itemName.classList.add('not-selected');
|
||||
}
|
||||
itemCheckbox.onchange = function() {
|
||||
if (itemCheckbox.checked) {
|
||||
itemName.classList.remove('not-selected');
|
||||
} else {
|
||||
itemName.classList.add('not-selected');
|
||||
}
|
||||
};
|
||||
|
||||
const deleteButton = document.createElement('button');
|
||||
deleteButton.innerHTML = `<svg width="24" height="24" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><g fill="white"><rect x="30" y="35" width="40" height="50" rx="5"></rect><rect x="25" y="30" width="50" height="5"></rect><rect x="40" y="20" width="20" height="10"></rect><line x1="40" y1="40" x2="40" y2="75" stroke="red" stroke-width="4"></line><line x1="50" y1="40" x2="50" y2="75" stroke="red" stroke-width="4"></line><line x1="60" y1="40" x2="60" y2="75" stroke="red" stroke-width="4"></line></g></svg>Delete`;
|
||||
deleteButton.style.display = "flex";
|
||||
deleteButton.style.flexDirection = "row";
|
||||
deleteButton.style.alignItems = "center";
|
||||
deleteButton.style.padding = "3px 10px";
|
||||
deleteButton.className = 'red-btn';
|
||||
deleteButton.onclick = function() {
|
||||
itemDiv.remove();
|
||||
};
|
||||
|
||||
itemDiv.appendChild(itemCheckbox);
|
||||
itemDiv.appendChild(itemName);
|
||||
itemDiv.appendChild(deleteButton);
|
||||
|
||||
document.getElementById(listName).appendChild(itemDiv);
|
||||
}
|
||||
|
||||
function getItemNames(listName) {
|
||||
const items = document.querySelectorAll(`#${listName} .list-item`);
|
||||
const names = Array.from(items)
|
||||
.filter(item => item.querySelector('input[type="checkbox"]').checked)
|
||||
.map(item => item.querySelector('input[type="text"]').value);
|
||||
return names;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
139
src/server/public/styles.css
Normal file
139
src/server/public/styles.css
Normal file
|
@ -0,0 +1,139 @@
|
|||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background: #1a1a1a;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: #2d2d2d;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
margin:20px;
|
||||
}
|
||||
|
||||
.miniContainer {
|
||||
background: linear-gradient(to bottom, #414141, #3f3f3f);
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.formOption {
|
||||
background: #2d2d2d4f;
|
||||
backdrop-filter: blur(10px);
|
||||
padding: 10px;
|
||||
border-radius:4px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
margin:10px;
|
||||
}
|
||||
|
||||
input[type="text"], input[type="number"], select {
|
||||
background: #cfcfcf;
|
||||
color: #000;
|
||||
border-radius: 4px;
|
||||
padding:5px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
code {
|
||||
background:#aaaaaa;
|
||||
border-radius:4px;
|
||||
padding:4px;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.list-item input[type="text"] {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.list-item input[type="checkbox"] {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.list-item .name.not-selected {
|
||||
text-decoration: line-through;
|
||||
color: #929292
|
||||
}
|
||||
|
||||
.agent {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
background: #363636;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button {
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-left: 5px;
|
||||
transition: all 0.3s ease;
|
||||
background: #5c5c5c
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 3px 10px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.add-btn svg {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.green-btn {
|
||||
background: #4CAF50;
|
||||
}
|
||||
|
||||
.blue-btn {
|
||||
background: #2196F3;
|
||||
}
|
||||
|
||||
.red-btn {
|
||||
background: #f44336;
|
||||
}
|
||||
|
||||
.green-btn:hover { background: #45a049; }
|
||||
.blue-btn:hover { background: #1976D2; }
|
||||
.red-btn:hover { background: #d32f2f; }
|
||||
|
||||
.status-icon {
|
||||
font-size: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.status-icon.online {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.status-icon.offline {
|
||||
color: #f44336;
|
||||
}
|
1
src/server/saved_settings.json
Normal file
1
src/server/saved_settings.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
Loading…
Add table
Reference in a new issue