Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

442 lines
16 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>🎮 斗地主测试客户端 (v2)</title>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<style>
* { box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
h1 { color: #333; text-align: center; }
.card {
background: white;
border-radius: 8px;
padding: 20px;
margin: 15px 0;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.status {
padding: 10px;
border-radius: 4px;
margin: 10px 0;
font-weight: bold;
}
.status.connected { background: #d4edda; color: #155724; }
.status.disconnected { background: #f8d7da; color: #721c24; }
input, button {
padding: 10px;
margin: 5px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
button {
background: #007bff;
color: white;
border: none;
cursor: pointer;
}
button:hover { background: #0056b3; }
button:disabled { background: #ccc; cursor: not-allowed; }
.log {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 10px;
max-height: 300px;
overflow-y: auto;
font-family: monospace;
font-size: 12px;
}
.log-entry {
margin: 2px 0;
padding: 4px;
border-radius: 2px;
}
.log-entry.send { background: #e3f2fd; }
.log-entry.receive { background: #f3e5f5; }
.log-entry.error { background: #ffebee; }
.flex { display: flex; gap: 10px; flex-wrap: wrap; }
.flex > * { flex: 1; min-width: 150px; }
</style>
</head>
<body>
<h1>🎮 Net-Games 测试客户端</h1>
<!-- 连接状态 -->
<div class="card">
<h3>连接状态</h3>
<div id="connectionStatus" class="status disconnected">未连接</div>
<div class="flex">
<input type="text" id="serverUrl" value="http://129.211.173.87:8900" placeholder="服务器地址">
<button onclick="connect()">连接</button>
<button onclick="disconnect()">断开</button>
</div>
</div>
<!-- 快速开始 -->
<div class="card" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;">
<h3 style="margin-top: 0;">⚡ 快速开始(推荐)</h3>
<p style="margin: 5px 0; opacity: 0.9;">一键创建房间、添加AI、准备并开始游戏</p>
<div class="flex" style="align-items: center;">
<input type="text" id="quickPlayerName" value="蔡叔叔" placeholder="你的昵称" style="background: rgba(255,255,255,0.9);">
<select id="quickAiCount" style="background: rgba(255,255,255,0.9);">
<option value="1">1个AI</option>
<option value="2" selected>2个AI</option>
</select>
<select id="quickAiType1" style="background: rgba(255,255,255,0.9);">
<option value="rule" selected>AI-1: 规则</option>
<option value="deepseek">AI-1: DeepSeek</option>
</select>
<select id="quickAiType2" style="background: rgba(255,255,255,0.9);">
<option value="rule">AI-2: 规则</option>
<option value="deepseek" selected>AI-2: DeepSeek</option>
</select>
</div>
<button onclick="quickStart()" style="width: 100%; margin: 10px 0; padding: 15px; font-size: 16px; background: #00d4aa;">🚀 一键开始游戏</button>
</div>
<!-- 房间操作 -->
<div class="card">
<h3>🏠 手动房间操作</h3>
<div class="flex">
<input type="text" id="playerName" value="测试玩家" placeholder="玩家名称">
</div>
<div class="flex" style="align-items: center;">
<label style="min-width: 80px;">AI数量:</label>
<select id="aiCount">
<option value="0">0 (纯真人)</option>
<option value="1">1</option>
<option value="2" selected>2</option>
</select>
<label style="min-width: 80px;">AI类型:</label>
<select id="aiType">
<option value="rule" selected>规则AI</option>
<option value="deepseek">DeepSeek</option>
</select>
</div>
<div class="flex">
<button onclick="createRoom()" id="btnCreate">创建房间</button>
<input type="text" id="roomCode" placeholder="房间号" maxlength="6">
<button onclick="joinRoom()" id="btnJoin">加入房间</button>
<button onclick="leaveRoom()" id="btnLeave">离开房间</button>
</div>
</div>
<!-- 游戏控制 -->
<div class="card">
<h3>游戏控制</h3>
<div class="flex">
<button onclick="setReady()" id="btnReady">准备</button>
<button onclick="startGame()" id="btnStart">开始游戏</button>
</div>
<div class="flex" style="margin-top: 10px;">
<input type="number" id="guessNumber" placeholder="输入数字 1-100" min="1" max="100">
<button onclick="makeGuess()">猜数字</button>
</div>
</div>
<!-- 当前状态 -->
<div class="card">
<h3>当前状态</h3>
<div id="gameState">等待连接...</div>
</div>
<!-- 日志 -->
<div class="card">
<h3>通信日志 <button onclick="clearLog()">清空</button></h3>
<div id="log" class="log"></div>
</div>
<script>
let socket = null;
let currentRoom = null;
let currentPlayer = null;
let quickStartRoom = false; // ⚡ 快速开始标记
function log(message, type = 'info') {
const logEl = document.getElementById('log');
const entry = document.createElement('div');
entry.className = `log-entry ${type}`;
const time = new Date().toLocaleTimeString();
entry.textContent = `[${time}] ${message}`;
logEl.insertBefore(entry, logEl.firstChild);
}
function updateState(state) {
document.getElementById('gameState').innerHTML = `<pre>${JSON.stringify(state, null, 2)}</pre>`;
}
function updateConnectionStatus(connected) {
const statusEl = document.getElementById('connectionStatus');
if (connected) {
statusEl.textContent = '已连接';
statusEl.className = 'status connected';
} else {
statusEl.textContent = '未连接';
statusEl.className = 'status disconnected';
}
}
function connect() {
const url = document.getElementById('serverUrl').value;
log(`正在连接到 ${url}...`);
socket = io(url);
socket.on('connect', () => {
log(`连接成功! Socket ID: ${socket.id}`, 'receive');
updateConnectionStatus(true);
});
socket.on('disconnect', () => {
log('连接已断开', 'error');
updateConnectionStatus(false);
currentRoom = null;
currentPlayer = null;
});
socket.on('error', (data) => {
log(`错误: ${JSON.stringify(data)}`, 'error');
});
// 房间事件
socket.on('connected', (data) => {
log(`服务器消息: ${data.message}`, 'receive');
});
socket.on('room_created', (data) => {
log(`房间创建成功: ${JSON.stringify(data)}`, 'receive');
if (data.success) {
currentRoom = data.room;
currentPlayer = data.player;
document.getElementById('roomCode').value = currentRoom.code;
updateState(data.room);
// ⚡ 快速开始:自动准备并开始
if (quickStartRoom) {
setTimeout(() => {
log('🤖 自动准备...');
socket.emit('set_ready', { ready: true });
setTimeout(() => {
log('🎮 自动开始游戏...');
socket.emit('start_game');
quickStartRoom = false;
}, 600);
}, 300);
}
}
});
socket.on('room_joined', (data) => {
log(`加入房间成功: ${JSON.stringify(data)}`, 'receive');
if (data.success) {
currentRoom = data.room;
currentPlayer = data.player;
updateState(data.room);
}
});
socket.on('room_left', (data) => {
log(`离开房间: ${JSON.stringify(data)}`, 'receive');
currentRoom = null;
currentPlayer = null;
});
socket.on('room_updated', (data) => {
log(`房间更新: ${JSON.stringify(data)}`, 'receive');
if (data.room) {
currentRoom = data.room;
updateState(data.room);
}
});
socket.on('player_joined', (data) => {
log(`玩家加入: ${JSON.stringify(data)}`, 'receive');
});
socket.on('player_left', (data) => {
log(`玩家离开: ${JSON.stringify(data)}`, 'receive');
});
socket.on('player_disconnected', (data) => {
log(`玩家离线: ${JSON.stringify(data)}`, 'receive');
});
// 游戏事件
socket.on('game_started', (data) => {
log(`游戏开始: ${JSON.stringify(data)}`, 'receive');
if (data.room) {
currentRoom = data.room;
updateState(data.room);
}
});
socket.on('state_update', (data) => {
log(`状态更新: ${JSON.stringify(data)}`, 'receive');
if (data.game_state) {
updateState(data.game_state);
}
});
socket.on('game_ended', (data) => {
log(`游戏结束: ${JSON.stringify(data)}`, 'receive');
});
socket.on('action_failed', (data) => {
log(`操作失败: ${JSON.stringify(data)}`, 'error');
});
socket.on('pong', (data) => {
log(`心跳响应: ${JSON.stringify(data)}`, 'receive');
});
}
function disconnect() {
if (socket) {
socket.disconnect();
socket = null;
}
}
function createRoom() {
if (!socket) {
log('请先连接服务器', 'error');
return;
}
const playerName = document.getElementById('playerName').value || '测试玩家';
const aiCount = parseInt(document.getElementById('aiCount').value);
const aiType = document.getElementById('aiType').value;
// 构建AI配置
const ai_players = [];
for (let i = 0; i < aiCount; i++) {
ai_players.push({
name: `AI-${i+1}(${aiType})`,
ai_type: aiType
});
}
socket.emit('create_room', {
game_type: 'doudizhu',
player_name: playerName,
config: { max_players: 3 },
ai_players: ai_players
});
log(`发送: create_room (游戏:斗地主, AI:${aiCount}个${aiType})`, 'send');
}
function joinRoom() {
if (!socket) {
log('请先连接服务器', 'error');
return;
}
const roomCode = document.getElementById('roomCode').value.toUpperCase();
const playerName = document.getElementById('playerName').value || '测试玩家';
if (!roomCode) {
log('请输入房间号', 'error');
return;
}
socket.emit('join_room', {
room_code: roomCode,
player_name: playerName
});
log(`发送: join_room (${roomCode})`, 'send');
}
function leaveRoom() {
if (!socket) return;
socket.emit('leave_room');
log(`发送: leave_room`, 'send');
}
function setReady() {
if (!socket) return;
socket.emit('set_ready', { ready: true });
log(`发送: set_ready`, 'send');
}
function startGame() {
if (!socket) return;
socket.emit('start_game');
log(`发送: start_game`, 'send');
}
function makeGuess() {
if (!socket) return;
const number = parseInt(document.getElementById('guessNumber').value);
if (isNaN(number) || number < 1 || number > 100) {
log('请输入 1-100 之间的数字', 'error');
return;
}
socket.emit('game_action', {
action: 'guess',
data: { number: number }
});
log(`发送: game_action (guess ${number})`, 'send');
}
function clearLog() {
document.getElementById('log').innerHTML = '';
}
// ⚡ 快速开始:一键创建房间并开始
function quickStart() {
if (!socket) {
log('请先连接服务器', 'error');
return;
}
if (currentRoom) {
log('您已在房间中,请先离开当前房间', 'error');
return;
}
const playerName = document.getElementById('quickPlayerName').value || '蔡叔叔';
const aiCount = parseInt(document.getElementById('quickAiCount').value);
const aiType1 = document.getElementById('quickAiType1').value;
const aiType2 = document.getElementById('quickAiType2').value;
// 构建AI配置
const ai_players = [];
if (aiCount >= 1) {
ai_players.push({ name: `AI-1(${aiType1})`, ai_type: aiType1 });
}
if (aiCount >= 2) {
ai_players.push({ name: `AI-2(${aiType2})`, ai_type: aiType2 });
}
quickStartRoom = true;
socket.emit('create_room', {
game_type: 'doudizhu',
player_name: playerName,
config: { max_players: 3 },
ai_players: ai_players
});
log(`🚀 快速开始: 创建斗地主房间 (${aiCount}个AI)`, 'send');
}
// 每30秒发送心跳
setInterval(() => {
if (socket && socket.connected) {
socket.emit('ping', { timestamp: Date.now() });
}
}, 30000);
// 页面加载时自动连接(如果配置了自动连接)
// connect();
</script>
</body>
</html>