-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit.lua
More file actions
233 lines (190 loc) · 8.31 KB
/
Copy pathinit.lua
File metadata and controls
233 lines (190 loc) · 8.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
-- mods/atlas_viewer/init.lua
local player_states = {}
-- 1. 設定からフォントグリッド情報を読み込み、総ピクセルサイズを計算する関数
local function load_setting_config()
local pattern = core.settings:get("atlas_viewer_name_pattern") or "atlas_mcl_p%02X.png"
local raw_bg = core.settings:get("atlas_viewer_bg_color") or "#7F7F7F"
-- settingtypes.txt の定義と完全に一致する形で数値を取得
local char_w = tonumber(core.settings:get("atlas_viewer_char_width")) or 12
local char_h = tonumber(core.settings:get("atlas_viewer_char_height")) or 12
local grid_cols = tonumber(core.settings:get("atlas_viewer_columns")) or 16
local grid_rows = tonumber(core.settings:get("atlas_viewer_rows")) or 16
-- 数学的に正しいアトラス画像の総ピクセルサイズを算出
local img_w = char_w * grid_cols
local img_h = char_h * grid_rows
return {
file_pattern = pattern,
bg_color = raw_bg,
original_w = img_w,
original_h = img_h
}
end
local mod_config = load_setting_config()
-- 1枚のアトラス画像をテーブルに閉じ込めて安全に埋め込むHTML生成関数
local function generate_hypertext_atlas(page, zoom_level, bg_color)
local img_name = string.format(mod_config.file_pattern, page)
-- 算出された元の解像度に対して、ズーム倍率を正確に乗算
local disp_w = mod_config.original_w * zoom_level
local disp_h = mod_config.original_h * zoom_level
local html = string.format("<global background=%s margin=0>", bg_color) ..
string.format("<table columns=1 width=%d>", disp_w) ..
"<tr>" ..
string.format("<td><img name=%s width=%d height=%d></td>", img_name, disp_w, disp_h) ..
"</tr>" ..
"</table>"
return html
end
-- 2. メイン描画関数
local function show_viewer(player_name)
-- 設定の変更を即時反映させるため、開くタイミングで再取得
mod_config = load_setting_config()
local state = player_states[player_name]
if not state then
state = {
zoom_level = 1,
bg = mod_config.bg_color,
page = 0,
scroll_x = 0,
scroll_y = 0
}
player_states[player_name] = state
end
-- 40ピクセル=1.0マスとする、人間用の直感ピクセル変換ヘルパー
local scale = 1.0
local function px(pixel)
return (pixel / 40) * scale
end
-- 横400px・縦440pxのサイズ
local fs_size = string.format("size[%f,%f];", px(400), px(440))
local formspec = "formspec_version[5]" .. fs_size .. "real_coordinates[true]" .. "bgcolor[#00000000;true]"
-- 拡大時の画像サイズを計算
local content_w = mod_config.original_w * state.zoom_level
local content_h = mod_config.original_h * state.zoom_level
-- 覗き窓の固定サイズ(320px × 320px)
local view_w = 320
local view_h = 320
-- 📦 【インフラ核心】:縦コンテナの中に横コンテナを仕込む、鉄壁の2重ネストハック!
-- 1つ目:縦方向スクロールコンテナ(第5引数に vertical を明示)
formspec = formspec .. string.format("scroll_container[%f,%f;%f,%f;scroll_v;vertical]",
px(20), px(20), px(view_w), px(view_h))
-- 2つ目:横方向スクロールコンテナ(第5引数に horizontal を明示)
formspec = formspec .. string.format("scroll_container[0,0;%f,%f;scroll_h;horizontal]",
px(view_w), px(view_h))
-- 1. メイン表示エリア (テーブルでラップしたHTML)
local atlas_html = generate_hypertext_atlas(state.page, state.zoom_level, state.bg)
formspec = formspec .. string.format("hypertext[0,0;%f,%f;atlas_box;%s]",
px(content_w), px(content_h), atlas_html)
-- 2つのコンテナを順番に閉じる
formspec = formspec .. "scroll_container_end[]"
formspec = formspec .. "scroll_container_end[]"
-- 🎛️ 【仕様5準拠スクロールバー】:引数をジャスト5個「scrollbar[X,Y;W,H;方向;名前;初期位置]」に統一固定!
-- これにより、C++層の Invalid エラーが永久に消滅します。位置は窓の右端と下端をキープ。
formspec = formspec .. string.format("scrollbar[%f,%f;%f,%f;vertical;scroll_v;%d]",
px(344), px(20), px(16), px(view_h), state.scroll_y)
formspec = formspec .. string.format("scrollbar[%f,%f;%f,%f;horizontal;scroll_h;%d]",
px(20), px(344), px(view_w), px(16), state.scroll_x)
-- 2. パネル背景 (固定色、下部コントロールエリア用)
local panel_bg = "#222222"
formspec = formspec .. string.format("box[%f,%f;%f,%f;%s]", px(0), px(360), px(400), px(80), panel_bg)
-- 3. UIパーツ (Y=360px以下のコントロールエリア)
formspec = formspec .. string.format("label[%f,%f;Page: %02X]", px(20), px(384), state.page)
-- Prev移動系
formspec = formspec .. string.format("button[%f,%f;%f,%f;btn_prev16;-16]", px(80), px(372), px(32), px(24))
formspec = formspec .. string.format("button[%f,%f;%f,%f;btn_prev1;-1]", px(116), px(372), px(32), px(24))
-- リセット
formspec = formspec .. string.format("button[%f,%f;%f,%f;btn_reset;0]", px(152), px(372), px(32), px(24))
-- Next移動系
formspec = formspec .. string.format("button[%f,%f;%f,%f;btn_next1;+1]", px(188), px(372), px(32), px(24))
formspec = formspec .. string.format("button[%f,%f;%f,%f;btn_next16;+16]", px(224), px(372), px(32), px(24))
-- ズームボタン
local zoom_label = (state.zoom_level == 2) and "View100%" or "View200%"
formspec = formspec .. string.format("button[%f,%f;%f,%f;btn_zoom;%s]", px(280), px(372), px(80), px(24), zoom_label)
-- 下段:カラー入力エリア
formspec = formspec .. string.format("label[%f,%f;BG Color:]", px(20), px(416))
formspec = formspec .. string.format("field[%f,%f;%f,%f;txt_bg;;%s]", px(80), px(404), px(80), px(24), state.bg)
formspec = formspec .. string.format("button[%f,%f;%f,%f;btn_set_bg;Apply]", px(164), px(404), px(48), px(24))
formspec = formspec .. string.format("button_exit[%f,%f;%f,%f;quit;Close]", px(300), px(404), px(80), px(24))
core.show_formspec(player_name, "atlas_viewer:main", formspec)
end
-- 3. イベント処理
core.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "atlas_viewer:main" then return end
if fields.quit == "true" then
return
end
local name = player:get_player_name()
local state = player_states[name]
if not state then return end
local refresh = false
-- 💡 【新設】スクロールバーのドラッグ位置イベントの完全パース連動
if fields.scroll_v then
local evt = core.explode_scrollbar_event(fields.scroll_v)
if evt.type == "CHG" then
state.scroll_y = evt.value
refresh = true
end
end
if fields.scroll_h then
local evt = core.explode_scrollbar_event(fields.scroll_h)
if evt.type == "CHG" then
state.scroll_x = evt.value
refresh = true
end
end
-- 入力値の保持
if fields.txt_bg then
state.bg = fields.txt_bg
end
-- ページ操作ロジック
if fields.btn_next16 then
state.page = math.min(255, state.page + 16)
refresh = true
elseif fields.btn_next1 then
state.page = math.min(255, state.page + 1)
refresh = true
elseif fields.btn_prev16 then
state.page = math.max(0, state.page - 16)
refresh = true
elseif fields.btn_prev1 then
state.page = math.max(0, state.page - 1)
refresh = true
elseif fields.btn_reset then
state.page = 0
-- 💡 ページを初期化する際は、スクロール位置も安全に左上にリセット
state.scroll_x = 0
state.scroll_y = 0
refresh = true
-- ズームボタン
-- 💡 100%等倍に戻す際は、はみ出しが無くなるためスクロール位置もゼロクリア
elseif fields.btn_zoom then
state.zoom_level = (state.zoom_level == 1) and 2 or 1
state.scroll_x = 0
state.scroll_y = 0
refresh = true
-- 背景適用
elseif fields.btn_set_bg or fields.key_enter == "true" then
refresh = true
end
if refresh and fields.quit ~= "true" then
show_viewer(name)
end
end)
-- 4. チャットコマンドで起動
core.register_chatcommand("aview", {
params = "",
description = "Open Atlas Viewer",
func = function(name, param)
show_viewer(name)
return true
end,
})
-- 5. アイテム登録
core.register_craftitem("atlas_viewer:viewer", {
description = "Atlas Image Viewer",
inventory_image = "atlas_view.png",
stack_max = 1,
on_use = function(itemstack, user)
if user then show_viewer(user:get_player_name()) end
return itemstack
end,
})