feat: 2.3.2
This commit is contained in:
@@ -6,43 +6,43 @@ extends Control
|
||||
## Open scenes/tools/skin_catalog_editor.tscn in the editor, then press F6 (Run Current Scene).
|
||||
## Edit skins in the form, then click "💾 Save & Generate" to rewrite:
|
||||
## • scripts/managers/skin_manager.gd (SKIN_CATALOG block)
|
||||
## • server/nakama/tekton_admin.js (SHOP_CATALOG_DEFS block)
|
||||
## • server/nakama/economy.js (SHOP_CATALOG_DEFS block)
|
||||
|
||||
const DATA_PATH := "res://assets/data/skin_catalog_data.json"
|
||||
const DATA_PATH := "res://assets/data/skin_catalog_data.json"
|
||||
const SKIN_MANAGER_PATH := "res://scripts/managers/skin_manager.gd"
|
||||
const ADMIN_JS_PATH := "res://server/nakama/tekton_admin.js"
|
||||
const ADMIN_JS_PATH := "res://server/nakama/economy.js"
|
||||
|
||||
const CATEGORIES := ["head", "costume", "glove", "accessory"]
|
||||
const RARITIES := ["Common", "Rare", "Epic", "Legendary"]
|
||||
const MODES := ["override", "overlay"]
|
||||
const RARITIES := ["Common", "Rare", "Epic", "Legendary"]
|
||||
const MODES := ["override", "overlay"]
|
||||
|
||||
# Sentinel markers — must match what's in the target files
|
||||
const BEGIN_SKIN := "## [BEGIN_SKIN_CATALOG]"
|
||||
const END_SKIN := "## [END_SKIN_CATALOG]"
|
||||
const END_SKIN := "## [END_SKIN_CATALOG]"
|
||||
const BEGIN_SHOP := "// [BEGIN_SHOP_CATALOG_DEFS]"
|
||||
const END_SHOP := "// [END_SHOP_CATALOG_DEFS]"
|
||||
const END_SHOP := "// [END_SHOP_CATALOG_DEFS]"
|
||||
|
||||
# ─── State ───────────────────────────────────────────────────────────────────
|
||||
var _data: Array = []
|
||||
var _selected_idx: int = -1
|
||||
var _dirty: bool = false
|
||||
var _data: Array = []
|
||||
var _selected_idx: int = -1
|
||||
var _dirty: bool = false
|
||||
|
||||
# ─── UI refs (built in code) ─────────────────────────────────────────────────
|
||||
var _skin_list_vbox: VBoxContainer
|
||||
var _status_label: Label
|
||||
var _form_panel: PanelContainer
|
||||
var _no_sel_label: Label
|
||||
var _form_item_id: LineEdit
|
||||
var _form_name: LineEdit
|
||||
var _form_character: LineEdit
|
||||
var _form_gold: SpinBox
|
||||
var _form_star: SpinBox
|
||||
var _form_category: OptionButton
|
||||
var _form_rarity: OptionButton
|
||||
var _slots_vbox: VBoxContainer
|
||||
var _duplicate_btn: Button
|
||||
var _delete_btn: Button
|
||||
var _save_btn: Button
|
||||
var _skin_list_vbox: VBoxContainer
|
||||
var _status_label: Label
|
||||
var _form_panel: PanelContainer
|
||||
var _no_sel_label: Label
|
||||
var _form_item_id: LineEdit
|
||||
var _form_name: LineEdit
|
||||
var _form_character: LineEdit
|
||||
var _form_gold: SpinBox
|
||||
var _form_star: SpinBox
|
||||
var _form_category: OptionButton
|
||||
var _form_rarity: OptionButton
|
||||
var _slots_vbox: VBoxContainer
|
||||
var _duplicate_btn: Button
|
||||
var _delete_btn: Button
|
||||
var _save_btn: Button
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
func _ready() -> void:
|
||||
@@ -54,7 +54,7 @@ func _ready() -> void:
|
||||
# UI Construction
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
func _build_ui() -> void:
|
||||
anchor_right = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
# Root VBox
|
||||
@@ -137,13 +137,13 @@ func _build_ui() -> void:
|
||||
|
||||
# Form fields
|
||||
form_vbox.add_child(_section_label("── Item Info ───────────────────────────"))
|
||||
_form_item_id = _field(form_vbox, "Item ID", "e.g. oldpop_hat1")
|
||||
_form_name = _field(form_vbox, "Display Name", "e.g. Oldpop Hat I")
|
||||
_form_character = _field(form_vbox, "Character (node)", "e.g. Oldpop, Masbro, Bob")
|
||||
_form_gold = _spinbox(form_vbox, "Gold Price", 0, 99999)
|
||||
_form_star = _spinbox(form_vbox, "Star Price", 0, 99999)
|
||||
_form_category = _option(form_vbox, "Category", CATEGORIES)
|
||||
_form_rarity = _option(form_vbox, "Rarity", RARITIES)
|
||||
_form_item_id = _field(form_vbox, "Item ID", "e.g. oldpop_hat1")
|
||||
_form_name = _field(form_vbox, "Display Name", "e.g. Oldpop Hat I")
|
||||
_form_character = _field(form_vbox, "Character (node)", "e.g. Oldpop, Masbro, Bob")
|
||||
_form_gold = _spinbox(form_vbox, "Gold Price", 0, 99999)
|
||||
_form_star = _spinbox(form_vbox, "Star Price", 0, 99999)
|
||||
_form_category = _option(form_vbox, "Category", CATEGORIES)
|
||||
_form_rarity = _option(form_vbox, "Rarity", RARITIES)
|
||||
|
||||
# ── Slots section ─────────────────────────────────────────────────────────
|
||||
var slots_hdr := HBoxContainer.new()
|
||||
@@ -280,23 +280,23 @@ func _on_list_item_pressed(idx: int) -> void:
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
func _populate_form() -> void:
|
||||
if _selected_idx < 0 or _selected_idx >= _data.size():
|
||||
_form_panel.visible = false
|
||||
_form_panel.visible = false
|
||||
_no_sel_label.visible = true
|
||||
_duplicate_btn.disabled = true
|
||||
_delete_btn.disabled = true
|
||||
_delete_btn.disabled = true
|
||||
return
|
||||
|
||||
_form_panel.visible = true
|
||||
_form_panel.visible = true
|
||||
_no_sel_label.visible = false
|
||||
_duplicate_btn.disabled = false
|
||||
_delete_btn.disabled = false
|
||||
_delete_btn.disabled = false
|
||||
|
||||
var e: Dictionary = _data[_selected_idx]
|
||||
_form_item_id.text = e.get("item_id", "")
|
||||
_form_name.text = e.get("name", "")
|
||||
_form_character.text = e.get("character", "")
|
||||
_form_gold.value = e.get("gold", 0)
|
||||
_form_star.value = e.get("star", 0)
|
||||
_form_item_id.text = e.get("item_id", "")
|
||||
_form_name.text = e.get("name", "")
|
||||
_form_character.text = e.get("character", "")
|
||||
_form_gold.value = e.get("gold", 0)
|
||||
_form_star.value = e.get("star", 0)
|
||||
|
||||
var cat_idx := CATEGORIES.find(e.get("category", "head"))
|
||||
_form_category.selected = max(0, cat_idx)
|
||||
@@ -355,13 +355,13 @@ func _commit_form() -> void:
|
||||
if _selected_idx < 0 or _selected_idx >= _data.size():
|
||||
return
|
||||
var e: Dictionary = _data[_selected_idx]
|
||||
e["item_id"] = _form_item_id.text.strip_edges()
|
||||
e["name"] = _form_name.text.strip_edges()
|
||||
e["item_id"] = _form_item_id.text.strip_edges()
|
||||
e["name"] = _form_name.text.strip_edges()
|
||||
e["character"] = _form_character.text.strip_edges()
|
||||
e["gold"] = int(_form_gold.value)
|
||||
e["star"] = int(_form_star.value)
|
||||
e["category"] = CATEGORIES[_form_category.selected]
|
||||
e["rarity"] = RARITIES[_form_rarity.selected]
|
||||
e["gold"] = int(_form_gold.value)
|
||||
e["star"] = int(_form_star.value)
|
||||
e["category"] = CATEGORIES[_form_category.selected]
|
||||
e["rarity"] = RARITIES[_form_rarity.selected]
|
||||
# Read slots
|
||||
var slots: Array = []
|
||||
for row in _slots_vbox.get_children():
|
||||
@@ -371,8 +371,8 @@ func _commit_form() -> void:
|
||||
if ch.size() < 3:
|
||||
continue
|
||||
slots.append({
|
||||
"mesh": (ch[0] as LineEdit).text.strip_edges(),
|
||||
"mode": MODES[(ch[1] as OptionButton).selected],
|
||||
"mesh": (ch[0] as LineEdit).text.strip_edges(),
|
||||
"mode": MODES[(ch[1] as OptionButton).selected],
|
||||
"material": (ch[2] as LineEdit).text.strip_edges(),
|
||||
})
|
||||
e["slots"] = slots
|
||||
@@ -384,14 +384,14 @@ func _on_add_pressed() -> void:
|
||||
if _selected_idx >= 0:
|
||||
_commit_form()
|
||||
_data.append({
|
||||
"item_id": "new_skin_%d" % _data.size(),
|
||||
"name": "New Skin",
|
||||
"category": "head",
|
||||
"item_id": "new_skin_%d" % _data.size(),
|
||||
"name": "New Skin",
|
||||
"category": "head",
|
||||
"character": "",
|
||||
"gold": 0,
|
||||
"star": 0,
|
||||
"rarity": "Common",
|
||||
"slots": [],
|
||||
"gold": 0,
|
||||
"star": 0,
|
||||
"rarity": "Common",
|
||||
"slots": [],
|
||||
})
|
||||
_selected_idx = _data.size() - 1
|
||||
_refresh_list()
|
||||
@@ -454,7 +454,7 @@ func _on_save_pressed() -> void:
|
||||
var err_gd := _generate_skin_manager()
|
||||
var err_js := _generate_admin_js()
|
||||
if err_gd == OK and err_js == OK:
|
||||
_set_status("✓ skin_manager.gd and tekton_admin.js updated successfully!", Color(0.4, 1.0, 0.4))
|
||||
_set_status("✓ skin_manager.gd and economy.js updated successfully!", Color(0.4, 1.0, 0.4))
|
||||
else:
|
||||
_set_status("⚠ Some files could not be updated — check the Output log.", Color.YELLOW)
|
||||
|
||||
@@ -465,7 +465,7 @@ func _generate_skin_manager() -> int:
|
||||
if not FileAccess.file_exists(SKIN_MANAGER_PATH):
|
||||
push_error("[SkinCatalogEditor] File not found: " + SKIN_MANAGER_PATH)
|
||||
return ERR_FILE_NOT_FOUND
|
||||
var f := FileAccess.open(SKIN_MANAGER_PATH, FileAccess.READ)
|
||||
var f := FileAccess.open(SKIN_MANAGER_PATH, FileAccess.READ)
|
||||
var src: String = f.get_as_text()
|
||||
f.close()
|
||||
|
||||
@@ -516,20 +516,20 @@ func _generate_skin_manager() -> int:
|
||||
return OK
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Code Generation — tekton_admin.js
|
||||
# Code Generation — economy.js
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
func _generate_admin_js() -> int:
|
||||
if not FileAccess.file_exists(ADMIN_JS_PATH):
|
||||
push_error("[SkinCatalogEditor] File not found: " + ADMIN_JS_PATH)
|
||||
return ERR_FILE_NOT_FOUND
|
||||
var f := FileAccess.open(ADMIN_JS_PATH, FileAccess.READ)
|
||||
var f := FileAccess.open(ADMIN_JS_PATH, FileAccess.READ)
|
||||
var src: String = f.get_as_text()
|
||||
f.close()
|
||||
|
||||
var b := src.find(BEGIN_SHOP)
|
||||
var e := src.find(END_SHOP)
|
||||
if b == -1 or e == -1:
|
||||
push_error("[SkinCatalogEditor] Sentinel markers not found in tekton_admin.js")
|
||||
push_error("[SkinCatalogEditor] Sentinel markers not found in economy.js")
|
||||
return ERR_INVALID_DATA
|
||||
|
||||
var lines: PackedStringArray = []
|
||||
@@ -545,12 +545,12 @@ func _generate_admin_js() -> int:
|
||||
var char_val: String = entry.get("character", "")
|
||||
var char_part: String = (", character: \"%s\"" % char_val) if not char_val.is_empty() else ""
|
||||
lines.append(" { id: \"%s\", name: \"%s\", category: \"%s\", gold: %d, star: %d, rarity: \"%s\"%s }," % [
|
||||
entry.get("item_id", ""),
|
||||
entry.get("name", ""),
|
||||
entry.get("item_id", ""),
|
||||
entry.get("name", ""),
|
||||
cat,
|
||||
entry.get("gold", 0),
|
||||
entry.get("star", 0),
|
||||
entry.get("rarity", "Common"),
|
||||
entry.get("gold", 0),
|
||||
entry.get("star", 0),
|
||||
entry.get("rarity", "Common"),
|
||||
char_part,
|
||||
])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user