diff --git a/api/land_api.php b/api/land_api.php index 4da2356..f01ba8d 100644 --- a/api/land_api.php +++ b/api/land_api.php @@ -551,6 +551,7 @@ function initLandTables($db) { 'deny_fluid' => "INTEGER DEFAULT 0", 'clear_all_bad' => "INTEGER DEFAULT 0", 'is_public_building' => "INTEGER DEFAULT 0", + 'allow_visitor_teleport' => "INTEGER DEFAULT 0", ]; foreach ($permColumns as $col => $type) { try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN $col $type"); } catch (\Throwable $e) {} @@ -657,7 +658,7 @@ function handleSyncLands($db, $post) { deny_wool_shear, deny_animal_feeding, warp_x, warp_y, warp_z, warp_yaw, warp_pitch, warp_world, deny_container, deny_mob_attack, - enable_announce, announce_template, txt_content, deny_fluid, is_public_building) + enable_announce, announce_template, txt_content, deny_fluid, is_public_building, allow_visitor_teleport) VALUES (:id, :name, :owner, :world, :x1, :z1, :x2, :z2, :ymin, :ymax, :size, :created, :synced, :confiscate_items, :deny_use_items, :give_effects, :clear_effects, :clear_all_bad, @@ -672,7 +673,7 @@ function handleSyncLands($db, $post) { :deny_wool_shear, :deny_animal_feeding, :warp_x, :warp_y, :warp_z, :warp_yaw, :warp_pitch, :warp_world, :deny_container, :deny_mob_attack, - :enable_announce, :announce_template, :txt_content, :deny_fluid, :is_public_building)"); + :enable_announce, :announce_template, :txt_content, :deny_fluid, :is_public_building, :allow_visitor_teleport)"); foreach ($lands as $land) { $stmt->bindValue(':id', (int)($land['id'] ?? 0), SQLITE3_INTEGER); @@ -747,6 +748,7 @@ function handleSyncLands($db, $post) { $stmt->bindValue(':txt_content', $land['txt_content'] ?? '', SQLITE3_TEXT); $stmt->bindValue(':deny_fluid', (int)($land['deny_fluid'] ?? 0), SQLITE3_INTEGER); $stmt->bindValue(':is_public_building', (int)($land['is_public_building'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':allow_visitor_teleport', (int)($land['allow_visitor_teleport'] ?? 0), SQLITE3_INTEGER); $stmt->execute(); } @@ -1403,8 +1405,27 @@ function handleUpdateLandField($db, $playerName, $post) { return; } - // 允许的字段白名单 - $allowedFields = ['clear_effects', 'give_effects', 'clear_all_bad', 'deny_all_effects']; + // 允许的字段白名单(与Java端 updateLandFieldFromWeb 白名单完全对齐) + $allowedFields = [ + // 效果管理 + 'clear_effects', 'give_effects', 'clear_all_bad', 'deny_all_effects', + // 基础权限(与Java GUI访客权限列表一致) + 'deny_move', 'deny_block_place', 'deny_block_break', 'deny_entity_interact', + 'deny_container', 'deny_pvp', 'deny_mount', 'deny_ender_pearl', + 'deny_thrown_projectiles', 'deny_raid', 'deny_bow', 'deny_potion', + 'deny_fire', 'deny_fire_spread', 'deny_pickup', 'deny_drop', + 'deny_explosion', 'deny_fall_damage', 'deny_hunger', 'deny_all_damage', + 'deny_item_frame', 'deny_glowing', 'deny_redstone_interaction', + 'deny_door_interaction', 'deny_noteblock_jukebox', 'deny_lead', + 'deny_crop_harvest', 'deny_wool_shear', 'deny_animal_feeding', + 'deny_mob_attack', 'deny_fluid', + // 高级设置 + 'confiscate_items', 'deny_use_items', 'punish_commands', + 'peace_mode', 'peace_mode_duration', 'enforce_game_mode', + 'enter_msg', 'leave_msg', 'confiscate_msg', + // 传送与公共建筑 + 'allow_visitor_teleport', 'is_public_building', + ]; if (!in_array($field, $allowedFields)) { echo json_encode(['success' => false, 'error' => '不允许的字段: ' . $field]); return; diff --git a/api/sync.php b/api/sync.php index 51b2d53..c5345f6 100644 --- a/api/sync.php +++ b/api/sync.php @@ -462,6 +462,21 @@ function syncLands() { try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN clear_all_bad_effects INTEGER DEFAULT 0"); } catch (\Throwable $e) {} try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_all_effects INTEGER DEFAULT 0"); } catch (\Throwable $e) {} try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN admin_changed INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + // ★ 新增权限列迁移(与Java area_lands表完整对齐) + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_mount INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_ender_pearl INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_bow INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_potion INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_fire INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_raid INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_container INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_mob_attack INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN is_public_building INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN allow_visitor_teleport INTEGER DEFAULT 0"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN confiscate_items TEXT DEFAULT ''"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN deny_use_items TEXT DEFAULT ''"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN punish_commands TEXT DEFAULT ''"); } catch (\Throwable $e) {} + try { $db->exec("ALTER TABLE web_area_lands ADD COLUMN clear_all_bad INTEGER DEFAULT 0"); } catch (\Throwable $e) {} $now = time(); $stmt = $db->prepare("INSERT OR REPLACE INTO web_area_lands @@ -470,19 +485,25 @@ function syncLands() { enter_msg, leave_msg, confiscate_msg, enable_announce, announce_template, txt_content, deny_block_break, deny_block_place, deny_fluid, deny_pvp, deny_fire_spread, deny_all_effects, deny_item_frame, deny_entity_interact, deny_move, deny_pickup, deny_drop, deny_explosion, deny_fall_damage, deny_hunger, - deny_all_damage, clear_effects, give_effects, clear_all_bad_effects, + deny_all_damage, clear_effects, give_effects, clear_all_bad, admin_changed, deny_thrown_projectiles, deny_glowing, deny_redstone_interaction, deny_door_interaction, deny_noteblock_jukebox, deny_lead, deny_crop_harvest, deny_wool_shear, deny_animal_feeding, - warp_x, warp_y, warp_z, warp_yaw, warp_pitch, warp_world) + warp_x, warp_y, warp_z, warp_yaw, warp_pitch, warp_world, + deny_mount, deny_ender_pearl, deny_bow, deny_potion, deny_fire, deny_raid, + deny_container, deny_mob_attack, is_public_building, allow_visitor_teleport, + confiscate_items, deny_use_items, punish_commands, clear_all_bad_effects) VALUES (:id, :name, :owner, :world, :x1, :z1, :x2, :z2, :ymin, :ymax, :size, :created, :synced, :peace_mode, :peace_dur, :peace_wl, :enforce_gm, :mode_exempt, :enter_msg, :leave_msg, :confiscate_msg, :announce, :announce_tpl, :txt_content, :deny_block_break, :deny_block_place, :deny_fluid, :deny_pvp, :deny_fire_spread, :deny_all_effects, :deny_item_frame, :deny_entity_interact, :deny_move, :deny_pickup, :deny_drop, :deny_explosion, :deny_fall_damage, :deny_hunger, - :deny_all_damage, :clear_effects, :give_effects, :clear_all_bad_effects, + :deny_all_damage, :clear_effects, :give_effects, :clear_all_bad, :admin_changed, :deny_thrown_projectiles, :deny_glowing, :deny_redstone_interaction, :deny_door_interaction, :deny_noteblock_jukebox, :deny_lead, :deny_crop_harvest, :deny_wool_shear, :deny_animal_feeding, - :warp_x, :warp_y, :warp_z, :warp_yaw, :warp_pitch, :warp_world)"); + :warp_x, :warp_y, :warp_z, :warp_yaw, :warp_pitch, :warp_world, + :deny_mount, :deny_ender_pearl, :deny_bow, :deny_potion, :deny_fire, :deny_raid, + :deny_container, :deny_mob_attack, :is_public_building, :allow_visitor_teleport, + :confiscate_items, :deny_use_items, :punish_commands, :clear_all_bad_effects)"); $count = 0; foreach ($lands as $land) { $stmt->bindValue(':id', (int)($land['id'] ?? 0), SQLITE3_INTEGER); @@ -543,6 +564,21 @@ function syncLands() { $stmt->bindValue(':warp_yaw', (float)($land['warp_yaw'] ?? 0), SQLITE3_FLOAT); $stmt->bindValue(':warp_pitch', (float)($land['warp_pitch'] ?? 0), SQLITE3_FLOAT); $stmt->bindValue(':warp_world', $land['warp_world'] ?? '', SQLITE3_TEXT); + // ★ 新增字段绑定(与Java area_lands表完整对齐) + $stmt->bindValue(':deny_mount', (int)($land['deny_mount'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':deny_ender_pearl', (int)($land['deny_ender_pearl'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':deny_bow', (int)($land['deny_bow'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':deny_potion', (int)($land['deny_potion'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':deny_fire', (int)($land['deny_fire'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':deny_raid', (int)($land['deny_raid'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':deny_container', (int)($land['deny_container'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':deny_mob_attack', (int)($land['deny_mob_attack'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':is_public_building', (int)($land['is_public_building'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':allow_visitor_teleport', (int)($land['allow_visitor_teleport'] ?? 0), SQLITE3_INTEGER); + $stmt->bindValue(':confiscate_items', $land['confiscate_items'] ?? '', SQLITE3_TEXT); + $stmt->bindValue(':deny_use_items', $land['deny_use_items'] ?? '', SQLITE3_TEXT); + $stmt->bindValue(':punish_commands', $land['punish_commands'] ?? '', SQLITE3_TEXT); + $stmt->bindValue(':clear_all_bad', (int)($land['clear_all_bad'] ?? 0), SQLITE3_INTEGER); $stmt->execute(); $count++; } diff --git a/player.php b/player.php index 8449134..38f21fe 100644 --- a/player.php +++ b/player.php @@ -2936,6 +2936,69 @@ async function renderLandDetail(el, landName) { } html += ``; + // ★★★ 领地权限开关面板(与Java端GUI访客权限列表完全对齐) ★★★ + const permDefs = [ + // [字段名, 显示名, 是否反转(allow类)] + ['deny_move', '移动', false], + ['deny_block_place', '放置方块', false], + ['deny_block_break', '破坏方块', false], + ['deny_entity_interact', '实体交互(船/矿车/盔甲架/展示框)', false], + ['deny_container', '容器管理', false], + ['deny_pvp', '玩家对战', false], + ['deny_mount', '骑乘坐具', false], + ['deny_ender_pearl', '投掷末影珍珠', false], + ['deny_thrown_projectiles', '投掷物(三叉戟/雪球/风蛋)', false], + ['deny_raid', '袭击', false], + ['deny_bow', '弓箭射击', false], + ['deny_potion', '药水效果', false], + ['deny_fire', '点燃', false], + ['deny_fire_spread', '火焰蔓延', false], + ['deny_pickup', '拾取物品', true], // allowPickup: true=允许 + ['deny_drop', '丢弃物品', true], // allowDrop: true=允许 + ['deny_explosion', '爆炸', false], + ['deny_fall_damage', '摔落伤害', false], + ['deny_hunger', '饥饿', false], + ['deny_all_damage', '所有伤害', false], + ['deny_all_effects', '所有效果', false], + ['deny_item_frame', '展示框交互', false], + ['deny_glowing', '玩家发光', false], + ['deny_redstone_interaction', '红石电路(按钮/压力板/中继器)', false], + ['deny_door_interaction', '门禁交互(门/栅栏门)', false], + ['deny_noteblock_jukebox', '音频(音符盒/唱片机)', false], + ['deny_lead', '拴绳使用', false], + ['deny_crop_harvest', '农作物收获', false], + ['deny_wool_shear', '剪切羊毛/生物', false], + ['deny_animal_feeding', '投喂动物', false], + ['deny_mob_attack', '攻击生物', false], + ['deny_fluid', '流体放置', false], + ['allow_visitor_teleport', '允许传送', true], + ['is_public_building', '公共建筑设施', true], + ]; + + html += `
+

🛡️ 领地权限

+

点击切换权限状态。启用=允许该行为,禁用=阻止该行为。

+
`; + + for (const [field, label, isInverted] of permDefs) { + const rawVal = parseInt(land[field] || 0); + // 反转类(allow_*/is_public):1=启用;deny类:0=启用 + const isEnabled = isInverted ? (rawVal === 1) : (rawVal === 0); + const bgColor = isEnabled ? 'rgba(34,197,94,0.15)' : 'rgba(239,68,68,0.1)'; + const borderColor = isEnabled ? 'rgba(34,197,94,0.4)' : 'rgba(239,68,68,0.3)'; + const textColor = isEnabled ? '#22c55e' : '#ef4444'; + const icon = isEnabled ? '✓' : '✕'; + + html += ` + ${icon} ${escHtml(label)} + `; + } + + html += `
`; + html += ``; el.innerHTML = html; @@ -3108,6 +3171,45 @@ async function toggleLandField(landName, field) { } } +// ★ 权限开关切换(处理deny/allow反转逻辑) +// isInverted=true时:DB值1=禁用(显示红),DB值0=启用(显示绿) +// isInverted=false时:DB值1=禁用(显示红),DB值0=启用(显示绿) — 相同逻辑,反转体现在发送值 +async function togglePerm(landName, field, isInverted) { + try { + // 读取当前值 + const detailUrl = new URL(API + 'land_api.php', location.href); + detailUrl.searchParams.set('action', 'land_detail'); + detailUrl.searchParams.set('token', TOKEN); + detailUrl.searchParams.set('name', landName); + const detailRes = await fetch(detailUrl); + const detailData = await detailRes.json(); + if (!detailData.success) { glassAlert(detailData.error); return; } + + const currentDbVal = parseInt(detailData.land[field] || 0); + // deny类:当前0(允许)→发送1(禁止);allow类:当前0(禁止)→发送1(允许) + // 统一取反即可 + const newVal = currentDbVal ? '0' : '1'; + + const url = new URL(API + 'land_api.php', location.href); + url.searchParams.set('action', 'update_land_field'); + url.searchParams.set('token', TOKEN); + const body = new URLSearchParams(); + body.set('name', landName); + body.set('field', field); + body.set('value', newVal); + const res = await fetch(url, { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: body.toString() }); + const data = await res.json(); + if (data.success) { + landsState.currentLand = landName; + await renderLandDetail(document.getElementById('content'), landName); + } else { + glassAlert(data.error || '操作失败'); + } + } catch (e) { + glassAlert('操作失败: ' + e.message); + } +} + async function addClearEffect(landName) { // MC药水效果列表(用户选择而非手动输入) const EFFECTS = [