specprotocol 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,621 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * SpecProtocol Web Panel — Control your bot from the browser.
5
- *
6
- * Usage:
7
- * specprotocol-web
8
- * specprotocol-web --host mc.server.com --port 25565 --username Bot --panel-port 3000
9
- */
10
-
11
- const { createBot } = require('../dist/index.js');
12
- const http = require('http');
13
- const readline = require('readline');
14
-
15
- const args = process.argv.slice(2);
16
-
17
- function getArg(name) {
18
- const idx = args.indexOf(`--${name}`);
19
- if (idx !== -1 && args[idx + 1]) return args[idx + 1];
20
- return null;
21
- }
22
-
23
- function ask(question) {
24
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
25
- return new Promise((resolve) => {
26
- rl.question(question, (answer) => {
27
- rl.close();
28
- resolve(answer);
29
- });
30
- });
31
- }
32
-
33
- // ─── Bot State ──────────────────────────────────────────
34
- const state = {
35
- status: 'disconnected',
36
- username: '',
37
- host: '',
38
- position: { x: 0, y: 0, z: 0 },
39
- health: 20,
40
- food: 20,
41
- dimension: '',
42
- entityId: 0,
43
- chatLog: [],
44
- connectedAt: null,
45
- };
46
-
47
- let bot = null;
48
- const sseClients = new Set();
49
-
50
- function broadcast(event, data) {
51
- const msg = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
52
- for (const res of sseClients) {
53
- res.write(msg);
54
- }
55
- }
56
-
57
- function addChat(msg) {
58
- const entry = { time: new Date().toLocaleTimeString(), text: msg };
59
- state.chatLog.push(entry);
60
- if (state.chatLog.length > 100) state.chatLog.shift();
61
- broadcast('chat', entry);
62
- }
63
-
64
- // ─── HTML Dashboard ─────────────────────────────────────
65
- function getHTML() {
66
- return `<!DOCTYPE html>
67
- <html lang="tr">
68
- <head>
69
- <meta charset="UTF-8">
70
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
71
- <title>SpecProtocol — Web Panel</title>
72
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
73
- <style>
74
- * { margin: 0; padding: 0; box-sizing: border-box; }
75
- :root {
76
- --bg: #0a0a0f;
77
- --card: #12121a;
78
- --card-border: #1e1e2e;
79
- --accent: #7c3aed;
80
- --accent-glow: rgba(124, 58, 237, 0.3);
81
- --green: #22c55e;
82
- --red: #ef4444;
83
- --yellow: #eab308;
84
- --text: #e2e8f0;
85
- --text-dim: #64748b;
86
- --chat-bg: #0f0f17;
87
- }
88
- body {
89
- font-family: 'Inter', sans-serif;
90
- background: var(--bg);
91
- color: var(--text);
92
- min-height: 100vh;
93
- }
94
- .container {
95
- max-width: 1200px;
96
- margin: 0 auto;
97
- padding: 24px;
98
- }
99
- header {
100
- display: flex;
101
- align-items: center;
102
- justify-content: space-between;
103
- padding: 20px 0;
104
- border-bottom: 1px solid var(--card-border);
105
- margin-bottom: 24px;
106
- }
107
- header h1 {
108
- font-size: 24px;
109
- font-weight: 700;
110
- background: linear-gradient(135deg, #7c3aed, #a78bfa);
111
- -webkit-background-clip: text;
112
- -webkit-text-fill-color: transparent;
113
- }
114
- .status-badge {
115
- display: flex; align-items: center; gap: 8px;
116
- padding: 6px 14px;
117
- border-radius: 20px;
118
- font-size: 13px;
119
- font-weight: 600;
120
- background: rgba(34,197,94,0.1);
121
- border: 1px solid rgba(34,197,94,0.3);
122
- color: var(--green);
123
- }
124
- .status-badge.offline {
125
- background: rgba(239,68,68,0.1);
126
- border-color: rgba(239,68,68,0.3);
127
- color: var(--red);
128
- }
129
- .status-dot {
130
- width: 8px; height: 8px;
131
- border-radius: 50%;
132
- background: var(--green);
133
- animation: pulse 2s infinite;
134
- }
135
- .status-badge.offline .status-dot {
136
- background: var(--red);
137
- animation: none;
138
- }
139
- @keyframes pulse {
140
- 0%, 100% { opacity: 1; }
141
- 50% { opacity: 0.4; }
142
- }
143
- .grid {
144
- display: grid;
145
- grid-template-columns: repeat(4, 1fr);
146
- gap: 16px;
147
- margin-bottom: 24px;
148
- }
149
- .stat-card {
150
- background: var(--card);
151
- border: 1px solid var(--card-border);
152
- border-radius: 12px;
153
- padding: 20px;
154
- transition: border-color 0.2s;
155
- }
156
- .stat-card:hover { border-color: var(--accent); }
157
- .stat-label {
158
- font-size: 12px;
159
- text-transform: uppercase;
160
- letter-spacing: 1px;
161
- color: var(--text-dim);
162
- margin-bottom: 8px;
163
- }
164
- .stat-value {
165
- font-size: 24px;
166
- font-weight: 700;
167
- font-family: 'JetBrains Mono', monospace;
168
- }
169
- .health-bar {
170
- width: 100%;
171
- height: 6px;
172
- background: #1e1e2e;
173
- border-radius: 3px;
174
- margin-top: 10px;
175
- overflow: hidden;
176
- }
177
- .health-fill {
178
- height: 100%;
179
- border-radius: 3px;
180
- transition: width 0.5s ease;
181
- background: linear-gradient(90deg, var(--red), var(--green));
182
- }
183
- .main-grid {
184
- display: grid;
185
- grid-template-columns: 1fr 350px;
186
- gap: 20px;
187
- }
188
- .chat-panel {
189
- background: var(--card);
190
- border: 1px solid var(--card-border);
191
- border-radius: 12px;
192
- display: flex;
193
- flex-direction: column;
194
- height: 450px;
195
- }
196
- .panel-header {
197
- padding: 14px 18px;
198
- font-weight: 600;
199
- font-size: 14px;
200
- border-bottom: 1px solid var(--card-border);
201
- display: flex; align-items: center; gap: 8px;
202
- }
203
- .chat-messages {
204
- flex: 1;
205
- overflow-y: auto;
206
- padding: 12px 18px;
207
- font-family: 'JetBrains Mono', monospace;
208
- font-size: 13px;
209
- background: var(--chat-bg);
210
- }
211
- .chat-messages::-webkit-scrollbar { width: 4px; }
212
- .chat-messages::-webkit-scrollbar-thumb { background: var(--card-border); border-radius: 2px; }
213
- .chat-msg {
214
- padding: 4px 0;
215
- line-height: 1.5;
216
- animation: fadeIn 0.2s;
217
- }
218
- .chat-msg .time { color: var(--text-dim); }
219
- @keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; } }
220
- .chat-input-wrap {
221
- display: flex;
222
- border-top: 1px solid var(--card-border);
223
- }
224
- .chat-input-wrap input {
225
- flex: 1;
226
- background: transparent;
227
- border: none;
228
- color: var(--text);
229
- font-family: 'JetBrains Mono', monospace;
230
- font-size: 13px;
231
- padding: 14px 18px;
232
- outline: none;
233
- }
234
- .chat-input-wrap button {
235
- background: var(--accent);
236
- border: none;
237
- color: white;
238
- padding: 0 20px;
239
- cursor: pointer;
240
- font-weight: 600;
241
- font-size: 13px;
242
- border-radius: 0 0 12px 0;
243
- transition: background 0.2s;
244
- }
245
- .chat-input-wrap button:hover { background: #6d28d9; }
246
- .actions-panel {
247
- display: flex;
248
- flex-direction: column;
249
- gap: 16px;
250
- }
251
- .action-card {
252
- background: var(--card);
253
- border: 1px solid var(--card-border);
254
- border-radius: 12px;
255
- padding: 18px;
256
- }
257
- .action-card h3 {
258
- font-size: 14px;
259
- font-weight: 600;
260
- margin-bottom: 12px;
261
- display: flex; align-items: center; gap: 8px;
262
- }
263
- .btn-grid {
264
- display: grid;
265
- grid-template-columns: 1fr 1fr;
266
- gap: 8px;
267
- }
268
- .btn {
269
- background: #1e1e2e;
270
- border: 1px solid var(--card-border);
271
- color: var(--text);
272
- padding: 10px;
273
- border-radius: 8px;
274
- cursor: pointer;
275
- font-size: 13px;
276
- font-weight: 500;
277
- transition: all 0.2s;
278
- font-family: 'Inter', sans-serif;
279
- }
280
- .btn:hover { background: var(--accent); border-color: var(--accent); }
281
- .btn.danger { border-color: rgba(239,68,68,0.3); }
282
- .btn.danger:hover { background: var(--red); border-color: var(--red); }
283
- .btn.full { grid-column: 1 / -1; }
284
- .coord-display {
285
- font-family: 'JetBrains Mono', monospace;
286
- font-size: 13px;
287
- background: var(--chat-bg);
288
- padding: 12px;
289
- border-radius: 8px;
290
- line-height: 1.8;
291
- }
292
- .coord-display span { color: var(--accent); font-weight: 600; }
293
- @media (max-width: 768px) {
294
- .grid { grid-template-columns: repeat(2, 1fr); }
295
- .main-grid { grid-template-columns: 1fr; }
296
- }
297
- </style>
298
- </head>
299
- <body>
300
- <div class="container">
301
- <header>
302
- <h1>🎮 SpecProtocol</h1>
303
- <div class="status-badge" id="statusBadge">
304
- <div class="status-dot"></div>
305
- <span id="statusText">Bağlanıyor...</span>
306
- </div>
307
- </header>
308
-
309
- <div class="grid">
310
- <div class="stat-card">
311
- <div class="stat-label">❤️ Can</div>
312
- <div class="stat-value" id="health">20</div>
313
- <div class="health-bar"><div class="health-fill" id="healthBar" style="width:100%"></div></div>
314
- </div>
315
- <div class="stat-card">
316
- <div class="stat-label">🍖 Açlık</div>
317
- <div class="stat-value" id="food">20</div>
318
- <div class="health-bar"><div class="health-fill" id="foodBar" style="width:100%;background:linear-gradient(90deg,var(--yellow),var(--green))"></div></div>
319
- </div>
320
- <div class="stat-card">
321
- <div class="stat-label">🌍 Boyut</div>
322
- <div class="stat-value" id="dimension" style="font-size:14px">—</div>
323
- </div>
324
- <div class="stat-card">
325
- <div class="stat-label">⏱️ Bağlantı</div>
326
- <div class="stat-value" id="uptime" style="font-size:18px">00:00</div>
327
- </div>
328
- </div>
329
-
330
- <div class="main-grid">
331
- <div class="chat-panel">
332
- <div class="panel-header">💬 Chat</div>
333
- <div class="chat-messages" id="chatBox"></div>
334
- <div class="chat-input-wrap">
335
- <input type="text" id="chatInput" placeholder="Mesaj yaz..." autocomplete="off">
336
- <button onclick="sendChat()">Gönder</button>
337
- </div>
338
- </div>
339
-
340
- <div class="actions-panel">
341
- <div class="action-card">
342
- <h3>📍 Pozisyon</h3>
343
- <div class="coord-display" id="coords">
344
- X: <span>0</span><br>
345
- Y: <span>0</span><br>
346
- Z: <span>0</span>
347
- </div>
348
- </div>
349
-
350
- <div class="action-card">
351
- <h3>⚡ Komutlar</h3>
352
- <div class="btn-grid">
353
- <button class="btn" onclick="sendAction('jump')">⬆️ Zıpla</button>
354
- <button class="btn" onclick="sendAction('sneak')">🔽 Eğil</button>
355
- <button class="btn" onclick="sendAction('slot', 0)">1️⃣ Slot 1</button>
356
- <button class="btn" onclick="sendAction('slot', 4)">5️⃣ Slot 5</button>
357
- <button class="btn full danger" onclick="sendAction('disconnect')">🔌 Bağlantıyı Kes</button>
358
- </div>
359
- </div>
360
-
361
- <div class="action-card">
362
- <h3>👤 Bot Bilgisi</h3>
363
- <div class="coord-display">
364
- İsim: <span id="botName">—</span><br>
365
- Sunucu: <span id="serverAddr">—</span><br>
366
- Entity ID: <span id="entityId">—</span>
367
- </div>
368
- </div>
369
- </div>
370
- </div>
371
- </div>
372
-
373
- <script>
374
- const chatBox = document.getElementById('chatBox');
375
- const chatInput = document.getElementById('chatInput');
376
-
377
- // SSE for real-time updates
378
- const evtSource = new EventSource('/events');
379
-
380
- evtSource.addEventListener('state', (e) => {
381
- const s = JSON.parse(e.data);
382
- document.getElementById('health').textContent = Math.round(s.health);
383
- document.getElementById('food').textContent = Math.round(s.food);
384
- document.getElementById('healthBar').style.width = (s.health / 20 * 100) + '%';
385
- document.getElementById('foodBar').style.width = (s.food / 20 * 100) + '%';
386
- document.getElementById('dimension').textContent = (s.dimension || '—').replace('minecraft:', '');
387
- document.getElementById('botName').textContent = s.username || '—';
388
- document.getElementById('serverAddr').textContent = s.host || '—';
389
- document.getElementById('entityId').textContent = s.entityId || '—';
390
-
391
- const badge = document.getElementById('statusBadge');
392
- const statusText = document.getElementById('statusText');
393
- if (s.status === 'connected') {
394
- badge.classList.remove('offline');
395
- statusText.textContent = 'Bağlı';
396
- } else {
397
- badge.classList.add('offline');
398
- statusText.textContent = 'Bağlı Değil';
399
- }
400
- });
401
-
402
- evtSource.addEventListener('position', (e) => {
403
- const p = JSON.parse(e.data);
404
- document.getElementById('coords').innerHTML =
405
- 'X: <span>' + p.x.toFixed(1) + '</span><br>' +
406
- 'Y: <span>' + p.y.toFixed(1) + '</span><br>' +
407
- 'Z: <span>' + p.z.toFixed(1) + '</span>';
408
- });
409
-
410
- evtSource.addEventListener('chat', (e) => {
411
- const msg = JSON.parse(e.data);
412
- const div = document.createElement('div');
413
- div.className = 'chat-msg';
414
- div.innerHTML = '<span class="time">[' + msg.time + ']</span> ' + escapeHtml(msg.text);
415
- chatBox.appendChild(div);
416
- chatBox.scrollTop = chatBox.scrollHeight;
417
- });
418
-
419
- function escapeHtml(t) {
420
- return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
421
- }
422
-
423
- function sendChat() {
424
- const msg = chatInput.value.trim();
425
- if (!msg) return;
426
- fetch('/api/chat', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({message: msg}) });
427
- chatInput.value = '';
428
- }
429
-
430
- function sendAction(action, value) {
431
- fetch('/api/action', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({action, value}) });
432
- }
433
-
434
- chatInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') sendChat(); });
435
-
436
- // Uptime counter
437
- setInterval(() => {
438
- fetch('/api/state').then(r => r.json()).then(s => {
439
- if (s.connectedAt) {
440
- const diff = Math.floor((Date.now() - new Date(s.connectedAt).getTime()) / 1000);
441
- const m = String(Math.floor(diff / 60)).padStart(2, '0');
442
- const sec = String(diff % 60).padStart(2, '0');
443
- document.getElementById('uptime').textContent = m + ':' + sec;
444
- }
445
- }).catch(() => {});
446
- }, 1000);
447
- </script>
448
- </body>
449
- </html>`;
450
- }
451
-
452
- // ─── HTTP Server ────────────────────────────────────────
453
- function startServer(panelPort) {
454
- const server = http.createServer((req, res) => {
455
- // CORS
456
- res.setHeader('Access-Control-Allow-Origin', '*');
457
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
458
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
459
-
460
- if (req.method === 'GET' && (req.url === '/' || req.url === '/index.html')) {
461
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
462
- res.end(getHTML());
463
- }
464
- else if (req.method === 'GET' && req.url === '/events') {
465
- // SSE
466
- res.writeHead(200, {
467
- 'Content-Type': 'text/event-stream',
468
- 'Cache-Control': 'no-cache',
469
- 'Connection': 'keep-alive',
470
- });
471
- sseClients.add(res);
472
- // Send initial state
473
- res.write(`event: state\ndata: ${JSON.stringify(state)}\n\n`);
474
- for (const msg of state.chatLog) {
475
- res.write(`event: chat\ndata: ${JSON.stringify(msg)}\n\n`);
476
- }
477
- req.on('close', () => sseClients.delete(res));
478
- }
479
- else if (req.method === 'GET' && req.url === '/api/state') {
480
- res.writeHead(200, { 'Content-Type': 'application/json' });
481
- res.end(JSON.stringify(state));
482
- }
483
- else if (req.method === 'POST' && req.url === '/api/chat') {
484
- let body = '';
485
- req.on('data', c => body += c);
486
- req.on('end', () => {
487
- try {
488
- const { message } = JSON.parse(body);
489
- if (bot && message) {
490
- bot.chat(message);
491
- addChat(`[Sen] ${message}`);
492
- }
493
- } catch (e) { }
494
- res.writeHead(200);
495
- res.end('ok');
496
- });
497
- }
498
- else if (req.method === 'POST' && req.url === '/api/action') {
499
- let body = '';
500
- req.on('data', c => body += c);
501
- req.on('end', () => {
502
- try {
503
- const { action, value } = JSON.parse(body);
504
- if (!bot) { res.writeHead(200); res.end('no bot'); return; }
505
- switch (action) {
506
- case 'jump':
507
- const p = bot.position;
508
- bot.setPosition(p.x, p.y + 1.25, p.z);
509
- addChat('[Sistem] Zıpladı');
510
- break;
511
- case 'sneak':
512
- addChat('[Sistem] Eğildi');
513
- break;
514
- case 'slot':
515
- bot.setHeldItem(value || 0);
516
- addChat(`[Sistem] Slot ${(value || 0) + 1} seçildi`);
517
- break;
518
- case 'disconnect':
519
- bot.disconnect();
520
- addChat('[Sistem] Bağlantı kesildi');
521
- break;
522
- }
523
- } catch (e) { }
524
- res.writeHead(200);
525
- res.end('ok');
526
- });
527
- }
528
- else {
529
- res.writeHead(404);
530
- res.end('Not found');
531
- }
532
- });
533
-
534
- server.listen(panelPort, () => {
535
- console.log(` 🌐 Web Panel: http://localhost:${panelPort}`);
536
- console.log('');
537
- });
538
- }
539
-
540
- // ─── Main ───────────────────────────────────────────────
541
- async function main() {
542
- console.log('');
543
- console.log(' ╔═══════════════════════════════════╗');
544
- console.log(' ║ 🎮 SpecProtocol Web Panel ║');
545
- console.log(' ║ Minecraft Bot Framework (1.21.4) ║');
546
- console.log(' ╚═══════════════════════════════════╝');
547
- console.log('');
548
-
549
- const host = getArg('host') || await ask(' Sunucu adresi (localhost): ') || 'localhost';
550
- const port = parseInt(getArg('port') || await ask(' Port (25565): ') || '25565');
551
- const username = getArg('username') || await ask(' Bot adı (SpecBot): ') || 'SpecBot';
552
- const panelPort = parseInt(getArg('panel-port') || await ask(' Panel portu (3000): ') || '3000');
553
- const auth = getArg('auth') || 'offline';
554
-
555
- state.host = `${host}:${port}`;
556
- state.username = username;
557
-
558
- // Start web panel
559
- startServer(panelPort);
560
-
561
- console.log(` → ${host}:${port} adresine "${username}" olarak bağlanılıyor...`);
562
- console.log('');
563
-
564
- try {
565
- bot = await createBot({ host, port, username, auth });
566
-
567
- state.status = 'connected';
568
- state.connectedAt = new Date().toISOString();
569
- broadcast('state', state);
570
- addChat('[Sistem] Sunucuya bağlandı');
571
-
572
- bot.on('spawn', () => {
573
- state.dimension = bot.world?.dimension || 'overworld';
574
- state.entityId = bot.entityId;
575
- broadcast('state', state);
576
- addChat(`[Sistem] Dünyada doğuldu! (${state.dimension})`);
577
- console.log(` ✅ Spawned! Web Panel: http://localhost:${panelPort}`);
578
- });
579
-
580
- bot.on('position', (pos) => {
581
- state.position = { x: pos.x, y: pos.y, z: pos.z };
582
- broadcast('position', state.position);
583
- });
584
-
585
- bot.on('health', (health, food) => {
586
- state.health = health;
587
- state.food = food;
588
- broadcast('state', state);
589
- if (health <= 0) addChat('[Sistem] 💀 Bot öldü!');
590
- });
591
-
592
- bot.on('chat', (message, isOverlay) => {
593
- if (!isOverlay) addChat(message);
594
- });
595
-
596
- bot.on('kicked', (reason) => {
597
- addChat(`[Sistem] 🚫 Sunucudan atıldı: ${reason}`);
598
- state.status = 'disconnected';
599
- broadcast('state', state);
600
- });
601
-
602
- bot.on('error', (err) => {
603
- addChat(`[Hata] ${err.message}`);
604
- });
605
-
606
- bot.on('end', () => {
607
- state.status = 'disconnected';
608
- broadcast('state', state);
609
- addChat('[Sistem] Bağlantı kesildi');
610
- console.log(' 🔌 Bağlantı kesildi');
611
- });
612
-
613
- } catch (err) {
614
- addChat(`[Hata] Bağlantı kurulamadı: ${err.message}`);
615
- state.status = 'disconnected';
616
- broadcast('state', state);
617
- console.error(` ❌ ${err.message}`);
618
- }
619
- }
620
-
621
- main();