Commit d1981422 authored by Nemo Ma's avatar Nemo Ma

fix(admin): preserve itmpara JSON commas in resource editor

parent 7d154693
......@@ -22,6 +22,7 @@ $admin_cmd_list = Array(
'roommng' => 5,
'antiAFKmng' => 4,
'templates_clean' => 4,
'resourcemng' => 7,
);
if(!$cuser||!$cpass) { gexit($_ERROR['no_login'],__file__,__line__); }
......
......@@ -257,6 +257,8 @@ $lang = array
'templates_clean_comment' => '清空已生成的模板缓存文件',
'roommng' => '临时性房间管理',
'roommng_comment' => '强制关闭指定编号的房间<br>不能关闭0号大房间(临时功能)',
'resourcemng' => '游戏资源管理',
'resourcemng_comment' => '管理地图物品/商店/开局物品与NPC配置,支持按RuleSet编辑',
'pcmng' => '玩家数据管理',
'pcmng_comment' => '修改当前局玩家的各数值,不影响帐号',
......
<?php
if(!defined('IN_ADMIN')) {
exit('Access Denied');
}
if(!isset($res_type)) $res_type = 'mapitem';
if(!isset($start)) $start = 0;
if(!isset($pagemode)) $pagemode = '';
if(!isset($keyword)) $keyword = '';
if(!isset($ruleset)) $ruleset = '__default__';
if(!isset($action)) $action = 'list';
if(isset($edit_id)) {
$action = 'edit';
$record_id = intval($edit_id);
}
if(isset($delete_id)) {
$action = 'delete';
$record_id = intval($delete_id);
}
$start = getstart($start,$pagemode);
$keyword = trim($keyword);
$res_type = in_array($res_type, array('mapitem','shopitem','stitem','stwep','npc')) ? $res_type : 'mapitem';
$ruleset = preg_match('/^[A-Za-z0-9_]+$/', $ruleset) ? $ruleset : '__default__';
$ruleset_list = resourcemng_get_rulesets($res_type);
if(!isset($ruleset_list[$ruleset])) $ruleset = '__default__';
$target_file = $ruleset_list[$ruleset]['file'];
$allow_upload = ($mygroup > 10);
if($action === 'download') {
if(file_exists($target_file)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($target_file).'"');
header('Content-Length: '.filesize($target_file));
readfile($target_file);
adminlog('resourcemng_download',$res_type,$ruleset,basename($target_file));
exit;
}
$cmd_info = '下载失败:目标文件不存在。';
}
if($action === 'upload' && $allow_upload) {
if(!empty($_FILES['cfgfile']['tmp_name']) && is_uploaded_file($_FILES['cfgfile']['tmp_name'])) {
$uploaded = file_get_contents($_FILES['cfgfile']['tmp_name']);
if($uploaded !== false && strlen($uploaded) > 0) {
if(@file_put_contents($target_file, $uploaded) !== false) {
$cmd_info = '上传覆盖成功。';
adminlog('resourcemng_upload',$res_type,$ruleset,$_FILES['cfgfile']['name']);
} else {
$cmd_info = '上传失败:写入文件失败。';
}
} else {
$cmd_info = '上传失败:文件内容为空或不可读。';
}
} else {
$cmd_info = '上传失败:未检测到上传文件。';
}
}
$resource = resourcemng_read_data($res_type, $target_file);
$records = $resource['records'];
$header = $resource['header'];
$columns = $resource['columns'];
if($action === 'save_record') {
$id = isset($record_id) ? intval($record_id) : -1;
if(isset($records[$id])) {
$new_row = resourcemng_collect_row($res_type, $_POST, $records[$id]);
$valid = resourcemng_validate_row($res_type, $new_row, $err);
if($valid) {
$records[$id] = $new_row;
if(resourcemng_write_data($res_type, $target_file, $header, $records)) {
$cmd_info = '记录已保存。';
adminlog('resourcemng_edit',$res_type,$ruleset,$id);
} else {
$cmd_info = '保存失败:写入文件失败。';
}
} else {
$cmd_info = '保存失败:'.$err;
}
} else {
$cmd_info = '保存失败:记录不存在。';
}
$resource = resourcemng_read_data($res_type, $target_file);
$records = $resource['records'];
}
if($action === 'delete') {
$id = isset($record_id) ? intval($record_id) : -1;
if(isset($records[$id])) {
unset($records[$id]);
$records = array_values($records);
if(resourcemng_write_data($res_type, $target_file, $header, $records)) {
$cmd_info = '记录已删除。';
adminlog('resourcemng_delete',$res_type,$ruleset,$id);
} else {
$cmd_info = '删除失败:写入文件失败。';
}
}
$resource = resourcemng_read_data($res_type, $target_file);
$records = $resource['records'];
}
if($action === 'add') {
$new_row = resourcemng_collect_row($res_type, $_POST, array());
$valid = resourcemng_validate_row($res_type, $new_row, $err);
if($valid) {
if($res_type === 'npc' && isset($record_id) && intval($record_id) >= 0) $records[intval($record_id)] = $new_row;
else $records[] = $new_row;
if(resourcemng_write_data($res_type, $target_file, $header, $records)) {
$cmd_info = '新记录已添加。';
adminlog('resourcemng_add',$res_type,$ruleset,'new');
} else {
$cmd_info = '新增失败:写入文件失败。';
}
} else {
$cmd_info = '新增失败:'.$err;
}
$resource = resourcemng_read_data($res_type, $target_file);
$records = $resource['records'];
}
$edit_record = array();
if($action === 'edit' && isset($record_id)) {
$id = intval($record_id);
if(isset($records[$id])) $edit_record = $records[$id];
}
$edit_record_json = '';
if($res_type === 'npc' && !empty($edit_record)) {
$edit_record_json = json_encode($edit_record, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
}
$filtered = array();
foreach($records as $i => $row) {
$ok = true;
if($keyword !== '') {
$src = is_array($row) ? json_encode($row,JSON_UNESCAPED_UNICODE) : strval($row);
if(stripos($src, $keyword) === false) $ok = false;
}
if($ok) {
$row['_idx'] = $i;
if($res_type === 'npc') {
$row['_sub_count'] = (isset($row['sub']) && is_array($row['sub'])) ? count($row['sub']) : 0;
}
$filtered[] = $row;
}
}
$total_count = count($filtered);
$paged_records = array_slice($filtered, $start, $showlimit);
$resultinfo = '第'.($total_count?($start+1):0).'条-第'.($start+count($paged_records)).'条 / 共'.$total_count.'条';
include template('admin_resourcemng');
function resourcemng_get_rulesets($res_type){
$map = array(
'mapitem' => 'mapitem_1.php',
'shopitem' => 'shopitem_1.php',
'stitem' => 'stitem_1.php',
'stwep' => 'stwep_1.php',
'npc' => 'npc_1.php',
);
$list = array();
$list['__default__'] = array('name' => '默认配置', 'file' => GAME_ROOT.'./gamedata/cache/'.$map[$res_type]);
$ruleset_root = GAME_ROOT.'./gamedata/ruleset';
if(is_dir($ruleset_root)) {
foreach(scandir($ruleset_root) as $id) {
if($id === '.' || $id === '..') continue;
if(!preg_match('/^[A-Za-z0-9_]+$/',$id)) continue;
$file = $ruleset_root.'/'.$id.'/cache/'.$map[$res_type];
if(file_exists($file)) {
$list[$id] = array('name' => 'RuleSet: '.$id, 'file' => $file);
}
}
}
return $list;
}
function resourcemng_read_data($res_type, $file){
if($res_type === 'npc') {
if(!defined('IN_GAME')) define('IN_GAME', TRUE);
$npcinit = array(); $npcinfo = array();
include $file;
return array('header' => '', 'records' => $npcinfo, 'columns' => array('key','value_json'), 'type' => 'npc');
}
$raw = file_get_contents($file);
if($raw === false) $raw = '';
$raw = str_replace("\r\n", "\n", $raw);
$lines = explode("\n", $raw);
$header = '';
$data_lines = array();
$in_guard = false;
foreach($lines as $line) {
$trim = trim($line);
if($trim === '') continue;
if(strpos($trim, '<?') === 0) {
$header .= $line."\n";
$in_guard = (strpos($trim, '?>') === false);
continue;
}
if($in_guard) {
$header .= $line."\n";
if(strpos($trim, '?>') !== false) $in_guard = false;
continue;
}
if(strpos($trim,'//') === 0) { $header .= $line."\n"; continue; }
$data_lines[] = $line;
}
$records = array();
$expected = count(resourcemng_columns($res_type));
foreach($data_lines as $line) {
$line = trim($line);
// 配置行统一以逗号结尾,先去掉末尾分隔符,保留中间 JSON/文本中的逗号
$line = preg_replace('/,\s*$/', '', $line);
$row = explode(',', $line, $expected);
$row = array_map('trim', $row);
if(count($row) < $expected) $row = array_pad($row, $expected, '');
$records[] = $row;
}
$columns = resourcemng_columns($res_type);
return array('header' => $header, 'records' => $records, 'columns' => $columns, 'type' => 'csv');
}
function resourcemng_write_data($res_type, $file, $header, $records){
if($res_type === 'npc') {
$data = "<?php\n\n\tif(!defined('IN_GAME')) exit('Access Denied');\n\n";
$data .= "\t\$npcinit = array\n\t(\n\t\t'name' => '',\t'pass' => 'bra', 'gd' => 'm',\t'icon' => 0,\t'club' => 0,\t\n\t\t'mhp' => 0,\t'msp' => 0,\t'att' => 0,\t'def' => 0,\t'pls' => 0,\t'lvl' => 0,\n\t\t'money' => 0,\t'inf' => '',\t'rage' => 0,\t'pose' => 0,\t'tactic' => 0,\t\n\t\t'killnum' => 0,\t'state' => 1,\t'teamID' => '',\t'teamPass' => '','bid' => 0,\n\t\t'horizon' => 0, 'clbpara' => Array(),\n\t\t'wp' => 0, 'wk' => 0, 'wc' => 0, 'wg' => 0, 'wd' => 0, 'wf' => 0, 'skills' => 0, 'rp' => 0,\n\t);\n";
$data .= "\t\$npcinfo = ".var_export($records, true).";\n?>";
return @file_put_contents($file, $data) !== false;
}
$out = rtrim($header)."\n";
foreach($records as $row) {
$out .= implode(',', $row).",\n";
}
return @file_put_contents($file, $out) !== false;
}
function resourcemng_columns($res_type){
$map = array(
'mapitem' => array('刷新禁区','地图编号','数量','名称','类别','效果值','耐久/次数','属性','itmpara'),
'shopitem' => array('记录类型','分类/出现率','价格/参数','等级','名称','类别','效果值','耐久/次数','属性','itmpara'),
'stitem' => array('名称','类别','效果值','耐久/次数','属性','itmpara'),
'stwep' => array('名称','类别','效果值','耐久/次数','属性','itmpara'),
'npc' => array('NPC类别','配置JSON'),
);
return $map[$res_type];
}
function resourcemng_collect_row($res_type, $input, $default){
if($res_type === 'npc') {
$key = isset($input['record_id']) ? intval($input['record_id']) : -1;
$json = isset($input['npc_json']) ? trim($input['npc_json']) : '';
$arr = $default;
if($key >= 0) {
$decoded = json_decode($json, true);
if(!is_array($decoded)) $decoded = array();
$arr = $decoded;
}
return $arr;
}
$row = $default;
$size = count(resourcemng_columns($res_type));
for($i=0;$i<$size;$i++) {
$val = isset($input['col_'.$i]) ? trim($input['col_'.$i]) : '';
$val = str_replace(array("\n","\r"), array('',''), $val);
// 最后一列是 itmpara(JSON),必须保留半角逗号
if($i === $size - 1) {
$row[$i] = $val;
} else {
$row[$i] = str_replace(',', ',', $val);
}
}
return $row;
}
function resourcemng_validate_row($res_type, $row, &$err){
$err = '';
if($res_type === 'npc') {
if(!is_array($row)) { $err = 'NPC配置必须为对象数组'; return false; }
return true;
}
if(empty($row) || trim($row[0]) === '') {
$err = '首字段不能为空';
return false;
}
// CSV 资源的最后一列为 itmpara,若填写则应为合法 JSON
$last = count($row) - 1;
if($last >= 0) {
$itmpara = trim($row[$last]);
if($itmpara !== '' && $itmpara !== 'null') {
json_decode($itmpara, true);
if(json_last_error() !== JSON_ERROR_NONE) {
$err = 'itmpara 不是合法JSON:'.json_last_error_msg();
return false;
}
}
}
return true;
}
?>
......@@ -91,6 +91,11 @@
<td>$lang['templates_clean_comment']</td>
<td>$admin_cmd_list['templates_clean']</td>
</tr>
<tr height="45px">
<td><input type="submit" style="width:100;height:40;" value="$lang['resourcemng']" onclick="$('command').value='resourcemng'" <!--{if $mygroup < $admin_cmd_list['resourcemng']}-->disabled="true"<!--{/if}-->></td>
<td>$lang['resourcemng_comment']</td>
<td>$admin_cmd_list['resourcemng']</td>
</tr>
<tr height="45px">
<td><input type="submit" style="width:100;height:40;" value="$lang['roommng']" onclick="$('command').value='roommng'" <!--{if $mygroup < $admin_cmd_list['roommng']}-->disabled="true"<!--{/if}-->></td>
<td>$lang['roommng_comment']</td>
......
<form method="post" name="resmng" action="admin.php" enctype="multipart/form-data">
<input type="hidden" name="mode" value="resourcemng">
<input type="hidden" name="start" value="$start">
<input type="hidden" name="record_id" id="record_id" value="$record_id">
<table class="admin" cellspacing="1" cellpadding="4">
<tr>
<td colspan="4" class="tdtitle">游戏资源管理</td>
</tr>
<tr>
<td>资源类型</td>
<td>
<select name="res_type">
<option value="mapitem" <!--{if $res_type=='mapitem'}-->selected<!--{/if}-->>地图物品</option>
<option value="shopitem" <!--{if $res_type=='shopitem'}-->selected<!--{/if}-->>商店物品</option>
<option value="stitem" <!--{if $res_type=='stitem'}-->selected<!--{/if}-->>开局物品</option>
<option value="stwep" <!--{if $res_type=='stwep'}-->selected<!--{/if}-->>开局武器</option>
<option value="npc" <!--{if $res_type=='npc'}-->selected<!--{/if}-->>开局NPC</option>
</select>
</td>
<td>配置来源</td>
<td>
<select name="ruleset">
<!--{loop $ruleset_list $rid $rinfo}-->
<option value="$rid" <!--{if $ruleset==$rid}-->selected<!--{/if}-->>$rinfo['name']</option>
<!--{/loop}-->
</select>
<input type="submit" name="action" value="list">
</td>
</tr>
<tr>
<td>搜索</td>
<td colspan="3">
<input type="text" name="keyword" value="$keyword" style="width:300px;">
<input type="submit" name="action" value="list">
<span class="yellow">$resultinfo</span>
</td>
</tr>
<tr>
<td>文件操作</td>
<td colspan="3">
<input type="submit" name="action" value="download">
<!--{if $allow_upload}-->
<input type="file" name="cfgfile">
<input type="submit" name="action" value="upload">
<!--{else}-->
<span class="grey">上传覆盖仅限管理员等级 &gt; 10</span>
<!--{/if}-->
</td>
</tr>
</table>
<br>
<!--{if $res_type!='npc'}-->
<table class="admin" cellspacing="1" cellpadding="4">
<tr>
<th>ID</th>
<!--{loop $columns $i $c}-->
<th>$c</th>
<!--{/loop}-->
<th>操作</th>
</tr>
<!--{loop $paged_records $idx $row}-->
<tr>
<td>$row['_idx']</td>
<!--{loop $columns $ci $c}-->
<td>{eval echo $row[$ci];}</td>
<!--{/loop}-->
<td>
<button type="submit" name="edit_id" value="$row['_idx']">编辑</button>
<button type="submit" name="delete_id" value="$row['_idx']" onclick="return confirm('确认删除该记录?');">删除</button>
</td>
</tr>
<!--{/loop}-->
</table>
<!--{else}-->
<table class="admin" cellspacing="1" cellpadding="4">
<tr>
<th>NPC类别</th>
<th>子键数量</th>
<th>操作</th>
</tr>
<!--{loop $paged_records $idx $row}-->
<tr>
<td>$row['_idx']</td>
<td>$row['_sub_count']</td>
<td>
<button type="submit" name="edit_id" value="$row['_idx']">编辑</button>
<button type="submit" name="delete_id" value="$row['_idx']" onclick="return confirm('确认删除该类别?');">删除</button>
</td>
</tr>
<!--{/loop}-->
</table>
<!--{/if}-->
<br>
<table class="admin" cellspacing="1" cellpadding="4">
<tr>
<td colspan="2" class="tdtitle">编辑/新增</td>
</tr>
<!--{if $res_type!='npc'}-->
<tr>
<td>ID</td>
<td><input type="text" name="record_id" value="$record_id"></td>
</tr>
<!--{loop $columns $i $c}-->
<tr>
<td>$c</td>
<td><input type="text" name="col_$i" style="width:98%;" value="{$edit_record[$i]}"></td>
</tr>
<!--{/loop}-->
<tr>
<td colspan="2">
<button type="submit" name="action" value="save_record">保存当前ID</button>
<button type="submit" name="action" value="add">新增记录</button>
</td>
</tr>
<!--{else}-->
<tr>
<td>NPC类别ID</td>
<td><input type="text" name="record_id" value="$record_id"></td>
</tr>
<tr>
<td>JSON配置</td>
<td>
<textarea name="npc_json" style="width:98%;height:260px;">$edit_record_json</textarea>
</td>
</tr>
<tr>
<td colspan="2">
<button type="submit" name="action" value="save_record">保存当前类别</button>
<button type="submit" name="action" value="add">新增类别</button>
</td>
</tr>
<!--{/if}-->
</table>
<div style="margin-top:8px;">
<button type="submit" name="pagemode" value="up">上一页</button>
<button type="submit" name="pagemode" value="down">下一页</button>
</div>
</form>
......@@ -117,7 +117,8 @@ if($mode == 'enter') {
$arhe = $arae = $arfe = $arte = 0;
$arhs = $aras = $arfs = $arts = 0;
for ($i=0; $i<=6; $i++){$itm[$i] = $itmk[$i] = $itmsk[$i] = ''; $itme[$i] = $itms[$i] = 0;}
for ($i=0; $i<=6; $i++){$itm[$i] = $itmk[$i] = $itmsk[$i] = $itmpara[$i] = ''; $itme[$i] = $itms[$i] = 0;}
$weppara = '';
$itm[1] = '面包'; $itmk[1] = 'HH'; $itme[1] = 120; $itms[1] = 15;
$itm[2] = '矿泉水'; $itmk[2] = 'HS'; $itme[2] = 140; $itms[2] = 15;
//$itm[6] = '银白盒子'; $itmk[6] = 'p'; $itme[6] = 1; $itms[6] = 1; $itmsk[6] = 'ps';
......@@ -139,7 +140,9 @@ if($mode == 'enter') {
$weplist = openfile(config('stwep',$gamecfg));
do {
$index = rand(1,count($weplist)-1);
list($wep,$wepk,$wepe,$weps,$wepsk) = explode(",",$weplist[$index]);
$wline = rtrim($weplist[$index]);
$wline = preg_replace('/,\s*$/', '', $wline);
list($wep,$wepk,$wepe,$weps,$wepsk,$weppara) = array_pad(explode(",", $wline, 6), 6, '');
} while(!$wepk);
$stitemlist = openfile(config('stitem',$gamecfg));
......@@ -149,7 +152,9 @@ if($mode == 'enter') {
} while(!$itmk[3]);*/
do {
$index = rand(1,count($stitemlist)-1);
list($itm[4],$itmk[4],$itme[4],$itms[4],$itmsk[4]) = explode(",",$stitemlist[$index]);
$iline = rtrim($stitemlist[$index]);
$iline = preg_replace('/,\s*$/', '', $iline);
list($itm[4],$itmk[4],$itme[4],$itms[4],$itmsk[4],$itmpara[4]) = array_pad(explode(",", $iline, 6), 6, '');
} while(!$itmk[4] || ($itmk[3] == $itmk[4]));
if ($name == 'Amarillo_NMC') {
......@@ -185,6 +190,7 @@ if($mode == 'enter') {
{
${'itm'.$i} = $value; ${'itmk'.$i} = $itmk[$i]; ${'itme'.$i} = $itme[$i]; ${'itms'.$i} = $itms[$i];
if(isset($itmsk[$i])) ${'itmsk'.$i} = $itmsk[$i];
if(isset($itmpara[$i])) ${'itmpara'.$i} = $itmpara[$i];
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment