修复PHP操作效果后JSON解析崩溃:convertEffectsForFrontend增加容错处理+handleUpdateLandField统一管道格式到变更队列+player.php所有effects JSON.parse加try-catch

This commit is contained in:
ypsdf1
2026-07-12 11:41:26 +08:00
parent 0760cc1d2e
commit f5879f4087
2 changed files with 55 additions and 17 deletions
+44 -11
View File
@@ -11,22 +11,32 @@ error_reporting(E_ERROR | E_PARSE);
* ★ 将Java自定义格式转换为JSON数组
* give_effects: "夜视:1:99999|SPEED:2:60" → [["夜视","1","99999"],["SPEED","2","60"]]
* clear_effects: "POISON,WITHER" → ["POISON","WITHER"]
* 兼容JSON格式(Java sync回写时可能是JSON):[["夜视","1","99999"]] → 直接返回
*/
function convertEffectsForFrontend($row) {
if (!empty($row['give_effects']) && $row['give_effects'][0] !== '[') {
$parts = explode('|', $row['give_effects']);
if (!empty($row['give_effects'])) {
$raw = $row['give_effects'];
if ($raw[0] === '[') {
// 可能是JSON格式,验证是否有效
$decoded = json_decode($raw, true);
if (is_array($decoded)) {
// 有效JSON,确保每个元素都是数组格式
$arr = [];
foreach ($parts as $p) {
$p = trim($p);
if (empty($p)) continue;
$pieces = explode(':', $p);
if (count($pieces) >= 2) {
$arr[] = $pieces;
foreach ($decoded as $e) {
if (is_array($e) && count($e) >= 2) {
$arr[] = array_map('strval', $e);
} elseif (is_string($e)) {
$arr[] = [$e, '1', '99999'];
}
}
$row['give_effects'] = json_encode($arr, JSON_UNESCAPED_UNICODE);
} else {
$arr[] = [$pieces[0], '1', '99999'];
// JSON无效,尝试作为管道格式解析
$row['give_effects'] = convertPipeEffectsToFrontend($raw);
}
} else {
$row['give_effects'] = convertPipeEffectsToFrontend($raw);
}
$row['give_effects'] = json_encode($arr);
}
if (!empty($row['clear_effects']) && $row['clear_effects'][0] !== '[') {
$names = array_filter(explode(',', $row['clear_effects']), function($n) { return !empty(trim($n)); });
@@ -35,6 +45,28 @@ function convertEffectsForFrontend($row) {
return $row;
}
/**
* 管道格式 → JSON数组
* "力量:255:60|速度:1:300" → [["力量","255","60"],["速度","1","300"]]
*/
function convertPipeEffectsToFrontend($raw) {
$parts = explode('|', $raw);
$arr = [];
foreach ($parts as $p) {
$p = trim($p);
if (empty($p)) continue;
$pieces = explode(':', $p);
if (count($pieces) >= 3) {
$arr[] = [$pieces[0], $pieces[1], $pieces[2]];
} elseif (count($pieces) === 2) {
$arr[] = [$pieces[0], $pieces[1], '300'];
} elseif (count($pieces) === 1 && $pieces[0] !== '') {
$arr[] = [$pieces[0], '1', '99999'];
}
}
return json_encode($arr, JSON_UNESCAPED_UNICODE);
}
// ★ 29种权限类型定义(必须在try之前,否则handleGetMemberPerms调用时变量未定义)
// ★ 与Java AreaProtection.getLandDefaultDeny 完全对齐(32个per-player权限键)
$PERM_TYPES = [
@@ -1595,10 +1627,11 @@ function handleUpdateLandField($db, $playerName, $post) {
$stmt2->execute();
// 记录变更到变更队列(Java端轮询)
// ★ 统一存储转换后的格式(管道格式),Java端parseEffectsString原生支持
$stmt3 = $db->prepare("INSERT INTO web_admin_changes (change_type, target_id, target_name, change_data, created_at) VALUES ('land_field_change', :lid, :name, :data, :now)");
$stmt3->bindValue(':lid', (int)$land['id'], SQLITE3_INTEGER);
$stmt3->bindValue(':name', $name, SQLITE3_TEXT);
$stmt3->bindValue(':data', json_encode(['field' => $field, 'value' => $value]), SQLITE3_TEXT);
$stmt3->bindValue(':data', json_encode(['field' => $field, 'value' => $storeValue], JSON_UNESCAPED_UNICODE), SQLITE3_TEXT);
$stmt3->bindValue(':now', time(), SQLITE3_INTEGER);
$stmt3->execute();
+10 -5
View File
@@ -2870,8 +2870,10 @@ async function renderLandDetail(el, landName) {
html += `</div></div>`;
// ★★★ 效果管理 ★★★
const clearEffects = land.clear_effects ? JSON.parse(land.clear_effects) : [];
const giveEffects = land.give_effects ? JSON.parse(land.give_effects) : [];
let clearEffects = [];
let giveEffects = [];
try { clearEffects = land.clear_effects ? JSON.parse(land.clear_effects) : []; } catch(e) { clearEffects = []; }
try { giveEffects = land.give_effects ? JSON.parse(land.give_effects) : []; } catch(e) { giveEffects = []; }
const clearAllBad = !!parseInt(land.clear_all_bad || 0);
const denyAll = !!parseInt(land.deny_all_effects || 0);
@@ -3286,7 +3288,8 @@ async function addClearEffect(landName) {
const detailRes = await fetch(detailUrl);
const detailData = await detailRes.json();
if (!detailData.success) { glassAlert(detailData.error); return; }
const current = detailData.land.clear_effects ? JSON.parse(detailData.land.clear_effects) : [];
let current = [];
try { current = detailData.land.clear_effects ? JSON.parse(detailData.land.clear_effects) : []; } catch(e) { current = []; }
// 过滤掉已添加的效果(兼容中文名和英文名)
const EN_TO_CN = {SPEED:'速度',SLOWNESS:'缓慢',HASTE:'急迫',MINING_FATIGUE:'挖掘疲劳',STRENGTH:'力量',JUMP_BOOST:'跳跃提升',NAUSEA:'反胃',REGENERATION:'再生',RESISTANCE:'抗性提升',FIRE_RESISTANCE:'火焰抗性',WATER_BREATHING:'水下呼吸',INVISIBILITY:'隐身',BLINDNESS:'失明',NIGHT_VISION:'夜视',WEAKNESS:'虚弱',POISON:'中毒',WITHER:'凋零',HEALTH_BOOST:'生命提升',ABSORPTION:'吸收',SATURATION:'饱和',GLOWING:'发光',LEVITATION:'漂浮',SLOW_FALLING:'缓降',LUCK:'幸运',UNLUCK:'厄运',DOLPHINS_GRACE:'海豚的恩惠',CONDUIT_POWER:'潮涌能量',BAD_OMEN:'不祥之兆',HERO_OF_THE_VILLAGE:'英雄',INSTANT_HEALTH:'瞬间治疗',INSTANT_DAMAGE:'瞬间伤害',WORLD_BORDER:'边界',DARKNESS:'黑暗'};
@@ -3362,7 +3365,8 @@ async function addGiveEffect(landName) {
const detailRes = await fetch(detailUrl);
const detailData = await detailRes.json();
if (!detailData.success) { glassAlert(detailData.error); return; }
const current = detailData.land.give_effects ? JSON.parse(detailData.land.give_effects) : [];
let current = [];
try { current = detailData.land.give_effects ? JSON.parse(detailData.land.give_effects) : []; } catch(e) { current = []; }
// 过滤掉已添加的效果(兼容中文名和英文名)
const EN_TO_CN = {SPEED:'速度',SLOWNESS:'缓慢',HASTE:'急迫',MINING_FATIGUE:'挖掘疲劳',STRENGTH:'力量',JUMP_BOOST:'跳跃提升',NAUSEA:'反胃',REGENERATION:'再生',RESISTANCE:'抗性提升',FIRE_RESISTANCE:'火焰抗性',WATER_BREATHING:'水下呼吸',INVISIBILITY:'隐身',BLINDNESS:'失明',NIGHT_VISION:'夜视',WEAKNESS:'虚弱',POISON:'中毒',WITHER:'凋零',HEALTH_BOOST:'生命提升',ABSORPTION:'吸收',SATURATION:'饱和',GLOWING:'发光',LEVITATION:'漂浮',SLOW_FALLING:'缓降',LUCK:'幸运',UNLUCK:'厄运',DOLPHINS_GRACE:'海豚的恩惠',CONDUIT_POWER:'潮涌能量',BAD_OMEN:'不祥之兆',HERO_OF_THE_VILLAGE:'英雄',INSTANT_HEALTH:'瞬间治疗',INSTANT_DAMAGE:'瞬间伤害',WORLD_BORDER:'边界',DARKNESS:'黑暗'};
@@ -3418,7 +3422,8 @@ async function removeLandEffect(landName, field, effValue) {
const detailData = await detailRes.json();
if (!detailData.success) { glassAlert(detailData.error); return; }
let current = detailData.land[field] ? JSON.parse(detailData.land[field]) : [];
let current = [];
try { current = detailData.land[field] ? JSON.parse(detailData.land[field]) : []; } catch(e) { current = []; }
if (field === 'clear_effects') {
// clear_effects: 效果名可能是中文或英文,两种都匹配
const EN_TO_CN = {SPEED:'速度',SLOWNESS:'缓慢',HASTE:'急迫',MINING_FATIGUE:'挖掘疲劳',STRENGTH:'力量',JUMP_BOOST:'跳跃提升',NAUSEA:'反胃',REGENERATION:'再生',RESISTANCE:'抗性提升',FIRE_RESISTANCE:'火焰抗性',WATER_BREATHING:'水下呼吸',INVISIBILITY:'隐身',BLINDNESS:'失明',NIGHT_VISION:'夜视',WEAKNESS:'虚弱',POISON:'中毒',WITHER:'凋零',HEALTH_BOOST:'生命提升',ABSORPTION:'吸收',SATURATION:'饱和',GLOWING:'发光',LEVITATION:'漂浮',SLOW_FALLING:'缓降',LUCK:'幸运',UNLUCK:'厄运',DOLPHINS_GRACE:'海豚的恩惠',CONDUIT_POWER:'潮涌能量',BAD_OMEN:'不祥之兆',HERO_OF_THE_VILLAGE:'英雄',INSTANT_HEALTH:'瞬间治疗',INSTANT_DAMAGE:'瞬间伤害',WORLD_BORDER:'边界',DARKNESS:'黑暗'};