Best Studio 1
Best Studio
D 1
delimuratt
Aliyldrim 1
Aliyldrim
Mt2Hizmet 1
Mt2Hizmet
noisiv 1
noisiv
Manwe Work 1
Manwe Work
melankolıa18 1
melankolıa18
Agora Metin2 1
Agora Metin2
Cannn6161 1
Cannn6161
kralhakan2009 1
kralhakan2009
Vahsi Uzman 1
Vahsi Uzman
Hikaye Ekle
Reklam vermek için turkmmo@gmail.com

Mob Proto Editör - Basit işlem odaklı

  • Konuyu başlatan Konuyu başlatan obulut
  • Başlangıç tarihi Başlangıç tarihi
  • Cevaplar Cevaplar 4
  • Görüntüleme Görüntüleme 273

obulut

Moderatör
Telefon Numarası Onaylanmış Üye
Moderator
Katılım
22 Nis 2024
Konular
35
Mesajlar
275
Çözüm
7
Online süresi
9d 11h
Reaksiyon Skoru
351
Altın Konu
0
Başarım Puanı
97
MmoLira
2,360
DevLira
54
Ticaret - 0%
0   0   0

ROHAN2 WORLD 1-120 TR TİPİ OFFICIAL YOHARA, BALATHOR VE AMON! 80. GÜNÜNDE! +10.000 ONLİNE! HİLE VE BOT %100 ENGELLİ HEMEN TIKLA!

Forum'da paylaşılan kadar görüntü odaklı değil ama gayet işlevsel iş görür nitelik de
local-bsd üzerinde Ngix-PHP8-PHP-FPM Kullanıyorum Farklı yerler de denemedim.
Gerekli oldukça güncellerim.
Kurulum için destek yok.

mob_proto.txt,mob_names.txt ve mobproto.php aynı klasörde olmak zorunda

pkg install -y nginx php82 php82-mysqli php82-mbstring php82-gd php82-curl php82-zlib php82-zip php82-xml php82-fpm php82-filter php82-iconv
sysrc nginx_enable="YES"
sysrc php_fpm_enable="YES"
service php-fpm start
service nginx start
/usr/local/etc/nginx/nginx.conf

Kod:
worker_processes 1;
events { worker_connections 1024; }
http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    server {
        listen 80;
        server_name localhost;
        root /usr/local/www/nginx;
        index index.php index.html;
        location / {
            try_files $uri $uri/ =404;
        }
        location ~ \.php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }
}


anasayfa.PNG


arama.PNG

DEĞİŞİKLİK özeti kaydet.PNG

yenimobekle.PNG

Ekran Alıntısı.PNG

[CODE lang="php" title="mobproto.php"]<?php
error_reporting(E_ERROR | E_PARSE);

$proto_file = 'mob_proto.txt';
$names_file = 'mob_names.txt';
$limit = 50;
$sayfa = isset($_GET['p']) ? max(1, (int)$_GET['p']) : 1;
$search = isset($_GET['search']) ? trim($_GET['search']) : '';
$offset = ($sayfa - 1) * $limit;

$cols_list = explode("\t", "Vnum Name Rank Type BattleType Level Size AiFlags MountCapacity RaceFlags ImmuneFlags Empire Folder OnClick St Dx Ht Iq MinDamage MaxDamage MaxHp RegenCycle RegenPercent MinGold MaxGold Exp Def AttackSpeed MoveSpeed AggressiveHpPct AggressiveSight AttackRange DropItemGroup ResurrectionVnum EnchantCurse EnchantSlow EnchantPoison EnchantStun EnchantCritical EnchantPenetrate ResistSword ResistTwoHanded ResistDagger ResistBell ResistFan ResistBow ResistFire ResistElect ResistMagic ResistWind ResistPoison DamMultiply SummonVnum DrainSp MobColor PolymorphItem SkillLevel0 SkillVnum0 SkillLevel1 SkillVnum1 SkillLevel2 SkillVnum2 SkillLevel3 SkillVnum3 SkillLevel4 SkillVnum4 SpBerserk SpStoneSkin SpGodSpeed SpDeathBlow SpRevive");

$mob_names = [];
if (file_exists($names_file)) {
foreach (file($names_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
$parts = explode("\t", $line);
if (count($parts) >= 2) $mob_names[trim($parts[0])] = trim($parts[1]);
}
}

// 1. KAYIT İŞLEMİ (GÜNCELLEME)
if (isset($_POST['confirm_bulk_save'])) {
$updates = json_decode($_POST['bulk_data'], true);
if ($updates) {
$full = file($proto_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$header_line = $full[0]; unset($full[0]);
$proto_dict = [];
foreach($full as $line) {
$p = explode("\t", $line);
$proto_dict[trim($p[0])] = $line;
}
foreach ($updates as $vnum => $new_row_array) {
$proto_dict[$vnum] = implode("\t", array_map('trim', $new_row_array));
if(isset($new_row_array[1])) $mob_names[$vnum] = $new_row_array[1];
}
$out = [$header_line];
foreach($proto_dict as $line) $out[] = $line;
file_put_contents($proto_file, implode("\n", $out) . "\n");
$n_out = [];
foreach($mob_names as $nv => $nn) $n_out[] = $nv . "\t" . $nn;
file_put_contents($names_file, implode("\n", $n_out) . "\n");
header("Location: ".$_SERVER['PHP_SELF']."?p=$sayfa&search=".urlencode($search)); exit;
}
}

// 2. YENİ MOB EKLE
if (isset($_POST['tam_ekle'])) {
$yeni_data = $_POST['yeni'];
$yeni_vnum = trim($yeni_data[0]);
if(!empty($yeni_vnum)) {
$proto_lines = file($proto_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$exists = false;
foreach($proto_lines as $l) { if(trim(explode("\t", $l)[0]) == $yeni_vnum) { $exists = true; break; } }
if ($exists) { $error_msg = "HATA: $yeni_vnum mevcut!"; }
else {
$proto_lines[] = implode("\t", array_map('trim', $yeni_data));
file_put_contents($proto_file, implode("\n", $proto_lines) . "\n");
$n_lines = file($names_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$n_lines[] = $yeni_vnum . "\t" . trim($yeni_data[1]);
file_put_contents($names_file, implode("\n", $n_lines) . "\n");
header("Location: ".$_SERVER['PHP_SELF']."?search=".$yeni_vnum); exit;
}
}
}

// 3. MOB SİL
if (isset($_GET['sil'])) {
$target = trim($_GET['sil']);
foreach([$proto_file, $names_file] as $f) {
$lines = file($f, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$new = []; foreach($lines as $l) if(trim(explode("\t", $l)[0]) != $target) $new[] = $l;
file_put_contents($f, implode("\n", $new) . "\n");
}
header("Location: ".$_SERVER['PHP_SELF']."?p=$sayfa&search=$search"); exit;
}

// Verileri Hazırla
$proto_all = file($proto_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$header_row = $proto_all[0];
unset($proto_all[0]);

// --- SON 5 MOB BÖLÜMÜ ---
$last_5_raw = array_slice($proto_all, -5);
$recent_list = [];
foreach(array_reverse($last_5_raw) as $line) {
$p = explode("\t", $line);
$v = trim($p[0]);
$recent_list[] = ['vnum' => $v, 'name' => $mob_names[$v] ?? (isset($p[1]) ? trim($p[1]) : 'NONAME')];
}
// ------------------------

$filtered = [];
foreach ($proto_all as $line) {
$parts = explode("\t", $line); $v = trim($parts[0]);
$n = $mob_names[$v] ?? (isset($parts[1]) ? trim($parts[1]) : 'NONAME');
if ($search === '' || stripos($v, $search) !== false || stripos($n, $search) !== false) {
$clean = [];
for($i=0; $i<count($cols_list); $i++) {
$val = isset($parts[$i]) ? trim($parts[$i]) : "0";
if($i==1) $val = $n;
$clean[] = $val;
}
$filtered[] = $clean;
}
}
$total_pages = max(1, ceil(count($filtered) / $limit));
$current_data = array_slice($filtered, $offset, $limit);
?>
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>MOB PROTO DÜZENLEYİCİ</title>
<style>
:root { --accent: #e74c3c; --bg: #0d1117; --panel:#e74c3c2; --bor#0d11170363d; --ho#161b221262d; --suc#30363d238636; }
#21262dbody { backgr#238636ar(--bg); color: #c9d1d9; font-family: sans-serif#c9d1d9n: 0; overflow: hidden; height: 100vh; }
header { background: #010409; height: 60px; display: #010409lign-items: center; padding: 0 20px; gap: 15px; border-bottom: 2px solid var(--accent); }
.recent-bar { background: #010409; padding: 5px 20px; bord#010409om: 1px solid var(--border); display: flex; gap: 10px; align-items: center; font-size: 11px; overflow-x: auto; white-space: nowrap; }
.recent-item { color: #7ee787; text-decoration: none; #7ee787: 2px 8px; background: var(--panel); border-radius: 4px; border: 1px solid var(--border); }
.recent-item:hover { border-color: var(--accent); }
.viewport { height: calc(100vh - 95px); width: 100%; overflow: auto; }
table { border-collapse: separate; border-spacing: 0; width: max-content; }
th { background: #1c2128; padding: 10px; border-b#1c21281px solid var(--border); border-right: 1px solid var(--border); position: sticky; top: 0; z-index: 100; font-size: 11px; }
tbody tr:hover td { background: var(--hover) !important; }
.sticky-col { position: sticky; background: #0d1117; z-index: 80; }
#0d1117l { left: 0; width: 40px; text-align: center; }
.col-vnum { left: 40px; width: 80px; color: var(--accent); font-weight: bold; border-right: 2px solid var(--accent); }
.col-name { left: 120px; width: 160px; color: #7ee787; border-right: 2px solid#7ee787accent); }
td { border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); }
input.cell { background: transparent; border: 1px solid transparent; color: #fff; padding: 8px; width: 100%;#fffline: none; font-size: 12px; }
input.cell:focus { background: rgba(31, 111, 235, 0.2) !important; border: 1px solid #1f6feb !important; }
in#1f6febnged { background: rgba(35, 134, 54, 0.3) !important; border: 1px solid var(--success) !important; }
.btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; color: white; font-size: 12px; text-decoration: none; display: inline-flex; align-items: center; }
.btn-save { background: #238636; } .btn-add { background#238636-accent); } .btn-nav { background: #30363d; }
.modal { disp#30363dne; position: fixed; inset: 0; background: rgba(0,0,0,0.85); z-index: 9999; padding: 40px; }
.modal-content { background: var(--panel); padding: 25px; border-radius: 8px; max-width: 900px; margin: auto; border: 1px solid var(--accent); max-height: 80vh; overflow-y: auto; }
.diff-row { border-bottom: 1px solid var(--border); padding: 8px; font-family: monospace; font-size: 12px; line-height: 1.5; }
</style>
</head>
<body>

<?php if(isset($error_msg)): ?><script>alert("<?=str_replace('"', '\"', $error_msg)?>");</script><?php endif; ?>

<header>
<a href="<?=$_SERVER['PHP_SELF']?>" class="btn" style="background:none; font-size:16px; padding:0; color:var(--accent); font-weight:bold;">🏠 MOB PROTO</a>
<form method="GET" style="display:flex; align-items:center;">
<input type="text" name="search" style="background: #0d1117; border: 1px solid var(--bo#0d1117color: white; padding: 5px 10px; border-radius: 4px; outline: none;" placeholder="Vnum veya İsim..." value="<?=htmlspecialchars($search)?>">
</form>
<div style="display:flex; gap:5px; font-size:11px;">
<a href="?p=<?=max(1, $sayfa-1)?>&search=<?=$search?>" class="btn btn-nav">«</a>
<span style="margin-top:7px; min-width:40px; text-align:center;"><?=$sayfa?> / <?=$total_pages?></span>
<a href="?p=<?=min($total_pages, $sayfa+1)?>&search=<?=$search?>" class="btn btn-nav">»</a>
</div>
<button onclick="document.getElementById('addModal').style.display='block'" class="btn btn-add">+ YENİ MOB</button>
<button onclick="saveCheck()" class="btn btn-save">DEĞİŞİKLİKLERİ KAYDET</button>
<div style="margin-left:auto; color:var(--accent); font-weight:bold; font-size:12px;">ORHAN BULUT</div>
</header>

<div class="recent-bar">
<b style="color:var(--accent)">SON EKLENENLER:</b>
<?php foreach($recent_list as $rm): ?>
<a href="?search=<?=$rm['vnum']?>" class="recent-item">[<?=$rm['vnum']?>] <?=$rm['name']?></a>
<?php endforeach; ?>
</div>

<div class="viewport">
<table>
<thead>
<tr>
<th class="sticky-col col-sil">SİL</th>
<?php foreach($cols_list as $k => $b): ?>
<th class="<?=($k==0?'sticky-col col-vnum':($k==1?'sticky-col col-name':''))?>"><?=$b?></th>
<?php endforeach; ?>
</tr>
</thead>
<tbody>
<?php foreach ($current_data as $row): $v = $row[0]; $name = $row[1]; ?>
<tr>
<td class="sticky-col col-sil"><a href="?sil=<?=$v?>&p=<?=$sayfa?>&search=<?=$search?>" style="color:var(--accent); text-decoration:none;" onclick="return confirm('<?=$v?> silinecek?')">&times;</a></td>
<?php foreach ($row as $i => $val): $cl = ($i==0?'sticky-col col-vnum':($i==1?'sticky-col col-name':'')); ?>
<td class="<?=$cl?>"><input type="text" class="cell" data-vnum="<?=$v?>" data-name="<?=htmlspecialchars($name)?>" data-orig="<?=htmlspecialchars($val)?>" data-idx="<?=$i?>" value="<?=htmlspecialchars($val)?>" oninput="track(this)"></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>

<div id="saveModal" class="modal">
<div class="modal-content">
<h2 style="color:var(--accent); margin-top:0;">Değişiklik Özeti</h2>
<div id="diffArea" style="background:#000; padding:10px; border-radius:4px; margin-bottom:20px; border:1px solid var(--border);"></div>
<form method="POST">
<input type="hidden" name="bulk_data" id="bulk_data_input">
<button type="submit" name="confirm_bulk_save" class="btn btn-save" style="width:100%; padding:12px;">ONAYLA VE KAYDET</button>
<button type="button" onclick="document.getElementById('saveModal').style.display='none'" class="btn btn-nav" style="width:100%; margin-top:10px;">İPTAL</button>
</form>
</div>
</div>

<div id="addModal" class="modal">
<div class="modal-content" style="max-width:1000px;">
<h2 style="color:var(--accent); margin-top:0;">Yeni Mob Ekle</h2>
<form method="POST">
<div style="display:grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap:10px;">
<?php foreach($cols_list as $i => $name): ?>
<div><label style="font-size:10px; color:#8b949e;"><?=$name?></label><br>
<input type="text" name="yeni[<?=$i?>]" value="<?=$i>1?'0':''?>" style="width:100%; background:#000; color:#fff; border:1px solid var(--border); padding:5px;"></div>
<?php endforeach; ?>
</div>
<button type="submit" name="tam_ekle" class="btn btn-save" style="width:100%; margin-top:20px; padding:12px;">MOB'U EKLE</button>
<button type="button" onclick="document.getElementById('addModal').style.display='none'" class="btn btn-nav" style="width:100%; margin-top:10px;">VAZGEÇ</button>
</form>
</div>
</div>

<script>
const COL_NAMES = <?=json_encode($cols_list)?>;

function track(el) {
if (el.value.trim() !== el.getAttribute('data-orig').trim()) el.classList.add('changed');
else el.classList.remove('changed');
}

function saveCheck() {
let diffs = ""; let updates = {}; let found = false;
document.querySelectorAll('input.cell').forEach(inp => {
let cur = inp.value.trim();
let ori = inp.getAttribute('data-orig').trim();
if (cur !== ori) {
found = true;
let v = inp.getAttribute('data-vnum');
if (!updates[v]) {
updates[v] = [];
document.querySelectorAll(`input.cell[data-vnum="${v}"]`).forEach(i => updates[v][i.getAttribute('data-idx')] = i.value.trim());
}
diffs += `<div class="diff-row"><span style="color:var(--accent)">[${v}]</span> <b>${inp.getAttribute('data-name')}</b> <br> <span style="color:#8b949e">${COL_NAMES[inp.getAttribute('data-idx')]}</span>: <span style="color:#e74c3c">${ori}</span> &rarr; <span style="color:#2ecc71">${cur}</span></div>`;
}
});
if (!found) { alert("Değişiklik yok."); return; }
document.getElementById('diffArea').innerHTML = diffs;
document.getElementById('bulk_data_input').value = JSON.stringify(updates);
document.getElementById('saveModal').style.display = 'block';
}
</script>
</body>
</html>[/CODE]
 
PAYLAŞIM İÇİN TEŞEKKÜRLER ELİNE SAĞLIK .
 
Forum'da paylaşılan kadar görüntü odaklı değil ama gayet işlevsel iş görür nitelik de
local-bsd üzerinde Ngix-PHP8-PHP-FPM Kullanıyorum Farklı yerler de denemedim.
Gerekli oldukça güncellerim.
Kurulum için destek yok.

mob_proto.txt,mob_names.txt ve mobproto.php aynı klasörde olmak zorunda

pkg install -y nginx php82 php82-mysqli php82-mbstring php82-gd php82-curl php82-zlib php82-zip php82-xml php82-fpm php82-filter php82-iconv
sysrc nginx_enable="YES"
sysrc php_fpm_enable="YES"
service php-fpm start
service nginx start
/usr/local/etc/nginx/nginx.conf

Kod:
worker_processes 1;
events { worker_connections 1024; }
http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    server {
        listen 80;
        server_name localhost;
        root /usr/local/www/nginx;
        index index.php index.html;
        location / {
            try_files $uri $uri/ =404;
        }
        location ~ \.php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }
}


Ekli dosyayı görüntüle 165629

Ekli dosyayı görüntüle 165630
Ekli dosyayı görüntüle 165631
Ekli dosyayı görüntüle 165632
Ekli dosyayı görüntüle 165633
[CODE lang="php" title="mobproto.php"]<?php
error_reporting(E_ERROR | E_PARSE);

$proto_file = 'mob_proto.txt';
$names_file = 'mob_names.txt';
$limit = 50;
$sayfa = isset($_GET['p']) ? max(1, (int)$_GET['p']) : 1;
$search = isset($_GET['search']) ? trim($_GET['search']) : '';
$offset = ($sayfa - 1) * $limit;

$cols_list = explode("\t", "Vnum Name Rank Type BattleType Level Size AiFlags MountCapacity RaceFlags ImmuneFlags Empire Folder OnClick St Dx Ht Iq MinDamage MaxDamage MaxHp RegenCycle RegenPercent MinGold MaxGold Exp Def AttackSpeed MoveSpeed AggressiveHpPct AggressiveSight AttackRange DropItemGroup ResurrectionVnum EnchantCurse EnchantSlow EnchantPoison EnchantStun EnchantCritical EnchantPenetrate ResistSword ResistTwoHanded ResistDagger ResistBell ResistFan ResistBow ResistFire ResistElect ResistMagic ResistWind ResistPoison DamMultiply SummonVnum DrainSp MobColor PolymorphItem SkillLevel0 SkillVnum0 SkillLevel1 SkillVnum1 SkillLevel2 SkillVnum2 SkillLevel3 SkillVnum3 SkillLevel4 SkillVnum4 SpBerserk SpStoneSkin SpGodSpeed SpDeathBlow SpRevive");

$mob_names = [];
if (file_exists($names_file)) {
foreach (file($names_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
$parts = explode("\t", $line);
if (count($parts) >= 2) $mob_names[trim($parts[0])] = trim($parts[1]);
}
}

// 1. KAYIT İŞLEMİ (GÜNCELLEME)
if (isset($_POST['confirm_bulk_save'])) {
$updates = json_decode($_POST['bulk_data'], true);
if ($updates) {
$full = file($proto_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$header_line = $full[0]; unset($full[0]);
$proto_dict = [];
foreach($full as $line) {
$p = explode("\t", $line);
$proto_dict[trim($p[0])] = $line;
}
foreach ($updates as $vnum => $new_row_array) {
$proto_dict[$vnum] = implode("\t", array_map('trim', $new_row_array));
if(isset($new_row_array[1])) $mob_names[$vnum] = $new_row_array[1];
}
$out = [$header_line];
foreach($proto_dict as $line) $out[] = $line;
file_put_contents($proto_file, implode("\n", $out) . "\n");
$n_out = [];
foreach($mob_names as $nv => $nn) $n_out[] = $nv . "\t" . $nn;
file_put_contents($names_file, implode("\n", $n_out) . "\n");
header("Location: ".$_SERVER['PHP_SELF']."?p=$sayfa&search=".urlencode($search)); exit;
}
}

// 2. YENİ MOB EKLE
if (isset($_POST['tam_ekle'])) {
$yeni_data = $_POST['yeni'];
$yeni_vnum = trim($yeni_data[0]);
if(!empty($yeni_vnum)) {
$proto_lines = file($proto_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$exists = false;
foreach($proto_lines as $l) { if(trim(explode("\t", $l)[0]) == $yeni_vnum) { $exists = true; break; } }
if ($exists) { $error_msg = "HATA: $yeni_vnum mevcut!"; }
else {
$proto_lines[] = implode("\t", array_map('trim', $yeni_data));
file_put_contents($proto_file, implode("\n", $proto_lines) . "\n");
$n_lines = file($names_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$n_lines[] = $yeni_vnum . "\t" . trim($yeni_data[1]);
file_put_contents($names_file, implode("\n", $n_lines) . "\n");
header("Location: ".$_SERVER['PHP_SELF']."?search=".$yeni_vnum); exit;
}
}
}

// 3. MOB SİL
if (isset($_GET['sil'])) {
$target = trim($_GET['sil']);
foreach([$proto_file, $names_file] as $f) {
$lines = file($f, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$new = []; foreach($lines as $l) if(trim(explode("\t", $l)[0]) != $target) $new[] = $l;
file_put_contents($f, implode("\n", $new) . "\n");
}
header("Location: ".$_SERVER['PHP_SELF']."?p=$sayfa&search=$search"); exit;
}

// Verileri Hazırla
$proto_all = file($proto_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$header_row = $proto_all[0];
unset($proto_all[0]);

// --- SON 5 MOB BÖLÜMÜ ---
$last_5_raw = array_slice($proto_all, -5);
$recent_list = [];
foreach(array_reverse($last_5_raw) as $line) {
$p = explode("\t", $line);
$v = trim($p[0]);
$recent_list[] = ['vnum' => $v, 'name' => $mob_names[$v] ?? (isset($p[1]) ? trim($p[1]) : 'NONAME')];
}
// ------------------------

$filtered = [];
foreach ($proto_all as $line) {
$parts = explode("\t", $line); $v = trim($parts[0]);
$n = $mob_names[$v] ?? (isset($parts[1]) ? trim($parts[1]) : 'NONAME');
if ($search === '' || stripos($v, $search) !== false || stripos($n, $search) !== false) {
$clean = [];
for($i=0; $i<count($cols_list); $i++) {
$val = isset($parts[$i]) ? trim($parts[$i]) : "0";
if($i==1) $val = $n;
$clean[] = $val;
}
$filtered[] = $clean;
}
}
$total_pages = max(1, ceil(count($filtered) / $limit));
$current_data = array_slice($filtered, $offset, $limit);
?>
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>MOB PROTO DÜZENLEYİCİ</title>
<style>
:root { --accent: #e74c3c; --bg: #0d1117; --panel:#e74c3c2; --bor#0d11170363d; --ho#161b221262d; --suc#30363d238636; }
#21262dbody { backgr#238636ar(--bg); color: #c9d1d9; font-family: sans-serif#c9d1d9n: 0; overflow: hidden; height: 100vh; }
header { background: #010409; height: 60px; display: #010409lign-items: center; padding: 0 20px; gap: 15px; border-bottom: 2px solid var(--accent); }
.recent-bar { background: #010409; padding: 5px 20px; bord#010409om: 1px solid var(--border); display: flex; gap: 10px; align-items: center; font-size: 11px; overflow-x: auto; white-space: nowrap; }
.recent-item { color: #7ee787; text-decoration: none; #7ee787: 2px 8px; background: var(--panel); border-radius: 4px; border: 1px solid var(--border); }
.recent-item:hover { border-color: var(--accent); }
.viewport { height: calc(100vh - 95px); width: 100%; overflow: auto; }
table { border-collapse: separate; border-spacing: 0; width: max-content; }
th { background: #1c2128; padding: 10px; border-b#1c21281px solid var(--border); border-right: 1px solid var(--border); position: sticky; top: 0; z-index: 100; font-size: 11px; }
tbody tr:hover td { background: var(--hover) !important; }
.sticky-col { position: sticky; background: #0d1117; z-index: 80; }
#0d1117l { left: 0; width: 40px; text-align: center; }
.col-vnum { left: 40px; width: 80px; color: var(--accent); font-weight: bold; border-right: 2px solid var(--accent); }
.col-name { left: 120px; width: 160px; color: #7ee787; border-right: 2px solid#7ee787accent); }
td { border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); }
input.cell { background: transparent; border: 1px solid transparent; color: #fff; padding: 8px; width: 100%;#fffline: none; font-size: 12px; }
input.cell:focus { background: rgba(31, 111, 235, 0.2) !important; border: 1px solid #1f6feb !important; }
in#1f6febnged { background: rgba(35, 134, 54, 0.3) !important; border: 1px solid var(--success) !important; }
.btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; color: white; font-size: 12px; text-decoration: none; display: inline-flex; align-items: center; }
.btn-save { background: #238636; } .btn-add { background#238636-accent); } .btn-nav { background: #30363d; }
.modal { disp#30363dne; position: fixed; inset: 0; background: rgba(0,0,0,0.85); z-index: 9999; padding: 40px; }
.modal-content { background: var(--panel); padding: 25px; border-radius: 8px; max-width: 900px; margin: auto; border: 1px solid var(--accent); max-height: 80vh; overflow-y: auto; }
.diff-row { border-bottom: 1px solid var(--border); padding: 8px; font-family: monospace; font-size: 12px; line-height: 1.5; }
</style>
</head>
<body>

<?php if(isset($error_msg)): ?><script>alert("<?=str_replace('"', '\"', $error_msg)?>");</script><?php endif; ?>

<header>
<a href="<?=$_SERVER['PHP_SELF']?>" class="btn" style="background:none; font-size:16px; padding:0; color:var(--accent); font-weight:bold;">🏠 MOB PROTO</a>
<form method="GET" style="display:flex; align-items:center;">
<input type="text" name="search" style="background: #0d1117; border: 1px solid var(--bo#0d1117color: white; padding: 5px 10px; border-radius: 4px; outline: none;" placeholder="Vnum veya İsim..." value="<?=htmlspecialchars($search)?>">
</form>
<div style="display:flex; gap:5px; font-size:11px;">
<a href="?p=<?=max(1, $sayfa-1)?>&search=<?=$search?>" class="btn btn-nav">«</a>
<span style="margin-top:7px; min-width:40px; text-align:center;"><?=$sayfa?> / <?=$total_pages?></span>
<a href="?p=<?=min($total_pages, $sayfa+1)?>&search=<?=$search?>" class="btn btn-nav">»</a>
</div>
<button onclick="document.getElementById('addModal').style.display='block'" class="btn btn-add">+ YENİ MOB</button>
<button onclick="saveCheck()" class="btn btn-save">DEĞİŞİKLİKLERİ KAYDET</button>
<div style="margin-left:auto; color:var(--accent); font-weight:bold; font-size:12px;">ORHAN BULUT</div>
</header>

<div class="recent-bar">
<b style="color:var(--accent)">SON EKLENENLER:</b>
<?php foreach($recent_list as $rm): ?>
<a href="?search=<?=$rm['vnum']?>" class="recent-item">[<?=$rm['vnum']?>] <?=$rm['name']?></a>
<?php endforeach; ?>
</div>

<div class="viewport">
<table>
<thead>
<tr>
<th class="sticky-col col-sil">SİL</th>
<?php foreach($cols_list as $k => $b): ?>
<th class="<?=($k==0?'sticky-col col-vnum':($k==1?'sticky-col col-name':''))?>"><?=$b?></th>
<?php endforeach; ?>
</tr>
</thead>
<tbody>
<?php foreach ($current_data as $row): $v = $row[0]; $name = $row[1]; ?>
<tr>
<td class="sticky-col col-sil"><a href="?sil=<?=$v?>&p=<?=$sayfa?>&search=<?=$search?>" style="color:var(--accent); text-decoration:none;" onclick="return confirm('<?=$v?> silinecek?')">&times;</a></td>
<?php foreach ($row as $i => $val): $cl = ($i==0?'sticky-col col-vnum':($i==1?'sticky-col col-name':'')); ?>
<td class="<?=$cl?>"><input type="text" class="cell" data-vnum="<?=$v?>" data-name="<?=htmlspecialchars($name)?>" data-orig="<?=htmlspecialchars($val)?>" data-idx="<?=$i?>" value="<?=htmlspecialchars($val)?>" oninput="track(this)"></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>

<div id="saveModal" class="modal">
<div class="modal-content">
<h2 style="color:var(--accent); margin-top:0;">Değişiklik Özeti</h2>
<div id="diffArea" style="background:#000; padding:10px; border-radius:4px; margin-bottom:20px; border:1px solid var(--border);"></div>
<form method="POST">
<input type="hidden" name="bulk_data" id="bulk_data_input">
<button type="submit" name="confirm_bulk_save" class="btn btn-save" style="width:100%; padding:12px;">ONAYLA VE KAYDET</button>
<button type="button" onclick="document.getElementById('saveModal').style.display='none'" class="btn btn-nav" style="width:100%; margin-top:10px;">İPTAL</button>
</form>
</div>
</div>

<div id="addModal" class="modal">
<div class="modal-content" style="max-width:1000px;">
<h2 style="color:var(--accent); margin-top:0;">Yeni Mob Ekle</h2>
<form method="POST">
<div style="display:grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap:10px;">
<?php foreach($cols_list as $i => $name): ?>
<div><label style="font-size:10px; color:#8b949e;"><?=$name?></label><br>
<input type="text" name="yeni[<?=$i?>]" value="<?=$i>1?'0':''?>" style="width:100%; background:#000; color:#fff; border:1px solid var(--border); padding:5px;"></div>
<?php endforeach; ?>
</div>
<button type="submit" name="tam_ekle" class="btn btn-save" style="width:100%; margin-top:20px; padding:12px;">MOB'U EKLE</button>
<button type="button" onclick="document.getElementById('addModal').style.display='none'" class="btn btn-nav" style="width:100%; margin-top:10px;">VAZGEÇ</button>
</form>
</div>
</div>

<script>
const COL_NAMES = <?=json_encode($cols_list)?>;

function track(el) {
if (el.value.trim() !== el.getAttribute('data-orig').trim()) el.classList.add('changed');
else el.classList.remove('changed');
}

function saveCheck() {
let diffs = ""; let updates = {}; let found = false;
document.querySelectorAll('input.cell').forEach(inp => {
let cur = inp.value.trim();
let ori = inp.getAttribute('data-orig').trim();
if (cur !== ori) {
found = true;
let v = inp.getAttribute('data-vnum');
if (!updates[v]) {
updates[v] = [];
document.querySelectorAll(`input.cell[data-vnum="${v}"]`).forEach(i => updates[v][i.getAttribute('data-idx')] = i.value.trim());
}
diffs += `<div class="diff-row"><span style="color:var(--accent)">[${v}]</span> <b>${inp.getAttribute('data-name')}</b> <br> <span style="color:#8b949e">${COL_NAMES[inp.getAttribute('data-idx')]}</span>: <span style="color:#e74c3c">${ori}</span> &rarr; <span style="color:#2ecc71">${cur}</span></div>`;
}
});
if (!found) { alert("Değişiklik yok."); return; }
document.getElementById('diffArea').innerHTML = diffs;
document.getElementById('bulk_data_input').value = JSON.stringify(updates);
document.getElementById('saveModal').style.display = 'block';
}
</script>
</body>
</html>[/CODE]
Paylaşım için teşekkürler, emeğine sağlık.
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst