minimap.php

main 204 lines · 6.2 KB Raw
Alex Alex Commit Initial commit 01/10/2026 09:20
1<?php
2/**
3 * Title: Minimap
4 * Icon: fa-map-o
5 * Group: Server Info
6 * Order: 20
7 * Description: Import an OTClient .otmm minimap and show it on Server Information.
8 */
9
10if (!defined('ACP_ROOT')) {
11 http_response_code(403);
12 die('Direct access denied.');
13}
14
15if ($_SERVER['REQUEST_METHOD'] === 'POST') {
16
17 $do = (string)($_POST['do'] ?? '');
18
19 if ($do === 'delete') {
20 minimap_delete();
21 acp_log('minimap.remove');
22 acp_flash_success(t('acp.map.removed'));
23 acp_redirect('minimap');
24 }
25
26 if ($do === 'upload') {
27 $file = $_FILES['otmm'] ?? null;
28
29 if (!is_array($file) || ($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
30 acp_flash_error(t('acp.map.select_file'));
31 acp_redirect('minimap');
32 }
33
34 if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
35 $reasons = [
36 UPLOAD_ERR_INI_SIZE => t('acp.map.err_ini_size'),
37 UPLOAD_ERR_FORM_SIZE => t('acp.map.err_form_size'),
38 UPLOAD_ERR_PARTIAL => t('acp.map.err_partial'),
39 UPLOAD_ERR_NO_TMP_DIR => t('acp.map.err_no_tmp_dir'),
40 UPLOAD_ERR_CANT_WRITE => t('acp.map.err_cant_write'),
41 UPLOAD_ERR_EXTENSION => t('acp.map.err_extension'),
42 ];
43 acp_flash_error($reasons[(int)$file['error']] ?? t('acp.map.upload_failed'));
44 acp_redirect('minimap');
45 }
46
47 if (!is_uploaded_file((string)$file['tmp_name'])) {
48 acp_flash_error(t('acp.map.unverified'));
49 acp_redirect('minimap');
50 }
51
52 $error = null;
53 if (minimap_import((string)$file['tmp_name'], (string)$file['name'], $error)) {
54 $fresh = json_decode((string)file_get_contents(minimap_meta_path()), true);
55 acp_log('minimap.import', (string)$file['name'], [
56 'tiles' => (int)($fresh['tiles'] ?? 0),
57 'floors' => count((array)($fresh['floors'] ?? [])),
58 ]);
59 acp_flash_success(t('acp.map.imported', [
60 'tiles' => number_format((int)($fresh['tiles'] ?? 0)),
61 'floors' => number_format(count((array)($fresh['floors'] ?? []))),
62 ]));
63 } else {
64 acp_flash_error((string)$error);
65 }
66
67 acp_redirect('minimap');
68 }
69}
70
71$minimap = minimap_data();
72$root = minimap_root();
73
74$diskBytes = 0;
75foreach (glob($root . '/*.png') ?: [] as $tile) {
76 $diskBytes += (int)filesize($tile);
77}
78
79$writable = is_dir($root) ? is_writable($root) : is_writable(dirname($root));
80$maxUpload = min(
81 (int)serverdata_ini_bytes((string)ini_get('upload_max_filesize')),
82 (int)serverdata_ini_bytes((string)ini_get('post_max_size'))
83);
84?>
85
86<div class="acp-toolbar">
87 <div>
88 <?php if ($minimap !== false): ?>
89 <span class="acp-pill acp-pill--green"><?= t('acp.map.active_pill') ?></span>
90 <?php else: ?>
91 <span class="acp-pill acp-pill--grey"><?= t('acp.map.none_pill') ?></span>
92 <?php endif; ?>
93 </div>
94 <div class="acp-actions is-tight">
95 <a class="acp-btn acp-btn--ghost acp-btn--sm" href="<?= h(acp_site('serverinfo.php')) ?>" target="_blank">
96 <i class="fa fa-external-link"></i> <?= t('acp.map.view_serverinfo') ?>
97 </a>
98 </div>
99</div>
100
101<div class="acp-grid acp-grid--2">
102
103 <section class="acp-card">
104 <header class="acp-card-head">
105 <h2><?= t('acp.map.import_title') ?></h2>
106 <p><?= t('acp.map.import_sub', ['folder' => '<code>minimap</code>']) ?></p>
107 </header>
108 <div class="acp-card-body">
109
110 <?php if (!$writable): ?>
111 <div class="acp-flash acp-flash--error">
112 <i class="fa fa-exclamation-triangle"></i>
113 <span><?= t('acp.map.not_writable', ['folder' => '<code>' . h(ZNOTE_MINIMAP_DIR) . '</code>']) ?></span>
114 </div>
115 <?php endif; ?>
116
117 <?php if (!extension_loaded('gd') || !extension_loaded('zlib')): ?>
118 <div class="acp-flash acp-flash--error">
119 <i class="fa fa-exclamation-triangle"></i>
120 <span><?= t('acp.map.missing_ext', ['gd' => '<code>gd</code>', 'zlib' => '<code>zlib</code>']) ?></span>
121 </div>
122 <?php endif; ?>
123
124 <form method="post" enctype="multipart/form-data">
125 <?= acp_csrf_field() ?>
126 <input type="hidden" name="do" value="upload">
127
128 <div class="acp-field">
129 <label class="acp-label" for="otmm"><?= t('acp.map.file_label') ?></label>
130 <input class="acp-input" type="file" id="otmm" name="otmm" accept=".otmm" required>
131 </div>
132
133 <div class="acp-actions">
134 <button class="acp-btn acp-btn--green" type="submit" <?= $writable ? '' : 'disabled' ?>>
135 <i class="fa fa-upload"></i> <?= t('acp.map.import_btn') ?>
136 </button>
137 <?php if ($minimap !== false): ?>
138 <button class="acp-btn acp-btn--red" type="submit" form="minimapDelete">
139 <i class="fa fa-trash"></i> <?= t('acp.map.remove_btn') ?>
140 </button>
141 <?php endif; ?>
142 </div>
143 </form>
144
145 <?php if ($minimap !== false): ?>
146 <form method="post" id="minimapDelete" onsubmit="return confirm('<?= h(t('acp.map.confirm_remove')) ?>');">
147 <?= acp_csrf_field() ?>
148 <input type="hidden" name="do" value="delete">
149 </form>
150 <?php endif; ?>
151
152 <p class="acp-hint">
153 <?= t('acp.map.upload_hint', [
154 'folder' => '<code>' . h(ZNOTE_MINIMAP_DIR) . '</code>',
155 'max' => (int)(ZNOTE_MINIMAP_MAX_BYTES / 1048576),
156 'accepts' => h(serverdata_human_size($maxUpload)),
157 ]) ?>
158 </p>
159 </div>
160 </section>
161
162 <section class="acp-card">
163 <header class="acp-card-head">
164 <h2><?= t('acp.map.status_title') ?></h2>
165 <p><?= t('acp.map.status_sub') ?></p>
166 </header>
167 <div class="acp-card-body is-flush">
168 <?php if ($minimap === false): ?>
169 <div class="acp-card-body">
170 <?php acp_empty(t('acp.map.none_body'), 'fa-map-o'); ?>
171 </div>
172 <?php else: ?>
173 <div class="acp-table-wrap">
174 <table class="acp-table">
175 <tbody>
176 <tr>
177 <td><?= t('acp.map.col_source') ?></td>
178 <td><code><?= h((string)($minimap['source'] ?? 'minimap.otmm')) ?></code></td>
179 </tr>
180 <tr>
181 <td><?= t('acp.map.col_imported') ?></td>
182 <td><?= h(date('Y-m-d H:i', (int)($minimap['date'] ?? 0))) ?></td>
183 </tr>
184 <tr>
185 <td><?= t('acp.map.col_floors') ?></td>
186 <td><?= h(implode(', ', array_map('intval', array_keys((array)$minimap['floors'])))) ?></td>
187 </tr>
188 <tr>
189 <td><?= t('acp.map.col_tiles') ?></td>
190 <td><?= number_format((int)($minimap['tiles'] ?? 0)) ?></td>
191 </tr>
192 <tr>
193 <td><?= t('acp.map.col_disk') ?></td>
194 <td><?= h(serverdata_human_size($diskBytes)) ?></td>
195 </tr>
196 </tbody>
197 </table>
198 </div>
199 <?php endif; ?>
200 </div>
201 </section>
202
203</div>
204
Top