Spaces:
Build error
Build error
Download templates/settings.html from smodusermc/MC: direct link, hf CLI and curl.
- Browser
- Download file 16.7 kB
-
https://huggingface.co/spaces/smodusermc/MC/resolve/main/templates/settings.html
- Command line
-
hf download hf://spaces/smodusermc/MC/templates/settings.html
-
curl -L -o settings.html https://huggingface.co/spaces/smodusermc/MC/resolve/main/templates/settings.html
16.7 kB
| {% extends "base.html" %} | |
| {% block page_title %}Settings{% endblock %} | |
| {% block content %} | |
| <div class="settings-container"> | |
| <!-- Server Properties --> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h3>Server Properties</h3> | |
| <button class="btn btn-primary" onclick="saveProperties()">Save Changes</button> | |
| </div> | |
| <div class="card-body"> | |
| <div class="settings-grid"> | |
| <div class="setting-group"> | |
| <h4>General</h4> | |
| <div class="setting-item"> | |
| <label for="prop-motd">Server MOTD</label> | |
| <input type="text" id="prop-motd" value="{{ properties.get('motd', '') }}"> | |
| </div> | |
| <div class="setting-item"> | |
| <label for="prop-max-players">Max Players</label> | |
| <input type="number" id="prop-max-players" value="{{ properties.get('max-players', '2') }}" min="1" max="2"> | |
| <span class="setting-hint">Limited to 2 for free tier</span> | |
| </div> | |
| <div class="setting-item"> | |
| <label for="prop-difficulty">Difficulty</label> | |
| <select id="prop-difficulty"> | |
| <option value="peaceful" {{ 'selected' if properties.get('difficulty') == 'peaceful' else '' }}>Peaceful</option> | |
| <option value="easy" {{ 'selected' if properties.get('difficulty') == 'easy' else '' }}>Easy</option> | |
| <option value="normal" {{ 'selected' if properties.get('difficulty') == 'normal' else '' }}>Normal</option> | |
| <option value="hard" {{ 'selected' if properties.get('difficulty') == 'hard' else '' }}>Hard</option> | |
| </select> | |
| </div> | |
| <div class="setting-item"> | |
| <label for="prop-gamemode">Default Gamemode</label> | |
| <select id="prop-gamemode"> | |
| <option value="survival" {{ 'selected' if properties.get('gamemode') == 'survival' else '' }}>Survival</option> | |
| <option value="creative" {{ 'selected' if properties.get('gamemode') == 'creative' else '' }}>Creative</option> | |
| <option value="adventure" {{ 'selected' if properties.get('gamemode') == 'adventure' else '' }}>Adventure</option> | |
| <option value="spectator" {{ 'selected' if properties.get('gamemode') == 'spectator' else '' }}>Spectator</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="setting-group"> | |
| <h4>World</h4> | |
| <div class="setting-item"> | |
| <label for="prop-level-name">World Name</label> | |
| <input type="text" id="prop-level-name" value="{{ properties.get('level-name', 'world') }}"> | |
| </div> | |
| <div class="setting-item"> | |
| <label for="prop-view-distance">View Distance</label> | |
| <input type="number" id="prop-view-distance" value="{{ properties.get('view-distance', '10') }}" min="3" max="16"> | |
| </div> | |
| <div class="setting-item"> | |
| <label for="prop-simulation-distance">Simulation Distance</label> | |
| <input type="number" id="prop-simulation-distance" value="{{ properties.get('simulation-distance', '8') }}" min="3" max="12"> | |
| </div> | |
| <div class="setting-item checkbox"> | |
| <label> | |
| <input type="checkbox" id="prop-pvp" {{ 'checked' if properties.get('pvp', 'true') == 'true' else '' }}> | |
| Enable PvP | |
| </label> | |
| </div> | |
| <div class="setting-item checkbox"> | |
| <label> | |
| <input type="checkbox" id="prop-allow-flight" {{ 'checked' if properties.get('allow-flight', 'false') == 'true' else '' }}> | |
| Allow Flight | |
| </label> | |
| </div> | |
| </div> | |
| <div class="setting-group"> | |
| <h4>Security</h4> | |
| <div class="setting-item checkbox"> | |
| <label> | |
| <input type="checkbox" id="prop-online-mode" {{ 'checked' if properties.get('online-mode', 'true') == 'true' else '' }}> | |
| Online Mode (Premium only) | |
| </label> | |
| <span class="setting-hint">Disable for cracked clients</span> | |
| </div> | |
| <div class="setting-item checkbox"> | |
| <label> | |
| <input type="checkbox" id="prop-white-list" {{ 'checked' if properties.get('white-list', 'false') == 'true' else '' }}> | |
| Enable Whitelist | |
| </label> | |
| </div> | |
| <div class="setting-item checkbox"> | |
| <label> | |
| <input type="checkbox" id="prop-enable-command-block" {{ 'checked' if properties.get('enable-command-block', 'true') == 'true' else '' }}> | |
| Enable Command Blocks | |
| </label> | |
| </div> | |
| <div class="setting-item"> | |
| <label for="prop-spawn-protection">Spawn Protection Radius</label> | |
| <input type="number" id="prop-spawn-protection" value="{{ properties.get('spawn-protection', '0') }}" min="0" max="50"> | |
| </div> | |
| </div> | |
| <div class="setting-group"> | |
| <h4>Performance</h4> | |
| <div class="setting-item"> | |
| <label for="prop-max-tick-time">Max Tick Time (ms)</label> | |
| <input type="number" id="prop-max-tick-time" value="{{ properties.get('max-tick-time', '60000') }}" min="-1"> | |
| <span class="setting-hint">-1 to disable watchdog</span> | |
| </div> | |
| <div class="setting-item"> | |
| <label for="prop-network-compression">Network Compression Threshold</label> | |
| <input type="number" id="prop-network-compression" value="{{ properties.get('network-compression-threshold', '256') }}" min="-1"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card-body"> | |
| <div class="pinger-info"> | |
| <div class="info-row"> | |
| <span class="info-label">Status:</span> | |
| <span class="info-value">{{ 'Running' if pinger_status.running else 'Stopped' }}</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Ping Interval:</span> | |
| <span class="info-value">{{ pinger_status.interval }} seconds</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Total Pings:</span> | |
| <span class="info-value">{{ pinger_status.ping_count }}</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Last Ping:</span> | |
| <span class="info-value">{{ pinger_status.last_ping or 'Never' }}</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Target URL:</span> | |
| <span class="info-value">{{ pinger_status.target_url or 'Auto-detect' }}</span> | |
| </div> | |
| </div> | |
| <div class="pinger-note"> | |
| <p><strong>ℹ️ About Keep-Alive:</strong> This service automatically pings your Space | |
| every {{ pinger_status.interval // 60 }} minutes to prevent it from sleeping due to inactivity. | |
| This is essential for maintaining server availability on HuggingFace Spaces free tier.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Connection Info --> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h3>Connection Information</h3> | |
| </div> | |
| <div class="card-body"> | |
| <div class="connection-info"> | |
| <div class="info-box"> | |
| <h4>🌐 How to Connect</h4> | |
| <p>To connect to this Minecraft server, you'll need to use a TCP tunnel service | |
| since HuggingFace Spaces doesn't expose the Minecraft port directly.</p> | |
| <div class="connection-steps"> | |
| <h5>Option 1: Using playit.gg (Recommended)</h5> | |
| <ol> | |
| <li>Go to <a href="https://playit.gg" target="_blank">playit.gg</a> and create an account</li> | |
| <li>Download and run the playit agent</li> | |
| <li>Create a Minecraft Java tunnel pointing to <code>localhost:25565</code></li> | |
| <li>Share the generated address with your friend</li> | |
| </ol> | |
| <h5>Option 2: Using ngrok</h5> | |
| <ol> | |
| <li>Install ngrok: <code>npm install -g ngrok</code></li> | |
| <li>Run: <code>ngrok tcp 25565</code></li> | |
| <li>Use the provided address to connect</li> | |
| </ol> | |
| </div> | |
| </div> | |
| <div class="info-box warning"> | |
| <h4>⚠️ Important Notes</h4> | |
| <ul> | |
| <li>The server runs on port <strong>25565</strong> internally</li> | |
| <li>You need an external tunnel to make it accessible from the internet</li> | |
| <li>Free tunnel services may have connection limits</li> | |
| <li>Consider setting <strong>Online Mode</strong> to false if using cracked launchers</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Danger Zone --> | |
| <div class="card danger-zone"> | |
| <div class="card-header"> | |
| <h3>⚠️ Danger Zone</h3> | |
| </div> | |
| <div class="card-body"> | |
| <div class="danger-actions"> | |
| <div class="danger-item"> | |
| <div class="danger-info"> | |
| <h4>Reset Server</h4> | |
| <p>Delete all world data and start fresh. This cannot be undone!</p> | |
| </div> | |
| <button class="btn btn-danger" onclick="resetServer()">Reset Server</button> | |
| </div> | |
| <div class="danger-item"> | |
| <div class="danger-info"> | |
| <h4>Delete All Mods</h4> | |
| <p>Remove all installed mods from the server.</p> | |
| </div> | |
| <button class="btn btn-danger" onclick="deleteAllMods()">Delete All Mods</button> | |
| </div> | |
| <div class="danger-item"> | |
| <div class="danger-info"> | |
| <h4>Force Stop Server</h4> | |
| <p>Forcefully terminate the server process. May cause data loss!</p> | |
| </div> | |
| <button class="btn btn-danger" onclick="forceStop()">Force Stop</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {% endblock %} | |
| {% block scripts %} | |
| <script> | |
| async function saveProperties() { | |
| const properties = { | |
| 'motd': document.getElementById('prop-motd').value, | |
| 'max-players': document.getElementById('prop-max-players').value, | |
| 'difficulty': document.getElementById('prop-difficulty').value, | |
| 'gamemode': document.getElementById('prop-gamemode').value, | |
| 'level-name': document.getElementById('prop-level-name').value, | |
| 'view-distance': document.getElementById('prop-view-distance').value, | |
| 'simulation-distance': document.getElementById('prop-simulation-distance').value, | |
| 'pvp': document.getElementById('prop-pvp').checked ? 'true' : 'false', | |
| 'allow-flight': document.getElementById('prop-allow-flight').checked ? 'true' : 'false', | |
| 'online-mode': document.getElementById('prop-online-mode').checked ? 'true' : 'false', | |
| 'white-list': document.getElementById('prop-white-list').checked ? 'true' : 'false', | |
| 'enable-command-block': document.getElementById('prop-enable-command-block').checked ? 'true' : 'false', | |
| 'spawn-protection': document.getElementById('prop-spawn-protection').value, | |
| 'max-tick-time': document.getElementById('prop-max-tick-time').value, | |
| 'network-compression-threshold': document.getElementById('prop-network-compression').value | |
| }; | |
| try { | |
| const response = await fetch('/api/settings/properties', { | |
| method: 'POST', | |
| headers: {'Content-Type': 'application/json'}, | |
| body: JSON.stringify(properties) | |
| }); | |
| const data = await response.json(); | |
| showToast(data.message, data.success ? 'success' : 'error'); | |
| if (data.success) { | |
| showToast('Restart server to apply changes', 'info'); | |
| } | |
| } catch (error) { | |
| showToast('Failed to save properties', 'error'); | |
| } | |
| } | |
| async function resetServer() { | |
| if (!confirm('⚠️ WARNING: This will delete ALL world data!\n\nAre you absolutely sure?')) return; | |
| if (!confirm('This is your LAST CHANCE to cancel.\n\nType "RESET" in the next prompt to confirm.')) return; | |
| const confirmation = prompt('Type "RESET" to confirm:'); | |
| if (confirmation !== 'RESET') { | |
| showToast('Reset cancelled', 'info'); | |
| return; | |
| } | |
| try { | |
| // Stop server first | |
| await fetch('/api/server/stop', {method: 'POST'}); | |
| // Delete world folder | |
| await fetch('/api/files/delete', { | |
| method: 'POST', | |
| headers: {'Content-Type': 'application/json'}, | |
| body: JSON.stringify({path: 'world'}) | |
| }); | |
| showToast('Server reset complete. Start the server to generate a new world.', 'success'); | |
| } catch (error) { | |
| showToast('Reset failed: ' + error.message, 'error'); | |
| } | |
| } | |
| async function deleteAllMods() { | |
| if (!confirm('Delete ALL installed mods?')) return; | |
| try { | |
| const response = await fetch('/api/mods'); | |
| const mods = await response.json(); | |
| for (const mod of mods) { | |
| await fetch('/api/mods/delete', { | |
| method: 'POST', | |
| headers: {'Content-Type': 'application/json'}, | |
| body: JSON.stringify({filename: mod.filename}) | |
| }); | |
| } | |
| showToast('All mods deleted', 'success'); | |
| } catch (error) { | |
| showToast('Failed to delete mods', 'error'); | |
| } | |
| } | |
| async function forceStop() { | |
| if (!confirm('Force stop the server? This may cause data loss!')) return; | |
| try { | |
| const response = await fetch('/api/server/stop', { | |
| method: 'POST', | |
| headers: {'Content-Type': 'application/json'}, | |
| body: JSON.stringify({force: true}) | |
| }); | |
| const data = await response.json(); | |
| showToast(data.message, data.success ? 'success' : 'error'); | |
| } catch (error) { | |
| showToast('Force stop failed', 'error'); | |
| } | |
| } | |
| </script> | |
| {% endblock %} |